VTY: decouple telnet_interface from 'struct gsmnet'

We want the VTY and telnet code to be independent from the BSC
application(s).  As a side note, we also like to eliminate static
global variables for 'struct gsm_network' all over the code.

As such, telnet_init() is now passed along a "private" pointer,
which getst stored in telnet_connection.priv.  This telnet_connection
is then stored in vty->priv, which in turn gets dereferenced if
anyone needs a reference to 'struct gsm_network' from the BSC vty
code.

Also:
 * vty_init() now calls cmd_init()
 * the ugliness that telnet_init() calls back into the application by means of
   bsc_vty_init() function has been removed.
 * telnet_init() now returns any errors, so the main program can exit
   e.g. if the port is already in use.
diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h
index b8c36b6..5a3e179 100644
--- a/openbsc/include/openbsc/telnet_interface.h
+++ b/openbsc/include/openbsc/telnet_interface.h
@@ -21,23 +21,20 @@
 #ifndef TELNET_INTERFACE_H
 #define TELNET_INTERFACE_H
 
-#include "gsm_data.h"
-#include <openbsc/debug.h>
+#include <osmocore/logging.h>
 #include <osmocore/select.h>
 
 #include <vty/vty.h>
 
 struct telnet_connection {
 	struct llist_head entry;
-	struct gsm_network *network;
+	void *priv;
 	struct bsc_fd fd;
 	struct vty *vty;
 	struct log_target *dbg;
 };
 
 
-void telnet_init(struct gsm_network *network, int port);
-
-int bsc_vty_init(struct gsm_network *net);
+int telnet_init(void *tall_ctx, void *priv, int port);
 
 #endif
diff --git a/openbsc/include/vty/vty.h b/openbsc/include/vty/vty.h
index 23430d5..f82ada1 100644
--- a/openbsc/include/vty/vty.h
+++ b/openbsc/include/vty/vty.h
@@ -129,7 +129,7 @@
 
 /* Prototypes. */
 void vty_init(const char *name, const char *version, const char *copyright);
-int vty_read_config_file(const char *file_name);
+int vty_read_config_file(const char *file_name, void *priv);
 void vty_init_vtysh (void);
 void vty_reset (void);
 struct vty *vty_new (void);
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 7435122..fa058aa 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -37,11 +37,16 @@
 #include <osmocore/talloc.h>
 #include <openbsc/signal.h>
 
+#include <vty/command.h>
+
+#include "../bscconfig.h"
+
 /* MCC and MNC for the Location Area Identifier */
 static struct log_target *stderr_target;
 struct gsm_network *bsc_gsmnet = 0;
 static const char *database_name = "hlr.sqlite3";
 static const char *config_file = "openbsc.cfg";
+extern const char *openbsc_copyright;
 
 /* timer to store statistics */
 #define DB_SYNC_INTERVAL	60, 0
@@ -213,7 +218,10 @@
 	/* enable filters */
 	log_set_all_filter(stderr_target, 1);
 
-	/* This needs to precede handle_options() as it calls vty_init() */
+	/* This needs to precede handle_options() */
+	vty_init("OpenBSC", PACKAGE_VERSION, openbsc_copyright);
+	bsc_vty_init();
+
 	rc = bsc_bootstrap_network(mncc_recv, config_file);
 	if (rc < 0)
 		exit(1);
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index 77446a2..7db4d31 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -1,6 +1,6 @@
 /* A hackish minimal BSC (+MSC +HLR) implementation */
 
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
  * All Rights Reserved
  *
@@ -1062,6 +1062,7 @@
 int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *),
 			  const char *config_file)
 {
+	struct telnet_connection dummy_conn;
 	struct gsm_bts *bts;
 	int rc;
 
@@ -1073,13 +1074,18 @@
 	bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
 	bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
 
-	telnet_init(bsc_gsmnet, 4242);
-	rc = vty_read_config_file(config_file);
+	/* our vty command code expects vty->priv to point to a telnet_connection */
+	dummy_conn.priv = bsc_gsmnet;
+	rc = vty_read_config_file(config_file, &dummy_conn);
 	if (rc < 0) {
 		LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
 	}
 
+	rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, 4242);
+	if (rc < 0)
+		return rc;
+
 	register_signal_handler(SS_NM, nm_sig_cb, NULL);
 
 	llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c
index 9cd73e1..e450d1f 100644
--- a/openbsc/src/gprs/gb_proxy_main.c
+++ b/openbsc/src/gprs/gb_proxy_main.c
@@ -205,12 +205,18 @@
 	log_add_target(stderr_target);
 	log_set_all_filter(stderr_target, 1);
 
-	telnet_init(&dummy_network, 4246);
+	vty_init("Osmocom Gb Proxy", PACKAGE_VERSION, openbsc_copyright);
+	openbsc_vty_add_cmds();
+        gbproxy_vty_init();
 
 	handle_options(argc, argv);
 
 	rate_ctr_init(tall_bsc_ctx);
 
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4246);
+	if (rc < 0)
+		exit(1);
+
 	bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb);
 	if (!bssgp_nsi) {
 		LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
@@ -247,15 +253,3 @@
 
 	exit(0);
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init("Osmocom Gb Proxy", PACKAGE_VERSION, openbsc_copyright);
-
-	openbsc_vty_add_cmds();
-        gbproxy_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
index a8501d1..7ee2833 100644
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ b/openbsc/src/gprs/gb_proxy_vty.c
@@ -175,7 +175,7 @@
 	int rc;
 
 	g_cfg = cfg;
-	rc = vty_read_config_file(config_file);
+	rc = vty_read_config_file(config_file, NULL);
 	if (rc < 0) {
 		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index 81b130b..aaad654 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -138,8 +138,14 @@
 	log_add_target(stderr_target);
 	log_set_all_filter(stderr_target, 1);
 
+	vty_init("Osmocom SGSN", PACKAGE_VERSION, openbsc_copyright);
+	openbsc_vty_add_cmds();
+        sgsn_vty_init();
+
 	rate_ctr_init(tall_bsc_ctx);
-	telnet_init(&dummy_network, 4245);
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4245);
+	if (rc < 0)
+		exit(1);
 
 	sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb);
 	if (!sgsn_nsi) {
@@ -166,15 +172,3 @@
 
 	exit(0);
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init("Osmocom SGSN", PACKAGE_VERSION, openbsc_copyright);
-
-	openbsc_vty_add_cmds();
-        sgsn_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index d56a279..c16e191 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -139,7 +139,7 @@
 	int rc;
 
 	g_cfg = cfg;
-	rc = vty_read_config_file(config_file);
+	rc = vty_read_config_file(config_file, NULL);
 	if (rc < 0) {
 		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index fd03c99..63955e7 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -193,7 +193,9 @@
 	if (!cfg)
 		return -1;
 
-	telnet_init(&dummy_network, 4243);
+	vty_init("OpenBSC MGCP", PACKAGE_VERSION, openbsc_copyright);
+	openbsc_vty_add_cmds();
+	mgcp_vty_init();
 
 	handle_options(argc, argv);
 
@@ -201,6 +203,10 @@
 	if (rc < 0)
 		return rc;
 
+	rc = telnet_init(tall_bsc_ctx, &dummy_network, 4243);
+	if (rc < 0)
+		return rc;
+
 	/* set some callbacks */
 	cfg->reset_cb = mgcp_rsip_cb;
 	cfg->change_cb = mgcp_change_cb;
@@ -253,15 +259,3 @@
 
 	return 0;
 }
-
-struct gsm_network;
-int bsc_vty_init(struct gsm_network *dummy)
-{
-	cmd_init(1);
-	vty_init("OpenBSC MGCP", PACKAGE_VERSION, openbsc_copyright);
-
-	openbsc_vty_add_cmds();
-        mgcp_vty_init();
-	return 0;
-}
-
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index 2804ce9..1e76839 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -267,7 +267,7 @@
 	int i, rc;
 
 	g_cfg = cfg;
-	rc = vty_read_config_file(config_file);
+	rc = vty_read_config_file(config_file, NULL);
 	if (rc < 0) {
 		fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
 		return rc;
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index 853cdf9..37e1c25 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -25,17 +25,10 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <openbsc/telnet_interface.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_04_11.h>
 #include <osmocore/msgb.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
 #include <osmocore/talloc.h>
-#include <openbsc/debug.h>
+#include <osmocore/logging.h>
+#include <openbsc/telnet_interface.h>
 
 #include <vty/buffer.h>
 
@@ -53,21 +46,19 @@
 	.priv_nr    = 0,
 };
 
-void telnet_init(struct gsm_network *network, int port)
+int telnet_init(void *tall_ctx, void *priv, int port)
 {
 	struct sockaddr_in sock_addr;
-	int fd, on = 1;
+	int fd, rc, on = 1;
 
-	tall_telnet_ctx = talloc_named_const(tall_bsc_ctx, 1,
+	tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
 					     "telnet_connection");
 
-	bsc_vty_init(network);
-
 	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 
 	if (fd < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface socket creation failed\n");
-		return;
+		LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n");
+		return fd;
 	}
 
 	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
@@ -77,19 +68,25 @@
 	sock_addr.sin_port = htons(port);
 	sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
-	if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface failed to bind\n");
-		return;
+	rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
+	if (bind < 0) {
+		LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n");
+		close(fd);
+		return rc;
 	}
 
-	if (listen(fd, 0) < 0) {
-		LOGP(DNM, LOGL_ERROR, "Telnet interface failed to listen\n");
-		return;
+	rc = listen(fd, 0);
+	if (rc < 0) {
+		LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n");
+		close(fd);
+		return rc;
 	}
 
-	server_socket.data = network;
+	server_socket.data = priv;
 	server_socket.fd = fd;
 	bsc_register_fd(&server_socket);
+
+	return 0;
 }
 
 extern const char *openbsc_copyright;
@@ -152,13 +149,12 @@
 	int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
 
 	if (new_connection < 0) {
-		LOGP(DNM, LOGL_ERROR, "telnet accept failed\n");
-		return -1;
+		LOGP(0, LOGL_ERROR, "telnet accept failed\n");
+		return new_connection;
 	}
 
-
 	connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
-	connection->network = (struct gsm_network*)fd->data;
+	connection->priv = fd->data;
 	connection->fd.data = connection;
 	connection->fd.fd = new_connection;
 	connection->fd.when = BSC_FD_READ;
@@ -170,7 +166,9 @@
 
 	connection->vty = vty_create(new_connection, connection);
 	if (!connection->vty) {
-		LOGP(DNM, LOGL_ERROR, "couldn't create VTY\n");
+		LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
+		close(new_connection);
+		talloc_free(connection);
 		return -1;
 	}
 
diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c
index 821c08c..438b6c3 100644
--- a/openbsc/src/vty/vty.c
+++ b/openbsc/src/vty/vty.c
@@ -1354,7 +1354,7 @@
 
 /* Read up configuration file */
 static int
-vty_read_file(FILE *confp)
+vty_read_file(FILE *confp, void *priv)
 {
 	int ret;
 	struct vty *vty;
@@ -1363,6 +1363,7 @@
 	vty->fd = 0;
 	vty->type = VTY_FILE;
 	vty->node = CONFIG_NODE;
+	vty->priv = priv;
 
 	ret = config_from_file(vty, confp);
 
@@ -1634,14 +1635,16 @@
 /* Install vty's own commands like `who' command. */
 void vty_init(const char *name, const char *version, const char *copyright)
 {
-	host.prog_name = name;
-	host.prog_version = version;
-	host.prog_copyright = copyright;
-
 	tall_vty_ctx = talloc_named_const(NULL, 0, "vty");
 	tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector");
 	tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command");
 
+	cmd_init(1);
+
+	host.prog_name = name;
+	host.prog_version = version;
+	host.prog_copyright = copyright;
+
 	/* For further configuration read, preserve current directory. */
 	vty_save_cwd();
 
@@ -1664,7 +1667,7 @@
 	install_element(VTY_NODE, &no_vty_login_cmd);
 }
 
-int vty_read_config_file(const char *file_name)
+int vty_read_config_file(const char *file_name, void *priv)
 {
 	FILE *cfile;
 	int rc;
@@ -1673,7 +1676,7 @@
 	if (!cfile)
 		return -ENOENT;
 
-	rc = vty_read_file(cfile);
+	rc = vty_read_file(cfile, priv);
 	fclose(cfile);
 
 	host_config_set(file_name);
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index eaa0eac..e68dffd 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -43,8 +43,6 @@
 
 #include "../bscconfig.h"
 
-static struct gsm_network *gsmnet;
-
 /* FIXME: this should go to some common file */
 static const struct value_string gprs_ns_timer_strs[] = {
 	{ 0, "tns-block" },
@@ -96,6 +94,12 @@
 	1,
 };
 
+struct gsm_network *gsmnet_from_vty(struct vty *v)
+{
+	struct telnet_connection *conn = v->priv;
+	return (struct gsm_network *) conn->priv;
+}
+
 static int dummy_config_write(struct vty *v)
 {
 	return CMD_SUCCESS;
@@ -161,7 +165,7 @@
 DEFUN(show_net, show_net_cmd, "show network",
 	SHOW_STR "Display information about a GSM NETWORK\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	net_dump_vty(vty, net);
 
 	return CMD_SUCCESS;
@@ -235,7 +239,7 @@
 	SHOW_STR "Display information about a BTS\n"
 		"BTS number")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	int bts_nr;
 
 	if (argc != 0) {
@@ -410,6 +414,7 @@
 
 static int config_write_bts(struct vty *v)
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(v);
 	struct gsm_bts *bts;
 
 	llist_for_each_entry(bts, &gsmnet->bts_list, list)
@@ -420,6 +425,8 @@
 
 static int config_write_net(struct vty *vty)
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	vty_out(vty, "network%s", VTY_NEWLINE);
 	vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
 	vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
@@ -491,7 +498,7 @@
 	"BTS Number\n"
 	"TRX Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts = NULL;
 	struct gsm_bts_trx *trx;
 	int bts_nr, trx_nr;
@@ -557,7 +564,7 @@
 	SHOW_STR "Display information about a TS\n"
 	"BTS Number\n" "TRX Number\n" "Timeslot Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
 	struct gsm_bts_trx_ts *ts;
@@ -717,7 +724,7 @@
 static int lchan_summary(struct vty *vty, int argc, const char **argv,
 			 void (*dump_cb)(struct vty *, struct gsm_lchan *))
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
 	struct gsm_bts_trx_ts *ts;
@@ -935,7 +942,7 @@
 	SHOW_STR "Display information about paging reuqests of a BTS\n"
 	"BTS Number\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 	struct gsm_bts *bts;
 	int bts_nr;
 
@@ -966,7 +973,7 @@
       cfg_net_cmd,
       "network", NETWORK_STR)
 {
-	vty->index = gsmnet;
+	vty->index = gsmnet_from_vty(vty);
 	vty->node = GSMNET_NODE;
 
 	return CMD_SUCCESS;
@@ -978,6 +985,8 @@
       "network country code <1-999>",
       "Set the GSM network country code")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->country_code = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -988,6 +997,8 @@
       "mobile network code <1-999>",
       "Set the GSM mobile network code")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->network_code = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -998,6 +1009,8 @@
       "short name NAME",
       "Set the short GSM network name")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	if (gsmnet->name_short)
 		talloc_free(gsmnet->name_short);
 
@@ -1011,6 +1024,8 @@
       "long name NAME",
       "Set the long GSM network name")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	if (gsmnet->name_long)
 		talloc_free(gsmnet->name_long);
 
@@ -1029,6 +1044,7 @@
 	"Use SMS-token based authentication\n")
 {
 	enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 
 	gsmnet->auth_policy = policy;
 
@@ -1040,6 +1056,8 @@
       "location updating reject cause <2-111>",
       "Set the reject cause of location updating reject\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->reject_cause = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1052,6 +1070,8 @@
 	"A5 encryption\n" "A5/0: No encryption\n"
 	"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->a5_encryption= atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1063,6 +1083,8 @@
 	"New Establish Cause Indication\n"
 	"Don't set the NECI bit\n" "Set the NECI bit\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->neci = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1076,6 +1098,8 @@
 	"Request any location, prefer MS-based\n"
 	"Request any location, prefer MS-assisted\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1085,6 +1109,8 @@
       "mm info (0|1)",
 	"Whether to send MM INFO after LOC UPD ACCEPT")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
 	gsmnet->send_mm_info = atoi(argv[0]);
 
 	return CMD_SUCCESS;
@@ -1099,6 +1125,7 @@
 	"Perform in-call handover\n")
 {
 	int enable = atoi(argv[0]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 
 	if (enable && ipacc_rtp_direct) {
 		vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
@@ -1121,6 +1148,7 @@
 	HO_WIN_RXLEV_STR
 	"How many RxLev measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1130,6 +1158,7 @@
 	HO_WIN_RXQUAL_STR
 	"How many RxQual measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1139,6 +1168,7 @@
 	HO_WIN_RXLEV_STR
 	"How many RxQual measurements are used for averaging")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1148,6 +1178,7 @@
 	HO_PBUDGET_STR
 	"How often to check if we have a better cell (SACCH frames)")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.pwr_interval = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1157,6 +1188,7 @@
 	HO_PBUDGET_STR
 	"How many dB does a neighbor to be stronger to become a HO candidate")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1166,6 +1198,7 @@
 	HANDOVER_STR
 	"How big is the maximum timing advance before HO is forced")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->handover.max_distance = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
@@ -1177,6 +1210,7 @@
       "Configure GSM Timers\n"					\
       doc)							\
 {								\
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);	\
 	int value = atoi(argv[0]);				\
 								\
 	if (value < 0 || value > 65535) {			\
@@ -1209,6 +1243,7 @@
       "Select a BTS to configure\n"
 	"BTS Number\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	int bts_nr = atoi(argv[0]);
 	struct gsm_bts *bts;
 
@@ -1943,16 +1978,11 @@
 	return CMD_SUCCESS;
 }
 
-extern int bsc_vty_init_extra(struct gsm_network *net);
+extern int bsc_vty_init_extra(void);
 extern const char *openbsc_copyright;
 
-int bsc_vty_init(struct gsm_network *net)
+int bsc_vty_init(void)
 {
-	gsmnet = net;
-
-	cmd_init(1);
-	vty_init("OpenBSC", PACKAGE_VERSION, openbsc_copyright);
-
 	install_element_ve(&show_net_cmd);
 	install_element_ve(&show_bts_cmd);
 	install_element_ve(&show_trx_cmd);
@@ -2063,7 +2093,7 @@
 	install_element(TS_NODE, &cfg_ts_pchan_cmd);
 	install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
 
-	bsc_vty_init_extra(net);
+	bsc_vty_init_extra();
 
 	return 0;
 }
diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c
index 06eb2a5..619caf5 100644
--- a/openbsc/src/vty_interface_cmds.c
+++ b/openbsc/src/vty_interface_cmds.c
@@ -19,17 +19,20 @@
  *
  */
 
-#include <openbsc/vty.h>
-#include <openbsc/telnet_interface.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <osmocore/talloc.h>
 
+#include <openbsc/vty.h>
+#include <openbsc/telnet_interface.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/debug.h>
+
 #include <vty/command.h>
 #include <vty/buffer.h>
 #include <vty/vty.h>
 
-#include <stdlib.h>
-
 static void _vty_output(struct log_target *tgt, const char *line)
 {
 	struct vty *vty = tgt->tgt_vty.vty;
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index 202518e..c18aef3 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -43,7 +43,7 @@
 #include <openbsc/debug.h>
 #include <openbsc/vty.h>
 
-static struct gsm_network *gsmnet;
+extern struct gsm_network *gsmnet_from_vty(struct vty *v);
 
 struct cmd_node subscr_node = {
 	SUBSCR_NODE,
@@ -103,6 +103,7 @@
       "subscriber IMSI",
       "Select a Subscriber to configure\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	const char *imsi = argv[0];
 	struct gsm_subscriber *subscr;
 
@@ -175,6 +176,7 @@
       "show subscriber [IMSI]",
 	SHOW_STR "Display information about a subscriber\n")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	const char *imsi;
 	struct gsm_subscriber *subscr;
 
@@ -218,6 +220,7 @@
       "sms send pending",
       "Send all pending SMS")
 {
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	struct gsm_sms *sms;
 	int id = 0;
 
@@ -250,7 +253,7 @@
 	strncpy(sms->text, text, sizeof(sms->text)-1);
 
 	/* FIXME: don't use ID 1 static */
-	sms->sender = subscr_get_by_id(gsmnet, 1);
+	sms->sender = subscr_get_by_id(receiver->net, 1);
 	sms->reply_path_req = 0;
 	sms->status_rep_req = 0;
 	sms->ud_hdr_ind = 0;
@@ -275,7 +278,8 @@
 	return CMD_SUCCESS;
 }
 
-static struct gsm_subscriber *get_subscr_by_argv(const char *type,
+static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
+						 const char *type,
 						 const char *id)
 {
 	if (!strcmp(type, "extension"))
@@ -302,7 +306,8 @@
       "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE",
 	SUBSCR_HELP "SMS Operations\n" "Send SMS\n" "Actual SMS Text")
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	char *str;
 	int rc;
 
@@ -326,7 +331,8 @@
 	SUBSCR_HELP
 	"Silent SMS Operation\n" "Send Silent SMS\n" "Actual SMS text\n")
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	char *str;
 	int rc;
 
@@ -358,7 +364,8 @@
 	SUBSCR_HELP "Silent call operation\n" "Start silent call\n"
 	CHAN_TYPE_HELP)
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	int rc, type;
 
 	if (!subscr) {
@@ -395,7 +402,8 @@
 	SUBSCR_HELP "Silent call operation\n" "Stop silent call\n"
 	CHAN_TYPE_HELP)
 {
-	struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]);
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
 	int rc;
 
 	if (!subscr) {
@@ -526,7 +534,7 @@
       "show statistics",
 	SHOW_STR "Display network statistics\n")
 {
-	struct gsm_network *net = gsmnet;
+	struct gsm_network *net = gsmnet_from_vty(vty);
 
 	openbsc_vty_print_statistics(vty, net);
 	vty_out(vty, "Location Update         : %lu attach, %lu normal, %lu periodic%s",
@@ -556,10 +564,8 @@
 }
 
 
-int bsc_vty_init_extra(struct gsm_network *net)
+int bsc_vty_init_extra(void)
 {
-	gsmnet = net;
-
 	register_signal_handler(SS_SCALL, scall_cbfn, NULL);
 
 	install_element_ve(&show_subscr_cmd);