libcoap 4.3.5-develop-5010974
Loading...
Searching...
No Matches
coap_pdu.c
Go to the documentation of this file.
1/* coap_pdu.c -- CoAP PDU handling
2 *
3 * Copyright (C) 2010--2026 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
17
18#if defined(HAVE_LIMITS_H)
19#include <limits.h>
20#endif
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#ifndef __ZEPHYR__
26#ifdef HAVE_ARPA_INET_H
27#include <arpa/inet.h>
28#endif
29#ifdef HAVE_WINSOCK2_H
30#include <winsock2.h>
31#endif
32#endif /* !__ZEPHYR__ */
33
34#include <ctype.h>
35
36#ifndef min
37#define min(a,b) ((a) < (b) ? (a) : (b))
38#endif
39
40#ifndef max
41#define max(a,b) ((a) > (b) ? (a) : (b))
42#endif
43
44void
45coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
46 assert(pdu);
47 assert(pdu->token);
49 if (pdu->alloc_size > size)
50 pdu->alloc_size = size;
51 pdu->type = 0;
52 pdu->code = 0;
53 pdu->ref = 0;
54 pdu->hdr_size = 0;
55 pdu->actual_token.length = 0;
56 pdu->e_token_length = 0;
57 pdu->crit_opt = 0;
58 pdu->mid = 0;
59 pdu->max_opt = 0;
60 pdu->max_size = size;
61 pdu->used_size = 0;
62 pdu->data = NULL;
63 pdu->body_data = NULL;
64 pdu->body_length = 0;
65 pdu->body_offset = 0;
66 pdu->body_total = 0;
67 pdu->lg_xmit = NULL;
68 pdu->session = NULL;
69 pdu->data_free = NULL;
70}
71
72#ifdef WITH_LWIP
74coap_pdu_from_pbuf(struct pbuf *pbuf) {
75 coap_pdu_t *pdu;
76
77 if (pbuf == NULL)
78 return NULL;
79
80 LWIP_ASSERT("Can only deal with contiguous PBUFs (increase PBUF_POOL_BUFSIZE)",
81 pbuf->tot_len == pbuf->len);
82 LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf",
83 pbuf->ref == 1);
84
85 pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
86 if (!pdu) {
87 pbuf_free(pbuf);
88 return NULL;
89 }
90
92 pdu->pbuf = pbuf;
93 pdu->token = (uint8_t *)pbuf->payload + pdu->max_hdr_size;
94 pdu->alloc_size = pbuf->tot_len - pdu->max_hdr_size;
95 coap_pdu_clear(pdu, pdu->alloc_size);
96
97 return pdu;
98}
99#endif /* LWIP */
100
103 size_t size) {
104 coap_pdu_t *pdu;
105
106#ifndef RIOT_VERSION
107 assert(type <= 0x3);
108 assert(code <= 0xff);
109 assert(mid >= 0 && mid <= 0xffff);
110#endif /* RIOT_VERSION */
111
112#if defined(WITH_LWIP) && MEMP_USE_CUSTOM_POOLS
113#if MEMP_STATS
114 /* Reserve 1 PDU for a response packet */
115 if (memp_pools[MEMP_COAP_PDU]->stats->used + 1 >=
116 memp_pools[MEMP_COAP_PDU]->stats->avail) {
117 memp_pools[MEMP_COAP_PDU]->stats->err++;
118 return NULL;
119 }
120#endif /* MEMP_STATS */
121#endif /* LWIP && MEMP_USE_CUSTOM_POOLS */
122 pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
123 if (!pdu)
124 return NULL;
125
126#if COAP_DEFAULT_MAX_PDU_RX_SIZE <= COAP_MAX_MESSAGE_SIZE_TCP16
127 /* on TCP, the CoAP header will also have a maximum length of 4 bytes */
129#else
131#endif
132 if (size > ((size_t)COAP_DEFAULT_MAX_PDU_RX_SIZE - pdu->max_hdr_size)) {
134 return NULL;
135 }
136
137 pdu->alloc_size = min(size, COAP_DEFAULT_MTU);
138#ifdef WITH_LWIP
139 pdu->pbuf = pbuf_alloc(PBUF_TRANSPORT, pdu->alloc_size + pdu->max_hdr_size, PBUF_RAM);
140 if (pdu->pbuf == NULL) {
142 return NULL;
143 }
144 pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
145#else /* WITH_LWIP */
146 uint8_t *buf;
148 if (buf == NULL) {
150 return NULL;
151 }
152 pdu->token = buf + pdu->max_hdr_size;
153#endif /* WITH_LWIP */
154 coap_pdu_clear(pdu, size);
155 pdu->mid = mid;
156 pdu->type = type;
157 pdu->code = code;
158 return pdu;
159}
160
163 coap_session_t *session) {
164 coap_pdu_t *pdu;
165
166 coap_lock_lock(return NULL);
167 pdu = coap_new_pdu_lkd(type, code, session);
169 return pdu;
170}
171
174 coap_session_t *session) {
175 coap_pdu_t *pdu;
176
178 pdu = coap_pdu_init(type, code, coap_new_message_id_lkd(session),
180 if (!pdu)
181 coap_log_crit("coap_new_pdu: cannot allocate memory for new PDU (size = %" PRIuS ")\n",
183 return pdu;
184}
185
186COAP_API void
192
193void
195 if (pdu != NULL) {
196 if (pdu->ref) {
197 pdu->ref--;
198 return;
199 }
200#ifdef WITH_LWIP
201 pbuf_free(pdu->pbuf);
202#else
203 if (pdu->token != NULL)
205#endif
208 }
209}
210
213 coap_session_t *session,
214 size_t token_length,
215 const uint8_t *token,
216 coap_opt_filter_t *drop_options) {
217 coap_pdu_t *new_pdu;
218
219 coap_lock_lock(return NULL);
220 new_pdu = coap_pdu_duplicate_lkd(old_pdu,
221 session,
222 token_length,
223 token,
224 drop_options);
226 return new_pdu;
227}
228
229
230/*
231 * Note: This does not include any data, just the token and options
232 */
235 coap_session_t *session,
236 size_t token_length,
237 const uint8_t *token,
238 coap_opt_filter_t *drop_options) {
239#if COAP_CLIENT_SUPPORT
240 uint8_t doing_first = session->doing_first;
241#endif /* COAP_CLIENT_SUPPORT */
242 coap_pdu_t *pdu;
243
245 /*
246 * Need to make sure that coap_session_max_pdu_size_lkd() immediately
247 * returns, rather than wait for the first CSM response from remote
248 * that indicates BERT size (TCP/TLS only) as this may be called early
249 * the OSCORE logic.
250 */
251#if COAP_CLIENT_SUPPORT
252 session->doing_first = 0;
253#endif /* COAP_CLIENT_SUPPORT */
254 pdu = coap_pdu_init(old_pdu->type, old_pdu->code,
256 max(old_pdu->max_size,
258#if COAP_CLIENT_SUPPORT
259 /* Restore any pending waits */
260 session->doing_first = doing_first;
261#endif /* COAP_CLIENT_SUPPORT */
262 if (pdu == NULL)
263 return NULL;
264
265 coap_add_token(pdu, token_length, token);
266 pdu->lg_xmit = old_pdu->lg_xmit;
267
268 if (drop_options == NULL) {
269 /* Drop COAP_PAYLOAD_START as well if data */
270 size_t length = old_pdu->used_size - old_pdu->e_token_length -
271 (old_pdu->data ?
272 old_pdu->used_size - (old_pdu->data - old_pdu->token) +1 : 0);
273 if (!coap_pdu_resize(pdu, length + pdu->e_token_length))
274 goto fail;
275 /* Copy the options but not any data across */
276 memcpy(pdu->token + pdu->e_token_length,
277 old_pdu->token + old_pdu->e_token_length, length);
278 pdu->used_size += length;
279 pdu->max_opt = old_pdu->max_opt;
280 } else {
281 /* Copy across all the options the slow way */
282 coap_opt_iterator_t opt_iter;
283 coap_opt_t *option;
284
285 coap_option_iterator_init(old_pdu, &opt_iter, COAP_OPT_ALL);
286 while ((option = coap_option_next(&opt_iter))) {
287 if (drop_options && coap_option_filter_get(drop_options, opt_iter.number))
288 continue;
289 if (!coap_add_option_internal(pdu, opt_iter.number,
290 coap_opt_length(option),
291 coap_opt_value(option)))
292 goto fail;
293 }
294 }
295 return pdu;
296
297fail:
299 return NULL;
300}
301
302
303/*
304 * The new size does not include the coap header (max_hdr_size)
305 */
306int
307coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
308 if (new_size > pdu->alloc_size) {
309 /* Expanding the PDU usage */
310#if !defined(WITH_LWIP)
311 uint8_t *new_hdr;
312#else /* WITH_LWIP */
313 struct pbuf *new_hdr;
314#endif /* WITH_LWIP */
315 size_t offset;
316
317 if (pdu->max_size && new_size > pdu->max_size) {
318 coap_log_warn("coap_pdu_resize: pdu too big\n");
319 return 0;
320 }
321 if (pdu->data != NULL) {
322 assert(pdu->data > pdu->token);
323 offset = pdu->data - pdu->token;
324 } else {
325 offset = 0;
326 }
327#if !defined(WITH_LWIP)
328 new_hdr = (uint8_t *)coap_realloc_type(COAP_PDU_BUF,
329 pdu->token - pdu->max_hdr_size,
330 new_size + pdu->max_hdr_size);
331#else /* WITH_LWIP */
332 new_hdr = pbuf_alloc(PBUF_TRANSPORT, new_size + pdu->max_hdr_size, PBUF_RAM);
333#endif /* WITH_LWIP */
334 if (new_hdr == NULL) {
335 coap_log_warn("coap_pdu_resize: realloc failed\n");
336 return 0;
337 }
338#if !defined(WITH_LWIP)
339 pdu->token = new_hdr + pdu->max_hdr_size;
340#else /* WITH_LWIP */
341 memcpy(new_hdr->payload, pdu->pbuf->payload, pdu->pbuf->len);
342 pbuf_free(pdu->pbuf);
343 pdu->pbuf = new_hdr;
344 pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
345#endif /* WITH_LWIP */
346 if (offset > 0)
347 pdu->data = pdu->token + offset;
348 else
349 pdu->data = NULL;
351 pdu->actual_token.s = &pdu->token[0];
353 pdu->actual_token.s = &pdu->token[1];
354 else
355 pdu->actual_token.s = &pdu->token[2];
356 pdu->alloc_size = new_size;
357 }
358 return 1;
359}
360
361int
363 if (size > pdu->alloc_size) {
364 size_t new_size = max(256, pdu->alloc_size * 2);
365 while (size > new_size)
366 new_size *= 2;
367 if (pdu->max_size && new_size > pdu->max_size) {
368 new_size = pdu->max_size;
369 if (new_size < size)
370 return 0;
371 }
372 if (!coap_pdu_resize(pdu, new_size))
373 return 0;
374 }
375 return 1;
376}
377
378int
379coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
380 size_t bias = 0;
381
382 /* must allow for pdu == NULL as callers may rely on this */
383 if (!pdu)
384 return 0;
385
386 if (pdu->used_size) {
387 coap_log_warn("coap_add_token: The token must defined first. Token ignored\n");
388 return 0;
389 }
390 pdu->actual_token.length = len;
391 if (len < COAP_TOKEN_EXT_1B_BIAS) {
392 bias = 0;
393 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
394 bias = 1;
395 } else if (len <= COAP_TOKEN_EXT_MAX) {
396 bias = 2;
397 } else {
398 coap_log_warn("coap_add_token: Token size too large. Token ignored\n");
399 return 0;
400 }
401 if (!coap_pdu_check_resize(pdu, len + bias)) {
402 coap_log_warn("coap_add_token: Insufficient space for token. Token ignored\n");
403 return 0;
404 }
405
406 pdu->actual_token.length = len;
407 pdu->actual_token.s = &pdu->token[bias];
408 pdu->e_token_length = (uint32_t)(len + bias);
409 if (len) {
410 switch (bias) {
411 case 0:
412 memcpy(pdu->token, data, len);
413 break;
414 case 1:
415 pdu->token[0] = (uint8_t)(len - COAP_TOKEN_EXT_1B_BIAS);
416 memcpy(&pdu->token[1], data, len);
417 break;
418 case 2:
419 pdu->token[0] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) >> 8);
420 pdu->token[1] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) & 0xff);
421 memcpy(&pdu->token[2], data, len);
422 break;
423 default:
424 break;
425 }
426 }
427 pdu->max_opt = 0;
428 pdu->used_size = len + bias;
429 pdu->data = NULL;
430
431 return 1;
432}
433
434/* It is assumed that coap_encode_var_safe8() has been called to reduce data */
435int
436coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
437 size_t bias = 0;
438 size_t old_len;
439
440 /* must allow for pdu == NULL as callers may rely on this */
441 if (!pdu)
442 return 0;
443
444 if (pdu->used_size == 0) {
445 return coap_add_token(pdu, len, data);
446 }
447
448 old_len = pdu->e_token_length;
449
450 if (len < COAP_TOKEN_EXT_1B_BIAS) {
451 bias = 0;
452 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
453 bias = 1;
454 } else if (len <= COAP_TOKEN_EXT_MAX) {
455 bias = 2;
456 } else {
457 coap_log_warn("coap_add_token: Token size too large. Token ignored\n");
458 return 0;
459 }
460 if ((len + bias) == pdu->e_token_length) {
461 /* Easy case - just data has changed */
462 } else if ((len + bias) > pdu->e_token_length) {
463 if (!coap_pdu_check_resize(pdu,
464 pdu->used_size + (len + bias) - pdu->e_token_length)) {
465 coap_log_warn("Failed to update token\n");
466 return 0;
467 }
468 memmove(&pdu->token[(len + bias) - pdu->e_token_length],
469 pdu->token, pdu->used_size);
470 pdu->used_size += len + bias - pdu->e_token_length;
471 if (pdu->data) {
472 pdu->data += (len + bias) - pdu->e_token_length;
473 }
474 } else {
475 pdu->used_size -= pdu->e_token_length - (len + bias);
476 memmove(pdu->token, &pdu->token[pdu->e_token_length - (len + bias)], pdu->used_size);
477 if (pdu->data) {
478 pdu->data -= pdu->e_token_length - (len + bias);
479 }
480 }
481
482 pdu->actual_token.length = len;
483 pdu->actual_token.s = &pdu->token[bias];
484 pdu->e_token_length = (uint8_t)(len + bias);
485 if (len) {
486 switch (bias) {
487 case 0:
488 if (memcmp(pdu->token, data, len) != 0)
489 memcpy(pdu->token, data, len);
490 break;
491 case 1:
492 pdu->token[0] = (uint8_t)(len - COAP_TOKEN_EXT_1B_BIAS);
493 memcpy(&pdu->token[1], data, len);
494 break;
495 case 2:
496 pdu->token[0] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) >> 8);
497 pdu->token[1] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) & 0xff);
498 memcpy(&pdu->token[2], data, len);
499 break;
500 default:
501 break;
502 }
503 }
504 if (old_len != pdu->e_token_length && pdu->hdr_size && pdu->session)
505 /* Need to fix up the header */
506 if (!coap_pdu_encode_header(pdu, pdu->session->proto))
507 return 0;
508 return 1;
509}
510
511int
513 coap_opt_iterator_t opt_iter;
514 coap_opt_t *option;
515 coap_opt_t *next_option = NULL;
516 size_t opt_delta;
517 coap_option_t decode_this;
518 coap_option_t decode_next;
519
520 /* Need to locate where in current options to remove this one */
522 while ((option = coap_option_next(&opt_iter))) {
523 if (opt_iter.number == number) {
524 /* Found option to delete */
525 break;
526 }
527 }
528 if (!option)
529 return 0;
530
531 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token),
532 &decode_this))
533 return 0;
534
535 next_option = coap_option_next(&opt_iter);
536 if (next_option) {
537 if (!coap_opt_parse(next_option,
538 pdu->used_size - (next_option - pdu->token),
539 &decode_next))
540 return 0;
541 opt_delta = decode_this.delta + decode_next.delta;
542 if (opt_delta < 13) {
543 /* can simply update the delta of next option */
544 next_option[0] = (next_option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
545 } else if (opt_delta < 269 && decode_next.delta < 13) {
546 /* next option delta size increase */
547 next_option -= 1;
548 next_option[0] = (next_option[1] & 0x0f) + (13 << 4);
549 next_option[1] = (coap_opt_t)(opt_delta - 13);
550 } else if (opt_delta < 269) {
551 /* can simply update the delta of next option */
552 next_option[1] = (coap_opt_t)(opt_delta - 13);
553 } else if (decode_next.delta < 13) { /* opt_delta >= 269 */
554 /* next option delta size increase */
555 if (next_option - option < 2) {
556 /* Need to shuffle everything up by 1 before decrement */
557 if (!coap_pdu_check_resize(pdu, pdu->used_size + 1))
558 return 0;
559 /* Possible a re-size took place with a realloc() */
560 /* Need to rediscover this and next options */
562 while ((option = coap_option_next(&opt_iter))) {
563 if (opt_iter.number == number) {
564 /* Found option to delete */
565 break;
566 }
567 }
568 next_option = coap_option_next(&opt_iter);
569 assert(option != NULL);
570 assert(next_option != NULL);
571 memmove(&next_option[1], next_option,
572 pdu->used_size - (next_option - pdu->token));
573 pdu->used_size++;
574 if (pdu->data)
575 pdu->data++;
576 next_option++;
577 }
578 next_option -= 2;
579 next_option[0] = (next_option[2] & 0x0f) + (14 << 4);
580 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
581 next_option[2] = (opt_delta - 269) & 0xff;
582 } else if (decode_next.delta < 269) { /* opt_delta >= 269 */
583 /* next option delta size increase */
584 next_option -= 1;
585 next_option[0] = (next_option[1] & 0x0f) + (14 << 4);
586 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
587 next_option[2] = (opt_delta - 269) & 0xff;
588 } else { /* decode_next.delta >= 269 && opt_delta >= 269 */
589 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
590 next_option[2] = (opt_delta - 269) & 0xff;
591 }
592 } else {
593 next_option = option + coap_opt_encode_size(decode_this.delta,
594 coap_opt_length(option));
595 pdu->max_opt -= decode_this.delta;
596 }
597 if (pdu->used_size - (next_option - pdu->token))
598 memmove(option, next_option, pdu->used_size - (next_option - pdu->token));
599 pdu->used_size -= next_option - option;
600 if (pdu->data)
601 pdu->data -= next_option - option;
602 return 1;
603}
604
605int
607 /* Validate that the option is repeatable */
608 switch (number) {
609 /* Ignore list of genuine repeatable */
611 case COAP_OPTION_ETAG:
617 case COAP_OPTION_RTAG:
618 break;
619 /* Protest at the known non-repeatable options and ignore them */
637 case COAP_OPTION_ECHO:
639 coap_log_info("Option number %d is not defined as repeatable - dropped\n",
640 number);
641 return 0;
642 default:
643 coap_log_info("Option number %d is not defined as repeatable\n",
644 number);
645 /* Accepting it after warning as there may be user defineable options */
646 break;
647 }
648 return 1;
649}
650
651size_t
653 const uint8_t *data) {
654 coap_opt_iterator_t opt_iter;
655 coap_opt_t *option;
656 uint16_t prev_number = 0;
657 size_t shift;
658 size_t opt_delta;
659 coap_option_t decode;
660 size_t shrink = 0;
661
662 if (number >= pdu->max_opt)
663 return coap_add_option_internal(pdu, number, len, data);
664
665 /* Need to locate where in current options to insert this one */
667 while ((option = coap_option_next(&opt_iter))) {
668 if (opt_iter.number > number) {
669 /* Found where to insert */
670 break;
671 }
672 prev_number = opt_iter.number;
673 }
674 if (option == NULL) {
675 /* Code is broken somewhere */
676 coap_log_warn("coap_insert_option: Broken max_opt\n");
677 return 0;
678 }
679
680 /* size of option inc header to insert */
681 shift = coap_opt_encode_size(number - prev_number, len);
682
683 /* size of next option (header may shrink in size as delta changes */
684 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token), &decode))
685 return 0;
686 opt_delta = opt_iter.number - number;
687 if (opt_delta == 0) {
688 if (!coap_option_check_repeatable(number))
689 return 0;
690 }
691
692 if (!coap_pdu_check_resize(pdu,
693 pdu->used_size + shift - shrink))
694 return 0;
695
696 /* Possible a re-size took place with a realloc() */
697 /* Need to locate where in current options to insert this one */
699 while ((option = coap_option_next(&opt_iter))) {
700 if (opt_iter.number > number) {
701 /* Found where to insert */
702 break;
703 }
704 }
705 assert(option != NULL);
706
707 if (decode.delta < 13) {
708 /* can simply patch in the new delta of next option */
709 option[0] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
710 } else if (decode.delta < 269 && opt_delta < 13) {
711 /* option header is going to shrink by one byte */
712 option[1] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
713 shrink = 1;
714 } else if (decode.delta < 269 && opt_delta < 269) {
715 /* can simply patch in the new delta of next option */
716 option[1] = (coap_opt_t)(opt_delta - 13);
717 } else if (opt_delta < 13) {
718 /* option header is going to shrink by two bytes */
719 option[2] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
720 shrink = 2;
721 } else if (opt_delta < 269) {
722 /* option header is going to shrink by one bytes */
723 option[1] = (option[0] & 0x0f) + 0xd0;
724 option[2] = (coap_opt_t)(opt_delta - 13);
725 shrink = 1;
726 } else {
727 /* can simply patch in the new delta of next option */
728 option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
729 option[2] = (opt_delta - 269) & 0xff;
730 }
731
732 memmove(&option[shift], &option[shrink],
733 pdu->used_size - (option - pdu->token) - shrink);
734 if (!coap_opt_encode(option, pdu->alloc_size - pdu->used_size,
735 number - prev_number, data, len))
736 return 0;
737
738 if (shift >= shrink) {
739 pdu->used_size += shift - shrink;
740 if (pdu->data)
741 pdu->data += shift - shrink;
742 } else {
743 pdu->used_size -= shrink - shift;
744 if (pdu->data)
745 pdu->data -= shrink - shift;
746 }
747 return shift;
748}
749
750size_t
752 const uint8_t *data) {
753 coap_opt_iterator_t opt_iter;
754 coap_opt_t *option;
755 coap_option_t decode;
756 size_t new_length = 0;
757 size_t old_length = 0;
758
759 option = coap_check_option(pdu, number, &opt_iter);
760 if (!option)
761 return coap_insert_option(pdu, number, len, data);
762
763 old_length = coap_opt_parse(option, (size_t)-1, &decode);
764 if (old_length == 0)
765 return 0;
766 new_length = coap_opt_encode_size(decode.delta, len);
767
768 if (new_length > old_length) {
769 if (!coap_pdu_check_resize(pdu,
770 pdu->used_size + new_length - old_length))
771 return 0;
772 /* Possible a re-size took place with a realloc() */
773 option = coap_check_option(pdu, number, &opt_iter);
774 }
775
776 if (new_length != old_length)
777 memmove(&option[new_length], &option[old_length],
778 pdu->used_size - (option - pdu->token) - old_length);
779
780 if (!coap_opt_encode(option, new_length,
781 decode.delta, data, len))
782 return 0;
783
784 if (new_length >= old_length) {
785 pdu->used_size += new_length - old_length;
786 if (pdu->data)
787 pdu->data += new_length - old_length;
788 } else {
789 pdu->used_size -= old_length - new_length;
790 if (pdu->data)
791 pdu->data -= old_length - new_length;
792 }
793 return 1;
794}
795
796size_t
798 const uint8_t *data) {
799 if (pdu->data) {
800 coap_log_warn("coap_add_optlist_pdu: PDU already contains data\n");
801 return 0;
802 }
803 return coap_add_option_internal(pdu, number, len, data);
804}
805
806size_t
808 const uint8_t *data) {
809 size_t optsize;
810 coap_opt_t *opt;
811
812 assert(pdu);
813
814 if (number == pdu->max_opt) {
815 if (!coap_option_check_repeatable(number))
816 return 0;
817 }
818
819 if (COAP_PDU_IS_REQUEST(pdu) &&
820 (number == COAP_OPTION_PROXY_URI ||
821 number == COAP_OPTION_PROXY_SCHEME)) {
822 /*
823 * Need to check whether there is a hop-limit option. If not, it needs
824 * to be inserted by default (RFC 8768).
825 */
826 coap_opt_iterator_t opt_iter;
827
828 if (coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter) == NULL) {
829 size_t hop_limit = COAP_OPTION_HOP_LIMIT;
830
831 coap_insert_option(pdu, COAP_OPTION_HOP_LIMIT, 1, (uint8_t *)&hop_limit);
832 }
833 }
834
835 if (number < pdu->max_opt) {
836 coap_log_debug("coap_add_option: options are not in correct order\n");
837 return coap_insert_option(pdu, number, len, data);
838 }
839
840 optsize = coap_opt_encode_size(number - pdu->max_opt, len);
841 if (!coap_pdu_check_resize(pdu,
842 pdu->used_size + optsize))
843 return 0;
844
845 if (pdu->data) {
846 /* include option delimiter */
847 memmove(&pdu->data[optsize-1], &pdu->data[-1],
848 pdu->used_size - (pdu->data - pdu->token) + 1);
849 opt = pdu->data -1;
850 pdu->data += optsize;
851 } else {
852 opt = pdu->token + pdu->used_size;
853 }
854
855 /* encode option and check length */
856 optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
857 number - pdu->max_opt, data, len);
858
859 if (!optsize) {
860 coap_log_warn("coap_add_option: cannot add option\n");
861 /* error */
862 return 0;
863 } else {
864 pdu->max_opt = number;
865 pdu->used_size += optsize;
866 }
867
868 return optsize;
869}
870
871int
872coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
873 if (len == 0) {
874 return 1;
875 } else {
876 uint8_t *payload = coap_add_data_after(pdu, len);
877 if (payload != NULL)
878 memcpy(payload, data, len);
879 return payload != NULL;
880 }
881}
882
883uint8_t *
885 assert(pdu);
886 if (pdu->data) {
887 coap_log_warn("coap_add_data: PDU already contains data\n");
888 return 0;
889 }
890
891 if (len == 0)
892 return NULL;
893
894 if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
895 return 0;
896 pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
897 pdu->data = pdu->token + pdu->used_size;
898 pdu->used_size += len;
899 return pdu->data;
900}
901
902int
903coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data) {
904 size_t offset;
905 size_t total;
906
907 return coap_get_data_large(pdu, len, data, &offset, &total);
908}
909
910int
911coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data,
912 size_t *offset, size_t *total) {
913 assert(pdu);
914 assert(len);
915 assert(data);
916
917 *offset = pdu->body_offset;
918 *total = pdu->body_total;
919 if (pdu->body_data) {
920 *data = pdu->body_data;
921 *len = pdu->body_length;
922 return 1;
923 }
924 *data = pdu->data;
925 if (pdu->data == NULL) {
926 *len = 0;
927 *total = 0;
928 return 0;
929 }
930
931 *len = pdu->used_size - (pdu->data - pdu->token);
932 if (*total == 0)
933 *total = *len;
934
935 return 1;
936}
937
938#ifndef SHORT_ERROR_RESPONSE
939typedef struct {
940 unsigned char code;
941 const char *phrase;
943
944/* if you change anything here, make sure, that the longest string does not
945 * exceed COAP_ERROR_PHRASE_LENGTH. */
947 { COAP_RESPONSE_CODE(201), "Created" },
948 { COAP_RESPONSE_CODE(202), "Deleted" },
949 { COAP_RESPONSE_CODE(203), "Valid" },
950 { COAP_RESPONSE_CODE(204), "Changed" },
951 { COAP_RESPONSE_CODE(205), "Content" },
952 { COAP_RESPONSE_CODE(231), "Continue" },
953 { COAP_RESPONSE_CODE(400), "Bad Request" },
954 { COAP_RESPONSE_CODE(401), "Unauthorized" },
955 { COAP_RESPONSE_CODE(402), "Bad Option" },
956 { COAP_RESPONSE_CODE(403), "Forbidden" },
957 { COAP_RESPONSE_CODE(404), "Not Found" },
958 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
959 { COAP_RESPONSE_CODE(406), "Not Acceptable" },
960 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
961 { COAP_RESPONSE_CODE(409), "Conflict" },
962 { COAP_RESPONSE_CODE(412), "Precondition Failed" },
963 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
964 { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
965 { COAP_RESPONSE_CODE(422), "Unprocessable" },
966 { COAP_RESPONSE_CODE(429), "Too Many Requests" },
967 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
968 { COAP_RESPONSE_CODE(501), "Not Implemented" },
969 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
970 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
971 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
972 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
973 { COAP_RESPONSE_CODE(508), "Hop Limit Reached" },
974 { 0, NULL } /* end marker */
975};
976
977const char *
978coap_response_phrase(unsigned char code) {
979 int i;
980 for (i = 0; coap_error[i].code; ++i) {
981 if (coap_error[i].code == code)
982 return coap_error[i].phrase;
983 }
984 return NULL;
985}
986#endif
987
993static size_t
994next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt) {
995 coap_option_t option;
996 size_t optsize;
997
998 assert(optp);
999 assert(*optp);
1000 assert(length);
1001
1002 optsize = coap_opt_parse(*optp, *length, &option);
1003 assert(optsize <= *length);
1004
1005 /* signal an error if this option would exceed the
1006 * allowed number space */
1007 if ((uint32_t)(*max_opt) + option.delta > COAP_MAX_OPT) {
1008 return 0;
1009 }
1010 *max_opt += option.delta;
1011 *optp += optsize;
1012 *length -= optsize;
1013
1014 return optsize;
1015}
1016
1017size_t
1019 const uint8_t *data) {
1020 assert(data);
1021 size_t header_size = 0;
1022
1023 if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
1024 uint8_t len = *data >> 4;
1025 if (len < 13)
1026 header_size = 2;
1027 else if (len==13)
1028 header_size = 3;
1029 else if (len==14)
1030 header_size = 4;
1031 else
1032 header_size = 6;
1033 } else if (proto == COAP_PROTO_WS || proto==COAP_PROTO_WSS) {
1034 header_size = 2;
1035 } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
1036 header_size = 4;
1037 }
1038
1039 return header_size;
1040}
1041
1042#if !COAP_DISABLE_TCP
1043/*
1044 * strm
1045 * return +ve PDU size including token
1046 * 0 PDU does not parse
1047 */
1048size_t
1050 const uint8_t *data,
1051 size_t length) {
1052 assert(data);
1053 assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS ||
1054 proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS);
1055 assert(coap_pdu_parse_header_size(proto, data) <= length);
1056
1057 size_t size = 0;
1058 const uint8_t *token_start = NULL;
1059
1060 if ((proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) && length >= 1) {
1061 uint8_t len = *data >> 4;
1062 uint8_t tkl = *data & 0x0f;
1063
1064 if (len < 13) {
1065 size = len;
1066 token_start = &data[2];
1067 } else if (length >= 2) {
1068 if (len==13) {
1069 size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
1070 token_start = &data[3];
1071 } else if (length >= 3) {
1072 if (len==14) {
1073 size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
1074 token_start = &data[4];
1075 } else if (length >= 5) {
1076 size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
1077 + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
1078 token_start = &data[6];
1079 }
1080 }
1081 }
1082 if (token_start) {
1083 /* account for the token length */
1084 if (tkl < COAP_TOKEN_EXT_1B_TKL) {
1085 size += tkl;
1086 } else if (tkl == COAP_TOKEN_EXT_1B_TKL) {
1087 size += token_start[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1088 } else if (tkl == COAP_TOKEN_EXT_2B_TKL) {
1089 size += ((uint16_t)token_start[0] << 8) + token_start[1] +
1091 } else {
1092 /* Invalid at this point - caught later as undersized */
1093 }
1094 }
1095 }
1096
1097 return size;
1098}
1099#endif /* ! COAP_DISABLE_TCP */
1100
1101int
1103 uint8_t *hdr = pdu->token - pdu->hdr_size;
1104 uint8_t e_token_length;
1105
1106 if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
1107 assert(pdu->hdr_size == 4);
1108 if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
1109 coap_log_debug("coap_pdu_parse: UDP version not supported\n");
1110 return 0;
1111 }
1112 pdu->type = (hdr[0] >> 4) & 0x03;
1113 pdu->code = hdr[1];
1114 pdu->mid = (uint16_t)hdr[2] << 8 | hdr[3];
1115 } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
1116 assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
1117 pdu->type = COAP_MESSAGE_CON;
1118 pdu->code = hdr[pdu->hdr_size-1];
1119 pdu->mid = 0;
1120 } else if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS) {
1121 assert(pdu->hdr_size == 2);
1122 pdu->type = COAP_MESSAGE_CON;
1123 pdu->code = hdr[pdu->hdr_size-1];
1124 pdu->mid = 0;
1125 } else {
1126 coap_log_debug("coap_pdu_parse: unsupported protocol\n");
1127 return 0;
1128 }
1129
1130 e_token_length = hdr[0] & 0x0f;
1131 if (e_token_length < COAP_TOKEN_EXT_1B_TKL) {
1132 pdu->e_token_length = e_token_length;
1134 pdu->actual_token.s = &pdu->token[0];
1135 } else if (e_token_length == COAP_TOKEN_EXT_1B_TKL) {
1136 pdu->e_token_length = pdu->token[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1137 pdu->actual_token.length = pdu->e_token_length - 1;
1138 pdu->actual_token.s = &pdu->token[1];
1139 } else if (e_token_length == COAP_TOKEN_EXT_2B_TKL) {
1140 pdu->e_token_length = ((uint16_t)pdu->token[0] << 8) + pdu->token[1] +
1142 pdu->actual_token.length = pdu->e_token_length - 2;
1143 pdu->actual_token.s = &pdu->token[2];
1144 }
1145 if (pdu->e_token_length > pdu->alloc_size || e_token_length == 15) {
1146 /* Invalid PDU provided - not wise to assert here though */
1147 coap_log_debug("coap_pdu_parse: PDU header token size broken\n");
1148 pdu->e_token_length = 0;
1149 pdu->actual_token.length = 0;
1150 return 0;
1151 }
1152 return 1;
1153}
1154
1155static int
1157 switch ((coap_pdu_signaling_proto_t)pdu->code) {
1158 case COAP_SIGNALING_CSM:
1159 switch (pdu->max_opt) {
1161 if (len > 4)
1162 goto bad;
1163 break;
1165 if (len > 0)
1166 goto bad;
1167 break;
1169 if (len > 3)
1170 goto bad;
1171 break;
1172 default:
1173 if (pdu->max_opt & 0x01)
1174 goto bad; /* Critical */
1175 }
1176 break;
1179 switch (pdu->max_opt) {
1181 if (len > 0)
1182 goto bad;
1183 break;
1184 default:
1185 if (pdu->max_opt & 0x01)
1186 goto bad; /* Critical */
1187 }
1188 break;
1190 switch (pdu->max_opt) {
1192 if (len < 1 || len > 255)
1193 goto bad;
1194 break;
1196 if (len > 3)
1197 goto bad;
1198 break;
1199 default:
1200 if (pdu->max_opt & 0x01)
1201 goto bad; /* Critical */
1202 }
1203 break;
1205 switch (pdu->max_opt) {
1207 if (len > 2)
1208 goto bad;
1209 break;
1210 default:
1211 if (pdu->max_opt & 0x01)
1212 goto bad; /* Critical */
1213 }
1214 break;
1215 default:
1216 ;
1217 }
1218 return 1;
1219bad:
1220 return 0;
1221}
1222
1223static int
1225 int res = 1;
1226
1227 switch (pdu->max_opt) {
1229 if (len > 8)
1230 res = 0;
1231 break;
1233 if (len < 1 || len > 255)
1234 res = 0;
1235 break;
1236 case COAP_OPTION_ETAG:
1237 if (len < 1 || len > 8)
1238 res = 0;
1239 break;
1241 if (len != 0)
1242 res = 0;
1243 break;
1245 if (len > 3)
1246 res = 0;
1247 break;
1249 if (len > 2)
1250 res = 0;
1251 break;
1253 if (len > 255)
1254 res = 0;
1255 break;
1256 case COAP_OPTION_OSCORE:
1257 if (len > 255)
1258 res = 0;
1259 break;
1261 if (len > 255)
1262 res = 0;
1263 break;
1265 if (len > 2)
1266 res = 0;
1267 break;
1268 case COAP_OPTION_MAXAGE:
1269 if (len > 4)
1270 res = 0;
1271 break;
1273 if (len < 1 || len > 255)
1274 res = 0;
1275 break;
1277 if (len != 1)
1278 res = 0;
1279 break;
1280 case COAP_OPTION_ACCEPT:
1281 if (len > 2)
1282 res = 0;
1283 break;
1285 if (len > 3)
1286 res = 0;
1287 break;
1289 if (len > 255)
1290 res = 0;
1291 break;
1292 case COAP_OPTION_EDHOC:
1293 if (len != 0)
1294 res = 0;
1295 break;
1296 case COAP_OPTION_BLOCK2:
1297 if (len > 3)
1298 res = 0;
1299 break;
1300 case COAP_OPTION_BLOCK1:
1301 if (len > 3)
1302 res = 0;
1303 break;
1304 case COAP_OPTION_SIZE2:
1305 if (len > 4)
1306 res = 0;
1307 break;
1309 if (len > 3)
1310 res = 0;
1311 break;
1313 if (len < 1 || len > 1034)
1314 res = 0;
1315 break;
1317 if (len < 1 || len > 255)
1318 res = 0;
1319 break;
1320 case COAP_OPTION_SIZE1:
1321 if (len > 4)
1322 res = 0;
1323 break;
1324 case COAP_OPTION_ECHO:
1325 if (len > 40)
1326 res = 0;
1327 break;
1329 if (len > 1)
1330 res = 0;
1331 break;
1332 case COAP_OPTION_RTAG:
1333 if (len > 8)
1334 res = 0;
1335 break;
1336 default:
1337 ;
1338 }
1339 return res;
1340}
1341
1342static int
1343write_prefix(char **obp, size_t *len, const char *prf, size_t prflen) {
1344 /* Make sure space for null terminating byte */
1345 if (*len < prflen +1) {
1346 return 0;
1347 }
1348
1349 memcpy(*obp, prf, prflen);
1350 *obp += prflen;
1351 *len -= prflen;
1352 return 1;
1353}
1354
1355static int
1356write_char(char **obp, size_t *len, int c, int printable) {
1357 /* Make sure space for null terminating byte */
1358 if (*len < 2 +1) {
1359 return 0;
1360 }
1361
1362 if (!printable) {
1363 const uint8_t hex[] = "0123456789abcdef";
1364 (*obp)[0] = hex[(c & 0xf0) >> 4];
1365 (*obp)[1] = hex[c & 0x0f];
1366 } else {
1367 (*obp)[0] = isprint(c) ? c : '.';
1368 (*obp)[1] = ' ';
1369 }
1370 *obp += 2;
1371 *len -= 2;
1372 return 1;
1373}
1374
1375int
1377 int good = 1;
1378
1379 coap_option_filter_clear(error_opts);
1380
1381 /* sanity checks */
1382 if (pdu->code == 0) {
1383 if (pdu->used_size != 0 || pdu->e_token_length) {
1384 coap_log_debug("coap_pdu_parse: empty message is not empty\n");
1385 return 0;
1386 }
1387 }
1388
1389 if (pdu->e_token_length > pdu->used_size) {
1390 coap_log_debug("coap_pdu_parse: invalid Token\n");
1391 return 0;
1392 }
1393
1394 pdu->max_opt = 0;
1395 if (pdu->code == 0) {
1396 /* empty packet */
1397 pdu->used_size = 0;
1398 pdu->data = NULL;
1399 } else {
1400 /* skip header + token */
1401 coap_opt_t *opt = pdu->token + pdu->e_token_length;
1402 size_t length = pdu->used_size - pdu->e_token_length;
1403
1404 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1405#if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN)
1406 coap_opt_t *opt_last = opt;
1407#endif
1408 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1409 const uint32_t len =
1410 optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1411 if (optsize == 0) {
1412 coap_log_debug("coap_pdu_parse: %d.%02d: offset %u malformed option\n",
1413 pdu->code >> 5, pdu->code & 0x1F,
1414 (int)(opt_last - pdu->token - pdu->e_token_length));
1415 coap_option_filter_set(error_opts, pdu->max_opt);
1416 good = 0;
1417 break;
1418 }
1419 if (COAP_PDU_IS_SIGNALING(pdu) ?
1420 !coap_pdu_parse_opt_csm(pdu, len) :
1421 !coap_pdu_parse_opt_base(pdu, len)) {
1422 coap_log_warn("coap_pdu_parse: %d.%02d: offset %u option %u has bad length %" PRIu32 "\n",
1423 pdu->code >> 5, pdu->code & 0x1F,
1424 (int)(opt_last - pdu->token - pdu->e_token_length), pdu->max_opt,
1425 len);
1426 coap_option_filter_set(error_opts, pdu->max_opt);
1427 good = 0;
1428 }
1429 }
1430
1431 if (!good) {
1432 /*
1433 * Dump the options in the PDU for analysis, space separated except
1434 * error options which are prefixed by *
1435 * Two rows - hex and ascii (if printable)
1436 */
1437 static char outbuf[COAP_DEBUG_BUF_SIZE];
1438 char *obp;
1439 size_t tlen;
1440 size_t outbuflen;
1441 int i;
1442 int ok;
1443
1444 for (i = 0; i < 2; i++) {
1445 opt = pdu->token + pdu->e_token_length;
1446 length = pdu->used_size - pdu->e_token_length;
1447 pdu->max_opt = 0;
1448
1449 outbuflen = sizeof(outbuf);
1450 obp = outbuf;
1451 ok = write_prefix(&obp, &outbuflen, "O: ", 3);
1452 /*
1453 * Not safe to check for 'ok' here as a lot of variables may get
1454 * partially changed due to lack of outbuflen */
1455 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1456 coap_opt_t *opt_last = opt;
1457 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1458 const uint32_t len =
1459 optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1460 if (!optsize || (COAP_PDU_IS_SIGNALING(pdu) ?
1461 !coap_pdu_parse_opt_csm(pdu, len) :
1462 !coap_pdu_parse_opt_base(pdu, len))) {
1463 ok = ok && write_prefix(&obp, &outbuflen, "*", 1);
1464 if (!optsize) {
1465 /* Skip to end of options to output all data */
1466 opt = pdu->token + pdu->used_size;
1467 length = 0;
1468 }
1469 } else {
1470 ok = ok && write_prefix(&obp, &outbuflen, " ", 1);
1471 }
1472 tlen = opt - opt_last;
1473 while (tlen) {
1474 tlen--;
1475 ok = ok && write_char(&obp, &outbuflen, *opt_last, i);
1476 opt_last++;
1477 }
1478 }
1479 if (length && *opt == COAP_PAYLOAD_START) {
1480 write_char(&obp, &outbuflen, *opt, i);
1481 }
1482 /* write_*() always leaves a spare byte to null terminate */
1483 *obp = '\000';
1484 coap_log_debug("%s\n", outbuf);
1485 }
1486 }
1487
1488 if (length > 0) {
1489 assert(*opt == COAP_PAYLOAD_START);
1490 opt++;
1491 length--;
1492
1493 if (length == 0) {
1494 coap_log_debug("coap_pdu_parse: message ending in payload start marker\n");
1495 return 0;
1496 }
1497 }
1498 if (length > 0)
1499 pdu->data = (uint8_t *)opt;
1500 else
1501 pdu->data = NULL;
1502 }
1503
1504 return good;
1505}
1506
1507int
1509 const uint8_t *data,
1510 size_t length,
1511 coap_pdu_t *pdu) {
1512 coap_opt_filter_t error_opts;
1513
1514 return coap_pdu_parse2(proto, data, length, pdu, &error_opts);
1515}
1516
1517int
1519 const uint8_t *data,
1520 size_t length,
1521 coap_pdu_t *pdu,
1522 coap_opt_filter_t *error_opts) {
1523 size_t hdr_size;
1524
1525 if (length == 0)
1526 return 0;
1527 hdr_size = coap_pdu_parse_header_size(proto, data);
1528 if (!hdr_size || hdr_size > length)
1529 return 0;
1530 if (hdr_size > pdu->max_hdr_size)
1531 return 0;
1532 if (!coap_pdu_resize(pdu, length - hdr_size))
1533 return 0;
1534 if (pdu->token - hdr_size != data)
1535 memcpy(pdu->token - hdr_size, data, length);
1536 pdu->hdr_size = (uint8_t)hdr_size;
1537 pdu->used_size = length - hdr_size;
1538 return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu, error_opts);
1539}
1540
1541size_t
1543 uint8_t e_token_length;
1544
1546 e_token_length = (uint8_t)pdu->actual_token.length;
1547 } else if (pdu->actual_token.length < COAP_TOKEN_EXT_2B_BIAS) {
1548 e_token_length = COAP_TOKEN_EXT_1B_TKL;
1549 } else if (pdu->actual_token.length <= COAP_TOKEN_EXT_MAX) {
1550 e_token_length = COAP_TOKEN_EXT_2B_TKL;
1551 } else {
1552 coap_log_warn("coap_add_token: Token size too large. PDU ignored\n");
1553 return 0;
1554 }
1555 if (COAP_PROTO_NOT_RELIABLE(proto)) {
1556 assert(pdu->max_hdr_size >= 4);
1557 if (pdu->max_hdr_size < 4) {
1558 coap_log_warn("coap_pdu_encode_header: not enough space for UDP-style header\n");
1559 return 0;
1560 }
1561 pdu->token[-4] = COAP_DEFAULT_VERSION << 6
1562 | pdu->type << 4
1563 | e_token_length;
1564 pdu->token[-3] = pdu->code;
1565 pdu->token[-2] = (uint8_t)(pdu->mid >> 8);
1566 pdu->token[-1] = (uint8_t)(pdu->mid);
1567 pdu->hdr_size = 4;
1568#if !COAP_DISABLE_TCP
1569 } else if (COAP_PROTO_RELIABLE(proto)) {
1570 size_t len;
1571 assert(pdu->used_size >= pdu->e_token_length);
1572 if (pdu->used_size < pdu->e_token_length) {
1573 coap_log_warn("coap_pdu_encode_header: corrupted PDU\n");
1574 return 0;
1575 }
1576
1577 /* A lot of the reliable code assumes type is CON */
1578 if (pdu->type != COAP_MESSAGE_CON)
1579 pdu->type = COAP_MESSAGE_CON;
1580
1581 if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS)
1582 len = 0;
1583 else
1584 len = pdu->used_size - pdu->e_token_length;
1585 if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
1586 assert(pdu->max_hdr_size >= 2);
1587 if (pdu->max_hdr_size < 2) {
1588 coap_log_warn("coap_pdu_encode_header: not enough space for TCP0 header\n");
1589 return 0;
1590 }
1591 pdu->token[-2] = (uint8_t)len << 4
1592 | e_token_length;
1593 pdu->token[-1] = pdu->code;
1594 pdu->hdr_size = 2;
1595 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
1596 assert(pdu->max_hdr_size >= 3);
1597 if (pdu->max_hdr_size < 3) {
1598 coap_log_warn("coap_pdu_encode_header: not enough space for TCP8 header\n");
1599 return 0;
1600 }
1601 pdu->token[-3] = 13 << 4 | e_token_length;
1602 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
1603 pdu->token[-1] = pdu->code;
1604 pdu->hdr_size = 3;
1605 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
1606 assert(pdu->max_hdr_size >= 4);
1607 if (pdu->max_hdr_size < 4) {
1608 coap_log_warn("coap_pdu_encode_header: not enough space for TCP16 header\n");
1609 return 0;
1610 }
1611 pdu->token[-4] = 14 << 4 | e_token_length;
1612 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
1613 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
1614 pdu->token[-1] = pdu->code;
1615 pdu->hdr_size = 4;
1616 } else {
1617 assert(pdu->max_hdr_size >= 6);
1618 if (pdu->max_hdr_size < 6) {
1619 coap_log_warn("coap_pdu_encode_header: not enough space for TCP32 header\n");
1620 return 0;
1621 }
1622 pdu->token[-6] = 15 << 4 | e_token_length;
1623 pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
1624 pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
1625 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
1626 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
1627 pdu->token[-1] = pdu->code;
1628 pdu->hdr_size = 6;
1629 }
1630#endif /* ! COAP_DISABLE_TCP */
1631 } else {
1632 coap_log_warn("coap_pdu_encode_header: unsupported protocol\n");
1633 }
1634 return pdu->hdr_size;
1635}
1636
1639 return pdu->code;
1640}
1641
1642void
1644#ifndef RIOT_VERSION
1645 assert(code <= 0xff);
1646#endif /* RIOT_VERSION */
1647 pdu->code = code;
1648}
1649
1652 return pdu->type;
1653}
1654
1655void
1657 assert(type <= 0x3);
1658 pdu->type = type;
1659}
1660
1663 return pdu->actual_token;
1664}
1665
1668 return pdu->mid;
1669}
1670
1671void
1673#if (UINT_MAX > 65535)
1674 assert(mid >= 0 && mid <= 0xffff);
1675#endif /* UINT_MAX > 65535 */
1676 pdu->mid = mid;
1677}
1678
1679coap_pdu_t *
1681 if (pdu != NULL) {
1682 ++pdu->ref;
1683 }
1684 return pdu;
1685}
1686
1687coap_pdu_t *
1689 coap_pdu_t *pdu_rw = NULL;
1690
1691 if (pdu != NULL) {
1692
1693 /* Need to do this to not get a compiler warning about const parameters */
1694 memcpy(&pdu_rw, &pdu, sizeof(pdu_rw));
1695 ++pdu_rw->ref;
1696 }
1697 return pdu_rw;
1698}
#define PRIuS
#define PRIu32
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ COAP_PDU
Definition coap_mem.h:40
@ COAP_PDU_BUF
Definition coap_mem.h:41
void * coap_realloc_type(coap_memory_tag_t type, void *p, size_t size)
Reallocates a chunk p of bytes created by coap_malloc_type() or coap_realloc_type() and returns a poi...
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.
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 coap_option.c:41
#define NULL
Definition coap_option.h:30
uint16_t coap_option_num_t
Definition coap_option.h:37
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition coap_option.h:43
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 coap_pdu.c:994
static int coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len)
Definition coap_pdu.c:1156
error_desc_t coap_error[]
Definition coap_pdu.c:946
static int write_prefix(char **obp, size_t *len, const char *prf, size_t prflen)
Definition coap_pdu.c:1343
static int coap_pdu_parse_opt_base(coap_pdu_t *pdu, uint16_t len)
Definition coap_pdu.c:1224
#define min(a, b)
Definition coap_pdu.c:37
static int write_char(char **obp, size_t *len, int c, int printable)
Definition coap_pdu.c:1356
#define max(a, b)
Definition coap_pdu.c:41
uint16_t coap_new_message_id_lkd(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
#define coap_log_info(...)
Definition coap_debug.h:114
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_crit(...)
Definition coap_debug.h:96
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
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.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
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.
size_t coap_opt_encode_size(uint16_t delta, size_t length)
Compute storage bytes needed for an option with given delta and length.
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
int coap_option_filter_get(coap_opt_filter_t *filter, coap_option_num_t option)
Checks if number is contained in filter.
int coap_option_filter_set(coap_opt_filter_t *filter, coap_option_num_t option)
Sets the corresponding entry for number in filter.
#define COAP_MESSAGE_SIZE_OFFSET_TCP8
coap_pdu_t * coap_pdu_reference_lkd(coap_pdu_t *pdu)
Increment reference counter on a pdu to stop it prematurely getting freed off when coap_delete_pdu() ...
Definition coap_pdu.c:1680
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:194
#define COAP_DEBUG_BUF_SIZE
#define COAP_TOKEN_EXT_2B_TKL
size_t coap_insert_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Inserts option of given number in the pdu with the appropriate data.
Definition coap_pdu.c:652
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition coap_pdu.c:512
int coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Updates token in pdu with length len and data.
Definition coap_pdu.c:436
#define COAP_TOKEN_EXT_1B_BIAS
#define COAP_PDU_MAX_UDP_HEADER_SIZE
int coap_pdu_parse_opt(coap_pdu_t *pdu, coap_opt_filter_t *error_opts)
Verify consistency in the given CoAP PDU structure and locate the data.
Definition coap_pdu.c:1376
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto)
Decode the protocol specific header for the specified PDU.
Definition coap_pdu.c:1102
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 coap_pdu.c:1018
coap_pdu_t * coap_new_pdu_lkd(coap_pdu_type_t type, coap_pdu_code_t code, coap_session_t *session)
Creates a new CoAP PDU.
Definition coap_pdu.c:173
#define COAP_PDU_MAX_TCP_HEADER_SIZE
#define COAP_MAX_MESSAGE_SIZE_TCP8
#define COAP_DEFAULT_MAX_PDU_RX_SIZE
#define COAP_PDU_IS_SIGNALING(pdu)
#define COAP_TOKEN_EXT_2B_BIAS
#define COAP_MAX_MESSAGE_SIZE_TCP0
int coap_option_check_repeatable(coap_option_num_t number)
Check whether the option is allowed to be repeated or not.
Definition coap_pdu.c:606
#define COAP_MESSAGE_SIZE_OFFSET_TCP16
void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
Clears any contents from pdu and resets used_size, and data pointers.
Definition coap_pdu.c:45
#define COAP_MESSAGE_SIZE_OFFSET_TCP32
size_t coap_update_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Updates existing first option of given number in the pdu with the new data.
Definition coap_pdu.c:751
#define COAP_TOKEN_EXT_1B_TKL
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition coap_pdu.c:1542
coap_pdu_t * coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition coap_pdu.c:234
#define COAP_DEFAULT_VERSION
int coap_pdu_parse2(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu, coap_opt_filter_t *error_opts)
Parses data into the CoAP PDU structure given in result.
Definition coap_pdu.c:1518
#define COAP_PAYLOAD_START
int coap_pdu_check_resize(coap_pdu_t *pdu, size_t size)
Dynamically grows the size of pdu to new_size if needed.
Definition coap_pdu.c:362
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 coap_pdu.c:1049
coap_pdu_t * coap_const_pdu_reference_lkd(const coap_pdu_t *pdu)
Increment reference counter on a const pdu to stop it prematurely getting freed off when coap_delete_...
Definition coap_pdu.c:1688
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition coap_pdu.c:307
#define COAP_PDU_IS_REQUEST(pdu)
#define COAP_MAX_MESSAGE_SIZE_TCP16
size_t coap_add_option_internal(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition coap_pdu.c:807
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:135
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:148
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:122
#define COAP_OPTION_IF_MATCH
Definition coap_pdu.h:121
coap_pdu_code_t coap_pdu_get_code(const coap_pdu_t *pdu)
Gets the PDU code associated with pdu.
Definition coap_pdu.c:1638
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:140
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition coap_pdu.c:978
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:130
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition coap_pdu.h:208
#define COAP_OPTION_SIZE2
Definition coap_pdu.h:142
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:141
#define COAP_OPTION_Q_BLOCK1
Definition coap_pdu.h:137
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:145
COAP_API void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:187
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.
Definition coap_pdu.c:884
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:134
void coap_pdu_set_code(coap_pdu_t *pdu, coap_pdu_code_t code)
Sets the PDU code in the pdu.
Definition coap_pdu.c:1643
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:266
COAP_API coap_pdu_t * coap_pdu_duplicate(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition coap_pdu.c:212
#define COAP_OPTION_IF_NONE_MATCH
Definition coap_pdu.h:124
#define COAP_OPTION_LOCATION_PATH
Definition coap_pdu.h:127
#define COAP_TOKEN_EXT_MAX
Definition coap_pdu.h:62
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:129
#define COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH
Definition coap_pdu.h:202
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:163
coap_proto_t
CoAP protocol types Note: coap_layers_coap[] needs updating if extended.
Definition coap_pdu.h:316
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:330
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:128
#define COAP_OPTION_SIZE1
Definition coap_pdu.h:146
coap_pdu_type_t
CoAP PDU message type definitions.
Definition coap_pdu.h:70
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition coap_pdu.h:201
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition coap_pdu.c:379
#define COAP_OPTION_LOCATION_QUERY
Definition coap_pdu.h:138
void coap_pdu_set_type(coap_pdu_t *pdu, coap_pdu_type_t type)
Sets the PDU type in the pdu.
Definition coap_pdu.c:1656
size_t coap_add_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition coap_pdu.c:797
#define COAP_OPTION_Q_BLOCK2
Definition coap_pdu.h:143
#define COAP_SIGNALING_OPTION_CUSTODY
Definition coap_pdu.h:205
coap_pdu_signaling_proto_t
Definition coap_pdu.h:191
coap_pdu_type_t coap_pdu_get_type(const coap_pdu_t *pdu)
Gets the PDU type associated with pdu.
Definition coap_pdu.c:1651
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition coap_pdu.c:903
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 coap_pdu.c:1508
#define COAP_MAX_OPT
the highest option number we know
Definition coap_pdu.h:154
void coap_pdu_set_mid(coap_pdu_t *pdu, coap_mid_t mid)
Sets the message id in the pdu.
Definition coap_pdu.c:1672
#define COAP_OPTION_RTAG
Definition coap_pdu.h:149
COAP_API coap_pdu_t * coap_new_pdu(coap_pdu_type_t type, coap_pdu_code_t code, coap_session_t *session)
Creates a new CoAP PDU.
Definition coap_pdu.c:162
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:126
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition coap_pdu.c:102
#define COAP_OPTION_EDHOC
Definition coap_pdu.h:139
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:136
int coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data, size_t *offset, size_t *total)
Retrieves the data from a PDU, with support for large bodies of data that spans multiple PDUs.
Definition coap_pdu.c:911
#define COAP_DEFAULT_MTU
Definition coap_pdu.h:43
coap_mid_t coap_pdu_get_mid(const coap_pdu_t *pdu)
Gets the message id associated with pdu.
Definition coap_pdu.c:1667
#define COAP_OPTION_MAXAGE
Definition coap_pdu.h:133
#define COAP_OPTION_ETAG
Definition coap_pdu.h:123
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:144
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:125
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition coap_pdu.h:209
#define COAP_OPTION_ECHO
Definition coap_pdu.h:147
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition coap_pdu.h:212
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition coap_pdu.h:200
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 coap_pdu.c:872
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1662
@ COAP_PROTO_WS
Definition coap_pdu.h:322
@ COAP_PROTO_DTLS
Definition coap_pdu.h:319
@ COAP_PROTO_UDP
Definition coap_pdu.h:318
@ COAP_PROTO_TLS
Definition coap_pdu.h:321
@ COAP_PROTO_WSS
Definition coap_pdu.h:323
@ COAP_PROTO_TCP
Definition coap_pdu.h:320
@ COAP_MESSAGE_CON
Definition coap_pdu.h:71
@ COAP_SIGNALING_RELEASE
Definition coap_pdu.h:195
@ COAP_SIGNALING_CSM
Definition coap_pdu.h:192
@ COAP_SIGNALING_PONG
Definition coap_pdu.h:194
@ COAP_SIGNALING_PING
Definition coap_pdu.h:193
@ COAP_SIGNALING_ABORT
Definition coap_pdu.h:196
size_t coap_session_max_pdu_size_lkd(const coap_session_t *session)
Get maximum acceptable PDU size.
#define COAP_PROTO_NOT_RELIABLE(p)
#define COAP_PROTO_RELIABLE(p)
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:114
CoAP binary data definition with const data.
Definition coap_str.h:65
size_t length
length of binary data
Definition coap_str.h:66
const uint8_t * s
read-only binary data
Definition coap_str.h:67
Iterator to run through PDU options.
coap_option_num_t number
decoded option number
Representation of CoAP options.
Definition coap_option.h:49
uint16_t delta
Definition coap_option.h:50
structure for CoAP PDUs
uint8_t max_hdr_size
space reserved for protocol-specific header
uint16_t max_opt
highest option number in PDU
uint8_t * token
first byte of token (or extended length bytes prefix), if any, or options
coap_lg_xmit_t * lg_xmit
Holds ptr to lg_xmit if sending a set of blocks.
size_t body_length
Holds body data length.
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
const uint8_t * body_data
Holds ptr to re-assembled data or NULL.
size_t body_offset
Holds body data offset.
unsigned ref
reference count
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
uint8_t hdr_size
actual size used for protocol-specific header (0 until header is encoded)
coap_bin_const_t actual_token
Actual token in pdu.
uint8_t * data
first byte of payload, if any
coap_mid_t mid
message id, if any, in regular host byte order
uint32_t e_token_length
length of Token space (includes leading extended bytes
size_t used_size
used bytes of storage for token, options and payload
uint8_t crit_opt
Set if unknown critical option for proxy.
coap_binary_t * data_free
Data to be freed off by coap_delete_pdu()
size_t alloc_size
allocated storage for token, options and payload
coap_session_t * session
Session responsible for PDU or NULL.
size_t body_total
Holds body data total size.
coap_pdu_type_t type
message type
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_proto_t proto
protocol used
unsigned char code
Definition coap_pdu.c:940
const char * phrase
Definition coap_pdu.c:941