blobmsg.c 8.6 KB

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