From af1b968b22fa36d11dc2a20cb35dcbddaba50b7b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 6 Jul 2015 15:54:25 +0200 Subject: [PATCH 1/5] sms: Move the routing of the sms to a separate function The "default-route" for SMPP will be used after a local subscriber look-up. Sometimes we want to route everything to SMPP. Make this possible by changing this routine. --- openbsc/src/libmsc/gsm_04_11.c | 89 +++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 1b2a42c4f..0150de628 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -277,6 +277,55 @@ static int gsm340_gen_sms_deliver_tpdu(struct msgb *msg, struct gsm_sms *sms) return msg->len - old_msg_len; } +int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, + struct gsm_sms *gsms, uint8_t sms_mti) +{ + int rc; + + /* determine gsms->receiver based on dialled number */ + gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group, + gsms->dst.addr); + if (!gsms->receiver) { +#ifdef BUILD_SMPP + rc = smpp_try_deliver(gsms, conn); + if (rc == 1) { + rc = 1; /* cause 1: unknown subscriber */ + osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + } else if (rc < 0) { + rc = 21; /* cause 21: short message transfer rejected */ + /* FIXME: handle the error somehow? */ + } +#else + rc = 1; /* cause 1: unknown subscriber */ + osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); +#endif + goto out; + } + + switch (sms_mti) { + case GSM340_SMS_SUBMIT_MS2SC: + /* MS is submitting a SMS */ + rc = gsm340_rx_sms_submit(msg, gsms); + break; + case GSM340_SMS_COMMAND_MS2SC: + case GSM340_SMS_DELIVER_REP_MS2SC: + LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); + rc = GSM411_RP_CAUSE_IE_NOTEXIST; + break; + default: + LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); + rc = GSM411_RP_CAUSE_IE_NOTEXIST; + break; + } + + if (!rc && !gsms->receiver) + rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; + +out: + return rc; +} + + /* process an incoming TPDU (called from RP-DATA) * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -392,45 +441,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m /* FIXME: This looks very wrong */ send_signal(0, NULL, gsms, 0); - /* determine gsms->receiver based on dialled number */ - gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group, - gsms->dst.addr); - if (!gsms->receiver) { -#ifdef BUILD_SMPP - rc = smpp_try_deliver(gsms, conn); - if (rc == 1) { - rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); - } else if (rc < 0) { - rc = 21; /* cause 21: short message transfer rejected */ - /* FIXME: handle the error somehow? */ - } -#else - rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); -#endif - goto out; - } - - switch (sms_mti) { - case GSM340_SMS_SUBMIT_MS2SC: - /* MS is submitting a SMS */ - rc = gsm340_rx_sms_submit(msg, gsms); - break; - case GSM340_SMS_COMMAND_MS2SC: - case GSM340_SMS_DELIVER_REP_MS2SC: - LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); - rc = GSM411_RP_CAUSE_IE_NOTEXIST; - break; - default: - LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); - rc = GSM411_RP_CAUSE_IE_NOTEXIST; - break; - } - - if (!rc && !gsms->receiver) - rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; - + rc = sms_route_mt_sms(conn, msg, gsms, sms_mti); out: sms_free(gsms); From e3c391e8d00b80cc2a2c2a71a52a077cc9aaf9d7 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 6 Jul 2015 16:40:01 +0200 Subject: [PATCH 2/5] sms: Put the try_deliver into the header file Even if it is using BSC/NITB types let's put it in the header file than just declaring it at a place that could bitrot in a way that doesn't lead a warning. --- openbsc/src/libmsc/gsm_04_11.c | 2 -- openbsc/src/libmsc/smpp_smsc.h | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 0150de628..82e9faedf 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -57,8 +57,6 @@ #ifdef BUILD_SMPP #include "smpp_smsc.h" -extern int smpp_try_deliver(struct gsm_sms *sms, - struct gsm_subscriber_connection *conn); #endif void *tall_gsms_ctx; diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h index 21d28dda6..8d31b2b14 100644 --- a/openbsc/src/libmsc/smpp_smsc.h +++ b/openbsc/src/libmsc/smpp_smsc.h @@ -131,4 +131,12 @@ int smpp_route_pfx_del(struct osmo_smpp_acl *acl, int smpp_vty_init(void); int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode); + + + +struct gsm_sms; +struct gsm_subscriber_connection; + +int smpp_try_deliver(struct gsm_sms *sms, + struct gsm_subscriber_connection *conn); #endif From dcbc83355e1d7243180d436cadabd913bee2c922 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 6 Jul 2015 16:40:51 +0200 Subject: [PATCH 3/5] sms: Simplify the return handling for SMPP routes/unroutable --- openbsc/src/libmsc/gsm_04_11.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 82e9faedf..2b6966d44 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -297,7 +297,7 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, rc = 1; /* cause 1: unknown subscriber */ osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); #endif - goto out; + return rc; } switch (sms_mti) { @@ -319,7 +319,6 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, if (!rc && !gsms->receiver) rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; -out: return rc; } From 42cf2e03c936d34c1bda7d491f9e367bf02dddce Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 6 Jul 2015 16:41:30 +0200 Subject: [PATCH 4/5] sms: Add a way to always route SMS through SMPP systems default-route would only be looked at after there has been no subscriber in the local database. Depending on the setup this is not what one wants. This has been discussed at the OsmoDevCon and there have been hacks in some branches. Let's introduce a VTY command to select if SMPP should be consulted first and then fallback to the current behavior. --- openbsc/src/libmsc/gsm_04_11.c | 21 +++++++++++++++++++++ openbsc/src/libmsc/smpp_openbsc.c | 5 +++++ openbsc/src/libmsc/smpp_smsc.h | 3 +++ openbsc/src/libmsc/smpp_vty.c | 22 ++++++++++++++++++++++ openbsc/tests/vty_test_runner.py | 22 ++++++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 2b6966d44..b316d6213 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -280,6 +280,27 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, { int rc; +#ifdef BUILD_SMPP + /* + * Route through SMPP first before going to the local database. In case + * of a unroutable message and no local subscriber, SMPP will be tried + * twice. In case of an unknown subscriber continue with the normal + * delivery of the SMS. + */ + if (smpp_route_smpp_first(gsms, conn)) { + rc = smpp_try_deliver(gsms, conn); + if (rc == 1) + goto try_local; + if (rc < 0) { + rc = 21; /* cause 21: short message transfer rejected */ + /* FIXME: handle the error somehow? */ + } + return rc; + } + +try_local: +#endif + /* determine gsms->receiver based on dialled number */ gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group, gsms->dst.addr); diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index b17222fb4..057a9d048 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -539,6 +539,11 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms, static struct smsc *g_smsc; +int smpp_route_smpp_first(struct gsm_sms *sms, struct gsm_subscriber_connection *conn) +{ + return g_smsc->smpp_first; +} + int smpp_try_deliver(struct gsm_sms *sms, struct gsm_subscriber_connection *conn) { struct osmo_esme *esme; diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h index 8d31b2b14..3dd656242 100644 --- a/openbsc/src/libmsc/smpp_smsc.h +++ b/openbsc/src/libmsc/smpp_smsc.h @@ -92,6 +92,7 @@ struct smsc { uint16_t listen_port; char system_id[SMPP_SYS_ID_LEN+1]; int accept_all; + int smpp_first; struct osmo_smpp_acl *def_route; void *priv; }; @@ -137,6 +138,8 @@ int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode); struct gsm_sms; struct gsm_subscriber_connection; +int smpp_route_smpp_first(struct gsm_sms *sms, + struct gsm_subscriber_connection *conn); int smpp_try_deliver(struct gsm_sms *sms, struct gsm_subscriber_connection *conn); #endif diff --git a/openbsc/src/libmsc/smpp_vty.c b/openbsc/src/libmsc/smpp_vty.c index 75427a9c0..c0695fe7a 100644 --- a/openbsc/src/libmsc/smpp_vty.c +++ b/openbsc/src/libmsc/smpp_vty.c @@ -58,6 +58,24 @@ DEFUN(cfg_smpp, cfg_smpp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_smpp_first, cfg_smpp_first_cmd, + "smpp-first", + "Try SMPP routes before the subscriber DB\n") +{ + struct smsc *smsc = smsc_from_vty(vty); + smsc->smpp_first = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_no_smpp_first, cfg_no_smpp_first_cmd, + "no smpp-first", + NO_STR "Try SMPP before routes before the subscriber DB\n") +{ + struct smsc *smsc = smsc_from_vty(vty); + smsc->smpp_first = 0; + return CMD_SUCCESS; +} + DEFUN(cfg_smpp_port, cfg_smpp_port_cmd, "local-tcp-port <1-65535>", "Set the local TCP port on which we listen for SMPP\n" @@ -125,6 +143,8 @@ static int config_write_smpp(struct vty *vty) vty_out(vty, " system-id %s%s", smsc->system_id, VTY_NEWLINE); vty_out(vty, " policy %s%s", smsc->accept_all ? "accept-all" : "closed", VTY_NEWLINE); + vty_out(vty, " %ssmpp-first%s", + smsc->smpp_first ? "" : "no ", VTY_NEWLINE); return CMD_SUCCESS; } @@ -512,6 +532,8 @@ int smpp_vty_init(void) vty_install_default(SMPP_NODE); install_element(CONFIG_NODE, &cfg_smpp_cmd); + install_element(SMPP_NODE, &cfg_smpp_first_cmd); + install_element(SMPP_NODE, &cfg_no_smpp_first_cmd); install_element(SMPP_NODE, &cfg_smpp_port_cmd); install_element(SMPP_NODE, &cfg_smpp_sys_id_cmd); install_element(SMPP_NODE, &cfg_smpp_policy_cmd); diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index 4cd46653e..1aedcf21c 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -154,6 +154,28 @@ class TestVTYNITB(TestVTYGenericBSC): res = self.vty.command("list") return "smpp" in res + def testSmppFirst(self): + if not self.checkForSmpp(): + return + + # enable the configuration + self.vty.enable() + self.vty.command("configure terminal") + self.vty.command("smpp") + + # check the default + res = self.vty.command("write terminal") + self.assert_(res.find(' no smpp-first') > 0) + + self.vty.verify("smpp-first", ['']) + res = self.vty.command("write terminal") + self.assert_(res.find(' smpp-first') > 0) + self.assertEquals(res.find('no smpp-first'), -1) + + self.vty.verify("no smpp-first", ['']) + res = self.vty.command("write terminal") + self.assert_(res.find('no smpp-first') > 0) + def testVtyTree(self): self.vty.enable() self.assertTrue(self.vty.verify("configure terminal", [''])) From 7c19c6b4064b10511fa5f5327030c21616905d94 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 13 Jul 2015 10:39:51 +0200 Subject: [PATCH 5/5] sms: Do not go through the routing a second time If we have tried SMPP first and it was not routable, and then tried the local delivery there is no point in trying SMPP with the same parameters again. Leave early and return unknown sub to the caller. --- openbsc/src/libmsc/gsm_04_11.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index b316d6213..c2cec26cd 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -281,13 +281,15 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, int rc; #ifdef BUILD_SMPP + int smpp_first = smpp_route_smpp_first(gsms, conn); + /* * Route through SMPP first before going to the local database. In case * of a unroutable message and no local subscriber, SMPP will be tried * twice. In case of an unknown subscriber continue with the normal * delivery of the SMS. */ - if (smpp_route_smpp_first(gsms, conn)) { + if (smpp_first) { rc = smpp_try_deliver(gsms, conn); if (rc == 1) goto try_local; @@ -306,6 +308,10 @@ try_local: gsms->dst.addr); if (!gsms->receiver) { #ifdef BUILD_SMPP + /* Avoid a second look-up */ + if (smpp_first) + return 1; /* cause 1: unknown subscriber */ + rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */