blobmsg: add _len variants for all attribute checking methods
[project/libubox.git] / blobmsg.c
1 /*
2 * Copyright (C) 2010-2012 Felix Fietkau <nbd@openwrt.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include "blobmsg.h"
17
18 static const int blob_type[__BLOBMSG_TYPE_LAST] = {
19 [BLOBMSG_TYPE_INT8] = BLOB_ATTR_INT8,
20 [BLOBMSG_TYPE_INT16] = BLOB_ATTR_INT16,
21 [BLOBMSG_TYPE_INT32] = BLOB_ATTR_INT32,
22 [BLOBMSG_TYPE_INT64] = BLOB_ATTR_INT64,
23 [BLOBMSG_TYPE_DOUBLE] = BLOB_ATTR_DOUBLE,
24 [BLOBMSG_TYPE_STRING] = BLOB_ATTR_STRING,
25 [BLOBMSG_TYPE_UNSPEC] = BLOB_ATTR_BINARY,
26 };
27
28 static uint16_t
29 blobmsg_namelen(const struct blobmsg_hdr *hdr)
30 {
31 return be16_to_cpu(hdr->namelen);
32 }
33
34 bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
35 {
36 return blobmsg_check_attr_len(attr, name, blob_raw_len(attr));
37 }
38
39 static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name)
40 {
41 char *limit = (char *) attr + len;
42 const struct blobmsg_hdr *hdr;
43
44 hdr = blob_data(attr);
45 if (name && !hdr->namelen)
46 return false;
47
48 if ((char *) hdr->name + blobmsg_namelen(hdr) > limit)
49 return false;
50
51 if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr)))
52 return false;
53
54 if (hdr->name[blobmsg_namelen(hdr)] != 0)
55 return false;
56
57 return true;
58 }
59
60 static const char* blobmsg_check_data(const struct blob_attr *attr, size_t len, size_t *data_len)
61 {
62 char *limit = (char *) attr + len;
63 const char *data;
64
65 *data_len = blobmsg_data_len(attr);
66 if (*data_len > blob_raw_len(attr))
67 return NULL;
68
69 data = blobmsg_data(attr);
70 if (data + *data_len > limit)
71 return NULL;
72
73 return data;
74 }
75
76 bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len)
77 {
78 const char *data;
79 size_t data_len;
80 int id;
81
82 if (len < sizeof(struct blob_attr))
83 return false;
84
85 if (!blobmsg_check_name(attr, len, name))
86 return false;
87
88 id = blob_id(attr);
89 if (id > BLOBMSG_TYPE_LAST)
90 return false;
91
92 if (!blob_type[id])
93 return true;
94
95 data = blobmsg_check_data(attr, len, &data_len);
96 if (!data)
97 return false;
98
99 return blob_check_type(data, data_len, blob_type[id]);
100 }
101
102 int blobmsg_check_array(const struct blob_attr *attr, int type)
103 {
104 return blobmsg_check_array_len(attr, type, blob_raw_len(attr));
105 }
106
107 int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len)
108 {
109 struct blob_attr *cur;
110 bool name;
111 int size = 0;
112
113 if (type > BLOBMSG_TYPE_LAST)
114 return -1;
115
116 if (!blobmsg_check_attr_len(attr, false, len))
117 return -1;
118
119 switch (blobmsg_type(attr)) {
120 case BLOBMSG_TYPE_TABLE:
121 name = true;
122 break;
123 case BLOBMSG_TYPE_ARRAY:
124 name = false;
125 break;
126 default:
127 return -1;
128 }
129
130 __blobmsg_for_each_attr(cur, attr, len) {
131 if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
132 return -1;
133
134 if (!blobmsg_check_attr_len(cur, name, len))
135 return -1;
136
137 size++;
138 }
139
140 return size;
141 }
142
143 bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
144 {
145 return blobmsg_check_array(attr, type) >= 0;
146 }
147
148 bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len)
149 {
150 return blobmsg_check_array_len(attr, type, len) >= 0;
151 }
152
153 int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
154 struct blob_attr **tb, void *data, unsigned int len)
155 {
156 struct blob_attr *attr;
157 int i = 0;
158
159 memset(tb, 0, policy_len * sizeof(*tb));
160 __blob_for_each_attr(attr, data, len) {
161 if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
162 blob_id(attr) != policy[i].type)
163 continue;
164
165 if (!blobmsg_check_attr_len(attr, false, len))
166 return -1;
167
168 if (tb[i])
169 continue;
170
171 tb[i++] = attr;
172 if (i == policy_len)
173 break;
174 }
175
176 return 0;
177 }
178
179
180 int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
181 struct blob_attr **tb, void *data, unsigned int len)
182 {
183 struct blobmsg_hdr *hdr;
184 struct blob_attr *attr;
185 uint8_t *pslen;
186 int i;
187
188 memset(tb, 0, policy_len * sizeof(*tb));
189 if (!data || !len)
190 return -EINVAL;
191 pslen = alloca(policy_len);
192 for (i = 0; i < policy_len; i++) {
193 if (!policy[i].name)
194 continue;
195
196 pslen[i] = strlen(policy[i].name);
197 }
198
199 __blob_for_each_attr(attr, data, len) {
200 hdr = blob_data(attr);
201 for (i = 0; i < policy_len; i++) {
202 if (!policy[i].name)
203 continue;
204
205 if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
206 blob_id(attr) != policy[i].type)
207 continue;
208
209 if (blobmsg_namelen(hdr) != pslen[i])
210 continue;
211
212 if (!blobmsg_check_attr_len(attr, true, len))
213 return -1;
214
215 if (tb[i])
216 continue;
217
218 if (strcmp(policy[i].name, (char *) hdr->name) != 0)
219 continue;
220
221 tb[i] = attr;
222 }
223 }
224
225 return 0;
226 }
227
228
229 static struct blob_attr *
230 blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
231 {
232 struct blob_attr *attr;
233 struct blobmsg_hdr *hdr;
234 int attrlen, namelen;
235 char *pad_start, *pad_end;
236
237 if (!name)
238 name = "";
239
240 namelen = strlen(name);
241 attrlen = blobmsg_hdrlen(namelen) + payload_len;
242 attr = blob_new(buf, type, attrlen);
243 if (!attr)
244 return NULL;
245
246 attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
247 hdr = blob_data(attr);
248 hdr->namelen = cpu_to_be16(namelen);
249 strcpy((char *) hdr->name, (const char *)name);
250 pad_end = *data = blobmsg_data(attr);
251 pad_start = (char *) &hdr->name[namelen];
252 if (pad_start < pad_end)
253 memset(pad_start, 0, pad_end - pad_start);
254
255 return attr;
256 }
257
258 static inline int
259 attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
260 {
261 return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
262 }
263
264
265 void *
266 blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)
267 {
268 struct blob_attr *head;
269 int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE;
270 unsigned long offset = attr_to_offset(buf, buf->head);
271 void *data;
272
273 if (!name)
274 name = "";
275
276 head = blobmsg_new(buf, type, name, 0, &data);
277 if (!head)
278 return NULL;
279 blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name)));
280 buf->head = head;
281 return (void *)offset;
282 }
283
284 __attribute__((format(printf, 3, 0)))
285 int blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg)
286 {
287 va_list arg2;
288 char cbuf;
289 char *sbuf;
290 int len, ret;
291
292 va_copy(arg2, arg);
293 len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
294 va_end(arg2);
295
296 sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1);
297 if (!sbuf)
298 return -1;
299 ret = vsprintf(sbuf, format, arg);
300 blobmsg_add_string_buffer(buf);
301
302 return ret;
303 }
304
305 __attribute__((format(printf, 3, 4)))
306 int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
307 {
308 va_list ap;
309 int ret;
310
311 va_start(ap, format);
312 ret = blobmsg_vprintf(buf, name, format, ap);
313 va_end(ap);
314
315 return ret;
316 }
317
318 void *
319 blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
320 {
321 struct blob_attr *attr;
322 void *data_dest;
323
324 attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest);
325 if (!attr)
326 return NULL;
327
328 blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
329 blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
330
331 return data_dest;
332 }
333
334 void *
335 blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
336 {
337 struct blob_attr *attr = blob_next(buf->head);
338 int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE;
339 int required = maxlen - (buf->buflen - offset);
340
341 if (required <= 0)
342 goto out;
343
344 if (!blob_buf_grow(buf, required))
345 return NULL;
346 attr = blob_next(buf->head);
347
348 out:
349 return blobmsg_data(attr);
350 }
351
352 void
353 blobmsg_add_string_buffer(struct blob_buf *buf)
354 {
355 struct blob_attr *attr;
356 int len, attrlen;
357
358 attr = blob_next(buf->head);
359 len = strlen(blobmsg_data(attr)) + 1;
360
361 attrlen = blob_raw_len(attr) + len;
362 blob_set_raw_len(attr, attrlen);
363 blob_fill_pad(attr);
364
365 blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr));
366 }
367
368 int
369 blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
370 const void *data, unsigned int len)
371 {
372 struct blob_attr *attr;
373 void *data_dest;
374
375 attr = blobmsg_new(buf, type, name, len, &data_dest);
376 if (!attr)
377 return -1;
378
379 if (len > 0)
380 memcpy(data_dest, data, len);
381
382 return 0;
383 }