This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Ivan Kluchnikov kluchnikovi at gmail.comBefore sending mm info message to ms: - extract mcc and mnc from imsi - try to find virtual network with the same mcc and mnc - 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 --- openbsc/include/openbsc/gsm_data.h | 16 ++++ openbsc/include/openbsc/vty.h | 1 + openbsc/src/libbsc/bsc_vty.c | 156 +++++++++++++++++++++++++++++++++++++ openbsc/src/libbsc/net_init.c | 1 + openbsc/src/libcommon/common_vty.c | 9 +++ openbsc/src/libcommon/gsm_data.c | 42 ++++++++++ openbsc/src/libmsc/gsm_04_08.c | 45 +++++++++-- 7 files changed, 262 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 6d7aba3..9a52254 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; }; +struct gsm_virt_network { + struct llist_head list; + uint8_t nr; + struct gsm_network *network; + uint16_t country_code; + uint16_t network_code; + 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/vty.h b/openbsc/include/openbsc/vty.h index bc30e23..2848702 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, diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 29f2501..b414395 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,42 @@ 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); + vty_out(vty, " Country Code %u, Network Code %u%s", + virt_net->country_code, virt_net->network_code, 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 +785,26 @@ 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); + vty_out(vty, " network country code %u%s", virt_net->country_code, VTY_NEWLINE); + vty_out(vty, " mobile network code %u%s", virt_net->network_code, VTY_NEWLINE); + vty_out(vty, " short name %s%s", virt_net->name_short, VTY_NEWLINE); + vty_out(vty, " long name %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 +1674,91 @@ 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_ncc, + cfg_virt_net_ncc_cmd, + "network country code <1-999>", + "Set the GSM network country code\n" + "Country commands\n" + CODE_CMD_STR + "Network Country Code to use\n") +{ + struct gsm_virt_network *virt_net = vty->index; + + virt_net->country_code = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_virt_net_mnc, + cfg_virt_net_mnc_cmd, + "mobile network code <0-999>", + "Set the GSM mobile network code\n" + "Network Commands\n" + CODE_CMD_STR + "Mobile Network Code to use\n") +{ + struct gsm_virt_network *virt_net = vty->index; + + virt_net->network_code = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_virt_net_name_short, + cfg_virt_net_name_short_cmd, + "short name NAME", + "Set the short GSM network name\n" NAME_CMD_STR NAME_STR) +{ + struct gsm_virt_network *virt_net = vty->index; + + bsc_replace_string(virt_net->network, &virt_net->name_short, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_virt_net_name_long, + cfg_virt_net_name_long_cmd, + "long name NAME", + "Set the long GSM network name\n" NAME_CMD_STR NAME_STR) +{ + struct gsm_virt_network *virt_net = vty->index; + + bsc_replace_string(virt_net->network, &virt_net->name_long, argv[0]); + return CMD_SUCCESS; +} + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -3763,6 +3910,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 +3959,14 @@ 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_ncc_cmd); + install_element(VIRT_NET_NODE, &cfg_virt_net_mnc_cmd); + install_element(VIRT_NET_NODE, &cfg_virt_net_name_short_cmd); + install_element(VIRT_NET_NODE, &cfg_virt_net_name_long_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 568a0b8..1fe9f3e 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 a0674f0..c3434f1 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; { diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 16035ed..5076a3e 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -192,6 +192,48 @@ 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->country_code = 1; + virt_net->network_code = 1; + 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 1524ec4..db03d0e 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -702,6 +702,15 @@ static uint8_t bcdify(uint8_t value) return ret; } +static void mcc_mnc_from_imsi(char* imsi, uint16_t* mcc, uint16_t* mnc) +{ + char mcc_str[4]; + char mnc_str[3]; + strncpy(mcc_str, imsi, 3); + strncpy(mnc_str, imsi + 3, 2); + *mcc = atoi(mcc_str); + *mnc = atoi(mnc_str); +} /* Section 9.2.15a */ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) @@ -719,13 +728,33 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) int tzunits; int dst = 0; + uint16_t imsi_mcc; + uint16_t imsi_mnc; + 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) { + mcc_mnc_from_imsi(conn->subscr->imsi, &imsi_mcc, &imsi_mnc); + 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 && + (virt_net->country_code == imsi_mcc) && + (virt_net->network_code == imsi_mnc)) { + 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 +770,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 +781,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 +798,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 +809,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); } -- 1.9.1