bsc: Allow to generate new system information online

Increase the bcch_change_mark and generate a new copy of the
system information. Make the method public, add a small test
case. Manually verified using the FakeBTS. I don't know if
the MS will re-read these SIs.

Related: SYS#739
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 254feaf..8e95e64 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -423,6 +423,7 @@
 void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
 int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
 struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
+int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
 
 /* generic E1 line operations for all ISDN-based BTS. */
 extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c
index 09f9acc..6315c8a 100644
--- a/openbsc/src/libbsc/bsc_ctrl_commands.c
+++ b/openbsc/src/libbsc/bsc_ctrl_commands.c
@@ -184,6 +184,41 @@
 
 CTRL_CMD_DEFINE(bts_apply_config, "apply-configuration");
 
+static int verify_bts_si(struct ctrl_cmd *cmd, const char *v, void *d)
+{
+    return 0;
+}
+
+static int get_bts_si(struct ctrl_cmd *cmd, void *data)
+{
+	cmd->reply = "Write only attribute";
+	return CTRL_CMD_ERROR;
+}
+
+static int set_bts_si(struct ctrl_cmd *cmd, void *data)
+{
+	struct gsm_bts *bts = cmd->node;
+	struct gsm_bts_trx *trx;
+
+	/* Generate a new ID */
+	bts->bcch_change_mark += 1;
+	bts->bcch_change_mark %= 0x7;
+
+	llist_for_each_entry(trx, &bts->trx_list, list) {
+		int rc;
+
+		rc = gsm_bts_trx_set_system_infos(trx);
+		if (rc != 0) {
+			cmd->reply = "Failed to generate SI";
+			return CTRL_CMD_ERROR;
+		}
+	}
+
+	cmd->reply = "Generated new System Information";
+	return CTRL_CMD_REPLY;
+}
+CTRL_CMD_DEFINE(bts_si, "send-new-system-informations");
+
 /* TRX related commands below here */
 CTRL_HELPER_GET_INT(trx_max_power, struct gsm_bts_trx, max_power_red);
 static int verify_trx_max_power(struct ctrl_cmd *cmd, const char *value, void *_data)
@@ -237,6 +272,7 @@
 	rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_lac);
 	rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_ci);
 	rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_apply_config);
+	rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_si);
 
 	rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power);
 	return rc;
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 796d027..a59ab3d 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -121,7 +121,7 @@
 }
 
 /* set all system information types */
-static int set_system_infos(struct gsm_bts_trx *trx)
+int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx)
 {
 	int i, rc;
 	struct gsm_bts *bts = trx->bts;
@@ -269,7 +269,7 @@
 		rsl_nokia_si_begin(trx);
 	}
 
-	set_system_infos(trx);
+	gsm_bts_trx_set_system_infos(trx);
 
 	if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
 		/* channel unspecific, power reduction in 2 dB steps */
diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py
index d18e302..9858007 100644
--- a/openbsc/tests/ctrl_test_runner.py
+++ b/openbsc/tests/ctrl_test_runner.py
@@ -216,6 +216,16 @@
         self.assertEquals(r['mtype'], 'ERROR')
         self.assertEquals(r['error'], 'Input not within the range')
 
+    def testBtsGenerateSystemInformation(self):
+        r = self.do_get('bts.0.send-new-system-informations')
+        self.assertEquals(r['mtype'], 'ERROR')
+        self.assertEquals(r['error'], 'Write only attribute')
+
+        # No RSL links so it will fail
+        r = self.do_set('bts.0.send-new-system-informations', '1')
+        self.assertEquals(r['mtype'], 'ERROR')
+        self.assertEquals(r['error'], 'Failed to generate SI')
+
     def testTrxPowerRed(self):
         r = self.do_get('bts.0.trx.0.max-power-reduction')
         self.assertEquals(r['mtype'], 'GET_REPLY')