Added single octet TV (type + value) to libosmocore.
[osmocom-bb.git] / include / osmocore / tlv.h
1 #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
29 static 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
39 static 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
47 static 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
56 static 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
65 static 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
75 static 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
89 static 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
95 static 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
102 static 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
109 static 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
121 static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
122 {
123         *buf++ = val;
124         return buf;
125 }
126
127 static 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! */
136 static 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
145 static 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
151 static 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
157 static 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
163 static 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
169 static 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
175 static 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
181 static 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
187 static 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 static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
194                                       const uint8_t *val)
195 {
196         uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
197         return tvlv_put(buf, tag, len, val);
198 }
199
200 /* TLV parsing */
201
202 struct tlv_p_entry {
203         uint16_t len;
204         const uint8_t *val;
205 };
206
207 enum tlv_type {
208         TLV_TYPE_NONE,
209         TLV_TYPE_FIXED,
210         TLV_TYPE_T,
211         TLV_TYPE_TV,
212         TLV_TYPE_TLV,
213         TLV_TYPE_TL16V,
214         TLV_TYPE_TvLV,
215         TLV_TYPE_SINGLE_TV
216 };
217
218 struct tlv_def {
219         enum tlv_type type;
220         uint8_t fixed_len;
221 };
222
223 struct tlv_definition {
224         struct tlv_def def[0xff];
225 };
226
227 struct tlv_parsed {
228         struct tlv_p_entry lv[0xff];
229 };
230
231 extern struct tlv_definition tvlv_att_def;
232
233 int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
234                   const struct tlv_definition *def,
235                   const uint8_t *buf, int buf_len);
236 int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
237               const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
238 /* take a master (src) tlvdev and fill up all empty slots in 'dst' */
239 void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
240
241 #define TLVP_PRESENT(x, y)      ((x)->lv[y].val)
242 #define TLVP_LEN(x, y)          (x)->lv[y].len
243 #define TLVP_VAL(x, y)          (x)->lv[y].val
244
245 #endif /* _TLV_H */