blob: 4ae9f6c49f2372b959520f2a2b7419baec529429 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001#ifndef _TLV_H
2#define _TLV_H
3
4#include <sys/types.h>
5#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
29static inline u_int16_t TVLV_GROSS_LEN(u_int16_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
Harald Welte91b5b0d2009-02-06 12:51:39 +000037/* TLV generation */
38
Harald Weltea4d49e92009-05-23 06:39:58 +000039static inline u_int8_t *lv_put(u_int8_t *buf, u_int8_t len,
40 const u_int8_t *val)
41{
42 *buf++ = len;
43 memcpy(buf, val, len);
44 return buf + len;
45}
46
Harald Welte52b1f982008-12-23 20:25:15 +000047static inline u_int8_t *tlv_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
48 const u_int8_t *val)
49{
50 *buf++ = tag;
51 *buf++ = len;
52 memcpy(buf, val, len);
53 return buf + len;
54}
55
56static inline u_int8_t *tlv16_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
57 const u_int16_t *val)
58{
59 *buf++ = tag;
60 *buf++ = len;
61 memcpy(buf, val, len*2);
62 return buf + len*2;
63}
64
Harald Welte702d8702008-12-26 20:25:35 +000065static inline u_int8_t *tl16v_put(u_int8_t *buf, u_int8_t tag, u_int16_t len,
66 const u_int8_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
Harald Welte73310c32009-10-24 10:04:02 +020075static inline u_int8_t *tvlv_put(u_int8_t *buf, u_int8_t tag, u_int16_t len,
76 const u_int8_t *val)
77{
78 u_int8_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
Harald Welte52b1f982008-12-23 20:25:15 +000089static inline u_int8_t *msgb_tlv16_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int16_t *val)
90{
91 u_int8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
92 return tlv16_put(buf, tag, len, val);
93}
94
Harald Welte702d8702008-12-26 20:25:35 +000095static inline u_int8_t *msgb_tl16v_put(struct msgb *msg, u_int8_t tag, u_int16_t len,
96 const u_int8_t *val)
97{
98 u_int8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
99 return tl16v_put(buf, tag, len, val);
100}
101
Harald Welte73310c32009-10-24 10:04:02 +0200102static inline u_int8_t *msgb_tvlv_put(struct msgb *msg, u_int8_t tag, u_int16_t len,
103 const u_int8_t *val)
104{
105 u_int8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
106 return tvlv_put(buf, tag, len, val);
107}
108
Holger Hans Peter Freyther701d1752010-02-09 16:26:49 +0100109static inline u_int8_t *msgb_l16tv_put(struct msgb *msg, u_int16_t len, u_int8_t tag,
110 const u_int8_t *val)
111{
112 u_int8_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
Harald Weltea4d49e92009-05-23 06:39:58 +0000121static inline u_int8_t *v_put(u_int8_t *buf, u_int8_t val)
122{
123 *buf++ = val;
124 return buf;
125}
126
Harald Welte52b1f982008-12-23 20:25:15 +0000127static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag,
128 u_int8_t val)
129{
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 Welte4b634542008-12-27 01:55:51 +0000136static inline u_int8_t *tv16_put(u_int8_t *buf, u_int8_t tag,
137 u_int16_t val)
138{
139 *buf++ = tag;
140 *buf++ = val >> 8;
141 *buf++ = val & 0xff;
142 return buf;
143}
144
Harald Weltea4d49e92009-05-23 06:39:58 +0000145static inline u_int8_t *msgb_lv_put(struct msgb *msg, u_int8_t len, const u_int8_t *val)
146{
147 u_int8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
148 return lv_put(buf, len, val);
149}
150
Harald Welte52b1f982008-12-23 20:25:15 +0000151static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
152{
153 u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
154 return tlv_put(buf, tag, len, val);
155}
156
157static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val)
158{
159 u_int8_t *buf = msgb_put(msg, 2);
160 return tv_put(buf, tag, val);
161}
162
Harald Weltea4d49e92009-05-23 06:39:58 +0000163static inline u_int8_t *msgb_v_put(struct msgb *msg, u_int8_t val)
164{
165 u_int8_t *buf = msgb_put(msg, 1);
166 return v_put(buf, val);
167}
168
Harald Welte4b634542008-12-27 01:55:51 +0000169static inline u_int8_t *msgb_tv16_put(struct msgb *msg, u_int8_t tag, u_int16_t val)
170{
171 u_int8_t *buf = msgb_put(msg, 3);
172 return tv16_put(buf, tag, val);
173}
174
Harald Welte52b1f982008-12-23 20:25:15 +0000175static inline u_int8_t *msgb_tlv_push(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
176{
177 u_int8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
178 return tlv_put(buf, tag, len, val);
179}
180
181static inline u_int8_t *msgb_tv_push(struct msgb *msg, u_int8_t tag, u_int8_t val)
182{
183 u_int8_t *buf = msgb_push(msg, 2);
184 return tv_put(buf, tag, val);
185}
186
Harald Welte4b634542008-12-27 01:55:51 +0000187static inline u_int8_t *msgb_tv16_push(struct msgb *msg, u_int8_t tag, u_int16_t val)
188{
189 u_int8_t *buf = msgb_push(msg, 3);
190 return tv16_put(buf, tag, val);
191}
192
Harald Welte91b5b0d2009-02-06 12:51:39 +0000193/* TLV parsing */
194
195struct tlv_p_entry {
Harald Weltee0590df2009-02-15 03:34:15 +0000196 u_int16_t len;
Harald Welte7bc4cbc2009-02-21 12:59:22 +0000197 const u_int8_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;
212 u_int8_t fixed_len;
213};
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
Sylvain Munauteb429b72009-10-26 20:19:59 +0100225int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val,
226 const struct tlv_definition *def,
227 const u_int8_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 Weltea4d49e92009-05-23 06:39:58 +0000229 const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_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 */