blob: 8321b880ea766d2705a70aeed54713ed9ea6b819 [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>
Harald Welte73310c32009-10-24 10:04:02 +02003#include <openbsc/gsm_data.h>
4
5struct tlv_definition tvlv_att_def;
Harald Welte91b5b0d2009-02-06 12:51:39 +00006
Harald Weltee0590df2009-02-15 03:34:15 +00007int tlv_dump(struct tlv_parsed *dec)
8{
9 int i;
10
11 for (i = 0; i <= 0xff; i++) {
12 if (!dec->lv[i].val)
13 continue;
14 printf("T=%02x L=%d\n", i, dec->lv[i].len);
15 }
16 return 0;
17}
18
Harald Weltea4d49e92009-05-23 06:39:58 +000019/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
20 * def: input: a structure defining the valid TLV tags / configurations
21 * buf: input: the input data buffer to be parsed
22 * buf_len: input: the length of the input data buffer
23 * lv_tag: input: an initial LV tag at the start of the buffer
24 * lv_tag2: input: a second initial LV tag following lv_tag
25 */
Harald Welte7bc4cbc2009-02-21 12:59:22 +000026int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
Harald Weltea4d49e92009-05-23 06:39:58 +000027 const u_int8_t *buf, int buf_len, u_int8_t lv_tag,
28 u_int8_t lv_tag2)
Harald Welte91b5b0d2009-02-06 12:51:39 +000029{
Harald Welte2fa79342009-02-14 19:07:10 +000030 u_int8_t tag, len = 1;
Harald Weltea4d49e92009-05-23 06:39:58 +000031 const u_int8_t *pos = buf;
Harald Welte2fa79342009-02-14 19:07:10 +000032 int num_parsed = 0;
Harald Welte91b5b0d2009-02-06 12:51:39 +000033
Harald Welte2fa79342009-02-14 19:07:10 +000034 memset(dec, 0, sizeof(*dec));
Harald Welte91b5b0d2009-02-06 12:51:39 +000035
Harald Weltea4d49e92009-05-23 06:39:58 +000036 if (lv_tag) {
37 if (pos > buf + buf_len)
38 return -1;
39 dec->lv[lv_tag].val = pos+1;
40 dec->lv[lv_tag].len = *pos;
41 len = dec->lv[lv_tag].len + 1;
42 if (pos + len > buf + buf_len)
43 return -2;
44 num_parsed++;
45 pos += len;
46 }
47 if (lv_tag2) {
48 if (pos > buf + buf_len)
49 return -1;
50 dec->lv[lv_tag2].val = pos+1;
51 dec->lv[lv_tag2].len = *pos;
52 len = dec->lv[lv_tag2].len + 1;
53 if (pos + len > buf + buf_len)
54 return -2;
55 num_parsed++;
56 pos += len;
57 }
58
59 for (; pos < buf+buf_len; pos += len) {
Harald Welte2fa79342009-02-14 19:07:10 +000060 tag = *pos;
61 /* FIXME: use tables for knwon IEI */
Harald Weltee0590df2009-02-15 03:34:15 +000062 switch (def->def[tag].type) {
63 case TLV_TYPE_T:
Harald Welte2fa79342009-02-14 19:07:10 +000064 /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
65 dec->lv[tag].val = pos;
66 dec->lv[tag].len = 0;
67 len = 1;
68 num_parsed++;
Harald Weltee0590df2009-02-15 03:34:15 +000069 break;
70 case TLV_TYPE_TV:
71 dec->lv[tag].val = pos+1;
72 dec->lv[tag].len = 1;
73 len = 2;
74 num_parsed++;
75 break;
76 case TLV_TYPE_FIXED:
77 dec->lv[tag].val = pos+1;
78 dec->lv[tag].len = def->def[tag].fixed_len;
79 len = def->def[tag].fixed_len + 1;
80 num_parsed++;
81 break;
82 case TLV_TYPE_TLV:
Harald Welte2fa79342009-02-14 19:07:10 +000083 /* GSM TS 04.07 11.2.4: Type 4 TLV */
84 if (pos + 1 > buf + buf_len)
85 return -1;
86 dec->lv[tag].val = pos+2;
87 dec->lv[tag].len = *(pos+1);
88 len = dec->lv[tag].len + 2;
89 if (pos + len > buf + buf_len)
90 return -2;
91 num_parsed++;
Harald Weltee0590df2009-02-15 03:34:15 +000092 break;
Harald Welte73310c32009-10-24 10:04:02 +020093 case TLV_TYPE_TvLV:
94 if (*(pos+1) & 0x80) {
95 /* like TLV, but without highest bit of len */
96 if (pos + 1 > buf + buf_len)
97 return -1;
98 dec->lv[tag].val = pos+2;
99 dec->lv[tag].len = *(pos+1) & 0x7f;
100 len = dec->lv[tag].len + 2;
101 if (pos + len > buf + buf_len)
102 return -2;
103 num_parsed++;
104 break;
105 }
106 /* like TL16V, fallthrough */
Harald Weltee0590df2009-02-15 03:34:15 +0000107 case TLV_TYPE_TL16V:
108 if (pos + 2 > buf + buf_len)
109 return -1;
110 dec->lv[tag].val = pos+3;
111 dec->lv[tag].len = *(pos+1) << 8 | *(pos+2);
112 len = dec->lv[tag].len + 3;
113 if (pos + len > buf + buf_len)
114 return -2;
115 num_parsed++;
116 break;
Harald Welte2fa79342009-02-14 19:07:10 +0000117 }
Harald Welte91b5b0d2009-02-06 12:51:39 +0000118 }
Harald Weltee0590df2009-02-15 03:34:15 +0000119 //tlv_dump(dec);
Harald Welte2fa79342009-02-14 19:07:10 +0000120 return num_parsed;
Harald Welte91b5b0d2009-02-06 12:51:39 +0000121}
Harald Weltee0590df2009-02-15 03:34:15 +0000122
Harald Welte73310c32009-10-24 10:04:02 +0200123static __attribute__((constructor)) void on_dso_load_tlv(void)
124{
125 int i;
126 for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++)
127 tvlv_att_def.def[i].type = TLV_TYPE_TvLV;
128}