diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 8f0e4658c..6f367864f 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -708,7 +708,8 @@ int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand); int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan); struct msgb *gsm48_msgb_alloc(void); int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans); -int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi); +int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi); +int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char* imsi); int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len); int gsm48_send_rr_release(struct gsm_lchan *lchan); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index abb6e86bf..eeabc0fce 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -899,7 +899,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) bts->network->network_code, bts->location_area_code); mid = msgb_put(msg, GSM48_MID_TMSI_LEN); - generate_mid_from_tmsi(mid, tmsi); + gsm48_generate_mid_from_tmsi(mid, tmsi); DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e771ea3b2..c62f04d57 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -164,6 +164,12 @@ static char bcd2char(u_int8_t bcd) return 'A' + (bcd - 0xa); } +/* only works for numbers in ascci */ +static u_int8_t char2bcd(char c) +{ + return c - 0x30; +} + void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, u_int16_t mnc, u_int16_t lac) @@ -187,7 +193,7 @@ void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, lai48->lac = htons(lac); } -int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi) +int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi) { u_int32_t *tptr = (u_int32_t *) &buf[3]; @@ -199,6 +205,35 @@ int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi) return 7; } +int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char *imsi) +{ + unsigned int length = strlen(imsi), i, off = 0; + u_int8_t odd = (length & 0x1) == 1; + + buf[0] = GSM48_IE_MOBILE_ID; + buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3); + + /* if the length is even we will fill half of the last octet */ + if (odd) + buf[1] = (length + 1) >> 1; + else + buf[1] = (length + 2) >> 1; + + for (i = 1; i < buf[1]; ++i) { + u_int8_t lower, upper; + + lower = char2bcd(imsi[++off]); + if (!odd && off + 1 == length) + upper = 0x0f; + else + upper = char2bcd(imsi[++off]) & 0x0f; + + buf[2 + i] = (upper << 4) | lower; + } + + return 2 + buf[1]; +} + /* Section 9.1.8 / Table 9.9 */ struct chreq { u_int8_t val; diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index c79356e50..fd0611a14 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -99,7 +99,7 @@ static void page_ms(struct gsm_paging_request *request) page_group = calculate_group(request->bts, request->subscr); tmsi = strtoul(request->subscr->tmsi, NULL, 10); - mi_len = generate_mid_from_tmsi(mi, tmsi); + mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi); rsl_paging_cmd(request->bts, page_group, mi_len, mi, request->chan_type); } diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index c99766a72..bbf812965 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -24,13 +24,20 @@ #include #include +#include +#include #define COMPARE(result, op, value) \ if (!((result) op (value))) {\ fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \ exit(-1); \ } - + +#define COMPARE_STR(result, value) \ + if (strcmp(result, value) != 0) { \ + fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \ + exit(-1); \ + } /* * Test Location Area Identifier formatting. Table 10.5.3 of 04.08 @@ -58,9 +65,38 @@ static void test_location_area_identifier(void) COMPARE(lai48.lac, ==, htons(0x000f)); } +static void test_mi_functionality(void) +{ + const char *imsi_odd = "987654321098763"; + const char *imsi_even = "9876543210987654"; + const u_int32_t tmsi = 0xfabeacd0; + u_int8_t mi[128]; + unsigned int mi_len; + char mi_parsed[GSM48_MI_SIZE]; + + printf("Testing parsing and generating TMSI/IMSI\n"); + + /* tmsi code */ + mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi); + gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len - 2); + COMPARE((u_int32_t)strtoul(mi_parsed, NULL, 10), ==, tmsi); + + /* imsi code */ + mi_len = gsm48_generate_mid_from_imsi(mi, imsi_odd); + gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2); + printf("hex: %s\n", hexdump(mi, mi_len)); + COMPARE_STR(mi_parsed, imsi_odd); + + mi_len = gsm48_generate_mid_from_imsi(mi, imsi_even); + gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2); + printf("hex: %s\n", hexdump(mi, mi_len)); + COMPARE_STR(mi_parsed, imsi_even); +} + int main(int argc, char** argv) { - test_location_area_identifier(); + test_location_area_identifier(); + test_mi_functionality(); }