blob: 4a9bd272e747e0ffa57b2b79abfbce3f807e7b39 [file] [log] [blame]
Sylvain Munaut12ba7782014-06-16 10:13:40 +02001#pragma once
Harald Welteec8b4502010-02-20 20:34:29 +01002
3#include <stdint.h>
4#include <string.h>
5
Pablo Neira Ayuso83419342011-03-22 16:36:13 +01006#include <osmocom/core/msgb.h>
Harald Welte50ef7332017-05-15 12:45:59 +02007#include <osmocom/core/bit16gen.h>
8#include <osmocom/core/bit32gen.h>
Harald Welteec8b4502010-02-20 20:34:29 +01009
Harald Welte57c7d372011-08-17 17:50:55 +020010/*! \defgroup tlv GSM L3 compatible TLV parser
11 * @{
12 */
13/*! \file tlv.h */
14
Harald Welteec8b4502010-02-20 20:34:29 +010015/* Terminology / wording
16 tag length value (in bits)
17
18 V - - 8
19 LV - 8 N * 8
20 TLV 8 8 N * 8
21 TL16V 8 16 N * 8
22 TLV16 8 8 N * 16
23 TvLV 8 8/16 N * 8
Harald Welte2fe68472012-07-14 01:50:33 +020024 vTvLV 8/16 8/16 N * 8
Harald Welteec8b4502010-02-20 20:34:29 +010025
26*/
27
Harald Welte57c7d372011-08-17 17:50:55 +020028/*! \brief gross length of a LV type field */
Harald Welteec8b4502010-02-20 20:34:29 +010029#define LV_GROSS_LEN(x) (x+1)
Harald Welte57c7d372011-08-17 17:50:55 +020030/*! \brief gross length of a TLV type field */
Harald Welteec8b4502010-02-20 20:34:29 +010031#define TLV_GROSS_LEN(x) (x+2)
Harald Welte57c7d372011-08-17 17:50:55 +020032/*! \brief gross length of a TLV16 type field */
Harald Welteec8b4502010-02-20 20:34:29 +010033#define TLV16_GROSS_LEN(x) ((2*x)+2)
Harald Welte57c7d372011-08-17 17:50:55 +020034/*! \brief gross length of a TL16V type field */
Harald Welteec8b4502010-02-20 20:34:29 +010035#define TL16V_GROSS_LEN(x) (x+3)
Harald Welte57c7d372011-08-17 17:50:55 +020036/*! \brief gross length of a L16TV type field */
Harald Welteec8b4502010-02-20 20:34:29 +010037#define L16TV_GROSS_LEN(x) (x+3)
38
Harald Welte57c7d372011-08-17 17:50:55 +020039/*! \brief maximum length of TLV of one byte length */
Harald Welteec8b4502010-02-20 20:34:29 +010040#define TVLV_MAX_ONEBYTE 0x7f
41
Harald Welte57c7d372011-08-17 17:50:55 +020042/*! \brief gross length of a TVLV type field */
Harald Welteec8b4502010-02-20 20:34:29 +010043static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
44{
45 if (len <= TVLV_MAX_ONEBYTE)
46 return TLV_GROSS_LEN(len);
47 else
48 return TL16V_GROSS_LEN(len);
49}
50
Harald Welte2fe68472012-07-14 01:50:33 +020051/*! \brief gross length of vTvL header (tag+len) */
52static inline uint16_t VTVL_GAN_GROSS_LEN(uint16_t tag, uint16_t len)
53{
54 uint16_t ret = 2;
55
56 if (tag > TVLV_MAX_ONEBYTE)
57 ret++;
58
59 if (len > TVLV_MAX_ONEBYTE)
60 ret++;
61
62 return ret;
63}
64
65/*! \brief gross length of vTvLV (tag+len+val) */
66static inline uint16_t VTVLV_GAN_GROSS_LEN(uint16_t tag, uint16_t len)
67{
68 uint16_t ret;
69
70 if (len <= TVLV_MAX_ONEBYTE)
Vadim Yanitskiyac9e2d82017-05-14 20:52:46 +030071 ret = TLV_GROSS_LEN(len);
Harald Welte2fe68472012-07-14 01:50:33 +020072 else
Vadim Yanitskiyac9e2d82017-05-14 20:52:46 +030073 ret = TL16V_GROSS_LEN(len);
Harald Welte2fe68472012-07-14 01:50:33 +020074
75 if (tag > TVLV_MAX_ONEBYTE)
76 ret += 1;
77
78 return ret;
79}
80
Harald Welteec8b4502010-02-20 20:34:29 +010081/* TLV generation */
82
Harald Welte57c7d372011-08-17 17:50:55 +020083/*! \brief put (append) a LV field */
Harald Welteec8b4502010-02-20 20:34:29 +010084static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
85 const uint8_t *val)
86{
87 *buf++ = len;
88 memcpy(buf, val, len);
89 return buf + len;
90}
91
Harald Welte57c7d372011-08-17 17:50:55 +020092/*! \brief put (append) a TLV field */
Harald Welteec8b4502010-02-20 20:34:29 +010093static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
94 const uint8_t *val)
95{
96 *buf++ = tag;
97 *buf++ = len;
98 memcpy(buf, val, len);
99 return buf + len;
100}
101
Harald Welte57c7d372011-08-17 17:50:55 +0200102/*! \brief put (append) a TLV16 field */
Harald Welteec8b4502010-02-20 20:34:29 +0100103static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
104 const uint16_t *val)
105{
106 *buf++ = tag;
107 *buf++ = len;
108 memcpy(buf, val, len*2);
109 return buf + len*2;
110}
111
Harald Welte57c7d372011-08-17 17:50:55 +0200112/*! \brief put (append) a TL16V field */
Harald Welteec8b4502010-02-20 20:34:29 +0100113static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
114 const uint8_t *val)
115{
116 *buf++ = tag;
117 *buf++ = len >> 8;
118 *buf++ = len & 0xff;
119 memcpy(buf, val, len);
120 return buf + len*2;
121}
122
Harald Welte57c7d372011-08-17 17:50:55 +0200123/*! \brief put (append) a TvLV field */
Harald Welteec8b4502010-02-20 20:34:29 +0100124static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
125 const uint8_t *val)
126{
127 uint8_t *ret;
128
129 if (len <= TVLV_MAX_ONEBYTE) {
130 ret = tlv_put(buf, tag, len, val);
131 buf[1] |= 0x80;
132 } else
133 ret = tl16v_put(buf, tag, len, val);
134
135 return ret;
136}
137
Harald Welte2fe68472012-07-14 01:50:33 +0200138/*! \brief put (append) a variable-length tag or variable-length length * */
139static inline uint8_t *vt_gan_put(uint8_t *buf, uint16_t tag)
140{
141 if (tag > TVLV_MAX_ONEBYTE) {
142 /* two-byte TAG */
143 *buf++ = 0x80 | (tag >> 8);
144 *buf++ = (tag & 0xff);
145 } else
146 *buf++ = tag;
147
148 return buf;
149}
150
151/* \brief put (append) vTvL (GAN) field (tag + length)*/
152static inline uint8_t *vtvl_gan_put(uint8_t *buf, uint16_t tag, uint16_t len)
153{
154 uint8_t *ret;
155
156 ret = vt_gan_put(buf, tag);
157 return vt_gan_put(ret, len);
158}
159
160/* \brief put (append) vTvLV (GAN) field (tag + length + val) */
161static inline uint8_t *vtvlv_gan_put(uint8_t *buf, uint16_t tag, uint16_t len,
162 const uint8_t *val)
163{
164 uint8_t *ret;
165
166 ret = vtvl_gan_put(buf, tag, len );
167
168 memcpy(ret, val, len);
169 ret = buf + len;
170
171 return ret;
172}
173
Harald Welte57c7d372011-08-17 17:50:55 +0200174/*! \brief put (append) a TLV16 field to \ref msgb */
Harald Welteec8b4502010-02-20 20:34:29 +0100175static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
176{
177 uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
178 return tlv16_put(buf, tag, len, val);
179}
180
Harald Welte57c7d372011-08-17 17:50:55 +0200181/*! \brief put (append) a TL16V field to \ref msgb */
Harald Welteec8b4502010-02-20 20:34:29 +0100182static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
183 const uint8_t *val)
184{
185 uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
186 return tl16v_put(buf, tag, len, val);
187}
188
Harald Welte57c7d372011-08-17 17:50:55 +0200189/*! \brief put (append) a TvLV field to \ref msgb */
Harald Welteec8b4502010-02-20 20:34:29 +0100190static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
191 const uint8_t *val)
192{
193 uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
194 return tvlv_put(buf, tag, len, val);
195}
196
Harald Welte2fe68472012-07-14 01:50:33 +0200197/*! \brief put (append) a vTvLV field to \ref msgb */
198static inline uint8_t *msgb_vtvlv_gan_put(struct msgb *msg, uint16_t tag,
199 uint16_t len, const uint8_t *val)
200{
201 uint8_t *buf = msgb_put(msg, VTVLV_GAN_GROSS_LEN(tag, len));
202 return vtvlv_gan_put(buf, tag, len, val);
203}
204
Harald Welte57c7d372011-08-17 17:50:55 +0200205/*! \brief put (append) a L16TV field to \ref msgb */
Harald Welteec8b4502010-02-20 20:34:29 +0100206static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
207 const uint8_t *val)
208{
209 uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
210
211 *buf++ = len >> 8;
212 *buf++ = len & 0xff;
213 *buf++ = tag;
214 memcpy(buf, val, len);
215 return buf + len;
216}
217
Harald Welte57c7d372011-08-17 17:50:55 +0200218/*! \brief put (append) a V field */
Harald Welteec8b4502010-02-20 20:34:29 +0100219static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
220{
221 *buf++ = val;
222 return buf;
223}
224
Harald Welte57c7d372011-08-17 17:50:55 +0200225/*! \brief put (append) a TV field */
Harald Welteec8b4502010-02-20 20:34:29 +0100226static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag,
227 uint8_t val)
228{
229 *buf++ = tag;
230 *buf++ = val;
231 return buf;
232}
233
Harald Welte57c7d372011-08-17 17:50:55 +0200234/*! \brief put (append) a TVfixed field */
Harald Welte63196de2011-03-05 14:32:50 +0100235static inline uint8_t *tv_fixed_put(uint8_t *buf, uint8_t tag,
236 unsigned int len, const uint8_t *val)
237{
238 *buf++ = tag;
239 memcpy(buf, val, len);
240 return buf + len;
241}
242
Harald Welte57c7d372011-08-17 17:50:55 +0200243/*! \brief put (append) a TV16 field
244 * \param[in,out] buf data buffer
245 * \param[in] tag Tag value
246 * \param[in] val Value (in host byte order!)
247 */
Harald Welteec8b4502010-02-20 20:34:29 +0100248static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag,
249 uint16_t val)
250{
251 *buf++ = tag;
252 *buf++ = val >> 8;
253 *buf++ = val & 0xff;
254 return buf;
255}
256
Harald Welte2c020432012-01-22 23:03:38 +0100257/*! \brief put (append) a LV field to a \ref msgb
258 * \returns pointer to first byte after newly-put information */
Harald Welteec8b4502010-02-20 20:34:29 +0100259static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
260{
261 uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
262 return lv_put(buf, len, val);
263}
264
Harald Welte2c020432012-01-22 23:03:38 +0100265/*! \brief put (append) a TLV field to a \ref msgb
266 * \returns pointer to first byte after newly-put information */
Harald Welteec8b4502010-02-20 20:34:29 +0100267static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
268{
269 uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
270 return tlv_put(buf, tag, len, val);
271}
272
Harald Welte2c020432012-01-22 23:03:38 +0100273/*! \brief put (append) a TV field to a \ref msgb
274 * \returns pointer to first byte after newly-put information */
Harald Welteec8b4502010-02-20 20:34:29 +0100275static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
276{
277 uint8_t *buf = msgb_put(msg, 2);
278 return tv_put(buf, tag, val);
279}
280
Harald Welte2c020432012-01-22 23:03:38 +0100281/*! \brief put (append) a TVfixed field to a \ref msgb
282 * \returns pointer to first byte after newly-put information */
Harald Welte63196de2011-03-05 14:32:50 +0100283static inline uint8_t *msgb_tv_fixed_put(struct msgb *msg, uint8_t tag,
284 unsigned int len, const uint8_t *val)
285{
286 uint8_t *buf = msgb_put(msg, 1+len);
287 return tv_fixed_put(buf, tag, len, val);
288}
289
Harald Welte2c020432012-01-22 23:03:38 +0100290/*! \brief put (append) a V field to a \ref msgb
291 * \returns pointer to first byte after newly-put information */
Harald Welteec8b4502010-02-20 20:34:29 +0100292static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
293{
294 uint8_t *buf = msgb_put(msg, 1);
295 return v_put(buf, val);
296}
297
Harald Welte2c020432012-01-22 23:03:38 +0100298/*! \brief put (append) a TV16 field to a \ref msgb
299 * \returns pointer to first byte after newly-put information */
Harald Welteec8b4502010-02-20 20:34:29 +0100300static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
301{
302 uint8_t *buf = msgb_put(msg, 3);
303 return tv16_put(buf, tag, val);
304}
305
Harald Welte2c020432012-01-22 23:03:38 +0100306/*! \brief push (prepend) a TLV field to a \ref msgb
307 * \returns pointer to first byte of newly-pushed information */
Harald Welteec8b4502010-02-20 20:34:29 +0100308static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
309{
310 uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
Harald Welte2c020432012-01-22 23:03:38 +0100311 tlv_put(buf, tag, len, val);
312 return buf;
Harald Welteec8b4502010-02-20 20:34:29 +0100313}
314
Harald Welte2c020432012-01-22 23:03:38 +0100315/*! \brief push (prepend) a TV field to a \ref msgb
316 * \returns pointer to first byte of newly-pushed information */
Harald Welteec8b4502010-02-20 20:34:29 +0100317static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
318{
319 uint8_t *buf = msgb_push(msg, 2);
Harald Welte2c020432012-01-22 23:03:38 +0100320 tv_put(buf, tag, val);
321 return buf;
Harald Welteec8b4502010-02-20 20:34:29 +0100322}
323
Harald Welte2c020432012-01-22 23:03:38 +0100324/*! \brief push (prepend) a TV16 field to a \ref msgb
325 * \returns pointer to first byte of newly-pushed information */
Harald Welteec8b4502010-02-20 20:34:29 +0100326static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
327{
328 uint8_t *buf = msgb_push(msg, 3);
Harald Welte2c020432012-01-22 23:03:38 +0100329 tv16_put(buf, tag, val);
330 return buf;
Harald Welteec8b4502010-02-20 20:34:29 +0100331}
332
Harald Welte2c020432012-01-22 23:03:38 +0100333/*! \brief push (prepend) a TvLV field to a \ref msgb
334 * \returns pointer to first byte of newly-pushed information */
Harald Welte3415d412010-02-21 19:03:41 +0100335static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
336 const uint8_t *val)
337{
338 uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
Harald Welte2c020432012-01-22 23:03:38 +0100339 tvlv_put(buf, tag, len, val);
340 return buf;
Harald Welte3415d412010-02-21 19:03:41 +0100341}
342
Harald Welte2fe68472012-07-14 01:50:33 +0200343/* \brief push (prepend) a vTvL header to a \ref msgb
344 */
345static inline uint8_t *msgb_vtvl_gan_push(struct msgb *msg, uint16_t tag,
346 uint16_t len)
347{
348 uint8_t *buf = msgb_push(msg, VTVL_GAN_GROSS_LEN(tag, len));
349 vtvl_gan_put(buf, tag, len);
350 return buf;
351}
352
353
354static inline uint8_t *msgb_vtvlv_gan_push(struct msgb *msg, uint16_t tag,
355 uint16_t len, const uint8_t *val)
356{
357 uint8_t *buf = msgb_push(msg, VTVLV_GAN_GROSS_LEN(tag, len));
358 vtvlv_gan_put(buf, tag, len, val);
359 return buf;
360}
361
Harald Welteec8b4502010-02-20 20:34:29 +0100362/* TLV parsing */
363
Harald Welte57c7d372011-08-17 17:50:55 +0200364/*! \brief Entry in a TLV parser array */
Harald Welteec8b4502010-02-20 20:34:29 +0100365struct tlv_p_entry {
Harald Welte57c7d372011-08-17 17:50:55 +0200366 uint16_t len; /*!< \brief length */
367 const uint8_t *val; /*!< \brief pointer to value */
Harald Welteec8b4502010-02-20 20:34:29 +0100368};
369
Harald Welte57c7d372011-08-17 17:50:55 +0200370/*! \brief TLV type */
Harald Welteec8b4502010-02-20 20:34:29 +0100371enum tlv_type {
Harald Welte57c7d372011-08-17 17:50:55 +0200372 TLV_TYPE_NONE, /*!< \brief no type */
373 TLV_TYPE_FIXED, /*!< \brief fixed-length value-only */
374 TLV_TYPE_T, /*!< \brief tag-only */
375 TLV_TYPE_TV, /*!< \brief tag-value (8bit) */
376 TLV_TYPE_TLV, /*!< \brief tag-length-value */
377 TLV_TYPE_TL16V, /*!< \brief tag, 16 bit length, value */
378 TLV_TYPE_TvLV, /*!< \brief tag, variable length, value */
Harald Welte2fe68472012-07-14 01:50:33 +0200379 TLV_TYPE_SINGLE_TV, /*!< \brief tag and value (both 4 bit) in 1 byte */
380 TLV_TYPE_vTvLV_GAN, /*!< \brief variable-length tag, variable-length length */
Harald Welteec8b4502010-02-20 20:34:29 +0100381};
382
Harald Welte57c7d372011-08-17 17:50:55 +0200383/*! \brief Definition of a single IE (Information Element) */
Harald Welteec8b4502010-02-20 20:34:29 +0100384struct tlv_def {
Harald Welte57c7d372011-08-17 17:50:55 +0200385 enum tlv_type type; /*!< \brief TLV type */
386 uint8_t fixed_len; /*!< \brief length in case of \ref TLV_TYPE_FIXED */
Harald Welteec8b4502010-02-20 20:34:29 +0100387};
388
Harald Welte57c7d372011-08-17 17:50:55 +0200389/*! \brief Definition of All 256 IE / TLV */
Harald Welteec8b4502010-02-20 20:34:29 +0100390struct tlv_definition {
Harald Weltee0aa5bb2011-07-16 15:42:46 +0200391 struct tlv_def def[256];
Harald Welteec8b4502010-02-20 20:34:29 +0100392};
393
Harald Welte57c7d372011-08-17 17:50:55 +0200394/*! \brief result of the TLV parser */
Harald Welteec8b4502010-02-20 20:34:29 +0100395struct tlv_parsed {
Harald Weltee0aa5bb2011-07-16 15:42:46 +0200396 struct tlv_p_entry lv[256];
Harald Welteec8b4502010-02-20 20:34:29 +0100397};
398
399extern struct tlv_definition tvlv_att_def;
Harald Welte2fe68472012-07-14 01:50:33 +0200400extern struct tlv_definition vtvlv_gan_att_def;
Harald Welteec8b4502010-02-20 20:34:29 +0100401
402int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
403 const struct tlv_definition *def,
404 const uint8_t *buf, int buf_len);
405int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
406 const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
Neels Hofmeyr9e57a5a2015-12-21 11:20:14 +0100407/* take a master (src) tlv def and fill up all empty slots in 'dst' */
Harald Welteec8b4502010-02-20 20:34:29 +0100408void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
409
410#define TLVP_PRESENT(x, y) ((x)->lv[y].val)
411#define TLVP_LEN(x, y) (x)->lv[y].len
412#define TLVP_VAL(x, y) (x)->lv[y].val
413
Harald Weltecc27fa62014-08-18 15:31:04 +0200414#define TLVP_PRES_LEN(tp, tag, min_len) \
415 (TLVP_PRESENT(tp, tag) && TLVP_LEN(tp, tag) >= min_len)
416
Andreas Eversberg01675962012-11-06 12:02:59 +0100417/*! \brief Align given TLV element with 16 bit value to an even address
418 * \param[in] tp pointer to \ref tlv_parsed
419 * \param[in] pos element to return
420 * \returns aligned 16 bit value
421 */
422static inline uint16_t tlvp_val16_unal(const struct tlv_parsed *tp, int pos)
423{
424 uint16_t res;
425 memcpy(&res, TLVP_VAL(tp, pos), sizeof(res));
426 return res;
427}
428
429/*! \brief Align given TLV element with 32 bit value to an address that is a multiple of 4
430 * \param[in] tp pointer to \ref tlv_parsed
431 * \param[in] pos element to return
432 * \returns aligned 32 bit value
433 */
434static inline uint32_t tlvp_val32_unal(const struct tlv_parsed *tp, int pos)
435{
436 uint32_t res;
437 memcpy(&res, TLVP_VAL(tp, pos), sizeof(res));
438 return res;
439}
440
Harald Welte50ef7332017-05-15 12:45:59 +0200441/*! \brief Retrieve (possibly unaligned) TLV element and convert to host byte order
442 * \param[in] tp pointer to \ref tlv_parsed
443 * \param[in] pos element to return
444 * \returns aligned 16 bit value in host byte order
445 */
446static inline uint16_t tlvp_val16be(const struct tlv_parsed *tp, int pos)
447{
448 return osmo_load16be(TLVP_VAL(tp, pos));
449}
450
451/*! \brief Retrieve (possibly unaligned) TLV element and convert to host byte order
452 * \param[in] tp pointer to \ref tlv_parsed
453 * \param[in] pos element to return
454 * \returns aligned 32 bit value in host byte order
455 */
456static inline uint32_t tlvp_val32be(const struct tlv_parsed *tp, int pos)
457{
458 return osmo_load32be(TLVP_VAL(tp, pos));
459}
460
461
Maxdbd3a922017-01-02 14:10:30 +0100462struct tlv_parsed *osmo_tlvp_copy(const struct tlv_parsed *tp_orig, void *ctx);
463int osmo_tlvp_merge(struct tlv_parsed *dst, const struct tlv_parsed *src);
Harald Weltefbd02fa2016-04-25 15:19:35 +0200464int osmo_shift_v_fixed(uint8_t **data, size_t *data_len,
465 size_t len, uint8_t **value);
466int osmo_match_shift_tv_fixed(uint8_t **data, size_t *data_len,
467 uint8_t tag, size_t len, uint8_t **value);
468int osmo_shift_tlv(uint8_t **data, size_t *data_len,
469 uint8_t *tag, uint8_t **value, size_t *value_len);
470int osmo_match_shift_tlv(uint8_t **data, size_t *data_len,
471 uint8_t tag, uint8_t **value, size_t *value_len);
472int osmo_shift_lv(uint8_t **data, size_t *data_len,
473 uint8_t **value, size_t *value_len);
474
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200475/*! @} */