diff options
author | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2016-04-08 10:44:28 +0300 |
---|---|---|
committer | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2016-04-19 14:29:09 +0300 |
commit | 67fd3b1a0281c87f4f83e2771b0d851930d1fdaa (patch) | |
tree | a10b332e0594d096bb21caa81300476f87bc2dc9 /openbsc | |
parent | e85e7910d22374ba33a347839aa17289f4b9a077 (diff) |
Add support of virtual networks for sending network name to ms depending on imsifairwaves/master
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
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 16 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_subscriber.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/vty.h | 2 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_vty.c | 137 | ||||
-rw-r--r-- | openbsc/src/libbsc/net_init.c | 1 | ||||
-rw-r--r-- | openbsc/src/libcommon/common_vty.c | 19 | ||||
-rw-r--r-- | openbsc/src/libcommon/gsm_data.c | 40 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 42 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_vty.c | 10 | ||||
-rw-r--r-- | openbsc/tests/vty_test_runner.py | 41 |
10 files changed, 290 insertions, 19 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index b67b8c6b9..57bf9badc 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -243,6 +243,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; @@ -286,6 +289,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 { @@ -428,6 +441,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 tsc, 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 818a20e64..f8404c4f5 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, @@ -40,6 +41,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 d5f739405..c51b3602b 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)# ", @@ -342,6 +348,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) @@ -748,6 +791,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); @@ -1614,6 +1678,72 @@ DEFUN(cfg_net_exten_prefix, 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, @@ -3772,6 +3902,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); @@ -3820,6 +3951,12 @@ int bsc_vty_init(const struct log_info *cat) install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd); install_element(GSMNET_NODE, &cfg_net_exten_prefix_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 16e8146a7..856431554 100644 --- a/openbsc/src/libbsc/net_init.c +++ b/openbsc/src/libbsc/net_init.c @@ -72,6 +72,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 186fbe0b7..7bfbdbee8 100644 --- a/openbsc/src/libcommon/common_vty.c +++ b/openbsc/src/libcommon/common_vty.c @@ -42,6 +42,15 @@ enum node_type 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 4ce4ecac7..f3503aa7b 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 5a9e1ecc6..5f1366111 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -681,6 +681,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) @@ -698,13 +708,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 */ @@ -720,8 +746,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 */ @@ -731,11 +757,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 */ @@ -748,8 +774,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 */ @@ -759,7 +785,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 c0695fe7a..db6767778 100644 --- a/openbsc/src/libmsc/smpp_vty.c +++ b/openbsc/src/libmsc/smpp_vty.c @@ -227,16 +227,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 928eb8680..9a3ab7247 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -111,6 +111,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() @@ -132,6 +135,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",[''])) @@ -284,6 +293,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 testSubscriberCreateDelete(self): self.vty.enable() |