From 02fd83d79991665d59362f24d7a0ed263c6d91c0 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sat, 5 Jan 2019 00:38:54 +0100 Subject: [PATCH] add osmo_mi_name(), for MI-to-string like "IMSI-123456" We have gsm48_mi_to_string() and osmo_bcd2str(), but still lack a function that conveniently prints both MI type and value in one function call. Related: http://people.osmocom.org/neels/mi_mi_mi.jpg Change-Id: I7798c3ef983c2e333b2b9cbffef6f366f370bd81 --- include/osmocom/gsm/gsm48.h | 1 + src/gsm/gsm48.c | 36 +++++++++++++++++++++++++++++++++++ src/gsm/libosmogsm.map | 1 + tests/gsm0408/gsm0408_test.c | 26 +++++++++++++++++++++++++ tests/gsm0408/gsm0408_test.ok | 18 ++++++++++++++++++ 5 files changed, 82 insertions(+) diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h index 2b14e6cd5..0f5727a07 100644 --- a/include/osmocom/gsm/gsm48.h +++ b/include/osmocom/gsm/gsm48.h @@ -53,6 +53,7 @@ uint8_t gsm48_generate_mid(uint8_t *buf, const char *id, uint8_t mi_type); int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, const int mi_len); const char *gsm48_mi_type_name(uint8_t mi); +const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len); /* Parse Routeing Area Identifier */ void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf); diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c index 190622ff8..853ea5134 100644 --- a/src/gsm/gsm48.c +++ b/src/gsm/gsm48.c @@ -433,6 +433,42 @@ const char *gsm48_mi_type_name(uint8_t mi) return get_value_string(mi_type_names, mi); } +/*! Return a human readable representation of a Mobile Identity in static buffer. + * \param[in] mi Mobile Identity buffer containing 3GPP TS 04.08 style MI type and data. + * \param[in] mi_len Length of mi. + * \return A string like "IMSI-1234567", "TMSI-0x1234ABCD" or "unknown", "TMSI-invalid"... + */ +const char *osmo_mi_name(const uint8_t *mi, uint8_t mi_len) +{ + static char mi_name[10 + GSM48_MI_SIZE + 1]; + uint8_t mi_type; + uint32_t tmsi; + char mi_string[GSM48_MI_SIZE]; + + mi_type = (mi && mi_len) ? (mi[0] & GSM_MI_TYPE_MASK) : GSM_MI_TYPE_NONE; + + switch (mi_type) { + case GSM_MI_TYPE_TMSI: + /* Table 10.5.4.3, reverse generate_mid_from_tmsi */ + if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { + tmsi = osmo_load32be(&mi[1]); + snprintf(mi_name, sizeof(mi_name), "TMSI-0x%08" PRIX32, tmsi); + return mi_name; + } + return "TMSI-invalid"; + + case GSM_MI_TYPE_IMSI: + case GSM_MI_TYPE_IMEI: + case GSM_MI_TYPE_IMEISV: + osmo_bcd2str(mi_string, sizeof(mi_string), mi, 1, (mi_len * 2) - (mi[0] & GSM_MI_ODD ? 0 : 1), true); + snprintf(mi_name, sizeof(mi_name), "%s-%s", gsm48_mi_type_name(mi_type), mi_string); + return mi_name; + + default: + return "unknown"; + } +} + /*! Checks is particular message is cipherable in A/Gb mode according to * 3GPP TS 24.008 ยง 4.7.1.2 * \param[in] hdr Message header diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index bb978786a..8b7a1641b 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -325,6 +325,7 @@ gsm48_rr_att_tlvdef; gsm48_set_dtx; gsm48_dtx_mode; gsm48_mi_type_name; +osmo_mi_name; gsm48_mcc_mnc_to_bcd; gsm48_mcc_mnc_from_bcd; gsm48_generate_lai2; diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index 9bb320d05..37ef3f151 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -355,6 +355,7 @@ static void test_mid_from_imsi(void) struct test_mid_encode_decode_test { uint8_t mi_type; const char *mi_str; + const char *mi_name; size_t str_size; const char *expect_mi_tlv_hex; const char *expect_str; @@ -365,31 +366,37 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = { .mi_type = GSM_MI_TYPE_IMSI, .mi_str = "123456789012345", + .mi_name = "IMSI-123456789012345", .expect_mi_tlv_hex = "17081932547698103254", }, { .mi_type = GSM_MI_TYPE_IMSI, .mi_str = "12345678901234", + .mi_name = "IMSI-12345678901234", .expect_mi_tlv_hex = "170811325476981032f4", }, { .mi_type = GSM_MI_TYPE_IMSI, .mi_str = "423423", + .mi_name = "IMSI-423423", .expect_mi_tlv_hex = "1704413224f3", }, { .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD, .mi_str = "423423", + .mi_name = "IMSI-423423", .expect_mi_tlv_hex = "1704413224f3", }, { .mi_type = GSM_MI_TYPE_IMSI, .mi_str = "4234235", + .mi_name = "IMSI-4234235", .expect_mi_tlv_hex = "170449322453", }, { .mi_type = GSM_MI_TYPE_IMSI, .mi_str = "4234235", + .mi_name = "IMSI-4234235", .expect_mi_tlv_hex = "170449322453", .str_size = 4, .expect_str = "423", @@ -397,26 +404,31 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = { .mi_type = GSM_MI_TYPE_IMEI, .mi_str = "123456789012345", + .mi_name = "IMEI-123456789012345", .expect_mi_tlv_hex = "17081a32547698103254", }, { .mi_type = GSM_MI_TYPE_IMEI, .mi_str = "98765432109876", + .mi_name = "IMEI-98765432109876", .expect_mi_tlv_hex = "170892785634129078f6", }, { .mi_type = GSM_MI_TYPE_IMEI, .mi_str = "987654321098765", + .mi_name = "IMEI-987654321098765", .expect_mi_tlv_hex = "17089a78563412907856", }, { .mi_type = GSM_MI_TYPE_IMEISV, .mi_str = "987654321098765432", + .mi_name = "IMEI-SV-987654321098765432", .expect_mi_tlv_hex = "170a937856341290785634f2", }, { .mi_type = GSM_MI_TYPE_IMEISV, .mi_str = "987654321098765432", + .mi_name = "IMEI-SV-987654321098765432", .expect_mi_tlv_hex = "170a937856341290785634f2", .str_size = 16, .expect_str = "987654321098765", @@ -425,18 +437,21 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = /* gsm48 treats TMSI as decimal string */ .mi_type = GSM_MI_TYPE_TMSI, .mi_str = "305419896", /* 0x12345678 as decimal */ + .mi_name = "TMSI-0x12345678", .expect_mi_tlv_hex = "1705f412345678", .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */ }, { .mi_type = GSM_MI_TYPE_TMSI, .mi_str = "12648430", /* 0xc0ffee as decimal */ + .mi_name = "TMSI-0x00C0FFEE", .expect_mi_tlv_hex = "1705f400c0ffee", .expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */ }, { .mi_type = GSM_MI_TYPE_TMSI, .mi_str = "0", + .mi_name = "TMSI-0x00000000", .expect_mi_tlv_hex = "1705f400000000", .expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */ }, @@ -444,6 +459,7 @@ static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = /* gsm48 treats TMSI as decimal string */ .mi_type = GSM_MI_TYPE_TMSI, .mi_str = "305419896", /* 0x12345678 as decimal */ + .mi_name = "TMSI-0x12345678", .expect_mi_tlv_hex = "1705f412345678", .str_size = 5, .expect_str = "3054", @@ -452,18 +468,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_str = "", }, { .mi_type = GSM_MI_TYPE_NONE, .mi_str = "1234", + .mi_name = "unknown", .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */ .expect_str = "", }, { .mi_type = GSM_MI_ODD, .mi_str = "1234", + .mi_name = "unknown", .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */ .expect_str = "", }, @@ -512,6 +531,13 @@ static void test_mid_encode_decode(void) if (rc != expect_rc) printf(" ERROR: expected rc=%d\n", expect_rc); + if (t->mi_name) { + const char *mi_name = osmo_mi_name(mi_buf, mi_len); + printf(" -> MI-name=%s\n", osmo_quote_str(mi_name, -1)); + if (strcmp(mi_name, t->mi_name)) + printf(" ERROR: expected MI-name=%s\n", osmo_quote_str(t->mi_name, -1)); + } + /* Now make sure the resulting string is always '\0' terminated. * The above started out with a zeroed buffer, now repeat with a tainted one. */ str_len = strlen(str); diff --git a/tests/gsm0408/gsm0408_test.ok b/tests/gsm0408/gsm0408_test.ok index d6579e503..0c1355580 100644 --- a/tests/gsm0408/gsm0408_test.ok +++ b/tests/gsm0408/gsm0408_test.ok @@ -7,57 +7,75 @@ Testing Mobile Identity conversions - IMSI 123456789012345 -> MI-TLV-hex='17081932547698103254' -> MI-str="123456789012345" rc=16 + -> MI-name="IMSI-123456789012345" - IMSI 12345678901234 -> MI-TLV-hex='170811325476981032f4' -> MI-str="12345678901234" rc=15 + -> MI-name="IMSI-12345678901234" - IMSI 423423 -> MI-TLV-hex='1704413224f3' -> 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" - IMSI 4234235 -> MI-TLV-hex='170449322453' -> MI-str="4234235" rc=8 + -> MI-name="IMSI-4234235" - IMSI 4234235 -> MI-TLV-hex='170449322453' -> MI-str="423" rc=4 + -> MI-name="IMSI-4234235" - IMEI 123456789012345 -> MI-TLV-hex='17081a32547698103254' -> MI-str="123456789012345" rc=16 + -> MI-name="IMEI-123456789012345" - IMEI 98765432109876 -> MI-TLV-hex='170892785634129078f6' -> MI-str="98765432109876" rc=15 + -> MI-name="IMEI-98765432109876" - IMEI 987654321098765 -> MI-TLV-hex='17089a78563412907856' -> MI-str="987654321098765" rc=16 + -> MI-name="IMEI-987654321098765" - IMEI-SV 987654321098765432 -> MI-TLV-hex='170a937856341290785634f2' -> MI-str="987654321098765432" rc=19 + -> MI-name="IMEI-SV-987654321098765432" - IMEI-SV 987654321098765432 -> MI-TLV-hex='170a937856341290785634f2' -> MI-str="987654321098765" rc=16 + -> MI-name="IMEI-SV-987654321098765432" - TMSI 305419896 -> MI-TLV-hex='1705f412345678' -> MI-str="305419896" rc=9 + -> MI-name="TMSI-0x12345678" - TMSI 12648430 -> MI-TLV-hex='1705f400c0ffee' -> MI-str="12648430" rc=8 + -> MI-name="TMSI-0x00C0FFEE" - TMSI 0 -> MI-TLV-hex='1705f400000000' -> MI-str="0" rc=1 + -> MI-name="TMSI-0x00000000" - TMSI 305419896 -> MI-TLV-hex='1705f412345678' -> MI-str="3054" rc=9 + -> MI-name="TMSI-0x12345678" - NONE 123 -> MI-TLV-hex='17021832' -> MI-str="" rc=1 + -> MI-name="unknown" - NONE 1234 -> MI-TLV-hex='17031032f4' -> MI-str="" rc=1 + -> MI-name="unknown" - unknown 0x8 1234 -> MI-TLV-hex='17031032f4' -> MI-str="" rc=1 + -> MI-name="unknown" Decoding zero length Mobile Identities - MI type: IMSI