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)
This commit is contained in:
parent
e7b452a7a0
commit
a4d49e96ab
|
@ -6,12 +6,21 @@
|
|||
|
||||
#include <openbsc/msgb.h>
|
||||
|
||||
#define LV_GROSS_LEN(x) (x+1)
|
||||
#define TLV_GROSS_LEN(x) (x+2)
|
||||
#define TLV16_GROSS_LEN(x) ((2*x)+2)
|
||||
#define TL16V_GROSS_LEN(x) (x+3)
|
||||
|
||||
/* TLV generation */
|
||||
|
||||
static inline u_int8_t *lv_put(u_int8_t *buf, u_int8_t len,
|
||||
const u_int8_t *val)
|
||||
{
|
||||
*buf++ = len;
|
||||
memcpy(buf, val, len);
|
||||
return buf + len;
|
||||
}
|
||||
|
||||
static inline u_int8_t *tlv_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
|
||||
const u_int8_t *val)
|
||||
{
|
||||
|
@ -53,6 +62,12 @@ static inline u_int8_t *msgb_tl16v_put(struct msgb *msg, u_int8_t tag, u_int16_t
|
|||
return tl16v_put(buf, tag, len, val);
|
||||
}
|
||||
|
||||
static inline u_int8_t *v_put(u_int8_t *buf, u_int8_t val)
|
||||
{
|
||||
*buf++ = val;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag,
|
||||
u_int8_t val)
|
||||
{
|
||||
|
@ -70,6 +85,12 @@ static inline u_int8_t *tv16_put(u_int8_t *buf, u_int8_t tag,
|
|||
return buf;
|
||||
}
|
||||
|
||||
static inline u_int8_t *msgb_lv_put(struct msgb *msg, u_int8_t len, const u_int8_t *val)
|
||||
{
|
||||
u_int8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
|
||||
return lv_put(buf, len, val);
|
||||
}
|
||||
|
||||
static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
|
||||
{
|
||||
u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
|
||||
|
@ -82,6 +103,12 @@ static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val
|
|||
return tv_put(buf, tag, val);
|
||||
}
|
||||
|
||||
static inline u_int8_t *msgb_v_put(struct msgb *msg, u_int8_t val)
|
||||
{
|
||||
u_int8_t *buf = msgb_put(msg, 1);
|
||||
return v_put(buf, val);
|
||||
}
|
||||
|
||||
static inline u_int8_t *msgb_tv16_put(struct msgb *msg, u_int8_t tag, u_int16_t val)
|
||||
{
|
||||
u_int8_t *buf = msgb_put(msg, 3);
|
||||
|
@ -135,7 +162,7 @@ struct tlv_parsed {
|
|||
};
|
||||
|
||||
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);
|
||||
|
||||
#define TLVP_PRESENT(x, y) ((x)->lv[y].val)
|
||||
#define TLVP_LEN(x, y) (x)->lv[y].len
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue