libcoap 4.3.5-develop-590570a
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, max(size, COAP_DEFAULT_MTU) + pdu->max_hdr_size,
140 PBUF_RAM);
141 if (pdu->pbuf == NULL) {
143 return NULL;
144 }
145 pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
146#else /* ! WITH_LWIP */
147 uint8_t *buf;
149 if (buf == NULL) {
151 return NULL;
152 }
153 pdu->token = buf + pdu->max_hdr_size;
154#endif /* ! WITH_LWIP */
155 coap_pdu_clear(pdu, size);
156 pdu->mid = mid;
157 pdu->type = type;
158 pdu->code = code;
159 return pdu;
160}
161
164 coap_session_t *session) {
165 coap_pdu_t *pdu;
166
167 coap_lock_lock(return NULL);
168 pdu = coap_new_pdu_lkd(type, code, session);
170 return pdu;
171}
172
175 coap_session_t *session) {
176 coap_pdu_t *pdu;
177
179 pdu = coap_pdu_init(type, code, coap_new_message_id_lkd(session),
181 if (!pdu)
182 coap_log_crit("coap_new_pdu: cannot allocate memory for new PDU (size = %" PRIuS ")\n",
184 return pdu;
185}
186
187COAP_API void
193
194void
196 if (pdu != NULL) {
197 if (pdu->ref) {
198 pdu->ref--;
199 return;
200 }
201#ifdef WITH_LWIP
202 pbuf_free(pdu->pbuf);
203#else
204 if (pdu->token != NULL)
206#endif
209 }
210}
211
214 coap_session_t *session,
215 size_t token_length,
216 const uint8_t *token,
217 coap_opt_filter_t *drop_options) {
218 coap_pdu_t *new_pdu;
219
220 coap_lock_lock(return NULL);
221 new_pdu = coap_pdu_duplicate_lkd(old_pdu,
222 session,
223 token_length,
224 token,
225 drop_options, COAP_BOOL_FALSE);
227 return new_pdu;
228}
229
230
231/*
232 * Note: This does not include any data, just the token and options
233 */
236 coap_session_t *session,
237 size_t token_length,
238 const uint8_t *token,
239 coap_opt_filter_t *drop_options,
240 coap_bool_t expand_opt_abb) {
241#if COAP_CLIENT_SUPPORT
242 uint8_t doing_first = session->doing_first;
243#endif /* COAP_CLIENT_SUPPORT */
244 coap_pdu_t *pdu;
245
247 /*
248 * Need to make sure that coap_session_max_pdu_size_lkd() immediately
249 * returns, rather than wait for the first CSM response from remote
250 * that indicates BERT size (TCP/TLS only) as this may be called early
251 * the OSCORE logic.
252 */
253#if COAP_CLIENT_SUPPORT
254 session->doing_first = 0;
255#endif /* COAP_CLIENT_SUPPORT */
256 pdu = coap_pdu_init(old_pdu->type, old_pdu->code,
258 max(old_pdu->max_size,
260#if COAP_CLIENT_SUPPORT
261 /* Restore any pending waits */
262 session->doing_first = doing_first;
263#endif /* COAP_CLIENT_SUPPORT */
264 if (pdu == NULL)
265 return NULL;
266
267 coap_add_token(pdu, token_length, token);
268 pdu->lg_xmit = old_pdu->lg_xmit;
269
270 if (drop_options == NULL && expand_opt_abb == COAP_BOOL_FALSE) {
271 /* Drop COAP_PAYLOAD_START as well if data */
272 size_t length = old_pdu->used_size - old_pdu->e_token_length -
273 (old_pdu->data ?
274 old_pdu->used_size - (old_pdu->data - old_pdu->token) +1 : 0);
275 if (!coap_pdu_resize(pdu, length + pdu->e_token_length))
276 goto fail;
277 /* Copy the options but not any data across */
278 memcpy(pdu->token + pdu->e_token_length,
279 old_pdu->token + old_pdu->e_token_length, length);
280 pdu->used_size += length;
281 pdu->max_opt = old_pdu->max_opt;
282 } else {
283 /* Copy across all the options the slow way */
284 coap_opt_iterator_t opt_iter;
285 coap_opt_t *option;
286
287 coap_option_iterator_init(old_pdu, &opt_iter, COAP_OPT_ALL);
288 while ((option = coap_option_next(&opt_iter))) {
289 if (opt_iter.number == COAP_OPTION_URI_PATH_ABB && expand_opt_abb == COAP_BOOL_TRUE) {
290 uint32_t value;
291 const char *exp;
292
294 coap_opt_length(option));
296 if (exp) {
297 while (exp) {
298 const char *next = strchr(exp, '/');
299
301 next ? (int)(next - exp) : (int)strlen(exp),
302 (const uint8_t *)exp))
303 goto fail;
304 if (next)
305 exp = next + 1;
306 else
307 exp = NULL;
308 }
309 } else {
311 coap_log_info("coap_pdu_duplicate: Uri-Path-Abbrev value %" PRIu32 " not known for fallback\n",
312 value);
313 return NULL;
314 }
315 } else {
316 if (drop_options) {
317 if (coap_option_filter_get(drop_options, opt_iter.number))
318 continue;
319 }
320 if (!coap_insert_option(pdu, opt_iter.number,
321 coap_opt_length(option),
322 coap_opt_value(option)))
323 goto fail;
324 }
325 }
326 }
327 return pdu;
328
329fail:
331 return NULL;
332}
333
334
335/*
336 * The new size does not include the coap header (max_hdr_size)
337 */
338int
339coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
340 if (new_size > pdu->alloc_size) {
341 /* Expanding the PDU usage */
342#if !defined(WITH_LWIP)
343 uint8_t *new_hdr;
344#else /* WITH_LWIP */
345 struct pbuf *new_hdr;
346#endif /* WITH_LWIP */
347 size_t offset;
348
349 if (pdu->max_size && new_size > pdu->max_size) {
350 coap_log_warn("coap_pdu_resize: pdu too big\n");
351 return 0;
352 }
353 if (pdu->data != NULL) {
354 assert(pdu->data > pdu->token);
355 offset = pdu->data - pdu->token;
356 } else {
357 offset = 0;
358 }
359#if !defined(WITH_LWIP)
360 new_hdr = (uint8_t *)coap_realloc_type(COAP_PDU_BUF,
361 pdu->token - pdu->max_hdr_size,
362 new_size + pdu->max_hdr_size);
363#else /* WITH_LWIP */
364 new_hdr = pbuf_alloc(PBUF_TRANSPORT, new_size + pdu->max_hdr_size, PBUF_RAM);
365#endif /* WITH_LWIP */
366 if (new_hdr == NULL) {
367 coap_log_warn("coap_pdu_resize: realloc failed\n");
368 return 0;
369 }
370#if !defined(WITH_LWIP)
371 pdu->token = new_hdr + pdu->max_hdr_size;
372#else /* WITH_LWIP */
373 memcpy(new_hdr->payload, pdu->pbuf->payload, pdu->pbuf->len);
374 pbuf_free(pdu->pbuf);
375 pdu->pbuf = new_hdr;
376 pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
377#endif /* WITH_LWIP */
378 if (offset > 0)
379 pdu->data = pdu->token + offset;
380 else
381 pdu->data = NULL;
383 pdu->actual_token.s = &pdu->token[0];
385 pdu->actual_token.s = &pdu->token[1];
386 else
387 pdu->actual_token.s = &pdu->token[2];
388 pdu->alloc_size = new_size;
389 }
390 return 1;
391}
392
393int
395 if (size > pdu->alloc_size) {
396 size_t new_size = max(256, pdu->alloc_size * 2);
397 while (size > new_size)
398 new_size *= 2;
399 if (pdu->max_size && new_size > pdu->max_size) {
400 new_size = pdu->max_size;
401 if (new_size < size)
402 return 0;
403 }
404 if (!coap_pdu_resize(pdu, new_size))
405 return 0;
406 }
407 return 1;
408}
409
410int
411coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
412 size_t bias = 0;
413
414 /* must allow for pdu == NULL as callers may rely on this */
415 if (!pdu)
416 return 0;
417
418 if (pdu->used_size) {
419 coap_log_warn("coap_add_token: The token must defined first. Token ignored\n");
420 return 0;
421 }
422 pdu->actual_token.length = len;
423 if (len < COAP_TOKEN_EXT_1B_BIAS) {
424 bias = 0;
425 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
426 bias = 1;
427 } else if (len <= COAP_TOKEN_EXT_MAX) {
428 bias = 2;
429 } else {
430 coap_log_warn("coap_add_token: Token size too large. Token ignored\n");
431 return 0;
432 }
433 if (!coap_pdu_check_resize(pdu, len + bias)) {
434 coap_log_warn("coap_add_token: Insufficient space for token. Token ignored\n");
435 return 0;
436 }
437
438 pdu->actual_token.length = len;
439 pdu->actual_token.s = &pdu->token[bias];
440 pdu->e_token_length = (uint32_t)(len + bias);
441 if (len) {
442 switch (bias) {
443 case 0:
444 memcpy(pdu->token, data, len);
445 break;
446 case 1:
447 pdu->token[0] = (uint8_t)(len - COAP_TOKEN_EXT_1B_BIAS);
448 memcpy(&pdu->token[1], data, len);
449 break;
450 case 2:
451 pdu->token[0] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) >> 8);
452 pdu->token[1] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) & 0xff);
453 memcpy(&pdu->token[2], data, len);
454 break;
455 default:
456 break;
457 }
458 }
459 pdu->max_opt = 0;
460 pdu->used_size = len + bias;
461 pdu->data = NULL;
462
463 return 1;
464}
465
466/* It is assumed that coap_encode_var_safe8() has been called to reduce data */
467int
468coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
469 size_t bias = 0;
470 size_t old_len;
471
472 /* must allow for pdu == NULL as callers may rely on this */
473 if (!pdu)
474 return 0;
475
476 if (pdu->used_size == 0) {
477 return coap_add_token(pdu, len, data);
478 }
479
480 old_len = pdu->e_token_length;
481
482 if (len < COAP_TOKEN_EXT_1B_BIAS) {
483 bias = 0;
484 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
485 bias = 1;
486 } else if (len <= COAP_TOKEN_EXT_MAX) {
487 bias = 2;
488 } else {
489 coap_log_warn("coap_update_token: Token size too large. Token ignored\n");
490 return 0;
491 }
492 if ((len + bias) == pdu->e_token_length) {
493 /* Easy case - just data has changed */
494 } else if ((len + bias) > pdu->e_token_length) {
495 if (!coap_pdu_check_resize(pdu,
496 pdu->used_size + (len + bias) - pdu->e_token_length)) {
497 coap_log_warn("Failed to update token\n");
498 return 0;
499 }
500 memmove(&pdu->token[(len + bias) - pdu->e_token_length],
501 pdu->token, pdu->used_size);
502 pdu->used_size += len + bias - pdu->e_token_length;
503 if (pdu->data) {
504 pdu->data += (len + bias) - pdu->e_token_length;
505 }
506 } else {
507 pdu->used_size -= pdu->e_token_length - (len + bias);
508 memmove(pdu->token, &pdu->token[pdu->e_token_length - (len + bias)], pdu->used_size);
509 if (pdu->data) {
510 pdu->data -= pdu->e_token_length - (len + bias);
511 }
512 }
513
514 pdu->actual_token.length = len;
515 pdu->actual_token.s = &pdu->token[bias];
516 pdu->e_token_length = (uint8_t)(len + bias);
517 if (len) {
518 switch (bias) {
519 case 0:
520 if (memcmp(pdu->token, data, len) != 0)
521 memcpy(pdu->token, data, len);
522 break;
523 case 1:
524 pdu->token[0] = (uint8_t)(len - COAP_TOKEN_EXT_1B_BIAS);
525 memcpy(&pdu->token[1], data, len);
526 break;
527 case 2:
528 pdu->token[0] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) >> 8);
529 pdu->token[1] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) & 0xff);
530 memcpy(&pdu->token[2], data, len);
531 break;
532 default:
533 break;
534 }
535 }
536 if (old_len != pdu->e_token_length && pdu->hdr_size && pdu->session)
537 /* Need to fix up the header */
538 if (!coap_pdu_encode_header(pdu, pdu->session->proto))
539 return 0;
540 return 1;
541}
542
543int
545 coap_opt_iterator_t opt_iter;
546 coap_opt_t *option;
547 coap_opt_t *next_option = NULL;
548 size_t opt_delta;
549 coap_option_t decode_this;
550 coap_option_t decode_next;
551
552 /* Need to locate where in current options to remove this one */
554 while ((option = coap_option_next(&opt_iter))) {
555 if (opt_iter.number == number) {
556 /* Found option to delete */
557 break;
558 }
559 }
560 if (!option)
561 return 0;
562
563 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token),
564 &decode_this))
565 return 0;
566
567 next_option = coap_option_next(&opt_iter);
568 if (next_option) {
569 if (!coap_opt_parse(next_option,
570 pdu->used_size - (next_option - pdu->token),
571 &decode_next))
572 return 0;
573 opt_delta = decode_this.delta + decode_next.delta;
574 if (opt_delta < 13) {
575 /* can simply update the delta of next option */
576 next_option[0] = (next_option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
577 } else if (opt_delta < 269 && decode_next.delta < 13) {
578 /* next option delta size increase */
579 next_option -= 1;
580 next_option[0] = (next_option[1] & 0x0f) + (13 << 4);
581 next_option[1] = (coap_opt_t)(opt_delta - 13);
582 } else if (opt_delta < 269) {
583 /* can simply update the delta of next option */
584 next_option[1] = (coap_opt_t)(opt_delta - 13);
585 } else if (decode_next.delta < 13) { /* opt_delta >= 269 */
586 /* next option delta size increase */
587 if (next_option - option < 2) {
588 /* Need to shuffle everything up by 1 before decrement */
589 if (!coap_pdu_check_resize(pdu, pdu->used_size + 1))
590 return 0;
591 /* Possible a re-size took place with a realloc() */
592 /* Need to rediscover this and next options */
594 while ((option = coap_option_next(&opt_iter))) {
595 if (opt_iter.number == number) {
596 /* Found option to delete */
597 break;
598 }
599 }
600 next_option = coap_option_next(&opt_iter);
601 assert(option != NULL);
602 assert(next_option != NULL);
603 memmove(&next_option[1], next_option,
604 pdu->used_size - (next_option - pdu->token));
605 pdu->used_size++;
606 if (pdu->data)
607 pdu->data++;
608 next_option++;
609 }
610 next_option -= 2;
611 next_option[0] = (next_option[2] & 0x0f) + (14 << 4);
612 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
613 next_option[2] = (opt_delta - 269) & 0xff;
614 } else if (decode_next.delta < 269) { /* opt_delta >= 269 */
615 /* next option delta size increase */
616 next_option -= 1;
617 next_option[0] = (next_option[1] & 0x0f) + (14 << 4);
618 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
619 next_option[2] = (opt_delta - 269) & 0xff;
620 } else { /* decode_next.delta >= 269 && opt_delta >= 269 */
621 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
622 next_option[2] = (opt_delta - 269) & 0xff;
623 }
624 } else {
625 next_option = option + coap_opt_encode_size(decode_this.delta,
626 coap_opt_length(option));
627 pdu->max_opt -= decode_this.delta;
628 }
629 if (pdu->used_size - (next_option - pdu->token))
630 memmove(option, next_option, pdu->used_size - (next_option - pdu->token));
631 pdu->used_size -= next_option - option;
632 if (pdu->data)
633 pdu->data -= next_option - option;
634 return 1;
635}
636
637int
639 /* Validate that the option is repeatable */
640 switch (number) {
641 /* Ignore list of genuine repeatable */
643 case COAP_OPTION_ETAG:
649 case COAP_OPTION_RTAG:
650 break;
651 /* Protest at the known non-repeatable options and ignore them */
670 case COAP_OPTION_ECHO:
672 coap_log_info("Option number %d is not defined as repeatable - dropped\n",
673 number);
674 return 0;
675 default:
676 coap_log_info("Option number %d is not defined as repeatable\n",
677 number);
678 /* Accepting it after warning as there may be user defineable options */
679 break;
680 }
681 return 1;
682}
683
684size_t
686 const uint8_t *data) {
687 coap_opt_iterator_t opt_iter;
688 coap_opt_t *option;
689 uint16_t prev_number = 0;
690 size_t shift;
691 size_t opt_delta;
692 coap_option_t decode;
693 size_t shrink = 0;
694
695 if (number >= pdu->max_opt)
696 return coap_add_option_internal(pdu, number, len, data);
697
698 /* Need to locate where in current options to insert this one */
700 while ((option = coap_option_next(&opt_iter))) {
701 if (opt_iter.number > number) {
702 /* Found where to insert */
703 break;
704 }
705 prev_number = opt_iter.number;
706 }
707 if (option == NULL) {
708 /* Code is broken somewhere */
709 coap_log_warn("coap_insert_option: Broken max_opt\n");
710 return 0;
711 }
712
713 /* size of option inc header to insert */
714 shift = coap_opt_encode_size(number - prev_number, len);
715
716 /* size of next option (header may shrink in size as delta changes */
717 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token), &decode))
718 return 0;
719 opt_delta = opt_iter.number - number;
720 if (opt_delta == 0) {
721 if (!coap_option_check_repeatable(number))
722 return 0;
723 }
724
725 if (!coap_pdu_check_resize(pdu,
726 pdu->used_size + shift - shrink))
727 return 0;
728
729 /* Possible a re-size took place with a realloc() */
730 /* Need to locate where in current options to insert this one */
732 while ((option = coap_option_next(&opt_iter))) {
733 if (opt_iter.number > number) {
734 /* Found where to insert */
735 break;
736 }
737 }
738 assert(option != NULL);
739
740 if (decode.delta < 13) {
741 /* can simply patch in the new delta of next option */
742 option[0] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
743 } else if (decode.delta < 269 && opt_delta < 13) {
744 /* option header is going to shrink by one byte */
745 option[1] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
746 shrink = 1;
747 } else if (decode.delta < 269 && opt_delta < 269) {
748 /* can simply patch in the new delta of next option */
749 option[1] = (coap_opt_t)(opt_delta - 13);
750 } else if (opt_delta < 13) {
751 /* option header is going to shrink by two bytes */
752 option[2] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
753 shrink = 2;
754 } else if (opt_delta < 269) {
755 /* option header is going to shrink by one bytes */
756 option[1] = (option[0] & 0x0f) + 0xd0;
757 option[2] = (coap_opt_t)(opt_delta - 13);
758 shrink = 1;
759 } else {
760 /* can simply patch in the new delta of next option */
761 option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
762 option[2] = (opt_delta - 269) & 0xff;
763 }
764
765 memmove(&option[shift], &option[shrink],
766 pdu->used_size - (option - pdu->token) - shrink);
767 if (!coap_opt_encode(option, pdu->alloc_size - pdu->used_size,
768 number - prev_number, data, len))
769 return 0;
770
771 if (shift >= shrink) {
772 pdu->used_size += shift - shrink;
773 if (pdu->data)
774 pdu->data += shift - shrink;
775 } else {
776 pdu->used_size -= shrink - shift;
777 if (pdu->data)
778 pdu->data -= shrink - shift;
779 }
780 return shift;
781}
782
783size_t
785 const uint8_t *data) {
786 coap_opt_iterator_t opt_iter;
787 coap_opt_t *option;
788 coap_option_t decode;
789 size_t new_length = 0;
790 size_t old_length = 0;
791
792 option = coap_check_option(pdu, number, &opt_iter);
793 if (!option)
794 return coap_insert_option(pdu, number, len, data);
795
796 old_length = coap_opt_parse(option, (size_t)-1, &decode);
797 if (old_length == 0)
798 return 0;
799 new_length = coap_opt_encode_size(decode.delta, len);
800
801 if (new_length > old_length) {
802 if (!coap_pdu_check_resize(pdu,
803 pdu->used_size + new_length - old_length))
804 return 0;
805 /* Possible a re-size took place with a realloc() */
806 option = coap_check_option(pdu, number, &opt_iter);
807 }
808
809 if (new_length != old_length)
810 memmove(&option[new_length], &option[old_length],
811 pdu->used_size - (option - pdu->token) - old_length);
812
813 if (!coap_opt_encode(option, new_length,
814 decode.delta, data, len))
815 return 0;
816
817 if (new_length >= old_length) {
818 pdu->used_size += new_length - old_length;
819 if (pdu->data)
820 pdu->data += new_length - old_length;
821 } else {
822 pdu->used_size -= old_length - new_length;
823 if (pdu->data)
824 pdu->data -= old_length - new_length;
825 }
826 return 1;
827}
828
829size_t
831 const uint8_t *data) {
832 if (pdu->data) {
833 coap_log_warn("coap_add_option: PDU already contains data\n");
834 return 0;
835 }
836 if (!coap_pdu_parse_opt_base(number, len, data)) {
837 coap_log_warn("qcoap_add_option: %d: Invalid option length / data\n", number);
838 return 0;
839 }
840 return coap_add_option_internal(pdu, number, len, data);
841}
842
843size_t
845 const uint8_t *data) {
846 size_t optsize;
847 coap_opt_t *opt;
848
849 assert(pdu);
850
851 if (number == pdu->max_opt) {
852 if (!coap_option_check_repeatable(number))
853 return 0;
854 }
855
856 if (COAP_PDU_IS_REQUEST(pdu) &&
857 (number == COAP_OPTION_PROXY_URI ||
858 number == COAP_OPTION_PROXY_SCHEME)) {
859 /*
860 * Need to check whether there is a hop-limit option. If not, it needs
861 * to be inserted by default (RFC 8768).
862 */
863 coap_opt_iterator_t opt_iter;
864
865 if (coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter) == NULL) {
866 size_t hop_limit = COAP_OPTION_HOP_LIMIT;
867
868 coap_insert_option(pdu, COAP_OPTION_HOP_LIMIT, 1, (uint8_t *)&hop_limit);
869 }
870 }
871
872 if (number < pdu->max_opt) {
873 coap_log_debug("coap_add_option: options are not in correct order\n");
874 return coap_insert_option(pdu, number, len, data);
875 }
876
877 optsize = coap_opt_encode_size(number - pdu->max_opt, len);
878 if (!coap_pdu_check_resize(pdu,
879 pdu->used_size + optsize))
880 return 0;
881
882 if (pdu->data) {
883 /* include option delimiter */
884 memmove(&pdu->data[optsize-1], &pdu->data[-1],
885 pdu->used_size - (pdu->data - pdu->token) + 1);
886 opt = pdu->data -1;
887 pdu->data += optsize;
888 } else {
889 opt = pdu->token + pdu->used_size;
890 }
891
892 /* encode option and check length */
893 optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
894 number - pdu->max_opt, data, len);
895
896 if (!optsize) {
897 coap_log_warn("coap_add_option: cannot add option\n");
898 /* error */
899 return 0;
900 } else {
901 pdu->max_opt = number;
902 pdu->used_size += optsize;
903 }
904
905 return optsize;
906}
907
908int
909coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
910 if (len == 0) {
911 return 1;
912 } else {
913 uint8_t *payload = coap_add_data_after(pdu, len);
914 if (payload != NULL)
915 memcpy(payload, data, len);
916 return payload != NULL;
917 }
918}
919
920uint8_t *
922 assert(pdu);
923 if (pdu->data) {
924 coap_log_warn("coap_add_data: PDU already contains data\n");
925 return 0;
926 }
927
928 if (len == 0)
929 return NULL;
930
931 if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
932 return 0;
933 pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
934 pdu->data = pdu->token + pdu->used_size;
935 pdu->used_size += len;
936 return pdu->data;
937}
938
939int
940coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data) {
941 size_t offset;
942 size_t total;
943
944 return coap_get_data_large(pdu, len, data, &offset, &total);
945}
946
947int
948coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data,
949 size_t *offset, size_t *total) {
950 assert(pdu);
951 assert(len);
952 assert(data);
953
954 *offset = pdu->body_offset;
955 *total = pdu->body_total;
956 if (pdu->body_data) {
957 *data = pdu->body_data;
958 *len = pdu->body_length;
959 return 1;
960 }
961 *data = pdu->data;
962 if (pdu->data == NULL) {
963 *len = 0;
964 *total = 0;
965 return 0;
966 }
967
968 *len = pdu->used_size - (pdu->data - pdu->token);
969 if (*total == 0)
970 *total = *len;
971
972 return 1;
973}
974
975#ifndef SHORT_ERROR_RESPONSE
976typedef struct {
977 unsigned char code;
978 const char *phrase;
980
981/* if you change anything here, make sure, that the longest string does not
982 * exceed COAP_ERROR_PHRASE_LENGTH. */
984 { COAP_RESPONSE_CODE(201), "Created" },
985 { COAP_RESPONSE_CODE(202), "Deleted" },
986 { COAP_RESPONSE_CODE(203), "Valid" },
987 { COAP_RESPONSE_CODE(204), "Changed" },
988 { COAP_RESPONSE_CODE(205), "Content" },
989 { COAP_RESPONSE_CODE(231), "Continue" },
990 { COAP_RESPONSE_CODE(400), "Bad Request" },
991 { COAP_RESPONSE_CODE(401), "Unauthorized" },
992 { COAP_RESPONSE_CODE(402), "Bad Option" },
993 { COAP_RESPONSE_CODE(403), "Forbidden" },
994 { COAP_RESPONSE_CODE(404), "Not Found" },
995 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
996 { COAP_RESPONSE_CODE(406), "Not Acceptable" },
997 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
998 { COAP_RESPONSE_CODE(409), "Conflict" },
999 { COAP_RESPONSE_CODE(412), "Precondition Failed" },
1000 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
1001 { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
1002 { COAP_RESPONSE_CODE(422), "Unprocessable" },
1003 { COAP_RESPONSE_CODE(429), "Too Many Requests" },
1004 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
1005 { COAP_RESPONSE_CODE(501), "Not Implemented" },
1006 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
1007 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
1008 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
1009 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
1010 { COAP_RESPONSE_CODE(508), "Hop Limit Reached" },
1011 { 0, NULL } /* end marker */
1012};
1013
1014const char *
1015coap_response_phrase(unsigned char code) {
1016 int i;
1017 for (i = 0; coap_error[i].code; ++i) {
1018 if (coap_error[i].code == code)
1019 return coap_error[i].phrase;
1020 }
1021 return NULL;
1022}
1023#endif
1024
1030static size_t
1031next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt) {
1032 coap_option_t option;
1033 size_t optsize;
1034
1035 assert(optp);
1036 assert(*optp);
1037 assert(length);
1038
1039 optsize = coap_opt_parse(*optp, *length, &option);
1040 assert(optsize <= *length);
1041
1042 /* signal an error if this option would exceed the
1043 * allowed number space */
1044 if ((uint32_t)(*max_opt) + option.delta > COAP_MAX_OPT) {
1045 return 0;
1046 }
1047 *max_opt += option.delta;
1048 *optp += optsize;
1049 *length -= optsize;
1050
1051 return optsize;
1052}
1053
1054size_t
1056 const uint8_t *data) {
1057 assert(data);
1058 size_t header_size = 0;
1059
1060 if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
1061 uint8_t len = *data >> 4;
1062 if (len < 13)
1063 header_size = 2;
1064 else if (len==13)
1065 header_size = 3;
1066 else if (len==14)
1067 header_size = 4;
1068 else
1069 header_size = 6;
1070 } else if (proto == COAP_PROTO_WS || proto==COAP_PROTO_WSS) {
1071 header_size = 2;
1072 } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
1073 header_size = 4;
1074 }
1075
1076 return header_size;
1077}
1078
1079#if !COAP_DISABLE_TCP
1080/*
1081 * strm
1082 * return +ve PDU size including token
1083 * 0 PDU does not parse
1084 */
1085size_t
1087 const uint8_t *data,
1088 size_t length) {
1089 assert(data);
1090 assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS ||
1091 proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS);
1092 assert(coap_pdu_parse_header_size(proto, data) <= length);
1093
1094 size_t size = 0;
1095 const uint8_t *token_start = NULL;
1096
1097 if ((proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) && length >= 1) {
1098 uint8_t len = *data >> 4;
1099 uint8_t tkl = *data & 0x0f;
1100
1101 if (len < 13) {
1102 size = len;
1103 token_start = &data[2];
1104 } else if (length >= 2) {
1105 if (len==13) {
1106 size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
1107 token_start = &data[3];
1108 } else if (length >= 3) {
1109 if (len==14) {
1110 size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
1111 token_start = &data[4];
1112 } else if (length >= 5) {
1113 size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
1114 + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
1115 token_start = &data[6];
1116 }
1117 }
1118 }
1119 if (token_start) {
1120 /* account for the token length */
1121 if (tkl < COAP_TOKEN_EXT_1B_TKL) {
1122 size += tkl;
1123 } else if (tkl == COAP_TOKEN_EXT_1B_TKL) {
1124 size += token_start[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1125 } else if (tkl == COAP_TOKEN_EXT_2B_TKL) {
1126 size += ((uint16_t)token_start[0] << 8) + token_start[1] +
1128 } else {
1129 /* Invalid at this point - caught later as undersized */
1130 }
1131 }
1132 }
1133
1134 return size;
1135}
1136#endif /* ! COAP_DISABLE_TCP */
1137
1138int
1140 uint8_t *hdr = pdu->token - pdu->hdr_size;
1141 uint8_t e_token_length;
1142
1143 if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
1144 assert(pdu->hdr_size == 4);
1145 if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
1146 coap_log_debug("coap_pdu_parse: UDP version not supported\n");
1147 return 0;
1148 }
1149 pdu->type = (hdr[0] >> 4) & 0x03;
1150 pdu->code = hdr[1];
1151 pdu->mid = (uint16_t)hdr[2] << 8 | hdr[3];
1152 } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
1153 assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
1154 pdu->type = COAP_MESSAGE_CON;
1155 pdu->code = hdr[pdu->hdr_size-1];
1156 pdu->mid = 0;
1157 } else if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS) {
1158 assert(pdu->hdr_size == 2);
1159 pdu->type = COAP_MESSAGE_CON;
1160 pdu->code = hdr[pdu->hdr_size-1];
1161 pdu->mid = 0;
1162 } else {
1163 coap_log_debug("coap_pdu_parse: unsupported protocol\n");
1164 return 0;
1165 }
1166
1167 e_token_length = hdr[0] & 0x0f;
1168 if (e_token_length < COAP_TOKEN_EXT_1B_TKL) {
1169 pdu->e_token_length = e_token_length;
1171 pdu->actual_token.s = &pdu->token[0];
1172 } else if (e_token_length == COAP_TOKEN_EXT_1B_TKL) {
1173 if (pdu->used_size < 1)
1174 goto bad_ext_token;
1175 pdu->e_token_length = pdu->token[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1176 pdu->actual_token.length = pdu->e_token_length - 1;
1177 pdu->actual_token.s = &pdu->token[1];
1178 } else if (e_token_length == COAP_TOKEN_EXT_2B_TKL) {
1179 if (pdu->used_size < 2)
1180 goto bad_ext_token;
1181 pdu->e_token_length = ((uint16_t)pdu->token[0] << 8) + pdu->token[1] +
1183 pdu->actual_token.length = pdu->e_token_length - 2;
1184 pdu->actual_token.s = &pdu->token[2];
1185 }
1186 if (pdu->e_token_length > pdu->alloc_size || e_token_length == 15) {
1187 goto bad_ext_token;
1188 }
1189 return 1;
1190
1191bad_ext_token:
1192 /* Invalid PDU provided - not wise to assert here though */
1193 coap_log_debug("coap_pdu_parse: PDU header extended token size broken\n");
1194 pdu->e_token_length = 0;
1195 pdu->actual_token.length = 0;
1196 return 0;
1197}
1198
1199static int
1201 switch ((coap_pdu_signaling_proto_t)pdu->code) {
1202 case COAP_SIGNALING_CSM:
1203 switch (pdu->max_opt) {
1205 if (len > 4)
1206 goto bad;
1207 break;
1209 if (len > 0)
1210 goto bad;
1211 break;
1213 if (len > 3)
1214 goto bad;
1215 break;
1216 default:
1217 if (pdu->max_opt & 0x01)
1218 goto bad; /* Critical */
1219 }
1220 break;
1223 switch (pdu->max_opt) {
1225 if (len > 0)
1226 goto bad;
1227 break;
1228 default:
1229 if (pdu->max_opt & 0x01)
1230 goto bad; /* Critical */
1231 }
1232 break;
1234 switch (pdu->max_opt) {
1236 if (len < 1 || len > 255)
1237 goto bad;
1238 break;
1240 if (len > 3)
1241 goto bad;
1242 break;
1243 default:
1244 if (pdu->max_opt & 0x01)
1245 goto bad; /* Critical */
1246 }
1247 break;
1249 switch (pdu->max_opt) {
1251 if (len > 2)
1252 goto bad;
1253 break;
1254 default:
1255 if (pdu->max_opt & 0x01)
1256 goto bad; /* Critical */
1257 }
1258 break;
1259 default:
1260 ;
1261 }
1262 return 1;
1263bad:
1264 return 0;
1265}
1266
1267int
1268coap_pdu_parse_opt_base(coap_option_num_t number, size_t len, const uint8_t *opt_val) {
1269 int res = 1;
1270
1271 switch (number) {
1273 if (len > 8)
1274 res = 0;
1275 break;
1277 if (len < 1 || len > 255)
1278 res = 0;
1279 break;
1280 case COAP_OPTION_ETAG:
1281 if (len < 1 || len > 8)
1282 res = 0;
1283 break;
1285 if (len != 0)
1286 res = 0;
1287 break;
1289 if (len > 3)
1290 res = 0;
1291 break;
1293 if (len > 2)
1294 res = 0;
1295 break;
1298 if (len > 255)
1299 res = 0;
1300 if (coap_check_dots(opt_val, len)) {
1301 res = 0;
1302 }
1303 break;
1304 case COAP_OPTION_OSCORE:
1305 if (len > 255)
1306 res = 0;
1307 break;
1309 if (len > 2)
1310 res = 0;
1311 break;
1312 case COAP_OPTION_MAXAGE:
1313 if (len > 4)
1314 res = 0;
1315 break;
1317 if (len < 1 || len > 255)
1318 res = 0;
1319 break;
1321 if (len != 1)
1322 res = 0;
1323 break;
1324 case COAP_OPTION_ACCEPT:
1325 if (len > 2)
1326 res = 0;
1327 break;
1329 if (len > 3)
1330 res = 0;
1331 break;
1333 if (len > 255)
1334 res = 0;
1335 break;
1336 case COAP_OPTION_EDHOC:
1337 if (len != 0)
1338 res = 0;
1339 break;
1340 case COAP_OPTION_BLOCK2:
1341 if (len > 3)
1342 res = 0;
1343 break;
1344 case COAP_OPTION_BLOCK1:
1345 if (len > 3)
1346 res = 0;
1347 break;
1348 case COAP_OPTION_SIZE2:
1349 if (len > 4)
1350 res = 0;
1351 break;
1353 if (len > 3)
1354 res = 0;
1355 break;
1357 if (len < 1 || len > 1034)
1358 res = 0;
1359 break;
1361 if (len < 1 || len > 255)
1362 res = 0;
1363 break;
1364 case COAP_OPTION_SIZE1:
1365 if (len > 4)
1366 res = 0;
1367 break;
1368 case COAP_OPTION_ECHO:
1369 if (len > 40)
1370 res = 0;
1371 break;
1373 if (len > 1)
1374 res = 0;
1375 break;
1376 case COAP_OPTION_RTAG:
1377 if (len > 8)
1378 res = 0;
1379 break;
1380 default:
1381 ;
1382 }
1383 return res;
1384}
1385
1386static int
1387write_prefix(char **obp, size_t *len, const char *prf, size_t prflen) {
1388 /* Make sure space for null terminating byte */
1389 if (*len < prflen +1) {
1390 return 0;
1391 }
1392
1393 memcpy(*obp, prf, prflen);
1394 *obp += prflen;
1395 *len -= prflen;
1396 return 1;
1397}
1398
1399static int
1400write_char(char **obp, size_t *len, int c, int printable) {
1401 /* Make sure space for null terminating byte */
1402 if (*len < 2 +1) {
1403 return 0;
1404 }
1405
1406 if (!printable) {
1407 const uint8_t hex[] = "0123456789abcdef";
1408 (*obp)[0] = hex[(c & 0xf0) >> 4];
1409 (*obp)[1] = hex[c & 0x0f];
1410 } else {
1411 (*obp)[0] = isprint(c) ? c : '.';
1412 (*obp)[1] = ' ';
1413 }
1414 *obp += 2;
1415 *len -= 2;
1416 return 1;
1417}
1418
1419int
1421 int good = 1;
1422
1423 coap_option_filter_clear(error_opts);
1424
1425 /* sanity checks */
1426 if (pdu->code == 0) {
1427 if (pdu->used_size != 0 || pdu->e_token_length) {
1428 coap_log_debug("coap_pdu_parse: empty message is not empty\n");
1429 return 0;
1430 }
1431 }
1432
1433 if (pdu->e_token_length > pdu->used_size) {
1434 coap_log_debug("coap_pdu_parse: invalid Token\n");
1435 return 0;
1436 }
1437
1438 pdu->max_opt = 0;
1439 if (pdu->code == 0) {
1440 /* empty packet */
1441 pdu->used_size = 0;
1442 pdu->data = NULL;
1443 } else {
1444 /* skip header + token */
1445 coap_opt_t *opt = pdu->token + pdu->e_token_length;
1446 size_t length = pdu->used_size - pdu->e_token_length;
1447
1448 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1449#if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN)
1450 coap_opt_t *opt_last = opt;
1451#endif
1452 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1453 uint32_t len;
1454 const uint8_t *opt_val;
1455
1456 if (optsize == 0) {
1457 coap_log_debug("coap_pdu_parse: %d.%02d: offset %u malformed option\n",
1458 pdu->code >> 5, pdu->code & 0x1F,
1459 (int)(opt_last - pdu->token - pdu->e_token_length));
1460 coap_option_filter_set(error_opts, pdu->max_opt);
1461 good = 0;
1462 break;
1463 }
1464 len = coap_opt_length((const uint8_t *)opt - optsize);
1465 opt_val = coap_opt_value((const uint8_t *)opt - optsize);
1466 if (COAP_PDU_IS_SIGNALING(pdu) ?
1467 !coap_pdu_parse_opt_csm(pdu, len) :
1468 !coap_pdu_parse_opt_base(pdu->max_opt, len, opt_val)) {
1469 coap_log_warn("coap_pdu_parse: %d.%02d: offset %u option %u has bad length %" PRIu32 " or value\n",
1470 pdu->code >> 5, pdu->code & 0x1F,
1471 (int)(opt_last - pdu->token - pdu->e_token_length), pdu->max_opt,
1472 len);
1473 coap_option_filter_set(error_opts, pdu->max_opt);
1474 good = 0;
1475 }
1476 }
1477
1478 if (!good) {
1479 /*
1480 * Dump the options in the PDU for analysis, space separated except
1481 * error options which are prefixed by *
1482 * Two rows - hex and ascii (if printable)
1483 */
1484 static char outbuf[COAP_DEBUG_BUF_SIZE];
1485 char *obp;
1486 size_t tlen;
1487 size_t outbuflen;
1488 int i;
1489 int ok;
1490
1491 for (i = 0; i < 2; i++) {
1492 opt = pdu->token + pdu->e_token_length;
1493 length = pdu->used_size - pdu->e_token_length;
1494 pdu->max_opt = 0;
1495
1496 outbuflen = sizeof(outbuf);
1497 obp = outbuf;
1498 ok = write_prefix(&obp, &outbuflen, "O: ", 3);
1499 /*
1500 * Not safe to check for 'ok' here as a lot of variables may get
1501 * partially changed due to lack of outbuflen */
1502 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1503 coap_opt_t *opt_last = opt;
1504 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1505 const uint32_t len =
1506 optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1507 const uint8_t *opt_val =
1508 optsize ? coap_opt_value((const uint8_t *)opt - optsize) : 0;
1509
1510 if (!optsize || (COAP_PDU_IS_SIGNALING(pdu) ?
1511 !coap_pdu_parse_opt_csm(pdu, len) :
1512 !coap_pdu_parse_opt_base(pdu->max_opt, len, opt_val))) {
1513 ok = ok && write_prefix(&obp, &outbuflen, "*", 1);
1514 if (!optsize) {
1515 /* Skip to end of options to output all data */
1516 opt = pdu->token + pdu->used_size;
1517 length = 0;
1518 }
1519 } else {
1520 ok = ok && write_prefix(&obp, &outbuflen, " ", 1);
1521 }
1522 tlen = opt - opt_last;
1523 while (tlen) {
1524 tlen--;
1525 ok = ok && write_char(&obp, &outbuflen, *opt_last, i);
1526 opt_last++;
1527 }
1528 }
1529 if (length && *opt == COAP_PAYLOAD_START) {
1530 write_char(&obp, &outbuflen, *opt, i);
1531 }
1532 /* write_*() always leaves a spare byte to null terminate */
1533 *obp = '\000';
1534 coap_log_debug("%s\n", outbuf);
1535 }
1536 }
1537
1538 if (length > 0) {
1539 assert(*opt == COAP_PAYLOAD_START);
1540 opt++;
1541 length--;
1542
1543 if (length == 0) {
1544 coap_log_debug("coap_pdu_parse: message ending in payload start marker\n");
1545 return 0;
1546 }
1547 }
1548 if (length > 0)
1549 pdu->data = (uint8_t *)opt;
1550 else
1551 pdu->data = NULL;
1552 }
1553
1554 return good;
1555}
1556
1557int
1559 const uint8_t *data,
1560 size_t length,
1561 coap_pdu_t *pdu) {
1562 coap_opt_filter_t error_opts;
1563
1564 return coap_pdu_parse2(proto, data, length, pdu, &error_opts);
1565}
1566
1567int
1569 const uint8_t *data,
1570 size_t length,
1571 coap_pdu_t *pdu,
1572 coap_opt_filter_t *error_opts) {
1573 size_t hdr_size;
1574
1575 if (length == 0)
1576 return 0;
1577 hdr_size = coap_pdu_parse_header_size(proto, data);
1578 if (!hdr_size || hdr_size > length)
1579 return 0;
1580 if (hdr_size > pdu->max_hdr_size)
1581 return 0;
1582 if (!coap_pdu_resize(pdu, length - hdr_size))
1583 return 0;
1584 if (pdu->token - hdr_size != data)
1585 memcpy(pdu->token - hdr_size, data, length);
1586 pdu->hdr_size = (uint8_t)hdr_size;
1587 pdu->used_size = length - hdr_size;
1588 return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu, error_opts);
1589}
1590
1591size_t
1593 uint8_t e_token_length;
1594
1596 e_token_length = (uint8_t)pdu->actual_token.length;
1597 } else if (pdu->actual_token.length < COAP_TOKEN_EXT_2B_BIAS) {
1598 e_token_length = COAP_TOKEN_EXT_1B_TKL;
1599 } else if (pdu->actual_token.length <= COAP_TOKEN_EXT_MAX) {
1600 e_token_length = COAP_TOKEN_EXT_2B_TKL;
1601 } else {
1602 coap_log_warn("coap_pdu_encode_header: Token size too large. PDU ignored\n");
1603 return 0;
1604 }
1605 if (COAP_PROTO_NOT_RELIABLE(proto)) {
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 UDP-style header\n");
1609 return 0;
1610 }
1611 pdu->token[-4] = COAP_DEFAULT_VERSION << 6
1612 | pdu->type << 4
1613 | e_token_length;
1614 pdu->token[-3] = pdu->code;
1615 pdu->token[-2] = (uint8_t)(pdu->mid >> 8);
1616 pdu->token[-1] = (uint8_t)(pdu->mid);
1617 pdu->hdr_size = 4;
1618#if !COAP_DISABLE_TCP
1619 } else if (COAP_PROTO_RELIABLE(proto)) {
1620 size_t len;
1621 assert(pdu->used_size >= pdu->e_token_length);
1622 if (pdu->used_size < pdu->e_token_length) {
1623 coap_log_warn("coap_pdu_encode_header: corrupted PDU\n");
1624 return 0;
1625 }
1626
1627 /* A lot of the reliable code assumes type is CON */
1628 if (pdu->type != COAP_MESSAGE_CON)
1629 pdu->type = COAP_MESSAGE_CON;
1630
1631 if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS)
1632 len = 0;
1633 else
1634 len = pdu->used_size - pdu->e_token_length;
1635 if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
1636 assert(pdu->max_hdr_size >= 2);
1637 if (pdu->max_hdr_size < 2) {
1638 coap_log_warn("coap_pdu_encode_header: not enough space for TCP0 header\n");
1639 return 0;
1640 }
1641 pdu->token[-2] = (uint8_t)len << 4
1642 | e_token_length;
1643 pdu->token[-1] = pdu->code;
1644 pdu->hdr_size = 2;
1645 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
1646 assert(pdu->max_hdr_size >= 3);
1647 if (pdu->max_hdr_size < 3) {
1648 coap_log_warn("coap_pdu_encode_header: not enough space for TCP8 header\n");
1649 return 0;
1650 }
1651 pdu->token[-3] = 13 << 4 | e_token_length;
1652 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
1653 pdu->token[-1] = pdu->code;
1654 pdu->hdr_size = 3;
1655 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
1656 assert(pdu->max_hdr_size >= 4);
1657 if (pdu->max_hdr_size < 4) {
1658 coap_log_warn("coap_pdu_encode_header: not enough space for TCP16 header\n");
1659 return 0;
1660 }
1661 pdu->token[-4] = 14 << 4 | e_token_length;
1662 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
1663 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
1664 pdu->token[-1] = pdu->code;
1665 pdu->hdr_size = 4;
1666 } else {
1667 assert(pdu->max_hdr_size >= 6);
1668 if (pdu->max_hdr_size < 6) {
1669 coap_log_warn("coap_pdu_encode_header: not enough space for TCP32 header\n");
1670 return 0;
1671 }
1672 pdu->token[-6] = 15 << 4 | e_token_length;
1673 pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
1674 pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
1675 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
1676 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
1677 pdu->token[-1] = pdu->code;
1678 pdu->hdr_size = 6;
1679 }
1680#endif /* ! COAP_DISABLE_TCP */
1681 } else {
1682 coap_log_warn("coap_pdu_encode_header: unsupported protocol\n");
1683 }
1684 return pdu->hdr_size;
1685}
1686
1689 return pdu->code;
1690}
1691
1692void
1694#ifndef RIOT_VERSION
1695 assert(code <= 0xff);
1696#endif /* RIOT_VERSION */
1697 pdu->code = code;
1698}
1699
1702 return pdu->type;
1703}
1704
1705void
1707 assert(type <= 0x3);
1708 pdu->type = type;
1709}
1710
1713 return pdu->actual_token;
1714}
1715
1718 return pdu->mid;
1719}
1720
1721void
1723#if (UINT_MAX > 65535)
1724 assert(mid >= 0 && mid <= 0xffff);
1725#endif /* UINT_MAX > 65535 */
1726 pdu->mid = mid;
1727}
1728
1729coap_pdu_t *
1731 if (pdu != NULL) {
1732 ++pdu->ref;
1733 }
1734 return pdu;
1735}
1736
1737coap_pdu_t *
1739 coap_pdu_t *pdu_rw = NULL;
1740
1741 if (pdu != NULL) {
1742
1743 /* Need to do this to not get a compiler warning about const parameters */
1744 memcpy(&pdu_rw, &pdu, sizeof(pdu_rw));
1745 ++pdu_rw->ref;
1746 }
1747 return pdu_rw;
1748}
#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:1031
static int coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len)
Definition coap_pdu.c:1200
error_desc_t coap_error[]
Definition coap_pdu.c:983
static int write_prefix(char **obp, size_t *len, const char *prf, size_t prflen)
Definition coap_pdu.c:1387
#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:1400
#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.
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
#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:1730
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:195
#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:685
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:544
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:468
#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:1420
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:1139
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:1055
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:174
int coap_pdu_parse_opt_base(coap_option_num_t number, size_t len, const uint8_t *opt_val)
Check the length / data (if appropriate) of an option.
Definition coap_pdu.c:1268
#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:638
#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
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, coap_bool_t expand_opt_abb)
Duplicate an existing PDU.
Definition coap_pdu.c:235
#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:784
#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:1592
#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:1568
#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:394
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:1086
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:1738
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:339
#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:844
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:136
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:149
#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:1688
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:141
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition coap_pdu.c:1015
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:130
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition coap_pdu.h:209
#define COAP_OPTION_SIZE2
Definition coap_pdu.h:143
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:142
#define COAP_OPTION_Q_BLOCK1
Definition coap_pdu.h:138
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:146
COAP_API void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:188
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:921
coap_bool_t
Definition coap_pdu.h:377
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:135
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:1693
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:267
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:213
#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:203
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:164
coap_proto_t
CoAP protocol types Note: coap_layers_coap[] needs updating if extended.
Definition coap_pdu.h:317
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:331
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:128
#define COAP_OPTION_SIZE1
Definition coap_pdu.h:147
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:202
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:411
#define COAP_OPTION_LOCATION_QUERY
Definition coap_pdu.h:139
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:1706
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:830
#define COAP_OPTION_Q_BLOCK2
Definition coap_pdu.h:144
#define COAP_SIGNALING_OPTION_CUSTODY
Definition coap_pdu.h:206
coap_pdu_signaling_proto_t
Definition coap_pdu.h:192
coap_pdu_type_t coap_pdu_get_type(const coap_pdu_t *pdu)
Gets the PDU type associated with pdu.
Definition coap_pdu.c:1701
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:940
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:1558
#define COAP_MAX_OPT
the highest option number we know
Definition coap_pdu.h:155
void coap_pdu_set_mid(coap_pdu_t *pdu, coap_mid_t mid)
Sets the message id in the pdu.
Definition coap_pdu.c:1722
#define COAP_OPTION_RTAG
Definition coap_pdu.h:150
#define COAP_OPTION_URI_PATH_ABB
Definition coap_pdu.h:131
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:163
#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:140
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:137
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:948
#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:1717
#define COAP_OPTION_MAXAGE
Definition coap_pdu.h:134
#define COAP_OPTION_ETAG
Definition coap_pdu.h:123
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:145
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:125
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition coap_pdu.h:210
#define COAP_OPTION_ECHO
Definition coap_pdu.h:148
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition coap_pdu.h:213
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition coap_pdu.h:201
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:909
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1712
@ COAP_BOOL_FALSE
Definition coap_pdu.h:378
@ COAP_BOOL_TRUE
Definition coap_pdu.h:379
@ COAP_PROTO_WS
Definition coap_pdu.h:323
@ COAP_PROTO_DTLS
Definition coap_pdu.h:320
@ COAP_PROTO_UDP
Definition coap_pdu.h:319
@ COAP_PROTO_TLS
Definition coap_pdu.h:322
@ COAP_PROTO_WSS
Definition coap_pdu.h:324
@ COAP_PROTO_TCP
Definition coap_pdu.h:321
@ COAP_MESSAGE_CON
Definition coap_pdu.h:71
@ COAP_SIGNALING_RELEASE
Definition coap_pdu.h:196
@ COAP_SIGNALING_CSM
Definition coap_pdu.h:193
@ COAP_SIGNALING_PONG
Definition coap_pdu.h:195
@ COAP_SIGNALING_PING
Definition coap_pdu.h:194
@ COAP_SIGNALING_ABORT
Definition coap_pdu.h:197
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
int coap_check_dots(const uint8_t *s, size_t len)
Checks if path segment s consists of one or two dots.
Definition coap_uri.c:668
coap_upa_chain_t * coap_upa_server_mapping_chain
Definition coap_uri.c:33
const char * coap_map_abbrev_uri_path(coap_upa_chain_t *chain, uint32_t value)
Determine the expanded Uri-Path-Abbrev option value.
Definition coap_uri.c:1154
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:977
const char * phrase
Definition coap_pdu.c:978