aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-07-31 20:25:48 +0200
committerHarald Welte <laforge@gnumonks.org>2018-08-01 13:38:17 +0200
commit7869baf843fd10d0fd28f79395f3e7a01eebb8b7 (patch)
treef34c991ae405c1a7440eebf5615dbc43ee156e7d
parent48fd019b43ff2336553f2fe122db6929bea68ae8 (diff)
Deprecate ipa_ccm_idtag_parse() with ipa_ccm_id_{get,resp}_parse()
In the past, the function ipa_ccm_idtag_parse() was used to parse the payload of IPA CCM ID RESP packets. However, the function was based on a possible misunderstanding of the message encoding, and callers actually counted the first (upper) length nibble as part of the header and passed a pointer to the second (lower) length nibble of the first TLV into this function. As such, it was unfixable, and had to be replaced with a new function called ipa_ccm_id_resp_parse(). At the same time, we also add ipa_ccm_id_get_parse() to parse the slightly different format of the IPA CCM ID GET payload. We can never be 100% sure what is "correct", as our understanding of the protocol is entirely based on protocol analysis, without any official documentation available. This patch also introduces unit test coverage for both of the new functions. Revert "ipa: Add libosmogsm.map entry for ipa_ccm_idtag_parse_off" This reverts commit 7f31c90b80c08fbfe2d84d70d397402fdb38b94c. Revert "ipa: Properly parse LV stream of a ID_GET request" This reverts commit f558ed4bb9c0f00997b8f97c2b251a574c1a64c4. It introduced a function/behavior that was not originally intended: The parse of IPA CCM ID GET (8bit length followed by 1 byte tag and variable-length payload) instead of the IPA CCM ID RESP (16bit length followed by 1 byte tag and variable-length payload). Change-Id: I1834d90fbcdbfcb05f5b8cfe39bfe9543737ef8f
-rw-r--r--include/osmocom/gsm/ipa.h10
-rw-r--r--src/gsm/ipa.c83
-rw-r--r--src/gsm/libosmogsm.map3
-rw-r--r--tests/utils/utils_test.c64
-rw-r--r--tests/utils/utils_test.ok4
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