libosmogsm  0.9.3
Osmocom GSM library
tlv.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <stdint.h>
4 #include <string.h>
5 
6 #include <osmocom/core/msgb.h>
7 
13 /* Terminology / wording
14  tag length value (in bits)
15 
16  V - - 8
17  LV - 8 N * 8
18  TLV 8 8 N * 8
19  TL16V 8 16 N * 8
20  TLV16 8 8 N * 16
21  TvLV 8 8/16 N * 8
22  vTvLV 8/16 8/16 N * 8
23 
24 */
25 
27 #define LV_GROSS_LEN(x) (x+1)
28 
29 #define TLV_GROSS_LEN(x) (x+2)
30 
31 #define TLV16_GROSS_LEN(x) ((2*x)+2)
32 
33 #define TL16V_GROSS_LEN(x) (x+3)
34 
35 #define L16TV_GROSS_LEN(x) (x+3)
36 
38 #define TVLV_MAX_ONEBYTE 0x7f
39 
41 static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
42 {
43  if (len <= TVLV_MAX_ONEBYTE)
44  return TLV_GROSS_LEN(len);
45  else
46  return TL16V_GROSS_LEN(len);
47 }
48 
50 static inline uint16_t VTVL_GAN_GROSS_LEN(uint16_t tag, uint16_t len)
51 {
52  uint16_t ret = 2;
53 
54  if (tag > TVLV_MAX_ONEBYTE)
55  ret++;
56 
57  if (len > TVLV_MAX_ONEBYTE)
58  ret++;
59 
60  return ret;
61 }
62 
64 static inline uint16_t VTVLV_GAN_GROSS_LEN(uint16_t tag, uint16_t len)
65 {
66  uint16_t ret;
67 
68  if (len <= TVLV_MAX_ONEBYTE)
69  return TLV_GROSS_LEN(len);
70  else
71  return TL16V_GROSS_LEN(len);
72 
73  if (tag > TVLV_MAX_ONEBYTE)
74  ret += 1;
75 
76  return ret;
77 }
78 
79 /* TLV generation */
80 
82 static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
83  const uint8_t *val)
84 {
85  *buf++ = len;
86  memcpy(buf, val, len);
87  return buf + len;
88 }
89 
91 static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
92  const uint8_t *val)
93 {
94  *buf++ = tag;
95  *buf++ = len;
96  memcpy(buf, val, len);
97  return buf + len;
98 }
99 
101 static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
102  const uint16_t *val)
103 {
104  *buf++ = tag;
105  *buf++ = len;
106  memcpy(buf, val, len*2);
107  return buf + len*2;
108 }
109 
111 static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
112  const uint8_t *val)
113 {
114  *buf++ = tag;
115  *buf++ = len >> 8;
116  *buf++ = len & 0xff;
117  memcpy(buf, val, len);
118  return buf + len*2;
119 }
120 
122 static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
123  const uint8_t *val)
124 {
125  uint8_t *ret;
126 
127  if (len <= TVLV_MAX_ONEBYTE) {
128  ret = tlv_put(buf, tag, len, val);
129  buf[1] |= 0x80;
130  } else
131  ret = tl16v_put(buf, tag, len, val);
132 
133  return ret;
134 }
135 
137 static inline uint8_t *vt_gan_put(uint8_t *buf, uint16_t tag)
138 {
139  if (tag > TVLV_MAX_ONEBYTE) {
140  /* two-byte TAG */
141  *buf++ = 0x80 | (tag >> 8);
142  *buf++ = (tag & 0xff);
143  } else
144  *buf++ = tag;
145 
146  return buf;
147 }
148 
149 /* \brief put (append) vTvL (GAN) field (tag + length)*/
150 static inline uint8_t *vtvl_gan_put(uint8_t *buf, uint16_t tag, uint16_t len)
151 {
152  uint8_t *ret;
153 
154  ret = vt_gan_put(buf, tag);
155  return vt_gan_put(ret, len);
156 }
157 
158 /* \brief put (append) vTvLV (GAN) field (tag + length + val) */
159 static inline uint8_t *vtvlv_gan_put(uint8_t *buf, uint16_t tag, uint16_t len,
160  const uint8_t *val)
161 {
162  uint8_t *ret;
163 
164  ret = vtvl_gan_put(buf, tag, len );
165 
166  memcpy(ret, val, len);
167  ret = buf + len;
168 
169  return ret;
170 }
171 
173 static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
174 {
175  uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
176  return tlv16_put(buf, tag, len, val);
177 }
178 
180 static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
181  const uint8_t *val)
182 {
183  uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
184  return tl16v_put(buf, tag, len, val);
185 }
186 
188 static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
189  const uint8_t *val)
190 {
191  uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
192  return tvlv_put(buf, tag, len, val);
193 }
194 
196 static inline uint8_t *msgb_vtvlv_gan_put(struct msgb *msg, uint16_t tag,
197  uint16_t len, const uint8_t *val)
198 {
199  uint8_t *buf = msgb_put(msg, VTVLV_GAN_GROSS_LEN(tag, len));
200  return vtvlv_gan_put(buf, tag, len, val);
201 }
202 
204 static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
205  const uint8_t *val)
206 {
207  uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
208 
209  *buf++ = len >> 8;
210  *buf++ = len & 0xff;
211  *buf++ = tag;
212  memcpy(buf, val, len);
213  return buf + len;
214 }
215 
217 static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
218 {
219  *buf++ = val;
220  return buf;
221 }
222 
224 static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag,
225  uint8_t val)
226 {
227  *buf++ = tag;
228  *buf++ = val;
229  return buf;
230 }
231 
233 static inline uint8_t *tv_fixed_put(uint8_t *buf, uint8_t tag,
234  unsigned int len, const uint8_t *val)
235 {
236  *buf++ = tag;
237  memcpy(buf, val, len);
238  return buf + len;
239 }
240 
246 static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag,
247  uint16_t val)
248 {
249  *buf++ = tag;
250  *buf++ = val >> 8;
251  *buf++ = val & 0xff;
252  return buf;
253 }
254 
257 static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
258 {
259  uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
260  return lv_put(buf, len, val);
261 }
262 
265 static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
266 {
267  uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
268  return tlv_put(buf, tag, len, val);
269 }
270 
273 static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
274 {
275  uint8_t *buf = msgb_put(msg, 2);
276  return tv_put(buf, tag, val);
277 }
278 
281 static inline uint8_t *msgb_tv_fixed_put(struct msgb *msg, uint8_t tag,
282  unsigned int len, const uint8_t *val)
283 {
284  uint8_t *buf = msgb_put(msg, 1+len);
285  return tv_fixed_put(buf, tag, len, val);
286 }
287 
290 static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
291 {
292  uint8_t *buf = msgb_put(msg, 1);
293  return v_put(buf, val);
294 }
295 
298 static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
299 {
300  uint8_t *buf = msgb_put(msg, 3);
301  return tv16_put(buf, tag, val);
302 }
303 
306 static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
307 {
308  uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
309  tlv_put(buf, tag, len, val);
310  return buf;
311 }
312 
315 static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
316 {
317  uint8_t *buf = msgb_push(msg, 2);
318  tv_put(buf, tag, val);
319  return buf;
320 }
321 
324 static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
325 {
326  uint8_t *buf = msgb_push(msg, 3);
327  tv16_put(buf, tag, val);
328  return buf;
329 }
330 
333 static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
334  const uint8_t *val)
335 {
336  uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
337  tvlv_put(buf, tag, len, val);
338  return buf;
339 }
340 
341 /* \brief push (prepend) a vTvL header to a \ref msgb
342  */
343 static inline uint8_t *msgb_vtvl_gan_push(struct msgb *msg, uint16_t tag,
344  uint16_t len)
345 {
346  uint8_t *buf = msgb_push(msg, VTVL_GAN_GROSS_LEN(tag, len));
347  vtvl_gan_put(buf, tag, len);
348  return buf;
349 }
350 
351 
352 static inline uint8_t *msgb_vtvlv_gan_push(struct msgb *msg, uint16_t tag,
353  uint16_t len, const uint8_t *val)
354 {
355  uint8_t *buf = msgb_push(msg, VTVLV_GAN_GROSS_LEN(tag, len));
356  vtvlv_gan_put(buf, tag, len, val);
357  return buf;
358 }
359 
360 /* TLV parsing */
361 
363 struct tlv_p_entry {
364  uint16_t len;
365  const uint8_t *val;
366 };
367 
369 enum tlv_type {
379 };
380 
382 struct tlv_def {
383  enum tlv_type type;
384  uint8_t fixed_len;
385 };
386 
389  struct tlv_def def[256];
390 };
391 
393 struct tlv_parsed {
394  struct tlv_p_entry lv[256];
395 };
396 
397 extern struct tlv_definition tvlv_att_def;
398 extern struct tlv_definition vtvlv_gan_att_def;
399 
400 int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
401  const struct tlv_definition *def,
402  const uint8_t *buf, int buf_len);
403 int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
404  const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
405 /* take a master (src) tlvdev and fill up all empty slots in 'dst' */
406 void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
407 
408 #define TLVP_PRESENT(x, y) ((x)->lv[y].val)
409 #define TLVP_LEN(x, y) (x)->lv[y].len
410 #define TLVP_VAL(x, y) (x)->lv[y].val
411 
412 #define TLVP_PRES_LEN(tp, tag, min_len) \
413  (TLVP_PRESENT(tp, tag) && TLVP_LEN(tp, tag) >= min_len)
414 
420 static inline uint16_t tlvp_val16_unal(const struct tlv_parsed *tp, int pos)
421 {
422  uint16_t res;
423  memcpy(&res, TLVP_VAL(tp, pos), sizeof(res));
424  return res;
425 }
426 
432 static inline uint32_t tlvp_val32_unal(const struct tlv_parsed *tp, int pos)
433 {
434  uint32_t res;
435  memcpy(&res, TLVP_VAL(tp, pos), sizeof(res));
436  return res;
437 }
438