NAT: move BSC config into separate file

Introduce new configuration option bscs-config-file which includes BSC
configuration from the given file. Both absolute and relative (to the
main config file) paths are supported.
Add 'show bscs-config' command to display current BSC configuration.
Note: it is still possible to have BSC configuration in the main
file (provided proper index number is used) and in runtime but BSC
configuration is no longer saved automatically. The management of
included configuration file is left to external tools.
Update configuration examples.

Fixes: OS#1669
Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c
index ab82adf..f433324 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -34,6 +34,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <libgen.h>
 
 #define _GNU_SOURCE
 #include <getopt.h>
@@ -1626,6 +1627,8 @@
 	local_addr.s_addr = INADDR_ANY;
 	handle_options(argc, argv);
 
+	nat->include_base = dirname(talloc_strdup(tall_bsc_ctx, config_file));
+
 	rate_ctr_init(tall_bsc_ctx);
 	osmo_stats_init(tall_bsc_ctx);
 
@@ -1651,7 +1654,7 @@
 	/* seed the PRNG */
 	srand(time(NULL));
 
-
+	LOGP(DNAT, LOGL_NOTICE, "BSCs configured from %s\n", nat->resolved_path);
 
 	/*
 	 * Setup the MGCP code..
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
index 4348d6f..b7b49e6 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
@@ -96,6 +96,8 @@
 	vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
 	vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
 	vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
+	if (_nat->include_file)
+		vty_out(vty, " bscs-config-file %s%s", _nat->include_file, VTY_NEWLINE);
 	if (_nat->token)
 		vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
 	vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE);
@@ -181,6 +183,14 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(show_bscs, show_bscs_cmd, "show bscs-config",
+      SHOW_STR "Show configured BSCs\n"
+      "Both from included file and vty\n")
+{
+	vty_out(vty, "BSCs configuration loaded from %s:%s", _nat->resolved_path,
+		VTY_NEWLINE);
+	return config_write_bsc(vty);
+}
 
 DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
       SHOW_STR "Display information about SCCP\n"
@@ -495,6 +505,34 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_nat_include,
+      cfg_nat_include_cmd,
+      "bscs-config-file NAME",
+      "Set the filename of the BSC configuration to include.\n"
+      "The filename to be included.")
+{
+	char *path;
+	int rc;
+
+	if ('/' == argv[0][0])
+		bsc_replace_string(_nat, &_nat->resolved_path, argv[0]);
+	else {
+		path = talloc_asprintf(_nat, "%s/%s", _nat->include_base,
+				       argv[0]);
+		bsc_replace_string(_nat, &_nat->resolved_path, path);
+		talloc_free(path);
+	}
+
+	rc = vty_read_config_file(_nat->resolved_path, NULL);
+	if (rc < 0) {
+		vty_out(vty, "Failed to parse the config file %s: %s%s",
+			_nat->resolved_path, strerror(-rc), VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	bsc_replace_string(_nat, &_nat->include_file, argv[0]);
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_nat_no_acc_lst_name,
       cfg_nat_no_acc_lst_name_cmd,
       "no access-list-name",
@@ -865,8 +903,11 @@
 	/* verify that the LACs are unique */
 	llist_for_each_entry(tmp, &_nat->bsc_configs, entry) {
 		if (bsc_config_handles_lac(tmp, lac)) {
-			vty_out(vty, "%% LAC %d is already used.%s", lac, VTY_NEWLINE);
-			return CMD_ERR_INCOMPLETE;
+			if (tmp->nr != conf->nr) {
+				vty_out(vty, "%% LAC %d is already used.%s", lac,
+					VTY_NEWLINE);
+				return CMD_ERR_INCOMPLETE;
+			}
 		}
 	}
 
@@ -1179,6 +1220,7 @@
 	install_element_ve(&show_msc_cmd);
 	install_element_ve(&test_regex_cmd);
 	install_element_ve(&show_bsc_mgcp_cmd);
+	install_element_ve(&show_bscs_cmd);
 	install_element_ve(&show_bar_lst_cmd);
 	install_element_ve(&show_prefix_tree_cmd);
 	install_element_ve(&show_ussd_connection_cmd);
@@ -1200,6 +1242,7 @@
 	install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
 	install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
 	install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd);
+	install_element(NAT_NODE, &cfg_nat_include_cmd);
 	install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd);
 	install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd);
 	install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd);
@@ -1236,7 +1279,7 @@
 
 	/* BSC subgroups */
 	install_element(NAT_NODE, &cfg_bsc_cmd);
-	install_node(&bsc_node, config_write_bsc);
+	install_node(&bsc_node, NULL);
 	vty_install_default(NAT_BSC_NODE);
 	install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd);
 	install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd);