blobmsg.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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_STRING] = BLOB_ATTR_STRING,
  23. [BLOBMSG_TYPE_UNSPEC] = BLOB_ATTR_BINARY,
  24. };
  25. static uint16_t
  26. blobmsg_namelen(const struct blobmsg_hdr *hdr)
  27. {
  28. return be16_to_cpu(hdr->namelen);
  29. }
  30. bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
  31. {
  32. const struct blobmsg_hdr *hdr;
  33. const char *data;
  34. int id, len;
  35. if (blob_len(attr) < sizeof(struct blobmsg_hdr))
  36. return false;
  37. hdr = (void *) attr->data;
  38. if (!hdr->namelen && name)
  39. return false;
  40. if (blobmsg_namelen(hdr) > blob_len(attr) - sizeof(struct blobmsg_hdr))
  41. return false;
  42. if (hdr->name[blobmsg_namelen(hdr)] != 0)
  43. return false;
  44. id = blob_id(attr);
  45. len = blobmsg_data_len(attr);
  46. data = blobmsg_data(attr);
  47. if (id > BLOBMSG_TYPE_LAST)
  48. return false;
  49. if (!blob_type[id])
  50. return true;
  51. return blob_check_type(data, len, blob_type[id]);
  52. }
  53. int blobmsg_check_array(const struct blob_attr *attr, int type)
  54. {
  55. struct blob_attr *cur;
  56. bool name;
  57. int rem;
  58. int size = 0;
  59. switch (blobmsg_type(attr)) {
  60. case BLOBMSG_TYPE_TABLE:
  61. name = true;
  62. break;
  63. case BLOBMSG_TYPE_ARRAY:
  64. name = false;
  65. break;
  66. default:
  67. return -1;
  68. }
  69. blobmsg_for_each_attr(cur, attr, rem) {
  70. if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
  71. return -1;
  72. if (!blobmsg_check_attr(cur, name))
  73. return -1;
  74. size++;
  75. }
  76. return size;
  77. }
  78. bool blobmsg_check_attr_list(const struct blob_attr *attr, int type)
  79. {
  80. return blobmsg_check_array(attr, type) >= 0;
  81. }
  82. int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
  83. struct blob_attr **tb, void *data, unsigned int len)
  84. {
  85. struct blob_attr *attr;
  86. int i = 0;
  87. memset(tb, 0, policy_len * sizeof(*tb));
  88. __blob_for_each_attr(attr, data, len) {
  89. if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
  90. blob_id(attr) != policy[i].type)
  91. continue;
  92. if (!blobmsg_check_attr(attr, false))
  93. return -1;
  94. if (tb[i])
  95. continue;
  96. tb[i++] = attr;
  97. if (i == policy_len)
  98. break;
  99. }
  100. return 0;
  101. }
  102. int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
  103. struct blob_attr **tb, void *data, unsigned int len)
  104. {
  105. struct blobmsg_hdr *hdr;
  106. struct blob_attr *attr;
  107. uint8_t *pslen;
  108. int i;
  109. memset(tb, 0, policy_len * sizeof(*tb));
  110. pslen = alloca(policy_len);
  111. for (i = 0; i < policy_len; i++) {
  112. if (!policy[i].name)
  113. continue;
  114. pslen[i] = strlen(policy[i].name);
  115. }
  116. __blob_for_each_attr(attr, data, len) {
  117. hdr = blob_data(attr);
  118. for (i = 0; i < policy_len; i++) {
  119. if (!policy[i].name)
  120. continue;
  121. if (policy[i].type != BLOBMSG_TYPE_UNSPEC &&
  122. blob_id(attr) != policy[i].type)
  123. continue;
  124. if (blobmsg_namelen(hdr) != pslen[i])
  125. continue;
  126. if (!blobmsg_check_attr(attr, true))
  127. return -1;
  128. if (tb[i])
  129. continue;
  130. if (strcmp(policy[i].name, (char *) hdr->name) != 0)
  131. continue;
  132. tb[i] = attr;
  133. }
  134. }
  135. return 0;
  136. }
  137. static struct blob_attr *
  138. blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)
  139. {
  140. struct blob_attr *attr;
  141. struct blobmsg_hdr *hdr;
  142. int attrlen, namelen;
  143. char *pad_start, *pad_end;
  144. if (!name)
  145. name = "";
  146. namelen = strlen(name);
  147. attrlen = blobmsg_hdrlen(namelen) + payload_len;
  148. attr = blob_new(buf, type, attrlen);
  149. if (!attr)
  150. return NULL;
  151. attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
  152. hdr = blob_data(attr);
  153. hdr->namelen = cpu_to_be16(namelen);
  154. strcpy((char *) hdr->name, (const char *)name);
  155. pad_end = *data = blobmsg_data(attr);
  156. pad_start = (char *) &hdr->name[namelen];
  157. if (pad_start < pad_end)
  158. memset(pad_start, 0, pad_end - pad_start);
  159. return attr;
  160. }
  161. static inline int
  162. attr_to_offset(struct blob_buf *buf, struct blob_attr *attr)
  163. {
  164. return (char *)attr - (char *) buf->buf + BLOB_COOKIE;
  165. }
  166. void *
  167. blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)
  168. {
  169. struct blob_attr *head;
  170. int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE;
  171. unsigned long offset = attr_to_offset(buf, buf->head);
  172. void *data;
  173. if (!name)
  174. name = "";
  175. head = blobmsg_new(buf, type, name, 0, &data);
  176. if (!head)
  177. return NULL;
  178. blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name)));
  179. buf->head = head;
  180. return (void *)offset;
  181. }
  182. int
  183. blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg)
  184. {
  185. va_list arg2;
  186. char cbuf;
  187. char *sbuf;
  188. int len, ret;
  189. va_copy(arg2, arg);
  190. len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
  191. va_end(arg2);
  192. sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1);
  193. if (!sbuf)
  194. return -1;
  195. ret = vsprintf(sbuf, format, arg);
  196. blobmsg_add_string_buffer(buf);
  197. return ret;
  198. }
  199. int
  200. blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
  201. {
  202. va_list ap;
  203. int ret;
  204. va_start(ap, format);
  205. ret = blobmsg_vprintf(buf, name, format, ap);
  206. va_end(ap);
  207. return ret;
  208. }
  209. void *
  210. blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
  211. {
  212. struct blob_attr *attr;
  213. void *data_dest;
  214. attr = blobmsg_new(buf, BLOBMSG_TYPE_STRING, name, maxlen, &data_dest);
  215. if (!attr)
  216. return NULL;
  217. blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr));
  218. blob_set_raw_len(attr, blob_raw_len(attr) - maxlen);
  219. return data_dest;
  220. }
  221. void *
  222. blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
  223. {
  224. struct blob_attr *attr = blob_next(buf->head);
  225. int offset = attr_to_offset(buf, blob_next(buf->head)) + blob_pad_len(attr) - BLOB_COOKIE;
  226. int required = maxlen - (buf->buflen - offset);
  227. if (required <= 0)
  228. goto out;
  229. if (!blob_buf_grow(buf, required))
  230. return NULL;
  231. attr = blob_next(buf->head);
  232. out:
  233. return blobmsg_data(attr);
  234. }
  235. void
  236. blobmsg_add_string_buffer(struct blob_buf *buf)
  237. {
  238. struct blob_attr *attr;
  239. int len, attrlen;
  240. attr = blob_next(buf->head);
  241. len = strlen(blobmsg_data(attr)) + 1;
  242. attrlen = blob_raw_len(attr) + len;
  243. blob_set_raw_len(attr, attrlen);
  244. blob_fill_pad(attr);
  245. blob_set_raw_len(buf->head, blob_raw_len(buf->head) + blob_pad_len(attr));
  246. }
  247. int
  248. blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
  249. const void *data, unsigned int len)
  250. {
  251. struct blob_attr *attr;
  252. void *data_dest;
  253. attr = blobmsg_new(buf, type, name, len, &data_dest);
  254. if (!attr)
  255. return -1;
  256. if (len > 0)
  257. memcpy(data_dest, data, len);
  258. return 0;
  259. }