libcoap 4.3.4
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--2023 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
16#include "coap3/coap_internal.h"
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#ifdef HAVE_ARPA_INET_H
26#include <arpa/inet.h>
27#endif
28#ifdef HAVE_WINSOCK2_H
29#include <winsock2.h>
30#endif
31#include <ctype.h>
32
33#ifndef min
34#define min(a,b) ((a) < (b) ? (a) : (b))
35#endif
36
37#ifndef max
38#define max(a,b) ((a) > (b) ? (a) : (b))
39#endif
40
41void
42coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
43 assert(pdu);
44 assert(pdu->token);
46 if (pdu->alloc_size > size)
47 pdu->alloc_size = size;
48 pdu->type = 0;
49 pdu->code = 0;
50 pdu->hdr_size = 0;
51 pdu->actual_token.length = 0;
52 pdu->e_token_length = 0;
53 pdu->crit_opt = 0;
54 pdu->mid = 0;
55 pdu->max_opt = 0;
56 pdu->max_size = size;
57 pdu->used_size = 0;
58 pdu->data = NULL;
59 pdu->body_data = NULL;
60 pdu->body_length = 0;
61 pdu->body_offset = 0;
62 pdu->body_total = 0;
63 pdu->lg_xmit = NULL;
64 pdu->session = NULL;
65}
66
67#ifdef WITH_LWIP
69coap_pdu_from_pbuf(struct pbuf *pbuf) {
70 coap_pdu_t *pdu;
71
72 if (pbuf == NULL)
73 return NULL;
74
75 LWIP_ASSERT("Can only deal with contiguous PBUFs (increase PBUF_POOL_BUFSIZE)",
76 pbuf->tot_len == pbuf->len);
77 LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf",
78 pbuf->ref == 1);
79
80 pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
81 if (!pdu) {
82 pbuf_free(pbuf);
83 return NULL;
84 }
85
87 pdu->pbuf = pbuf;
88 pdu->token = (uint8_t *)pbuf->payload + pdu->max_hdr_size;
89 pdu->alloc_size = pbuf->tot_len - pdu->max_hdr_size;
90 coap_pdu_clear(pdu, pdu->alloc_size);
91
92 return pdu;
93}
94#endif /* LWIP */
95
98 size_t size) {
99 coap_pdu_t *pdu;
100
101 assert(type <= 0x3);
102 assert(code <= 0xff);
103 assert(mid >= 0 && mid <= 0xffff);
104
105#ifdef WITH_LWIP
106#if MEMP_STATS
107 /* Reserve 1 PDU for a response packet */
108 if (memp_pools[MEMP_COAP_PDU]->stats->used + 1 >=
109 memp_pools[MEMP_COAP_PDU]->stats->avail) {
110 memp_pools[MEMP_COAP_PDU]->stats->err++;
111 return NULL;
112 }
113#endif /* MEMP_STATS */
114#endif /* LWIP */
115 pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
116 if (!pdu)
117 return NULL;
118
119#if defined(WITH_CONTIKI) || defined(WITH_LWIP)
120 assert(size <= COAP_DEFAULT_MAX_PDU_RX_SIZE);
121 if (size > COAP_DEFAULT_MAX_PDU_RX_SIZE)
122 return NULL;
124#else
126#endif
127
128#ifdef WITH_LWIP
129 pdu->pbuf = pbuf_alloc(PBUF_TRANSPORT, size + pdu->max_hdr_size, PBUF_RAM);
130 if (pdu->pbuf == NULL) {
132 return NULL;
133 }
134 pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
135#else /* WITH_LWIP */
136 uint8_t *buf;
137 pdu->alloc_size = min(size, 256);
139 if (buf == NULL) {
141 return NULL;
142 }
143 pdu->token = buf + pdu->max_hdr_size;
144#endif /* WITH_LWIP */
145 coap_pdu_clear(pdu, size);
146 pdu->mid = mid;
147 pdu->type = type;
148 pdu->code = code;
149 return pdu;
150}
151
154 coap_session_t *session) {
155 coap_pdu_t *pdu = coap_pdu_init(type, code, coap_new_message_id(session),
157 if (!pdu)
158 coap_log_crit("coap_new_pdu: cannot allocate memory for new PDU\n");
159 return pdu;
160}
161
162void
164 if (pdu != NULL) {
165#ifdef WITH_LWIP
166 pbuf_free(pdu->pbuf);
167#else
168 if (pdu->token != NULL)
170#endif
172 }
173}
174
175/*
176 * Note: This does not include any data, just the token and options
177 */
180 coap_session_t *session,
181 size_t token_length,
182 const uint8_t *token,
183 coap_opt_filter_t *drop_options) {
184 uint8_t doing_first = session->doing_first;
185 coap_pdu_t *pdu;
186
187 /*
188 * Need to make sure that coap_session_max_pdu_size() immediately
189 * returns, rather than wait for the first CSM response from remote
190 * that indicates BERT size (TCP/TLS only) as this may be called early
191 * the OSCORE logic.
192 */
193 session->doing_first = 0;
194 pdu = coap_pdu_init(old_pdu->type, old_pdu->code,
195 coap_new_message_id(session),
196 max(old_pdu->max_size,
197 coap_session_max_pdu_size(session)));
198 /* Restore any pending waits */
199 session->doing_first = doing_first;
200 if (pdu == NULL)
201 return NULL;
202
203 coap_add_token(pdu, token_length, token);
204 pdu->lg_xmit = old_pdu->lg_xmit;
205
206 if (drop_options == NULL) {
207 /* Drop COAP_PAYLOAD_START as well if data */
208 size_t length = old_pdu->used_size - old_pdu->e_token_length -
209 (old_pdu->data ?
210 old_pdu->used_size - (old_pdu->data - old_pdu->token) +1 : 0);
211 if (!coap_pdu_resize(pdu, length + pdu->e_token_length))
212 goto fail;
213 /* Copy the options but not any data across */
214 memcpy(pdu->token + pdu->e_token_length,
215 old_pdu->token + old_pdu->e_token_length, length);
216 pdu->used_size += length;
217 pdu->max_opt = old_pdu->max_opt;
218 } else {
219 /* Copy across all the options the slow way */
220 coap_opt_iterator_t opt_iter;
221 coap_opt_t *option;
222
223 coap_option_iterator_init(old_pdu, &opt_iter, COAP_OPT_ALL);
224 while ((option = coap_option_next(&opt_iter))) {
225 if (drop_options && coap_option_filter_get(drop_options, opt_iter.number))
226 continue;
227 if (!coap_add_option_internal(pdu, opt_iter.number,
228 coap_opt_length(option),
229 coap_opt_value(option)))
230 goto fail;
231 }
232 }
233 return pdu;
234
235fail:
236 coap_delete_pdu(pdu);
237 return NULL;
238}
239
240
241/*
242 * The new size does not include the coap header (max_hdr_size)
243 */
244int
245coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
246 if (new_size > pdu->alloc_size) {
247 /* Expanding the PDU usage */
248#if !defined(WITH_LWIP)
249 uint8_t *new_hdr;
250 size_t offset;
251#endif
252
253 if (pdu->max_size && new_size > pdu->max_size) {
254 coap_log_warn("coap_pdu_resize: pdu too big\n");
255 return 0;
256 }
257#if !defined(WITH_LWIP)
258 if (pdu->data != NULL) {
259 assert(pdu->data > pdu->token);
260 offset = pdu->data - pdu->token;
261 } else {
262 offset = 0;
263 }
264 new_hdr = (uint8_t *)coap_realloc_type(COAP_PDU_BUF,
265 pdu->token - pdu->max_hdr_size,
266 new_size + pdu->max_hdr_size);
267 if (new_hdr == NULL) {
268 coap_log_warn("coap_pdu_resize: realloc failed\n");
269 return 0;
270 }
271 pdu->token = new_hdr + pdu->max_hdr_size;
272 if (offset > 0)
273 pdu->data = pdu->token + offset;
274 else
275 pdu->data = NULL;
277 pdu->actual_token.s = &pdu->token[0];
279 pdu->actual_token.s = &pdu->token[1];
280 else
281 pdu->actual_token.s = &pdu->token[2];
282#endif
283 pdu->alloc_size = new_size;
284 }
285 return 1;
286}
287
288int
290 if (size > pdu->alloc_size) {
291 size_t new_size = max(256, pdu->alloc_size * 2);
292 while (size > new_size)
293 new_size *= 2;
294 if (pdu->max_size && new_size > pdu->max_size) {
295 new_size = pdu->max_size;
296 if (new_size < size)
297 return 0;
298 }
299 if (!coap_pdu_resize(pdu, new_size))
300 return 0;
301 }
302 return 1;
303}
304
305int
306coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
307 size_t bias = 0;
308
309 /* must allow for pdu == NULL as callers may rely on this */
310 if (!pdu)
311 return 0;
312
313 if (pdu->used_size) {
314 coap_log_warn("coap_add_token: The token must defined first. Token ignored\n");
315 return 0;
316 }
317 pdu->actual_token.length = len;
318 if (len < COAP_TOKEN_EXT_1B_BIAS) {
319 bias = 0;
320 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
321 bias = 1;
322 } else if (len <= COAP_TOKEN_EXT_MAX) {
323 bias = 2;
324 } else {
325 coap_log_warn("coap_add_token: Token size too large. Token ignored\n");
326 return 0;
327 }
328 if (!coap_pdu_check_resize(pdu, len + bias)) {
329 coap_log_warn("coap_add_token: Insufficient space for token. Token ignored\n");
330 return 0;
331 }
332
333 pdu->actual_token.length = len;
334 pdu->actual_token.s = &pdu->token[bias];
335 pdu->e_token_length = (uint32_t)(len + bias);
336 if (len) {
337 switch (bias) {
338 case 0:
339 memcpy(pdu->token, data, len);
340 break;
341 case 1:
342 pdu->token[0] = (uint8_t)(len - COAP_TOKEN_EXT_1B_BIAS);
343 memcpy(&pdu->token[1], data, len);
344 break;
345 case 2:
346 pdu->token[0] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) >> 8);
347 pdu->token[1] = (uint8_t)((len - COAP_TOKEN_EXT_2B_BIAS) & 0xff);
348 memcpy(&pdu->token[2], data, len);
349 break;
350 default:
351 break;
352 }
353 }
354 pdu->max_opt = 0;
355 pdu->used_size = len + bias;
356 pdu->data = NULL;
357
358 return 1;
359}
360
361/* It is assumed that coap_encode_var_safe8() has been called to reduce data */
362int
363coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
364 size_t bias = 0;
365
366 /* must allow for pdu == NULL as callers may rely on this */
367 if (!pdu)
368 return 0;
369
370 if (pdu->used_size == 0) {
371 return coap_add_token(pdu, len, data);
372 }
373 if (len < COAP_TOKEN_EXT_1B_BIAS) {
374 bias = 0;
375 } else if (len < COAP_TOKEN_EXT_2B_BIAS) {
376 bias = 1;
377 } else if (len <= COAP_TOKEN_EXT_MAX) {
378 bias = 2;
379 } else {
380 coap_log_warn("coap_add_token: Token size too large. Token ignored\n");
381 return 0;
382 }
383 if ((len + bias) == pdu->e_token_length) {
384 /* Easy case - just data has changed */
385 } else if ((len + bias) > pdu->e_token_length) {
386 if (!coap_pdu_check_resize(pdu,
387 pdu->used_size + (len + bias) - pdu->e_token_length)) {
388 coap_log_warn("Failed to update token\n");
389 return 0;
390 }
391 memmove(&pdu->token[(len + bias) - pdu->e_token_length],
392 pdu->token, pdu->used_size);
393 pdu->used_size += len + bias - pdu->e_token_length;
394 if (pdu->data) {
395 pdu->data += (len + bias) - pdu->e_token_length;
396 }
397 } else {
398 pdu->used_size -= pdu->e_token_length - (len + bias);
399 memmove(pdu->token, &pdu->token[pdu->e_token_length - (len + bias)], pdu->used_size);
400 if (pdu->data) {
401 pdu->data -= pdu->e_token_length - (len + bias);
402 }
403 }
404
405 pdu->actual_token.length = len;
406 pdu->actual_token.s = &pdu->token[bias];
407 pdu->e_token_length = (uint8_t)(len + bias);
408 if (len) {
409 switch (bias) {
410 case 0:
411 if (memcmp(pdu->token, data, len) != 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 return 1;
428}
429
430int
432 coap_opt_iterator_t opt_iter;
433 coap_opt_t *option;
434 coap_opt_t *next_option = NULL;
435 size_t opt_delta;
436 coap_option_t decode_this;
437 coap_option_t decode_next;
438
439 /* Need to locate where in current options to remove this one */
441 while ((option = coap_option_next(&opt_iter))) {
442 if (opt_iter.number == number) {
443 /* Found option to delete */
444 break;
445 }
446 }
447 if (!option)
448 return 0;
449
450 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token),
451 &decode_this))
452 return 0;
453
454 next_option = coap_option_next(&opt_iter);
455 if (next_option) {
456 if (!coap_opt_parse(next_option,
457 pdu->used_size - (next_option - pdu->token),
458 &decode_next))
459 return 0;
460 opt_delta = decode_this.delta + decode_next.delta;
461 if (opt_delta < 13) {
462 /* can simply update the delta of next option */
463 next_option[0] = (next_option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
464 } else if (opt_delta < 269 && decode_next.delta < 13) {
465 /* next option delta size increase */
466 next_option -= 1;
467 next_option[0] = (next_option[1] & 0x0f) + (13 << 4);
468 next_option[1] = (coap_opt_t)(opt_delta - 13);
469 } else if (opt_delta < 269) {
470 /* can simply update the delta of next option */
471 next_option[1] = (coap_opt_t)(opt_delta - 13);
472 } else if (decode_next.delta < 13) { /* opt_delta >= 269 */
473 /* next option delta size increase */
474 if (next_option - option < 2) {
475 /* Need to shuffle everything up by 1 before decrement */
476 if (!coap_pdu_check_resize(pdu, pdu->used_size + 1))
477 return 0;
478 /* Possible a re-size took place with a realloc() */
479 /* Need to rediscover this and next options */
481 while ((option = coap_option_next(&opt_iter))) {
482 if (opt_iter.number == number) {
483 /* Found option to delete */
484 break;
485 }
486 }
487 next_option = coap_option_next(&opt_iter);
488 assert(option != NULL);
489 assert(next_option != NULL);
490 memmove(&next_option[1], next_option,
491 pdu->used_size - (next_option - pdu->token));
492 pdu->used_size++;
493 if (pdu->data)
494 pdu->data++;
495 next_option++;
496 }
497 next_option -= 2;
498 next_option[0] = (next_option[2] & 0x0f) + (14 << 4);
499 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
500 next_option[2] = (opt_delta - 269) & 0xff;
501 } else if (decode_next.delta < 269) { /* opt_delta >= 269 */
502 /* next option delta size increase */
503 next_option -= 1;
504 next_option[0] = (next_option[1] & 0x0f) + (14 << 4);
505 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
506 next_option[2] = (opt_delta - 269) & 0xff;
507 } else { /* decode_next.delta >= 269 && opt_delta >= 269 */
508 next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
509 next_option[2] = (opt_delta - 269) & 0xff;
510 }
511 } else {
512 next_option = option + coap_opt_encode_size(decode_this.delta,
513 coap_opt_length(option));
514 pdu->max_opt -= decode_this.delta;
515 }
516 if (pdu->used_size - (next_option - pdu->token))
517 memmove(option, next_option, pdu->used_size - (next_option - pdu->token));
518 pdu->used_size -= next_option - option;
519 if (pdu->data)
520 pdu->data -= next_option - option;
521 return 1;
522}
523
524int
526 /* Validate that the option is repeatable */
527 switch (number) {
528 /* Ignore list of genuine repeatable */
530 case COAP_OPTION_ETAG:
535 case COAP_OPTION_RTAG:
536 break;
537 /* Protest at the known non-repeatable options and ignore them */
553 case COAP_OPTION_ECHO:
555 coap_log_info("Option number %d is not defined as repeatable - dropped\n",
556 number);
557 return 0;
558 default:
559 coap_log_info("Option number %d is not defined as repeatable\n",
560 number);
561 /* Accepting it after warning as there may be user defineable options */
562 break;
563 }
564 return 1;
565}
566
567size_t
569 const uint8_t *data) {
570 coap_opt_iterator_t opt_iter;
571 coap_opt_t *option;
572 uint16_t prev_number = 0;
573 size_t shift;
574 size_t opt_delta;
575 coap_option_t decode;
576 size_t shrink = 0;
577
578 if (number >= pdu->max_opt)
579 return coap_add_option_internal(pdu, number, len, data);
580
581 /* Need to locate where in current options to insert this one */
583 while ((option = coap_option_next(&opt_iter))) {
584 if (opt_iter.number > number) {
585 /* Found where to insert */
586 break;
587 }
588 prev_number = opt_iter.number;
589 }
590 if (option == NULL) {
591 /* Code is broken somewhere */
592 coap_log_warn("coap_insert_option: Broken max_opt\n");
593 return 0;
594 }
595
596 /* size of option inc header to insert */
597 shift = coap_opt_encode_size(number - prev_number, len);
598
599 /* size of next option (header may shrink in size as delta changes */
600 if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token), &decode))
601 return 0;
602 opt_delta = opt_iter.number - number;
603 if (opt_delta == 0) {
604 if (!coap_option_check_repeatable(number))
605 return 0;
606 }
607
608 if (!coap_pdu_check_resize(pdu,
609 pdu->used_size + shift - shrink))
610 return 0;
611
612 /* Possible a re-size took place with a realloc() */
613 /* Need to locate where in current options to insert this one */
615 while ((option = coap_option_next(&opt_iter))) {
616 if (opt_iter.number > number) {
617 /* Found where to insert */
618 break;
619 }
620 }
621 assert(option != NULL);
622
623 if (decode.delta < 13) {
624 /* can simply patch in the new delta of next option */
625 option[0] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
626 } else if (decode.delta < 269 && opt_delta < 13) {
627 /* option header is going to shrink by one byte */
628 option[1] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
629 shrink = 1;
630 } else if (decode.delta < 269 && opt_delta < 269) {
631 /* can simply patch in the new delta of next option */
632 option[1] = (coap_opt_t)(opt_delta - 13);
633 } else if (opt_delta < 13) {
634 /* option header is going to shrink by two bytes */
635 option[2] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
636 shrink = 2;
637 } else if (opt_delta < 269) {
638 /* option header is going to shrink by one bytes */
639 option[1] = (option[0] & 0x0f) + 0xd0;
640 option[2] = (coap_opt_t)(opt_delta - 13);
641 shrink = 1;
642 } else {
643 /* can simply patch in the new delta of next option */
644 option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
645 option[2] = (opt_delta - 269) & 0xff;
646 }
647
648 memmove(&option[shift], &option[shrink],
649 pdu->used_size - (option - pdu->token) - shrink);
650 if (!coap_opt_encode(option, pdu->alloc_size - pdu->used_size,
651 number - prev_number, data, len))
652 return 0;
653
654 if (shift >= shrink) {
655 pdu->used_size += shift - shrink;
656 if (pdu->data)
657 pdu->data += shift - shrink;
658 } else {
659 pdu->used_size -= shrink - shift;
660 if (pdu->data)
661 pdu->data -= shrink - shift;
662 }
663 return shift;
664}
665
666size_t
668 const uint8_t *data) {
669 coap_opt_iterator_t opt_iter;
670 coap_opt_t *option;
671 coap_option_t decode;
672 size_t new_length = 0;
673 size_t old_length = 0;
674
675 option = coap_check_option(pdu, number, &opt_iter);
676 if (!option)
677 return coap_insert_option(pdu, number, len, data);
678
679 old_length = coap_opt_parse(option, (size_t)-1, &decode);
680 if (old_length == 0)
681 return 0;
682 new_length = coap_opt_encode_size(decode.delta, len);
683
684 if (new_length > old_length) {
685 if (!coap_pdu_check_resize(pdu,
686 pdu->used_size + new_length - old_length))
687 return 0;
688 /* Possible a re-size took place with a realloc() */
689 option = coap_check_option(pdu, number, &opt_iter);
690 }
691
692 if (new_length != old_length)
693 memmove(&option[new_length], &option[old_length],
694 pdu->used_size - (option - pdu->token) - old_length);
695
696 if (!coap_opt_encode(option, new_length,
697 decode.delta, data, len))
698 return 0;
699
700 if (new_length >= old_length) {
701 pdu->used_size += new_length - old_length;
702 if (pdu->data)
703 pdu->data += new_length - old_length;
704 } else {
705 pdu->used_size -= old_length - new_length;
706 if (pdu->data)
707 pdu->data -= old_length - new_length;
708 }
709 return 1;
710}
711
712size_t
714 const uint8_t *data) {
715 if (pdu->data) {
716 coap_log_warn("coap_add_optlist_pdu: PDU already contains data\n");
717 return 0;
718 }
719 return coap_add_option_internal(pdu, number, len, data);
720}
721
722size_t
724 const uint8_t *data) {
725 size_t optsize;
726 coap_opt_t *opt;
727
728 assert(pdu);
729
730 if (number == pdu->max_opt) {
731 if (!coap_option_check_repeatable(number))
732 return 0;
733 }
734
735 if (COAP_PDU_IS_REQUEST(pdu) &&
736 (number == COAP_OPTION_PROXY_URI ||
737 number == COAP_OPTION_PROXY_SCHEME)) {
738 /*
739 * Need to check whether there is a hop-limit option. If not, it needs
740 * to be inserted by default (RFC 8768).
741 */
742 coap_opt_iterator_t opt_iter;
743
744 if (coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter) == NULL) {
745 size_t hop_limit = COAP_OPTION_HOP_LIMIT;
746
747 coap_insert_option(pdu, COAP_OPTION_HOP_LIMIT, 1, (uint8_t *)&hop_limit);
748 }
749 }
750
751 if (number < pdu->max_opt) {
752 coap_log_debug("coap_add_option: options are not in correct order\n");
753 return coap_insert_option(pdu, number, len, data);
754 }
755
756 optsize = coap_opt_encode_size(number - pdu->max_opt, len);
757 if (!coap_pdu_check_resize(pdu,
758 pdu->used_size + optsize))
759 return 0;
760
761 if (pdu->data) {
762 /* include option delimiter */
763 memmove(&pdu->data[optsize-1], &pdu->data[-1],
764 pdu->used_size - (pdu->data - pdu->token) + 1);
765 opt = pdu->data -1;
766 pdu->data += optsize;
767 } else {
768 opt = pdu->token + pdu->used_size;
769 }
770
771 /* encode option and check length */
772 optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
773 number - pdu->max_opt, data, len);
774
775 if (!optsize) {
776 coap_log_warn("coap_add_option: cannot add option\n");
777 /* error */
778 return 0;
779 } else {
780 pdu->max_opt = number;
781 pdu->used_size += optsize;
782 }
783
784 return optsize;
785}
786
787int
788coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
789 if (len == 0) {
790 return 1;
791 } else {
792 uint8_t *payload = coap_add_data_after(pdu, len);
793 if (payload != NULL)
794 memcpy(payload, data, len);
795 return payload != NULL;
796 }
797}
798
799uint8_t *
801 assert(pdu);
802 if (pdu->data) {
803 coap_log_warn("coap_add_data: PDU already contains data\n");
804 return 0;
805 }
806
807 if (len == 0)
808 return NULL;
809
810 if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
811 return 0;
812 pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
813 pdu->data = pdu->token + pdu->used_size;
814 pdu->used_size += len;
815 return pdu->data;
816}
817
818int
819coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data) {
820 size_t offset;
821 size_t total;
822
823 return coap_get_data_large(pdu, len, data, &offset, &total);
824}
825
826int
827coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data,
828 size_t *offset, size_t *total) {
829 assert(pdu);
830 assert(len);
831 assert(data);
832
833 *offset = pdu->body_offset;
834 *total = pdu->body_total;
835 if (pdu->body_data) {
836 *data = pdu->body_data;
837 *len = pdu->body_length;
838 return 1;
839 }
840 *data = pdu->data;
841 if (pdu->data == NULL) {
842 *len = 0;
843 *total = 0;
844 return 0;
845 }
846
847 *len = pdu->used_size - (pdu->data - pdu->token);
848 if (*total == 0)
849 *total = *len;
850
851 return 1;
852}
853
854#ifndef SHORT_ERROR_RESPONSE
855typedef struct {
856 unsigned char code;
857 const char *phrase;
859
860/* if you change anything here, make sure, that the longest string does not
861 * exceed COAP_ERROR_PHRASE_LENGTH. */
863 { COAP_RESPONSE_CODE(201), "Created" },
864 { COAP_RESPONSE_CODE(202), "Deleted" },
865 { COAP_RESPONSE_CODE(203), "Valid" },
866 { COAP_RESPONSE_CODE(204), "Changed" },
867 { COAP_RESPONSE_CODE(205), "Content" },
868 { COAP_RESPONSE_CODE(231), "Continue" },
869 { COAP_RESPONSE_CODE(400), "Bad Request" },
870 { COAP_RESPONSE_CODE(401), "Unauthorized" },
871 { COAP_RESPONSE_CODE(402), "Bad Option" },
872 { COAP_RESPONSE_CODE(403), "Forbidden" },
873 { COAP_RESPONSE_CODE(404), "Not Found" },
874 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
875 { COAP_RESPONSE_CODE(406), "Not Acceptable" },
876 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
877 { COAP_RESPONSE_CODE(409), "Conflict" },
878 { COAP_RESPONSE_CODE(412), "Precondition Failed" },
879 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
880 { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
881 { COAP_RESPONSE_CODE(422), "Unprocessable" },
882 { COAP_RESPONSE_CODE(429), "Too Many Requests" },
883 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
884 { COAP_RESPONSE_CODE(501), "Not Implemented" },
885 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
886 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
887 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
888 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
889 { COAP_RESPONSE_CODE(508), "Hop Limit Reached" },
890 { 0, NULL } /* end marker */
891};
892
893const char *
894coap_response_phrase(unsigned char code) {
895 int i;
896 for (i = 0; coap_error[i].code; ++i) {
897 if (coap_error[i].code == code)
898 return coap_error[i].phrase;
899 }
900 return NULL;
901}
902#endif
903
909static size_t
910next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt) {
911 coap_option_t option;
912 size_t optsize;
913
914 assert(optp);
915 assert(*optp);
916 assert(length);
917
918 optsize = coap_opt_parse(*optp, *length, &option);
919 if (optsize) {
920 assert(optsize <= *length);
921
922 /* signal an error if this option would exceed the
923 * allowed number space */
924 if (*max_opt + option.delta > COAP_MAX_OPT) {
925 return 0;
926 }
927 *max_opt += option.delta;
928 *optp += optsize;
929 *length -= optsize;
930 }
931
932 return optsize;
933}
934
935size_t
937 const uint8_t *data) {
938 assert(data);
939 size_t header_size = 0;
940
941 if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
942 uint8_t len = *data >> 4;
943 if (len < 13)
944 header_size = 2;
945 else if (len==13)
946 header_size = 3;
947 else if (len==14)
948 header_size = 4;
949 else
950 header_size = 6;
951 } else if (proto == COAP_PROTO_WS || proto==COAP_PROTO_WSS) {
952 header_size = 2;
953 } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
954 header_size = 4;
955 }
956
957 return header_size;
958}
959
960/*
961 * strm
962 * return +ve PDU size including token
963 * 0 PDU does not parse
964 */
965size_t
967 const uint8_t *data,
968 size_t length) {
969 assert(data);
970 assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS ||
971 proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS);
972 assert(coap_pdu_parse_header_size(proto, data) <= length);
973
974 size_t size = 0;
975 const uint8_t *token_start = NULL;
976
977 if ((proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) && length >= 1) {
978 uint8_t len = *data >> 4;
979 uint8_t tkl = *data & 0x0f;
980
981 if (len < 13) {
982 size = len;
983 token_start = &data[2];
984 } else if (length >= 2) {
985 if (len==13) {
986 size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
987 token_start = &data[3];
988 } else if (length >= 3) {
989 if (len==14) {
990 size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
991 token_start = &data[4];
992 } else if (length >= 5) {
993 size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
994 + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
995 token_start = &data[6];
996 }
997 }
998 }
999 if (token_start) {
1000 /* account for the token length */
1001 if (tkl < COAP_TOKEN_EXT_1B_TKL) {
1002 size += tkl;
1003 } else if (tkl == COAP_TOKEN_EXT_1B_TKL) {
1004 size += token_start[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1005 } else if (tkl == COAP_TOKEN_EXT_2B_TKL) {
1006 size += ((uint16_t)token_start[0] << 8) + token_start[1] +
1008 } else {
1009 /* Invalid at this point - caught later as undersized */
1010 }
1011 }
1012 }
1013
1014 return size;
1015}
1016
1017int
1019 uint8_t *hdr = pdu->token - pdu->hdr_size;
1020 uint8_t e_token_length;
1021
1022 if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
1023 assert(pdu->hdr_size == 4);
1024 if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
1025 coap_log_debug("coap_pdu_parse: UDP version not supported\n");
1026 return 0;
1027 }
1028 pdu->type = (hdr[0] >> 4) & 0x03;
1029 pdu->code = hdr[1];
1030 pdu->mid = (uint16_t)hdr[2] << 8 | hdr[3];
1031 } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
1032 assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
1033 pdu->type = COAP_MESSAGE_CON;
1034 pdu->code = hdr[pdu->hdr_size-1];
1035 pdu->mid = 0;
1036 } else if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS) {
1037 assert(pdu->hdr_size == 2);
1038 pdu->type = COAP_MESSAGE_CON;
1039 pdu->code = hdr[pdu->hdr_size-1];
1040 pdu->mid = 0;
1041 } else {
1042 coap_log_debug("coap_pdu_parse: unsupported protocol\n");
1043 return 0;
1044 }
1045
1046 e_token_length = hdr[0] & 0x0f;
1047 if (e_token_length < COAP_TOKEN_EXT_1B_TKL) {
1048 pdu->e_token_length = e_token_length;
1050 pdu->actual_token.s = &pdu->token[0];
1051 } else if (e_token_length == COAP_TOKEN_EXT_1B_TKL) {
1052 pdu->e_token_length = pdu->token[0] + COAP_TOKEN_EXT_1B_BIAS + 1;
1053 pdu->actual_token.length = pdu->e_token_length - 1;
1054 pdu->actual_token.s = &pdu->token[1];
1055 } else if (e_token_length == COAP_TOKEN_EXT_2B_TKL) {
1056 pdu->e_token_length = ((uint16_t)pdu->token[0] << 8) + pdu->token[1] +
1058 pdu->actual_token.length = pdu->e_token_length - 2;
1059 pdu->actual_token.s = &pdu->token[2];
1060 }
1061 if (pdu->e_token_length > pdu->alloc_size || e_token_length == 15) {
1062 /* Invalid PDU provided - not wise to assert here though */
1063 coap_log_debug("coap_pdu_parse: PDU header token size broken\n");
1064 pdu->e_token_length = 0;
1065 pdu->actual_token.length = 0;
1066 return 0;
1067 }
1068 return 1;
1069}
1070
1071static int
1073 switch ((coap_pdu_signaling_proto_t)pdu->code) {
1074 case COAP_SIGNALING_CSM:
1075 switch (pdu->max_opt) {
1077 if (len > 4)
1078 goto bad;
1079 break;
1081 if (len > 0)
1082 goto bad;
1083 break;
1085 if (len > 3)
1086 goto bad;
1087 break;
1088 default:
1089 if (pdu->max_opt & 0x01)
1090 goto bad; /* Critical */
1091 }
1092 break;
1095 switch (pdu->max_opt) {
1097 if (len > 0)
1098 goto bad;
1099 break;
1100 default:
1101 if (pdu->max_opt & 0x01)
1102 goto bad; /* Critical */
1103 }
1104 break;
1106 switch (pdu->max_opt) {
1108 if (len < 1 || len > 255)
1109 goto bad;
1110 break;
1112 if (len > 3)
1113 goto bad;
1114 break;
1115 default:
1116 if (pdu->max_opt & 0x01)
1117 goto bad; /* Critical */
1118 }
1119 break;
1121 switch (pdu->max_opt) {
1123 if (len > 2)
1124 goto bad;
1125 break;
1126 default:
1127 if (pdu->max_opt & 0x01)
1128 goto bad; /* Critical */
1129 }
1130 break;
1131 default:
1132 ;
1133 }
1134 return 1;
1135bad:
1136 return 0;
1137}
1138
1139static int
1141 int res = 1;
1142
1143 switch (pdu->max_opt) {
1145 if (len > 8)
1146 res = 0;
1147 break;
1149 if (len < 1 || len > 255)
1150 res = 0;
1151 break;
1152 case COAP_OPTION_ETAG:
1153 if (len < 1 || len > 8)
1154 res = 0;
1155 break;
1157 if (len != 0)
1158 res = 0;
1159 break;
1161 if (len > 3)
1162 res = 0;
1163 break;
1165 if (len > 2)
1166 res = 0;
1167 break;
1169 if (len > 255)
1170 res = 0;
1171 break;
1172 case COAP_OPTION_OSCORE:
1173 if (len > 255)
1174 res = 0;
1175 break;
1177 if (len > 255)
1178 res = 0;
1179 break;
1181 if (len > 2)
1182 res = 0;
1183 break;
1184 case COAP_OPTION_MAXAGE:
1185 if (len > 4)
1186 res = 0;
1187 break;
1189 if (len < 1 || len > 255)
1190 res = 0;
1191 break;
1193 if (len != 1)
1194 res = 0;
1195 break;
1196 case COAP_OPTION_ACCEPT:
1197 if (len > 2)
1198 res = 0;
1199 break;
1201 if (len > 255)
1202 res = 0;
1203 break;
1204 case COAP_OPTION_BLOCK2:
1205 if (len > 3)
1206 res = 0;
1207 break;
1208 case COAP_OPTION_BLOCK1:
1209 if (len > 3)
1210 res = 0;
1211 break;
1212 case COAP_OPTION_SIZE2:
1213 if (len > 4)
1214 res = 0;
1215 break;
1217 if (len < 1 || len > 1034)
1218 res = 0;
1219 break;
1221 if (len < 1 || len > 255)
1222 res = 0;
1223 break;
1224 case COAP_OPTION_SIZE1:
1225 if (len > 4)
1226 res = 0;
1227 break;
1228 case COAP_OPTION_ECHO:
1229 if (len > 40)
1230 res = 0;
1231 break;
1233 if (len > 1)
1234 res = 0;
1235 break;
1236 case COAP_OPTION_RTAG:
1237 if (len > 8)
1238 res = 0;
1239 break;
1240 default:
1241 ;
1242 }
1243 return res;
1244}
1245
1246static int
1247write_prefix(char **obp, size_t *len, const char *prf, size_t prflen) {
1248 /* Make sure space for null terminating byte */
1249 if (*len < prflen +1) {
1250 return 0;
1251 }
1252
1253 memcpy(*obp, prf, prflen);
1254 *obp += prflen;
1255 *len -= prflen;
1256 return 1;
1257}
1258
1259static int
1260write_char(char **obp, size_t *len, char c, int printable) {
1261 /* Make sure space for null terminating byte */
1262 if (*len < 2 +1) {
1263 return 0;
1264 }
1265
1266 if (!printable) {
1267 const uint8_t hex[] = "0123456789abcdef";
1268 (*obp)[0] = hex[(c & 0xf0) >> 4];
1269 (*obp)[1] = hex[c & 0x0f];
1270 } else {
1271 (*obp)[0] = isprint(c) ? c : '.';
1272 (*obp)[1] = ' ';
1273 }
1274 *obp += 2;
1275 *len -= 2;
1276 return 1;
1277}
1278
1279int
1281
1282 int good = 1;
1283 /* sanity checks */
1284 if (pdu->code == 0) {
1285 if (pdu->used_size != 0 || pdu->e_token_length) {
1286 coap_log_debug("coap_pdu_parse: empty message is not empty\n");
1287 return 0;
1288 }
1289 }
1290
1291 if (pdu->e_token_length > pdu->used_size) {
1292 coap_log_debug("coap_pdu_parse: invalid Token\n");
1293 return 0;
1294 }
1295
1296 pdu->max_opt = 0;
1297 if (pdu->code == 0) {
1298 /* empty packet */
1299 pdu->used_size = 0;
1300 pdu->data = NULL;
1301 } else {
1302 /* skip header + token */
1303 coap_opt_t *opt = pdu->token + pdu->e_token_length;
1304 size_t length = pdu->used_size - pdu->e_token_length;
1305
1306 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1307#if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_WARN)
1308 coap_opt_t *opt_last = opt;
1309#endif
1310 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1311 const uint32_t len =
1312 optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1313 if (optsize == 0) {
1314 coap_log_debug("coap_pdu_parse: %d.%02d: offset %u malformed option\n",
1315 pdu->code >> 5, pdu->code & 0x1F,
1316 (int)(opt_last - pdu->token - pdu->e_token_length));
1317 good = 0;
1318 break;
1319 }
1320 if (COAP_PDU_IS_SIGNALING(pdu) ?
1321 !coap_pdu_parse_opt_csm(pdu, len) :
1322 !coap_pdu_parse_opt_base(pdu, len)) {
1323 coap_log_warn("coap_pdu_parse: %d.%02d: offset %u option %u has bad length %" PRIu32 "\n",
1324 pdu->code >> 5, pdu->code & 0x1F,
1325 (int)(opt_last - pdu->token - pdu->e_token_length), pdu->max_opt,
1326 len);
1327 good = 0;
1328 }
1329 }
1330
1331 if (!good) {
1332 /*
1333 * Dump the options in the PDU for analysis, space separated except
1334 * error options which are prefixed by *
1335 * Two rows - hex and ascii (if printable)
1336 */
1337 static char outbuf[COAP_DEBUG_BUF_SIZE];
1338 char *obp;
1339 size_t tlen;
1340 size_t outbuflen;
1341 int i;
1342 int ok;
1343
1344 for (i = 0; i < 2; i++) {
1345 opt = pdu->token + pdu->e_token_length;
1346 length = pdu->used_size - pdu->e_token_length;
1347 pdu->max_opt = 0;
1348
1349 outbuflen = sizeof(outbuf);
1350 obp = outbuf;
1351 ok = write_prefix(&obp, &outbuflen, "O: ", 3);
1352 while (length > 0 && *opt != COAP_PAYLOAD_START) {
1353 coap_opt_t *opt_last = opt;
1354 size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1355 const uint32_t len =
1356 optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1357 if (!optsize || (COAP_PDU_IS_SIGNALING(pdu) ?
1358 !coap_pdu_parse_opt_csm(pdu, len) :
1359 !coap_pdu_parse_opt_base(pdu, len))) {
1360 ok = ok && write_prefix(&obp, &outbuflen, "*", 1);
1361 if (!optsize) {
1362 /* Skip to end of options to output all data */
1363 opt = pdu->token + pdu->used_size;
1364 length = 0;
1365 }
1366 } else {
1367 ok = ok && write_prefix(&obp, &outbuflen, " ", 1);
1368 }
1369 tlen = opt - opt_last;
1370 while (tlen--) {
1371 ok = ok && write_char(&obp, &outbuflen, *opt_last, i);
1372 opt_last++;
1373 }
1374 }
1375 if (length && *opt == COAP_PAYLOAD_START) {
1376 ok = ok && write_char(&obp, &outbuflen, *opt, i);
1377 }
1378 /* write_*() always leaves a spare byte to null terminate */
1379 *obp = '\000';
1380 coap_log_debug("%s\n", outbuf);
1381 }
1382 }
1383
1384 if (length > 0) {
1385 assert(*opt == COAP_PAYLOAD_START);
1386 opt++;
1387 length--;
1388
1389 if (length == 0) {
1390 coap_log_debug("coap_pdu_parse: message ending in payload start marker\n");
1391 return 0;
1392 }
1393 }
1394 if (length > 0)
1395 pdu->data = (uint8_t *)opt;
1396 else
1397 pdu->data = NULL;
1398 }
1399
1400 return good;
1401}
1402
1403int
1405 const uint8_t *data,
1406 size_t length,
1407 coap_pdu_t *pdu) {
1408 size_t hdr_size;
1409
1410 if (length == 0)
1411 return 0;
1412 hdr_size = coap_pdu_parse_header_size(proto, data);
1413 if (!hdr_size || hdr_size > length)
1414 return 0;
1415 if (hdr_size > pdu->max_hdr_size)
1416 return 0;
1417 if (!coap_pdu_resize(pdu, length - hdr_size))
1418 return 0;
1419 if (pdu->token - hdr_size != data)
1420 memcpy(pdu->token - hdr_size, data, length);
1421 pdu->hdr_size = (uint8_t)hdr_size;
1422 pdu->used_size = length - hdr_size;
1423 return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu);
1424}
1425
1426size_t
1428 uint8_t e_token_length;
1429
1431 e_token_length = (uint8_t)pdu->actual_token.length;
1432 } else if (pdu->actual_token.length < COAP_TOKEN_EXT_2B_BIAS) {
1433 e_token_length = COAP_TOKEN_EXT_1B_TKL;
1434 } else if (pdu->actual_token.length <= COAP_TOKEN_EXT_MAX) {
1435 e_token_length = COAP_TOKEN_EXT_2B_TKL;
1436 } else {
1437 coap_log_warn("coap_add_token: Token size too large. PDU ignored\n");
1438 return 0;
1439 }
1440 if (COAP_PROTO_NOT_RELIABLE(proto)) {
1441 assert(pdu->max_hdr_size >= 4);
1442 if (pdu->max_hdr_size < 4) {
1443 coap_log_warn("coap_pdu_encode_header: not enough space for UDP-style header\n");
1444 return 0;
1445 }
1446 pdu->token[-4] = COAP_DEFAULT_VERSION << 6
1447 | pdu->type << 4
1448 | e_token_length;
1449 pdu->token[-3] = pdu->code;
1450 pdu->token[-2] = (uint8_t)(pdu->mid >> 8);
1451 pdu->token[-1] = (uint8_t)(pdu->mid);
1452 pdu->hdr_size = 4;
1453 } else if (COAP_PROTO_RELIABLE(proto)) {
1454 size_t len;
1455 assert(pdu->used_size >= pdu->e_token_length);
1456 if (pdu->used_size < pdu->e_token_length) {
1457 coap_log_warn("coap_pdu_encode_header: corrupted PDU\n");
1458 return 0;
1459 }
1460 if (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS)
1461 len = 0;
1462 else
1463 len = pdu->used_size - pdu->e_token_length;
1464 if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
1465 assert(pdu->max_hdr_size >= 2);
1466 if (pdu->max_hdr_size < 2) {
1467 coap_log_warn("coap_pdu_encode_header: not enough space for TCP0 header\n");
1468 return 0;
1469 }
1470 pdu->token[-2] = (uint8_t)len << 4
1471 | e_token_length;
1472 pdu->token[-1] = pdu->code;
1473 pdu->hdr_size = 2;
1474 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
1475 assert(pdu->max_hdr_size >= 3);
1476 if (pdu->max_hdr_size < 3) {
1477 coap_log_warn("coap_pdu_encode_header: not enough space for TCP8 header\n");
1478 return 0;
1479 }
1480 pdu->token[-3] = 13 << 4 | e_token_length;
1481 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
1482 pdu->token[-1] = pdu->code;
1483 pdu->hdr_size = 3;
1484 } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
1485 assert(pdu->max_hdr_size >= 4);
1486 if (pdu->max_hdr_size < 4) {
1487 coap_log_warn("coap_pdu_encode_header: not enough space for TCP16 header\n");
1488 return 0;
1489 }
1490 pdu->token[-4] = 14 << 4 | e_token_length;
1491 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
1492 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
1493 pdu->token[-1] = pdu->code;
1494 pdu->hdr_size = 4;
1495 } else {
1496 assert(pdu->max_hdr_size >= 6);
1497 if (pdu->max_hdr_size < 6) {
1498 coap_log_warn("coap_pdu_encode_header: not enough space for TCP32 header\n");
1499 return 0;
1500 }
1501 pdu->token[-6] = 15 << 4 | e_token_length;
1502 pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
1503 pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
1504 pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
1505 pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
1506 pdu->token[-1] = pdu->code;
1507 pdu->hdr_size = 6;
1508 }
1509 } else {
1510 coap_log_warn("coap_pdu_encode_header: unsupported protocol\n");
1511 }
1512 return pdu->hdr_size;
1513}
1514
1517 return pdu->code;
1518}
1519
1520void
1522 assert(code <= 0xff);
1523 pdu->code = code;
1524}
1525
1528 return pdu->type;
1529}
1530
1531void
1533 assert(type <= 0x3);
1534 pdu->type = type;
1535}
1536
1539 return pdu->actual_token;
1540}
1541
1544 return pdu->mid;
1545}
1546
1547void
1549 assert(mid >= 0 && mid <= 0xffff);
1550 pdu->mid = mid;
1551}
Pulls together all the internal only header files.
#define PRIu32
@ COAP_PDU
Definition coap_mem.h:45
@ COAP_PDU_BUF
Definition coap_mem.h:46
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
uint16_t coap_option_num_t
Definition coap_option.h:20
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:26
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:910
static int write_char(char **obp, size_t *len, char c, int printable)
Definition coap_pdu.c:1260
static int coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len)
Definition coap_pdu.c:1072
error_desc_t coap_error[]
Definition coap_pdu.c:862
static int write_prefix(char **obp, size_t *len, const char *prf, size_t prflen)
Definition coap_pdu.c:1247
static int coap_pdu_parse_opt_base(coap_pdu_t *pdu, uint16_t len)
Definition coap_pdu.c:1140
#define min(a, b)
Definition coap_pdu.c:34
#define max(a, b)
Definition coap_pdu.c:38
uint16_t coap_new_message_id(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
#define coap_log_debug(...)
Definition coap_debug.h:120
#define coap_log_info(...)
Definition coap_debug.h:108
#define coap_log_warn(...)
Definition coap_debug.h:102
#define coap_log_crit(...)
Definition coap_debug.h:90
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.
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.
#define COAP_MESSAGE_SIZE_OFFSET_TCP8
#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:568
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:431
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:363
#define COAP_TOKEN_EXT_1B_BIAS
#define COAP_PDU_MAX_UDP_HEADER_SIZE
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:1018
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:936
#define COAP_PDU_MAX_TCP_HEADER_SIZE
#define COAP_MAX_MESSAGE_SIZE_TCP8
#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:525
#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:42
#define COAP_MESSAGE_SIZE_OFFSET_TCP32
int coap_pdu_parse_opt(coap_pdu_t *pdu)
Verify consistency in the given CoAP PDU structure and locate the data.
Definition coap_pdu.c:1280
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:667
#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:1427
#define COAP_DEFAULT_VERSION
#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:289
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:966
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:245
#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:723
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:129
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:141
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:116
#define COAP_OPTION_IF_MATCH
Definition coap_pdu.h:115
coap_pdu_code_t coap_pdu_get_code(const coap_pdu_t *pdu)
Gets the PDU code associated with pdu.
Definition coap_pdu.c:1516
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:133
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition coap_pdu.c:894
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:124
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition coap_pdu.h:197
#define COAP_OPTION_SIZE2
Definition coap_pdu.h:135
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:134
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:138
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:800
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:128
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition coap_pdu.c:163
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:1521
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:255
#define COAP_OPTION_IF_NONE_MATCH
Definition coap_pdu.h:118
#define COAP_OPTION_LOCATION_PATH
Definition coap_pdu.h:121
#define COAP_TOKEN_EXT_MAX
Definition coap_pdu.h:57
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:123
#define COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH
Definition coap_pdu.h:191
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:152
coap_proto_t
CoAP protocol types.
Definition coap_pdu.h:304
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:153
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:318
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:122
#define COAP_OPTION_SIZE1
Definition coap_pdu.h:139
coap_pdu_type_t
CoAP PDU message type definitions.
Definition coap_pdu.h:64
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition coap_pdu.h:190
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:306
#define COAP_OPTION_LOCATION_QUERY
Definition coap_pdu.h:132
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:1532
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:713
#define COAP_SIGNALING_OPTION_CUSTODY
Definition coap_pdu.h:194
coap_pdu_signaling_proto_t
Definition coap_pdu.h:180
coap_pdu_type_t coap_pdu_get_type(const coap_pdu_t *pdu)
Gets the PDU type associated with pdu.
Definition coap_pdu.c:1527
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:819
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:1404
#define COAP_MAX_OPT
the highest option number we know
Definition coap_pdu.h:144
void coap_pdu_set_mid(coap_pdu_t *pdu, coap_mid_t mid)
Sets the message id in the pdu.
Definition coap_pdu.c:1548
#define COAP_OPTION_RTAG
Definition coap_pdu.h:142
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:179
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:120
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:97
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:130
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:827
coap_mid_t coap_pdu_get_mid(const coap_pdu_t *pdu)
Gets the message id associated with pdu.
Definition coap_pdu.c:1543
#define COAP_OPTION_MAXAGE
Definition coap_pdu.h:127
#define COAP_OPTION_ETAG
Definition coap_pdu.h:117
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:137
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:119
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition coap_pdu.h:198
#define COAP_OPTION_ECHO
Definition coap_pdu.h:140
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition coap_pdu.h:201
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition coap_pdu.h:189
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:788
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition coap_pdu.c:1538
@ COAP_PROTO_WS
Definition coap_pdu.h:310
@ COAP_PROTO_DTLS
Definition coap_pdu.h:307
@ COAP_PROTO_UDP
Definition coap_pdu.h:306
@ COAP_PROTO_TLS
Definition coap_pdu.h:309
@ COAP_PROTO_WSS
Definition coap_pdu.h:311
@ COAP_PROTO_TCP
Definition coap_pdu.h:308
@ COAP_MESSAGE_CON
Definition coap_pdu.h:65
@ COAP_SIGNALING_RELEASE
Definition coap_pdu.h:184
@ COAP_SIGNALING_CSM
Definition coap_pdu.h:181
@ COAP_SIGNALING_PONG
Definition coap_pdu.h:183
@ COAP_SIGNALING_PING
Definition coap_pdu.h:182
@ COAP_SIGNALING_ABORT
Definition coap_pdu.h:185
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
#define COAP_PROTO_NOT_RELIABLE(p)
#define COAP_PROTO_RELIABLE(p)
CoAP binary data definition with const data.
Definition coap_str.h:64
size_t length
length of binary data
Definition coap_str.h:65
const uint8_t * s
read-only binary data
Definition coap_str.h:66
Iterator to run through PDU options.
coap_option_num_t number
decoded option number
Representation of CoAP options.
Definition coap_option.h:32
uint16_t delta
Definition coap_option.h:33
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.
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.
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...
uint8_t doing_first
Set if doing client's first request.
unsigned char code
Definition coap_pdu.c:856
const char * phrase
Definition coap_pdu.c:857