diff options
author | Neels Hofmeyr <neels@hofmeyr.de> | 2020-05-26 02:45:23 +0200 |
---|---|---|
committer | Neels Hofmeyr <neels@hofmeyr.de> | 2020-06-12 16:35:26 +0200 |
commit | d1ceca9d48eb3d8b212f386a1ebb35d8fc612297 (patch) | |
tree | ed3b0558378654bf1699c98b766b78520dde2d97 /tests/gsm0408 | |
parent | 0b6a8c8446497da32970b8442c68eca796518b6d (diff) |
add osmo_mobile_identity API
Implement better API around 3GPP TS 24.008 Mobile Identity coding.
struct osmo_mobile_identity is a decoded representation of the raw Mobile
Identity, with a string representation as well as dedicated raw uint32_t TMSI.
The aim is to remove all uncertainty about decoded buffer sizes / data types.
I have patches ready for all osmo programs, completely replacing the Mobile
Identity coding with this new API. Hence deprecate the old MI API.
New API functions provide properly size-checking implementations of:
- decoding a raw MI from a bunch of MI octets;
- locating and decoding MI from a full 3GPP TS 24.008 Complete Layer 3 msgb;
- encoding to a buffer;
- encoding to the end of a msgb.
Other than the old gsm48_generate_mid(), omit a TLV tag and length from
encoding. Many callers manually stripped the tag and value after calling
gsm48_generate_mid(). The aim is to leave writing a TL to the caller entirely,
especially since some callers need to use a TvL, i.e. support a variable-size
length of 8 or 16 bit.
New validity checks so far not implemented anywhere else:
- stricter validation of number of digits of IMSI, IMEI, IMEI-SV MI.
- stricter on filler nibbles to be 0xf.
Rationale:
While implementing osmo-bsc's MSC pooling feature in osmo-bsc, this API will be
used to reduce the number of times a Mobile Identity is extracted from a raw
RSL message.
Extracting the Mobile Identity from messages has numerous duplicate
implementations across our code with various levels of specialization.
https://xkcd.com/927/
To name a few:
- libosmocore: gsm48_mi_to_string(), osmo_mi_name_buf()
- osmo-bsc: extract_sub()
- osmo-msc: mm_rx_loc_upd_req(), cm_serv_reuse_conn(), gsm48_rx_mm_serv_req(),
vlr_proc_acc_req()
We have existing functions to produce a human readable string from a Mobile
Identity, more or less awkward:
- gsm48_mi_to_string() decodes a TMSI as a decimal number. These days we use
hexadecimal TMSI everywhere.
- osmo_mi_name_buf() decodes the BCD digits from a raw MI every time, so we'd
need to pass around the raw message bytes. Also, osmo_mi_name_buf() has the
wrong signature, it should return a length like snprintf().
- osmo-bsc's extract_sub() first uses gsm48_mi_to_string() which encodes the
raw uint32_t TMSI to a string, and then calls strtoul() via
tmsi_from_string() to code those back to a raw uint32_t.
Each of the above implementations employ their own size overflow checks, each
invoke osmo_bcd2str() and implement their own TMSI osmo_load32be() handling.
Too much code dup, let's hope that each and every one is correct.
In osmo-bsc, I am now implementing MSC pooling, and need to extract NRI bits
from a TMSI Mobile Identity. Since none of the above functions are general
enough to be re-used, I found myself again copy-pasting Mobile Identity code:
locating the MI in a 24.008 message with proper size checks, decoding MI
octets.
This time I would like it to become a generally re-usable API.
Change-Id: Ic3f969e739654c1e8c387aedeeba5cce07fe2307
Diffstat (limited to 'tests/gsm0408')
-rw-r--r-- | tests/gsm0408/gsm0408_test.c | 387 | ||||
-rw-r--r-- | tests/gsm0408/gsm0408_test.ok | 63 |
2 files changed, 436 insertions, 14 deletions
diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index 96178237..a86fe110 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -18,6 +18,8 @@ * */ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -386,8 +388,9 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = { .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD, .mi_str = "423423", - .mi_name = "IMSI-423423", - .expect_mi_tlv_hex = "1704413224f3", + .expect_str = "", + .expect_rc = 1, + .mi_name = "unknown", }, { .mi_type = GSM_MI_TYPE_IMSI, @@ -471,21 +474,21 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = .mi_type = GSM_MI_TYPE_NONE, .mi_str = "123", .mi_name = "unknown", - .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */ + .expect_mi_tlv_hex = "", .expect_str = "", }, { .mi_type = GSM_MI_TYPE_NONE, .mi_str = "1234", .mi_name = "unknown", - .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */ + .expect_mi_tlv_hex = "", .expect_str = "", }, { .mi_type = GSM_MI_ODD, .mi_str = "1234", .mi_name = "unknown", - .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */ + .expect_mi_tlv_hex = "", .expect_str = "", }, }; @@ -522,9 +525,14 @@ static void test_mid_encode_decode(void) printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex); } - /* skip the GSM48_IE_MOBILE_ID tag and length */ - mi_buf = tlv_buf + 2; - mi_len = tlv_len - 2; + if (tlv_len) { + /* skip the GSM48_IE_MOBILE_ID tag and length */ + mi_buf = tlv_buf + 2; + mi_len = tlv_len - 2; + } else { + mi_buf = NULL; + mi_len = 0; + } rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len); printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc); @@ -611,6 +619,368 @@ static void test_mid_decode_zero_length(void) printf("\n"); } +struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex) +{ + struct msgb *msg = msgb_alloc_headroom(size, 4, label); + OSMO_ASSERT(msg); + msg->l3h = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg))); + return msg; +} + +struct mobile_identity_tc { + const char *label; + const char *compl_l3_msg; + int expect_rc; + struct osmo_mobile_identity expect_mi; +}; + +/* Some Complete Layer 3 messages copied from real GSM network traces. */ +struct mobile_identity_tc mobile_identity_tests[] = { + { + .label = "LU with IMSI 901700000004620", + .compl_l3_msg = "050802008168000130" "089910070000006402", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "901700000004620", + }, + }, + { + .label = "LU with TMSI 0x0980ad8a", + .compl_l3_msg = "05084262f224002a50" "05f40980ad8a", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0x0980ad8a, + }, + }, + { + .label = "LU with invalid MI type", + .compl_l3_msg = "050802008168000130" "089d10070000006402", + .expect_rc = -EINVAL, + }, + { + .label = "LU with truncated IMSI MI", + .compl_l3_msg = "050802008168000130" "0899100700000064", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with too short IMSI MI (12345)", + .compl_l3_msg = "050802008168000130" "03193254", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with just long enough IMSI MI 123456", + .compl_l3_msg = "050802008168000130" "04113254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456", + }, + }, + { + .label = "LU with max length IMSI MI 123456789012345", + .compl_l3_msg = "050802008168000130" "081932547698103254", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456789012345", + }, + }, + { + .label = "LU with just too long IMSI MI 1234567890123456", + .compl_l3_msg = "050802008168000130" "091132547698103254f6", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with truncated TMSI MI", + .compl_l3_msg = "05084262f224002a50" "05f40980ad", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with odd length TMSI", + .compl_l3_msg = "05084262f224002a50" "05fc0980ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with too long TMSI MI", + .compl_l3_msg = "05084262f224002a50" "06f40980ad23", + .expect_rc = -EBADMSG, + }, + { + .label = "LU with too short TMSI", + .compl_l3_msg = "05084262f224002a50" "04f480ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Request with IMSI 123456", + .compl_l3_msg = "052401035058a6" "04113254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456", + }, + }, + { + .label = "CM Service Request with TMSI 0x5a42e404", + .compl_l3_msg = "052401035058a6" "05f45a42e404", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0x5a42e404, + }, + }, + { + .label = "CM Service Request with shorter CM2, with IMSI 123456", + .compl_l3_msg = "052401025058" "04113254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456", + }, + }, + { + .label = "CM Service Request with longer CM2, with IMSI 123456", + .compl_l3_msg = "052401055058a62342" "04113254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456", + }, + }, + { + .label = "CM Service Request with shorter CM2, with TMSI 0x00000000", + .compl_l3_msg = "052401025058" "05f400000000", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0, + }, + }, + { + .label = "CM Service Request with invalid MI type", + .compl_l3_msg = "052401035058a6" "089d10070000006402", + .expect_rc = -EINVAL, + }, + { + .label = "CM Service Request with truncated IMSI MI", + .compl_l3_msg = "052401035058a6" "0899100700000064", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Request with truncated TMSI MI", + .compl_l3_msg = "0524010150" "05f40980ad", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Request with odd length TMSI", + .compl_l3_msg = "052401045058a623" "05fc0980ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Request with too long TMSI MI", + .compl_l3_msg = "052401035058a6" "06f40980ad23", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Request with too short TMSI", + .compl_l3_msg = "052401035058a6" "04f480ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "CM Service Reestablish Request with TMSI 0x5a42e404", + .compl_l3_msg = "052801035058a6" "05f45a42e404", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0x5a42e404, + }, + }, + { + .label = "Paging Response with IMSI 1234567", + .compl_l3_msg = "06270003505886" "0419325476", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "1234567", + }, + }, + { + .label = "Paging Response with TMSI 0xb48883de", + .compl_l3_msg = "06270003505886" "05f4b48883de", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0xb48883de, + }, + }, + { + .label = "Paging Response with TMSI, with unused nibble not 0xf", + .compl_l3_msg = "06270003505886" "0504b48883de", + .expect_rc = -EBADMSG, + }, + { + .label = "Paging Response with too short IMEI (1234567)", + .compl_l3_msg = "06270003505886" "041a325476", + .expect_rc = -EBADMSG, + }, + { + .label = "Paging Response with IMEI 123456789012345", + .compl_l3_msg = "06270003505886" "081a32547698103254", + .expect_mi = { + .type = GSM_MI_TYPE_IMEI, + .imei = "123456789012345", + }, + }, + { + .label = "Paging Response with IMEI 12345678901234 (no Luhn checksum)", + .compl_l3_msg = "06270003505886" "0812325476981032f4", + .expect_mi = { + .type = GSM_MI_TYPE_IMEI, + .imei = "12345678901234", + }, + }, + { + .label = "Paging Response with IMEISV 1234567890123456", + .compl_l3_msg = "06270003505886" "091332547698103254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMEISV, + .imeisv = "1234567890123456", + }, + }, + { + .label = "Paging Response with too short IMEISV 123456789012345", + .compl_l3_msg = "06270003505886" "081b32547698103254", + .expect_rc = -EBADMSG, + }, + { + .label = "Paging Response with too long IMEISV 12345678901234567", + .compl_l3_msg = "06270003505886" "091b3254769810325476", + .expect_rc = -EBADMSG, + }, + { + .label = "Paging Response with IMSI 123456789012345 and flipped ODD bit", + .compl_l3_msg = "06270003505886" "081132547698103254", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with IMSI 901700000004620", + .compl_l3_msg = "050130" "089910070000006402", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "901700000004620", + }, + }, + { + .label = "IMSI-Detach with TMSI 0x0980ad8a", + .compl_l3_msg = "050130" "05f40980ad8a", + .expect_mi = { + .type = GSM_MI_TYPE_TMSI, + .tmsi = 0x0980ad8a, + }, + }, + { + .label = "IMSI-Detach with invalid MI type", + .compl_l3_msg = "050130" "089d10070000006402", + .expect_rc = -EINVAL, + }, + { + .label = "IMSI-Detach with truncated IMSI MI", + .compl_l3_msg = "050130" "0899100700000064", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with too short IMSI MI (12345)", + .compl_l3_msg = "050130" "03193254", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with just long enough IMSI MI 123456", + .compl_l3_msg = "050130" "04113254f6", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456", + }, + }, + { + .label = "IMSI-Detach with max length IMSI MI 123456789012345", + .compl_l3_msg = "050130" "081932547698103254", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "123456789012345", + }, + }, + { + .label = "IMSI-Detach with just too long IMSI MI 1234567890123456", + .compl_l3_msg = "050130" "091132547698103254f6", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with truncated TMSI MI", + .compl_l3_msg = "050130" "05f40980ad", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with odd length TMSI", + .compl_l3_msg = "050130" "05fc0980ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with too long TMSI MI", + .compl_l3_msg = "050130" "06f40980ad23", + .expect_rc = -EBADMSG, + }, + { + .label = "IMSI-Detach with too short TMSI", + .compl_l3_msg = "050130" "04f480ad8a", + .expect_rc = -EBADMSG, + }, + { + .label = "Identity Response with IMSI 901700000004620", + .compl_l3_msg = "0519" "089910070000006402", + .expect_mi = { + .type = GSM_MI_TYPE_IMSI, + .imsi = "901700000004620", + }, + }, + { + .label = "Identity Response with IMEI 123456789012345", + .compl_l3_msg = "0519" "081a32547698103254", + .expect_mi = { + .type = GSM_MI_TYPE_IMEI, + .imei = "123456789012345", + }, + }, + { + .label = "Identity Response with IMEISV 9876543210987654", + .compl_l3_msg = "0519" "099378563412907856f4", + .expect_mi = { + .type = GSM_MI_TYPE_IMEISV, + .imeisv = "9876543210987654", + }, + }, +}; + +void test_struct_mobile_identity() +{ + struct mobile_identity_tc *t; + printf("%s()\n", __func__); + for (t = mobile_identity_tests; (t - mobile_identity_tests) < ARRAY_SIZE(mobile_identity_tests); t++) { + struct osmo_mobile_identity mi; + struct msgb *msg; + int rc; + memset(&mi, 0xff, sizeof(mi)); + + msg = msgb_from_hex(t->label, 1024, t->compl_l3_msg); + rc = osmo_mobile_identity_decode_from_l3(&mi, msg, false); + msgb_free(msg); + + printf("%s: rc = %d", t->label, rc); + if (!rc) { + printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &mi)); + } + + if (rc == t->expect_rc + && ((rc != 0) || !osmo_mobile_identity_cmp(&mi, &t->expect_mi))) { + printf(" ok"); + } else { + printf(" ERROR: Expected rc = %d", t->expect_rc); + if (!t->expect_rc) + printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &t->expect_mi)); + } + printf("\n"); + } + printf("\n"); +} + static const struct bcd_number_test { /* Human-readable test name */ const char *test_name; @@ -1182,6 +1552,7 @@ int main(int argc, char **argv) test_mid_from_imsi(); test_mid_encode_decode(); test_mid_decode_zero_length(); + test_struct_mobile_identity(); test_bcd_number_encode_decode(); test_ra_cap(); test_lai_encode_decode(); diff --git a/tests/gsm0408/gsm0408_test.ok b/tests/gsm0408/gsm0408_test.ok index d343869f..f8de54af 100644 --- a/tests/gsm0408/gsm0408_test.ok +++ b/tests/gsm0408/gsm0408_test.ok @@ -17,9 +17,9 @@ Testing Mobile Identity conversions -> MI-str="423423" rc=7 -> MI-name="IMSI-423423" - unknown 0x9 423423 - -> MI-TLV-hex='1704413224f3' - -> MI-str="423423" rc=7 - -> MI-name="IMSI-423423" + -> MI-TLV-hex='' + -> MI-str="" rc=1 + -> MI-name="unknown" - IMSI 4234235 -> MI-TLV-hex='170449322453' -> MI-str="4234235" rc=8 @@ -65,15 +65,15 @@ Testing Mobile Identity conversions -> MI-str="3054" rc=9 -> MI-name="TMSI-0x12345678" - NONE 123 - -> MI-TLV-hex='17021832' + -> MI-TLV-hex='' -> MI-str="" rc=1 -> MI-name="unknown" - NONE 1234 - -> MI-TLV-hex='17031032f4' + -> MI-TLV-hex='' -> MI-str="" rc=1 -> MI-name="unknown" - unknown 0x8 1234 - -> MI-TLV-hex='17031032f4' + -> MI-TLV-hex='' -> MI-str="" rc=1 -> MI-name="unknown" @@ -139,6 +139,57 @@ Decoding zero length Mobile Identities rc=1 returned empty string +test_struct_mobile_identity() +LU with IMSI 901700000004620: rc = 0, mi = IMSI-901700000004620 ok +LU with TMSI 0x0980ad8a: rc = 0, mi = TMSI-0x0980AD8A ok +LU with invalid MI type: rc = -22 ok +LU with truncated IMSI MI: rc = -74 ok +LU with too short IMSI MI (12345): rc = -74 ok +LU with just long enough IMSI MI 123456: rc = 0, mi = IMSI-123456 ok +LU with max length IMSI MI 123456789012345: rc = 0, mi = IMSI-123456789012345 ok +LU with just too long IMSI MI 1234567890123456: rc = -74 ok +LU with truncated TMSI MI: rc = -74 ok +LU with odd length TMSI: rc = -74 ok +LU with too long TMSI MI: rc = -74 ok +LU with too short TMSI: rc = -74 ok +CM Service Request with IMSI 123456: rc = 0, mi = IMSI-123456 ok +CM Service Request with TMSI 0x5a42e404: rc = 0, mi = TMSI-0x5A42E404 ok +CM Service Request with shorter CM2, with IMSI 123456: rc = 0, mi = IMSI-123456 ok +CM Service Request with longer CM2, with IMSI 123456: rc = 0, mi = IMSI-123456 ok +CM Service Request with shorter CM2, with TMSI 0x00000000: rc = 0, mi = TMSI-0x00000000 ok +CM Service Request with invalid MI type: rc = -22 ok +CM Service Request with truncated IMSI MI: rc = -74 ok +CM Service Request with truncated TMSI MI: rc = -74 ok +CM Service Request with odd length TMSI: rc = -74 ok +CM Service Request with too long TMSI MI: rc = -74 ok +CM Service Request with too short TMSI: rc = -74 ok +CM Service Reestablish Request with TMSI 0x5a42e404: rc = 0, mi = TMSI-0x5A42E404 ok +Paging Response with IMSI 1234567: rc = 0, mi = IMSI-1234567 ok +Paging Response with TMSI 0xb48883de: rc = 0, mi = TMSI-0xB48883DE ok +Paging Response with TMSI, with unused nibble not 0xf: rc = -74 ok +Paging Response with too short IMEI (1234567): rc = -74 ok +Paging Response with IMEI 123456789012345: rc = 0, mi = IMEI-123456789012345 ok +Paging Response with IMEI 12345678901234 (no Luhn checksum): rc = 0, mi = IMEI-12345678901234 ok +Paging Response with IMEISV 1234567890123456: rc = 0, mi = IMEI-SV-1234567890123456 ok +Paging Response with too short IMEISV 123456789012345: rc = -74 ok +Paging Response with too long IMEISV 12345678901234567: rc = -74 ok +Paging Response with IMSI 123456789012345 and flipped ODD bit: rc = -74 ok +IMSI-Detach with IMSI 901700000004620: rc = 0, mi = IMSI-901700000004620 ok +IMSI-Detach with TMSI 0x0980ad8a: rc = 0, mi = TMSI-0x0980AD8A ok +IMSI-Detach with invalid MI type: rc = -22 ok +IMSI-Detach with truncated IMSI MI: rc = -74 ok +IMSI-Detach with too short IMSI MI (12345): rc = -74 ok +IMSI-Detach with just long enough IMSI MI 123456: rc = 0, mi = IMSI-123456 ok +IMSI-Detach with max length IMSI MI 123456789012345: rc = 0, mi = IMSI-123456789012345 ok +IMSI-Detach with just too long IMSI MI 1234567890123456: rc = -74 ok +IMSI-Detach with truncated TMSI MI: rc = -74 ok +IMSI-Detach with odd length TMSI: rc = -74 ok +IMSI-Detach with too long TMSI MI: rc = -74 ok +IMSI-Detach with too short TMSI: rc = -74 ok +Identity Response with IMSI 901700000004620: rc = 0, mi = IMSI-901700000004620 ok +Identity Response with IMEI 123456789012345: rc = 0, mi = IMEI-123456789012345 ok +Identity Response with IMEISV 9876543210987654: rc = 0, mi = IMEI-SV-9876543210987654 ok + BSD number encoding / decoding test - Running test: regular 9-digit MSISDN - Encoding ASCII (buffer limit=0) '123456789'... |