diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 6ffe1ade9..bb90705ab 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -20,6 +20,8 @@ #ifndef _DB_H #define _DB_H +#include + #include "gsm_subscriber.h" struct gsm_equipment; @@ -36,7 +38,7 @@ int db_fini(void); /* subscriber management */ struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin, - uint64_t smax); + uint64_t smax, bool alloc_exten); struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, const char *subscr); int db_sync_subscriber(struct gsm_subscriber *subscriber); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index e7cd520d2..bdcd0e0dc 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -21,12 +22,6 @@ struct gsm_subscriber_group; #define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3] -enum gsm_subscr_creation_mode { - GSM_SUBSCR_DONT_CREATE = 0, - GSM_SUBSCR_CREAT_W_RAND_EXT = 1, - GSM_SUBSCR_CREAT_W_REGEXP = 2, -}; - enum gsm_security_event { GSM_SECURITY_NOAVAIL, GSM_SECURITY_AUTH_FAILED, @@ -289,7 +284,8 @@ struct gsm_network { struct osmo_bsc_data *bsc_data; /* subscriber related features */ - int subscr_creation_mode; + bool auto_create_subscr; + bool auto_assign_exten; uint64_t ext_min; uint64_t ext_max; struct gsm_subscriber_group *subscr_group; diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 3cba5d1ae..3d7c2449b 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -5,6 +5,8 @@ #include #include +#include + #define GSM_NAME_LENGTH 160 #define GSM_EXTENSION_LENGTH 15 /* MSISDN can only be 15 digits length */ @@ -90,8 +92,7 @@ enum gsm_subscriber_update_reason { struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr); struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr); struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp, - const char *imsi, uint64_t smin, - uint64_t smax); + const char *imsi); struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_subscriber_group *sgrp, uint32_t tmsi); struct gsm_subscriber *subscr_get_by_imsi(struct gsm_subscriber_group *sgrp, diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 04f2cc690..b0e87648e 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -195,6 +195,10 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) if (net->authorized_reg_str) vty_out(vty, ", authorized regexp: %s", net->authorized_reg_str); vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, " Auto create subscriber: %s%s", + net->auto_create_subscr ? "yes" : "no", VTY_NEWLINE); + vty_out(vty, " Auto assign extension: %s%s", + net->auto_assign_exten ? "yes" : "no", VTY_NEWLINE); vty_out(vty, " Location updating reject cause: %u%s", net->reject_cause, VTY_NEWLINE); vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption, diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c index 4636d579e..0e99097e0 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -21,10 +21,13 @@ #include #include +#include + struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code, int (*mncc_recv)(struct gsm_network *, struct msgb *)) { struct gsm_network *net; + const char *default_regexp = "*"; net = talloc_zero(tall_bsc_ctx, struct gsm_network); if (!net) @@ -42,13 +45,18 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod return NULL; } + if (gsm_parse_reg(net, &net->authorized_regexp, &net->authorized_reg_str, 1, + &default_regexp) != 0) + return NULL; + /* Init back pointer */ net->bsc_data->auto_off_timeout = -1; net->bsc_data->network = net; INIT_LLIST_HEAD(&net->bsc_data->mscs); net->subscr_group->net = net; - net->subscr_creation_mode = GSM_SUBSCR_CREAT_W_RAND_EXT; + net->auto_create_subscr = true; + net->auto_assign_exten = true; net->country_code = country_code; net->network_code = network_code; diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c index a02db36b9..79e136d52 100644 --- a/openbsc/src/libmsc/ctrl_commands.c +++ b/openbsc/src/libmsc/ctrl_commands.c @@ -25,6 +25,8 @@ #include #include +#include + static bool alg_supported(const char *alg) { /* @@ -96,9 +98,7 @@ static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data) subscr = subscr_get_by_imsi(net->subscr_group, imsi); if (!subscr) - subscr = subscr_create_subscriber(net->subscr_group, imsi, - net->ext_min, - net->ext_max); + subscr = subscr_create_subscriber(net->subscr_group, imsi); if (!subscr) goto fail; diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index b3671393a..68eba3e17 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -519,7 +520,7 @@ int db_fini(void) } struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin, - uint64_t smax) + uint64_t smax, bool alloc_exten) { dbi_result result; struct gsm_subscriber *subscr; @@ -551,7 +552,8 @@ struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin, strncpy(subscr->imsi, imsi, sizeof(subscr->imsi)-1); dbi_result_free(result); LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); - db_subscriber_alloc_exten(subscr, smin, smax); + if (alloc_exten) + db_subscriber_alloc_exten(subscr, smin, smax); return subscr; } @@ -956,8 +958,11 @@ int db_sync_subscriber(struct gsm_subscriber *subscriber) dbi_conn_quote_string_copy(conn, subscriber->name, &q_name); - dbi_conn_quote_string_copy(conn, - subscriber->extension, &q_extension); + if (subscriber->extension[0] != '\0') + dbi_conn_quote_string_copy(conn, + subscriber->extension, &q_extension); + else + q_extension = strdup("NULL"); if (subscriber->tmsi != GSM_RESERVED_TMSI) { sprintf(tmsi, "%u", subscriber->tmsi); @@ -1062,15 +1067,17 @@ int db_subscriber_delete(struct gsm_subscriber *subscr) } dbi_result_free(result); - result = dbi_conn_queryf(conn, - "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s", - subscr->extension, subscr->extension); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete SMS for %llu\n", subscr->id); - return -1; + if (subscr->extension[0] != '\0') { + result = dbi_conn_queryf(conn, + "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s", + subscr->extension, subscr->extension); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to delete SMS for %llu\n", subscr->id); + return -1; + } + dbi_result_free(result); } - dbi_result_free(result); result = dbi_conn_queryf(conn, "DELETE FROM VLR WHERE subscriber_id=%llu", diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 67044971b..1b02efe42 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -530,15 +530,13 @@ static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, uint8_t id static struct gsm_subscriber *subscr_create(const struct gsm_network *net, const char *imsi) { - if (net->subscr_creation_mode == GSM_SUBSCR_DONT_CREATE) + if (!net->auto_create_subscr) return NULL; - if (net->subscr_creation_mode & GSM_SUBSCR_CREAT_W_REGEXP) - if (!subscr_regexp_check(net, imsi)) - return NULL; + if (!subscr_regexp_check(net, imsi)) + return NULL; - return subscr_create_subscriber(net->subscr_group, imsi, net->ext_min, - net->ext_max); + return subscr_create_subscriber(net->subscr_group, imsi); } /* Parse Chapter 9.2.11 Identity Response */ diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 1dc2cc26d..08198c765 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -203,10 +204,12 @@ void subscr_remove_request(struct subscr_request *request) } struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp, - const char *imsi, uint64_t smin, - uint64_t smax) + const char *imsi) { - struct gsm_subscriber *subscr = db_create_subscriber(imsi, smin, smax); + struct gsm_subscriber *subscr = db_create_subscriber(imsi, + sgrp->net->ext_min, + sgrp->net->ext_max, + sgrp->net->auto_assign_exten); if (subscr) subscr->group = sgrp; return subscr; diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index a035bf976..74da1d7dc 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -242,9 +242,7 @@ DEFUN(subscriber_create, if (subscr) db_sync_subscriber(subscr); else { - subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0], - gsmnet->ext_min, - gsmnet->ext_max); + subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]); if (!subscr) { vty_out(vty, "%% No subscriber created for IMSI %s%s", @@ -1044,6 +1042,8 @@ DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd, { struct gsm_network *gsmnet = gsmnet_from_vty(vty); uint64_t mi = atoi(argv[0]), ma = atoi(argv[1]); + gsmnet->auto_create_subscr = true; + gsmnet->auto_assign_exten = true; if (mi >= ma) { vty_out(vty, "Incorrect range: %s >= %s, expected MIN < MAX%s", argv[0], argv[1], VTY_NEWLINE); @@ -1055,15 +1055,13 @@ DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd, } DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd, - "subscriber-create-on-demand [regexp]", + "subscriber-create-on-demand [no-extension]", "Make a new record when a subscriber is first seen.\n" - "Create subscribers only if IMSI matches the regexp specified in " - "authorized-regexp command\n") + "Do not automatically assign extension to created subscribers\n") { struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->subscr_creation_mode = GSM_SUBSCR_CREAT_W_RAND_EXT; - if (argc) - gsmnet->subscr_creation_mode |= GSM_SUBSCR_CREAT_W_REGEXP; + gsmnet->auto_create_subscr = true; + gsmnet->auto_assign_exten = argc ? false : true; return CMD_SUCCESS; } @@ -1072,7 +1070,7 @@ DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd, NO_STR "Make a new record when a subscriber is first seen.\n") { struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->subscr_creation_mode = GSM_SUBSCR_DONT_CREATE; + gsmnet->auto_create_subscr = false; return CMD_SUCCESS; } @@ -1097,12 +1095,15 @@ DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd, static int config_write_nitb(struct vty *vty) { struct gsm_network *gsmnet = gsmnet_from_vty(vty); - enum gsm_subscr_creation_mode scm = gsmnet->subscr_creation_mode; - const char *reg = (scm & GSM_SUBSCR_CREAT_W_REGEXP) ? " regexp" : "", - *pref = scm ? "" : "no "; + vty_out(vty, "nitb%s", VTY_NEWLINE); - vty_out(vty, " %ssubscriber-create-on-demand%s%s", - pref, reg, VTY_NEWLINE); + if (!gsmnet->auto_create_subscr) + vty_out(vty, " no subscriber-create-on-demand%s", VTY_NEWLINE); + else + vty_out(vty, " subscriber-create-on-demand%s%s", + gsmnet->auto_assign_exten ? "" : " no-extension", + VTY_NEWLINE); + if (gsmnet->ext_min != GSM_MIN_EXTEN || gsmnet->ext_max != GSM_MAX_EXTEN) vty_out(vty, " subscriber-create-on-demand random %"PRIu64" %" PRIu64"%s", gsmnet->ext_min, gsmnet->ext_max, diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c index dc814813d..755a6e9eb 100644 --- a/openbsc/tests/db/db_test.c +++ b/openbsc/tests/db/db_test.c @@ -28,6 +28,7 @@ #include #include #include +#include #include static struct gsm_network dummy_net; @@ -159,12 +160,13 @@ static void test_sms_migrate(void) subscr_put(rcv_subscr); } -static void test_subs(const char *alice_imsi, char *imei1, char *imei2) +static void test_subs(const char *imsi, char *imei1, char *imei2, bool make_ext) { struct gsm_subscriber *alice = NULL, *alice_db; char scratch_str[256]; - alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN); + alice = db_create_subscriber(imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN, + make_ext); db_subscriber_assoc_imei(alice, imei1); if (imei2) db_subscriber_assoc_imei(alice, imei2); @@ -177,7 +179,7 @@ static void test_subs(const char *alice_imsi, char *imei1, char *imei2) COMPARE(alice, alice_db); SUBSCR_PUT(alice_db); /* Get by IMSI */ - alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi); + alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi); COMPARE(alice, alice_db); SUBSCR_PUT(alice_db); /* Get by id */ @@ -187,8 +189,14 @@ static void test_subs(const char *alice_imsi, char *imei1, char *imei2) SUBSCR_PUT(alice_db); /* Get by extension */ alice_db = db_get_subscriber(GSM_SUBSCRIBER_EXTENSION, alice->extension); - COMPARE(alice, alice_db); - SUBSCR_PUT(alice_db); + if (alice_db) { + if (!make_ext) + printf("FAIL: bogus extension created for IMSI %s\n", + imsi); + COMPARE(alice, alice_db); + SUBSCR_PUT(alice_db); + } else if (make_ext) + printf("FAIL: no subscriber extension for IMSI %s\n", imsi); SUBSCR_PUT(alice); } @@ -217,18 +225,22 @@ int main() struct gsm_subscriber *alice_db; char *alice_imsi = "3243245432345"; - alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN); + alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN, + true); db_sync_subscriber(alice); alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi); COMPARE(alice, alice_db); SUBSCR_PUT(alice_db); SUBSCR_PUT(alice); - test_subs("3693245423445", "1234567890", NULL); - test_subs("9993245423445", "1234567890", "6543560920"); + test_subs("3693245423445", "1234567890", NULL, true); + test_subs("9993245423445", "1234567890", "6543560920", true); + test_subs("3123122223445", "1234567890", NULL, false); + test_subs("9123121223445", "1234567890", "6543560920", false); /* create it again and see it fails */ - alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN); + alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN, + true); OSMO_ASSERT(!alice); test_sms(); diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index bae18669c..23939e84c 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -244,7 +244,7 @@ class TestVTYNITB(TestVTYGenericBSC): self.vty.command("configure terminal") self.vty.command("nitb") self.assertTrue(self.vty.verify("subscriber-create-on-demand", [''])) - self.assertTrue(self.vty.verify("subscriber-create-on-demand regexp", [''])) + self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", [''])) self.vty.command("end") def testSi2Q(self): @@ -400,6 +400,9 @@ class TestVTYNITB(TestVTYGenericBSC): self.vty.enable() imsi = "204300854013739" + imsi2 = "222301824913762" + imsi3 = "333500854113763" + imsi4 = "444583744053764" # Initially we don't have this subscriber self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi]) @@ -407,14 +410,60 @@ class TestVTYNITB(TestVTYGenericBSC): # Lets create one res = self.vty.command('subscriber create imsi '+imsi) self.assert_(res.find(" IMSI: "+imsi) > 0) + self.assert_(res.find("Extension") > 0) # Now we have it res = self.vty.command('show subscriber imsi '+imsi) self.assert_(res.find(" IMSI: "+imsi) > 0) + # With narrow random interval + self.vty.command("configure terminal") + self.vty.command("nitb") + self.assertTrue(self.vty.verify("subscriber-create-on-demand", [''])) + # wrong interval + res = self.vty.command("subscriber-create-on-demand random 221 122") + # error string will contain arguments + self.assert_(res.find("122") > 0) + self.assert_(res.find("221") > 0) + # correct interval - silent ok + self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 222", [''])) + self.vty.command("end") + + res = self.vty.command('subscriber create imsi ' + imsi2) + self.assert_(res.find(" IMSI: " + imsi2) > 0) + self.assert_(res.find("221") > 0 or res.find("222") > 0) + self.assert_(res.find(" Extension: ") > 0) + + # Without extension + self.vty.command("configure terminal") + self.vty.command("nitb") + self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", [''])) + self.vty.command("end") + res = self.vty.command('subscriber create imsi ' + imsi3) + self.assert_(res.find(" IMSI: " + imsi3) > 0) + self.assertEquals(res.find("Extension"), -1) + + # With extension again + self.vty.command("configure terminal") + self.vty.command("nitb") + self.assertTrue(self.vty.verify("no subscriber-create-on-demand", [''])) + self.assertTrue(self.vty.verify("subscriber-create-on-demand", [''])) + self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 666", [''])) + self.vty.command("end") + + res = self.vty.command('subscriber create imsi ' + imsi4) + self.assert_(res.find(" IMSI: " + imsi4) > 0) + self.assert_(res.find(" Extension: ") > 0) + # Delete it res = self.vty.command('subscriber imsi ' + imsi + ' delete') self.assert_("" == res) + res = self.vty.command('subscriber imsi ' + imsi2 + ' delete') + self.assert_("" == res) + res = self.vty.command('subscriber imsi ' + imsi3 + ' delete') + self.assert_("" == res) + res = self.vty.command('subscriber imsi ' + imsi4 + ' delete') + self.assert_("" == res) # Now it should not be there anymore res = self.vty.command('show subscriber imsi '+imsi)