[PATCH 1/2] Add support of virtual networks for sending network name to ms depending on imsi

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.com
Tue Apr 12 10:48:57 UTC 2016


Before 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




More information about the OpenBSC mailing list