coap.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #include "user_config.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "coap.h"
  5. #include "uri.h"
  6. extern void endpoint_setup(void);
  7. extern const coap_endpoint_t endpoints[];
  8. #ifdef COAP_DEBUG
  9. void coap_dumpHeader(coap_header_t *hdr)
  10. {
  11. printf("Header:\n");
  12. printf(" ver 0x%02X\n", hdr->ver);
  13. printf(" t 0x%02X\n", hdr->ver);
  14. printf(" tkl 0x%02X\n", hdr->tkl);
  15. printf(" code 0x%02X\n", hdr->code);
  16. printf(" id 0x%02X%02X\n", hdr->id[0], hdr->id[1]);
  17. }
  18. void coap_dump(const uint8_t *buf, size_t buflen, bool bare)
  19. {
  20. if (bare)
  21. {
  22. while(buflen--)
  23. printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
  24. }
  25. else
  26. {
  27. printf("Dump: ");
  28. while(buflen--)
  29. printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
  30. printf("\n");
  31. }
  32. }
  33. #endif
  34. int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen)
  35. {
  36. if (buflen < 4)
  37. return COAP_ERR_HEADER_TOO_SHORT;
  38. hdr->ver = (buf[0] & 0xC0) >> 6;
  39. if (hdr->ver != 1)
  40. return COAP_ERR_VERSION_NOT_1;
  41. hdr->t = (buf[0] & 0x30) >> 4;
  42. hdr->tkl = buf[0] & 0x0F;
  43. hdr->code = buf[1];
  44. hdr->id[0] = buf[2];
  45. hdr->id[1] = buf[3];
  46. return 0;
  47. }
  48. int coap_buildHeader(const coap_header_t *hdr, uint8_t *buf, size_t buflen)
  49. {
  50. // build header
  51. if (buflen < 4)
  52. return COAP_ERR_BUFFER_TOO_SMALL;
  53. buf[0] = (hdr->ver & 0x03) << 6;
  54. buf[0] |= (hdr->t & 0x03) << 4;
  55. buf[0] |= (hdr->tkl & 0x0F);
  56. buf[1] = hdr->code;
  57. buf[2] = hdr->id[0];
  58. buf[3] = hdr->id[1];
  59. return 4;
  60. }
  61. int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
  62. {
  63. if (hdr->tkl == 0)
  64. {
  65. tokbuf->p = NULL;
  66. tokbuf->len = 0;
  67. return 0;
  68. }
  69. else
  70. if (hdr->tkl <= 8)
  71. {
  72. if (4U + hdr->tkl > buflen)
  73. return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet
  74. tokbuf->p = buf+4; // past header
  75. tokbuf->len = hdr->tkl;
  76. return 0;
  77. }
  78. else
  79. {
  80. // invalid size
  81. return COAP_ERR_TOKEN_TOO_SHORT;
  82. }
  83. }
  84. int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8_t *buf, size_t buflen)
  85. {
  86. // inject token
  87. uint8_t *p;
  88. if (buflen < (4U + hdr->tkl))
  89. return COAP_ERR_BUFFER_TOO_SMALL;
  90. p = buf + 4;
  91. if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len))
  92. return COAP_ERR_UNSUPPORTED;
  93. if (hdr->tkl > 0)
  94. memcpy(p, tokbuf->p, hdr->tkl);
  95. // http://tools.ietf.org/html/rfc7252#section-3.1
  96. // inject options
  97. return hdr->tkl;
  98. }
  99. // advances p
  100. int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
  101. {
  102. const uint8_t *p = *buf;
  103. uint8_t headlen = 1;
  104. uint16_t len, delta;
  105. if (buflen < headlen) // too small
  106. return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
  107. delta = (p[0] & 0xF0) >> 4;
  108. len = p[0] & 0x0F;
  109. // These are untested and may be buggy
  110. if (delta == 13)
  111. {
  112. headlen++;
  113. if (buflen < headlen)
  114. return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
  115. delta = p[1] + 13;
  116. p++;
  117. }
  118. else
  119. if (delta == 14)
  120. {
  121. headlen += 2;
  122. if (buflen < headlen)
  123. return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
  124. delta = ((p[1] << 8) | p[2]) + 269;
  125. p+=2;
  126. }
  127. else
  128. if (delta == 15)
  129. return COAP_ERR_OPTION_DELTA_INVALID;
  130. if (len == 13)
  131. {
  132. headlen++;
  133. if (buflen < headlen)
  134. return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
  135. len = p[1] + 13;
  136. p++;
  137. }
  138. else
  139. if (len == 14)
  140. {
  141. headlen += 2;
  142. if (buflen < headlen)
  143. return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
  144. len = ((p[1] << 8) | p[2]) + 269;
  145. p+=2;
  146. }
  147. else
  148. if (len == 15)
  149. return COAP_ERR_OPTION_LEN_INVALID;
  150. if ((p + 1 + len) > (*buf + buflen))
  151. return COAP_ERR_OPTION_TOO_BIG;
  152. //printf("option num=%d\n", delta + *running_delta);
  153. option->num = delta + *running_delta;
  154. option->buf.p = p+1;
  155. option->buf.len = len;
  156. //coap_dump(p+1, len, false);
  157. // advance buf
  158. *buf = p + 1 + len;
  159. *running_delta += delta;
  160. return 0;
  161. }
  162. // http://tools.ietf.org/html/rfc7252#section-3.1
  163. int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
  164. {
  165. size_t optionIndex = 0;
  166. uint16_t delta = 0;
  167. const uint8_t *p = buf + 4 + hdr->tkl;
  168. const uint8_t *end = buf + buflen;
  169. int rc;
  170. if (p > end)
  171. return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds
  172. //coap_dump(p, end - p);
  173. // 0xFF is payload marker
  174. while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF))
  175. {
  176. if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p)))
  177. return rc;
  178. optionIndex++;
  179. }
  180. *numOptions = optionIndex;
  181. if (p+1 < end && *p == 0xFF) // payload marker
  182. {
  183. payload->p = p+1;
  184. payload->len = end-(p+1);
  185. }
  186. else
  187. {
  188. payload->p = NULL;
  189. payload->len = 0;
  190. }
  191. return 0;
  192. }
  193. int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen)
  194. {
  195. int n = 0;
  196. uint8_t *p = buf;
  197. uint8_t len, delta = 0;
  198. if (buflen < 5)
  199. return COAP_ERR_BUFFER_TOO_SMALL;
  200. coap_option_nibble(optDelta, &delta);
  201. coap_option_nibble(length, &len);
  202. *p++ = (0xFF & (delta << 4 | len));
  203. n++;
  204. if (delta == 13)
  205. {
  206. *p++ = (optDelta - 13);
  207. n++;
  208. }
  209. else
  210. if (delta == 14)
  211. {
  212. *p++ = ((optDelta-269) >> 8);
  213. *p++ = (0xFF & (optDelta-269));
  214. n+=2;
  215. }
  216. if (len == 13)
  217. {
  218. *p++ = (length - 13);
  219. n++;
  220. }
  221. else
  222. if (len == 14)
  223. {
  224. *p++ = (length >> 8);
  225. *p++ = (0xFF & (length-269));
  226. n+=2;
  227. }
  228. return n;
  229. }
  230. #ifdef COAP_DEBUG
  231. void coap_dumpOptions(coap_option_t *opts, size_t numopt)
  232. {
  233. size_t i;
  234. printf(" Options:\n");
  235. for (i=0;i<numopt;i++)
  236. {
  237. printf(" 0x%02X [ ", opts[i].num);
  238. coap_dump(opts[i].buf.p, opts[i].buf.len, true);
  239. printf(" ]\n");
  240. }
  241. }
  242. void coap_dumpPacket(coap_packet_t *pkt)
  243. {
  244. coap_dumpHeader(&pkt->hdr);
  245. coap_dumpOptions(pkt->opts, pkt->numopts);
  246. printf("Payload: ");
  247. coap_dump(pkt->payload.p, pkt->payload.len, true);
  248. printf("\n");
  249. }
  250. #endif
  251. int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
  252. {
  253. int rc;
  254. // coap_dump(buf, buflen, false);
  255. if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen)))
  256. return rc;
  257. // coap_dumpHeader(&hdr);
  258. if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen)))
  259. return rc;
  260. pkt->numopts = MAXOPT;
  261. if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen)))
  262. return rc;
  263. // coap_dumpOptions(opts, numopt);
  264. return 0;
  265. }
  266. // options are always stored consecutively, so can return a block with same option num
  267. const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count)
  268. {
  269. // FIXME, options is always sorted, can find faster than this
  270. size_t i;
  271. const coap_option_t *first = NULL;
  272. *count = 0;
  273. for (i=0;i<pkt->numopts;i++)
  274. {
  275. if (pkt->opts[i].num == num)
  276. {
  277. if (NULL == first)
  278. first = &pkt->opts[i];
  279. (*count)++;
  280. }
  281. else
  282. {
  283. if (NULL != first)
  284. break;
  285. }
  286. }
  287. return first;
  288. }
  289. int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf)
  290. {
  291. if (buf->len+1 > strbuflen)
  292. return COAP_ERR_BUFFER_TOO_SMALL;
  293. memcpy(strbuf, buf->p, buf->len);
  294. strbuf[buf->len] = 0;
  295. return 0;
  296. }
  297. int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
  298. {
  299. size_t opts_len = 0, hdr_len = 0, tok_len = 0;
  300. size_t i;
  301. uint8_t *p = buf;
  302. size_t left = *buflen;
  303. uint16_t running_delta = 0;
  304. hdr_len = coap_buildHeader(&(pkt->hdr), buf, *buflen);
  305. p += hdr_len;
  306. left -= hdr_len;
  307. tok_len = coap_buildToken(&(pkt->tok), &(pkt->hdr), buf, *buflen);
  308. p += tok_len;
  309. left -= tok_len;
  310. for (i=0;i<pkt->numopts;i++)
  311. {
  312. uint8_t len, delta = 0;
  313. uint16_t optDelta = 0;
  314. int rc = 0;
  315. if (((size_t)(p-buf)) > *buflen)
  316. return COAP_ERR_BUFFER_TOO_SMALL;
  317. optDelta = pkt->opts[i].num - running_delta;
  318. rc = coap_buildOptionHeader(optDelta, pkt->opts[i].buf.len, p, left);
  319. p += rc;
  320. left -= rc;
  321. memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len);
  322. p += pkt->opts[i].buf.len;
  323. left -= pkt->opts[i].buf.len;
  324. running_delta = pkt->opts[i].num;
  325. }
  326. opts_len = (p - buf) - 4; // number of bytes used by options
  327. if (pkt->payload.len > 0)
  328. {
  329. if (*buflen < 4 + 1 + pkt->payload.len + opts_len)
  330. return COAP_ERR_BUFFER_TOO_SMALL;
  331. buf[4 + opts_len] = 0xFF; // payload marker
  332. memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len);
  333. *buflen = opts_len + 5 + pkt->payload.len;
  334. }
  335. else
  336. *buflen = opts_len + 4;
  337. return 0;
  338. }
  339. void coap_option_nibble(uint32_t value, uint8_t *nibble)
  340. {
  341. if (value<13)
  342. {
  343. *nibble = (0xFF & value);
  344. }
  345. else
  346. if (value<=0xFF+13)
  347. {
  348. *nibble = 13;
  349. } else if (value<=0xFFFF+269)
  350. {
  351. *nibble = 14;
  352. }
  353. }
  354. int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type)
  355. {
  356. pkt->hdr.ver = 0x01;
  357. pkt->hdr.t = COAP_TYPE_ACK;
  358. pkt->hdr.tkl = 0;
  359. pkt->hdr.code = rspcode;
  360. pkt->hdr.id[0] = msgid_hi;
  361. pkt->hdr.id[1] = msgid_lo;
  362. pkt->numopts = 1;
  363. // need token in response
  364. if (tok) {
  365. pkt->hdr.tkl = tok->len;
  366. pkt->tok = *tok;
  367. }
  368. // safe because 1 < MAXOPT
  369. pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT;
  370. pkt->opts[0].buf.p = scratch->p;
  371. if (scratch->len < 2)
  372. return COAP_ERR_BUFFER_TOO_SMALL;
  373. scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8;
  374. scratch->p[1] = ((uint16_t)content_type & 0x00FF);
  375. pkt->opts[0].buf.len = 2;
  376. pkt->payload.p = content;
  377. pkt->payload.len = content_len;
  378. return 0;
  379. }
  380. unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) {
  381. unsigned int n, i;
  382. for (n = 0, i = val; i && n < sizeof(val); ++n)
  383. i >>= 8;
  384. i = n;
  385. while (i--) {
  386. buf[i] = val & 0xff;
  387. val >>= 8;
  388. }
  389. return n;
  390. }
  391. static uint8_t _token_data[4] = {'n','o','d','e'};
  392. coap_buffer_t the_token = { _token_data, 4 };
  393. static unsigned short message_id;
  394. int coap_make_request(coap_rw_buffer_t *scratch, coap_packet_t *pkt, coap_msgtype_t t, coap_method_t m, coap_uri_t *uri, const uint8_t *payload, size_t payload_len)
  395. {
  396. int res;
  397. pkt->hdr.ver = 0x01;
  398. pkt->hdr.t = t;
  399. pkt->hdr.tkl = 0;
  400. pkt->hdr.code = m;
  401. pkt->hdr.id[0] = (message_id >> 8) & 0xFF; //msgid_hi;
  402. pkt->hdr.id[1] = message_id & 0xFF; //msgid_lo;
  403. message_id++;
  404. NODE_DBG("message_id: %d.\n", message_id);
  405. pkt->numopts = 0;
  406. if (the_token.len) {
  407. pkt->hdr.tkl = the_token.len;
  408. pkt->tok = the_token;
  409. }
  410. if (scratch->len < 2) // TBD...
  411. return COAP_ERR_BUFFER_TOO_SMALL;
  412. uint8_t *saved = scratch->p;
  413. /* split arg into Uri-* options */
  414. // const char *addr = uri->host.s;
  415. // if(uri->host.length && (strlen(addr) != uri->host.length || memcmp(addr, uri->host.s, uri->host.length) != 0)){
  416. if(uri->host.length){
  417. /* add Uri-Host */
  418. // addr is destination address
  419. pkt->opts[pkt->numopts].num = COAP_OPTION_URI_HOST;
  420. pkt->opts[pkt->numopts].buf.p = uri->host.s;
  421. pkt->opts[pkt->numopts].buf.len = uri->host.length;
  422. pkt->numopts++;
  423. }
  424. if (uri->port != COAP_DEFAULT_PORT) {
  425. pkt->opts[pkt->numopts].num = COAP_OPTION_URI_PORT;
  426. res = coap_encode_var_bytes(scratch->p, uri->port);
  427. pkt->opts[pkt->numopts].buf.len = res;
  428. pkt->opts[pkt->numopts].buf.p = scratch->p;
  429. scratch->p += res;
  430. scratch->len -= res;
  431. pkt->numopts++;
  432. }
  433. if (uri->path.length) {
  434. res = coap_split_path(scratch, pkt, uri->path.s, uri->path.length);
  435. }
  436. if (uri->query.length) {
  437. res = coap_split_query(scratch, pkt, uri->query.s, uri->query.length);
  438. }
  439. pkt->payload.p = payload;
  440. pkt->payload.len = payload_len;
  441. scratch->p = saved; // save back the pointer.
  442. return 0;
  443. }
  444. // FIXME, if this looked in the table at the path before the method then
  445. // it could more easily return 405 errors
  446. int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt)
  447. {
  448. const coap_option_t *opt;
  449. int i;
  450. uint8_t count;
  451. const coap_endpoint_t *ep = endpoints;
  452. while(NULL != ep->handler)
  453. {
  454. if (ep->method != inpkt->hdr.code)
  455. goto next;
  456. if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
  457. {
  458. // if (count != ep->path->count)
  459. if ((count != ep->path->count ) && (count != ep->path->count + 1)) // +1 for /f/[function], /v/[variable]
  460. goto next;
  461. for (i=0;i<ep->path->count;i++)
  462. {
  463. if (opt[i].buf.len != strlen(ep->path->elems[i]))
  464. goto next;
  465. if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len))
  466. goto next;
  467. }
  468. // pre-path match!
  469. if (count==ep->path->count+1 && ep->user_entry == NULL)
  470. goto next;
  471. return ep->handler(ep, scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]);
  472. }
  473. next:
  474. ep++;
  475. }
  476. coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
  477. return 0;
  478. }
  479. void coap_setup(void)
  480. {
  481. message_id = (unsigned short)os_random(); // calculate only once
  482. }
  483. int
  484. check_token(coap_packet_t *pkt) {
  485. return pkt->tok.len == the_token.len && memcmp(pkt->tok.p, the_token.p, the_token.len) == 0;
  486. }