libcoap  4.3.0beta
pdu.c
Go to the documentation of this file.
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_internal.h"
10 
11 #if defined(HAVE_LIMITS_H)
12 #include <limits.h>
13 #endif
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
21 #ifdef HAVE_WINSOCK2_H
22 #include <winsock2.h>
23 #endif
24 
25 #ifndef min
26 #define min(a,b) ((a) < (b) ? (a) : (b))
27 #endif
28 
29 #ifndef max
30 #define max(a,b) ((a) > (b) ? (a) : (b))
31 #endif
32 
33 void
34 coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
35  assert(pdu);
36  assert(pdu->token);
38  if (pdu->alloc_size > size)
39  pdu->alloc_size = size;
40  pdu->type = 0;
41  pdu->code = 0;
42  pdu->hdr_size = 0;
43  pdu->token_length = 0;
44  pdu->tid = 0;
45  pdu->max_opt = 0;
46  pdu->max_size = size;
47  pdu->used_size = 0;
48  pdu->data = NULL;
49 }
50 
51 #ifdef WITH_LWIP
52 coap_pdu_t *
53 coap_pdu_from_pbuf( struct pbuf *pbuf )
54 {
55  coap_pdu_t *pdu;
56 
57  if (pbuf == NULL) return NULL;
58 
59  LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
60  LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
61 
62  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t) );
63  if (!pdu) {
64  pbuf_free(pbuf);
65  return NULL;
66  }
67 
69  pdu->pbuf = pbuf;
70  pdu->token = (uint8_t *)pbuf->payload + pdu->max_hdr_size;
71  pdu->alloc_size = pbuf->tot_len - pdu->max_hdr_size;
72  coap_pdu_clear(pdu, pdu->alloc_size);
73 
74  return pdu;
75 }
76 #endif
77 
78 coap_pdu_t *
79 coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size) {
80  coap_pdu_t *pdu;
81 
82  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
83  if (!pdu) return NULL;
84 
85 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
86  assert(size <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4);
87  if (size > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
88  return NULL;
90 #else
92 #endif
93 
94 #ifdef WITH_LWIP
95  pdu->pbuf = pbuf_alloc(PBUF_TRANSPORT, size + pdu->max_hdr_size, PBUF_RAM);
96  if (pdu->pbuf == NULL) {
98  return NULL;
99  }
100  pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
101 #else /* WITH_LWIP */
102  uint8_t *buf;
103  pdu->alloc_size = min(size, 256);
105  if (buf == NULL) {
106  coap_free_type(COAP_PDU, pdu);
107  return NULL;
108  }
109  pdu->token = buf + pdu->max_hdr_size;
110 #endif /* WITH_LWIP */
111  coap_pdu_clear(pdu, size);
112  pdu->tid = tid;
113  pdu->type = type;
114  pdu->code = code;
115  return pdu;
116 }
117 
118 coap_pdu_t *
119 coap_new_pdu(const struct coap_session_t *session) {
120  coap_pdu_t *pdu = coap_pdu_init(0, 0, 0, coap_session_max_pdu_size(session));
121  if (!pdu)
122  coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
123  return pdu;
124 }
125 
126 void
128  if (pdu != NULL) {
129 #ifdef WITH_LWIP
130  pbuf_free(pdu->pbuf);
131 #else
132  if (pdu->token != NULL)
134 #endif
135  coap_free_type(COAP_PDU, pdu);
136  }
137 }
138 
139 int
140 coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
141  if (new_size > pdu->alloc_size) {
142 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
143  uint8_t *new_hdr;
144  size_t offset;
145 #endif
146  if (pdu->max_size && new_size > pdu->max_size) {
147  coap_log(LOG_WARNING, "coap_pdu_resize: pdu too big\n");
148  return 0;
149  }
150 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
151  if (pdu->data != NULL) {
152  assert(pdu->data > pdu->token);
153  offset = pdu->data - pdu->token;
154  } else {
155  offset = 0;
156  }
157  new_hdr = (uint8_t*)realloc(pdu->token - pdu->max_hdr_size, new_size + pdu->max_hdr_size);
158  if (new_hdr == NULL) {
159  coap_log(LOG_WARNING, "coap_pdu_resize: realloc failed\n");
160  return 0;
161  }
162  pdu->token = new_hdr + pdu->max_hdr_size;
163  if (offset > 0)
164  pdu->data = pdu->token + offset;
165  else
166  pdu->data = NULL;
167 #endif
168  }
169  pdu->alloc_size = new_size;
170  return 1;
171 }
172 
173 int
174 coap_pdu_check_resize(coap_pdu_t *pdu, size_t size) {
175  if (size > pdu->alloc_size) {
176  size_t new_size = max(256, pdu->alloc_size * 2);
177  while (size > new_size)
178  new_size *= 2;
179  if (pdu->max_size && new_size > pdu->max_size) {
180  new_size = pdu->max_size;
181  if (new_size < size)
182  return 0;
183  }
184  if (!coap_pdu_resize(pdu, new_size))
185  return 0;
186  }
187  return 1;
188 }
189 
190 int
191 coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
192  /* must allow for pdu == NULL as callers may rely on this */
193  if (!pdu || len > 8)
194  return 0;
195 
196  if (pdu->used_size) {
198  "coap_add_token: The token must defined first. Token ignored\n");
199  return 0;
200  }
201  if (!coap_pdu_check_resize(pdu, len))
202  return 0;
203  pdu->token_length = (uint8_t)len;
204  if (len)
205  memcpy(pdu->token, data, len);
206  pdu->max_opt = 0;
207  pdu->used_size = len;
208  pdu->data = NULL;
209 
210  return 1;
211 }
212 
213 size_t
214 coap_insert_option(coap_pdu_t *pdu, uint16_t type, size_t len,
215  const uint8_t *data) {
216  coap_opt_iterator_t opt_iter;
217  coap_opt_t *option;
218  uint16_t prev_type = 0;
219  size_t shift;
220  size_t opt_delta;
221  coap_option_t decode;
222  size_t shrink = 0;
223 
224  if (type >= pdu->max_opt)
225  return coap_add_option(pdu, type, len, data);
226 
227  /* Need to locate where in current options to insert this one */
228  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
229  while ((option = coap_option_next(&opt_iter))) {
230  if (opt_iter.type > type) {
231  /* Found where to insert */
232  break;
233  }
234  prev_type = opt_iter.type;
235  }
236  assert(option != NULL);
237  /* size of option inc header to insert */
238  shift = coap_opt_encode_size(type - prev_type, len);
239 
240  /* size of next option (header may shrink in size as delta changes */
241  if (!coap_opt_parse(option, opt_iter.length + 5, &decode))
242  return 0;
243  opt_delta = opt_iter.type - type;
244 
245  if (!coap_pdu_check_resize(pdu,
246  pdu->used_size + shift - shrink))
247  return 0;
248 
249  /* Possible a re-size took place with a realloc() */
250  /* Need to locate where in current options to insert this one */
251  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
252  while ((option = coap_option_next(&opt_iter))) {
253  if (opt_iter.type > type) {
254  /* Found where to insert */
255  break;
256  }
257  }
258  assert(option != NULL);
259 
260  if (decode.delta <= 12) {
261  /* can simply patch in the new delta of next option */
262  option[0] = (option[0] & 0x0f) + (opt_delta << 4);
263  }
264  else if (decode.delta <= 269 && opt_delta <= 12) {
265  /* option header is going to shrink by one byte */
266  option[1] = (option[0] & 0x0f) + (opt_delta << 4);
267  shrink = 1;
268  }
269  else if (decode.delta <= 269 && opt_delta <= 269) {
270  /* can simply patch in the new delta of next option */
271  option[1] = opt_delta - 13;
272  }
273  else if (opt_delta <= 12) {
274  /* option header is going to shrink by two bytes */
275  option[2] = (option[0] & 0x0f) + (opt_delta << 4);
276  shrink = 2;
277  }
278  else if (opt_delta <= 269) {
279  /* option header is going to shrink by one bytes */
280  option[1] = (option[0] & 0x0f) + 0xd0;
281  option[2] = opt_delta - 13;
282  shrink = 1;
283  }
284  else {
285  /* can simply patch in the new delta of next option */
286  option[1] = (opt_delta - 269) >> 8;
287  option[2] = (opt_delta - 269) & 0xff;
288  }
289 
290  memmove(&option[shift], &option[shrink],
291  pdu->used_size - (option - pdu->token) - shrink);
292  if (!coap_opt_encode(option, pdu->alloc_size - pdu->used_size,
293  type - prev_type, data, len))
294  return 0;
295 
296  pdu->used_size += shift - shrink;
297  if (pdu->data)
298  pdu->data += shift - shrink;
299  return shift;
300 }
301 
302 int
303 coap_update_option(coap_pdu_t *pdu, uint16_t type, size_t len,
304  const uint8_t *data) {
305  coap_opt_iterator_t opt_iter;
306  coap_opt_t *option;
307  coap_option_t decode;
308  size_t new_length = 0;
309  size_t old_length = 0;
310 
311  option = coap_check_option(pdu, type, &opt_iter);
312  if (!option)
313  return coap_insert_option(pdu, type, len, data);
314 
315  old_length = coap_opt_parse(option, (size_t)-1, &decode);
316  if (old_length == 0)
317  return 0;
318  new_length = coap_opt_encode_size(decode.delta, len);
319 
320  if (new_length > old_length) {
321  if (!coap_pdu_check_resize(pdu,
322  pdu->used_size + new_length - old_length))
323  return 0;
324  /* Possible a re-size took place with a realloc() */
325  option = coap_check_option(pdu, type, &opt_iter);
326  }
327 
328  if (new_length != old_length)
329  memmove(&option[new_length], &option[old_length],
330  pdu->used_size - (option - pdu->token) - old_length);
331 
332  if (!coap_opt_encode(option, new_length,
333  decode.delta, data, len))
334  return 0;
335 
336  pdu->used_size += new_length - old_length;
337  if (pdu->data)
338  pdu->data += new_length - old_length;
339  return 1;
340 }
341 
342 /* FIXME: de-duplicate code with coap_add_option_later */
343 size_t
344 coap_add_option(coap_pdu_t *pdu, uint16_t type, size_t len,
345  const uint8_t *data) {
346  size_t optsize;
347  coap_opt_t *opt;
348 
349  assert(pdu);
350  pdu->data = NULL;
351 
352  if (type == pdu->max_opt) {
353  /* Validate that the option is repeatable */
354  switch (type) {
355  /* Ignore list of genuine repeatable */
357  case COAP_OPTION_ETAG:
362  break;
363  default:
364  coap_log(LOG_INFO, "Option %d is not defined as repeatable\n", type);
365  /* Accepting it after warning as there may be user defineable options */
366  break;
367  }
368  }
369 
370  if (COAP_PDU_IS_REQUEST(pdu) &&
371  (type == COAP_OPTION_PROXY_URI || type == COAP_OPTION_PROXY_SCHEME)) {
372  /*
373  * Need to check whether there is a hop-limit option. If not, it needs
374  * to be inserted by default (RFC 8768).
375  */
376  coap_opt_iterator_t opt_iter;
377 
378  if (coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter) == NULL) {
379  size_t hop_limit = COAP_OPTION_HOP_LIMIT;
380 
381  coap_insert_option(pdu, COAP_OPTION_HOP_LIMIT, 1, (uint8_t *)&hop_limit);
382  }
383  }
384 
385  if (type < pdu->max_opt) {
387  "coap_add_option: options are not in correct order\n");
388  return coap_insert_option(pdu, type, len, data);
389  }
390 
391  if (!coap_pdu_check_resize(pdu,
392  pdu->used_size + coap_opt_encode_size(type - pdu->max_opt, len)))
393  return 0;
394 
395  opt = pdu->token + pdu->used_size;
396 
397  /* encode option and check length */
398  optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
399  type - pdu->max_opt, data, len);
400 
401  if (!optsize) {
402  coap_log(LOG_WARNING, "coap_add_option: cannot add option\n");
403  /* error */
404  return 0;
405  } else {
406  pdu->max_opt = type;
407  pdu->used_size += optsize;
408  }
409 
410  return optsize;
411 }
412 
413 int
414 coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
415  if (len == 0) {
416  return 1;
417  } else {
418  uint8_t *payload = coap_add_data_after(pdu, len);
419  if (payload != NULL)
420  memcpy(payload, data, len);
421  return payload != NULL;
422  }
423 }
424 
425 uint8_t *
426 coap_add_data_after(coap_pdu_t *pdu, size_t len) {
427  assert(pdu);
428  assert(pdu->data == NULL);
429 
430  pdu->data = NULL;
431 
432  if (len == 0)
433  return NULL;
434 
435  if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
436  return 0;
437  pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
438  pdu->data = pdu->token + pdu->used_size;
439  pdu->used_size += len;
440  return pdu->data;
441 }
442 
443 int
444 coap_get_data(const coap_pdu_t *pdu, size_t *len, uint8_t **data) {
445  assert(pdu);
446  assert(len);
447  assert(data);
448 
449  *data = pdu->data;
450  if(pdu->data == NULL) {
451  *len = 0;
452  return 0;
453  }
454 
455  *len = pdu->used_size - (pdu->data - pdu->token);
456 
457  return 1;
458 }
459 
460 #ifndef SHORT_ERROR_RESPONSE
461 typedef struct {
462  unsigned char code;
463  const char *phrase;
464 } error_desc_t;
465 
466 /* if you change anything here, make sure, that the longest string does not
467  * exceed COAP_ERROR_PHRASE_LENGTH. */
469  { COAP_RESPONSE_CODE(201), "Created" },
470  { COAP_RESPONSE_CODE(202), "Deleted" },
471  { COAP_RESPONSE_CODE(203), "Valid" },
472  { COAP_RESPONSE_CODE(204), "Changed" },
473  { COAP_RESPONSE_CODE(205), "Content" },
474  { COAP_RESPONSE_CODE(231), "Continue" },
475  { COAP_RESPONSE_CODE(400), "Bad Request" },
476  { COAP_RESPONSE_CODE(401), "Unauthorized" },
477  { COAP_RESPONSE_CODE(402), "Bad Option" },
478  { COAP_RESPONSE_CODE(403), "Forbidden" },
479  { COAP_RESPONSE_CODE(404), "Not Found" },
480  { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
481  { COAP_RESPONSE_CODE(406), "Not Acceptable" },
482  { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
483  { COAP_RESPONSE_CODE(412), "Precondition Failed" },
484  { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
485  { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
486  { COAP_RESPONSE_CODE(500), "Internal Server Error" },
487  { COAP_RESPONSE_CODE(501), "Not Implemented" },
488  { COAP_RESPONSE_CODE(502), "Bad Gateway" },
489  { COAP_RESPONSE_CODE(503), "Service Unavailable" },
490  { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
491  { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
492  { COAP_RESPONSE_CODE(508), "Hop Limit Reached" },
493  { 0, NULL } /* end marker */
494 };
495 
496 const char *
497 coap_response_phrase(unsigned char code) {
498  int i;
499  for (i = 0; coap_error[i].code; ++i) {
500  if (coap_error[i].code == code)
501  return coap_error[i].phrase;
502  }
503  return NULL;
504 }
505 #endif
506 
512 static size_t
513 next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt) {
514  coap_option_t option;
515  size_t optsize;
516 
517  assert(optp); assert(*optp);
518  assert(length);
519 
520  optsize = coap_opt_parse(*optp, *length, &option);
521  if (optsize) {
522  assert(optsize <= *length);
523 
524  /* signal an error if this option would exceed the
525  * allowed number space */
526  if (*max_opt + option.delta > COAP_MAX_OPT) {
527  return 0;
528  }
529  *max_opt += option.delta;
530  *optp += optsize;
531  *length -= optsize;
532  }
533 
534  return optsize;
535 }
536 
537 size_t
539  const uint8_t *data) {
540  assert(data);
541  size_t header_size = 0;
542 
543  if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
544  uint8_t len = *data >> 4;
545  if (len < 13)
546  header_size = 2;
547  else if (len==13)
548  header_size = 3;
549  else if (len==14)
550  header_size = 4;
551  else
552  header_size = 6;
553  } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
554  header_size = 4;
555  }
556 
557  return header_size;
558 }
559 
560 size_t
562  const uint8_t *data,
563  size_t length) {
564  assert(data);
565  assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS);
566  assert(coap_pdu_parse_header_size(proto, data) <= length );
567 
568  size_t size = 0;
569 
570  if ((proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) && length >= 1) {
571  uint8_t len = *data >> 4;
572  if (len < 13) {
573  size = len;
574  } else if (length >= 2) {
575  if (len==13) {
576  size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
577  } else if (length >= 3) {
578  if (len==14) {
579  size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
580  } else if (length >= 5) {
581  size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
582  + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
583  }
584  }
585  }
586  size += data[0] & 0x0f;
587  }
588 
589  return size;
590 }
591 
592 int
594  uint8_t *hdr = pdu->token - pdu->hdr_size;
595  if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
596  assert(pdu->hdr_size == 4);
597  if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
598  coap_log(LOG_DEBUG, "coap_pdu_parse: UDP version not supported\n");
599  return 0;
600  }
601  pdu->type = (hdr[0] >> 4) & 0x03;
602  pdu->token_length = hdr[0] & 0x0f;
603  pdu->code = hdr[1];
604  pdu->tid = (uint16_t)hdr[2] << 8 | hdr[3];
605  } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
606  assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
607  pdu->type = COAP_MESSAGE_CON;
608  pdu->token_length = hdr[0] & 0x0f;
609  pdu->code = hdr[pdu->hdr_size-1];
610  pdu->tid = 0;
611  } else {
612  coap_log(LOG_DEBUG, "coap_pdu_parse: unsupported protocol\n");
613  return 0;
614  }
615  if (pdu->token_length > pdu->alloc_size) {
616  /* Invalid PDU provided - not wise to assert here though */
617  coap_log(LOG_DEBUG, "coap_pdu_parse: PDU header token size broken\n");
618  pdu->token_length = (uint8_t)pdu->alloc_size;
619  return 0;
620  }
621  return 1;
622 }
623 
624 static int
625 coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len) {
626  switch (pdu->code) {
627  case COAP_SIGNALING_CSM:
628  switch (pdu->max_opt) {
630  if (len > 4) goto bad;
631  break;
633  if (len > 0) goto bad;
634  break;
635  default:
636  ;
637  }
638  break;
639  case COAP_SIGNALING_PING:
640  case COAP_SIGNALING_PONG:
641  switch (pdu->max_opt) {
643  if (len > 0) goto bad;
644  break;
645  default:
646  ;
647  }
648  break;
650  switch (pdu->max_opt) {
652  if (len < 1 || len > 255) goto bad;
653  break;
655  if (len > 3) goto bad;
656  break;
657  default:
658  ;
659  }
660  break;
662  switch (pdu->max_opt) {
664  if (len > 2) goto bad;
665  break;
666  default:
667  ;
668  }
669  break;
670  default:
671  ;
672  }
673  return 1;
674 bad:
675  return 0;
676 }
677 
678 int
680 
681  int good = 1;
682  /* sanity checks */
683  if (pdu->code == 0) {
684  if (pdu->used_size != 0 || pdu->token_length) {
685  coap_log(LOG_DEBUG, "coap_pdu_parse: empty message is not empty\n");
686  return 0;
687  }
688  }
689 
690  if (pdu->token_length > pdu->used_size || pdu->token_length > 8) {
691  coap_log(LOG_DEBUG, "coap_pdu_parse: invalid Token\n");
692  return 0;
693  }
694 
695  pdu->max_opt = 0;
696  if (pdu->code == 0) {
697  /* empty packet */
698  pdu->used_size = 0;
699  pdu->data = NULL;
700  } else {
701  /* skip header + token */
702  coap_opt_t *opt = pdu->token + pdu->token_length;
703  size_t length = pdu->used_size - pdu->token_length;
704 
705  while (length > 0 && *opt != COAP_PAYLOAD_START) {
706  size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
707  const uint32_t len =
708  optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
709  if (optsize == 0) {
710  coap_log(LOG_DEBUG, "coap_pdu_parse: malformed option\n");
711  return 0;
712  }
713  if (COAP_PDU_IS_SIGNALING(pdu)) {
714  if (!coap_pdu_parse_opt_csm(pdu, len))
715  goto bad;
716  continue;
717  }
718  switch (pdu->max_opt) {
719  case COAP_OPTION_IF_MATCH: if (len > 8) goto bad; break;
720  case COAP_OPTION_URI_HOST: if (len < 1 || len > 255) goto bad; break;
721  case COAP_OPTION_ETAG: if (len < 1 || len > 8) goto bad; break;
722  case COAP_OPTION_IF_NONE_MATCH: if (len != 0) goto bad; break;
723  case COAP_OPTION_OBSERVE: if (len > 3) goto bad; break;
724  case COAP_OPTION_URI_PORT: if (len > 2) goto bad; break;
725  case COAP_OPTION_LOCATION_PATH: if (len > 255) goto bad; break;
726  case COAP_OPTION_OSCORE: if (len > 255) goto bad; break;
727  case COAP_OPTION_URI_PATH: if (len > 255) goto bad; break;
728  case COAP_OPTION_CONTENT_FORMAT:if (len > 2) goto bad; break;
729  case COAP_OPTION_MAXAGE: if (len > 4) goto bad; break;
730  case COAP_OPTION_URI_QUERY: if (len < 1 || len > 255) goto bad; break;
731  case COAP_OPTION_HOP_LIMIT: if (len < 1 || len > 1) goto bad; break;
732  case COAP_OPTION_ACCEPT: if (len > 2) goto bad; break;
733  case COAP_OPTION_LOCATION_QUERY:if (len > 255) goto bad; break;
734  case COAP_OPTION_BLOCK2: if (len > 3) goto bad; break;
735  case COAP_OPTION_BLOCK1: if (len > 3) goto bad; break;
736  case COAP_OPTION_SIZE2: if (len > 4) goto bad; break;
737  case COAP_OPTION_PROXY_URI: if (len < 1 || len > 1034) goto bad; break;
738  case COAP_OPTION_PROXY_SCHEME: if (len < 1 || len > 255) goto bad; break;
739  case COAP_OPTION_SIZE1: if (len > 4) goto bad; break;
740  case COAP_OPTION_NORESPONSE: if (len > 1) goto bad; break;
741  default:
742  ;
743  }
744  continue;
745 bad:
747  "coap_pdu_parse: %d.%02d: option %u has bad length %u\n",
748  pdu->code >> 5, pdu->code & 0x1F, pdu->max_opt, len);
749  good = 0;
750  }
751 
752  if (length > 0) {
753  assert(*opt == COAP_PAYLOAD_START);
754  opt++; length--;
755 
756  if (length == 0) {
758  "coap_pdu_parse: message ending in payload start marker\n");
759  return 0;
760  }
761  }
762  if (length > 0)
763  pdu->data = (uint8_t*)opt;
764  else
765  pdu->data = NULL;
766  }
767 
768  return good;
769 }
770 
771 int
773  const uint8_t *data,
774  size_t length,
775  coap_pdu_t *pdu)
776 {
777  size_t hdr_size;
778 
779  if (length == 0)
780  return 0;
781  hdr_size = coap_pdu_parse_header_size(proto, data);
782  if (!hdr_size || hdr_size > length)
783  return 0;
784  if (hdr_size > pdu->max_hdr_size)
785  return 0;
786  if (!coap_pdu_resize(pdu, length - hdr_size))
787  return 0;
788 #ifndef WITH_LWIP
789  memcpy(pdu->token - hdr_size, data, length);
790 #endif
791  pdu->hdr_size = (uint8_t)hdr_size;
792  pdu->used_size = length - hdr_size;
793  return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu);
794 }
795 
796 size_t
798  if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
799  assert(pdu->max_hdr_size >= 4);
800  if (pdu->max_hdr_size < 4) {
802  "coap_pdu_encode_header: not enough space for UDP-style header\n");
803  return 0;
804  }
805  pdu->token[-4] = COAP_DEFAULT_VERSION << 6
806  | pdu->type << 4
807  | pdu->token_length;
808  pdu->token[-3] = pdu->code;
809  pdu->token[-2] = (uint8_t)(pdu->tid >> 8);
810  pdu->token[-1] = (uint8_t)(pdu->tid);
811  pdu->hdr_size = 4;
812  } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
813  size_t len;
814  assert(pdu->used_size >= pdu->token_length);
815  if (pdu->used_size < pdu->token_length) {
816  coap_log(LOG_WARNING, "coap_pdu_encode_header: corrupted PDU\n");
817  return 0;
818  }
819  len = pdu->used_size - pdu->token_length;
820  if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
821  assert(pdu->max_hdr_size >= 2);
822  if (pdu->max_hdr_size < 2) {
824  "coap_pdu_encode_header: not enough space for TCP0 header\n");
825  return 0;
826  }
827  pdu->token[-2] = (uint8_t)len << 4
828  | pdu->token_length;
829  pdu->token[-1] = pdu->code;
830  pdu->hdr_size = 2;
831  } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
832  assert(pdu->max_hdr_size >= 3);
833  if (pdu->max_hdr_size < 3) {
835  "coap_pdu_encode_header: not enough space for TCP8 header\n");
836  return 0;
837  }
838  pdu->token[-3] = 13 << 4 | pdu->token_length;
839  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
840  pdu->token[-1] = pdu->code;
841  pdu->hdr_size = 3;
842  } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
843  assert(pdu->max_hdr_size >= 4);
844  if (pdu->max_hdr_size < 4) {
846  "coap_pdu_encode_header: not enough space for TCP16 header\n");
847  return 0;
848  }
849  pdu->token[-4] = 14 << 4 | pdu->token_length;
850  pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
851  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
852  pdu->token[-1] = pdu->code;
853  pdu->hdr_size = 4;
854  } else {
855  assert(pdu->max_hdr_size >= 6);
856  if (pdu->max_hdr_size < 6) {
858  "coap_pdu_encode_header: not enough space for TCP32 header\n");
859  return 0;
860  }
861  pdu->token[-6] = 15 << 4 | pdu->token_length;
862  pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
863  pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
864  pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
865  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
866  pdu->token[-1] = pdu->code;
867  pdu->hdr_size = 6;
868  }
869  } else {
870  coap_log(LOG_WARNING, "coap_pdu_encode_header: unsupported protocol\n");
871  }
872  return pdu->hdr_size;
873 }
Pulls together all the internal only header files.
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
Definition: coap_session.c:209
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_CRIT
Critical.
Definition: coap_debug.h:52
@ LOG_INFO
Information.
Definition: coap_debug.h:56
@ LOG_WARNING
Warning.
Definition: coap_debug.h:54
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:146
size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, uint16_t delta, const uint8_t *val, size_t length)
Encodes option with given delta into opt.
Definition: option.c:369
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:209
size_t coap_opt_encode_size(uint16_t delta, size_t length)
Compute storage bytes needed for an option with given delta and length.
Definition: option.c:348
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:122
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
Definition: option.c:110
coap_opt_t * coap_check_option(coap_pdu_t *pdu, uint16_t type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
Definition: option.c:196
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
@ COAP_PDU
Definition: mem.h:37
@ COAP_PDU_BUF
Definition: mem.h:38
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
Parses the option pointed to by opt into result.
Definition: option.c:35
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:25
int coap_update_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Updates existing first option of given type in the pdu with the new data.
Definition: pdu.c:303
static size_t next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt)
Advances *optp to next option if still in PDU.
Definition: pdu.c:513
int coap_pdu_check_resize(coap_pdu_t *pdu, size_t size)
Dynamically grows the size of pdu to new_size if needed.
Definition: pdu.c:174
static int coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len)
Definition: pdu.c:625
error_desc_t coap_error[]
Definition: pdu.c:468
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: pdu.c:127
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto)
Decode the protocol specific header for the specified PDU.
Definition: pdu.c:593
size_t coap_pdu_parse_header_size(coap_proto_t proto, const uint8_t *data)
Interprets data to determine the number of bytes in the header.
Definition: pdu.c:538
int coap_get_data(const coap_pdu_t *pdu, size_t *len, uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:444
coap_pdu_t * coap_pdu_init(uint8_t type, uint8_t code, uint16_t tid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition: pdu.c:79
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition: pdu.c:191
coap_pdu_t * coap_new_pdu(const struct coap_session_t *session)
Creates a new CoAP PDU.
Definition: pdu.c:119
void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
Clears any contents from pdu and resets used_size, and data pointers.
Definition: pdu.c:34
size_t coap_add_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Adds option of given type to pdu that is passed as first parameter.
Definition: pdu.c:344
int coap_pdu_parse_opt(coap_pdu_t *pdu)
Verify consistency in the given CoAP PDU structure and locate the data.
Definition: pdu.c:679
uint8_t * coap_add_data_after(coap_pdu_t *pdu, size_t len)
Adds given data to the pdu that is passed as first parameter but does not copy it.
Definition: pdu.c:426
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition: pdu.c:797
int coap_pdu_parse(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition: pdu.c:772
#define min(a, b)
Definition: pdu.c:26
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:497
size_t coap_insert_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Inserts option of given type in the pdu with the appropriate data.
Definition: pdu.c:214
size_t coap_pdu_parse_size(coap_proto_t proto, const uint8_t *data, size_t length)
Parses data to extract the message size.
Definition: pdu.c:561
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition: pdu.c:140
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:414
#define max(a, b)
Definition: pdu.c:30
#define COAP_OPTION_HOP_LIMIT
Definition: pdu.h:136
#define COAP_OPTION_NORESPONSE
Definition: pdu.h:145
#define COAP_OPTION_URI_HOST
Definition: pdu.h:123
#define COAP_OPTION_IF_MATCH
Definition: pdu.h:122
#define COAP_MESSAGE_SIZE_OFFSET_TCP8
Definition: pdu.h:38
#define COAP_OPTION_BLOCK2
Definition: pdu.h:139
#define COAP_OPTION_CONTENT_FORMAT
Definition: pdu.h:131
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition: pdu.h:194
#define COAP_OPTION_SIZE2
Definition: pdu.h:141
#define COAP_PROTO_TCP
Definition: pdu.h:346
#define COAP_OPTION_BLOCK1
Definition: pdu.h:140
#define COAP_OPTION_PROXY_SCHEME
Definition: pdu.h:143
#define COAP_SIGNALING_PONG
Definition: pdu.h:184
#define COAP_PDU_MAX_UDP_HEADER_SIZE
Definition: pdu.h:317
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:135
#define COAP_OPTION_IF_NONE_MATCH
Definition: pdu.h:125
#define COAP_OPTION_LOCATION_PATH
Definition: pdu.h:128
#define COAP_OPTION_URI_PATH
Definition: pdu.h:130
#define COAP_SIGNALING_CSM
Definition: pdu.h:182
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:155
#define COAP_PDU_MAX_TCP_HEADER_SIZE
Definition: pdu.h:318
#define COAP_PROTO_TLS
Definition: pdu.h:347
#define COAP_OPTION_OSCORE
Definition: pdu.h:129
#define COAP_MAX_MESSAGE_SIZE_TCP8
Definition: pdu.h:44
#define COAP_PDU_IS_SIGNALING(pdu)
Definition: pdu.h:315
#define COAP_OPTION_SIZE1
Definition: pdu.h:144
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition: pdu.h:190
#define COAP_MAX_MESSAGE_SIZE_TCP0
Definition: pdu.h:43
#define COAP_OPTION_LOCATION_QUERY
Definition: pdu.h:138
#define COAP_MESSAGE_SIZE_OFFSET_TCP16
Definition: pdu.h:39
uint8_t coap_proto_t
Definition: pdu.h:339
#define COAP_MESSAGE_SIZE_OFFSET_TCP32
Definition: pdu.h:40
#define COAP_SIGNALING_OPTION_CUSTODY
Definition: pdu.h:192
#define COAP_MESSAGE_CON
Definition: pdu.h:74
#define COAP_MAX_OPT
the highest option number we know
Definition: pdu.h:147
#define COAP_DEFAULT_VERSION
Definition: pdu.h:66
#define COAP_PROTO_DTLS
Definition: pdu.h:345
#define COAP_OPTION_URI_PORT
Definition: pdu.h:127
#define COAP_OPTION_ACCEPT
Definition: pdu.h:137
#define COAP_SIGNALING_RELEASE
Definition: pdu.h:185
#define COAP_PAYLOAD_START
Definition: pdu.h:257
#define COAP_OPTION_MAXAGE
Definition: pdu.h:134
#define COAP_OPTION_ETAG
Definition: pdu.h:124
#define COAP_OPTION_PROXY_URI
Definition: pdu.h:142
#define COAP_SIGNALING_PING
Definition: pdu.h:183
#define COAP_OPTION_OBSERVE
Definition: pdu.h:126
#define COAP_PDU_IS_REQUEST(pdu)
Definition: pdu.h:313
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition: pdu.h:195
#define COAP_MAX_MESSAGE_SIZE_TCP16
Definition: pdu.h:45
#define COAP_PROTO_UDP
Definition: pdu.h:344
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition: pdu.h:197
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: pdu.h:189
#define COAP_SIGNALING_ABORT
Definition: pdu.h:186
Iterator to run through PDU options.
Definition: option.h:186
uint16_t type
decoded option type
Definition: option.h:188
size_t length
remaining length of PDU
Definition: option.h:187
Representation of CoAP options.
Definition: option.h:31
uint16_t delta
Definition: option.h:32
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
uint8_t max_hdr_size
space reserved for protocol-specific header
Definition: pdu.h:290
uint8_t type
message type
Definition: pdu.h:288
uint16_t max_opt
highest option number in PDU
Definition: pdu.h:294
uint8_t * token
first byte of token, if any, or options
Definition: pdu.h:298
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
Definition: pdu.h:297
uint16_t tid
transaction id, if any, in regular host byte order
Definition: pdu.h:293
uint8_t code
request method (value 1–31) or response code (value 64-255)
Definition: pdu.h:289
uint8_t token_length
length of Token
Definition: pdu.h:292
uint8_t hdr_size
actual size used for protocol-specific header
Definition: pdu.h:291
uint8_t * data
first byte of payload, if any
Definition: pdu.h:299
size_t used_size
used bytes of storage for token, options and payload
Definition: pdu.h:296
size_t alloc_size
allocated storage for token, options and payload
Definition: pdu.h:295
unsigned char code
Definition: pdu.c:462
const char * phrase
Definition: pdu.c:463
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79