blob: e835f951f4969ca4e4a3265063f46a399713a0bc [file] [log] [blame]
Harald Weltee0590df2009-02-15 03:34:15 +00001#include <stdio.h>
Harald Welte91b5b0d2009-02-06 12:51:39 +00002#include <openbsc/tlv.h>
3
Harald Weltee0590df2009-02-15 03:34:15 +00004int tlv_dump(struct tlv_parsed *dec)
5{
6 int i;
7
8 for (i = 0; i <= 0xff; i++) {
9 if (!dec->lv[i].val)
10 continue;
11 printf("T=%02x L=%d\n", i, dec->lv[i].len);
12 }
13 return 0;
14}
15
Harald Weltea4d49e92009-05-23 06:39:58 +000016/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
17 * def: input: a structure defining the valid TLV tags / configurations
18 * buf: input: the input data buffer to be parsed
19 * buf_len: input: the length of the input data buffer
20 * lv_tag: input: an initial LV tag at the start of the buffer
21 * lv_tag2: input: a second initial LV tag following lv_tag
22 */
Harald Welte7bc4cbc2009-02-21 12:59:22 +000023int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
Harald Weltea4d49e92009-05-23 06:39:58 +000024 const u_int8_t *buf, int buf_len, u_int8_t lv_tag,
25 u_int8_t lv_tag2)
Harald Welte91b5b0d2009-02-06 12:51:39 +000026{
Harald Welte2fa79342009-02-14 19:07:10 +000027 u_int8_t tag, len = 1;
Harald Weltea4d49e92009-05-23 06:39:58 +000028 const u_int8_t *pos = buf;
Harald Welte2fa79342009-02-14 19:07:10 +000029 int num_parsed = 0;
Harald Welte91b5b0d2009-02-06 12:51:39 +000030
Harald Welte2fa79342009-02-14 19:07:10 +000031 memset(dec, 0, sizeof(*dec));
Harald Welte91b5b0d2009-02-06 12:51:39 +000032
Harald Weltea4d49e92009-05-23 06:39:58 +000033 if (lv_tag) {
34 if (pos > buf + buf_len)
35 return -1;
36 dec->lv[lv_tag].val = pos+1;
37 dec->lv[lv_tag].len = *pos;
38 len = dec->lv[lv_tag].len + 1;
39 if (pos + len > buf + buf_len)
40 return -2;
41 num_parsed++;
42 pos += len;
43 }
44 if (lv_tag2) {
45 if (pos > buf + buf_len)
46 return -1;
47 dec->lv[lv_tag2].val = pos+1;
48 dec->lv[lv_tag2].len = *pos;
49 len = dec->lv[lv_tag2].len + 1;
50 if (pos + len > buf + buf_len)
51 return -2;
52 num_parsed++;
53 pos += len;
54 }
55
56 for (; pos < buf+buf_len; pos += len) {
Harald Welte2fa79342009-02-14 19:07:10 +000057 tag = *pos;
58 /* FIXME: use tables for knwon IEI */
Harald Weltee0590df2009-02-15 03:34:15 +000059 switch (def->def[tag].type) {
60 case TLV_TYPE_T:
Harald Welte2fa79342009-02-14 19:07:10 +000061 /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
62 dec->lv[tag].val = pos;
63 dec->lv[tag].len = 0;
64 len = 1;
65 num_parsed++;
Harald Weltee0590df2009-02-15 03:34:15 +000066 break;
67 case TLV_TYPE_TV:
68 dec->lv[tag].val = pos+1;
69 dec->lv[tag].len = 1;
70 len = 2;
71 num_parsed++;
72 break;
73 case TLV_TYPE_FIXED:
74 dec->lv[tag].val = pos+1;
75 dec->lv[tag].len = def->def[tag].fixed_len;
76 len = def->def[tag].fixed_len + 1;
77 num_parsed++;
78 break;
79 case TLV_TYPE_TLV:
Harald Welte2fa79342009-02-14 19:07:10 +000080 /* GSM TS 04.07 11.2.4: Type 4 TLV */
81 if (pos + 1 > buf + buf_len)
82 return -1;
83 dec->lv[tag].val = pos+2;
84 dec->lv[tag].len = *(pos+1);
85 len = dec->lv[tag].len + 2;
86 if (pos + len > buf + buf_len)
87 return -2;
88 num_parsed++;
Harald Weltee0590df2009-02-15 03:34:15 +000089 break;
90 case TLV_TYPE_TL16V:
91 if (pos + 2 > buf + buf_len)
92 return -1;
93 dec->lv[tag].val = pos+3;
94 dec->lv[tag].len = *(pos+1) << 8 | *(pos+2);
95 len = dec->lv[tag].len + 3;
96 if (pos + len > buf + buf_len)
97 return -2;
98 num_parsed++;
99 break;
Harald Welte2fa79342009-02-14 19:07:10 +0000100 }
Harald Welte91b5b0d2009-02-06 12:51:39 +0000101 }
Harald Weltee0590df2009-02-15 03:34:15 +0000102 //tlv_dump(dec);
Harald Welte2fa79342009-02-14 19:07:10 +0000103 return num_parsed;
Harald Welte91b5b0d2009-02-06 12:51:39 +0000104}
Harald Weltee0590df2009-02-15 03:34:15 +0000105