aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Kluchnikov <kluchnikovi@gmail.com>2016-04-08 10:44:28 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2016-04-19 14:40:27 +0300
commit7be811ed95d004f92d98880bc8eaef6c28c3373d (patch)
tree5c43f66712d36d3717f6d8c460e0d24c413cfe9e
parent687f048ab04ed135eeb11deb29e6b4cb9727c27d (diff)
Add support of virtual networks for sending network name to ms depending on imsifairwaves/virt-net
Before sending mm info message to ms: - try to find virtual network with the imsi prefix which matches subscriber's imsi - if virtual network was found, use long and short network names of this virtual network for subscriber - if virtual network was not found, use long and short network names of main network for subscriber
-rw-r--r--openbsc/include/openbsc/gsm_data.h16
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h1
-rw-r--r--openbsc/include/openbsc/vty.h2
-rw-r--r--openbsc/src/libbsc/bsc_vty.c137
-rw-r--r--openbsc/src/libbsc/net_init.c1
-rw-r--r--openbsc/src/libcommon/common_vty.c19
-rw-r--r--openbsc/src/libcommon/gsm_data.c40
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c42
-rw-r--r--openbsc/src/libmsc/smpp_vty.c10
-rw-r--r--openbsc/tests/vty_test_runner.py42
10 files changed, 290 insertions, 20 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 6d7aba358..04efbdccb 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -248,6 +248,9 @@ struct gsm_network {
unsigned int num_bts;
struct llist_head bts_list;
+ unsigned int num_virt_net;
+ struct llist_head virt_net_list;
+
/* timer values */
int T3101;
int T3103;
@@ -293,6 +296,16 @@ struct gsm_network {
struct ctrl_handle *ctrl;
};
+#define GSM_IMSI_LENGTH 17
+struct gsm_virt_network {
+ struct llist_head list;
+ uint8_t nr;
+ struct gsm_network *network;
+ char imsi_prefix[GSM_IMSI_LENGTH];
+ char *name_long;
+ char *name_short;
+};
+
struct osmo_esme;
enum gsm_sms_source_id {
@@ -435,6 +448,9 @@ int gsm_bts_model_register(struct gsm_bts_model *model);
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan);
void subscr_con_free(struct gsm_subscriber_connection *conn);
+struct gsm_virt_network *gsm_virt_net_alloc_register(struct gsm_network *net);
+struct gsm_virt_network *gsm_virt_net_num(struct gsm_network *net, int num);
+
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net,
enum gsm_bts_type type,
uint8_t bsic);
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 7d6c776bc..7108bff03 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -5,7 +5,6 @@
#include <osmocom/core/linuxlist.h>
#define GSM_IMEI_LENGTH 17
-#define GSM_IMSI_LENGTH 17
#define GSM_NAME_LENGTH 160
#define GSM_EXTENSION_LENGTH 15 /* MSISDN can only be 15 digits length */
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
index bc30e2357..711f82a4f 100644
--- a/openbsc/include/openbsc/vty.h
+++ b/openbsc/include/openbsc/vty.h
@@ -17,6 +17,7 @@ extern struct cmd_element cfg_no_description_cmd;
enum bsc_vty_node {
GSMNET_NODE = _LAST_OSMOVTY_NODE + 1,
+ VIRT_NET_NODE,
BTS_NODE,
TRX_NODE,
TS_NODE,
@@ -41,6 +42,7 @@ enum bsc_vty_node {
extern int bsc_vty_is_config_node(struct vty *vty, int node);
extern void bsc_replace_string(void *ctx, char **dst, const char *newstr);
+extern int osmo_is_digits(const char *str);
struct log_info;
int bsc_vty_init(const struct log_info *cat);
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 29f2501f8..f8e981e0c 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -112,6 +112,12 @@ struct cmd_node net_node = {
1,
};
+struct cmd_node virt_net_node = {
+ VIRT_NET_NODE,
+ "%s(config-net-virt)# ",
+ 1,
+};
+
struct cmd_node bts_node = {
BTS_NODE,
"%s(config-net-bts)# ",
@@ -343,6 +349,43 @@ DEFUN(show_bts, show_bts_cmd, "show bts [<0-255>]",
return CMD_SUCCESS;
}
+static void virt_net_dump_vty(struct vty *vty, struct gsm_virt_network *virt_net)
+{
+ vty_out(vty, "Virtual network %u%s", virt_net->nr, VTY_NEWLINE);
+ if (strlen(virt_net->imsi_prefix)) {
+ vty_out(vty, " imsi-prefix %s%s", virt_net->imsi_prefix, VTY_NEWLINE);
+ }
+ vty_out(vty, " Long network name: '%s'%s",
+ virt_net->name_long, VTY_NEWLINE);
+ vty_out(vty, " Short network name: '%s'%s",
+ virt_net->name_short, VTY_NEWLINE);
+}
+
+DEFUN(show_virt_net, show_virt_net_cmd, "show virtual-network [<0-255>]",
+ SHOW_STR "Display information about a virtual network\n"
+ "Virtual network number")
+{
+ struct gsm_network *net = gsmnet_from_vty(vty);
+ int virt_net_nr;
+
+ if (argc != 0) {
+ /* use the virtual network number that the user has specified */
+ virt_net_nr = atoi(argv[0]);
+ if (virt_net_nr >= net->num_virt_net) {
+ vty_out(vty, "%% can't find virtual network '%s'%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ virt_net_dump_vty(vty, gsm_virt_net_num(net, virt_net_nr));
+ return CMD_SUCCESS;
+ }
+ /* print all virtual networks */
+ for (virt_net_nr = 0; virt_net_nr < net->num_virt_net; virt_net_nr++)
+ virt_net_dump_vty(vty, gsm_virt_net_num(net, virt_net_nr));
+
+ return CMD_SUCCESS;
+}
+
/* utility functions */
static void parse_e1_link(struct gsm_e1_subslot *e1_link, const char *line,
const char *ts, const char *ss)
@@ -743,6 +786,27 @@ static int config_write_bts(struct vty *v)
return CMD_SUCCESS;
}
+static void config_write_virt_net_single(struct vty *vty, struct gsm_virt_network *virt_net)
+{
+ vty_out(vty, " virtual-network %u%s", virt_net->nr, VTY_NEWLINE);
+ if (strlen(virt_net->imsi_prefix)) {
+ vty_out(vty, " imsi-prefix %s%s", virt_net->imsi_prefix, VTY_NEWLINE);
+ }
+ vty_out(vty, " name short %s%s", virt_net->name_short, VTY_NEWLINE);
+ vty_out(vty, " name long %s%s", virt_net->name_long, VTY_NEWLINE);
+}
+
+static int config_write_virt_net(struct vty *v)
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(v);
+ struct gsm_virt_network *virt_net;
+
+ llist_for_each_entry(virt_net, &gsmnet->virt_net_list, list)
+ config_write_virt_net_single(v, virt_net);
+
+ return CMD_SUCCESS;
+}
+
static int config_write_net(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1612,6 +1676,72 @@ DEFUN(cfg_net_subscr_keep,
return CMD_SUCCESS;
}
+DEFUN(cfg_virt_net,
+ cfg_virt_net_cmd,
+ "virtual-network <0-255>",
+ "Select a virtual network to configure\n"
+ "Virtual-network Number\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ int virt_net_nr = atoi(argv[0]);
+ struct gsm_virt_network *virt_net;
+
+ if (virt_net_nr > gsmnet->num_virt_net) {
+ vty_out(vty, "%% The next unused Virtual-network number is %u%s",
+ gsmnet->num_virt_net, VTY_NEWLINE);
+ return CMD_WARNING;
+ } else if (virt_net_nr == gsmnet->num_virt_net) {
+ /* allocate a new one */
+ virt_net = gsm_virt_net_alloc_register(gsmnet);
+ } else
+ virt_net = gsm_virt_net_num(gsmnet, virt_net_nr);
+
+ if (!virt_net) {
+ vty_out(vty, "%% Unable to allocate Virtual-network %u%s",
+ gsmnet->num_virt_net, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty->index = virt_net;
+ vty->index_sub = NULL;
+ vty->node = VIRT_NET_NODE;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_virt_net_imsi_prefix,
+ cfg_virt_net_imsi_prefix_cmd,
+ "imsi-prefix PREFIX",
+ "Set the IMSI prefix\n"
+ "Prefix\n")
+{
+ struct gsm_virt_network *virt_net = vty->index;
+ if (!osmo_is_digits(argv[0])) {
+ vty_out(vty, "%% PREFIX has to be numeric%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ snprintf(virt_net->imsi_prefix, sizeof(virt_net->imsi_prefix), "%s", argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_virt_net_name,
+ cfg_virt_net_name_cmd,
+ "name (short|long) NAME",
+ "Set the GSM network name\n"
+ "Short network name\n"
+ "Long network name\n"
+ NAME_CMD_STR NAME_STR)
+{
+ struct gsm_virt_network *virt_net = vty->index;
+
+ if (!strcmp(argv[0], "short"))
+ bsc_replace_string(virt_net->network, &virt_net->name_short, argv[1]);
+ else
+ bsc_replace_string(virt_net->network, &virt_net->name_long, argv[1]);
+
+ return CMD_SUCCESS;
+}
+
/* per-BTS configuration */
DEFUN(cfg_bts,
cfg_bts_cmd,
@@ -3763,6 +3893,7 @@ int bsc_vty_init(const struct log_info *cat)
install_element_ve(&show_net_cmd);
+ install_element_ve(&show_virt_net_cmd);
install_element_ve(&show_bts_cmd);
install_element_ve(&show_trx_cmd);
install_element_ve(&show_ts_cmd);
@@ -3811,6 +3942,12 @@ int bsc_vty_init(const struct log_info *cat)
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
+ install_element(GSMNET_NODE, &cfg_virt_net_cmd);
+ install_node(&virt_net_node, config_write_virt_net);
+ vty_install_default(VIRT_NET_NODE);
+ install_element(VIRT_NET_NODE, &cfg_virt_net_imsi_prefix_cmd);
+ install_element(VIRT_NET_NODE, &cfg_virt_net_name_cmd);
+
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);
vty_install_default(BTS_NODE);
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 568a0b85e..1fe9f3ef4 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -71,6 +71,7 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
INIT_LLIST_HEAD(&net->trans_list);
INIT_LLIST_HEAD(&net->upqueue);
INIT_LLIST_HEAD(&net->bts_list);
+ INIT_LLIST_HEAD(&net->virt_net_list);
net->stats.chreq.total = osmo_counter_alloc("net.chreq.total");
net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel");
diff --git a/openbsc/src/libcommon/common_vty.c b/openbsc/src/libcommon/common_vty.c
index a0674f0f1..66a82d8bc 100644
--- a/openbsc/src/libcommon/common_vty.c
+++ b/openbsc/src/libcommon/common_vty.c
@@ -42,6 +42,15 @@ int bsc_vty_go_parent(struct vty *vty)
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
+ case VIRT_NET_NODE:
+ vty->node = GSMNET_NODE;
+ {
+ /* set vty->index correctly ! */
+ struct gsm_virt_network *virt_net = vty->index;
+ vty->index = virt_net->network;
+ vty->index_sub = NULL;
+ }
+ break;
case BTS_NODE:
vty->node = GSMNET_NODE;
{
@@ -141,3 +150,13 @@ void bsc_replace_string(void *ctx, char **dst, const char *newstr)
talloc_free(*dst);
*dst = talloc_strdup(ctx, newstr);
}
+
+int osmo_is_digits(const char *str)
+{
+ int i;
+ for (i = 0; i < strlen(str); i++) {
+ if (!isdigit(str[i]))
+ return 0;
+ }
+ return 1;
+}
diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c
index 16035edcc..d75e7afef 100644
--- a/openbsc/src/libcommon/gsm_data.c
+++ b/openbsc/src/libcommon/gsm_data.c
@@ -192,6 +192,46 @@ const char *rrlp_mode_name(enum rrlp_mode mode)
return get_value_string(rrlp_mode_names, mode);
}
+struct gsm_virt_network *gsm_virt_net_alloc(void *ctx)
+{
+ struct gsm_virt_network *virt_net = talloc_zero(ctx, struct gsm_virt_network);
+ if (!virt_net)
+ return NULL;
+ return virt_net;
+}
+
+struct gsm_virt_network *gsm_virt_net_alloc_register(struct gsm_network *net)
+{
+ struct gsm_virt_network *virt_net;
+
+ virt_net = gsm_virt_net_alloc(net);
+ if (!virt_net)
+ return NULL;
+
+ virt_net->nr = net->num_virt_net++;
+ virt_net->network = net;
+ virt_net->name_short = talloc_strdup(net, "OpenBSC");
+ virt_net->name_long = talloc_strdup(net, "OpenBSC");
+
+ llist_add_tail(&virt_net->list, &net->virt_net_list);
+ return virt_net;
+}
+
+struct gsm_virt_network *gsm_virt_net_num(struct gsm_network *net, int num)
+{
+ struct gsm_virt_network *virt_net;
+
+ if (num >= net->num_virt_net)
+ return NULL;
+
+ llist_for_each_entry(virt_net, &net->virt_net_list, list) {
+ if (virt_net->nr == num)
+ return virt_net;
+ }
+
+ return NULL;
+}
+
static const struct value_string bts_gprs_mode_names[] = {
{ BTS_GPRS_NONE, "none" },
{ BTS_GPRS_GPRS, "gprs" },
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 1524ec44f..57a67263b 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -702,6 +702,16 @@ static uint8_t bcdify(uint8_t value)
return ret;
}
+int is_prefix_match_imsi(char *imsi_prefix, char *imsi)
+{
+ size_t prefix_len = strlen(imsi_prefix);
+ size_t imsi_len = strlen(imsi);
+ if ((prefix_len <= imsi_len) &&
+ (strncmp(imsi, imsi_prefix, prefix_len) == 0)) {
+ return 1;
+ }
+ return 0;
+}
/* Section 9.2.15a */
int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
@@ -719,13 +729,29 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
int tzunits;
int dst = 0;
+ char *name_long = net->name_long;
+ char *name_short = net->name_short;
+ int virt_net_nr;
+
msg->lchan = conn->lchan;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_INFO;
- if (net->name_long) {
+ if (net->num_virt_net) {
+ for (virt_net_nr = 0; virt_net_nr < net->num_virt_net; virt_net_nr++) {
+ struct gsm_virt_network* virt_net = gsm_virt_net_num(net, virt_net_nr);
+ if (virt_net && strlen(virt_net->imsi_prefix) &&
+ is_prefix_match_imsi(virt_net->imsi_prefix, conn->subscr->imsi)) {
+ name_long = virt_net->name_long;
+ name_short = virt_net->name_short;
+ break;
+ }
+ }
+ }
+
+ if (name_long) {
#if 0
name_len = strlen(net->name_long);
/* 10.5.3.5a */
@@ -741,8 +767,8 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
/* FIXME: Use Cell Broadcast, not UCS-2, since
* UCS-2 is only supported by later revisions of the spec */
#endif
- name_len = (strlen(net->name_long)*7)/8;
- name_pad = (8 - strlen(net->name_long)*7)%8;
+ name_len = (strlen(name_long)*7)/8;
+ name_pad = (8 - strlen(name_long)*7)%8;
if (name_pad > 0)
name_len++;
/* 10.5.3.5a */
@@ -752,11 +778,11 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
ptr8 = msgb_put(msg, name_len);
- gsm_7bit_encode_n(ptr8, name_len, net->name_long, NULL);
+ gsm_7bit_encode_n(ptr8, name_len, name_long, NULL);
}
- if (net->name_short) {
+ if (name_short) {
#if 0
name_len = strlen(net->name_short);
/* 10.5.3.5a */
@@ -769,8 +795,8 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
for (i = 0; i < name_len; i++)
ptr16[i] = htons(net->name_short[i]);
#endif
- name_len = (strlen(net->name_short)*7)/8;
- name_pad = (8 - strlen(net->name_short)*7)%8;
+ name_len = (strlen(name_short)*7)/8;
+ name_pad = (8 - strlen(name_short)*7)%8;
if (name_pad > 0)
name_len++;
/* 10.5.3.5a */
@@ -780,7 +806,7 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
ptr8 = msgb_put(msg, name_len);
- gsm_7bit_encode_n(ptr8, name_len, net->name_short, NULL);
+ gsm_7bit_encode_n(ptr8, name_len, name_short, NULL);
}
diff --git a/openbsc/src/libmsc/smpp_vty.c b/openbsc/src/libmsc/smpp_vty.c
index 351e8bec5..72b816fd3 100644
--- a/openbsc/src/libmsc/smpp_vty.c
+++ b/openbsc/src/libmsc/smpp_vty.c
@@ -277,16 +277,6 @@ DEFUN(cfg_esme_no_passwd, cfg_esme_no_passwd_cmd,
return CMD_SUCCESS;
}
-static int osmo_is_digits(const char *str)
-{
- int i;
- for (i = 0; i < strlen(str); i++) {
- if (!isdigit(str[i]))
- return 0;
- }
- return 1;
-}
-
static const struct value_string route_errstr[] = {
{ -EEXIST, "Route already exists" },
{ -ENODEV, "Route does not exist" },
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index ecf5204a4..03fdf45e0 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -133,6 +133,9 @@ class TestVTYGenericBSC(TestVTYBase):
self.assertTrue(self.vty.verify("network",['']))
self.assertEquals(self.vty.node(), 'config-net')
self.checkForEndAndExit()
+ self.assertTrue(self.vty.verify("virtual-network 0",['']))
+ self.assertEquals(self.vty.node(), 'config-net-virt')
+ self.checkForEndAndExit()
self.assertTrue(self.vty.verify("bts 0",['']))
self.assertEquals(self.vty.node(), 'config-net-bts')
self.checkForEndAndExit()
@@ -154,6 +157,12 @@ class TestVTYGenericBSC(TestVTYBase):
self.assertEquals(self.vty.node(), 'config-net-bts')
self.assertTrue(self.vty.verify("exit",['']))
self.assertEquals(self.vty.node(), 'config-net')
+ self.assertTrue(self.vty.verify("virtual-network 1",['']))
+ self.assertEquals(self.vty.node(), 'config-net-virt')
+ self.checkForEndAndExit()
+ self.vty.command("write terminal")
+ self.assertTrue(self.vty.verify("exit",['']))
+ self.assertEquals(self.vty.node(), 'config-net')
self.assertTrue(self.vty.verify("exit",['']))
self.assertEquals(self.vty.node(), 'config')
self.assertTrue(self.vty.verify("exit",['']))
@@ -307,6 +316,38 @@ class TestVTYNITB(TestVTYGenericBSC):
if classNum != 10:
self.assertEquals(res.find("rach access-control-class " + str(classNum) + " barred"), -1)
+ def testVirtualNetworks(self):
+ self.vty.enable()
+ self.vty.command("configure terminal")
+ self.vty.command("network")
+ self.vty.command("virtual-network 0")
+
+ # Test invalid input
+ self.vty.verify("imsi-prefix 1234567abcd89", ['% PREFIX has to be numeric'])
+ self.vty.verify("name short Test Net", ['% Unknown command.'])
+ self.vty.verify("name long Test Network", ['% Unknown command.'])
+
+ # Set virtual-networks
+ self.vty.verify("imsi-prefix 00202", [''])
+ self.vty.verify("name short TestNet2", [''])
+ self.vty.verify("name long TestNetwork2", [''])
+ self.vty.verify("exit",[''])
+ self.vty.command("virtual-network 1")
+ self.vty.verify("imsi-prefix 00303300", [''])
+ self.vty.verify("name short TestNet3", [''])
+ self.vty.verify("name long TestNetwork3", [''])
+
+ # Verify settings
+ res = self.vty.command("write terminal")
+ self.assert_(res.find('virtual-network 0') > 0)
+ self.assert_(res.find('imsi-prefix 00202') > 0)
+ self.assert_(res.find('name short TestNet2') > 0)
+ self.assert_(res.find('name long TestNetwork2') > 0)
+ self.assert_(res.find('virtual-network 1') > 0)
+ self.assert_(res.find('imsi-prefix 00303300') > 0)
+ self.assert_(res.find('name short TestNet3') > 0)
+ self.assert_(res.find('name long TestNetwork3') > 0)
+
def testSubscriberCreateDeleteTwice(self):
"""
OS#1657 indicates that there might be an issue creating the
@@ -342,7 +383,6 @@ class TestVTYNITB(TestVTYGenericBSC):
res = self.vty.command('show subscriber imsi '+imsi)
self.assert_(res != '% No subscriber found for imsi '+imsi)
-
def testSubscriberCreateDelete(self):
self.vty.enable()