blobmsg.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. static const int blob_type[__BLOBMSG_TYPE_LAST] = {
  18. [BLOBMSG_TYPE_INT8] = BLOB_ATTR_INT8,
  19. [BLOBMSG_TYPE_INT16] = BLOB_ATTR_INT16,
  20. [BLOBMSG_TYPE_INT32] = BLOB_ATTR_INT32,
  21. [BLOBMSG_TYPE_INT64] = BLOB_ATTR_INT64,
  22. [BLOBMSG_TYPE_DOUBLE] = BLOB_ATTR_DOUBLE,
  23. [BLOBMSG_TYPE_STRING] = BLOB_ATTR_STRING,
  24. [BLOBMSG_TYPE_UNSPEC] = BLOB_ATTR_BINARY,
  25. };
  26. bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
  27. {
  28. return blobmsg_check_attr_len(attr, name, blob_raw_len(attr));
  29. }
  30. static const struct blobmsg_hdr* blobmsg_hdr_from_blob(const struct blob_attr *attr, size_t len)
  31. {
  32. if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr))
  33. return NULL;
  34. return blob_data(attr);
  35. }
  36. static bool blobmsg_hdr_valid_namelen(const struct blobmsg_hdr *hdr, size_t len)
  37. {
  38. if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr) + blobmsg_namelen(hdr) + 1)
  39. return false;
  40. return true;
  41. }
  42. static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name)
  43. {
  44. char *limit = (char *) attr + len;
  45. const struct blobmsg_hdr *hdr;
  46. hdr = blobmsg_hdr_from_blob(attr, len);
  47. if (!hdr)
  48. return false;
  49. if (name && !hdr->namelen)
  50. return false;
  51. if (name && !blobmsg_hdr_valid_namelen(hdr, len))
  52. return false;
  53. if ((char *) hdr->name + blobmsg_namelen(hdr) + 1 > limit)
  54. return false;
  55. if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr)))
  56. return false;
  57. if (hdr->name[blobmsg_namelen(hdr)] != 0)
  58. return false;
  59. return true;
  60. }
  61. static const char* blobmsg_check_data(const struct blob_attr *attr, size_t len, size_t *data_len)
  62. {
  63. char *limit = (char *) attr + len;
  64. const char *data;
  65. *data_len = blobmsg_data_len(attr);
  66. if (*data_len > blob_raw_len(attr))
  67. return NULL;
  68. data = blobmsg_data(attr);
  69. if (data + *data_len > limit)
  70. return NULL;
  71. return data;
  72. }
  73. bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len)
  74. {
  75. const char *data;
  76. size_t data_len;
  77. int id;
  78. if (!blobmsg_check_name(attr, len, name))
  79. return false;
  80. id = blob_id(attr);
  81. if (id > BLOBMSG_TYPE_LAST)
  82. return false;
  83. if (!blob_type[id])
  84. return true;
  85. data = blobmsg_check_data(attr, len, &data_len);
  86. if (!data)
  87. return false;
  88. return blob_check_type(data, data_len, blob_type[id]);
  89. }
  90. int blobmsg_check_array(const struct blob_attr *attr, int type)
  91. {
  92. return blobmsg_check_array_len(attr, type, blob_len(attr));
  93. }
  94. int blobmsg_check_array_len(const struct blob_attr *attr, int type,
  95. size_t blob_len)
  96. {
  97. struct blob_attr *cur;
  98. size_t rem;
  99. bool name;
  100. int size = 0;
  101. if (type > BLOBMSG_TYPE_LAST)
  102. return -1;
  103. if (!blobmsg_check_attr_len(attr, false, blob_len))
  104. return -1;
  105. switch (blobmsg_type(attr)) {
  106. case BLOBMSG_TYPE_TABLE:
  107. name = true;
  108. break;
  109. case BLOBMSG_TYPE_ARRAY:
  110. name = false;
  111. break;
  112. default:
  113. return -1;
  114. }
  115. blobmsg_for_each_attr(cur, attr, rem) {
  116. if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
  117. return -1;
  118. if (!blobmsg_check_attr_len(cur, name, rem))
  119. return -1;
  120. size++;
  121. }
  122. return size;
  123. }
  124. bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
  125. {
  126. return blobmsg_check_array(attr, type) >= 0;
  127. }
  128. bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len)
  129. {
  130. return blobmsg_check_array_len(attr, type, len) >= 0;
  131. }
  132. int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
  133. struct blob_attr **tb, void *data, unsigned int len)
  134. {
  135. struct blob_attr *attr;
  136. int i = 0;
  137. memset(tb, 0, policy_len * sizeof(*tb));
  138. __blob_for_each_attr(attr, data, len) {
  139. if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
  140. blob_id(attr) != policy[i].type)
  141. continue;
  142. if (!blobmsg_check_attr_len(attr, false, len))
  143. return -1;
  144. if (tb[i])
  145. continue;
  146. tb[i++] = attr;
  147. if (i == policy_len)
  148. break;
  149. }
  150. return 0;
  151. }
  152. int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
  153. struct blob_attr **tb, void *data, unsigned int len)
  154. {
  155. const struct blobmsg_hdr *hdr;
  156. struct blob_attr *attr;
  157. uint8_t *pslen;
  158. int i;
  159. memset(tb, 0, policy_len * sizeof(*tb));
  160. if (!data || !len)
  161. return -EINVAL;
  162. pslen = alloca(policy_len);
  163. for (i = 0; i < policy_len; i++) {
  164. if (!policy[i].name)
  165. continue;
  166. pslen[i] = strlen(policy[i].name);
  167. }
  168. __blob_for_each_attr(attr, data, len) {
  169. hdr = blobmsg_hdr_from_blob(attr, len);
  170. if (!hdr)
  171. return -1;
  172. if (!blobmsg_hdr_valid_namelen(hdr, len))
  173. return -1;
  174. for (i = 0; i < policy_len; i++) {
  175. if (!policy[i].name)
  176. continue;
  177. if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
  178. blob_id(attr) != policy[i].type)
  179. continue;
  180. if (blobmsg_namelen(hdr) != pslen[i])
  181. continue;
  182. if (!blobmsg_check_attr_len(attr, true, len))
  183. return -1;
  184. if (tb[i])
  185. continue;
  186. if (strcmp(policy[i].name, (char *) hdr->name) != 0)
  187. continue;
  188. tb[i] = attr;
  189. }
  190. }
  191. return 0;
  192. }
  193. static struct blob_attr *
  194. blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
  195. {
  196. struct blob_attr *attr;
  197. struct blobmsg_hdr *hdr;
  198. int attrlen, namelen;
  199. char *pad_start, *pad_end;
  200. if (!name)
  201. name = "";
  202. namelen = strlen(name);
  203. attrlen = blobmsg_hdrlen(namelen) + payload_len;
  204. attr = blob_new(buf, type, attrlen);
  205. if (!attr)
  206. return NULL;
  207. attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
  208. hdr = blob_data(attr);
  209. hdr->namelen = cpu_to_be16(namelen);
  210. memcpy(hdr->name, name, namelen);
  211. hdr->name[namelen] = '\0';
  212. pad_end = *data = blobmsg_data(attr);
  213. pad_start = (char *) &hdr->name[namelen];
  214. if (pad_start < pad_end)
  215. memset(pad_start, 0, pad_end - pad_start);
  216. return attr;
  217. }
  218. static inline int
  219. attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
  220. {
  221. return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
  222. }
  223. void *
  224. blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)
  225. {
  226. struct blob_attr *head;
  227. int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE;
  228. unsigned long offset = attr_to_offset(buf, buf->head);
  229. void *data;
  230. if (!name)
  231. name = "";
  232. head = blobmsg_new(buf, type, name, 0, &data);
  233. if (!head)
  234. return NULL;
  235. blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name)));
  236. buf->head = head;
  237. return (void *)offset;
  238. }
  239. __attribute__((format(printf, 3, 0)))
  240. int blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg)
  241. {
  242. va_list arg2;
  243. char cbuf;
  244. char *sbuf;
  245. int len, ret;
  246. va_copy(arg2, arg);
  247. len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
  248. va_end(arg2);
  249. if (len < 0)
  250. return -1;
  251. sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1);
  252. if (!sbuf)
  253. return -1;
  254. ret = vsnprintf(sbuf, len + 1, format, arg);
  255. if (ret < 0)
  256. return -1;
  257. blobmsg_add_string_buffer(buf);
  258. return ret;
  259. }
  260. __attribute__((format(printf, 3, 4)))
  261. int blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
  262. {
  263. va_list ap;
  264. int ret;
  265. va_start(ap, format);
  266. ret = blobmsg_vprintf(buf, name, format, ap);
  267. va_end(ap);
  268. return ret;
  269. }
  270. void *
  271. blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
  272. {
  273. struct blob_attr *attr;
  274. void *data_dest;
  275. attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest);
  276. if (!attr)
  277. return NULL;
  278. blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
  279. blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
  280. return data_dest;
  281. }
  282. void *
  283. blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
  284. {
  285. struct blob_attr *attr = blob_next(buf->head);
  286. int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE;
  287. int required = maxlen - (buf->buflen - offset);
  288. if (required <= 0)
  289. goto out;
  290. if (!blob_buf_grow(buf, required))
  291. return NULL;
  292. attr = blob_next(buf->head);
  293. out:
  294. return blobmsg_data(attr);
  295. }
  296. void
  297. blobmsg_add_string_buffer(struct blob_buf *buf)
  298. {
  299. struct blob_attr *attr;
  300. int len, attrlen;
  301. attr = blob_next(buf->head);
  302. len = strlen(blobmsg_data(attr)) + 1;
  303. attrlen = blob_raw_len(attr) + len;
  304. blob_set_raw_len(attr, attrlen);
  305. blob_fill_pad(attr);
  306. blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr));
  307. }
  308. int
  309. blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
  310. const void *data, unsigned int len)
  311. {
  312. struct blob_attr *attr;
  313. void *data_dest;
  314. attr = blobmsg_new(buf, type, name, len, &data_dest);
  315. if (!attr)
  316. return -1;
  317. if (len > 0)
  318. memcpy(data_dest, data, len);
  319. return 0;
  320. }