From f558ed4bb9c0f00997b8f97c2b251a574c1a64c4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 2 Jun 2015 15:52:06 +0200 Subject: [PATCH] ipa: Properly parse LV stream of a ID_GET request For some reason the structure is closer to be a LV (length and value). The value is actually a tag but it is counted inside the length. Introduce an overload of the parse function to provide an offset for the length. This will be taken from the returned length. --- include/osmocom/gsm/ipa.h | 3 ++ src/gsm/ipa.c | 16 ++++++++-- tests/Makefile.am | 2 +- tests/utils/utils_test.c | 61 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/include/osmocom/gsm/ipa.h b/include/osmocom/gsm/ipa.h index 1227ee179..0bb01c590 100644 --- a/include/osmocom/gsm/ipa.h +++ b/include/osmocom/gsm/ipa.h @@ -27,6 +27,9 @@ 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); +/* 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); + /* parse an Unit ID in string format into the 'ipaccess_unit' data structure */ int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data); diff --git a/src/gsm/ipa.c b/src/gsm/ipa.c index 7cff1e818..dac20122b 100644 --- a/src/gsm/ipa.c +++ b/src/gsm/ipa.c @@ -88,6 +88,11 @@ 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); +} + +int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset) { uint8_t t_len; uint8_t t_tag; @@ -100,6 +105,11 @@ int ipa_ccm_idtag_parse(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\n", t_len); + return -EINVAL; + } + if (t_len > len + 1) { LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d\n", t_len); return -EINVAL; @@ -107,11 +117,11 @@ int ipa_ccm_idtag_parse(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; + dec->lv[t_tag].len = t_len - len_offset; dec->lv[t_tag].val = cur; - cur += t_len; - len -= t_len; + cur += t_len - len_offset; + len -= t_len - len_offset; } return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index b0701f828..6f76e5a44 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -16,7 +16,7 @@ check_PROGRAMS += msgfile/msgfile_test endif utils_utils_test_SOURCES = utils/utils_test.c -utils_utils_test_LDADD = $(top_builddir)/src/libosmocore.la +utils_utils_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la a5_a5_test_SOURCES = a5/a5_test.c ../src/gsm/a5.c a5_a5_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gsm/libosmogsm.la diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c index b21b074b1..1a79baa32 100644 --- a/tests/utils/utils_test.c +++ b/tests/utils/utils_test.c @@ -20,6 +20,9 @@ * */ +#include + +#include #include #include @@ -40,8 +43,66 @@ static void hexdump_test(void) printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data))); } +static void test_idtag_parsing(void) +{ + struct tlv_parsed tvp; + int rc; + + static uint8_t data[] = { + 0x01, 0x08, + 0x01, 0x07, + 0x01, 0x02, + 0x01, 0x03, + 0x01, 0x04, + 0x01, 0x05, + 0x01, 0x01, + 0x01, 0x00, + 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30, + 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, data, sizeof(data), 1); + OSMO_ASSERT(rc == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 8)); + OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 7)); + OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 2)); + OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 3)); + OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 4)); + OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 5)); + OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 1)); + OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 0)); + OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23)); + OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16); + + OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24)); + OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16); + + OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25)); +} + int main(int argc, char **argv) { + static const struct log_info log_info = {}; + log_init(&log_info, NULL); + hexdump_test(); + test_idtag_parsing(); return 0; }