@@ -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);
@@ -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;
@@ -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,
@@ -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;
@@ -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 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",
@@ -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);
@@ -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",
@@ -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);
@@ -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();
@@ -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")
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(-)