diff options
Diffstat (limited to 'src/osmo-bsc/osmo_bsc_bssap.c')
-rw-r--r-- | src/osmo-bsc/osmo_bsc_bssap.c | 314 |
1 files changed, 185 insertions, 129 deletions
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index 189456105..799cb46a2 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -273,6 +273,179 @@ decode_lai(const uint8_t *data, uint16_t *mcc, uint16_t *mnc, uint16_t *lac) return gsm48_decode_lai(&lai, mcc, mnc, lac) != 0 ? -1 : 0; } +static void +page_all_bts(struct bsc_msc_data *msc, uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + /* ignore errors from page_subscriber(); try all BTS */ + page_subscriber(msc, bts, tmsi, GSM_LAC_RESERVED_ALL_BTS, mi_string, chan_needed); + } +} + +static void +page_cgi(struct bsc_msc_data *msc, const uint8_t *data, uint8_t data_length, size_t remain, + uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + uint16_t ci; + int i = 0; + while (remain >= sizeof(struct gsm48_loc_area_id) + sizeof(ci)) { + uint16_t mcc, mnc, lac, *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; + } + 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) { + int paged = 0; + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + if (bts->location_area_code != 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); + 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); + } + } 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); + } + remain -= sizeof(struct gsm48_loc_area_id) + sizeof(ci); + i++; + } +} + +static void +page_lac_and_ci(struct bsc_msc_data *msc, const uint8_t *data, size_t remain, + uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + uint16_t *lacp_be, *ci_be; + lacp_be = (uint16_t *)(&data[1]); + ci_be = (uint16_t *)(&data[3]); + while (remain >= sizeof(*lacp_be) + sizeof(*ci_be)) { + uint16_t lac = osmo_load16be(lacp_be); + uint16_t ci = osmo_load16be(ci_be); + int paged = 0; + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + if (bts->location_area_code != 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); + 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); + } + remain -= sizeof(*lacp_be) + sizeof(*ci_be); + lacp_be++; + ci_be++; + } +} + +static void +page_ci(struct bsc_msc_data *msc, const uint8_t *data, size_t remain, + uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + uint16_t *ci_be = (uint16_t *)(&data[1]); + while (remain >= sizeof(*ci_be)) { + uint16_t ci = osmo_load16be(ci_be); + int paged = 0; + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + if (bts->cell_identity != ci) + continue; + /* ignore errors from page_subscriber(); keep trying other BTS */ + page_subscriber(msc, bts, tmsi, GSM_LAC_RESERVED_ALL_BTS, mi_string, chan_needed); + paged = 1; + } + if (!paged) { + LOGP(DMSC, LOGL_NOTICE, "Paging IMSI %s: BTS with CI %d not found\n", + mi_string, ci); + } + remain -= sizeof(*ci_be); + ci_be++; + } +} + +static void +page_lai_and_lac(struct bsc_msc_data *msc, const uint8_t *data, size_t data_length, size_t remain, + uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + 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) { + int paged = 0; + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + if (bts->location_area_code != lac) + continue; + /* ignore errors from page_subscriber(); keep trying other BTS */ + page_subscriber(msc, bts, tmsi, 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); + } + } else { + LOGP(DMSC, LOGL_DEBUG, "Not 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); + } + remain -= sizeof(struct gsm48_loc_area_id); + i++; + } +} + +static void +page_lac(struct bsc_msc_data *msc, const uint8_t *data, size_t remain, + uint32_t tmsi, const char *mi_string, uint8_t chan_needed) +{ + uint16_t *lacp_be = (uint16_t *)(&data[1]); + while (remain >= sizeof(*lacp_be)) { + uint16_t lac = osmo_load16be(lacp_be); + int paged = 0; + struct gsm_bts *bts; + llist_for_each_entry(bts, &msc->network->bts_list, list) { + if (bts->location_area_code != lac) + continue; + /* ignore errors from page_subscriber(); keep trying other BTS */ + page_subscriber(msc, bts, tmsi, 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); + } + remain -= sizeof(*lacp_be); + lacp_be++; + } +} + /* GSM 08.08 ยง 3.2.1.19 */ static int bssmap_handle_paging(struct bsc_msc_data *msc, struct msgb *msg, unsigned int payload_length) @@ -280,15 +453,11 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc, struct tlv_parsed tp; char mi_string[GSM48_MI_SIZE]; uint32_t tmsi = GSM_RESERVED_TMSI; - uint16_t lac, *lacp_be; - uint16_t mcc; - uint16_t mnc; uint8_t data_length; int remain; const uint8_t *data; uint8_t chan_needed = RSL_CHANNEED_ANY; uint8_t cell_ident; - struct gsm_bts *bts; tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0); remain = payload_length - 1; @@ -353,136 +522,29 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc, cell_ident = data[0] & 0xf; remain -= 1; /* cell ident consumed */ - /* Default fallback: page entire BSS */ - lac = GSM_LAC_RESERVED_ALL_BTS; - switch (cell_ident) { case CELL_IDENT_NO_CELL: LOGP(DMSC, LOGL_NOTICE, "Ignoring no-op paging request for IMSI %s\n", mi_string); return 0; /* nothing to do */ - case CELL_IDENT_WHOLE_GLOBAL: { - uint16_t ci; - int i = 0; - while (remain >= sizeof(struct gsm48_loc_area_id) + sizeof(ci)) { - 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)); - lac = GSM_LAC_RESERVED_ALL_BTS; - break; - } - 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) { - llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) - continue; - if (bts->cell_identity != ci) - continue; - if (page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed) < 0) - break; - } - } else { - LOGP(DMSC, LOGL_DEBUG, "Not 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); - } - remain -= sizeof(struct gsm48_loc_area_id) + sizeof(ci); - i++; - } - } - - case CELL_IDENT_LAC_AND_CI: { - uint16_t ci, *ci_be; - lacp_be = (uint16_t *)(&data[1]); - ci_be = (uint16_t *)(&data[3]); - while (remain >= sizeof(*lacp_be) + sizeof(*ci_be)) { - lac = osmo_load16be(lacp_be); - ci = osmo_load16be(ci_be); - - llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) - continue; - if (bts->cell_identity != ci) - continue; - if (page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed) < 0) - break; - } - - remain -= sizeof(*lacp_be) + sizeof(*ci_be); - lacp_be++; - ci_be++; - } + case CELL_IDENT_WHOLE_GLOBAL: + page_cgi(msc, data, data_length, remain, tmsi, mi_string, chan_needed); break; - } - - case CELL_IDENT_CI: { - uint16_t *ci_be = (uint16_t *)(&data[1]); - while (remain >= sizeof(*ci_be)) { - uint16_t ci = osmo_load16be(ci_be); - llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->cell_identity == ci) - break; - } + case CELL_IDENT_LAC_AND_CI: + page_lac_and_ci(msc, data, remain, tmsi, mi_string, chan_needed); + break; - if (bts) { - /* ignore errors from page_subscriber(); keep trying other BTS */ - page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed); - } else { - LOGP(DMSC, LOGL_ERROR, "Paging IMSI %s: BTS with cell identifier %d not found\n", - mi_string, ci); - } - remain -= sizeof(*ci_be); - ci_be++; - } + case CELL_IDENT_CI: + page_ci(msc, data, remain, tmsi, mi_string, chan_needed); break; - } - case CELL_IDENT_LAI_AND_LAC: { - int i = 0; - while (remain >= sizeof(struct gsm48_loc_area_id)) { - 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)); - lac = GSM_LAC_RESERVED_ALL_BTS; - break; - } - if (mcc == msc->network->country_code && mnc == msc->network->network_code) { - llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) - continue; - /* ignore errors from page_subscriber(); keep trying other BTS */ - page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed); - } - } else { - LOGP(DMSC, LOGL_DEBUG, "Not 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); - } - remain -= sizeof(struct gsm48_loc_area_id); - i++; - } + case CELL_IDENT_LAI_AND_LAC: + page_lai_and_lac(msc, data, data_length, remain, tmsi, mi_string, chan_needed); break; - } case CELL_IDENT_LAC: - lacp_be = (uint16_t *)(&data[1]); - while (remain >= sizeof(*lacp_be)) { - lac = osmo_load16be(lacp_be); - llist_for_each_entry(bts, &msc->network->bts_list, list) { - if (bts->location_area_code != lac) - continue; - /* ignore errors from page_subscriber(); keep trying other BTS */ - page_subscriber(msc, bts, tmsi, lac, mi_string, chan_needed); - } - remain -= sizeof(*lacp_be); - lacp_be++; - } + page_lac(msc, data, remain, tmsi, mi_string, chan_needed); break; case CELL_IDENT_BSS: @@ -491,20 +553,14 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc, " has invalid length: %u, paging entire BSS anyway (%s)\n", mi_string, CELL_IDENT_BSS, data_length, osmo_hexdump(data, data_length)); } - llist_for_each_entry(bts, &msc->network->bts_list, list) { - /* ignore errors from page_subscriber(); try all BTS */ - page_subscriber(msc, bts, tmsi, GSM_LAC_RESERVED_ALL_BTS, mi_string, chan_needed); - } + page_all_bts(msc, tmsi, mi_string, chan_needed); break; default: LOGP(DMSC, LOGL_NOTICE, "Paging IMSI %s: unimplemented Cell Identifier List (0x%x)," " paging entire BSS instead (%s)\n", mi_string, cell_ident, osmo_hexdump(data, data_length)); - llist_for_each_entry(bts, &msc->network->bts_list, list) { - /* ignore errors from page_subscriber(); try all BTS */ - page_subscriber(msc, bts, tmsi, GSM_LAC_RESERVED_ALL_BTS, mi_string, chan_needed); - } + page_all_bts(msc, tmsi, mi_string, chan_needed); break; } |