diff options
-rw-r--r-- | include/osmocom/gsm/ipa.h | 10 | ||||
-rw-r--r-- | src/gsm/ipa.c | 83 | ||||
-rw-r--r-- | src/gsm/libosmogsm.map | 3 | ||||
-rw-r--r-- | tests/utils/utils_test.c | 64 | ||||
-rw-r--r-- | tests/utils/utils_test.ok | 4 |
5 files changed, 149 insertions, 15 deletions
diff --git a/include/osmocom/gsm/ipa.h b/include/osmocom/gsm/ipa.h index 7e1d7237..ec143d0e 100644 --- a/include/osmocom/gsm/ipa.h +++ b/include/osmocom/gsm/ipa.h @@ -26,8 +26,14 @@ struct ipaccess_unit { /* obtain the human-readable name of an IPA CCM ID TAG */ const char *ipa_ccm_idtag_name(uint8_t tag); -/* parse a buffer of ID tags into a osmocom TLV style representation */ -int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len); +int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len) + OSMO_DEPRECATED("Use ipa_ccm_id_{get,resp}_parse instead"); + +/* parse payload of IPA CCM ID GET into a osmocom TLV style representation */ +int ipa_ccm_id_get_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len); + +/* parse payload of IPA CCM ID RESP into a osmocom TLV style representation */ +int ipa_ccm_id_resp_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len); /* Is the TAG included in the length field? */ int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset); diff --git a/src/gsm/ipa.c b/src/gsm/ipa.c index aecde831..3c7c300b 100644 --- a/src/gsm/ipa.c +++ b/src/gsm/ipa.c @@ -100,14 +100,47 @@ const char *ipa_ccm_idtag_name(uint8_t tag) int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len) { - return ipa_ccm_idtag_parse_off(dec, buf, len, 0); + uint8_t t_len; + uint8_t t_tag; + uint8_t *cur = buf; + + memset(dec, 0, sizeof(*dec)); + + while (len >= 2) { + len -= 2; + t_len = *cur++; + t_tag = *cur++; + + if (t_len > len + 1) { + LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1); + return -EINVAL; + } + + DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur); + + dec->lv[t_tag].len = t_len; + dec->lv[t_tag].val = cur; + + cur += t_len; + len -= t_len; + } + return 0; } -int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset) +/*! Parse the payload part of an IPA CCM ID GET, return \ref tlv_parsed format. + * The odd payload format of those messages is structured as follows: + * * 8bit length value (length of payload *and tag*) + * * 8bit tag value + * * optional, variable-length payload + * \param[out] dec Caller-provided/allocated output structure for parsed payload + * \param[in] buf Buffer containing the payload (excluding 1 byte msg_type) of the message + * \param[in] len Length of \a buf in octets + * \returns 0 on success; negative on error */ +int ipa_ccm_id_get_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len) { uint8_t t_len; uint8_t t_tag; - uint8_t *cur = buf; + const uint8_t *cur = buf; memset(dec, 0, sizeof(*dec)); @@ -116,11 +149,45 @@ int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, t_len = *cur++; t_tag = *cur++; - if (t_len < len_offset) { - LOGP(DLMI, LOGL_ERROR, "minimal offset not included: %d < %d\n", t_len, len_offset); + if (t_len > len + 1) { + LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1); return -EINVAL; } + DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur); + + dec->lv[t_tag].len = t_len-1; + dec->lv[t_tag].val = cur; + + cur += t_len-1; + len -= t_len-1; + } + return 0; +} + +/*! Parse the payload part of an IPA CCM ID RESP, return \ref tlv_parsed format. + * The odd payload format of those messages is structured as follows: + * * 16bit length value (length of payload *and tag*) + * * 8bit tag value + * * optional, variable-length payload + * \param[out] dec Caller-provided/allocated output structure for parsed payload + * \param[in] buf Buffer containing the payload (excluding 1 byte msg_type) of the message + * \param[in] len Length of \a buf in octets + * \returns 0 on success; negative on error */ +int ipa_ccm_id_resp_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len) +{ + uint8_t t_len; + uint8_t t_tag; + const uint8_t *cur = buf; + + memset(dec, 0, sizeof(*dec)); + + while (len >= 3) { + len -= 3; + t_len = *cur++ << 8; + t_len += *cur++; + t_tag = *cur++; + if (t_len > len + 1) { LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1); return -EINVAL; @@ -128,11 +195,11 @@ int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur); - dec->lv[t_tag].len = t_len - len_offset; + dec->lv[t_tag].len = t_len-1; dec->lv[t_tag].val = cur; - cur += t_len - len_offset; - len -= t_len - len_offset; + cur += t_len-1; + len -= t_len-1; } return 0; } diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index bc9ed528..a1d342aa 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -461,7 +461,8 @@ ipa_ccm_send_pong; ipa_ccm_tlv_to_unitdata; ipa_ccm_idtag_name; ipa_ccm_idtag_parse; -ipa_ccm_idtag_parse_off; +ipa_ccm_id_get_parse; +ipa_ccm_id_resp_parse; ipa_ccm_make_id_resp; ipa_ccm_make_id_resp_from_req; ipa_msg_alloc; diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c index eec13ca3..2f1e87da 100644 --- a/tests/utils/utils_test.c +++ b/tests/utils/utils_test.c @@ -21,6 +21,7 @@ */ #include <osmocom/gsm/ipa.h> +#include <osmocom/gsm/protocol/ipaccess.h> #include <osmocom/core/logging.h> #include <osmocom/core/utils.h> @@ -170,13 +171,65 @@ static void hexparse_test(void) printf("rc = %d\n", rc); } -static void test_idtag_parsing(void) +static void test_ipa_ccm_id_resp_parsing(void) +{ + struct tlv_parsed tvp; + int rc; + + static const uint8_t id_resp_data[] = { + 0x00, 0x13, IPAC_IDTAG_MACADDR, + '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0', + 0x00, 0x11, IPAC_IDTAG_IPADDR, + '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0', + 0x00, 0x0a, IPAC_IDTAG_UNIT, + '1','2','3','4','/','0','/','0','\0', + 0x00, 0x02, IPAC_IDTAG_LOCATION1, + '\0', + 0x00, 0x0d, IPAC_IDTAG_LOCATION2, + 'B','T','S','_','N','B','T','1','3','1','G','\0', + 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS, + '1','6','5','a','0','2','9','_','5','5','\0', + 0x00, 0x14, IPAC_IDTAG_SWVERSION, + '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0', + 0x00, 0x18, IPAC_IDTAG_UNITNAME, + 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0', + 0x00, 0x0a, IPAC_IDTAG_SERNR, + '0','0','1','1','0','7','8','1','\0' + }; + + printf("\nTesting IPA CCM ID RESP parsing\n"); + + rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data)); + OSMO_ASSERT(rc == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17); + OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR)); + OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09); +} + +static void test_ipa_ccm_id_get_parsing(void) { struct tlv_parsed tvp; int rc; /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */ - static uint8_t id_get_data[] = { + static const uint8_t id_get_data[] = { 0x01, 0x08, 0x01, 0x07, 0x01, 0x02, @@ -189,7 +242,9 @@ static void test_idtag_parsing(void) 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - rc = ipa_ccm_idtag_parse_off(&tvp, id_get_data, sizeof(id_get_data), 1); + printf("\nTesting IPA CCM ID GET parsing\n"); + + rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data)); OSMO_ASSERT(rc == 0); OSMO_ASSERT(TLVP_PRESENT(&tvp, 8)); @@ -568,7 +623,8 @@ int main(int argc, char **argv) hexdump_test(); hexparse_test(); - test_idtag_parsing(); + test_ipa_ccm_id_get_parsing(); + test_ipa_ccm_id_resp_parsing(); test_is_hexstr(); bcd_test(); str_escape_test(); diff --git a/tests/utils/utils_test.ok b/tests/utils/utils_test.ok index b158bf7b..abc7317a 100644 --- a/tests/utils/utils_test.ok +++ b/tests/utils/utils_test.ok @@ -27,6 +27,10 @@ rc = -1 Hexparse with invalid char rc = -1 +Testing IPA CCM ID GET parsing + +Testing IPA CCM ID RESP parsing + ----- test_is_hexstr 0: pass str='(null)' min=0 max=10 even=0 expect=valid 1: pass str='(null)' min=1 max=10 even=0 expect=invalid |