diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h index 5a33f6051..34cec3cad 100644 --- a/include/osmocom/gsm/gsm0808.h +++ b/include/osmocom/gsm/gsm0808.h @@ -319,6 +319,9 @@ const char *gsm0808_cause_class_name(enum gsm0808_cause_class class); * \returns Cause value */ enum gsm0808_cause gsm0808_get_cause(const struct tlv_parsed *tp); +const char *gsm0808_diagnostics_octet_location_str(uint8_t pointer); +const char *gsm0808_diagnostics_bit_location_str(uint8_t bit_pointer); + extern const struct value_string gsm0808_lcls_config_names[]; extern const struct value_string gsm0808_lcls_control_names[]; extern const struct value_string gsm0808_lcls_status_names[]; diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index d8a777334..1390f0e8a 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -663,3 +663,16 @@ enum gsm0808_lcls_status { GSM0808_LCLS_STS_LOCALLY_SWITCHED = 0x04, GSM0808_LCLS_STS_NA = 0xFF }; + +/* 3GPP TS 48.008 3.2.2.32 Diagnostics */ +struct gsm0808_diagnostics { + uint8_t error_pointer_octet; +#if OSMO_IS_LITTLE_ENDIAN + uint8_t error_pointer_bit_spare:4, + error_pointer_bit:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ + uint8_t error_pointer_bit:4, error_pointer_bit_spare:4; +#endif + uint8_t msg[0]; /*! received message which provoked the error */ +} __attribute__((packed)); diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index 788f6c3c7..23468c3ef 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -21,6 +21,8 @@ * */ +#include + #include #include #include @@ -34,6 +36,9 @@ * message generation/encoding. */ +/*! Char buffer to return strings from functions */ +static __thread char str_buff[512]; + /*! Create "Complete L3 Info" for AoIP, legacy implementation. * Instead use gsm0808_create_layer3_aoip2(), which is capable of three-digit MNC with leading zeros. * \param[in] msg_l3 msgb containing Layer 3 Message @@ -1670,6 +1675,39 @@ enum gsm0808_cause gsm0808_get_cause(const struct tlv_parsed *tp) return buf[0]; } +const char *gsm0808_diagnostics_octet_location_str(uint8_t pointer) +{ + switch (pointer) { + case 0: + return "Error location not determined"; + case 1: + return "The first octet of the message received (i.e. the message type) was found erroneous (unknown)"; + case 0xfd: + return "The first octet of the BSSAP header (Discrimination) was found erroneous"; + case 0xfe: + return "(DTAP only) The DLCI (second) octet of the BSSAP header was found erroneous"; + case 0xff: + return "The last octet of the BSSAP header (length indicator) was found erroneous"; + default: + snprintf(str_buff, sizeof(str_buff), "The %d octet of the message received was found erroneous", pointer); + return str_buff; + } +} + +const char *gsm0808_diagnostics_bit_location_str(uint8_t bit_pointer) +{ + if (bit_pointer == 0) { + return "No particular part of the octet is indicated"; + } else if (bit_pointer > 8) { + return "Reserved value"; + } + + snprintf(str_buff, sizeof(str_buff), + "An error was provoked by the field whose most significant bit is in bit position %d", + bit_pointer); + return str_buff; +} + const struct value_string gsm0808_lcls_config_names[] = { { GSM0808_LCLS_CFG_BOTH_WAY, "Connect both-way" }, { GSM0808_LCLS_CFG_BOTH_WAY_AND_BICAST_UL, diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index ce557465c..70b391631 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -159,6 +159,8 @@ gsm0808_bssmap_name; gsm0808_cause_name; gsm0808_cause_class_name; gsm0808_get_cause; +gsm0808_diagnostics_octet_location_str; +gsm0808_diagnostics_bit_location_str; gsm0808_create_ass; gsm0808_create_ass2; gsm0808_create_assignment_completed; diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index ce7339015..d9640aa3b 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -379,6 +379,55 @@ static void test_create_sapi_reject() msgb_free(msg); } +static void test_dec_confusion() +{ + static const uint8_t hex[] = + { 0x26, 0x04, 0x01, 0x52, 0x1f, 0x07, 0x00, 0xff, 0x00, 0x03, 0x25, 0x03, 0x25 }; + struct tlv_parsed tp; + int diag_len; + enum gsm0808_cause cause; + enum gsm0808_cause_class cause_class; + struct gsm0808_diagnostics *diag; + + printf("Testing decoding CONFUSION\n"); + + tlv_parse(&tp, gsm0808_att_tlvdef(), hex+1, sizeof(hex)-1, 0, 0); + + /* Check for the Cause and Diagnostic mandatory elements */ + if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE) || !TLVP_PRESENT(&tp, GSM0808_IE_DIAGNOSTIC)) { + printf("Either Cause or Diagnostic mandatory IE are not detected\n"); + return; + } + + diag_len = TLVP_LEN(&tp, GSM0808_IE_DIAGNOSTIC); + if (diag_len < 5) { + printf("Diagnostic length is too short: %d (expected > 5)\n", + diag_len); + return; + } + + cause = gsm0808_get_cause(&tp); + if ((int)cause < 0) { + printf("ERROR: failed (%s) to extract Cause, aborting\n", strerror(-(int)cause)); + return; + } + cause_class = gsm0808_cause_class(cause); + printf(" Cause class %d/0x%x (%s)\n", + cause_class, cause_class, gsm0808_cause_class_name(cause_class)); + printf(" Cause %d/0x%x (%s)\n", + cause, cause, gsm0808_cause_name(cause)); + + diag = (struct gsm0808_diagnostics *)TLVP_VAL(&tp, GSM0808_IE_DIAGNOSTIC); + printf(" Diagnostics error octet location %d (%s)\n", + diag->error_pointer_octet, + gsm0808_diagnostics_octet_location_str(diag->error_pointer_octet)); + printf(" Diagnostics error bit location %d (%s)\n", + diag->error_pointer_bit, + gsm0808_diagnostics_bit_location_str(diag->error_pointer_bit)); + printf(" Diagnostics message that provoked the error: %s\n", + osmo_hexdump(diag->msg, diag_len-2)); +} + static void test_create_ass() { static const uint8_t res1[] = @@ -2422,6 +2471,8 @@ int main(int argc, char **argv) test_gsm0808_cell_id_to_from_cgi(); + test_dec_confusion(); + printf("Done\n"); return EXIT_SUCCESS; } diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok index b620e3692..eaae7a691 100644 --- a/tests/gsm0808/gsm0808_test.ok +++ b/tests/gsm0808/gsm0808_test.ok @@ -910,4 +910,10 @@ cid unknown 0x1a7:unknown 0x1a7 -> cgi 777-007-7777-7777 -> cid unknown 0x1a7:un --> gsm0808_cell_id{LAC-CI} = LAC-CI:7777-7777 --> gsm0808_cell_id{LAI} = LAI:777-007-7777 --> gsm0808_cell_id{CGI} = CGI:777-007-7777-7777 +Testing decoding CONFUSION + Cause class 5/0x5 (Invalid message) + Cause 82/0x52 (INFORMATION ELEMENT OR FIELD MISSING) + Diagnostics error octet location 0 (Error location not determined) + Diagnostics error bit location 15 (Reserved value) + Diagnostics message that provoked the error: 00 03 25 03 25 Done