[PATCH 1/4] ussd: Send USSD on call setup on MSC errors

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Jacob Erlbeck jerlbeck at sysmocom.de
Wed Sep 11 08:46:55 UTC 2013


Send an USSD message to the mobile station requesting a connection
for a call or a SMS when the link to the MSC is down or in the
grace period.

The messages can be set (and this feature activated) by setting
bsc/missing-msc-text resp. msc/bsc-grace-text via the vty.

The generation of both messages has been tested manually.

Ticket: OW#957
---
 openbsc/include/openbsc/osmo_bsc.h      |   11 ++++-
 openbsc/include/openbsc/osmo_msc_data.h |    6 +++
 openbsc/src/osmo-bsc/osmo_bsc_api.c     |   58 ++++++++++++++++++++++++-
 openbsc/src/osmo-bsc/osmo_bsc_sccp.c    |   16 ++++---
 openbsc/src/osmo-bsc/osmo_bsc_vty.c     |   71 +++++++++++++++++++++++++++++++
 openbsc/tests/vty_test_runner.py        |   35 ++++++++++++++-
 6 files changed, 185 insertions(+), 12 deletions(-)

diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h
index 1d216ac..1032daa 100644
--- a/openbsc/include/openbsc/osmo_bsc.h
+++ b/openbsc/include/openbsc/osmo_bsc.h
@@ -7,6 +7,13 @@
 
 #define BSS_SEND_USSD 1
 
+enum bsc_con {
+	BSC_CON_SUCCESS,
+	BSC_CON_REJECT_NO_LINK,
+	BSC_CON_REJECT_RF_GRACE,
+	BSC_CON_NO_MEM,
+};
+
 struct sccp_connection;
 struct osmo_msc_data;
 struct bsc_msc_connection;
@@ -34,8 +41,8 @@ struct bsc_api *osmo_bsc_api();
 
 int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
 int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
-int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
-			      struct osmo_msc_data *msc);
+enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
+				       struct osmo_msc_data *msc);
 int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
 
 struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
diff --git a/openbsc/include/openbsc/osmo_msc_data.h b/openbsc/include/openbsc/osmo_msc_data.h
index 86b4a84..9c312ca 100644
--- a/openbsc/include/openbsc/osmo_msc_data.h
+++ b/openbsc/include/openbsc/osmo_msc_data.h
@@ -86,6 +86,9 @@ struct osmo_msc_data {
 
 	/* ussd msc connection lost text */
 	char *ussd_msc_lost_txt;
+
+	/* ussd text when MSC has entered the grace period */
+	char *ussd_grace_txt;
 };
 
 /*
@@ -103,6 +106,9 @@ struct osmo_bsc_data {
 	char *rf_ctrl_name;
 	struct osmo_bsc_rf *rf_ctrl;
 	int auto_off_timeout;
+
+	/* ussd text when there is no MSC available */
+	char *ussd_no_msc_txt;
 };
 
 
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c
index df8c044..5eb3de6 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_api.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c
@@ -85,6 +85,48 @@ static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
 	queue_msg_or_return(resp);
 }
 
+static void bsc_send_ussd_notification(struct gsm_subscriber_connection *conn,
+			   struct msgb *msg, const char *text)
+{
+	struct gsm48_hdr *gh;
+	int8_t pdisc;
+	uint8_t mtype;
+	int drop_message = 1;
+
+	if (! text)
+		return;
+
+	if (! msg || msgb_l3len(msg) < sizeof(*gh)) {
+		return;
+	}
+
+	gh = msgb_l3(msg);
+	pdisc = gh->proto_discr & 0x0f;
+	mtype = gh->msg_type & 0xbf;
+
+	/* Is CM service request? */
+	if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
+		struct gsm48_service_request *cm;
+
+		cm = (struct gsm48_service_request *) &gh->data[0];
+
+		/* Is type SMS or call? */
+		if (cm->cm_service_type == GSM48_CMSERV_SMS)
+			drop_message = 0;
+		else if (cm->cm_service_type == GSM48_CMSERV_MO_CALL_PACKET)
+			drop_message = 0;
+	}
+
+	if (drop_message) {
+		LOGP(DMSC, LOGL_DEBUG, "Skipping (not sending) USSD message: '%s'\n", text);
+		return;
+	}
+
+	LOGP(DMSC, LOGL_INFO, "Sending USSD message: '%s'\n", text);
+	gsm0480_send_ussdNotify(conn, 1, text);
+	gsm0480_send_releaseComplete(conn);
+}
+
 /*
  * Instruct to reserve data for a new connectiom, create the complete
  * layer three message, send it to open the connection.
@@ -100,6 +142,7 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
 	msc = bsc_find_msc(conn, msg);
 	if (!msc) {
 		LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
+		bsc_send_ussd_notification(conn, msg, conn->bts->network->bsc_data->ussd_no_msc_txt);
 		return -1;
 	}
 
@@ -112,10 +155,23 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
 	struct msgb *resp;
 	uint16_t network_code;
 	uint16_t country_code;
+	enum bsc_con ret;
 
 	/* allocate resource for a new connection */
-	if (bsc_create_new_connection(conn, msc) != 0)
+	ret = bsc_create_new_connection(conn, msc);
+
+	if (ret != BSC_CON_SUCCESS) {
+		/* allocation has failed */
+		if (ret == BSC_CON_REJECT_NO_LINK) {
+			bsc_send_ussd_notification(conn, msg, msc->ussd_msc_lost_txt);
+		} else if (ret == BSC_CON_REJECT_RF_GRACE) {
+			bsc_send_ussd_notification(conn, msg, msc->ussd_grace_txt);
+		}
+
 		return BSC_API_CONN_POL_REJECT;
+	}
+
+	// check return value, if failed check msg for  and send USSD
 
 	network_code = get_network_code_for_msc(conn->sccp_con->msc);
 	country_code = get_country_code_for_msc(conn->sccp_con->msc);
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
index 87f415e..deda0be 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c
@@ -188,35 +188,37 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
 	return 0;
 }
 
-int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
+enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
 			      struct osmo_msc_data *msc)
 {
 	struct osmo_bsc_sccp_con *bsc_con;
 	struct sccp_connection *sccp;
 
 	/* This should not trigger */
-	if (!msc->msc_con->is_authenticated) {
+	if (!msc || !msc->msc_con->is_authenticated) {
+		// VSAT link down
 		LOGP(DMSC, LOGL_ERROR,
 		     "How did this happen? MSC is not connected. Dropping.\n");
-		return -1;
+		return BSC_CON_REJECT_NO_LINK;
 	}
 
 	if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
+		// Approaching shore
 		LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
-		return -1;
+		return BSC_CON_REJECT_RF_GRACE;
 	}
 
 	sccp = sccp_connection_socket();
 	if (!sccp) {
 		LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
-		return -ENOMEM;
+		return BSC_CON_NO_MEM;
 	}
 
 	bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
 	if (!bsc_con) {
 		LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
 		sccp_connection_free(sccp);
-		return -1;
+		return BSC_CON_NO_MEM;
 	}
 
 	/* callbacks */
@@ -237,7 +239,7 @@ int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
 	bsc_con->conn = conn;
 	llist_add_tail(&bsc_con->entry, &active_connections);
 	conn->sccp_con = bsc_con;
-	return 0;
+	return BSC_CON_SUCCESS;
 }
 
 int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
index 90b0a0c..6f7cdbf 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
@@ -122,6 +122,11 @@ static void write_msc(struct vty *vty, struct osmo_msc_data *msc)
 	else
 		vty_out(vty, " no bsc-msc-lost-text%s", VTY_NEWLINE);
 
+	if (msc->ussd_grace_txt && msc->ussd_grace_txt[0])
+		vty_out(vty, " bsc-grace-text %s%s", msc->ussd_grace_txt, VTY_NEWLINE);
+	else
+		vty_out(vty, " no bsc-grace-text%s", VTY_NEWLINE);
+
 	if (msc->audio_length != 0) {
 		int i;
 
@@ -182,6 +187,11 @@ static int config_write_bsc(struct vty *vty)
 		vty_out(vty, " bsc-auto-rf-off %d%s",
 			bsc->auto_off_timeout, VTY_NEWLINE);
 
+	if (bsc->ussd_no_msc_txt && bsc->ussd_no_msc_txt[0])
+		vty_out(vty, " missing-msc-text %s%s", bsc->ussd_no_msc_txt, VTY_NEWLINE);
+	else
+		vty_out(vty, " no missing-msc-text%s", VTY_NEWLINE);
+
 	return CMD_SUCCESS;
 }
 
@@ -417,6 +427,63 @@ DEFUN(cfg_net_msc_no_lost_ussd,
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_net_msc_grace_ussd,
+      cfg_net_msc_grace_ussd_cmd,
+      "bsc-grace-text .TEXT",
+      "Set the USSD notification to be sent when the MSC has entered the grace period\n" "Text to be sent\n")
+{
+	struct osmo_msc_data *data = osmo_msc_data(vty);
+	char *str = argv_concat(argv, argc, 0);
+	if (!str)
+		return CMD_WARNING;
+
+	bsc_replace_string(osmo_bsc_data(vty), &data->ussd_grace_txt, str);
+	talloc_free(str);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_msc_no_grace_ussd,
+      cfg_net_msc_no_grace_ussd_cmd,
+      "no bsc-grace-text",
+      NO_STR "Clear the USSD notification to be sent when the MSC has entered the grace period\n")
+{
+	struct osmo_msc_data *data = osmo_msc_data(vty);
+
+	talloc_free(data->ussd_grace_txt);
+	data->ussd_grace_txt = 0;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_bsc_missing_msc_ussd,
+      cfg_net_bsc_missing_msc_ussd_cmd,
+      "missing-msc-text .TEXT",
+      "Set the USSD notification to be send when a MSC has not been found.\n" "Text to be sent\n")
+{
+	struct osmo_bsc_data *data = osmo_bsc_data(vty);
+	char *txt = argv_concat(argv, argc, 0);
+	if (!txt)
+		return CMD_WARNING;
+
+	bsc_replace_string(data, &data->ussd_no_msc_txt, txt);
+	talloc_free(txt);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_bsc_no_missing_msc_text,
+      cfg_net_bsc_no_missing_msc_text_cmd,
+      "no missing-msc-text",
+      NO_STR "Clear the USSD notification to be send when a MSC has not been found.\n")
+{
+	struct osmo_bsc_data *data = osmo_bsc_data(vty);
+
+	talloc_free(data->ussd_no_msc_txt);
+	data->ussd_no_msc_txt = 0;
+
+	return CMD_SUCCESS;
+}
+
+
 DEFUN(cfg_net_msc_type,
       cfg_net_msc_type_cmd,
       "type (normal|local)",
@@ -615,6 +682,8 @@ int bsc_vty_init_extra(void)
 	install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
 	install_element(BSC_NODE, &cfg_net_rf_off_time_cmd);
 	install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd);
+	install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd);
+	install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd);
 
 	install_node(&msc_node, config_write_msc);
 	bsc_install_default(MSC_NODE);
@@ -631,6 +700,8 @@ int bsc_vty_init_extra(void)
 	install_element(MSC_NODE, &cfg_net_msc_no_welcome_ussd_cmd);
 	install_element(MSC_NODE, &cfg_net_msc_lost_ussd_cmd);
 	install_element(MSC_NODE, &cfg_net_msc_no_lost_ussd_cmd);
+	install_element(MSC_NODE, &cfg_net_msc_grace_ussd_cmd);
+	install_element(MSC_NODE, &cfg_net_msc_no_grace_ussd_cmd);
 	install_element(MSC_NODE, &cfg_net_msc_type_cmd);
 	install_element(MSC_NODE, &cfg_net_msc_emerg_cmd);
 	install_element(MSC_NODE, &cfg_net_msc_local_prefix_cmd);
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index ab9670c..460b70e 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -207,7 +207,7 @@ class TestVTYBSC(TestVTYGenericBSC):
         self.vty.command("msc 0")
         self.assertEquals(self.vty.node(), 'config-msc')
 
-    def testUssdNotifications(self):
+    def testUssdNotificationsMsc(self):
         self.vty.enable()
         self.vty.command("configure terminal")
         self.vty.command("msc")
@@ -215,10 +215,12 @@ class TestVTYBSC(TestVTYGenericBSC):
         # Test invalid input
         self.vty.verify("bsc-msc-lost-text", ['% Command incomplete.'])
         self.vty.verify("bsc-welcome-text", ['% Command incomplete.'])
+        self.vty.verify("bsc-grace-text", ['% Command incomplete.'])
 
         # Enable USSD notifications
         self.vty.verify("bsc-msc-lost-text MSC disconnected", [''])
         self.vty.verify("bsc-welcome-text Hello MS", [''])
+        self.vty.verify("bsc-grace-text In grace period", [''])
 
         # Verify settings
         res = self.vty.command("write terminal")
@@ -226,17 +228,46 @@ class TestVTYBSC(TestVTYGenericBSC):
         self.assertEquals(res.find('no bsc-msc-lost-text'), -1)
         self.assert_(res.find('bsc-welcome-text Hello MS') > 0)
         self.assertEquals(res.find('no bsc-welcome-text'), -1)
+        self.assert_(res.find('bsc-grace-text In grace period') > 0)
+        self.assertEquals(res.find('no bsc-grace-text'), -1)
 
         # Now disable it..
         self.vty.verify("no bsc-msc-lost-text", [''])
         self.vty.verify("no bsc-welcome-text", [''])
+        self.vty.verify("no bsc-grace-text", [''])
 
         # Verify settings
         res = self.vty.command("write terminal")
         self.assertEquals(res.find('bsc-msc-lost-text MSC disconnected'), -1)
         self.assert_(res.find('no bsc-msc-lost-text') > 0)
-        self.assert_(res.find('no bsc-welcome-text') > 0)
         self.assertEquals(res.find('bsc-welcome-text Hello MS'), -1)
+        self.assert_(res.find('no bsc-welcome-text') > 0)
+        self.assertEquals(res.find('bsc-grace-text In grace period'), -1)
+        self.assert_(res.find('no bsc-grace-text') > 0)
+
+    def testUssdNotificationsBsc(self):
+        self.vty.enable()
+        self.vty.command("configure terminal")
+        self.vty.command("bsc")
+
+        # Test invalid input
+        self.vty.verify("missing-msc-text", ['% Command incomplete.'])
+
+        # Enable USSD notifications
+        self.vty.verify("missing-msc-text No MSC found", [''])
+
+        # Verify settings
+        res = self.vty.command("write terminal")
+        self.assert_(res.find('missing-msc-text No MSC found') > 0)
+        self.assertEquals(res.find('no missing-msc-text'), -1)
+
+        # Now disable it..
+        self.vty.verify("no missing-msc-text", [''])
+
+        # Verify settings
+        res = self.vty.command("write terminal")
+        self.assertEquals(res.find('missing-msc-text No MSC found'), -1)
+        self.assert_(res.find('no missing-msc-text') > 0)
 
 class TestVTYNAT(TestVTYGenericBSC):
 
-- 
1.7.9.5





More information about the OpenBSC mailing list