blob: 14c9910df4f31c5aa67900efb7055911e301d582 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001#ifndef _TLV_H
2#define _TLV_H
3
Harald Weltea3d55142010-02-20 19:10:44 +01004#include <stdint.h>
Harald Welte52b1f982008-12-23 20:25:15 +00005#include <string.h>
6
Harald Weltedfe6c7d2010-02-20 16:24:02 +01007#include <osmocore/msgb.h>
Harald Welte91b5b0d2009-02-06 12:51:39 +00008
Harald Welte73310c32009-10-24 10:04:02 +02009/* 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
Harald Weltea4d49e92009-05-23 06:39:58 +000021#define LV_GROSS_LEN(x) (x+1)
Harald Welte52b1f982008-12-23 20:25:15 +000022#define TLV_GROSS_LEN(x) (x+2)
23#define TLV16_GROSS_LEN(x) ((2*x)+2)
Harald Welte702d8702008-12-26 20:25:35 +000024#define TL16V_GROSS_LEN(x) (x+3)
Holger Hans Peter Freyther701d1752010-02-09 16:26:49 +010025#define L16TV_GROSS_LEN(x) (x+3)
Harald Welte52b1f982008-12-23 20:25:15 +000026
Harald Welte73310c32009-10-24 10:04:02 +020027#define TVLV_MAX_ONEBYTE 0x7f
28
Harald Weltea3d55142010-02-20 19:10:44 +010029static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
Harald Welte73310c32009-10-24 10:04:02 +020030{
31 if (len <= TVLV_MAX_ONEBYTE)
32 return TLV_GROSS_LEN(len);
33 else
34 return TL16V_GROSS_LEN(len);
35}
36
Harald Welte91b5b0d2009-02-06 12:51:39 +000037/* TLV generation */
38
Harald Weltea3d55142010-02-20 19:10:44 +010039static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
40 const uint8_t *val)
Harald Weltea4d49e92009-05-23 06:39:58 +000041{
42 *buf++ = len;
43 memcpy(buf, val, len);
44 return buf + len;
45}
46
Harald Weltea3d55142010-02-20 19:10:44 +010047static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
48 const uint8_t *val)
Harald Welte52b1f982008-12-23 20:25:15 +000049{
50 *buf++ = tag;
51 *buf++ = len;
52 memcpy(buf, val, len);
53 return buf + len;
54}
55
Harald Weltea3d55142010-02-20 19:10:44 +010056static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
57 const uint16_t *val)
Harald Welte52b1f982008-12-23 20:25:15 +000058{
59 *buf++ = tag;
60 *buf++ = len;
61 memcpy(buf, val, len*2);
62 return buf + len*2;
63}
64
Harald Weltea3d55142010-02-20 19:10:44 +010065static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
66 const uint8_t *val)
Harald Welte702d8702008-12-26 20:25:35 +000067{
68 *buf++ = tag;
69 *buf++ = len >> 8;
70 *buf++ = len & 0xff;
71 memcpy(buf, val, len);
72 return buf + len*2;
73}
74
Harald Weltea3d55142010-02-20 19:10:44 +010075static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
76 const uint8_t *val)
Harald Welte73310c32009-10-24 10:04:02 +020077{
Harald Weltea3d55142010-02-20 19:10:44 +010078 uint8_t *ret;
Harald Welte73310c32009-10-24 10:04:02 +020079
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
Harald Weltea3d55142010-02-20 19:10:44 +010089static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
Harald Welte52b1f982008-12-23 20:25:15 +000090{
Harald Weltea3d55142010-02-20 19:10:44 +010091 uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
Harald Welte52b1f982008-12-23 20:25:15 +000092 return tlv16_put(buf, tag, len, val);
93}
94
Harald Weltea3d55142010-02-20 19:10:44 +010095static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
96 const uint8_t *val)
Harald Welte702d8702008-12-26 20:25:35 +000097{
Harald Weltea3d55142010-02-20 19:10:44 +010098 uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
Harald Welte702d8702008-12-26 20:25:35 +000099 return tl16v_put(buf, tag, len, val);
100}
101
Harald Weltea3d55142010-02-20 19:10:44 +0100102static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
103 const uint8_t *val)
Harald Welte73310c32009-10-24 10:04:02 +0200104{
Harald Weltea3d55142010-02-20 19:10:44 +0100105 uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
Harald Welte73310c32009-10-24 10:04:02 +0200106 return tvlv_put(buf, tag, len, val);
107}
108
Harald Weltea3d55142010-02-20 19:10:44 +0100109static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
110 const uint8_t *val)
Holger Hans Peter Freyther701d1752010-02-09 16:26:49 +0100111{
Harald Weltea3d55142010-02-20 19:10:44 +0100112 uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
Holger Hans Peter Freyther701d1752010-02-09 16:26:49 +0100113
114 *buf++ = len >> 8;
115 *buf++ = len & 0xff;
116 *buf++ = tag;
117 memcpy(buf, val, len);
118 return buf + len;
119}
120
Harald Weltea3d55142010-02-20 19:10:44 +0100121static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
Harald Weltea4d49e92009-05-23 06:39:58 +0000122{
123 *buf++ = val;
124 return buf;
125}
126
Harald Weltea3d55142010-02-20 19:10:44 +0100127static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag,
128 uint8_t val)
Harald Welte52b1f982008-12-23 20:25:15 +0000129{
130 *buf++ = tag;
131 *buf++ = val;
132 return buf;
133}
134
Harald Welte5e3d91b2009-12-19 16:42:06 +0100135/* 'val' is still in host byte order! */
Harald Weltea3d55142010-02-20 19:10:44 +0100136static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag,
137 uint16_t val)
Harald Welte4b634542008-12-27 01:55:51 +0000138{
139 *buf++ = tag;
140 *buf++ = val >> 8;
141 *buf++ = val & 0xff;
142 return buf;
143}
144
Harald Weltea3d55142010-02-20 19:10:44 +0100145static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
Harald Weltea4d49e92009-05-23 06:39:58 +0000146{
Harald Weltea3d55142010-02-20 19:10:44 +0100147 uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
Harald Weltea4d49e92009-05-23 06:39:58 +0000148 return lv_put(buf, len, val);
149}
150
Harald Weltea3d55142010-02-20 19:10:44 +0100151static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
Harald Welte52b1f982008-12-23 20:25:15 +0000152{
Harald Weltea3d55142010-02-20 19:10:44 +0100153 uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
Harald Welte52b1f982008-12-23 20:25:15 +0000154 return tlv_put(buf, tag, len, val);
155}
156
Harald Weltea3d55142010-02-20 19:10:44 +0100157static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
Harald Welte52b1f982008-12-23 20:25:15 +0000158{
Harald Weltea3d55142010-02-20 19:10:44 +0100159 uint8_t *buf = msgb_put(msg, 2);
Harald Welte52b1f982008-12-23 20:25:15 +0000160 return tv_put(buf, tag, val);
161}
162
Harald Weltea3d55142010-02-20 19:10:44 +0100163static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
Harald Weltea4d49e92009-05-23 06:39:58 +0000164{
Harald Weltea3d55142010-02-20 19:10:44 +0100165 uint8_t *buf = msgb_put(msg, 1);
Harald Weltea4d49e92009-05-23 06:39:58 +0000166 return v_put(buf, val);
167}
168
Harald Weltea3d55142010-02-20 19:10:44 +0100169static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
Harald Welte4b634542008-12-27 01:55:51 +0000170{
Harald Weltea3d55142010-02-20 19:10:44 +0100171 uint8_t *buf = msgb_put(msg, 3);
Harald Welte4b634542008-12-27 01:55:51 +0000172 return tv16_put(buf, tag, val);
173}
174
Harald Weltea3d55142010-02-20 19:10:44 +0100175static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
Harald Welte52b1f982008-12-23 20:25:15 +0000176{
Harald Weltea3d55142010-02-20 19:10:44 +0100177 uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
Harald Welte52b1f982008-12-23 20:25:15 +0000178 return tlv_put(buf, tag, len, val);
179}
180
Harald Weltea3d55142010-02-20 19:10:44 +0100181static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
Harald Welte52b1f982008-12-23 20:25:15 +0000182{
Harald Weltea3d55142010-02-20 19:10:44 +0100183 uint8_t *buf = msgb_push(msg, 2);
Harald Welte52b1f982008-12-23 20:25:15 +0000184 return tv_put(buf, tag, val);
185}
186
Harald Weltea3d55142010-02-20 19:10:44 +0100187static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
Harald Welte4b634542008-12-27 01:55:51 +0000188{
Harald Weltea3d55142010-02-20 19:10:44 +0100189 uint8_t *buf = msgb_push(msg, 3);
Harald Welte4b634542008-12-27 01:55:51 +0000190 return tv16_put(buf, tag, val);
191}
192
Harald Welte91b5b0d2009-02-06 12:51:39 +0000193/* TLV parsing */
194
195struct tlv_p_entry {
Harald Weltea3d55142010-02-20 19:10:44 +0100196 uint16_t len;
197 const uint8_t *val;
Harald Welte91b5b0d2009-02-06 12:51:39 +0000198};
199
Harald Weltee0590df2009-02-15 03:34:15 +0000200enum tlv_type {
Harald Welte50781482010-01-10 17:45:23 +0100201 TLV_TYPE_NONE,
Harald Weltee0590df2009-02-15 03:34:15 +0000202 TLV_TYPE_FIXED,
203 TLV_TYPE_T,
204 TLV_TYPE_TV,
205 TLV_TYPE_TLV,
206 TLV_TYPE_TL16V,
Harald Welte73310c32009-10-24 10:04:02 +0200207 TLV_TYPE_TvLV,
Harald Weltee0590df2009-02-15 03:34:15 +0000208};
209
210struct tlv_def {
211 enum tlv_type type;
Harald Weltea3d55142010-02-20 19:10:44 +0100212 uint8_t fixed_len;
Harald Weltee0590df2009-02-15 03:34:15 +0000213};
214
215struct tlv_definition {
216 struct tlv_def def[0xff];
217};
218
Harald Welte2fa79342009-02-14 19:07:10 +0000219struct tlv_parsed {
Harald Welte91b5b0d2009-02-06 12:51:39 +0000220 struct tlv_p_entry lv[0xff];
221};
222
Harald Welte73310c32009-10-24 10:04:02 +0200223extern struct tlv_definition tvlv_att_def;
224
Harald Weltea3d55142010-02-20 19:10:44 +0100225int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
Sylvain Munauteb429b72009-10-26 20:19:59 +0100226 const struct tlv_definition *def,
Harald Weltea3d55142010-02-20 19:10:44 +0100227 const uint8_t *buf, int buf_len);
Harald Welte7bc4cbc2009-02-21 12:59:22 +0000228int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
Harald Weltea3d55142010-02-20 19:10:44 +0100229 const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
Harald Welte50781482010-01-10 17:45:23 +0100230/* take a master (src) tlvdev and fill up all empty slots in 'dst' */
231void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
Harald Welte2fa79342009-02-14 19:07:10 +0000232
233#define TLVP_PRESENT(x, y) ((x)->lv[y].val)
234#define TLVP_LEN(x, y) (x)->lv[y].len
235#define TLVP_VAL(x, y) (x)->lv[y].val
Harald Welte4b634542008-12-27 01:55:51 +0000236
Harald Welte52b1f982008-12-23 20:25:15 +0000237#endif /* _TLV_H */