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