aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-05-23 06:39:58 +0000
committerHarald Welte <laforge@gnumonks.org>2009-05-23 06:39:58 +0000
commita4d49e96ab45b12fe581d6ab3cecd0727bccb317 (patch)
treedbeebd5e255e0ef1b07c1be083f8691027e46afa /src
parente7b452a7a07b75f880fadeeb650efe2bac931c7b (diff)
Some messages have one or two length-value information elements. The is
no IE type included in the message. These information elements are mandatory, so their actual IE type is known. The improved parse_tlv() function allows to parse zero, one, or two length-value elements. (Andreas Eversberg)
Diffstat (limited to 'src')
-rw-r--r--src/abis_nm.c2
-rw-r--r--src/abis_rsl.c3
-rw-r--r--src/gsm_04_08.c2
-rw-r--r--src/tlv_parser.c37
4 files changed, 38 insertions, 6 deletions
diff --git a/src/abis_nm.c b/src/abis_nm.c
index 6909f7828..0107c294e 100644
--- a/src/abis_nm.c
+++ b/src/abis_nm.c
@@ -365,7 +365,7 @@ static const struct tlv_definition nm_att_tlvdef = {
int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
{
- return tlv_parse(tp, &nm_att_tlvdef, buf, len);
+ return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
}
static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
diff --git a/src/abis_rsl.c b/src/abis_rsl.c
index e7f953e0c..753a66609 100644
--- a/src/abis_rsl.c
+++ b/src/abis_rsl.c
@@ -112,7 +112,8 @@ static const struct tlv_definition rsl_att_tlvdef = {
[0xfc] = { TLV_TYPE_TV },
},
};
-#define rsl_tlv_parse(dec, buf, len) tlv_parse(dec, &rsl_att_tlvdef, buf, len)
+#define rsl_tlv_parse(dec, buf, len) \
+ tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0)
static u_int8_t mdisc_by_msgtype(u_int8_t msg_type)
{
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index ad7bba687..849ef4888 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -1119,7 +1119,7 @@ static int gsm48_cc_rx_setup(struct msgb *msg)
call->local_lchan = msg->lchan;
call->transaction_id = gh->proto_discr & 0xf0;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
+ tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD))
goto err;
diff --git a/src/tlv_parser.c b/src/tlv_parser.c
index fe6d28926..e835f951f 100644
--- a/src/tlv_parser.c
+++ b/src/tlv_parser.c
@@ -13,16 +13,47 @@ int tlv_dump(struct tlv_parsed *dec)
return 0;
}
+/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
+ * def: input: a structure defining the valid TLV tags / configurations
+ * buf: input: the input data buffer to be parsed
+ * buf_len: input: the length of the input data buffer
+ * lv_tag: input: an initial LV tag at the start of the buffer
+ * lv_tag2: input: a second initial LV tag following lv_tag
+ */
int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len)
+ const u_int8_t *buf, int buf_len, u_int8_t lv_tag,
+ u_int8_t lv_tag2)
{
u_int8_t tag, len = 1;
- const u_int8_t *pos;
+ const u_int8_t *pos = buf;
int num_parsed = 0;
memset(dec, 0, sizeof(*dec));
- for (pos = buf; pos < buf+buf_len; pos += len) {
+ if (lv_tag) {
+ if (pos > buf + buf_len)
+ return -1;
+ dec->lv[lv_tag].val = pos+1;
+ dec->lv[lv_tag].len = *pos;
+ len = dec->lv[lv_tag].len + 1;
+ if (pos + len > buf + buf_len)
+ return -2;
+ num_parsed++;
+ pos += len;
+ }
+ if (lv_tag2) {
+ if (pos > buf + buf_len)
+ return -1;
+ dec->lv[lv_tag2].val = pos+1;
+ dec->lv[lv_tag2].len = *pos;
+ len = dec->lv[lv_tag2].len + 1;
+ if (pos + len > buf + buf_len)
+ return -2;
+ num_parsed++;
+ pos += len;
+ }
+
+ for (; pos < buf+buf_len; pos += len) {
tag = *pos;
/* FIXME: use tables for knwon IEI */
switch (def->def[tag].type) {