Merge branch 'master' into sms
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 52dec90..d6f95f6 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -381,6 +381,7 @@
 struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num);
 
 const char *gsm_pchan_name(enum gsm_phys_chan_config c);
+enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
 const char *gsm_lchan_name(enum gsm_chan_t c);
 const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
 char *gsm_ts_name(struct gsm_bts_trx_ts *ts);
diff --git a/openbsc/include/vty/vty.h b/openbsc/include/vty/vty.h
index 4bb785b..d43d992 100644
--- a/openbsc/include/vty/vty.h
+++ b/openbsc/include/vty/vty.h
@@ -26,6 +26,7 @@
 	VTY_SERV,
 	VTY_READ,
 	VTY_WRITE,
+	VTY_CLOSED,
 	VTY_TIMEOUT_RESET,
 #ifdef VTYSH
 	VTYSH_SERV,
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 82cb788..9e0a260 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -1320,11 +1320,13 @@
 
 	switch (signal) {
 	case SIGINT:
-	case SIGABRT:
 		shutdown_net(gsmnet);
 		sleep(3);
 		exit(0);
 		break;
+	case SIGABRT:
+		/* in case of abort, we want to obtain a talloc report
+		 * and then return to the caller, who will abort the process */
 	case SIGUSR1:
 		talloc_report_full(tall_bsc_ctx, stderr);
 		break;
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 285b758..0ed0845 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -55,6 +55,18 @@
 	return pchan_names[c];
 }
 
+enum gsm_phys_chan_config gsm_pchan_parse(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pchan_names); i++) {
+		if (!strcasecmp(name, pchan_names[i]))
+			return i;
+	}
+
+	return -1;
+}
+
 static const char *lchan_names[] = {
 	[GSM_LCHAN_NONE]	= "NONE",
 	[GSM_LCHAN_SDCCH]	= "SDCCH",
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index 7a67fe1..ba57470 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -146,6 +146,10 @@
 		rc = vty_read(conn->vty);
 	}
 
+	/* vty might have been closed from vithin vty_read() */
+	if (!conn->vty)
+		return rc;
+
 	if (what & BSC_FD_WRITE) {
 		rc = buffer_flush_all(conn->vty->obuf, fd->fd);
 		if (rc == BUFFER_EMPTY)
@@ -192,6 +196,9 @@
 	struct telnet_connection *connection = vty->priv;
 	struct bsc_fd *bfd = &connection->fd;
 
+	if (vty->type != VTY_TERM)
+		return;
+
 	switch (event) {
 	case VTY_READ:
 		bfd->when |= BSC_FD_READ;
@@ -199,6 +206,11 @@
 	case VTY_WRITE:
 		bfd->when |= BSC_FD_WRITE;
 		break;
+	case VTY_CLOSED:
+		/* vty layer is about to free() vty */
+		connection->vty = NULL;
+		telnet_close_client(bfd);
+		break;
 	default:
 		break;
 	}
diff --git a/openbsc/src/vty/buffer.c b/openbsc/src/vty/buffer.c
index 6366100..be6623d 100644
--- a/openbsc/src/vty/buffer.c
+++ b/openbsc/src/vty/buffer.c
@@ -28,9 +28,12 @@
 #include <stddef.h>
 #include <sys/uio.h>
 
+#include <openbsc/talloc.h>
 #include <vty/buffer.h>
 #include <vty/vty.h>
 
+static void *tall_vbuf_ctx;
+
 /* Buffer master. */
 struct buffer {
 	/* Data list. */
@@ -61,14 +64,14 @@
    next page boundery. */
 #define BUFFER_SIZE_DEFAULT		4096
 
-#define BUFFER_DATA_FREE(D) free((D))
+#define BUFFER_DATA_FREE(D) talloc_free((D))
 
 /* Make new buffer. */
 struct buffer *buffer_new(size_t size)
 {
 	struct buffer *b;
 
-	b = calloc(1, sizeof(struct buffer));
+	b = talloc_zero(tall_vbuf_ctx, struct buffer);
 
 	if (size)
 		b->size = size;
@@ -89,7 +92,7 @@
 void buffer_free(struct buffer *b)
 {
 	buffer_reset(b);
-	free(b);
+	talloc_free(b);
 }
 
 /* Make string clone. */
@@ -102,7 +105,7 @@
 
 	for (data = b->head; data; data = data->next)
 		totlen += data->cp - data->sp;
-	if (!(s = malloc(totlen + 1)))
+	if (!(s = _talloc_zero(tall_vbuf_ctx, (totlen + 1), "buffer_getstr")))
 		return NULL;
 	p = s;
 	for (data = b->head; data; data = data->next) {
@@ -137,7 +140,9 @@
 {
 	struct buffer_data *d;
 
-	d = malloc(offsetof(struct buffer_data, data[b->size]));
+	d = _talloc_zero(tall_vbuf_ctx,
+			 offsetof(struct buffer_data, data[b->size]),
+			 "buffer_add");
 	if (!d)
 		return NULL;
 	d->cp = d->sp = 0;
@@ -458,3 +463,8 @@
 	}
 	return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
 }
+
+static __attribute__((constructor)) void on_dso_load_vty_buf(void)
+{
+	tall_vbuf_ctx = talloc_named_const(NULL, 1, "vty_buffer");
+}
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index 44bdf26..9841343 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -47,6 +47,9 @@
 
 #include <openbsc/gsm_data.h>
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/talloc.h>
+
+static void *tall_vcmd_ctx;
 
 /* Command vector which includes some level of command lists. Normally
    each daemon maintains each own cmdvec. */
@@ -172,7 +175,7 @@
 		len += strlen(argv[i]) + 1;
 	if (!len)
 		return NULL;
-	p = str = malloc(len);
+	p = str = _talloc_zero(tall_vcmd_ctx, len, "arvg_concat");
 	for (i = shift; i < argc; i++) {
 		size_t arglen;
 		memcpy(p, argv[i], (arglen = strlen(argv[i])));
@@ -274,7 +277,7 @@
 		       *cp != '\0')
 			cp++;
 		strlen = cp - start;
-		token = malloc(strlen + 1);
+		token = _talloc_zero(tall_vcmd_ctx, strlen + 1, "make_strvec");
 		memcpy(token, start, strlen);
 		*(token + strlen) = '\0';
 		vector_set(strvec, token);
@@ -299,7 +302,7 @@
 
 	for (i = 0; i < vector_active(v); i++)
 		if ((cp = vector_slot(v, i)) != NULL)
-			free(cp);
+			talloc_free(cp);
 
 	vector_free(v);
 }
@@ -330,7 +333,7 @@
 		cp++;
 
 	strlen = cp - start;
-	token = malloc(strlen + 1);
+	token = _talloc_zero(tall_vcmd_ctx, strlen + 1, "cmd_desc_str");
 	memcpy(token, start, strlen);
 	*(token + strlen) = '\0';
 
@@ -401,11 +404,11 @@
 
 		len = cp - sp;
 
-		token = malloc(len + 1);
+		token = _talloc_zero(tall_vcmd_ctx, len + 1, "cmd_make_descvec");
 		memcpy(token, sp, len);
 		*(token + len) = '\0';
 
-		desc = calloc(1, sizeof(struct desc));
+		desc = talloc_zero(tall_vcmd_ctx, struct desc);
 		desc->cmd = token;
 		desc->str = cmd_desc_str(&dp);
 
@@ -1852,7 +1855,8 @@
 			if (len < lcd) {
 				char *lcdstr;
 
-				lcdstr = malloc(lcd + 1);
+				lcdstr = _talloc_zero(tall_vcmd_ctx, lcd + 1,
+						      "complete-lcdstr");
 				memcpy(lcdstr, matchvec->index[0], lcd);
 				lcdstr[lcd] = '\0';
 
@@ -1861,7 +1865,7 @@
 				/* Free matchvec. */
 				for (i = 0; i < vector_active(matchvec); i++) {
 					if (vector_slot(matchvec, i))
-						free(vector_slot(matchvec, i));
+						talloc_free(vector_slot(matchvec, i));
 				}
 				vector_free(matchvec);
 
@@ -2472,11 +2476,14 @@
 	config_file = host.config;
 
 	config_file_sav =
-	    malloc(strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1);
+	    _talloc_zero(tall_vcmd_ctx,
+			 strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1,
+			 "config_file_sav");
 	strcpy(config_file_sav, config_file);
 	strcat(config_file_sav, CONF_BACKUP_EXT);
 
-	config_file_tmp = malloc(strlen(config_file) + 8);
+	config_file_tmp = _talloc_zero(tall_vcmd_ctx, strlen(config_file) + 8,
+					"config_file_tmp");
 	sprintf(config_file_tmp, "%s.XXXXXX", config_file);
 
 	/* Open file to configuration write. */
@@ -2484,8 +2491,8 @@
 	if (fd < 0) {
 		vty_out(vty, "Can't open configuration file %s.%s",
 			config_file_tmp, VTY_NEWLINE);
-		free(config_file_tmp);
-		free(config_file_sav);
+		talloc_free(config_file_tmp);
+		talloc_free(config_file_sav);
 		return CMD_WARNING;
 	}
 
@@ -2495,7 +2502,7 @@
 	file_vty->type = VTY_FILE;
 
 	/* Config file header print. */
-	vty_out(file_vty, "!\n! Zebra configuration saved from vty\n!   ");
+	vty_out(file_vty, "!\n! OpenBSC configuration saved from vty\n!   ");
 	//vty_time_print (file_vty, 1);
 	vty_out(file_vty, "!\n");
 
@@ -2511,16 +2518,16 @@
 			vty_out(vty,
 				"Can't unlink backup configuration file %s.%s",
 				config_file_sav, VTY_NEWLINE);
-			free(config_file_sav);
-			free(config_file_tmp);
+			talloc_free(config_file_sav);
+			talloc_free(config_file_tmp);
 			unlink(config_file_tmp);
 			return CMD_WARNING;
 		}
 	if (link(config_file, config_file_sav) != 0) {
 		vty_out(vty, "Can't backup old configuration file %s.%s",
 			config_file_sav, VTY_NEWLINE);
-		free(config_file_sav);
-		free(config_file_tmp);
+		talloc_free(config_file_sav);
+		talloc_free(config_file_tmp);
 		unlink(config_file_tmp);
 		return CMD_WARNING;
 	}
@@ -2528,24 +2535,24 @@
 	if (unlink(config_file) != 0) {
 		vty_out(vty, "Can't unlink configuration file %s.%s",
 			config_file, VTY_NEWLINE);
-		free(config_file_sav);
-		free(config_file_tmp);
+		talloc_free(config_file_sav);
+		talloc_free(config_file_tmp);
 		unlink(config_file_tmp);
 		return CMD_WARNING;
 	}
 	if (link(config_file_tmp, config_file) != 0) {
 		vty_out(vty, "Can't save configuration file %s.%s", config_file,
 			VTY_NEWLINE);
-		free(config_file_sav);
-		free(config_file_tmp);
+		talloc_free(config_file_sav);
+		talloc_free(config_file_tmp);
 		unlink(config_file_tmp);
 		return CMD_WARNING;
 	}
 	unlink(config_file_tmp);
 	sync();
 
-	free(config_file_sav);
-	free(config_file_tmp);
+	talloc_free(config_file_sav);
+	talloc_free(config_file_tmp);
 
 	if (chmod(config_file, CONFIGFILE_MASK) != 0) {
 		vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
@@ -2654,7 +2661,7 @@
 	}
 
 	if (host.name)
-		free(host.name);
+		talloc_free(host.name);
 
 	host.name = strdup(argv[0]);
 	return CMD_SUCCESS;
@@ -2666,7 +2673,7 @@
       NO_STR "Reset system's network name\n" "Host name of this router\n")
 {
 	if (host.name)
-		free(host.name);
+		talloc_free(host.name);
 	host.name = NULL;
 	return CMD_SUCCESS;
 }
@@ -2687,10 +2694,10 @@
 	if (argc == 2) {
 		if (*argv[0] == '8') {
 			if (host.password)
-				free(host.password);
+				talloc_free(host.password);
 			host.password = NULL;
 			if (host.password_encrypt)
-				free(host.password_encrypt);
+				talloc_free(host.password_encrypt);
 			host.password_encrypt = strdup(strdup(argv[1]));
 			return CMD_SUCCESS;
 		} else {
@@ -2707,13 +2714,13 @@
 	}
 
 	if (host.password)
-		free(host.password);
+		talloc_free(host.password);
 	host.password = NULL;
 
 #ifdef VTY_CRYPT_PW
 	if (host.encrypt) {
 		if (host.password_encrypt)
-			free(host.password_encrypt);
+			talloc_free(host.password_encrypt);
 		host.password_encrypt = strdup(zencrypt(argv[0]));
 	} else
 #endif
@@ -2745,11 +2752,11 @@
 	if (argc == 2) {
 		if (*argv[0] == '8') {
 			if (host.enable)
-				free(host.enable);
+				talloc_free(host.enable);
 			host.enable = NULL;
 
 			if (host.enable_encrypt)
-				free(host.enable_encrypt);
+				talloc_free(host.enable_encrypt);
 			host.enable_encrypt = strdup(argv[1]);
 
 			return CMD_SUCCESS;
@@ -2767,14 +2774,14 @@
 	}
 
 	if (host.enable)
-		free(host.enable);
+		talloc_free(host.enable);
 	host.enable = NULL;
 
 	/* Plain password input. */
 #ifdef VTY_CRYPT_PW
 	if (host.encrypt) {
 		if (host.enable_encrypt)
-			free(host.enable_encrypt);
+			talloc_free(host.enable_encrypt);
 		host.enable_encrypt = strdup(zencrypt(argv[0]));
 	} else
 #endif
@@ -2798,11 +2805,11 @@
       "Assign the privileged level password\n")
 {
 	if (host.enable)
-		free(host.enable);
+		talloc_free(host.enable);
 	host.enable = NULL;
 
 	if (host.enable_encrypt)
-		free(host.enable_encrypt);
+		talloc_free(host.enable_encrypt);
 	host.enable_encrypt = NULL;
 
 	return CMD_SUCCESS;
@@ -2821,12 +2828,12 @@
 
 	if (host.password) {
 		if (host.password_encrypt)
-			free(host.password_encrypt);
+			talloc_free(host.password_encrypt);
 		host.password_encrypt = strdup(zencrypt(host.password));
 	}
 	if (host.enable) {
 		if (host.enable_encrypt)
-			free(host.enable_encrypt);
+			talloc_free(host.enable_encrypt);
 		host.enable_encrypt = strdup(zencrypt(host.enable));
 	}
 
@@ -2844,11 +2851,11 @@
 	host.encrypt = 0;
 
 	if (host.password_encrypt)
-		free(host.password_encrypt);
+		talloc_free(host.password_encrypt);
 	host.password_encrypt = NULL;
 
 	if (host.enable_encrypt)
-		free(host.enable_encrypt);
+		talloc_free(host.enable_encrypt);
 	host.enable_encrypt = NULL;
 
 	return CMD_SUCCESS;
@@ -2924,7 +2931,7 @@
 		((message =
 		  argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
 	if (message)
-		free(message);
+		talloc_free(message);
 	return CMD_SUCCESS;
 }
 
@@ -2944,7 +2951,7 @@
 	zlog(NULL, level,
 	     ((message = argv_concat(argv, argc, 1)) ? message : ""));
 	if (message)
-		free(message);
+		talloc_free(message);
 	return CMD_SUCCESS;
 }
 
@@ -3076,7 +3083,9 @@
 			return CMD_WARNING;
 		}
 
-		if ((p = malloc(strlen(cwd) + strlen(fname) + 2))
+		if ((p = _talloc_zero(tall_vcmd_ctx,
+				      strlen(cwd) + strlen(fname) + 2),
+				      "set_log_file")
 		    == NULL) {
 			zlog_err("config_log_file: Unable to alloc mem!");
 			return CMD_WARNING;
@@ -3089,7 +3098,7 @@
 	ret = zlog_set_file(NULL, fullpath, loglevel);
 
 	if (p)
-		free(p);
+		talloc_free(p);
 
 	if (!ret) {
 		vty_out(vty, "can't open logfile %s\n", fname);
@@ -3097,7 +3106,7 @@
 	}
 
 	if (host.logfile)
-		free(host.logfile);
+		talloc_free(host.logfile);
 
 	host.logfile = strdup(fname);
 
@@ -3134,7 +3143,7 @@
 	zlog_reset_file(NULL);
 
 	if (host.logfile)
-		free(host.logfile);
+		talloc_free(host.logfile);
 
 	host.logfile = NULL;
 
@@ -3288,7 +3297,7 @@
       "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
 {
 	if (host.motdfile)
-		free(host.motdfile);
+		talloc_free(host.motdfile);
 	host.motdfile = strdup(argv[0]);
 
 	return CMD_SUCCESS;
@@ -3309,7 +3318,7 @@
 {
 	host.motd = NULL;
 	if (host.motdfile)
-		free(host.motdfile);
+		talloc_free(host.motdfile);
 	host.motdfile = NULL;
 	return CMD_SUCCESS;
 }
@@ -3412,3 +3421,8 @@
 	}
 	srand(time(NULL));
 }
+
+static __attribute__((constructor)) void on_dso_load_vty_command(void)
+{
+	tall_vcmd_ctx = talloc_named_const(NULL, 1, "vty_command");
+}
diff --git a/openbsc/src/vty/vector.c b/openbsc/src/vty/vector.c
index 7687010..c8885a4 100644
--- a/openbsc/src/vty/vector.c
+++ b/openbsc/src/vty/vector.c
@@ -23,12 +23,15 @@
 #include <unistd.h>
 
 #include <vty/vector.h>
+#include <openbsc/talloc.h>
 #include <memory.h>
 
+static void *tall_vvec_ctx;
+
 /* Initialize vector : allocate memory and return vector. */
 vector vector_init(unsigned int size)
 {
-	vector v = calloc(1, sizeof(struct _vector));
+	vector v = talloc_zero(tall_vvec_ctx, struct _vector);
 	if (!v)
 		return NULL;
 
@@ -38,9 +41,10 @@
 
 	v->alloced = size;
 	v->active = 0;
-	v->index = calloc(1, sizeof(void *) * size);
+	v->index = _talloc_zero(tall_vvec_ctx, sizeof(void *) * size,
+				"vector_init:index");
 	if (!v->index) {
-		free(v);
+		talloc_free(v);
 		return NULL;
 	}
 	return v;
@@ -48,24 +52,24 @@
 
 void vector_only_wrapper_free(vector v)
 {
-	free(v);
+	talloc_free(v);
 }
 
 void vector_only_index_free(void *index)
 {
-	free(index);
+	talloc_free(index);
 }
 
 void vector_free(vector v)
 {
-	free(v->index);
-	free(v);
+	talloc_free(v->index);
+	talloc_free(v);
 }
 
 vector vector_copy(vector v)
 {
 	unsigned int size;
-	vector new = calloc(1, sizeof(struct _vector));
+	vector new = talloc_zero(tall_vvec_ctx, struct _vector);
 	if (!new)
 		return NULL;
 
@@ -73,9 +77,9 @@
 	new->alloced = v->alloced;
 
 	size = sizeof(void *) * (v->alloced);
-	new->index = calloc(1, size);
+	new->index = _talloc_zero(tall_vvec_ctx, size, "vector_copy:index");
 	if (!new->index) {
-		free(new);
+		talloc_free(new);
 		return NULL;
 	}
 	memcpy(new->index, v->index, size);
@@ -89,7 +93,8 @@
 	if (v->alloced > num)
 		return;
 
-	v->index = realloc(v->index, sizeof(void *) * (v->alloced * 2));
+	v->index = talloc_realloc_size(tall_vvec_ctx, v->index,
+				       sizeof(void *) * (v->alloced * 2));
 	memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced);
 	v->alloced *= 2;
 
@@ -184,3 +189,8 @@
 
 	return count;
 }
+
+static __attribute__((constructor)) void on_dso_load_vty_vec(void)
+{
+	tall_vvec_ctx = talloc_named_const(NULL, 1, "vty_vector");
+}
diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c
index c461631..0549914 100644
--- a/openbsc/src/vty/vty.c
+++ b/openbsc/src/vty/vty.c
@@ -17,6 +17,7 @@
 #include <vty/vty.h>
 #include <vty/command.h>
 #include <vty/buffer.h>
+#include <openbsc/talloc.h>
 
 extern struct host host;
 
@@ -32,6 +33,8 @@
 
 static int no_password_check = 1;
 
+static void *tall_vty_ctx;
+
 static void vty_clear_buf(struct vty *vty)
 {
 	memset(vty->buf, 0, vty->max);
@@ -40,7 +43,7 @@
 /* Allocate new vty struct. */
 struct vty *vty_new()
 {
-	struct vty *new = malloc(sizeof(struct vty));
+	struct vty *new = talloc_zero(tall_vty_ctx, struct vty);
 
 	if (!new)
 		goto out;
@@ -48,7 +51,7 @@
 	new->obuf = buffer_new(0);	/* Use default buffer size. */
 	if (!new->obuf)
 		goto out_new;
-	new->buf = calloc(1, VTY_BUFSIZ);
+	new->buf = _talloc_zero(tall_vty_ctx, VTY_BUFSIZ, "vty_new->buf");
 	if (!new->buf)
 		goto out_obuf;
 
@@ -57,9 +60,9 @@
 	return new;
 
 out_obuf:
-	free(new->obuf);
+	buffer_free(new->obuf);
 out_new:
-	free(new);
+	talloc_free(new);
 	new = NULL;
 out:
 	return new;
@@ -135,16 +138,19 @@
 {
 	int i;
 
-	/* Flush buffer. */
-	buffer_flush_all(vty->obuf, vty->fd);
+	if (vty->obuf)  {
+		/* Flush buffer. */
+		buffer_flush_all(vty->obuf, vty->fd);
 
-	/* Free input buffer. */
-	buffer_free(vty->obuf);
+		/* Free input buffer. */
+		buffer_free(vty->obuf);
+		vty->obuf = NULL;
+	}
 
 	/* Free command history. */
 	for (i = 0; i < VTY_MAXHIST; i++)
 		if (vty->hist[i])
-			free(vty->hist[i]);
+			talloc_free(vty->hist[i]);
 
 	/* Unset vector. */
 	vector_unset(vtyvec, vty->fd);
@@ -153,17 +159,20 @@
 	if (vty->fd > 0)
 		close(vty->fd);
 
-	if (vty->buf)
-		free(vty->buf);
+	if (vty->buf) {
+		talloc_free(vty->buf);
+		vty->buf = NULL;
+	}
 
 	/* Check configure. */
 	vty_config_unlock(vty);
 
-	/* OK free vty. */
-	free(vty);
-
 	/* FIXME: memory leak. We need to call telnet_close_client() but don't
 	 * have bfd */
+	vty_event(VTY_CLOSED, vty->fd, vty);
+
+	/* OK free vty. */
+	talloc_free(vty);
 }
 
 int vty_shell(struct vty *vty)
@@ -199,7 +208,7 @@
 				else
 					size = size * 2;
 
-				p = realloc(p, size);
+				p = talloc_realloc_size(tall_vty_ctx, p, size);
 				if (!p)
 					return -1;
 
@@ -221,7 +230,7 @@
 
 		/* If p is not different with buf, it is allocated buffer.  */
 		if (p != buf)
-			free(p);
+			talloc_free(p);
 	}
 
 	return len;
@@ -344,7 +353,7 @@
 {
 	if (vty->max <= length) {
 		vty->max *= 2;
-		vty->buf = realloc(vty->buf, vty->max);
+		vty->buf = talloc_realloc_size(tall_vty_ctx, vty->buf, vty->max);
 		// FIXME: check return
 	}
 }
@@ -444,8 +453,8 @@
 
 	/* Insert history entry. */
 	if (vty->hist[vty->hindex])
-		free(vty->hist[vty->hindex]);
-	vty->hist[vty->hindex] = strdup(vty->buf);
+		talloc_free(vty->hist[vty->hindex]);
+	vty->hist[vty->hindex] = talloc_strdup(tall_vty_ctx, vty->buf);
 
 	/* History index rotation. */
 	vty->hindex++;
@@ -918,14 +927,14 @@
 		vty_backward_pure_word(vty);
 		vty_insert_word_overwrite(vty, matched[0]);
 		vty_self_insert(vty, ' ');
-		free(matched[0]);
+		//talloc_free(matched[0]);
 		break;
 	case CMD_COMPLETE_MATCH:
 		vty_prompt(vty);
 		vty_redraw_line(vty);
 		vty_backward_pure_word(vty);
 		vty_insert_word_overwrite(vty, matched[0]);
-		free(matched[0]);
+		talloc_free(matched[0]);
 		vector_only_index_free(matched);
 		return;
 		break;
@@ -934,7 +943,7 @@
 			if (i != 0 && ((i % 6) == 0))
 				vty_out(vty, "%s", VTY_NEWLINE);
 			vty_out(vty, "%-10s ", matched[i]);
-			free(matched[i]);
+			talloc_free(matched[i]);
 		}
 		vty_out(vty, "%s", VTY_NEWLINE);
 
@@ -968,7 +977,7 @@
 		return;
 	}
 
-	buf = calloc(1, strlen(desc->str) + 1);
+	buf = _talloc_zero(tall_vty_ctx, strlen(desc->str) + 1, "describe_fold");
 	if (!buf)
 		return;
 
@@ -989,7 +998,7 @@
 
 	vty_out(vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
 
-	free(buf);
+	talloc_free(buf);
 }
 
 /* Describe matched command function. */
@@ -1588,7 +1597,7 @@
 		getcwd(cwd, MAXPATHLEN);
 	}
 
-	vty_cwd = malloc(strlen(cwd) + 1);
+	vty_cwd = _talloc_zero(tall_vty_ctx, strlen(cwd) + 1, "save_cwd");
 	strcpy(vty_cwd, cwd);
 }
 
@@ -1613,6 +1622,8 @@
 	/* For further configuration read, preserve current directory. */
 	vty_save_cwd();
 
+	host.config = "openbsc.cfg";
+
 	vtyvec = vector_init(VECTOR_MIN_SIZE);
 
 	/* Install bgp top node. */
@@ -1635,3 +1646,8 @@
 	install_element(VTY_NODE, &no_vty_login_cmd);
 #endif
 }
+
+static __attribute__((constructor)) void on_dso_load_vty(void)
+{
+	tall_vty_ctx = talloc_named_const(NULL, 1, "vty");
+}
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index b480c3d..e191443 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -189,8 +189,9 @@
 		VTY_NEWLINE);
 	vty_out(vty, "\ttraining_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
 	vty_out(vty, "\tbase_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
-	vty_out(vty, "\tunit_id %u %u%s",
-		bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
+	if (is_ipaccess_bts(bts))
+		vty_out(vty, "\tunit_id %u %u%s",
+			bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
 
 	llist_for_each_entry(trx, &bts->trx_list, list)
 		config_write_trx_single(vty, trx);
@@ -690,8 +691,8 @@
 {
 	struct gsm_bts *bts = vty->index;
 
-	/* FIXME: implementation */
-	//bts->type =
+	bts->type = parse_btstype(argv[0]);
+
 	return CMD_SUCCESS;
 }
 
@@ -894,6 +895,36 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_ts_pchan,
+      cfg_ts_pchan_cmd,
+      "phys_chan_config PCHAN",
+      "Physical Channel configuration (TCH/SDCCH/...)")
+{
+	struct gsm_bts_trx_ts *ts = vty->index;
+	int pchanc;
+
+	pchanc = gsm_pchan_parse(argv[0]);
+	if (pchanc < 0)
+		return CMD_WARNING;
+
+	ts->pchan = pchanc;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ts_e1_subslot,
+      cfg_ts_e1_subslot_cmd,
+      "e1_subslot E1_IF <1-31> <0-4>",
+      "E1 sub-slot connected to this on-air timeslot")
+{
+	struct gsm_bts_trx_ts *ts = vty->index;
+
+	ts->e1_link.e1_nr = atoi(argv[0]);
+	ts->e1_link.e1_ts = atoi(argv[1]);
+	ts->e1_link.e1_ts_ss = atoi(argv[2]);
+
+	return CMD_SUCCESS;
+}
 
 /* Subscriber */
 DEFUN(show_subscr,
@@ -1010,6 +1041,8 @@
 	install_element(TRX_NODE, &cfg_ts_cmd);
 	install_node(&ts_node, dummy_config_write);
 	install_default(TS_NODE);
+	install_element(TS_NODE, &cfg_ts_pchan_cmd);
+	install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
 
 	install_element(CONFIG_NODE, &cfg_subscr_cmd);
 	install_node(&subscr_node, dummy_config_write);