static void handle_lu_request(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh; struct gsm48_loc_upd_req *lu; struct gsm48_loc_area_id lai; struct gsm_network *net; 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 = conn->bts->network; gh = msgb_l3(msg); lu = (struct gsm48_loc_upd_req *) gh->data; gsm48_generate_lai(&lai, net->country_code, net->network_code, conn->bts->location_area_code); if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) { LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); conn->sccp_con->new_subscriber = 1; } }
/** * Messages coming back from the MSC. */ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct osmo_msc_data *msc; struct gsm_network *net; struct gsm48_loc_area_id *lai; struct gsm48_hdr *gh; uint8_t mtype; if (msgb_l3len(msg) < sizeof(*gh)) { LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n"); return -1; } gh = (struct gsm48_hdr *) msgb_l3(msg); mtype = gh->msg_type & 0xbf; net = conn->bts->network; msc = conn->sccp_con->msc; if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { if (msc->core_ncc != -1 || msc->core_mcc != -1) { if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) { lai = (struct gsm48_loc_area_id *) &gh->data[0]; gsm48_generate_lai(lai, net->country_code, net->network_code, conn->bts->location_area_code); } } if (conn->sccp_con->new_subscriber) send_welcome_ussd(conn); } return 0; }
/* * Test Location Area Identifier formatting. Table 10.5.3 of 04.08 */ static void test_location_area_identifier(void) { struct gsm48_loc_area_id lai48; printf("Testing test location area identifier\n"); /* * Test the default/test setup. Coming from * bsc_hack.c dumps */ gsm48_generate_lai(&lai48, 1, 1, 1); COMPARE(lai48.digits[0], ==, 0x00); COMPARE(lai48.digits[1], ==, 0xF1); COMPARE(lai48.digits[2], ==, 0x10); COMPARE(lai48.lac, ==, htons(0x0001)); gsm48_generate_lai(&lai48, 602, 1, 15); COMPARE(lai48.digits[0], ==, 0x06); COMPARE(lai48.digits[1], ==, 0xF2); COMPARE(lai48.digits[2], ==, 0x10); COMPARE(lai48.lac, ==, htons(0x000f)); }
static inline void check_ra(const struct gprs_ra_id *raid) { struct gsm48_ra_id ra; struct gprs_ra_id raid0 = { .mnc = 0, .mcc = 0, .lac = 0, .rac = 0, }; gsm48_encode_ra(&ra, raid); printf("Constructed RA:\n"); gsm48_parse_ra(&raid0, (const uint8_t *)&ra); dump_ra(raid); printf("MCC+MNC in BCD: %s\n", osmo_hexdump(ra.digits, sizeof(ra.digits))); dump_ra(&raid0); printf("RA test..."); if (raid->mnc != raid0.mnc || raid->mcc != raid0.mcc || raid->lac != raid0.lac || raid->rac != raid0.rac || (raid->mnc_3_digits || raid->mnc > 99) != raid0.mnc_3_digits) printf("FAIL\n"); else printf("passed\n"); } static inline void check_lai(const struct gprs_ra_id *raid) { int rc; struct gsm48_loc_area_id lai = {}; struct gprs_ra_id decoded = {}; struct gprs_ra_id _laid = *raid; struct gprs_ra_id *laid = &_laid; laid->rac = 0; printf("- gsm48_generate_lai() from "); dump_ra(laid); gsm48_generate_lai(&lai, laid->mcc, laid->mnc, laid->lac); printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai))); rc = gsm48_decode_lai(&lai, &decoded.mcc, &decoded.mnc, &decoded.lac); if (rc) { printf(" gsm48_decode_lai() returned %d --> FAIL\n", rc); return; } printf(" gsm48_decode_lai() gives "); dump_ra(&decoded); if (decoded.mcc == laid->mcc && decoded.mnc == laid->mnc && decoded.lac == laid->lac) printf(" passed\n"); else printf(" FAIL\n"); }