[vty] Move layer3+ functionality to vty_interface_layer3.c

Move everything that is policy, requires access to a DB or is
generally in the domain of the MSC to vty_interface_layer3.c.
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 30968b0..b18b072 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -18,7 +18,7 @@
 
 libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
 
-bsc_hack_SOURCES = bsc_hack.c vty_interface.c
+bsc_hack_SOURCES = bsc_hack.c vty_interface.c vty_interface_layer3.c
 bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
 
 bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 1c5cb38..248e68e 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -30,8 +30,6 @@
 
 #include <openbsc/linuxlist.h>
 #include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_11.h>
 #include <openbsc/e1_input.h>
 #include <openbsc/abis_nm.h>
 #include <openbsc/gsm_utils.h>
@@ -64,12 +62,6 @@
 	1,
 };
 
-struct cmd_node subscr_node = {
-	SUBSCR_NODE,
-	"%s(subscriber)#",
-	1,
-};
-
 static int dummy_config_write(struct vty *v)
 {
 	return CMD_SUCCESS;
@@ -421,7 +413,7 @@
 	return CMD_SUCCESS;
 }
 
-static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
+void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
 {
 	vty_out(vty, "    ID: %llu, Authorized: %d%s", subscr->id,
 		subscr->authorized, VTY_NEWLINE);
@@ -704,28 +696,6 @@
 	return CMD_SUCCESS;
 }
 
-/* per-subscriber configuration */
-DEFUN(cfg_subscr,
-      cfg_subscr_cmd,
-      "subscriber IMSI",
-      "Select a Subscriber to configure\n")
-{
-	const char *imsi = argv[0];
-	struct gsm_subscriber *subscr;
-
-	subscr = subscr_get_by_imsi(gsmnet, imsi);
-	if (!subscr) {
-		vty_out(vty, "%% No subscriber for IMSI %s%s",
-			imsi, VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-
-	vty->index = subscr;
-	vty->node = SUBSCR_NODE;
-
-	return CMD_SUCCESS;
-}
-
 DEFUN(cfg_net,
       cfg_net_cmd,
       "network",
@@ -1158,220 +1128,6 @@
 	return CMD_SUCCESS;
 }
 
-/* Subscriber */
-DEFUN(show_subscr,
-      show_subscr_cmd,
-      "show subscriber [IMSI]",
-	SHOW_STR "Display information about a subscriber\n")
-{
-	const char *imsi;
-	struct gsm_subscriber *subscr;
-
-	if (argc >= 1) {
-		imsi = argv[0];
-		subscr = subscr_get_by_imsi(gsmnet, imsi);
-		if (!subscr) {
-			vty_out(vty, "%% unknown subscriber%s",
-				VTY_NEWLINE);
-			return CMD_WARNING;
-		}
-		subscr_dump_vty(vty, subscr);
-		
-		return CMD_SUCCESS;
-	}
-
-	/* FIXME: iterate over all subscribers ? */
-	return CMD_WARNING;
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(show_subscr_cache,
-      show_subscr_cache_cmd,
-      "show subscriber cache",
-	SHOW_STR "Display contents of subscriber cache\n")
-{
-	struct gsm_subscriber *subscr;
-
-	llist_for_each_entry(subscr, &active_subscribers, entry) {
-		vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
-		subscr_dump_vty(vty, subscr);
-	}
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(sms_send_pend,
-      sms_send_pend_cmd,
-      "sms send pending MIN_ID",
-      "Send all pending SMS starting from MIN_ID")
-{
-	struct gsm_sms *sms;
-	int id = atoi(argv[0]);
-
-	while (1) {
-		sms = db_sms_get_unsent(gsmnet, id++);
-		if (!sms)
-			return CMD_WARNING;
-
-		if (!sms->receiver) {
-			sms_free(sms);
-			continue;
-		}
-
-		gsm411_send_sms_subscr(sms->receiver, sms);
-	}
-
-	return CMD_SUCCESS;
-}
-
-static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
-{
-	struct buffer *b = buffer_new(1024);
-	int i;
-
-	if (!b)
-		return NULL;
-
-	for (i = base; i < argc; i++) {
-		buffer_putstr(b, argv[i]);
-		buffer_putc(b, ' ');
-	}
-	buffer_putc(b, '\0');
-
-	return b;
-}
-
-struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
-{
-	struct gsm_sms *sms = sms_alloc();
-
-	if (!sms)
-		return NULL;
-
-	if (!receiver->lac) {
-		/* subscriber currently not attached, store in database? */
-		return NULL;
-	}
-
-	sms->receiver = subscr_get(receiver);
-	strncpy(sms->text, text, sizeof(sms->text)-1);
-
-	/* FIXME: don't use ID 1 static */
-	sms->sender = subscr_get_by_id(gsmnet, 1);
-	sms->reply_path_req = 0;
-	sms->status_rep_req = 0;
-	sms->ud_hdr_ind = 0;
-	sms->protocol_id = 0; /* implicit */
-	sms->data_coding_scheme = 0; /* default 7bit */
-	strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
-	/* Generate user_data */
-	sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
-
-	return sms;
-}
-
-static int _send_sms_buffer(struct gsm_subscriber *receiver,
-			     struct buffer *b)
-{
-	struct gsm_sms *sms;
-
-	sms = sms_from_text(receiver, buffer_getstr(b));
-
-	gsm411_send_sms_subscr(receiver, sms);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(sms_send_ext,
-      sms_send_ext_cmd,
-      "sms send extension EXTEN .LINE",
-      "Send a message to a subscriber identified by EXTEN")
-{
-	struct gsm_subscriber *receiver;
-	struct buffer *b;
-	int rc;
-
-	receiver = subscr_get_by_extension(gsmnet, argv[0]);
-	if (!receiver)
-		return CMD_WARNING;
-
-	b = argv_to_buffer(argc, argv, 1);
-	rc = _send_sms_buffer(receiver, b);
-	buffer_free(b);
-
-	return rc;
-}
-
-DEFUN(sms_send_imsi,
-      sms_send_imsi_cmd,
-      "sms send imsi IMSI .LINE",
-      "Send a message to a subscriber identified by IMSI")
-{
-	struct gsm_subscriber *receiver;
-	struct buffer *b;
-	int rc;
-
-	receiver = subscr_get_by_imsi(gsmnet, argv[0]);
-	if (!receiver)
-		return CMD_WARNING;
-
-	b = argv_to_buffer(argc, argv, 1);
-	rc = _send_sms_buffer(receiver, b);
-	buffer_free(b);
-
-	return rc;
-}
-
-
-DEFUN(cfg_subscr_name,
-      cfg_subscr_name_cmd,
-      "name NAME",
-      "Set the name of the subscriber")
-{
-	const char *name = argv[0];
-	struct gsm_subscriber *subscr = vty->index;
-
-	strncpy(subscr->name, name, sizeof(subscr->name));
-
-	db_sync_subscriber(subscr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_subscr_extension,
-      cfg_subscr_extension_cmd,
-      "extension EXTENSION",
-      "Set the extension of the subscriber")
-{
-	const char *name = argv[0];
-	struct gsm_subscriber *subscr = vty->index;
-
-	strncpy(subscr->extension, name, sizeof(subscr->extension));
-
-	db_sync_subscriber(subscr);
-
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_subscr_authorized,
-      cfg_subscr_authorized_cmd,
-      "auth <0-1>",
-      "Set the authorization status of the subscriber")
-{
-	int auth = atoi(argv[0]);
-	struct gsm_subscriber *subscr = vty->index;
-
-	if (auth)
-		subscr->authorized = 1;
-	else
-		subscr->authorized = 0;
-
-	db_sync_subscriber(subscr);
-
-	return CMD_SUCCESS;
-}
-
 int bsc_vty_init(struct gsm_network *net)
 {
 	gsmnet = net;
@@ -1391,13 +1147,6 @@
 
 	install_element(VIEW_NODE, &show_paging_cmd);
 
-	install_element(VIEW_NODE, &show_subscr_cmd);
-	install_element(VIEW_NODE, &show_subscr_cache_cmd);
-
-	install_element(VIEW_NODE, &sms_send_pend_cmd);
-	install_element(VIEW_NODE, &sms_send_ext_cmd);
-	install_element(VIEW_NODE, &sms_send_imsi_cmd);
-
 	install_element(CONFIG_NODE, &cfg_net_cmd);
 	install_node(&net_node, config_write_net);
 	install_default(GSMNET_NODE);
@@ -1438,12 +1187,7 @@
 	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);
-	install_default(SUBSCR_NODE);
-	install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
-	install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
-	install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
+	bsc_vty_init_extra(net);
 
 	return 0;
 }
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
new file mode 100644
index 0000000..032e16f
--- /dev/null
+++ b/openbsc/src/vty_interface_layer3.c
@@ -0,0 +1,315 @@
+/* OpenBSC interface to quagga VTY */
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <vty/command.h>
+#include <vty/buffer.h>
+#include <vty/vty.h>
+
+#include <arpa/inet.h>
+
+#include <openbsc/linuxlist.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_subscriber.h>
+#include <openbsc/gsm_04_11.h>
+#include <openbsc/e1_input.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/gsm_utils.h>
+#include <openbsc/db.h>
+#include <openbsc/talloc.h>
+
+/* forward declarations */
+void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr);
+
+static struct gsm_network *gsmnet;
+
+struct cmd_node subscr_node = {
+	SUBSCR_NODE,
+	"%s(subscriber)#",
+	1,
+};
+
+static int dummy_config_write(struct vty *v)
+{
+	return CMD_SUCCESS;
+}
+
+
+static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
+{
+	struct buffer *b = buffer_new(1024);
+	int i;
+
+	if (!b)
+		return NULL;
+
+	for (i = base; i < argc; i++) {
+		buffer_putstr(b, argv[i]);
+		buffer_putc(b, ' ');
+	}
+	buffer_putc(b, '\0');
+
+	return b;
+}
+
+/* per-subscriber configuration */
+DEFUN(cfg_subscr,
+      cfg_subscr_cmd,
+      "subscriber IMSI",
+      "Select a Subscriber to configure\n")
+{
+	const char *imsi = argv[0];
+	struct gsm_subscriber *subscr;
+
+	subscr = subscr_get_by_imsi(gsmnet, imsi);
+	if (!subscr) {
+		vty_out(vty, "%% No subscriber for IMSI %s%s",
+			imsi, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	vty->index = subscr;
+	vty->node = SUBSCR_NODE;
+
+	return CMD_SUCCESS;
+}
+
+/* Subscriber */
+DEFUN(show_subscr,
+      show_subscr_cmd,
+      "show subscriber [IMSI]",
+	SHOW_STR "Display information about a subscriber\n")
+{
+	const char *imsi;
+	struct gsm_subscriber *subscr;
+
+	if (argc >= 1) {
+		imsi = argv[0];
+		subscr = subscr_get_by_imsi(gsmnet, imsi);
+		if (!subscr) {
+			vty_out(vty, "%% unknown subscriber%s",
+				VTY_NEWLINE);
+			return CMD_WARNING;
+		}
+		subscr_dump_vty(vty, subscr);
+
+		return CMD_SUCCESS;
+	}
+
+	/* FIXME: iterate over all subscribers ? */
+	return CMD_WARNING;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(show_subscr_cache,
+      show_subscr_cache_cmd,
+      "show subscriber cache",
+	SHOW_STR "Display contents of subscriber cache\n")
+{
+	struct gsm_subscriber *subscr;
+
+	llist_for_each_entry(subscr, &active_subscribers, entry) {
+		vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
+		subscr_dump_vty(vty, subscr);
+	}
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(sms_send_pend,
+      sms_send_pend_cmd,
+      "sms send pending MIN_ID",
+      "Send all pending SMS starting from MIN_ID")
+{
+	struct gsm_sms *sms;
+	int id = atoi(argv[0]);
+
+	while (1) {
+		sms = db_sms_get_unsent(gsmnet, id++);
+		if (!sms)
+			return CMD_WARNING;
+
+		if (!sms->receiver) {
+			sms_free(sms);
+			continue;
+		}
+
+		gsm411_send_sms_subscr(sms->receiver, sms);
+	}
+
+	return CMD_SUCCESS;
+}
+
+struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text)
+{
+	struct gsm_sms *sms = sms_alloc();
+
+	if (!sms)
+		return NULL;
+
+	if (!receiver->lac) {
+		/* subscriber currently not attached, store in database? */
+		return NULL;
+	}
+
+	sms->receiver = subscr_get(receiver);
+	strncpy(sms->text, text, sizeof(sms->text)-1);
+
+	/* FIXME: don't use ID 1 static */
+	sms->sender = subscr_get_by_id(gsmnet, 1);
+	sms->reply_path_req = 0;
+	sms->status_rep_req = 0;
+	sms->ud_hdr_ind = 0;
+	sms->protocol_id = 0; /* implicit */
+	sms->data_coding_scheme = 0; /* default 7bit */
+	strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1);
+	/* Generate user_data */
+	sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text);
+
+	return sms;
+}
+
+static int _send_sms_buffer(struct gsm_subscriber *receiver,
+			     struct buffer *b)
+{
+	struct gsm_sms *sms;
+
+	sms = sms_from_text(receiver, buffer_getstr(b));
+
+	gsm411_send_sms_subscr(receiver, sms);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(sms_send_ext,
+      sms_send_ext_cmd,
+      "sms send extension EXTEN .LINE",
+      "Send a message to a subscriber identified by EXTEN")
+{
+	struct gsm_subscriber *receiver;
+	struct buffer *b;
+	int rc;
+
+	receiver = subscr_get_by_extension(gsmnet, argv[0]);
+	if (!receiver)
+		return CMD_WARNING;
+
+	b = argv_to_buffer(argc, argv, 1);
+	rc = _send_sms_buffer(receiver, b);
+	buffer_free(b);
+
+	return rc;
+}
+
+DEFUN(sms_send_imsi,
+      sms_send_imsi_cmd,
+      "sms send imsi IMSI .LINE",
+      "Send a message to a subscriber identified by IMSI")
+{
+	struct gsm_subscriber *receiver;
+	struct buffer *b;
+	int rc;
+
+	receiver = subscr_get_by_imsi(gsmnet, argv[0]);
+	if (!receiver)
+		return CMD_WARNING;
+
+	b = argv_to_buffer(argc, argv, 1);
+	rc = _send_sms_buffer(receiver, b);
+	buffer_free(b);
+
+	return rc;
+}
+
+
+DEFUN(cfg_subscr_name,
+      cfg_subscr_name_cmd,
+      "name NAME",
+      "Set the name of the subscriber")
+{
+	const char *name = argv[0];
+	struct gsm_subscriber *subscr = vty->index;
+
+	strncpy(subscr->name, name, sizeof(subscr->name));
+
+	db_sync_subscriber(subscr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_subscr_extension,
+      cfg_subscr_extension_cmd,
+      "extension EXTENSION",
+      "Set the extension of the subscriber")
+{
+	const char *name = argv[0];
+	struct gsm_subscriber *subscr = vty->index;
+
+	strncpy(subscr->extension, name, sizeof(subscr->extension));
+
+	db_sync_subscriber(subscr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_subscr_authorized,
+      cfg_subscr_authorized_cmd,
+      "auth <0-1>",
+      "Set the authorization status of the subscriber")
+{
+	int auth = atoi(argv[0]);
+	struct gsm_subscriber *subscr = vty->index;
+
+	if (auth)
+		subscr->authorized = 1;
+	else
+		subscr->authorized = 0;
+
+	db_sync_subscriber(subscr);
+
+	return CMD_SUCCESS;
+}
+
+
+int bsc_vty_init_extra(struct gsm_network *net)
+{
+	gsmnet = net;
+
+	install_element(VIEW_NODE, &show_subscr_cmd);
+	install_element(VIEW_NODE, &show_subscr_cache_cmd);
+
+	install_element(VIEW_NODE, &sms_send_pend_cmd);
+	install_element(VIEW_NODE, &sms_send_ext_cmd);
+	install_element(VIEW_NODE, &sms_send_imsi_cmd);
+
+	install_element(CONFIG_NODE, &cfg_subscr_cmd);
+	install_node(&subscr_node, dummy_config_write);
+
+	install_default(SUBSCR_NODE);
+	install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
+	install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
+	install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
+
+	return 0;
+}