Make random MSISDN assignment optional
diff mbox

Message ID 1462205194-18849-1-git-send-email-msuraev@sysmocom.de
State New
Headers show

Commit Message

Max May 2, 2016, 4:06 p.m. UTC
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.

Fixes: OS#1658
---
 openbsc/include/openbsc/db.h                |  8 ++-
 openbsc/include/openbsc/gsm_data.h          |  8 +++
 openbsc/include/openbsc/gsm_subscriber.h    |  5 +-
 openbsc/src/libbsc/net_init.c               |  5 +-
 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              | 12 +++-
 openbsc/src/libmsc/gsm_subscriber.c         |  6 +-
 openbsc/src/libmsc/vty_interface_layer3.c   | 51 +++++++++++++--
 openbsc/tests/db/db_test.c                  | 99 +++++++++++++----------------
 openbsc/tests/vty_test_runner.py            | 14 ++++
 12 files changed, 169 insertions(+), 86 deletions(-)

Patch
diff mbox

diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index 6699a86..4da9634 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -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 ext);
 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);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 6d7aba3..14b002a 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -18,6 +18,12 @@  struct gsm_subscriber_group;
 
 #define OBSC_LINKID_CB(__msgb)	(__msgb)->cb[3]
 
+enum gsm_subscr_ext {
+	GSM_SUBSCR_DONT_CREATE = 0,
+	GSM_SUBSCR_RANDOM_EXT = 1,
+	GSM_SUBSCR_NO_EXT = 2
+};
+
 enum gsm_security_event {
 	GSM_SECURITY_NOAVAIL,
 	GSM_SECURITY_AUTH_FAILED,
@@ -283,6 +289,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;
 
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 7d6c776..5030d65 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -1,6 +1,8 @@ 
 #ifndef _GSM_SUBSCR_H
 #define _GSM_SUBSCR_H
 
+#include <stdbool.h>
+
 #include "gsm_data.h"
 #include <osmocom/core/linuxlist.h>
 
@@ -91,7 +93,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,
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 568a0b8..a524ead 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -48,7 +48,7 @@  struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
 	INIT_LLIST_HEAD(&net->bsc_data->mscs);
 
 	net->subscr_group->net = net;
-	net->create_subscriber = 1;
+	net->create_subscriber = GSM_SUBSCR_RANDOM_EXT;
 
 	net->country_code = country_code;
 	net->network_code = network_code;
@@ -104,7 +104,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;
diff --git a/openbsc/src/libcommon/gsm_subscriber_base.c b/openbsc/src/libcommon/gsm_subscriber_base.c
index a455824..5f0a1be 100644
--- a/openbsc/src/libcommon/gsm_subscriber_base.c
+++ b/openbsc/src/libcommon/gsm_subscriber_base.c
@@ -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);
 
diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c
index 9ac39de..44b1ebd 100644
--- a/openbsc/src/libmsc/ctrl_commands.c
+++ b/openbsc/src/libmsc/ctrl_commands.c
@@ -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;
 
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 267b5ef..5e55433 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -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 ext)
 {
 	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 (ext)
+		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 ('\0' != subscriber->extension[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 ('\0' != subscr->extension[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",
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 05cb886..d22db73 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -25,6 +25,7 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <time.h>
 #include <netinet/in.h>
@@ -517,6 +518,8 @@  static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *ms
 	struct gsm_network *net = bts->network;
 	uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
 	char mi_string[GSM48_MI_SIZE];
+	bool ext = (GSM_SUBSCR_RANDOM_EXT == net->create_subscriber) ? true :
+		false;
 
 	gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
 	DEBUGP(DMM, "IDENTITY RESPONSE: MI(%s)=%s\n",
@@ -532,7 +535,8 @@  static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *ms
 							  mi_string);
 			if (!conn->subscr && net->create_subscriber)
 				conn->subscr = subscr_create_subscriber(
-					net->subscr_group, mi_string);
+					net->subscr_group, mi_string,
+					net->ext_min, net->ext_max, ext);
 		}
 		if (!conn->subscr && conn->loc_operation) {
 			gsm0408_loc_upd_rej(conn, bts->network->reject_cause);
@@ -593,6 +597,8 @@  static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
 	struct gsm_bts *bts = conn->bts;
 	uint8_t mi_type;
 	char mi_string[GSM48_MI_SIZE];
+	bool ext = (GSM_SUBSCR_RANDOM_EXT == bts->network->create_subscriber) ?
+		true : false;
 
  	lu = (struct gsm48_loc_upd_req *) gh->data;
 
@@ -643,7 +649,9 @@  static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
 		subscr = subscr_get_by_imsi(bts->network->subscr_group, mi_string);
 		if (!subscr && bts->network->create_subscriber) {
 			subscr = subscr_create_subscriber(
-				bts->network->subscr_group, mi_string);
+				bts->network->subscr_group, mi_string,
+				bts->network->ext_min, bts->network->ext_max,
+				ext);
 		}
 		if (!subscr) {
 			gsm0408_loc_upd_rej(conn, bts->network->reject_cause);
diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c
index 57c10cf..7d62888 100644
--- a/openbsc/src/libmsc/gsm_subscriber.c
+++ b/openbsc/src/libmsc/gsm_subscriber.c
@@ -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;
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 790fedf..51b7258 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -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",
@@ -1032,11 +1038,33 @@  DEFUN(cfg_nitb, cfg_nitb_cmd,
 }
 
 DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
-      "subscriber-create-on-demand",
-      "Make a new record when a subscriber is first seen.\n")
+      "subscriber-create-on-demand [no-extension]",
+      "Make a new record when a subscriber is first seen.\n"
+      "Do not assign random extension when creating subscriber\n")
 {
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->create_subscriber = 1;
+	if (argc)
+		gsmnet->create_subscriber = GSM_SUBSCR_NO_EXT;
+	else
+		gsmnet->create_subscriber = GSM_SUBSCR_RANDOM_EXT;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd,
+      "subscriber-create-on-demand random <1-99999> <2-99999>",
+      "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;
 }
 
@@ -1045,7 +1073,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->create_subscriber = 0;
+	gsmnet->create_subscriber = GSM_SUBSCR_DONT_CREATE;
 	return CMD_SUCCESS;
 }
 
@@ -1070,9 +1098,17 @@  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);
+	const char *pref = gsmnet->create_subscriber ? "" : "no ", *post =
+		(GSM_SUBSCR_NO_EXT == gsmnet->create_subscriber) ?
+		" no-extension" : "";
+
 	vty_out(vty, "nitb%s", VTY_NEWLINE);
-	vty_out(vty, " %ssubscriber-create-on-demand%s",
-		gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
+	vty_out(vty, " %ssubscriber-create-on-demand%s%s", pref, post,
+		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;
@@ -1127,6 +1163,7 @@  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_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);
diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index fb159a5..a689789 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -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,10 +160,44 @@  static void test_sms_migrate(void)
 	subscr_put(rcv_subscr);
 }
 
-int main()
+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, GSM_MIN_EXTEN, GSM_MAX_EXTEN,
+				     ext);
+	db_subscriber_assoc_imei(alice, imei1);
+	if (imei2)
+		db_subscriber_assoc_imei(alice, imei2);
+	db_subscriber_alloc_tmsi(alice);
+	alice->lac=42;
+	db_sync_subscriber(alice);
+	/* Get by TMSI */
+	snprintf(scratch_str, sizeof(scratch_str), "%"PRIu32, alice->tmsi);
+	alice_db = db_get_subscriber(GSM_SUBSCRIBER_TMSI, scratch_str);
+	COMPARE(alice, alice_db);
+	SUBSCR_PUT(alice_db);
+	/* Get by IMSI */
+	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
+	COMPARE(alice, alice_db);
+	SUBSCR_PUT(alice_db);
+	/* Get by id */
+	snprintf(scratch_str, sizeof(scratch_str), "%llu", alice->id);
+	alice_db = db_get_subscriber(GSM_SUBSCRIBER_ID, scratch_str);
+	COMPARE(alice, alice_db);
+	SUBSCR_PUT(alice_db);
+	/* Get by extension */
+	alice_db = db_get_subscriber(GSM_SUBSCRIBER_EXTENSION, alice->extension);
+	if (alice_db) {
+		COMPARE(alice, alice_db);
+		SUBSCR_PUT(alice_db);
+	}
+	SUBSCR_PUT(alice);
+}
+
+int main()
+{
 	printf("Testing subscriber database code.\n");
 	osmo_init_logging(&log_info);
 	log_set_print_filename(osmo_stderr_target, 0);
@@ -186,68 +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);
 
-	alice_imsi = "3693245423445";
-	alice = db_create_subscriber(alice_imsi);
-	db_subscriber_assoc_imei(alice, "1234567890");
-	db_subscriber_alloc_tmsi(alice);
-	alice->lac=42;
-	db_sync_subscriber(alice);
-	/* Get by TMSI */
-	snprintf(scratch_str, sizeof(scratch_str), "%"PRIu32, alice->tmsi);
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_TMSI, scratch_str);
-	COMPARE(alice, alice_db);
-	SUBSCR_PUT(alice_db);
-	/* Get by IMSI */
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
-	COMPARE(alice, alice_db);
-	SUBSCR_PUT(alice_db);
-	/* Get by id */
-	snprintf(scratch_str, sizeof(scratch_str), "%llu", alice->id);
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_ID, scratch_str);
-	COMPARE(alice, alice_db);
-	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);
-	SUBSCR_PUT(alice);
-
-	alice_imsi = "9993245423445";
-	alice = db_create_subscriber(alice_imsi);
-	db_subscriber_alloc_tmsi(alice);
-	alice->lac=42;
-	db_sync_subscriber(alice);
-	db_subscriber_assoc_imei(alice, "1234567890");
-	db_subscriber_assoc_imei(alice, "6543560920");
-	/* Get by TMSI */
-	snprintf(scratch_str, sizeof(scratch_str), "%"PRIu32, alice->tmsi);
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_TMSI, scratch_str);
-	COMPARE(alice, alice_db);
-	SUBSCR_PUT(alice_db);
-	/* Get by IMSI */
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi);
-	COMPARE(alice, alice_db);
-	SUBSCR_PUT(alice_db);
-	/* Get by id */
-	snprintf(scratch_str, sizeof(scratch_str), "%llu", alice->id);
-	alice_db = db_get_subscriber(GSM_SUBSCRIBER_ID, scratch_str);
-	COMPARE(alice, alice_db);
-	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);
-	SUBSCR_PUT(alice);
+	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();
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index c088855..6c49a03 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -408,11 +408,13 @@  class TestVTYNITB(TestVTYGenericBSC):
         self.vty.enable()
 
         imsi = "204300854013739"
+        imsi2 = "204300854013769"
         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))
@@ -426,9 +428,21 @@  class TestVTYNITB(TestVTYGenericBSC):
 
         self.vty.verify('subscriber imsi '+imsi+' extension '+('1' * 14), [''])
 
+        # Another one - without extension
+        self.vty.command("configure terminal")
+        self.vty.command("nitb")
+        self.vty.command("subscriber-create-on-demand no-extension")
+        self.vty.command("end")
+
+        res = self.vty.command('subscriber create imsi ' + imsi2)
+        self.assert_(res.find("    IMSI: " + imsi2) > 0)
+        self.assertEquals(res.find("Extension"), -1)
+
         # Delete it
         res = self.vty.command('subscriber delete imsi '+imsi)
         self.assert_(res != "")
+        res = self.vty.command('subscriber delete imsi ' + imsi2)
+        self.assert_(res != "")
 
     def testShowPagingGroup(self):
         res = self.vty.command("show paging-group 255 1234567")