blob: 14c9910df4f31c5aa67900efb7055911e301d582 [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001#ifndef _TLV_H
2#define _TLV_H
3
4#include <stdint.h>
5#include <string.h>
6
7#include <osmocore/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
29static 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
39static 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
47static 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
56static 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
65static 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
75static 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
89static 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
95static 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
102static 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
109static 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
121static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
122{
123 *buf++ = val;
124 return buf;
125}
126
127static 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/* 'val' is still in host byte order! */
136static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag,
137 uint16_t val)
138{
139 *buf++ = tag;
140 *buf++ = val >> 8;
141 *buf++ = val & 0xff;
142 return buf;
143}
144
145static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
146{
147 uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
148 return lv_put(buf, len, val);
149}
150
151static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
152{
153 uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
154 return tlv_put(buf, tag, len, val);
155}
156
157static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
158{
159 uint8_t *buf = msgb_put(msg, 2);
160 return tv_put(buf, tag, val);
161}
162
163static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
164{
165 uint8_t *buf = msgb_put(msg, 1);
166 return v_put(buf, val);
167}
168
169static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
170{
171 uint8_t *buf = msgb_put(msg, 3);
172 return tv16_put(buf, tag, val);
173}
174
175static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
176{
177 uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
178 return tlv_put(buf, tag, len, val);
179}
180
181static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
182{
183 uint8_t *buf = msgb_push(msg, 2);
184 return tv_put(buf, tag, val);
185}
186
187static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
188{
189 uint8_t *buf = msgb_push(msg, 3);
190 return tv16_put(buf, tag, val);
191}
192
193/* TLV parsing */
194
195struct tlv_p_entry {
196 uint16_t len;
197 const uint8_t *val;
198};
199
200enum tlv_type {
201 TLV_TYPE_NONE,
202 TLV_TYPE_FIXED,
203 TLV_TYPE_T,
204 TLV_TYPE_TV,
205 TLV_TYPE_TLV,
206 TLV_TYPE_TL16V,
207 TLV_TYPE_TvLV,
208};
209
210struct tlv_def {
211 enum tlv_type type;
212 uint8_t fixed_len;
213};
214
215struct tlv_definition {
216 struct tlv_def def[0xff];
217};
218
219struct tlv_parsed {
220 struct tlv_p_entry lv[0xff];
221};
222
223extern struct tlv_definition tvlv_att_def;
224
225int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
226 const struct tlv_definition *def,
227 const uint8_t *buf, int buf_len);
228int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
229 const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
230/* 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);
232
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
236
237#endif /* _TLV_H */