summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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