From 5a09f75c1e7f66869da4a17c4cc417d367687b72 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Mon, 11 Jun 2018 04:58:53 +0700 Subject: gsm/gsm0480: refactor and expose gsm0480_parse_facility_ie() This function can be used when there is only a part of GSM 04.80 message available - Facility IE, e.g. when a message is carried over GSUP/MAP. Let's expose it. Refactoring includes the following: - adding the 'gsm0480_' prefix; - correcting inverted return value; - cosmetic code style changes. Change-Id: I623c39ffbe6cdee65eade8435a2faa04d0da193e --- include/osmocom/gsm/gsm0480.h | 2 ++ src/gsm/gsm0480.c | 46 ++++++++++++++++++++++++++++--------------- src/gsm/libosmogsm.map | 1 + tests/ussd/ussd_test.c | 40 +++++++++++++++++++++++++++++++++++++ tests/ussd/ussd_test.ok | 8 ++++++++ 5 files changed, 81 insertions(+), 16 deletions(-) diff --git a/include/osmocom/gsm/gsm0480.h b/include/osmocom/gsm/gsm0480.h index b31f8a71..fafa1f4b 100644 --- a/include/osmocom/gsm/gsm0480.h +++ b/include/osmocom/gsm/gsm0480.h @@ -93,6 +93,8 @@ struct ss_request { int gsm0480_extract_ie_by_tag(const struct gsm48_hdr *hdr, uint16_t msg_len, uint8_t **ie, uint16_t *ie_len, uint8_t ie_tag); +int gsm0480_parse_facility_ie(const uint8_t *facility_ie, uint16_t length, + struct ss_request *req); int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len, struct ss_request *request); diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index dfd98773..300c0ede 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -201,8 +201,6 @@ static int parse_ss_facility(const uint8_t *ss_facility, uint16_t len, struct ss_request *req); static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len, struct ss_request *req); -static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, - struct ss_request *req); static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, struct ss_request *req); static int parse_ss_return_result(const uint8_t *rr_data, uint16_t length, @@ -419,7 +417,7 @@ static int parse_ss_facility(const uint8_t *ss_facility, uint16_t len, if (len - 1 < facility_length) return 0; - return parse_facility_ie(ss_facility + 1, facility_length, req); + return !gsm0480_parse_facility_ie(ss_facility + 1, facility_length, req); } static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len, @@ -445,7 +443,7 @@ static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len, case GSM48_IE_CAUSE: break; case GSM0480_IE_FACILITY: - rc = parse_facility_ie(ss_ie + 2, iei_length, req); + rc = !gsm0480_parse_facility_ie(ss_ie + 2, iei_length, req); break; case GSM0480_IE_SS_VERSION: break; @@ -464,31 +462,40 @@ static int parse_ss_info_elements(const uint8_t *ss_ie, uint16_t len, return rc; } -static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, - struct ss_request *req) +/*! Parse the components of a given Facility IE + * \param[in] facility_ie The Facility IE + * \param[in] length The length of Facility IE + * \param[out] req Abstract representation of SS message + * \return 0 in case of success, otherwise -ERRNO + */ +int gsm0480_parse_facility_ie(const uint8_t *facility_ie, uint16_t length, + struct ss_request *req) { - int rc = 1; + uint8_t component_length; + uint8_t component_type; uint8_t offset = 0; + int rc = 1; + /* Iterate over components within IE */ while (offset + 2 <= length) { /* Component Type tag - table 3.7 */ - uint8_t component_type = facility_ie[offset]; - uint8_t component_length = facility_ie[offset+1]; + component_type = facility_ie[offset]; + component_length = facility_ie[offset + 1]; - /* size check */ + /* Make sure that there is no overflow */ if (offset + 2 + component_length > length) { LOGP(0, LOGL_ERROR, "Component does not fit.\n"); - return 0; + return -EINVAL; } switch (component_type) { case GSM0480_CTYPE_INVOKE: - rc &= parse_ss_invoke(facility_ie+2, + rc &= parse_ss_invoke(facility_ie + 2, component_length, req); break; case GSM0480_CTYPE_RETURN_RESULT: - rc &= parse_ss_return_result(facility_ie+2, + rc &= parse_ss_return_result(facility_ie + 2, component_length, req); break; @@ -502,10 +509,17 @@ static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, rc = 0; break; } - offset += (component_length+2); - }; - return rc; + offset += (component_length + 2); + } + + /** + * The internal functions are using inverted return + * codes, where '0' means error/failure. While a + * common approach is to return negative errno in + * case of any failure, and '0' if all is ok. + */ + return (rc == 0) ? -EINVAL : 0; } /* Parse an Invoke component - see table 3.3 */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 4aaed46e..0a6742cc 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -90,6 +90,7 @@ gsm0480_create_ussd_resp; gsm0480_create_ussd_notify; gsm0480_create_ussd_release_complete; gsm0480_extract_ie_by_tag; +gsm0480_parse_facility_ie; gsm0480_decode_ussd_request; gsm0480_decode_ss_request; gsm0480_wrap_facility; diff --git a/tests/ussd/ussd_test.c b/tests/ussd/ussd_test.c index 23fd7393..80250711 100644 --- a/tests/ussd/ussd_test.c +++ b/tests/ussd/ussd_test.c @@ -188,6 +188,43 @@ static void test_extract_ie_by_tag(void) printf("\n"); } +static void test_parse_facility_ie(void) +{ + struct ss_request req; + uint16_t ie_len; + uint8_t *ie; + int rc; + + printf("[i] Testing gsm0480_parse_facility_ie()\n"); + + /* Extract Facility IE from FACILITY message */ + rc = gsm0480_extract_ie_by_tag((struct gsm48_hdr *) ussd_facility, + sizeof(ussd_facility), &ie, &ie_len, GSM0480_IE_FACILITY); + OSMO_ASSERT(rc == 0); + OSMO_ASSERT(ie != NULL && ie_len > 0); + printf("[?] FACILITY message with Facility IE " + "(len=%u): %s\n", ie_len, osmo_hexdump(ie, ie_len)); + + /* Attempt to decode */ + memset(&req, 0x00, sizeof(req)); + rc = gsm0480_parse_facility_ie(ie, ie_len, &req); + OSMO_ASSERT(rc == 0); + + /* Verify expected vs decoded data */ + printf("[?] InvokeID: expected 0x%02x, decoded 0x%02x\n", + 0x01, req.invoke_id); + printf("[?] Operation code: expected 0x%02x, decoded 0x%02x\n", + 0x3c, req.opcode); + printf("[?] Data Coding Scheme: expected 0x%02x, decoded 0x%02x\n", + 0x0f, req.ussd_data_dcs); + printf("[?] Data length: expected 0x%02x, decoded 0x%02x\n", + 0x01, req.ussd_data_len); + printf("[?] Data: expected %s, decoded %s\n", "32", + osmo_hexdump_nospc(req.ussd_data, req.ussd_data_len)); + + printf("\n"); +} + int main(int argc, char **argv) { struct ss_request req; @@ -201,6 +238,9 @@ int main(int argc, char **argv) /* Test gsm0480_extract_ie_by_tag() */ test_extract_ie_by_tag(); + /* Test gsm0480_parse_facility_ie() */ + test_parse_facility_ie(); + memset(&req, 0, sizeof(req)); gsm0480_decode_ss_request((struct gsm48_hdr *) ussd_request, sizeof(ussd_request), &req); diff --git a/tests/ussd/ussd_test.ok b/tests/ussd/ussd_test.ok index 8fa4348f..1137080b 100644 --- a/tests/ussd/ussd_test.ok +++ b/tests/ussd/ussd_test.ok @@ -4,6 +4,14 @@ [?] FACILITY message with Facility IE (len=18): a2 10 02 01 01 30 0b 02 01 3c 30 06 04 01 0f 04 01 32 [?] RELEASE COMPLETE message with Facility IE (len=8): a3 06 02 01 05 02 01 24 +[i] Testing gsm0480_parse_facility_ie() +[?] FACILITY message with Facility IE (len=18): a2 10 02 01 01 30 0b 02 01 3c 30 06 04 01 0f 04 01 32 +[?] InvokeID: expected 0x01, decoded 0x01 +[?] Operation code: expected 0x3c, decoded 0x3c +[?] Data Coding Scheme: expected 0x0f, decoded 0x0f +[?] Data length: expected 0x01, decoded 0x01 +[?] Data: expected 32, decoded 32 + Tested if it still works. Text was: **321# interrogateSS CFU text..'' code 33 Testing parsing a USSD request and truncated versions -- cgit v1.2.3