• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/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 bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
 29 {
 30         return blobmsg_check_attr_len(attr, name, blob_raw_len(attr));
 31 }
 32 
 33 static bool blobmsg_check_name(const struct blob_attr *attr, bool name)
 34 {
 35         const struct blobmsg_hdr *hdr;
 36         uint16_t namelen;
 37 
 38         if (!blob_is_extended(attr))
 39                 return !name;
 40 
 41         if (blob_len(attr) < sizeof(struct blobmsg_hdr))
 42                 return false;
 43 
 44         hdr = (const struct blobmsg_hdr *)blob_data(attr);
 45         if (name && !hdr->namelen)
 46                 return false;
 47 
 48         namelen = blobmsg_namelen(hdr);
 49         if (blob_len(attr) < (size_t)blobmsg_hdrlen(namelen))
 50                 return false;
 51 
 52         if (hdr->name[namelen] != 0)
 53                 return false;
 54 
 55         return true;
 56 }
 57 
 58 bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len)
 59 {
 60         const char *data;
 61         size_t data_len;
 62         int id;
 63 
 64         if (len < sizeof(struct blob_attr))
 65                 return false;
 66 
 67         data_len = blob_raw_len(attr);
 68         if (data_len < sizeof(struct blob_attr) || data_len > len)
 69                 return false;
 70 
 71         if (!blobmsg_check_name(attr, name))
 72                 return false;
 73 
 74         id = blob_id(attr);
 75         if (id > BLOBMSG_TYPE_LAST)
 76                 return false;
 77 
 78         if (!blob_type[id])
 79                 return true;
 80 
 81         data = blobmsg_data(attr);
 82         data_len = blobmsg_data_len(attr);
 83 
 84         return blob_check_type(data, data_len, blob_type[id]);
 85 }
 86 
 87 int blobmsg_check_array(const struct blob_attr *attr, int type)
 88 {
 89         return blobmsg_check_array_len(attr, type, blob_raw_len(attr));
 90 }
 91 
 92 int blobmsg_check_array_len(const struct blob_attr *attr, int type,
 93                             size_t blob_len)
 94 {
 95         struct blob_attr *cur;
 96         size_t rem;
 97         bool name;
 98         int size = 0;
 99 
100         if (type > BLOBMSG_TYPE_LAST)
101                 return -1;
102 
103         if (!blobmsg_check_attr_len(attr, false, blob_len))
104                 return -1;
105 
106         switch (blobmsg_type(attr)) {
107         case BLOBMSG_TYPE_TABLE:
108                 name = true;
109                 break;
110         case BLOBMSG_TYPE_ARRAY:
111                 name = false;
112                 break;
113         default:
114                 return -1;
115         }
116 
117         blobmsg_for_each_attr(cur, attr, rem) {
118                 if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
119                         return -1;
120 
121                 if (!blobmsg_check_attr_len(cur, name, rem))
122                         return -1;
123 
124                 size++;
125         }
126 
127         return size;
128 }
129 
130 bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
131 {
132         return blobmsg_check_array(attr, type) >= 0;
133 }
134 
135 bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len)
136 {
137         return blobmsg_check_array_len(attr, type, len) >= 0;
138 }
139 
140 int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
141                         struct blob_attr **tb, void *data, unsigned int len)
142 {
143         struct blob_attr *attr;
144         int i = 0;
145 
146         memset(tb, 0, policy_len * sizeof(*tb));
147         __blob_for_each_attr(attr, data, len) {
148                 if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
149                     blob_id(attr) != policy[i].type)
150                         continue;
151 
152                 if (!blobmsg_check_attr_len(attr, false, len))
153                         return -1;
154 
155                 if (tb[i])
156                         continue;
157 
158                 tb[i++] = attr;
159                 if (i == policy_len)
160                         break;
161         }
162 
163         return 0;
164 }
165 
166 int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
167                   struct blob_attr **tb, void *data, unsigned int len)
168 {
169         const struct blobmsg_hdr *hdr;
170         struct blob_attr *attr;
171         uint8_t *pslen;
172         int i;
173 
174         memset(tb, 0, policy_len * sizeof(*tb));
175         if (!data || !len)
176                 return -EINVAL;
177         pslen = alloca(policy_len);
178         for (i = 0; i < policy_len; i++) {
179                 if (!policy[i].name)
180                         continue;
181 
182                 pslen[i] = strlen(policy[i].name);
183         }
184 
185         __blob_for_each_attr(attr, data, len) {
186                 if (!blobmsg_check_attr_len(attr, false, len))
187                         return -1;
188 
189                 if (!blob_is_extended(attr))
190                         continue;
191 
192                 hdr = blob_data(attr);
193                 for (i = 0; i < policy_len; i++) {
194                         if (!policy[i].name)
195                                 continue;
196 
197                         if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
198                             policy[i].type != BLOBMSG_CAST_INT64 &&
199                             blob_id(attr) != policy[i].type)
200                                 continue;
201 
202                         if (policy[i].type == BLOBMSG_CAST_INT64 &&
203                             (blob_id(attr) != BLOBMSG_TYPE_INT64 &&
204                              blob_id(attr) != BLOBMSG_TYPE_INT32 &&
205                              blob_id(attr) != BLOBMSG_TYPE_INT16 &&
206                              blob_id(attr) != BLOBMSG_TYPE_INT8))
207                                 continue;
208 
209                         if (blobmsg_namelen(hdr) != pslen[i])
210                                 continue;
211 
212                         if (tb[i])
213                                 continue;
214 
215                         if (strcmp(policy[i].name, (char *) hdr->name) != 0)
216                                 continue;
217 
218                         tb[i] = attr;
219                 }
220         }
221 
222         return 0;
223 }
224 
225 
226 static struct blob_attr *
227 blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
228 {
229         struct blob_attr *attr;
230         struct blobmsg_hdr *hdr;
231         int attrlen, namelen;
232         char *pad_start, *pad_end;
233 
234         if (!name)
235                 name = "";
236 
237         namelen = strlen(name);
238         attrlen = blobmsg_hdrlen(namelen) + payload_len;
239         attr = blob_new(buf, type, attrlen);
240         if (!attr)
241                 return NULL;
242 
243         attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
244         hdr = blob_data(attr);
245         hdr->namelen = cpu_to_be16(namelen);
246 
247         memcpy(hdr->name, name, namelen);
248         hdr->name[namelen] = '\0';
249 
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         if (len < 0)
297                 return -1;
298 
299         sbuf = blobmsg_alloc_string_buffer(buf, name, len);
300         if (!sbuf)
301                 return -1;
302 
303         ret = vsnprintf(sbuf, len + 1, format, arg);
304         if (ret < 0)
305                 return -1;
306 
307         blobmsg_add_string_buffer(buf);
308 
309         return ret;
310 }
311 
312 __attribute__((format(printf, 3, 4)))
313 int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
314 {
315         va_list ap;
316         int ret;
317 
318         va_start(ap, format);
319         ret = blobmsg_vprintf(buf, name, format, ap);
320         va_end(ap);
321 
322         return ret;
323 }
324 
325 void *
326 blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
327 {
328         struct blob_attr *attr;
329         void *data_dest;
330 
331         maxlen++;
332         attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest);
333         if (!attr)
334                 return NULL;
335 
336         blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
337         blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
338 
339         return data_dest;
340 }
341 
342 void *
343 blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
344 {
345         struct blob_attr *attr = blob_next(buf->head);
346         int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE;
347         int required = maxlen + 1 - (buf->buflen - offset);
348 
349         if (required <= 0)
350                 goto out;
351 
352         if (!blob_buf_grow(buf, required))
353                 return NULL;
354         attr = blob_next(buf->head);
355 
356 out:
357         return blobmsg_data(attr);
358 }
359 
360 void
361 blobmsg_add_string_buffer(struct blob_buf *buf)
362 {
363         struct blob_attr *attr;
364         int len, attrlen;
365 
366         attr = blob_next(buf->head);
367         len = strlen(blobmsg_data(attr)) + 1;
368 
369         attrlen = blob_raw_len(attr) + len;
370         blob_set_raw_len(attr, attrlen);
371         blob_fill_pad(attr);
372 
373         blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr));
374 }
375 
376 int
377 blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
378                   const void *data, unsigned int len)
379 {
380         struct blob_attr *attr;
381         void *data_dest;
382 
383         attr = blobmsg_new(buf, type, name, len, &data_dest);
384         if (!attr)
385                 return -1;
386 
387         if (len > 0)
388                 memcpy(data_dest, data, len);
389 
390         return 0;
391 }
392 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt