From f93970b167aba2805cc67e1326591f31fbe93ada Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 5 Mar 2018 02:09:40 +0100 Subject: implement support for 3-digit MNC with leading zeros Add 3-digit flags and use the new RAI and LAI API from libosmocore throughout the code base to be able to handle an MNC < 100 that has three digits (leading zeros). The changes to abis_test and gsm0408_test show that this code now handles 3-digit MNC correctly, by not dropping the leading zero as 0xf in the encoded PLMN. Re-implement CTRL commands 'mcc', 'mnc' and 'mcc-mnc-apply' to preserve the presence of the third digit of the MNC. Always reply with all leading zeros. Adjust the expected results in ctrl_test_runner.py, to show that it works. In VTY and CTRL, the parsing of MCC and MNC is inherently made stricter by use of osmo_{mcc,mnc}_from_str() -- they will no longer allow surplus characters and detect errno returned by strtol() (in contrast to atoi()). Depends: Id2240f7f518494c9df6c8bda52c0d5092f90f221 (libosmocore), Ib7176b1d65a03b76f41f94bc9d3293a8a07d24c6 (libosmocore), I020a4f11791c61742a3d795f782805f7b7e8733e (libosmocore) Change-Id: I8e722103344186fde118b26d8353db95a4581daa --- include/osmocom/bsc/bsc_msc_data.h | 4 +- include/osmocom/bsc/gsm_data.h | 16 ++++- src/libbsc/bsc_ctrl_commands.c | 87 +++++++++++++++++++++++----- src/libbsc/bsc_init.c | 7 ++- src/libbsc/bsc_vty.c | 28 ++++++--- src/libbsc/gsm_data.c | 5 +- src/libbsc/net_init.c | 6 +- src/libbsc/pcu_sock.c | 5 +- src/libbsc/system_information.c | 12 +--- src/osmo-bsc/osmo_bsc_api.c | 47 +++++---------- src/osmo-bsc/osmo_bsc_bssap.c | 58 ++++++++----------- src/osmo-bsc/osmo_bsc_ctrl.c | 7 ++- src/osmo-bsc/osmo_bsc_filter.c | 18 ++---- src/osmo-bsc/osmo_bsc_msc.c | 6 +- src/osmo-bsc/osmo_bsc_vty.c | 30 +++++++--- tests/abis/abis_test.c | 12 ++-- tests/abis/abis_test.ok | 6 +- tests/bssap/bssap_test.err | 2 +- tests/ctrl_test_runner.py | 22 +++---- tests/gsm0408/gsm0408_test.c | 9 ++- tests/gsm0408/gsm0408_test.ok | 6 +- tests/nanobts_omlattr/nanobts_omlattr_test.c | 3 +- 22 files changed, 225 insertions(+), 171 deletions(-) diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h index a3e0106f1..a04e632ac 100644 --- a/include/osmocom/bsc/bsc_msc_data.h +++ b/include/osmocom/bsc/bsc_msc_data.h @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -78,8 +79,7 @@ struct bsc_msc_data { struct osmo_timer_list pong_timer; int advanced_ping; struct bsc_msc_connection *msc_con; - int core_mnc; - int core_mcc; + struct osmo_plmn_id core_plmn; int core_lac; int core_ci; int rtp_base; diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 8692469b4..27aa2619e 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -1197,9 +1198,8 @@ struct gsm_network { * these have in common, like country and network code, put in yet * separate structs and placed as members in osmo_bsc and osmo_msc. */ - /* global parameters */ - uint16_t country_code; - uint16_t network_code; + struct osmo_plmn_id plmn; + /* bit-mask of permitted encryption algorithms. LSB=A5/0, MSB=A5/7 */ uint8_t a5_encryption_mask; int neci; @@ -1275,6 +1275,16 @@ struct gsm_network { } mgw; }; +static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts) +{ + static struct osmo_location_area_id lai; + lai = (struct osmo_location_area_id){ + .plmn = bts->network->plmn, + .lac = bts->location_area_code, + }; + return &lai; +} + extern void talloc_ctx_init(void *ctx_root); int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type); diff --git a/src/libbsc/bsc_ctrl_commands.c b/src/libbsc/bsc_ctrl_commands.c index 41d236126..64f458920 100644 --- a/src/libbsc/bsc_ctrl_commands.c +++ b/src/libbsc/bsc_ctrl_commands.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -30,8 +31,61 @@ #include #include -CTRL_CMD_DEFINE_RANGE(net_mnc, "mnc", struct gsm_network, network_code, 0, 999); -CTRL_CMD_DEFINE_RANGE(net_mcc, "mcc", struct gsm_network, country_code, 1, 999); +CTRL_CMD_DEFINE(net_mcc, "mcc"); +static int get_net_mcc(struct ctrl_cmd *cmd, void *_data) +{ + struct gsm_network *net = cmd->node; + cmd->reply = talloc_asprintf(cmd, "%s", osmo_mcc_name(net->plmn.mcc)); + if (!cmd->reply) { + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; + } + return CTRL_CMD_REPLY; +} +static int set_net_mcc(struct ctrl_cmd *cmd, void *_data) +{ + struct gsm_network *net = cmd->node; + uint16_t mcc; + if (osmo_mcc_from_str(cmd->value, &mcc)) + return -1; + net->plmn.mcc = mcc; + return get_net_mcc(cmd, _data); +} +static int verify_net_mcc(struct ctrl_cmd *cmd, const char *value, void *_data) +{ + if (osmo_mcc_from_str(value, NULL)) + return -1; + return 0; +} + +CTRL_CMD_DEFINE(net_mnc, "mnc"); +static int get_net_mnc(struct ctrl_cmd *cmd, void *_data) +{ + struct gsm_network *net = cmd->node; + cmd->reply = talloc_asprintf(cmd, "%s", osmo_mnc_name(net->plmn.mnc, net->plmn.mnc_3_digits)); + if (!cmd->reply) { + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; + } + return CTRL_CMD_REPLY; +} +static int set_net_mnc(struct ctrl_cmd *cmd, void *_data) +{ + struct gsm_network *net = cmd->node; + struct osmo_plmn_id plmn = net->plmn; + if (osmo_mnc_from_str(cmd->value, &plmn.mnc, &plmn.mnc_3_digits)) { + cmd->reply = "Error while decoding MNC"; + return CTRL_CMD_ERROR; + } + net->plmn = plmn; + return get_net_mnc(cmd, _data); +} +static int verify_net_mnc(struct ctrl_cmd *cmd, const char *value, void *_data) +{ + if (osmo_mnc_from_str(value, NULL, NULL)) + return -1; + return 0; +} static int set_net_apply_config(struct ctrl_cmd *cmd, void *data) { @@ -64,6 +118,7 @@ CTRL_CMD_DEFINE_WO_NOVRF(net_apply_config, "apply-configuration"); static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, void *d) { char *tmp, *saveptr, *mcc, *mnc; + int rc = 0; tmp = talloc_strdup(cmd, value); if (!tmp) @@ -71,39 +126,45 @@ static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, voi mcc = strtok_r(tmp, ",", &saveptr); mnc = strtok_r(NULL, ",", &saveptr); - talloc_free(tmp); - if (!mcc || !mnc) - return 1; - return 0; + if (osmo_mcc_from_str(mcc, NULL) || osmo_mnc_from_str(mnc, NULL, NULL)) + rc = -1; + + talloc_free(tmp); + return rc; } static int set_net_mcc_mnc_apply(struct ctrl_cmd *cmd, void *data) { struct gsm_network *net = cmd->node; char *tmp, *saveptr, *mcc_str, *mnc_str; - int mcc, mnc; + struct osmo_plmn_id plmn; tmp = talloc_strdup(cmd, cmd->value); if (!tmp) goto oom; - mcc_str = strtok_r(tmp, ",", &saveptr); mnc_str = strtok_r(NULL, ",", &saveptr); - mcc = atoi(mcc_str); - mnc = atoi(mnc_str); + if (osmo_mcc_from_str(mcc_str, &plmn.mcc)) { + cmd->reply = "Error while decoding MCC"; + return CTRL_CMD_ERROR; + } + + if (osmo_mnc_from_str(mnc_str, &plmn.mnc, &plmn.mnc_3_digits)) { + cmd->reply = "Error while decoding MNC"; + return CTRL_CMD_ERROR; + } talloc_free(tmp); - if (net->network_code == mnc && net->country_code == mcc) { + if (!osmo_plmn_cmp(&net->plmn, &plmn)) { cmd->reply = "Nothing changed"; return CTRL_CMD_REPLY; } - net->network_code = mnc; - net->country_code = mcc; + net->plmn = plmn; return set_net_apply_config(cmd, data); diff --git a/src/libbsc/bsc_init.c b/src/libbsc/bsc_init.c index a2f0504e1..f164533bc 100644 --- a/src/libbsc/bsc_init.c +++ b/src/libbsc/bsc_init.c @@ -326,9 +326,10 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx) unsigned int i; LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) " - "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u\n", - trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code, - bsc_gsmnet->network_code, trx->bts->location_area_code, + "on ARFCN %u using MCC-MNC %s LAC=%u CID=%u BSIC=%u\n", + trx->bts->nr, trx->nr, trx->arfcn, + osmo_plmn_name(&bsc_gsmnet->plmn), + trx->bts->location_area_code, trx->bts->cell_identity, trx->bts->bsic); /* diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c index 47bc51483..29a3c80a3 100644 --- a/src/libbsc/bsc_vty.c +++ b/src/libbsc/bsc_vty.c @@ -203,9 +203,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) struct pchan_load pl; int i; - vty_out(vty, "BSC is on Country Code %u, Network Code %u " - "and has %u BTS%s", net->country_code, net->network_code, - net->num_bts, VTY_NEWLINE); + vty_out(vty, "BSC is on MCC-MNC %s and has %u BTS%s", + osmo_plmn_name(&net->plmn), net->num_bts, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, " Encryption:"); for (i = 0; i < 8; i++) { @@ -955,8 +954,9 @@ static int config_write_net(struct vty *vty) int i; vty_out(vty, "network%s", VTY_NEWLINE); - vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE); - vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE); + vty_out(vty, " network country code %s%s", osmo_mcc_name(gsmnet->plmn.mcc), VTY_NEWLINE); + vty_out(vty, " mobile network code %s%s", + osmo_mnc_name(gsmnet->plmn.mnc, gsmnet->plmn.mnc_3_digits), VTY_NEWLINE); vty_out(vty, " encryption a5"); for (i = 0; i < 8; i++) { if (gsmnet->a5_encryption_mask & (1 << i)) @@ -4516,8 +4516,14 @@ DEFUN(cfg_net_ncc, "Network Country Code to use\n") { struct gsm_network *gsmnet = gsmnet_from_vty(vty); + uint16_t mcc; - gsmnet->country_code = atoi(argv[0]); + if (osmo_mcc_from_str(argv[0], &mcc)) { + vty_out(vty, "%% Error decoding MCC: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + gsmnet->plmn.mcc = mcc; return CMD_SUCCESS; } @@ -4531,8 +4537,16 @@ DEFUN(cfg_net_mnc, "Mobile Network Code to use\n") { struct gsm_network *gsmnet = gsmnet_from_vty(vty); + uint16_t mnc; + bool mnc_3_digits; + + if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) { + vty_out(vty, "%% Error decoding MNC: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } - gsmnet->network_code = atoi(argv[0]); + gsmnet->plmn.mnc = mnc; + gsmnet->plmn.mnc_3_digits = mnc_3_digits; return CMD_SUCCESS; } diff --git a/src/libbsc/gsm_data.c b/src/libbsc/gsm_data.c index d4a6a70f9..686e9c54e 100644 --- a/src/libbsc/gsm_data.c +++ b/src/libbsc/gsm_data.c @@ -272,8 +272,9 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts) { *raid = (struct gprs_ra_id){ - .mcc = bts->network->country_code, - .mnc = bts->network->network_code, + .mcc = bts->network->plmn.mcc, + .mnc = bts->network->plmn.mnc, + .mnc_3_digits = bts->network->plmn.mnc_3_digits, .lac = bts->location_area_code, .rac = bts->gprs.rac, }; diff --git a/src/libbsc/net_init.c b/src/libbsc/net_init.c index e44c335d1..d5ea5b275 100644 --- a/src/libbsc/net_init.c +++ b/src/libbsc/net_init.c @@ -47,8 +47,10 @@ struct gsm_network *bsc_network_init(void *ctx) if (!net) return NULL; - net->country_code = 1; - net->network_code = 1; + net->plmn = (struct osmo_plmn_id){ + .mcc = 1, + .mnc = 1, + }; /* Permit a compile-time default of A5/3 and A5/1 */ net->a5_encryption_mask = (1 << 3) | (1 << 1); diff --git a/src/libbsc/pcu_sock.c b/src/libbsc/pcu_sock.c index 9f1c80cc2..85af59842 100644 --- a/src/libbsc/pcu_sock.c +++ b/src/libbsc/pcu_sock.c @@ -152,8 +152,9 @@ static int pcu_tx_info_ind(struct gsm_bts *bts) info_ind->flags |= PCU_IF_FLAG_SYSMO; /* RAI */ - info_ind->mcc = bts->network->country_code; - info_ind->mnc = bts->network->network_code; + info_ind->mcc = bts->network->plmn.mcc; + info_ind->mnc = bts->network->plmn.mnc; + /* TODO: plmn.mnc_3_digits */ info_ind->lac = bts->location_area_code; info_ind->rac = bts->gprs.rac; diff --git a/src/libbsc/system_information.c b/src/libbsc/system_information.c index 750bba427..c7c85b043 100644 --- a/src/libbsc/system_information.c +++ b/src/libbsc/system_information.c @@ -860,9 +860,7 @@ static int generate_si3(enum osmo_sysinfo_type t, struct gsm_bts *bts) si3->header.system_information = GSM48_MT_RR_SYSINFO_3; si3->cell_identity = htons(bts->cell_identity); - gsm48_generate_lai(&si3->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai2(&si3->lai, bts_lai(bts)); si3->control_channel_desc = bts->si_common.chan_desc; si3->cell_options = bts->si_common.cell_options; si3->cell_sel_par = bts->si_common.cell_sel_par; @@ -914,9 +912,7 @@ static int generate_si4(enum osmo_sysinfo_type t, struct gsm_bts *bts) si4->header.skip_indicator = 0; si4->header.system_information = GSM48_MT_RR_SYSINFO_4; - gsm48_generate_lai(&si4->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai2(&si4->lai, bts_lai(bts)); si4->cell_sel_par = bts->si_common.cell_sel_par; si4->rach_control = bts->si_common.rach_control; if (acc_ramp_is_enabled(&bts->acc_ramp)) @@ -1088,9 +1084,7 @@ static int generate_si6(enum osmo_sysinfo_type t, struct gsm_bts *bts) si6->skip_indicator = 0; si6->system_information = GSM48_MT_RR_SYSINFO_6; si6->cell_identity = htons(bts->cell_identity); - gsm48_generate_lai(&si6->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai2(&si6->lai, bts_lai(bts)); si6->cell_options = bts->si_common.cell_options; si6->ncc_permitted = bts->si_common.ncc_permitted; /* allow/disallow DTXu */ diff --git a/src/osmo-bsc/osmo_bsc_api.c b/src/osmo-bsc/osmo_bsc_api.c index 465832c82..75dae1293 100644 --- a/src/osmo-bsc/osmo_bsc_api.c +++ b/src/osmo-bsc/osmo_bsc_api.c @@ -54,32 +54,20 @@ static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca static int complete_layer3(struct gsm_subscriber_connection *conn, struct msgb *msg, struct bsc_msc_data *msc); -static uint16_t get_network_code_for_msc(struct bsc_msc_data *msc) +static struct osmo_cell_global_id *cgi_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts) { - if (msc->core_mnc != -1) - return msc->core_mnc; - return msc->network->network_code; -} - -static uint16_t get_country_code_for_msc(struct bsc_msc_data *msc) -{ - if (msc->core_mcc != -1) - return msc->core_mcc; - return msc->network->country_code; -} - -static uint16_t get_lac_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts) -{ - if (msc->core_lac != -1) - return msc->core_lac; - return bts->location_area_code; -} + static struct osmo_cell_global_id cgi; + cgi.lai.plmn = msc->network->plmn; + if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID) + cgi.lai.plmn.mcc = msc->core_plmn.mcc; + if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID) { + cgi.lai.plmn.mnc = msc->core_plmn.mnc; + cgi.lai.plmn.mnc_3_digits = msc->core_plmn.mnc_3_digits; + } + cgi.lai.lac = (msc->core_lac != -1) ? msc->core_lac : bts->location_area_code; + cgi.cell_identity = (msc->core_ci != -1) ? msc->core_ci : bts->cell_identity; -static uint16_t get_ci_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts) -{ - if (msc->core_ci != -1) - return msc->core_ci; - return bts->cell_identity; + return &cgi; } static void bsc_maybe_lu_reject(struct gsm_subscriber_connection *conn, int con_type, int cause) @@ -242,10 +230,6 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, char *imsi = NULL; struct timeval tv; struct msgb *resp; - uint16_t network_code; - uint16_t country_code; - uint16_t lac; - uint16_t ci; enum bsc_con ret; int send_ping = msc->advanced_ping; @@ -285,14 +269,9 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, /* check return value, if failed check msg for and send USSD */ - network_code = get_network_code_for_msc(conn->sccp.msc); - country_code = get_country_code_for_msc(conn->sccp.msc); - lac = get_lac_for_msc(conn->sccp.msc, conn_get_bts(conn)); - ci = get_ci_for_msc(conn->sccp.msc, conn_get_bts(conn)); - bsc_scan_bts_msg(conn, msg); - resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci); + resp = gsm0808_create_layer3_2(msg, cgi_for_msc(conn->sccp.msc, conn_get_bts(conn)), NULL); if (!resp) { LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n"); osmo_bsc_sigtran_del_conn(conn); diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index d07cc558e..db749a3da 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -262,15 +262,14 @@ page_subscriber(struct bsc_msc_data *msc, struct gsm_bts *bts, /* Decode 5-byte LAI list element data (see TS 08.08 3.2.2.27) into MCC/MNC/LAC. * Return 0 if successful, negative on error. */ -static int -decode_lai(const uint8_t *data, uint16_t *mcc, uint16_t *mnc, uint16_t *lac) +static void +decode_lai(const uint8_t *data, struct osmo_location_area_id *laid) { struct gsm48_loc_area_id lai; /* Copy data to stack to prevent unaligned access in gsm48_decode_lai(). */ memcpy(&lai, data, sizeof(lai)); /* don't byte swap yet */ - - return gsm48_decode_lai(&lai, mcc, mnc, lac) != 0 ? -1 : 0; + gsm48_decode_lai2(&lai, laid); } static void @@ -290,37 +289,33 @@ page_cgi(struct bsc_msc_data *msc, const uint8_t *data, uint8_t data_length, siz uint16_t ci; int i = 0; while (remain >= sizeof(struct gsm48_loc_area_id) + sizeof(ci)) { - uint16_t mcc, mnc, lac, *ci_be; + struct osmo_location_area_id lai; + uint16_t *ci_be; size_t lai_offset = 1 + i * (sizeof(struct gsm48_loc_area_id) + sizeof(ci)); - if (decode_lai(&data[lai_offset], &mcc, &mnc, &lac) != 0) { - LOGP(DMSC, LOGL_ERROR, "Paging IMSI %s: Invalid LAI in Cell Identifier List " - "for BSS (0x%x), paging entire BSS anyway (%s)\n", - mi_string, CELL_IDENT_BSS, osmo_hexdump(data, data_length)); - page_all_bts(msc, tmsi, mi_string, chan_needed); - return; - } + decode_lai(&data[lai_offset], &lai); ci_be = (uint16_t *)(&data[lai_offset + sizeof(struct gsm48_loc_area_id)]); ci = osmo_load16be(ci_be); - if (mcc == msc->network->country_code && mnc == msc->network->network_code) { + if (!osmo_plmn_cmp(&lai.plmn, &msc->network->plmn)) { int paged = 0; struct gsm_bts *bts; llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) + if (bts->location_area_code != lai.lac) continue; if (bts->cell_identity != ci) continue; /* ignore errors from page_subscriber(); keep trying other BTS */ - page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed); + page_subscriber(msc, bts, tmsi, lai.lac, mi_string, chan_needed); paged = 1; } if (!paged) { LOGP(DMSC, LOGL_NOTICE, "Paging IMSI %s: BTS with LAC %d and CI %d not found\n", - mi_string, lac, ci); + mi_string, lai.lac, ci); } } else { - LOGP(DMSC, LOGL_DEBUG, "Paging IMSI %s: MCC/MNC in Cell Identifier List " - "(%d/%d) do not match our network (%d/%d)\n", mi_string, mcc, mnc, - msc->network->country_code, msc->network->network_code); + LOGP(DMSC, LOGL_DEBUG, "Paging IMSI %s: MCC-MNC in Cell Identifier List " + "(%s) do not match our network (%s)\n", + mi_string, osmo_plmn_name(&lai.plmn), + osmo_plmn_name2(&msc->network->plmn)); } remain -= sizeof(struct gsm48_loc_area_id) + sizeof(ci); i++; @@ -389,32 +384,27 @@ page_lai_and_lac(struct bsc_msc_data *msc, const uint8_t *data, size_t data_leng { int i = 0; while (remain >= sizeof(struct gsm48_loc_area_id)) { - uint16_t mcc, mnc, lac; - if (decode_lai(&data[1 + i * sizeof(struct gsm48_loc_area_id)], &mcc, &mnc, &lac) != 0) { - LOGP(DMSC, LOGL_ERROR, "Paging IMSI %s: Invalid LAI in Cell Identifier List " - "for BSS (0x%x), paging entire BSS anyway (%s)\n", - mi_string, CELL_IDENT_BSS, osmo_hexdump(data, data_length)); - page_all_bts(msc, tmsi, mi_string, chan_needed); - return; - } - if (mcc == msc->network->country_code && mnc == msc->network->network_code) { + struct osmo_location_area_id lai; + decode_lai(&data[1 + i * sizeof(struct gsm48_loc_area_id)], &lai); + if (!osmo_plmn_cmp(&lai.plmn, &msc->network->plmn)) { int paged = 0; struct gsm_bts *bts; llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) + if (bts->location_area_code != lai.lac) continue; /* ignore errors from page_subscriber(); keep trying other BTS */ - page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed); + page_subscriber(msc, bts, tmsi, lai.lac, mi_string, chan_needed); paged = 1; } if (!paged) { LOGP(DMSC, LOGL_NOTICE, "Paging IMSI %s: BTS with LAC %d not found\n", - mi_string, lac); + mi_string, lai.lac); } } else { - LOGP(DMSC, LOGL_DEBUG, "Paging IMSI %s: MCC/MNC in Cell Identifier List " - "(%d/%d) do not match our network (%d/%d)\n", mi_string, mcc, mnc, - msc->network->country_code, msc->network->network_code); + LOGP(DMSC, LOGL_DEBUG, "Paging IMSI %s: MCC-MNC in Cell Identifier List " + "(%s) do not match our network (%s)\n", + mi_string, osmo_plmn_name(&lai.plmn), + osmo_plmn_name2(&msc->network->plmn)); } remain -= sizeof(struct gsm48_loc_area_id); i++; diff --git a/src/osmo-bsc/osmo_bsc_ctrl.c b/src/osmo-bsc/osmo_bsc_ctrl.c index 6092f2379..5f88b85f7 100644 --- a/src/osmo-bsc/osmo_bsc_ctrl.c +++ b/src/osmo-bsc/osmo_bsc_ctrl.c @@ -207,10 +207,11 @@ static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_con policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts)); cmd->reply = talloc_asprintf_append(cmd->reply, - ",%s,%s,%s,%d,%d", + ",%s,%s,%s,%s,%s", oper, admin, policy, - bts->network->country_code, - bts->network->network_code); + osmo_mcc_name(bts->network->plmn.mcc), + osmo_mnc_name(bts->network->plmn.mnc, + bts->network->plmn.mnc_3_digits)); osmo_bsc_send_trap(cmd, msc_con); talloc_free(cmd); diff --git a/src/osmo-bsc/osmo_bsc_filter.c b/src/osmo-bsc/osmo_bsc_filter.c index c1f3e80a6..5f60989a7 100644 --- a/src/osmo-bsc/osmo_bsc_filter.c +++ b/src/osmo-bsc/osmo_bsc_filter.c @@ -36,21 +36,16 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn, struct gsm48_hdr *gh; struct gsm48_loc_upd_req *lu; struct gsm48_loc_area_id lai; - struct gsm_network *net; - struct gsm_bts *bts = conn_get_bts(conn); if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) { LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg)); return; } - net = bts->network; - gh = msgb_l3(msg); lu = (struct gsm48_loc_upd_req *) gh->data; - gsm48_generate_lai(&lai, net->country_code, net->network_code, - bts->location_area_code); + gsm48_generate_lai2(&lai, bts_lai(conn_get_bts(conn))); if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) { LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); @@ -315,9 +310,9 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn, static int has_core_identity(struct bsc_msc_data *msc) { - if (msc->core_mnc != -1) + if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID) return 1; - if (msc->core_mcc != -1) + if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID) return 1; if (msc->core_lac != -1) return 1; @@ -332,8 +327,6 @@ static int has_core_identity(struct bsc_msc_data *msc) int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct bsc_msc_data *msc; - struct gsm_bts *bts = conn_get_bts(conn); - struct gsm_network *net; struct gsm48_loc_area_id *lai; struct gsm48_hdr *gh; uint8_t pdisc; @@ -353,7 +346,6 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) return 0; mtype = gsm48_hdr_msg_type(gh); - net = bts->network; msc = conn->sccp.msc; if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { @@ -361,9 +353,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) { /* overwrite LAI in the message */ lai = (struct gsm48_loc_area_id *) &gh->data[0]; - gsm48_generate_lai(lai, net->country_code, - net->network_code, - bts->location_area_code); + gsm48_generate_lai2(lai, bts_lai(conn_get_bts(conn))); } } diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c index 46be2e644..e0c7556a9 100644 --- a/src/osmo-bsc/osmo_bsc_msc.c +++ b/src/osmo-bsc/osmo_bsc_msc.c @@ -581,8 +581,10 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr) INIT_LLIST_HEAD(&msc_data->dests); msc_data->ping_timeout = 20; msc_data->pong_timeout = 5; - msc_data->core_mnc = -1; - msc_data->core_mcc = -1; + msc_data->core_plmn = (struct osmo_plmn_id){ + .mcc = GSM_MCC_MNC_INVALID, + .mnc = GSM_MCC_MNC_INVALID, + }; msc_data->core_ci = -1; msc_data->core_lac = -1; msc_data->rtp_base = 4000; diff --git a/src/osmo-bsc/osmo_bsc_vty.c b/src/osmo-bsc/osmo_bsc_vty.c index e173b4a7b..3455d01af 100644 --- a/src/osmo-bsc/osmo_bsc_vty.c +++ b/src/osmo-bsc/osmo_bsc_vty.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -107,12 +108,12 @@ static void write_msc(struct vty *vty, struct bsc_msc_data *msc) struct bsc_msc_dest *dest; vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE); - if (msc->core_mnc != -1) - vty_out(vty, " core-mobile-network-code %d%s", - msc->core_mnc, VTY_NEWLINE); - if (msc->core_mcc != -1) - vty_out(vty, " core-mobile-country-code %d%s", - msc->core_mcc, VTY_NEWLINE); + if (msc->core_plmn.mnc != GSM_MCC_MNC_INVALID) + vty_out(vty, " core-mobile-network-code %s%s", + osmo_mnc_name(msc->core_plmn.mnc, msc->core_plmn.mnc_3_digits), VTY_NEWLINE); + if (msc->core_plmn.mcc != GSM_MCC_MNC_INVALID) + vty_out(vty, " core-mobile-country-code %s%s", + osmo_mcc_name(msc->core_plmn.mcc), VTY_NEWLINE); if (msc->core_lac != -1) vty_out(vty, " core-location-area-code %d%s", msc->core_lac, VTY_NEWLINE); @@ -236,7 +237,15 @@ DEFUN(cfg_net_bsc_ncc, "Use this network code for the core network\n" "MNC value\n") { struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_mnc = atoi(argv[0]); + uint16_t mnc; + bool mnc_3_digits; + + if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) { + vty_out(vty, "%% Error decoding MNC: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + data->core_plmn.mnc = mnc; + data->core_plmn.mnc_3_digits = mnc_3_digits; return CMD_SUCCESS; } @@ -245,8 +254,13 @@ DEFUN(cfg_net_bsc_mcc, "core-mobile-country-code <1-999>", "Use this country code for the core network\n" "MCC value\n") { + uint16_t mcc; struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_mcc = atoi(argv[0]); + if (osmo_mcc_from_str(argv[0], &mcc)) { + vty_out(vty, "%% Error decoding MCC: %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + data->core_plmn.mcc = mcc; return CMD_SUCCESS; } diff --git a/tests/abis/abis_test.c b/tests/abis/abis_test.c index 6369b0701..bb70a1505 100644 --- a/tests/abis/abis_test.c +++ b/tests/abis/abis_test.c @@ -101,8 +101,7 @@ static const struct test_abis_nm_ipaccess_cgi test_abis_nm_ipaccess_cgi_data[] = .plmn = { .mcc = 1, .mnc = 2, .mnc_3_digits = true }, .lac = 3, .cell_identity = 4, - .expect = "00f120" /* FAIL: should be "002100" */ - "0003" "0004", + .expect = "002100" "0003" "0004", }, { .plmn = { .mcc = 0, .mnc = 0, .mnc_3_digits = false }, @@ -114,8 +113,7 @@ static const struct test_abis_nm_ipaccess_cgi test_abis_nm_ipaccess_cgi_data[] = .plmn = { .mcc = 0, .mnc = 0, .mnc_3_digits = true }, .lac = 0, .cell_identity = 0, - .expect = "00f000" /* FAIL: should be "000000" */ - "0000" "0000", + .expect = "000000" "0000" "0000", }, { .plmn = { .mcc = 999, .mnc = 999, .mnc_3_digits = false }, @@ -133,8 +131,7 @@ static const struct test_abis_nm_ipaccess_cgi test_abis_nm_ipaccess_cgi_data[] = .plmn = { .mcc = 909, .mnc = 90, .mnc_3_digits = true }, .lac = 0xabcd, .cell_identity = 0x2345, - .expect = "09f909" /* FAIL: should be "090990" */ - "abcd" "2345", + .expect = "090990" "abcd" "2345", }, }; @@ -151,8 +148,7 @@ static void test_abis_nm_ipaccess_cgi() char *result; bool ok; - net.country_code = t->plmn.mcc; - net.network_code = t->plmn.mnc; + net.plmn = t->plmn; bts.network = &net; bts.location_area_code = t->lac; bts.cell_identity = t->cell_identity; diff --git a/tests/abis/abis_test.ok b/tests/abis/abis_test.ok index ff7772c07..e7e309c5f 100644 --- a/tests/abis/abis_test.ok +++ b/tests/abis/abis_test.ok @@ -8,9 +8,9 @@ SELECTED: 1 SELECTED: 0 test_sw_selection(): OK test_abis_nm_ipaccess_cgi[0]: result=00f12000030004 pass -test_abis_nm_ipaccess_cgi[1]: result=00f12000030004 pass +test_abis_nm_ipaccess_cgi[1]: result=00210000030004 pass test_abis_nm_ipaccess_cgi[2]: result=00f00000000000 pass -test_abis_nm_ipaccess_cgi[3]: result=00f00000000000 pass +test_abis_nm_ipaccess_cgi[3]: result=00000000000000 pass test_abis_nm_ipaccess_cgi[4]: result=999999ffffffff pass test_abis_nm_ipaccess_cgi[5]: result=09f909abcd2345 pass -test_abis_nm_ipaccess_cgi[6]: result=09f909abcd2345 pass +test_abis_nm_ipaccess_cgi[6]: result=090990abcd2345 pass diff --git a/tests/bssap/bssap_test.err b/tests/bssap/bssap_test.err index 18bfbca7e..8ae3b2286 100644 --- a/tests/bssap/bssap_test.err +++ b/tests/bssap/bssap_test.err @@ -16,7 +16,7 @@ bsc_handle_udt() returned 0 2: DMSC Rx MSC UDT: 00 19 52 08 08 59 51 20 69 00 07 43 94 09 04 01 08 44 60 1a 06 04 15 f5 49 00 65 DMSC Rx MSC UDT BSSMAP PAGING -DMSC Paging IMSI 515029600703449: MCC/MNC in Cell Identifier List (515/94) do not match our network (1/1) +DMSC Paging IMSI 515029600703449: MCC-MNC in Cell Identifier List (515-94) do not match our network (001-01) bsc_handle_udt() returned 0 3: diff --git a/tests/ctrl_test_runner.py b/tests/ctrl_test_runner.py index 41765ffc6..f43c09a79 100755 --- a/tests/ctrl_test_runner.py +++ b/tests/ctrl_test_runner.py @@ -371,32 +371,32 @@ class TestCtrlBSC(TestCtrlBase): r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mcc') - self.assertEquals(r['value'], '23') + self.assertEquals(r['value'], '023') r = self.do_set('mcc', '023') r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mcc') - self.assertEquals(r['value'], '23') + self.assertEquals(r['value'], '023') def testMnc(self): r = self.do_set('mnc', '9') r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '9') + self.assertEquals(r['value'], '09') r = self.do_set('mnc', '09') r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '9') + self.assertEquals(r['value'], '09') r = self.do_set('mnc', '009') r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '9') # FAIL: expecting '009' + self.assertEquals(r['value'], '009') def testMccMncApply(self): @@ -434,7 +434,7 @@ class TestCtrlBSC(TestCtrlBase): r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '4') + self.assertEquals(r['value'], '04') r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') @@ -450,7 +450,7 @@ class TestCtrlBSC(TestCtrlBase): r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '3') + self.assertEquals(r['value'], '03') r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') @@ -466,12 +466,12 @@ class TestCtrlBSC(TestCtrlBase): r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '3') # FAIL: expecting '003' + self.assertEquals(r['value'], '003') r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mcc') - self.assertEquals(r['value'], '2') + self.assertEquals(r['value'], '002') # Set same MNC with 3 digits r = self.do_set('mcc-mnc-apply', '2,003') @@ -482,12 +482,12 @@ class TestCtrlBSC(TestCtrlBase): r = self.do_get('mnc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mnc') - self.assertEquals(r['value'], '3') # FAIL: expecting '003' + self.assertEquals(r['value'], '003') r = self.do_get('mcc') self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['var'], 'mcc') - self.assertEquals(r['value'], '2') + self.assertEquals(r['value'], '002') class TestCtrlNAT(TestCtrlBase): diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index 9f5a5c41f..e8d5501bb 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -730,7 +730,7 @@ static const struct test_gsm48_ra_id_by_bts test_gsm48_ra_id_by_bts_data[] = { .lac = 3, .rac = 4, .expect = { - .digits = { 0x00, 0xf1, 0x20 }, /* FAIL: should be { 0x00, 0x21, 0x00 }, */ + .digits = { 0x00, 0x21, 0x00 }, .lac = 0x0300, /* network byte order of 3 */ .rac = 4, }, @@ -748,7 +748,7 @@ static const struct test_gsm48_ra_id_by_bts test_gsm48_ra_id_by_bts_data[] = { .lac = 0, .rac = 0, .expect = { - .digits = { 0x00, 0xf0, 0x00 }, /* FAIL: should be { 0, 0, 0 } */ + .digits = {}, }, }, { @@ -776,7 +776,7 @@ static const struct test_gsm48_ra_id_by_bts test_gsm48_ra_id_by_bts_data[] = { .lac = 0xabcd, .rac = 0xab, .expect = { - .digits = { 0x09, 0xf9, 0x09 }, /* FAIL: should be { 0x09, 0x09, 0x90 }, */ + .digits = { 0x09, 0x09, 0x90 }, .lac = 0xcdab, .rac = 0xab, }, @@ -795,8 +795,7 @@ static void test_gsm48_ra_id_by_bts() struct gsm48_ra_id result = {}; bool ok; - net.country_code = t->plmn.mcc; - net.network_code = t->plmn.mnc; + net.plmn = t->plmn; bts.network = &net; bts.location_area_code = t->lac; bts.gprs.rac = t->rac; diff --git a/tests/gsm0408/gsm0408_test.ok b/tests/gsm0408/gsm0408_test.ok index 686018bcd..00f87d556 100644 --- a/tests/gsm0408/gsm0408_test.ok +++ b/tests/gsm0408/gsm0408_test.ok @@ -215,10 +215,10 @@ SI5: 06 1d 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 SI5bis: 06 05 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 SI5ter: 06 06 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 test_gsm48_ra_id_by_bts[0]: digits='00f120' lac=0x0300=htons(3) rac=0x04=4 pass -test_gsm48_ra_id_by_bts[1]: digits='00f120' lac=0x0300=htons(3) rac=0x04=4 pass +test_gsm48_ra_id_by_bts[1]: digits='002100' lac=0x0300=htons(3) rac=0x04=4 pass test_gsm48_ra_id_by_bts[2]: digits='00f000' lac=0x0000=htons(0) rac=0x00=0 pass -test_gsm48_ra_id_by_bts[3]: digits='00f000' lac=0x0000=htons(0) rac=0x00=0 pass +test_gsm48_ra_id_by_bts[3]: digits='000000' lac=0x0000=htons(0) rac=0x00=0 pass test_gsm48_ra_id_by_bts[4]: digits='999999' lac=0xffff=htons(65535) rac=0xff=255 pass test_gsm48_ra_id_by_bts[5]: digits='09f909' lac=0xcdab=htons(43981) rac=0xab=171 pass -test_gsm48_ra_id_by_bts[6]: digits='09f909' lac=0xcdab=htons(43981) rac=0xab=171 pass +test_gsm48_ra_id_by_bts[6]: digits='090990' lac=0xcdab=htons(43981) rac=0xab=171 pass Done. diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.c b/tests/nanobts_omlattr/nanobts_omlattr_test.c index 0554f4393..6fa221c9d 100644 --- a/tests/nanobts_omlattr/nanobts_omlattr_test.c +++ b/tests/nanobts_omlattr/nanobts_omlattr_test.c @@ -218,8 +218,7 @@ int main(int argc, char **argv) bts->rach_ldavg_slots = -1; bts->c0->arfcn = 866; bts->cell_identity = 1337; - bts->network->country_code = 1; - bts->network->network_code = 1; + bts->network->plmn = (struct osmo_plmn_id){ .mcc=1, .mnc=1 }; bts->location_area_code = 1; bts->gprs.rac = 0; uint8_t attr_bts_expected[] = -- cgit v1.2.3