@@ -20,6 +20,8 @@
#ifndef _DB_H
#define _DB_H
+#include <stdbool.h>
+
#include "gsm_subscriber.h"
struct gsm_equipment;
@@ -35,13 +37,15 @@ int db_prepare(void);
int db_fini(void);
/* subscriber management */
-struct gsm_subscriber *db_create_subscriber(const char *imsi);
+struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin,
+ 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);
int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id));
int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber);
-int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber);
+int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
+ uint64_t smax);
int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t* token);
int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char *imei);
int db_subscriber_delete(struct gsm_subscriber *subscriber);
@@ -24,6 +24,7 @@ enum gsm_subscr_ext_alloc_policy {
GSM_SUBSCR_DONT_CREATE = 0,
GSM_SUBSCR_RANDOM_EXT = 1,
GSM_SUBSCR_MATCH_PREF = 2,
+ GSM_SUBSCR_NO_EXT = 4
};
enum gsm_security_event {
@@ -293,6 +294,8 @@ struct gsm_network {
/* subscriber related features */
int create_subscriber;
+ uint64_t ext_min;
+ uint64_t ext_max;
struct gsm_subscriber_group *subscr_group;
struct gsm_sms_queue *sms_queue;
@@ -1,6 +1,8 @@
#ifndef _GSM_SUBSCR_H
#define _GSM_SUBSCR_H
+#include <stdbool.h>
+
#include "gsm_data.h"
#include <osmocom/core/linuxlist.h>
@@ -90,7 +92,8 @@ 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);
+ const char *imsi, uint64_t smin,
+ uint64_t smax, bool ext);
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,
@@ -105,7 +105,8 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail");
net->mncc_recv = mncc_recv;
-
+ net->ext_min = GSM_MIN_EXTEN;
+ net->ext_max = GSM_MAX_EXTEN;
gsm_net_update_ctype(net);
return net;
@@ -60,6 +60,7 @@ struct gsm_subscriber *subscr_alloc(void)
llist_add_tail(&s->entry, &active_subscribers);
s->use_count = 1;
s->tmsi = GSM_RESERVED_TMSI;
+ s->extension[0] = '\0';
INIT_LLIST_HEAD(&s->requests);
@@ -18,6 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
+#include <stdbool.h>
+
#include <osmocom/ctrl/control_cmd.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
@@ -83,6 +86,8 @@ static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data)
char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL;
struct gsm_subscriber* subscr;
int rc;
+ bool ext = (GSM_SUBSCR_RANDOM_EXT & net->create_subscriber) ? true :
+ false;
tmp = talloc_strdup(cmd, cmd->value);
if (!tmp)
@@ -95,7 +100,9 @@ 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);
+ subscr = subscr_create_subscriber(net->subscr_group, imsi,
+ net->ext_min,
+ net->ext_max, ext);
if (!subscr)
goto fail;
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <libgen.h>
#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -500,7 +501,8 @@ int db_fini(void)
return 0;
}
-struct gsm_subscriber *db_create_subscriber(const char *imsi)
+struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin,
+ uint64_t smax, bool alloc_exten)
{
dbi_result result;
struct gsm_subscriber *subscr;
@@ -532,7 +534,8 @@ struct gsm_subscriber *db_create_subscriber(const char *imsi)
strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-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);
+ if (alloc_exten)
+ db_subscriber_alloc_exten(subscr, smin, smax);
return subscr;
}
@@ -937,8 +940,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);
@@ -1043,15 +1049,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",
@@ -1231,13 +1239,14 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
return 0;
}
-int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber)
+int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
+ uint64_t smax)
{
dbi_result result = NULL;
uint32_t try;
for (;;) {
- try = (rand()%(GSM_MAX_EXTEN-GSM_MIN_EXTEN+1)+GSM_MIN_EXTEN);
+ try = (rand() % (smax - smin + 1) + smin);
result = dbi_conn_queryf(conn,
"SELECT * FROM Subscriber "
"WHERE extension = %i",
@@ -523,14 +523,19 @@ 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)
{
+ const char *ap = net->auth_prefix;
+ bool ext = (GSM_SUBSCR_RANDOM_EXT & net->create_subscriber) ? true :
+ false;
+
if (GSM_SUBSCR_DONT_CREATE == net->create_subscriber)
return NULL;
if (net->create_subscriber & GSM_SUBSCR_MATCH_PREF)
- if (!subscr_prefix_check(net->auth_prefix, imsi))
+ if (!subscr_prefix_check(ap, imsi))
return NULL;
- return subscr_create_subscriber(net->subscr_group, imsi);
+ return subscr_create_subscriber(net->subscr_group, imsi, net->ext_min,
+ net->ext_max, ext);
}
/* Parse Chapter 9.2.11 Identity Response */
@@ -582,7 +587,6 @@ static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *ms
return gsm0408_authorize(conn, msg);
}
-
static void loc_upd_rej_cb(void *data)
{
struct gsm_subscriber_connection *conn = data;
@@ -203,9 +203,11 @@ void subscr_remove_request(struct subscr_request *request)
}
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
- const char *imsi)
+ const char *imsi, uint64_t smin,
+ uint64_t smax, bool ext)
{
- struct gsm_subscriber *subscr = db_create_subscriber(imsi);
+ struct gsm_subscriber *subscr =
+ db_create_subscriber(imsi, smin, smax, ext);
if (subscr)
subscr->group = sgrp;
return subscr;
@@ -21,6 +21,8 @@
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
+#include <stdbool.h>
+#include <inttypes.h>
#include <time.h>
#include <osmocom/vty/command.h>
@@ -235,12 +237,16 @@ DEFUN(subscriber_create,
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
struct gsm_subscriber *subscr;
+ bool ext = (GSM_SUBSCR_RANDOM_EXT == gsmnet->create_subscriber) ? true :
+ false;
subscr = subscr_get_by_imsi(gsmnet->subscr_group, argv[0]);
if (subscr)
db_sync_subscriber(subscr);
else {
- subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]);
+ subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0],
+ gsmnet->ext_min,
+ gsmnet->ext_max, ext);
if (!subscr) {
vty_out(vty, "%% No subscriber created for IMSI %s%s",
@@ -1031,6 +1037,34 @@ DEFUN(cfg_nitb, cfg_nitb_cmd,
return CMD_SUCCESS;
}
+/* Note: limit on the prefix length is set by internal vty code limitations */
+DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd,
+ "subscriber-create-on-demand random <1-9999999999> <2-9999999999>",
+ "Set random parameters for a new record when a subscriber is first seen.\n"
+ "Set random parameters for a new record when a subscriber is first seen.\n"
+ "Minimum for subscriber extension\n""Maximum for subscriber extension\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ uint64_t mi = atoi(argv[0]), ma = atoi(argv[1]);
+ if (mi >= ma) {
+ vty_out(vty, "Incorrect range: %s >= %s, expected MIN < MAX%s",
+ argv[0], argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ gsmnet->ext_min = mi;
+ gsmnet->ext_max = ma;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nitb_subscr_noext, cfg_nitb_subscr_noext_cmd,
+ "subscriber-create-no-extension",
+ "Do not assign extension when creating subscriber on demand.\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ gsmnet->create_subscriber |= GSM_SUBSCR_NO_EXT;
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
"subscriber-create-on-demand [imsi-prefix]",
"Make a new record when a subscriber is first seen.\n"
@@ -1038,9 +1072,11 @@ DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
"authorize-prefix command \n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->create_subscriber = GSM_SUBSCR_RANDOM_EXT;
+ if (!gsmnet->create_subscriber)
+ gsmnet->create_subscriber = GSM_SUBSCR_RANDOM_EXT;
if (argc)
gsmnet->create_subscriber |= GSM_SUBSCR_MATCH_PREF;
+
return CMD_SUCCESS;
}
@@ -1079,8 +1115,15 @@ static int config_write_nitb(struct vty *vty)
" imsi-prefix" : "";
vty_out(vty, "nitb%s", VTY_NEWLINE);
- vty_out(vty, " %ssubscriber-create-on-demand%s%s",
- pref, ims, VTY_NEWLINE);
+ vty_out(vty, " %ssubscriber-create-on-demand%s%s", pref, ims,
+ VTY_NEWLINE);
+ if (gsmnet->create_subscriber & GSM_SUBSCR_NO_EXT)
+ vty_out(vty, " subscriber-create-no-extension%s", 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,
+ VTY_NEWLINE);
+
vty_out(vty, " %sassign-tmsi%s",
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
return CMD_SUCCESS;
@@ -1135,6 +1178,8 @@ int bsc_vty_init_extra(void)
install_element(CONFIG_NODE, &cfg_nitb_cmd);
install_node(&nitb_node, config_write_nitb);
install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd);
+ install_element(NITB_NODE, &cfg_nitb_subscr_noext_cmd);
+ install_element(NITB_NODE, &cfg_nitb_subscr_random_cmd);
install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd);
install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd);
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <inttypes.h>
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 *alice_imsi, char *imei1, char *imei2, bool ext)
{
struct gsm_subscriber *alice = NULL, *alice_db;
char scratch_str[256];
- alice = db_create_subscriber(alice_imsi);
+ alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+ ext);
db_subscriber_assoc_imei(alice, imei1);
if (imei2)
db_subscriber_assoc_imei(alice, imei2);
@@ -219,18 +221,22 @@ int main()
struct gsm_subscriber *alice_db;
char *alice_imsi = "3243245432345";
- alice = db_create_subscriber(alice_imsi);
+ 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);
+ alice = db_create_subscriber(alice_imsi, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+ true);
OSMO_ASSERT(!alice);
test_sms();
@@ -422,11 +422,15 @@ class TestVTYNITB(TestVTYGenericBSC):
self.vty.enable()
imsi = "204300854013739"
+ imsi2 = "204301824913769"
+ imsi3 = "100500854113769"
+ imsi4 = "100583744053769"
wrong_imsi = "204300999999999"
# Lets create one
res = self.vty.command('subscriber create imsi '+imsi)
self.assert_(res.find(" IMSI: "+imsi) > 0)
+ self.assert_(res.find("Extension") > 0)
self.vty.verify('subscriber imsi '+wrong_imsi+' name wrong', ['% No subscriber found for imsi '+wrong_imsi])
res = self.vty.command('subscriber imsi '+imsi+' name '+('X' * 160))
@@ -440,9 +444,54 @@ class TestVTYNITB(TestVTYGenericBSC):
self.vty.verify('subscriber imsi '+imsi+' extension '+('1' * 14), [''])
+ # 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")
+ self.assert_(res.find("122") > 0)
+ self.assert_(res.find("221") > 0)
+ # correct interval
+ 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-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 delete imsi '+imsi)
self.assert_(res != "")
+ res = self.vty.command('subscriber delete imsi ' + imsi2)
+ self.assert_(res != "")
+ res = self.vty.command('subscriber delete imsi ' + imsi3)
+ self.assert_(res != "")
+ res = self.vty.command('subscriber delete imsi ' + imsi4)
+ self.assert_(res != "")
def testShowPagingGroup(self):
res = self.vty.command("show paging-group 255 1234567")
From: Max <msuraev@sysmocom.de> Previously if subscriber was automatically created it got assigned random MSISDN number between 20000 and 49999. Make it optional (defaulting to previous behavior) by adding following: * optional "no-extension" argument to subscriber-create-on-demand * db unit tests * vty test The range for random extension can now be specified with "subscriber-create-on-demand random" command. Note: using the db made with new code might result in subscribers with empty extension. Such subscribers cannot be deleted using old code. Make sure not to mix db versions or manually fix it by editing sqlite with external program. Fixes: OS#1658 --- openbsc/include/openbsc/db.h | 8 +++-- openbsc/include/openbsc/gsm_data.h | 3 ++ openbsc/include/openbsc/gsm_subscriber.h | 5 ++- openbsc/src/libbsc/net_init.c | 3 +- openbsc/src/libcommon/gsm_subscriber_base.c | 1 + openbsc/src/libmsc/ctrl_commands.c | 9 ++++- openbsc/src/libmsc/db.c | 37 ++++++++++++-------- openbsc/src/libmsc/gsm_04_08.c | 10 ++++-- openbsc/src/libmsc/gsm_subscriber.c | 6 ++-- openbsc/src/libmsc/vty_interface_layer3.c | 53 ++++++++++++++++++++++++++--- openbsc/tests/db/db_test.c | 18 ++++++---- openbsc/tests/vty_test_runner.py | 49 ++++++++++++++++++++++++++ 12 files changed, 168 insertions(+), 34 deletions(-)