gsm 04.80: fix typo (256, not 265!)
[osmocom-bb.git] / include / osmocom / gsm / tlv.h
1 #ifndef _TLV_H
2 #define _TLV_H
3
4 #include <stdint.h>
5 #include <string.h>
6
7 #include <osmocom/core/msgb.h>
8
9 /* Terminology / wording
10                 tag     length          value   (in bits)
11
12             V   -       -               8
13            LV   -       8               N * 8
14           TLV   8       8               N * 8
15         TL16V   8       16              N * 8
16         TLV16   8       8               N * 16
17          TvLV   8       8/16            N * 8
18
19 */
20
21 #define LV_GROSS_LEN(x)         (x+1)
22 #define TLV_GROSS_LEN(x)        (x+2)
23 #define TLV16_GROSS_LEN(x)      ((2*x)+2)
24 #define TL16V_GROSS_LEN(x)      (x+3)
25 #define L16TV_GROSS_LEN(x)      (x+3)
26
27 #define TVLV_MAX_ONEBYTE        0x7f
28
29 static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
30 {
31         if (len <= TVLV_MAX_ONEBYTE)
32                 return TLV_GROSS_LEN(len);
33         else
34                 return TL16V_GROSS_LEN(len);
35 }
36
37 /* TLV generation */
38
39 static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
40                                 const uint8_t *val)
41 {
42         *buf++ = len;
43         memcpy(buf, val, len);
44         return buf + len;
45 }
46
47 static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
48                                 const uint8_t *val)
49 {
50         *buf++ = tag;
51         *buf++ = len;
52         memcpy(buf, val, len);
53         return buf + len;
54 }
55
56 static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
57                                 const uint16_t *val)
58 {
59         *buf++ = tag;
60         *buf++ = len;
61         memcpy(buf, val, len*2);
62         return buf + len*2;
63 }
64
65 static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
66                                 const uint8_t *val)
67 {
68         *buf++ = tag;
69         *buf++ = len >> 8;
70         *buf++ = len & 0xff;
71         memcpy(buf, val, len);
72         return buf + len*2;
73 }
74
75 static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
76                                  const uint8_t *val)
77 {
78         uint8_t *ret;
79
80         if (len <= TVLV_MAX_ONEBYTE) {
81                 ret = tlv_put(buf, tag, len, val);
82                 buf[1] |= 0x80;
83         } else
84                 ret = tl16v_put(buf, tag, len, val);
85
86         return ret;
87 }
88
89 static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
90 {
91         uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
92         return tlv16_put(buf, tag, len, val);
93 }
94
95 static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
96                                         const uint8_t *val)
97 {
98         uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
99         return tl16v_put(buf, tag, len, val);
100 }
101
102 static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
103                                       const uint8_t *val)
104 {
105         uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
106         return tvlv_put(buf, tag, len, val);
107 }
108
109 static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
110                                        const uint8_t *val)
111 {
112         uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
113
114         *buf++ = len >> 8;
115         *buf++ = len & 0xff;
116         *buf++ = tag;
117         memcpy(buf, val, len);
118         return buf + len;
119 }
120
121 static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
122 {
123         *buf++ = val;
124         return buf;
125 }
126
127 static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag, 
128                                 uint8_t val)
129 {
130         *buf++ = tag;
131         *buf++ = val;
132         return buf;
133 }
134
135 static inline uint8_t *tv_fixed_put(uint8_t *buf, uint8_t tag,
136                                     unsigned int len, const uint8_t *val)
137 {
138         *buf++ = tag;
139         memcpy(buf, val, len);
140         return buf + len;
141 }
142
143 /* 'val' is still in host byte order! */
144 static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag, 
145                                  uint16_t val)
146 {
147         *buf++ = tag;
148         *buf++ = val >> 8;
149         *buf++ = val & 0xff;
150         return buf;
151 }
152
153 static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
154 {
155         uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
156         return lv_put(buf, len, val);
157 }
158
159 static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
160 {
161         uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
162         return tlv_put(buf, tag, len, val);
163 }
164
165 static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
166 {
167         uint8_t *buf = msgb_put(msg, 2);
168         return tv_put(buf, tag, val);
169 }
170
171 static inline uint8_t *msgb_tv_fixed_put(struct msgb *msg, uint8_t tag,
172                                         unsigned int len, const uint8_t *val)
173 {
174         uint8_t *buf = msgb_put(msg, 1+len);
175         return tv_fixed_put(buf, tag, len, val);
176 }
177
178 static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
179 {
180         uint8_t *buf = msgb_put(msg, 1);
181         return v_put(buf, val);
182 }
183
184 static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
185 {
186         uint8_t *buf = msgb_put(msg, 3);
187         return tv16_put(buf, tag, val);
188 }
189
190 static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
191 {
192         uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
193         return tlv_put(buf, tag, len, val);
194 }
195
196 static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
197 {
198         uint8_t *buf = msgb_push(msg, 2);
199         return tv_put(buf, tag, val);
200 }
201
202 static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
203 {
204         uint8_t *buf = msgb_push(msg, 3);
205         return tv16_put(buf, tag, val);
206 }
207
208 static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
209                                       const uint8_t *val)
210 {
211         uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
212         return tvlv_put(buf, tag, len, val);
213 }
214
215 /* TLV parsing */
216
217 struct tlv_p_entry {
218         uint16_t len;
219         const uint8_t *val;
220 };
221
222 enum tlv_type {
223         TLV_TYPE_NONE,
224         TLV_TYPE_FIXED,
225         TLV_TYPE_T,
226         TLV_TYPE_TV,
227         TLV_TYPE_TLV,
228         TLV_TYPE_TL16V,
229         TLV_TYPE_TvLV,
230         TLV_TYPE_SINGLE_TV
231 };
232
233 struct tlv_def {
234         enum tlv_type type;
235         uint8_t fixed_len;
236 };
237
238 struct tlv_definition {
239         struct tlv_def def[256];
240 };
241
242 struct tlv_parsed {
243         struct tlv_p_entry lv[256];
244 };
245
246 extern struct tlv_definition tvlv_att_def;
247
248 int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
249                   const struct tlv_definition *def,
250                   const uint8_t *buf, int buf_len);
251 int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
252               const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
253 /* take a master (src) tlvdev and fill up all empty slots in 'dst' */
254 void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
255
256 #define TLVP_PRESENT(x, y)      ((x)->lv[y].val)
257 #define TLVP_LEN(x, y)          (x)->lv[y].len
258 #define TLVP_VAL(x, y)          (x)->lv[y].val
259
260 #endif /* _TLV_H */