1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_coap, CONFIG_COAP_LOG_LEVEL);
9
10 #include <stdlib.h>
11 #include <stddef.h>
12 #include <string.h>
13 #include <stdbool.h>
14 #include <errno.h>
15 #include <zephyr/random/random.h>
16 #include <zephyr/sys/atomic.h>
17 #include <zephyr/sys/util.h>
18
19 #include <zephyr/types.h>
20 #include <zephyr/sys/byteorder.h>
21 #include <zephyr/sys/math_extras.h>
22
23 #include <zephyr/net/net_ip.h>
24 #include <zephyr/net/net_core.h>
25 #include <zephyr/net/coap.h>
26 #include <zephyr/net/coap_mgmt.h>
27
28 #define COAP_PATH_ELEM_DELIM '/'
29 #define COAP_PATH_ELEM_QUERY '?'
30 #define COAP_PATH_ELEM_AMP '&'
31
32 /* Values as per RFC 7252, section-3.1.
33 *
34 * Option Delta/Length: 4-bit unsigned integer. A value between 0 and
35 * 12 indicates the Option Delta/Length. Three values are reserved for
36 * special constructs:
37 * 13: An 8-bit unsigned integer precedes the Option Value and indicates
38 * the Option Delta/Length minus 13.
39 * 14: A 16-bit unsigned integer in network byte order precedes the
40 * Option Value and indicates the Option Delta/Length minus 269.
41 * 15: Reserved for future use.
42 */
43 #define COAP_OPTION_NO_EXT 12 /* Option's Delta/Length without extended data */
44 #define COAP_OPTION_EXT_13 13
45 #define COAP_OPTION_EXT_14 14
46 #define COAP_OPTION_EXT_15 15
47 #define COAP_OPTION_EXT_269 269
48
49 /* CoAP Payload Marker */
50 #define COAP_MARKER 0xFF
51
52 #define BASIC_HEADER_SIZE 4
53
54 #define COAP_OBSERVE_FIRST_OFFSET 2
55
56 /* The CoAP message ID that is incremented each time coap_next_id() is called. */
57 static uint16_t message_id;
58
59 static struct coap_transmission_parameters coap_transmission_params = {
60 .max_retransmission = CONFIG_COAP_MAX_RETRANSMIT,
61 .ack_timeout = CONFIG_COAP_INIT_ACK_TIMEOUT_MS,
62 #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT)
63 .ack_random_percent = CONFIG_COAP_ACK_RANDOM_PERCENT,
64 #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */
65 .coap_backoff_percent = CONFIG_COAP_BACKOFF_PERCENT
66 };
67
68 static int insert_option(struct coap_packet *cpkt, uint16_t code, const uint8_t *value,
69 uint16_t len);
70
encode_u8(struct coap_packet * cpkt,uint16_t offset,uint8_t data)71 static inline void encode_u8(struct coap_packet *cpkt, uint16_t offset, uint8_t data)
72 {
73 cpkt->data[offset] = data;
74 ++cpkt->offset;
75 }
76
encode_be16(struct coap_packet * cpkt,uint16_t offset,uint16_t data)77 static inline void encode_be16(struct coap_packet *cpkt, uint16_t offset, uint16_t data)
78 {
79 cpkt->data[offset] = data >> 8;
80 cpkt->data[offset + 1] = (uint8_t)data;
81 cpkt->offset += 2;
82 }
83
encode_buffer(struct coap_packet * cpkt,uint16_t offset,const uint8_t * data,uint16_t len)84 static inline void encode_buffer(struct coap_packet *cpkt, uint16_t offset, const uint8_t *data,
85 uint16_t len)
86 {
87 memcpy(cpkt->data + offset, data, len);
88 cpkt->offset += len;
89 }
90
enough_space(struct coap_packet * cpkt,const uint16_t bytes_to_add)91 static bool enough_space(struct coap_packet *cpkt, const uint16_t bytes_to_add)
92 {
93 return (cpkt != NULL) && (cpkt->max_len - cpkt->offset >= bytes_to_add);
94 }
95
append_u8(struct coap_packet * cpkt,uint8_t data)96 static inline bool append_u8(struct coap_packet *cpkt, uint8_t data)
97 {
98 if (!enough_space(cpkt, 1)) {
99 return false;
100 }
101
102 encode_u8(cpkt, cpkt->offset, data);
103
104 return true;
105 }
106
insert_u8(struct coap_packet * cpkt,uint8_t data,uint16_t offset)107 static inline bool insert_u8(struct coap_packet *cpkt, uint8_t data, uint16_t offset)
108 {
109 if (!enough_space(cpkt, 1)) {
110 return false;
111 }
112
113 memmove(&cpkt->data[offset + 1], &cpkt->data[offset], cpkt->offset - offset);
114
115 encode_u8(cpkt, offset, data);
116
117 return true;
118 }
119
append_be16(struct coap_packet * cpkt,uint16_t data)120 static inline bool append_be16(struct coap_packet *cpkt, uint16_t data)
121 {
122 if (!enough_space(cpkt, 2)) {
123 return false;
124 }
125
126 encode_be16(cpkt, cpkt->offset, data);
127
128 return true;
129 }
130
insert_be16(struct coap_packet * cpkt,uint16_t data,size_t offset)131 static inline bool insert_be16(struct coap_packet *cpkt, uint16_t data, size_t offset)
132 {
133 if (!enough_space(cpkt, 2)) {
134 return false;
135 }
136
137 memmove(&cpkt->data[offset + 2], &cpkt->data[offset], cpkt->offset - offset);
138
139 encode_be16(cpkt, cpkt->offset, data);
140
141 return true;
142 }
143
append(struct coap_packet * cpkt,const uint8_t * data,uint16_t len)144 static inline bool append(struct coap_packet *cpkt, const uint8_t *data, uint16_t len)
145 {
146 if (data == NULL || !enough_space(cpkt, len)) {
147 return false;
148 }
149
150 encode_buffer(cpkt, cpkt->offset, data, len);
151
152 return true;
153 }
154
insert(struct coap_packet * cpkt,const uint8_t * data,uint16_t len,size_t offset)155 static inline bool insert(struct coap_packet *cpkt, const uint8_t *data, uint16_t len,
156 size_t offset)
157 {
158 if (data == NULL || !enough_space(cpkt, len)) {
159 return false;
160 }
161
162 memmove(&cpkt->data[offset + len], &cpkt->data[offset], cpkt->offset - offset);
163
164 encode_buffer(cpkt, offset, data, len);
165
166 return true;
167 }
168
coap_packet_init(struct coap_packet * cpkt,uint8_t * data,uint16_t max_len,uint8_t ver,uint8_t type,uint8_t token_len,const uint8_t * token,uint8_t code,uint16_t id)169 int coap_packet_init(struct coap_packet *cpkt, uint8_t *data, uint16_t max_len,
170 uint8_t ver, uint8_t type, uint8_t token_len,
171 const uint8_t *token, uint8_t code, uint16_t id)
172 {
173 uint8_t hdr;
174 bool res;
175
176 if (!cpkt || !data || !max_len) {
177 return -EINVAL;
178 }
179
180 memset(cpkt, 0, sizeof(*cpkt));
181
182 cpkt->data = data;
183 cpkt->offset = 0U;
184 cpkt->max_len = max_len;
185 cpkt->delta = 0U;
186
187 hdr = (ver & 0x3) << 6;
188 hdr |= (type & 0x3) << 4;
189 hdr |= token_len & 0xF;
190
191 res = append_u8(cpkt, hdr);
192 if (!res) {
193 return -EINVAL;
194 }
195
196 res = append_u8(cpkt, code);
197 if (!res) {
198 return -EINVAL;
199 }
200
201 res = append_be16(cpkt, id);
202 if (!res) {
203 return -EINVAL;
204 }
205
206 if (token && token_len) {
207 res = append(cpkt, token, token_len);
208 if (!res) {
209 return -EINVAL;
210 }
211 }
212
213 /* Header length : (version + type + tkl) + code + id + [token] */
214 cpkt->hdr_len = 1 + 1 + 2 + token_len;
215
216 return 0;
217 }
218
coap_ack_init(struct coap_packet * cpkt,const struct coap_packet * req,uint8_t * data,uint16_t max_len,uint8_t code)219 int coap_ack_init(struct coap_packet *cpkt, const struct coap_packet *req,
220 uint8_t *data, uint16_t max_len, uint8_t code)
221 {
222 uint16_t id;
223 uint8_t ver;
224 uint8_t tkl;
225 uint8_t token[COAP_TOKEN_MAX_LEN];
226
227 ver = coap_header_get_version(req);
228 id = coap_header_get_id(req);
229 tkl = code ? coap_header_get_token(req, token) : 0;
230
231 return coap_packet_init(cpkt, data, max_len, ver, COAP_TYPE_ACK, tkl,
232 token, code, id);
233 }
234
coap_rst_init(struct coap_packet * cpkt,const struct coap_packet * req,uint8_t * data,uint16_t max_len)235 int coap_rst_init(struct coap_packet *cpkt, const struct coap_packet *req,
236 uint8_t *data, uint16_t max_len)
237 {
238 uint16_t id;
239 uint8_t ver;
240
241 ver = coap_header_get_version(req);
242 id = coap_header_get_id(req);
243
244 return coap_packet_init(cpkt, data, max_len, ver, COAP_TYPE_RESET, 0,
245 NULL, 0, id);
246 }
247
option_header_set_delta(uint8_t * opt,uint8_t delta)248 static void option_header_set_delta(uint8_t *opt, uint8_t delta)
249 {
250 *opt = (delta & 0xF) << 4;
251 }
252
option_header_set_len(uint8_t * opt,uint8_t len)253 static void option_header_set_len(uint8_t *opt, uint8_t len)
254 {
255 *opt |= (len & 0xF);
256 }
257
encode_extended_option(uint16_t num,uint8_t * opt,uint16_t * ext)258 static uint8_t encode_extended_option(uint16_t num, uint8_t *opt, uint16_t *ext)
259 {
260 if (num < COAP_OPTION_EXT_13) {
261 *opt = num;
262 *ext = 0U;
263
264 return 0;
265 } else if (num < COAP_OPTION_EXT_269) {
266 *opt = COAP_OPTION_EXT_13;
267 *ext = num - COAP_OPTION_EXT_13;
268
269 return 1;
270 }
271
272 *opt = COAP_OPTION_EXT_14;
273 *ext = num - COAP_OPTION_EXT_269;
274
275 return 2;
276 }
277
278 /* Insert an option at position `offset`. This is not adjusting the code delta of the
279 * option that follows the inserted one!
280 */
encode_option(struct coap_packet * cpkt,uint16_t code,const uint8_t * value,uint16_t len,size_t offset)281 static int encode_option(struct coap_packet *cpkt, uint16_t code, const uint8_t *value,
282 uint16_t len, size_t offset)
283 {
284 uint16_t delta_ext; /* Extended delta */
285 uint16_t len_ext; /* Extended length */
286 uint8_t opt; /* delta | len */
287 uint8_t opt_delta;
288 uint8_t opt_len;
289 uint8_t delta_size;
290 uint8_t len_size;
291 bool res;
292
293 delta_size = encode_extended_option(code, &opt_delta, &delta_ext);
294 len_size = encode_extended_option(len, &opt_len, &len_ext);
295
296 option_header_set_delta(&opt, opt_delta);
297 option_header_set_len(&opt, opt_len);
298
299 res = insert_u8(cpkt, opt, offset);
300 ++offset;
301 if (!res) {
302 return -EINVAL;
303 }
304
305 if (delta_size == 1U) {
306 res = insert_u8(cpkt, (uint8_t)delta_ext, offset);
307 ++offset;
308 if (!res) {
309 return -EINVAL;
310 }
311 } else if (delta_size == 2U) {
312 res = insert_be16(cpkt, delta_ext, offset);
313 offset += 2;
314 if (!res) {
315 return -EINVAL;
316 }
317 }
318
319 if (len_size == 1U) {
320 res = insert_u8(cpkt, (uint8_t)len_ext, offset);
321 ++offset;
322 if (!res) {
323 return -EINVAL;
324 }
325 } else if (len_size == 2U) {
326 res = insert_be16(cpkt, len_ext, offset);
327 offset += 2;
328 if (!res) {
329 return -EINVAL;
330 }
331 }
332
333 if (len && value) {
334 res = insert(cpkt, value, len, offset);
335 /* no need to update local offset */
336 if (!res) {
337 return -EINVAL;
338 }
339 }
340
341 return (1 + delta_size + len_size + len);
342 }
343
coap_packet_append_option(struct coap_packet * cpkt,uint16_t code,const uint8_t * value,uint16_t len)344 int coap_packet_append_option(struct coap_packet *cpkt, uint16_t code,
345 const uint8_t *value, uint16_t len)
346 {
347 int r;
348
349 if (!cpkt) {
350 return -EINVAL;
351 }
352
353 if (len && !value) {
354 return -EINVAL;
355 }
356
357 if (code < cpkt->delta) {
358 NET_DBG("Option is not added in ascending order");
359 return insert_option(cpkt, code, value, len);
360 }
361
362 /* Calculate delta, if this option is not the first one */
363 if (cpkt->opt_len) {
364 code = (code == cpkt->delta) ? 0 : code - cpkt->delta;
365 }
366
367 r = encode_option(cpkt, code, value, len, cpkt->hdr_len + cpkt->opt_len);
368 if (r < 0) {
369 return -EINVAL;
370 }
371
372 cpkt->opt_len += r;
373 cpkt->delta += code;
374
375 return 0;
376 }
377
coap_append_option_int(struct coap_packet * cpkt,uint16_t code,unsigned int val)378 int coap_append_option_int(struct coap_packet *cpkt, uint16_t code,
379 unsigned int val)
380 {
381 uint8_t data[4], len;
382
383 if (val == 0U) {
384 data[0] = 0U;
385 len = 0U;
386 } else if (val < 0xFF) {
387 data[0] = (uint8_t) val;
388 len = 1U;
389 } else if (val < 0xFFFF) {
390 sys_put_be16(val, data);
391 len = 2U;
392 } else if (val < 0xFFFFFF) {
393 sys_put_be16(val, &data[1]);
394 data[0] = val >> 16;
395 len = 3U;
396 } else {
397 sys_put_be32(val, data);
398 len = 4U;
399 }
400
401 return coap_packet_append_option(cpkt, code, data, len);
402 }
403
coap_option_value_to_int(const struct coap_option * option)404 unsigned int coap_option_value_to_int(const struct coap_option *option)
405 {
406 switch (option->len) {
407 case 0:
408 return 0;
409 case 1:
410 return option->value[0];
411 case 2:
412 return (option->value[1] << 0) | (option->value[0] << 8);
413 case 3:
414 return (option->value[2] << 0) | (option->value[1] << 8) |
415 (option->value[0] << 16);
416 case 4:
417 return (option->value[3] << 0) | (option->value[2] << 8) |
418 (option->value[1] << 16) | (option->value[0] << 24);
419 default:
420 return 0;
421 }
422
423 return 0;
424 }
425
coap_packet_append_payload_marker(struct coap_packet * cpkt)426 int coap_packet_append_payload_marker(struct coap_packet *cpkt)
427 {
428 return append_u8(cpkt, COAP_MARKER) ? 0 : -EINVAL;
429 }
430
coap_packet_append_payload(struct coap_packet * cpkt,const uint8_t * payload,uint16_t payload_len)431 int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload,
432 uint16_t payload_len)
433 {
434 return append(cpkt, payload, payload_len) ? 0 : -EINVAL;
435 }
436
coap_next_token(void)437 uint8_t *coap_next_token(void)
438 {
439 static uint8_t token[COAP_TOKEN_MAX_LEN];
440
441 sys_rand_get(token, COAP_TOKEN_MAX_LEN);
442
443 return token;
444 }
445
option_header_get_delta(uint8_t opt)446 static uint8_t option_header_get_delta(uint8_t opt)
447 {
448 return (opt & 0xF0) >> 4;
449 }
450
option_header_get_len(uint8_t opt)451 static uint8_t option_header_get_len(uint8_t opt)
452 {
453 return opt & 0x0F;
454 }
455
read_u8(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint8_t * value)456 static int read_u8(uint8_t *data, uint16_t offset, uint16_t *pos,
457 uint16_t max_len, uint8_t *value)
458 {
459 if (max_len - offset < 1) {
460 return -EINVAL;
461 }
462
463 *value = data[offset++];
464 *pos = offset;
465
466 return max_len - offset;
467 }
468
read_be16(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t * value)469 static int read_be16(uint8_t *data, uint16_t offset, uint16_t *pos,
470 uint16_t max_len, uint16_t *value)
471 {
472 if (max_len - offset < 2) {
473 return -EINVAL;
474 }
475
476 *value = data[offset++] << 8;
477 *value |= data[offset++];
478 *pos = offset;
479
480 return max_len - offset;
481 }
482
read(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t len,uint8_t * value)483 static int read(uint8_t *data, uint16_t offset, uint16_t *pos,
484 uint16_t max_len, uint16_t len, uint8_t *value)
485 {
486 if (max_len - offset < len) {
487 return -EINVAL;
488 }
489
490 memcpy(value, data + offset, len);
491 offset += len;
492 *pos = offset;
493
494 return max_len - offset;
495 }
496
decode_delta(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t opt,uint16_t * opt_ext,uint16_t * hdr_len)497 static int decode_delta(uint8_t *data, uint16_t offset, uint16_t *pos, uint16_t max_len,
498 uint16_t opt, uint16_t *opt_ext, uint16_t *hdr_len)
499 {
500 int ret = 0;
501 *hdr_len = 0;
502
503 if (opt == COAP_OPTION_EXT_13) {
504 uint8_t val;
505
506 *hdr_len = 1U;
507
508 ret = read_u8(data, offset, pos, max_len, &val);
509 if (ret < 0) {
510 return -EINVAL;
511 }
512
513 opt = val + COAP_OPTION_EXT_13;
514 } else if (opt == COAP_OPTION_EXT_14) {
515 uint16_t val;
516
517 *hdr_len = 2U;
518
519 ret = read_be16(data, offset, pos, max_len, &val);
520 if (ret < 0) {
521 return -EINVAL;
522 }
523
524 opt = val + COAP_OPTION_EXT_269;
525 } else if (opt == COAP_OPTION_EXT_15) {
526 return -EINVAL;
527 }
528
529 *opt_ext = opt;
530
531 return ret;
532 }
533
parse_option(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t * opt_delta,uint16_t * opt_len,struct coap_option * option)534 static int parse_option(uint8_t *data, uint16_t offset, uint16_t *pos,
535 uint16_t max_len, uint16_t *opt_delta, uint16_t *opt_len,
536 struct coap_option *option)
537 {
538 uint16_t hdr_len;
539 uint16_t delta;
540 uint16_t len;
541 uint8_t opt;
542 int r;
543
544 r = read_u8(data, offset, pos, max_len, &opt);
545 if (r < 0) {
546 return r;
547 }
548
549 /* This indicates that options have ended */
550 if (opt == COAP_MARKER) {
551 /* packet w/ marker but no payload is malformed */
552 return r > 0 ? 0 : -EINVAL;
553 }
554
555 *opt_len += 1U;
556
557 delta = option_header_get_delta(opt);
558 len = option_header_get_len(opt);
559
560 /* r == 0 means no more data to read from fragment, but delta
561 * field shows that packet should contain more data, it must
562 * be a malformed packet.
563 */
564 if (r == 0 && delta > COAP_OPTION_NO_EXT) {
565 return -EINVAL;
566 }
567
568 if (delta > COAP_OPTION_NO_EXT) {
569 /* In case 'delta' doesn't fit the option fixed header. */
570 r = decode_delta(data, *pos, pos, max_len,
571 delta, &delta, &hdr_len);
572 if ((r < 0) || (r == 0 && len > COAP_OPTION_NO_EXT)) {
573 return -EINVAL;
574 }
575
576 if (u16_add_overflow(*opt_len, hdr_len, opt_len)) {
577 return -EINVAL;
578 }
579 }
580
581 if (len > COAP_OPTION_NO_EXT) {
582 /* In case 'len' doesn't fit the option fixed header. */
583 r = decode_delta(data, *pos, pos, max_len,
584 len, &len, &hdr_len);
585 if (r < 0) {
586 return -EINVAL;
587 }
588
589 if (u16_add_overflow(*opt_len, hdr_len, opt_len)) {
590 return -EINVAL;
591 }
592 }
593
594 if (u16_add_overflow(*opt_delta, delta, opt_delta) ||
595 u16_add_overflow(*opt_len, len, opt_len)) {
596 return -EINVAL;
597 }
598
599 if (r == 0 && len != 0U) {
600 /* r == 0 means no more data to read from fragment, but len
601 * field shows that packet should contain more data, it must
602 * be a malformed packet.
603 */
604 return -EINVAL;
605 }
606
607 if (option) {
608 /*
609 * Make sure the option data will fit into the value field of
610 * coap_option.
611 * NOTE: To expand the size of the value field set:
612 * CONFIG_COAP_EXTENDED_OPTIONS_LEN=y
613 * CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE=<size>
614 */
615 if (len > sizeof(option->value)) {
616 NET_ERR("%u is > sizeof(coap_option->value)(%zu)!",
617 len, sizeof(option->value));
618 return -EINVAL;
619 }
620
621 option->delta = *opt_delta;
622 option->len = len;
623 r = read(data, *pos, pos, max_len, len, &option->value[0]);
624 if (r < 0) {
625 return -EINVAL;
626 }
627 } else {
628 if (u16_add_overflow(*pos, len, pos)) {
629 return -EINVAL;
630 }
631
632 r = max_len - *pos;
633 }
634
635 return r;
636 }
637
638 /* Remove the raw data of an option. Also adjusting offsets.
639 * But not adjusting code delta of the option after the removed one.
640 */
remove_option_data(struct coap_packet * cpkt,const uint16_t to_offset,const uint16_t from_offset)641 static void remove_option_data(struct coap_packet *cpkt,
642 const uint16_t to_offset,
643 const uint16_t from_offset)
644 {
645 const uint16_t move_size = from_offset - to_offset;
646
647 memmove(cpkt->data + to_offset, cpkt->data + from_offset, cpkt->offset - from_offset);
648 cpkt->opt_len -= move_size;
649 cpkt->offset -= move_size;
650 }
651
652 /* Remove an option (that is not the last one).
653 * Also adjusting the code delta of the option following the removed one.
654 */
remove_middle_option(struct coap_packet * cpkt,uint16_t offset,uint16_t opt_delta,const uint16_t previous_offset,const uint16_t previous_code)655 static int remove_middle_option(struct coap_packet *cpkt,
656 uint16_t offset,
657 uint16_t opt_delta,
658 const uint16_t previous_offset,
659 const uint16_t previous_code)
660 {
661 int r;
662 struct coap_option option;
663 uint16_t opt_len = 0;
664
665 /* get the option after the removed one */
666 r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len,
667 &opt_delta, &opt_len, &option);
668 if (r < 0) {
669 return -EILSEQ;
670 }
671
672 /* clear requested option and the one after (delta changed) */
673 remove_option_data(cpkt, previous_offset, offset);
674
675 /* reinsert option that comes after the removed option (with adjusted delta) */
676 r = encode_option(cpkt, option.delta - previous_code, option.value, option.len,
677 previous_offset);
678 if (r < 0) {
679 return -EINVAL;
680 }
681 cpkt->opt_len += r;
682
683 return 0;
684 }
coap_packet_remove_option(struct coap_packet * cpkt,uint16_t code)685 int coap_packet_remove_option(struct coap_packet *cpkt, uint16_t code)
686 {
687 uint16_t offset = 0;
688 uint16_t opt_delta = 0;
689 uint16_t opt_len = 0;
690 uint16_t previous_offset = 0;
691 uint16_t previous_code = 0;
692 struct coap_option option;
693 int r;
694
695 if (!cpkt) {
696 return -EINVAL;
697 }
698
699 if (cpkt->opt_len == 0) {
700 return 0;
701 }
702
703 if (code > cpkt->delta) {
704 return 0;
705 }
706
707 offset = cpkt->hdr_len;
708 previous_offset = cpkt->hdr_len;
709
710 /* Find the requested option */
711 while (offset < cpkt->hdr_len + cpkt->opt_len) {
712 r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len,
713 &opt_delta, &opt_len, &option);
714 if (r < 0) {
715 return -EILSEQ;
716 }
717
718 if (opt_delta == code) {
719 break;
720 }
721
722 if (opt_delta > code) {
723 return 0;
724 }
725
726 previous_code = opt_delta;
727 previous_offset = offset;
728 }
729
730 /* Check if the found option is the last option */
731 if (cpkt->opt_len > opt_len) {
732 /* not last option */
733 r = remove_middle_option(cpkt, offset, opt_delta, previous_offset, previous_code);
734 if (r < 0) {
735 return r;
736 }
737 } else {
738 /* last option */
739 remove_option_data(cpkt, previous_offset, cpkt->hdr_len + cpkt->opt_len);
740 cpkt->delta = previous_code;
741 }
742
743 return 0;
744 }
745
coap_packet_parse(struct coap_packet * cpkt,uint8_t * data,uint16_t len,struct coap_option * options,uint8_t opt_num)746 int coap_packet_parse(struct coap_packet *cpkt, uint8_t *data, uint16_t len,
747 struct coap_option *options, uint8_t opt_num)
748 {
749 uint16_t opt_len;
750 uint16_t offset;
751 uint16_t delta;
752 uint8_t num;
753 uint8_t tkl;
754 int ret;
755
756 if (!cpkt || !data) {
757 return -EINVAL;
758 }
759
760 if (len < BASIC_HEADER_SIZE) {
761 return -EINVAL;
762 }
763
764 if (options) {
765 memset(options, 0, opt_num * sizeof(struct coap_option));
766 }
767
768 cpkt->data = data;
769 cpkt->offset = len;
770 cpkt->max_len = len;
771 cpkt->opt_len = 0U;
772 cpkt->hdr_len = 0U;
773 cpkt->delta = 0U;
774
775 /* Token lengths 9-15 are reserved. */
776 tkl = cpkt->data[0] & 0x0f;
777 if (tkl > 8) {
778 return -EBADMSG;
779 }
780
781 cpkt->hdr_len = BASIC_HEADER_SIZE + tkl;
782 if (cpkt->hdr_len > len) {
783 return -EBADMSG;
784 }
785
786 if (cpkt->hdr_len == len) {
787 return 0;
788 }
789
790 offset = cpkt->hdr_len;
791 opt_len = 0U;
792 delta = 0U;
793 num = 0U;
794
795 while (1) {
796 struct coap_option *option;
797
798 option = num < opt_num ? &options[num++] : NULL;
799 ret = parse_option(cpkt->data, offset, &offset, cpkt->max_len,
800 &delta, &opt_len, option);
801 if (ret < 0) {
802 return -EILSEQ;
803 } else if (ret == 0) {
804 break;
805 }
806 }
807
808 cpkt->opt_len = opt_len;
809 cpkt->delta = delta;
810
811 return 0;
812 }
813
coap_packet_set_path(struct coap_packet * cpkt,const char * path)814 int coap_packet_set_path(struct coap_packet *cpkt, const char *path)
815 {
816 int ret = 0;
817 int path_start, path_end;
818 int path_length;
819 bool contains_query = false;
820 int i;
821
822 path_start = 0;
823 path_end = 0;
824 path_length = strlen(path);
825 for (i = 0; i < path_length; i++) {
826 path_end = i;
827 if (path[i] == COAP_PATH_ELEM_DELIM) {
828 /* Guard for preceding delimiters */
829 if (path_start < path_end) {
830 ret = coap_packet_append_option(cpkt, COAP_OPTION_URI_PATH,
831 path + path_start,
832 path_end - path_start);
833 if (ret < 0) {
834 LOG_ERR("Failed to append path to CoAP message");
835 goto out;
836 }
837 }
838 /* Check if there is a new path after delimiter,
839 * if not, point to the end of string to not add
840 * new option after this
841 */
842 if (path_length > i + 1) {
843 path_start = i + 1;
844 } else {
845 path_start = path_length;
846 }
847 } else if (path[i] == COAP_PATH_ELEM_QUERY) {
848 /* Guard for preceding delimiters */
849 if (path_start < path_end) {
850 ret = coap_packet_append_option(cpkt, COAP_OPTION_URI_PATH,
851 path + path_start,
852 path_end - path_start);
853 if (ret < 0) {
854 LOG_ERR("Failed to append path to CoAP message");
855 goto out;
856 }
857 }
858 /* Rest of the path is query */
859 contains_query = true;
860 if (path_length > i + 1) {
861 path_start = i + 1;
862 } else {
863 path_start = path_length;
864 }
865 break;
866 }
867 }
868
869 if (contains_query) {
870 for (i = path_start; i < path_length; i++) {
871 path_end = i;
872 if (path[i] == COAP_PATH_ELEM_AMP || path[i] == COAP_PATH_ELEM_QUERY) {
873 /* Guard for preceding delimiters */
874 if (path_start < path_end) {
875 ret = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY,
876 path + path_start,
877 path_end - path_start);
878 if (ret < 0) {
879 LOG_ERR("Failed to append path to CoAP message");
880 goto out;
881 }
882 }
883 /* Check if there is a new query option after delimiter,
884 * if not, point to the end of string to not add
885 * new option after this
886 */
887 if (path_length > i + 1) {
888 path_start = i + 1;
889 } else {
890 path_start = path_length;
891 }
892 }
893 }
894 }
895
896 if (path_start < path_length) {
897 if (contains_query) {
898 ret = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY,
899 path + path_start,
900 path_end - path_start + 1);
901 } else {
902 ret = coap_packet_append_option(cpkt, COAP_OPTION_URI_PATH,
903 path + path_start,
904 path_end - path_start + 1);
905 }
906 if (ret < 0) {
907 LOG_ERR("Failed to append path to CoAP message");
908 goto out;
909 }
910 }
911
912 out:
913 return ret;
914 }
915
coap_find_options(const struct coap_packet * cpkt,uint16_t code,struct coap_option * options,uint16_t veclen)916 int coap_find_options(const struct coap_packet *cpkt, uint16_t code,
917 struct coap_option *options, uint16_t veclen)
918 {
919 uint16_t opt_len;
920 uint16_t offset;
921 uint16_t delta;
922 uint8_t num;
923 int r;
924
925 /* Check if there are options to parse */
926 if (cpkt->hdr_len == cpkt->max_len) {
927 return 0;
928 }
929
930 offset = cpkt->hdr_len;
931 opt_len = 0U;
932 delta = 0U;
933 num = 0U;
934
935 while (delta <= code && num < veclen) {
936 r = parse_option(cpkt->data, offset, &offset,
937 cpkt->max_len, &delta, &opt_len,
938 &options[num]);
939 if (r < 0) {
940 return -EINVAL;
941 }
942
943 if (code == options[num].delta) {
944 num++;
945 }
946
947 if (r == 0) {
948 break;
949 }
950 }
951
952 return num;
953 }
954
coap_header_get_version(const struct coap_packet * cpkt)955 uint8_t coap_header_get_version(const struct coap_packet *cpkt)
956 {
957 if (!cpkt || !cpkt->data) {
958 return 0;
959 }
960
961 return (cpkt->data[0] & 0xC0) >> 6;
962 }
963
coap_header_get_type(const struct coap_packet * cpkt)964 uint8_t coap_header_get_type(const struct coap_packet *cpkt)
965 {
966 if (!cpkt || !cpkt->data) {
967 return 0;
968 }
969
970 return (cpkt->data[0] & 0x30) >> 4;
971 }
972
__coap_header_get_code(const struct coap_packet * cpkt)973 static uint8_t __coap_header_get_code(const struct coap_packet *cpkt)
974 {
975 if (!cpkt || !cpkt->data) {
976 return 0;
977 }
978
979 return cpkt->data[1];
980 }
981
coap_header_set_code(const struct coap_packet * cpkt,uint8_t code)982 int coap_header_set_code(const struct coap_packet *cpkt, uint8_t code)
983 {
984 if (!cpkt || !cpkt->data) {
985 return -EINVAL;
986 }
987
988 cpkt->data[1] = code;
989 return 0;
990 }
991
coap_header_get_token(const struct coap_packet * cpkt,uint8_t * token)992 uint8_t coap_header_get_token(const struct coap_packet *cpkt, uint8_t *token)
993 {
994 uint8_t tkl;
995
996 if (!cpkt || !cpkt->data) {
997 return 0;
998 }
999
1000 tkl = cpkt->data[0] & 0x0f;
1001 if (tkl > COAP_TOKEN_MAX_LEN) {
1002 return 0;
1003 }
1004
1005 if (tkl) {
1006 memcpy(token, cpkt->data + BASIC_HEADER_SIZE, tkl);
1007 }
1008
1009 return tkl;
1010 }
1011
coap_header_get_code(const struct coap_packet * cpkt)1012 uint8_t coap_header_get_code(const struct coap_packet *cpkt)
1013 {
1014 uint8_t code = __coap_header_get_code(cpkt);
1015
1016 switch (code) {
1017 /* Methods are encoded in the code field too */
1018 case COAP_METHOD_GET:
1019 case COAP_METHOD_POST:
1020 case COAP_METHOD_PUT:
1021 case COAP_METHOD_DELETE:
1022 case COAP_METHOD_FETCH:
1023 case COAP_METHOD_PATCH:
1024 case COAP_METHOD_IPATCH:
1025
1026 /* All the defined response codes */
1027 case COAP_RESPONSE_CODE_OK:
1028 case COAP_RESPONSE_CODE_CREATED:
1029 case COAP_RESPONSE_CODE_DELETED:
1030 case COAP_RESPONSE_CODE_VALID:
1031 case COAP_RESPONSE_CODE_CHANGED:
1032 case COAP_RESPONSE_CODE_CONTENT:
1033 case COAP_RESPONSE_CODE_CONTINUE:
1034 case COAP_RESPONSE_CODE_BAD_REQUEST:
1035 case COAP_RESPONSE_CODE_UNAUTHORIZED:
1036 case COAP_RESPONSE_CODE_BAD_OPTION:
1037 case COAP_RESPONSE_CODE_FORBIDDEN:
1038 case COAP_RESPONSE_CODE_NOT_FOUND:
1039 case COAP_RESPONSE_CODE_NOT_ALLOWED:
1040 case COAP_RESPONSE_CODE_NOT_ACCEPTABLE:
1041 case COAP_RESPONSE_CODE_INCOMPLETE:
1042 case COAP_RESPONSE_CODE_CONFLICT:
1043 case COAP_RESPONSE_CODE_PRECONDITION_FAILED:
1044 case COAP_RESPONSE_CODE_REQUEST_TOO_LARGE:
1045 case COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT:
1046 case COAP_RESPONSE_CODE_UNPROCESSABLE_ENTITY:
1047 case COAP_RESPONSE_CODE_TOO_MANY_REQUESTS:
1048 case COAP_RESPONSE_CODE_INTERNAL_ERROR:
1049 case COAP_RESPONSE_CODE_NOT_IMPLEMENTED:
1050 case COAP_RESPONSE_CODE_BAD_GATEWAY:
1051 case COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE:
1052 case COAP_RESPONSE_CODE_GATEWAY_TIMEOUT:
1053 case COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED:
1054 case COAP_CODE_EMPTY:
1055 return code;
1056 default:
1057 return COAP_CODE_EMPTY;
1058 }
1059 }
1060
coap_header_get_id(const struct coap_packet * cpkt)1061 uint16_t coap_header_get_id(const struct coap_packet *cpkt)
1062 {
1063 if (!cpkt || !cpkt->data) {
1064 return 0;
1065 }
1066
1067 return (cpkt->data[2] << 8) | cpkt->data[3];
1068 }
1069
coap_packet_get_payload(const struct coap_packet * cpkt,uint16_t * len)1070 const uint8_t *coap_packet_get_payload(const struct coap_packet *cpkt, uint16_t *len)
1071 {
1072 int payload_len;
1073
1074 if (!cpkt || !len) {
1075 return NULL;
1076 }
1077
1078 payload_len = cpkt->offset - cpkt->hdr_len - cpkt->opt_len;
1079 if (payload_len > 1) {
1080 *len = payload_len - 1; /* subtract payload marker length */
1081 } else {
1082 *len = 0U;
1083 }
1084
1085 return *len == 0 ? NULL :
1086 cpkt->data + cpkt->hdr_len + cpkt->opt_len + 1;
1087 }
1088
coap_uri_path_match(const char * const * path,struct coap_option * options,uint8_t opt_num)1089 bool coap_uri_path_match(const char * const *path,
1090 struct coap_option *options,
1091 uint8_t opt_num)
1092 {
1093 uint8_t i;
1094 uint8_t j = 0U;
1095
1096 for (i = 0U; i < opt_num && path[j]; i++) {
1097 if (options[i].delta != COAP_OPTION_URI_PATH) {
1098 continue;
1099 }
1100
1101 if (IS_ENABLED(CONFIG_COAP_URI_WILDCARD) && strlen(path[j]) == 1) {
1102 if (*path[j] == '+') {
1103 /* Single-level wildcard */
1104 j++;
1105 continue;
1106 } else if (*path[j] == '#') {
1107 /* Multi-level wildcard */
1108 return true;
1109 }
1110 }
1111
1112 if (options[i].len != strlen(path[j])) {
1113 return false;
1114 }
1115
1116 if (memcmp(options[i].value, path[j], options[i].len)) {
1117 return false;
1118 }
1119
1120 j++;
1121 }
1122
1123 if (path[j]) {
1124 return false;
1125 }
1126
1127 for (; i < opt_num; i++) {
1128 if (options[i].delta == COAP_OPTION_URI_PATH) {
1129 return false;
1130 }
1131 }
1132
1133 return true;
1134 }
1135
method_from_code(const struct coap_resource * resource,uint8_t code,coap_method_t * method)1136 static int method_from_code(const struct coap_resource *resource,
1137 uint8_t code, coap_method_t *method)
1138 {
1139 switch (code) {
1140 case COAP_METHOD_GET:
1141 *method = resource->get;
1142 return 0;
1143 case COAP_METHOD_POST:
1144 *method = resource->post;
1145 return 0;
1146 case COAP_METHOD_PUT:
1147 *method = resource->put;
1148 return 0;
1149 case COAP_METHOD_DELETE:
1150 *method = resource->del;
1151 return 0;
1152 case COAP_METHOD_FETCH:
1153 *method = resource->fetch;
1154 return 0;
1155 case COAP_METHOD_PATCH:
1156 *method = resource->patch;
1157 return 0;
1158 case COAP_METHOD_IPATCH:
1159 *method = resource->ipatch;
1160 return 0;
1161 default:
1162 return -EINVAL;
1163 }
1164 }
1165
1166
is_empty_message(const struct coap_packet * cpkt)1167 static inline bool is_empty_message(const struct coap_packet *cpkt)
1168 {
1169 return __coap_header_get_code(cpkt) == COAP_CODE_EMPTY;
1170 }
1171
coap_packet_is_request(const struct coap_packet * cpkt)1172 bool coap_packet_is_request(const struct coap_packet *cpkt)
1173 {
1174 uint8_t code = coap_header_get_code(cpkt);
1175
1176 return (code != COAP_CODE_EMPTY) && !(code & ~COAP_REQUEST_MASK);
1177 }
1178
coap_handle_request_len(struct coap_packet * cpkt,struct coap_resource * resources,size_t resources_len,struct coap_option * options,uint8_t opt_num,struct sockaddr * addr,socklen_t addr_len)1179 int coap_handle_request_len(struct coap_packet *cpkt,
1180 struct coap_resource *resources,
1181 size_t resources_len,
1182 struct coap_option *options,
1183 uint8_t opt_num,
1184 struct sockaddr *addr, socklen_t addr_len)
1185 {
1186 if (!coap_packet_is_request(cpkt)) {
1187 return -ENOTSUP;
1188 }
1189
1190 /* FIXME: deal with hierarchical resources */
1191 for (size_t i = 0; i < resources_len; i++) {
1192 coap_method_t method;
1193 uint8_t code;
1194
1195 if (!coap_uri_path_match(resources[i].path, options, opt_num)) {
1196 continue;
1197 }
1198
1199 code = coap_header_get_code(cpkt);
1200 if (method_from_code(&resources[i], code, &method) < 0) {
1201 return -ENOTSUP;
1202 }
1203
1204 if (!method) {
1205 return -EPERM;
1206 }
1207
1208 return method(&resources[i], cpkt, addr, addr_len);
1209 }
1210
1211 return -ENOENT;
1212 }
1213
coap_handle_request(struct coap_packet * cpkt,struct coap_resource * resources,struct coap_option * options,uint8_t opt_num,struct sockaddr * addr,socklen_t addr_len)1214 int coap_handle_request(struct coap_packet *cpkt,
1215 struct coap_resource *resources,
1216 struct coap_option *options,
1217 uint8_t opt_num,
1218 struct sockaddr *addr, socklen_t addr_len)
1219 {
1220 size_t resources_len = 0;
1221 struct coap_resource *resource;
1222
1223 for (resource = resources; resource && resource->path; resource++) {
1224 resources_len++;
1225 }
1226
1227 return coap_handle_request_len(cpkt, resources, resources_len, options, opt_num, addr,
1228 addr_len);
1229 }
1230
coap_block_transfer_init(struct coap_block_context * ctx,enum coap_block_size block_size,size_t total_size)1231 int coap_block_transfer_init(struct coap_block_context *ctx,
1232 enum coap_block_size block_size,
1233 size_t total_size)
1234 {
1235 ctx->block_size = block_size;
1236 ctx->total_size = total_size;
1237 ctx->current = 0;
1238
1239 return 0;
1240 }
1241
1242 #define GET_BLOCK_SIZE(v) (((v) & 0x7))
1243 #define GET_MORE(v) (!!((v) & 0x08))
1244 #define GET_NUM(v) ((v) >> 4)
1245
1246 #define SET_BLOCK_SIZE(v, b) (v |= ((b) & 0x07))
1247 #define SET_MORE(v, m) ((v) |= (m) ? 0x08 : 0x00)
1248 #define SET_NUM(v, n) ((v) |= ((n) << 4))
1249
coap_append_descriptive_block_option(struct coap_packet * cpkt,struct coap_block_context * ctx)1250 int coap_append_descriptive_block_option(struct coap_packet *cpkt, struct coap_block_context *ctx)
1251 {
1252 if (coap_packet_is_request(cpkt)) {
1253 return coap_append_block1_option(cpkt, ctx);
1254 } else {
1255 return coap_append_block2_option(cpkt, ctx);
1256 }
1257 }
1258
coap_has_descriptive_block_option(struct coap_packet * cpkt)1259 bool coap_has_descriptive_block_option(struct coap_packet *cpkt)
1260 {
1261 if (coap_packet_is_request(cpkt)) {
1262 return coap_get_option_int(cpkt, COAP_OPTION_BLOCK1) >= 0;
1263 } else {
1264 return coap_get_option_int(cpkt, COAP_OPTION_BLOCK2) >= 0;
1265 }
1266 }
1267
coap_remove_descriptive_block_option(struct coap_packet * cpkt)1268 int coap_remove_descriptive_block_option(struct coap_packet *cpkt)
1269 {
1270 if (coap_packet_is_request(cpkt)) {
1271 return coap_packet_remove_option(cpkt, COAP_OPTION_BLOCK1);
1272 } else {
1273 return coap_packet_remove_option(cpkt, COAP_OPTION_BLOCK2);
1274 }
1275 }
1276
coap_block_has_more(struct coap_packet * cpkt)1277 bool coap_block_has_more(struct coap_packet *cpkt)
1278 {
1279 bool more = false;
1280 int opt;
1281
1282 if (coap_packet_is_request(cpkt)) {
1283 opt = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1284 } else {
1285 opt = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1286 }
1287 if (opt >= 0) {
1288 more = GET_MORE(opt);
1289 }
1290 return more;
1291 }
1292
coap_append_block1_option(struct coap_packet * cpkt,struct coap_block_context * ctx)1293 int coap_append_block1_option(struct coap_packet *cpkt,
1294 struct coap_block_context *ctx)
1295 {
1296 uint16_t bytes = coap_block_size_to_bytes(ctx->block_size);
1297 unsigned int val = 0U;
1298 int r;
1299
1300 if (coap_packet_is_request(cpkt)) {
1301 SET_BLOCK_SIZE(val, ctx->block_size);
1302 SET_MORE(val, ctx->current + bytes < ctx->total_size);
1303 SET_NUM(val, ctx->current / bytes);
1304 } else {
1305 SET_BLOCK_SIZE(val, ctx->block_size);
1306 SET_NUM(val, ctx->current / bytes);
1307 }
1308
1309 r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK1, val);
1310
1311 return r;
1312 }
1313
coap_append_block2_option(struct coap_packet * cpkt,struct coap_block_context * ctx)1314 int coap_append_block2_option(struct coap_packet *cpkt,
1315 struct coap_block_context *ctx)
1316 {
1317 int r, val = 0;
1318 uint16_t bytes = coap_block_size_to_bytes(ctx->block_size);
1319
1320 if (coap_packet_is_request(cpkt)) {
1321 SET_BLOCK_SIZE(val, ctx->block_size);
1322 SET_NUM(val, ctx->current / bytes);
1323 } else {
1324 SET_BLOCK_SIZE(val, ctx->block_size);
1325 SET_MORE(val, ctx->current + bytes < ctx->total_size);
1326 SET_NUM(val, ctx->current / bytes);
1327 }
1328
1329 r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK2, val);
1330
1331 return r;
1332 }
1333
coap_append_size1_option(struct coap_packet * cpkt,struct coap_block_context * ctx)1334 int coap_append_size1_option(struct coap_packet *cpkt,
1335 struct coap_block_context *ctx)
1336 {
1337 return coap_append_option_int(cpkt, COAP_OPTION_SIZE1, ctx->total_size);
1338 }
1339
coap_append_size2_option(struct coap_packet * cpkt,struct coap_block_context * ctx)1340 int coap_append_size2_option(struct coap_packet *cpkt,
1341 struct coap_block_context *ctx)
1342 {
1343 return coap_append_option_int(cpkt, COAP_OPTION_SIZE2, ctx->total_size);
1344 }
1345
coap_get_option_int(const struct coap_packet * cpkt,uint16_t code)1346 int coap_get_option_int(const struct coap_packet *cpkt, uint16_t code)
1347 {
1348 struct coap_option option = {};
1349 unsigned int val;
1350 int count = 1;
1351
1352 count = coap_find_options(cpkt, code, &option, count);
1353 if (count <= 0) {
1354 return -ENOENT;
1355 }
1356
1357 val = coap_option_value_to_int(&option);
1358
1359 return val;
1360 }
1361
coap_get_block1_option(const struct coap_packet * cpkt,bool * has_more,uint32_t * block_number)1362 int coap_get_block1_option(const struct coap_packet *cpkt, bool *has_more, uint32_t *block_number)
1363 {
1364 int ret = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1365
1366 if (ret < 0) {
1367 return ret;
1368 }
1369
1370 *has_more = GET_MORE(ret);
1371 *block_number = GET_NUM(ret);
1372 ret = 1 << (GET_BLOCK_SIZE(ret) + 4);
1373 return ret;
1374 }
1375
coap_get_block2_option(const struct coap_packet * cpkt,bool * has_more,uint32_t * block_number)1376 int coap_get_block2_option(const struct coap_packet *cpkt, bool *has_more,
1377 uint32_t *block_number)
1378 {
1379 int ret = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1380
1381 if (ret < 0) {
1382 return ret;
1383 }
1384
1385 *has_more = GET_MORE(ret);
1386 *block_number = GET_NUM(ret);
1387 ret = 1 << (GET_BLOCK_SIZE(ret) + 4);
1388 return ret;
1389 }
1390
insert_option(struct coap_packet * cpkt,uint16_t code,const uint8_t * value,uint16_t len)1391 int insert_option(struct coap_packet *cpkt, uint16_t code, const uint8_t *value, uint16_t len)
1392 {
1393 uint16_t offset = cpkt->hdr_len;
1394 uint16_t opt_delta = 0;
1395 uint16_t opt_len = 0;
1396 uint16_t last_opt = 0;
1397 uint16_t last_offset = cpkt->hdr_len;
1398 struct coap_option option = {0};
1399 int r;
1400
1401 while (offset < cpkt->hdr_len + cpkt->opt_len) {
1402 r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len,
1403 &opt_delta, &opt_len, &option);
1404 if (r < 0) {
1405 return -EILSEQ;
1406 }
1407
1408 if (opt_delta > code) {
1409 break;
1410 }
1411
1412 last_opt = opt_delta;
1413 last_offset = offset;
1414 }
1415
1416 const uint16_t option_size = offset - last_offset;
1417 /* clear option after new option (delta changed) */
1418 memmove(cpkt->data + last_offset, cpkt->data + offset, cpkt->offset - offset);
1419 cpkt->opt_len -= option_size;
1420 cpkt->offset -= option_size;
1421
1422 /* add the new option */
1423 const uint16_t new_option_delta = code - last_opt;
1424
1425 r = encode_option(cpkt, new_option_delta, value, len, last_offset);
1426 if (r < 0) {
1427 return -EINVAL;
1428 }
1429 cpkt->opt_len += r;
1430
1431 /* reinsert option that comes after the new option (with adjusted delta) */
1432 r = encode_option(cpkt, option.delta - code, option.value, option.len, last_offset + r);
1433 if (r < 0) {
1434 return -EINVAL;
1435 }
1436 cpkt->opt_len += r;
1437
1438 return 0;
1439 }
1440
update_descriptive_block(struct coap_block_context * ctx,int block,int size)1441 static int update_descriptive_block(struct coap_block_context *ctx,
1442 int block, int size)
1443 {
1444 size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1445
1446 if (block == -ENOENT) {
1447 return 0;
1448 }
1449
1450 if (size && ctx->total_size && ctx->total_size != size) {
1451 return -EINVAL;
1452 }
1453
1454 if (ctx->current > 0 && GET_BLOCK_SIZE(block) > ctx->block_size) {
1455 return -EINVAL;
1456 }
1457
1458 if (ctx->total_size && new_current > ctx->total_size) {
1459 return -EINVAL;
1460 }
1461
1462 if (size) {
1463 ctx->total_size = size;
1464 }
1465 ctx->current = new_current;
1466 ctx->block_size = MIN(GET_BLOCK_SIZE(block), ctx->block_size);
1467
1468 return 0;
1469 }
1470
update_control_block1(struct coap_block_context * ctx,int block,int size)1471 static int update_control_block1(struct coap_block_context *ctx,
1472 int block, int size)
1473 {
1474 size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1475
1476 if (block == -ENOENT) {
1477 return 0;
1478 }
1479
1480 if (new_current != ctx->current) {
1481 return -EINVAL;
1482 }
1483
1484 if (GET_BLOCK_SIZE(block) > ctx->block_size) {
1485 return -EINVAL;
1486 }
1487
1488 ctx->block_size = GET_BLOCK_SIZE(block);
1489
1490 if (size >= 0) {
1491 ctx->total_size = size;
1492 }
1493
1494 return 0;
1495 }
1496
update_control_block2(struct coap_block_context * ctx,int block,int size)1497 static int update_control_block2(struct coap_block_context *ctx,
1498 int block, int size)
1499 {
1500 size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1501
1502 if (block == -ENOENT) {
1503 return 0;
1504 }
1505
1506 if (GET_MORE(block)) {
1507 return -EINVAL;
1508 }
1509
1510 if (GET_NUM(block) > 0 && GET_BLOCK_SIZE(block) != ctx->block_size) {
1511 return -EINVAL;
1512 }
1513
1514 ctx->current = new_current;
1515 ctx->block_size = MIN(GET_BLOCK_SIZE(block), ctx->block_size);
1516
1517 return 0;
1518 }
1519
coap_update_from_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1520 int coap_update_from_block(const struct coap_packet *cpkt,
1521 struct coap_block_context *ctx)
1522 {
1523 int r, block1, block2, size1, size2;
1524
1525 block1 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1526 block2 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1527 size1 = coap_get_option_int(cpkt, COAP_OPTION_SIZE1);
1528 size2 = coap_get_option_int(cpkt, COAP_OPTION_SIZE2);
1529
1530 if (coap_packet_is_request(cpkt)) {
1531 r = update_control_block2(ctx, block2, size2);
1532 if (r) {
1533 return r;
1534 }
1535
1536 return update_descriptive_block(ctx, block1, size1 == -ENOENT ? 0 : size1);
1537 }
1538
1539 r = update_control_block1(ctx, block1, size1);
1540 if (r) {
1541 return r;
1542 }
1543
1544 return update_descriptive_block(ctx, block2, size2 == -ENOENT ? 0 : size2);
1545 }
1546
coap_next_block_for_option(const struct coap_packet * cpkt,struct coap_block_context * ctx,enum coap_option_num option)1547 int coap_next_block_for_option(const struct coap_packet *cpkt,
1548 struct coap_block_context *ctx,
1549 enum coap_option_num option)
1550 {
1551 int block;
1552 uint16_t block_len = 0;
1553
1554 if (option != COAP_OPTION_BLOCK1 && option != COAP_OPTION_BLOCK2) {
1555 return -EINVAL;
1556 }
1557
1558 block = coap_get_option_int(cpkt, option);
1559
1560 if (block < 0) {
1561 return block;
1562 }
1563
1564 coap_packet_get_payload(cpkt, &block_len);
1565 /* Check that the package does not exceed the expected size ONLY */
1566 if ((ctx->total_size > 0) &&
1567 (ctx->total_size < (ctx->current + block_len))) {
1568 return -EMSGSIZE;
1569 }
1570 ctx->current += block_len;
1571
1572 if (!GET_MORE(block)) {
1573 return 0;
1574 }
1575
1576 return (int)ctx->current;
1577 }
1578
coap_next_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1579 size_t coap_next_block(const struct coap_packet *cpkt,
1580 struct coap_block_context *ctx)
1581 {
1582 enum coap_option_num option;
1583 int ret;
1584
1585 option = coap_packet_is_request(cpkt) ? COAP_OPTION_BLOCK1 : COAP_OPTION_BLOCK2;
1586 ret = coap_next_block_for_option(cpkt, ctx, option);
1587
1588 return MAX(ret, 0);
1589 }
1590
coap_pending_init(struct coap_pending * pending,const struct coap_packet * request,const struct sockaddr * addr,const struct coap_transmission_parameters * params)1591 int coap_pending_init(struct coap_pending *pending,
1592 const struct coap_packet *request,
1593 const struct sockaddr *addr,
1594 const struct coap_transmission_parameters *params)
1595 {
1596 memset(pending, 0, sizeof(*pending));
1597
1598 pending->id = coap_header_get_id(request);
1599
1600 memcpy(&pending->addr, addr, sizeof(*addr));
1601
1602 if (params) {
1603 pending->params = *params;
1604 } else {
1605 pending->params = coap_transmission_params;
1606 }
1607
1608 pending->data = request->data;
1609 pending->len = request->offset;
1610 pending->t0 = k_uptime_get();
1611 pending->retries = pending->params.max_retransmission;
1612
1613 return 0;
1614 }
1615
coap_pending_next_unused(struct coap_pending * pendings,size_t len)1616 struct coap_pending *coap_pending_next_unused(
1617 struct coap_pending *pendings, size_t len)
1618 {
1619 struct coap_pending *p;
1620 size_t i;
1621
1622 for (i = 0, p = pendings; i < len; i++, p++) {
1623 if (p->data == 0) {
1624 return p;
1625 }
1626 }
1627
1628 return NULL;
1629 }
1630
coap_reply_next_unused(struct coap_reply * replies,size_t len)1631 struct coap_reply *coap_reply_next_unused(
1632 struct coap_reply *replies, size_t len)
1633 {
1634 struct coap_reply *r;
1635 size_t i;
1636
1637 for (i = 0, r = replies; i < len; i++, r++) {
1638 if (!r->reply) {
1639 return r;
1640 }
1641 }
1642
1643 return NULL;
1644 }
1645
is_addr_unspecified(const struct sockaddr * addr)1646 static inline bool is_addr_unspecified(const struct sockaddr *addr)
1647 {
1648 if (addr->sa_family == AF_UNSPEC) {
1649 return true;
1650 }
1651
1652 if (addr->sa_family == AF_INET6) {
1653 return net_ipv6_is_addr_unspecified(
1654 &(net_sin6(addr)->sin6_addr));
1655 } else if (addr->sa_family == AF_INET) {
1656 return net_sin(addr)->sin_addr.s4_addr32[0] == 0U;
1657 }
1658
1659 return false;
1660 }
1661
coap_observer_next_unused(struct coap_observer * observers,size_t len)1662 struct coap_observer *coap_observer_next_unused(
1663 struct coap_observer *observers, size_t len)
1664 {
1665 struct coap_observer *o;
1666 size_t i;
1667
1668 for (i = 0, o = observers; i < len; i++, o++) {
1669 if (is_addr_unspecified(&o->addr)) {
1670 return o;
1671 }
1672 }
1673
1674 return NULL;
1675 }
1676
coap_pending_received(const struct coap_packet * response,struct coap_pending * pendings,size_t len)1677 struct coap_pending *coap_pending_received(
1678 const struct coap_packet *response,
1679 struct coap_pending *pendings, size_t len)
1680 {
1681 struct coap_pending *p;
1682 uint16_t resp_id = coap_header_get_id(response);
1683 size_t i;
1684
1685 for (i = 0, p = pendings; i < len; i++, p++) {
1686 if (!p->timeout) {
1687 continue;
1688 }
1689
1690 if (resp_id != p->id) {
1691 continue;
1692 }
1693
1694 return p;
1695 }
1696
1697 return NULL;
1698 }
1699
coap_pending_next_to_expire(struct coap_pending * pendings,size_t len)1700 struct coap_pending *coap_pending_next_to_expire(
1701 struct coap_pending *pendings, size_t len)
1702 {
1703 struct coap_pending *p, *found = NULL;
1704 size_t i;
1705 int64_t expiry, min_expiry = INT64_MAX;
1706
1707 for (i = 0, p = pendings; i < len; i++, p++) {
1708 if (!p->timeout) {
1709 continue;
1710 }
1711
1712 expiry = p->t0 + p->timeout;
1713
1714 if (expiry < min_expiry) {
1715 min_expiry = expiry;
1716 found = p;
1717 }
1718 }
1719
1720 return found;
1721 }
1722
init_ack_timeout(const struct coap_transmission_parameters * params)1723 static uint32_t init_ack_timeout(const struct coap_transmission_parameters *params)
1724 {
1725 #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT)
1726 const uint16_t random_percent = params->ack_random_percent ? params->ack_random_percent
1727 : CONFIG_COAP_ACK_RANDOM_PERCENT;
1728 const uint32_t max_ack = params->ack_timeout * random_percent / 100U;
1729 const uint32_t min_ack = params->ack_timeout;
1730
1731 /* Randomly generated initial ACK timeout
1732 * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR
1733 * Ref: https://tools.ietf.org/html/rfc7252#section-4.8
1734 */
1735 return min_ack + (sys_rand32_get() % (max_ack - min_ack));
1736 #else
1737 return params->ack_timeout;
1738 #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */
1739 }
1740
coap_pending_cycle(struct coap_pending * pending)1741 bool coap_pending_cycle(struct coap_pending *pending)
1742 {
1743 if (pending->timeout == 0) {
1744 /* Initial transmission. */
1745 pending->timeout = init_ack_timeout(&pending->params);
1746 return true;
1747 }
1748
1749 if (pending->retries == 0) {
1750 return false;
1751 }
1752
1753 pending->t0 += pending->timeout;
1754 pending->timeout = pending->timeout * pending->params.coap_backoff_percent / 100;
1755 pending->retries--;
1756
1757 return true;
1758 }
1759
coap_pending_clear(struct coap_pending * pending)1760 void coap_pending_clear(struct coap_pending *pending)
1761 {
1762 pending->timeout = 0;
1763 pending->data = NULL;
1764 }
1765
coap_pendings_clear(struct coap_pending * pendings,size_t len)1766 void coap_pendings_clear(struct coap_pending *pendings, size_t len)
1767 {
1768 struct coap_pending *p;
1769 size_t i;
1770
1771 for (i = 0, p = pendings; i < len; i++, p++) {
1772 coap_pending_clear(p);
1773 }
1774 }
1775
coap_pendings_count(struct coap_pending * pendings,size_t len)1776 size_t coap_pendings_count(struct coap_pending *pendings, size_t len)
1777 {
1778 struct coap_pending *p = pendings;
1779 size_t c = 0;
1780
1781 for (size_t i = 0; i < len && p; i++, p++) {
1782 if (p->timeout) {
1783 c++;
1784 }
1785 }
1786 return c;
1787 }
1788
1789 /* Reordering according to RFC7641 section 3.4 but without timestamp comparison */
1790 IF_DISABLED(CONFIG_ZTEST, (static inline))
coap_age_is_newer(int v1,int v2)1791 bool coap_age_is_newer(int v1, int v2)
1792 {
1793 return (v1 < v2 && v2 - v1 < (1 << 23))
1794 || (v1 > v2 && v1 - v2 > (1 << 23));
1795 }
1796
coap_observer_increment_age(struct coap_resource * resource)1797 static inline void coap_observer_increment_age(struct coap_resource *resource)
1798 {
1799 resource->age++;
1800 if (resource->age > COAP_OBSERVE_MAX_AGE) {
1801 resource->age = COAP_OBSERVE_FIRST_OFFSET;
1802 }
1803 }
1804
coap_response_received(const struct coap_packet * response,const struct sockaddr * from,struct coap_reply * replies,size_t len)1805 struct coap_reply *coap_response_received(
1806 const struct coap_packet *response,
1807 const struct sockaddr *from,
1808 struct coap_reply *replies, size_t len)
1809 {
1810 struct coap_reply *r;
1811 uint8_t token[COAP_TOKEN_MAX_LEN];
1812 bool piggybacked = false;
1813 uint8_t type;
1814 uint16_t id;
1815 uint8_t tkl;
1816 size_t i;
1817
1818 type = coap_header_get_type(response);
1819 id = coap_header_get_id(response);
1820 tkl = coap_header_get_token(response, token);
1821
1822 if ((type == COAP_TYPE_ACK && is_empty_message(response)) ||
1823 coap_packet_is_request(response)) {
1824 /* Request or empty ACK can't be response */
1825 return NULL;
1826 }
1827
1828 if (type == COAP_TYPE_ACK) {
1829 piggybacked = true;
1830 }
1831
1832 for (i = 0, r = replies; i < len; i++, r++) {
1833 int age;
1834
1835 /* Skip unused entry. */
1836 if (r->reply == NULL) {
1837 continue;
1838 }
1839
1840 /* Reset should only be handled if Message ID matches. */
1841 if (type == COAP_TYPE_RESET) {
1842 if (r->id != id) {
1843 continue;
1844 }
1845
1846 goto handle_reply;
1847 }
1848
1849 /* In a piggybacked response, the Message ID of the Confirmable
1850 * request and the Acknowledgment MUST match, and the tokens of
1851 * the response and original request MUST match. In a separate
1852 * response, just the tokens of the response and original request
1853 * MUST match.
1854 */
1855 if (piggybacked) {
1856 if (r->id != id) {
1857 continue;
1858 }
1859 }
1860
1861 if (r->tkl != tkl) {
1862 continue;
1863 }
1864
1865 if (r->tkl > 0) {
1866 if (memcmp(r->token, token, r->tkl) != 0) {
1867 continue;
1868 }
1869 }
1870
1871 age = coap_get_option_int(response, COAP_OPTION_OBSERVE);
1872 /* handle observed requests only if received in order */
1873 if (age == -ENOENT || coap_age_is_newer(r->age, age)) {
1874 r->age = age;
1875 if (coap_header_get_code(response) != COAP_RESPONSE_CODE_CONTINUE) {
1876 handle_reply:
1877 r->reply(response, r, from);
1878 }
1879 }
1880
1881 return r;
1882 }
1883
1884 return NULL;
1885 }
1886
coap_reply_init(struct coap_reply * reply,const struct coap_packet * request)1887 void coap_reply_init(struct coap_reply *reply,
1888 const struct coap_packet *request)
1889 {
1890 uint8_t token[COAP_TOKEN_MAX_LEN];
1891 uint8_t tkl;
1892
1893 reply->id = coap_header_get_id(request);
1894 tkl = coap_header_get_token(request, token);
1895
1896 if (tkl > 0) {
1897 memcpy(reply->token, token, tkl);
1898 }
1899
1900 reply->tkl = tkl;
1901
1902 /* Any initial observe response should be accepted */
1903 reply->age = -1;
1904 }
1905
coap_reply_clear(struct coap_reply * reply)1906 void coap_reply_clear(struct coap_reply *reply)
1907 {
1908 (void)memset(reply, 0, sizeof(*reply));
1909 }
1910
coap_replies_clear(struct coap_reply * replies,size_t len)1911 void coap_replies_clear(struct coap_reply *replies, size_t len)
1912 {
1913 struct coap_reply *r;
1914 size_t i;
1915
1916 for (i = 0, r = replies; i < len; i++, r++) {
1917 coap_reply_clear(r);
1918 }
1919 }
1920
coap_resource_notify(struct coap_resource * resource)1921 int coap_resource_notify(struct coap_resource *resource)
1922 {
1923 struct coap_observer *o;
1924
1925 if (!resource->notify) {
1926 return -ENOENT;
1927 }
1928
1929 if (sys_slist_is_empty(&resource->observers)) {
1930 return 0;
1931 }
1932
1933 coap_observer_increment_age(resource);
1934
1935 SYS_SLIST_FOR_EACH_CONTAINER(&resource->observers, o, list) {
1936 resource->notify(resource, o);
1937 }
1938
1939 return 0;
1940 }
1941
coap_request_is_observe(const struct coap_packet * request)1942 bool coap_request_is_observe(const struct coap_packet *request)
1943 {
1944 return coap_get_option_int(request, COAP_OPTION_OBSERVE) == 0;
1945 }
1946
coap_observer_init(struct coap_observer * observer,const struct coap_packet * request,const struct sockaddr * addr)1947 void coap_observer_init(struct coap_observer *observer,
1948 const struct coap_packet *request,
1949 const struct sockaddr *addr)
1950 {
1951 observer->tkl = coap_header_get_token(request, observer->token);
1952
1953 net_ipaddr_copy(&observer->addr, addr);
1954 }
1955
coap_observer_raise_event(struct coap_resource * resource,struct coap_observer * observer,uint32_t mgmt_event)1956 static inline void coap_observer_raise_event(struct coap_resource *resource,
1957 struct coap_observer *observer,
1958 uint32_t mgmt_event)
1959 {
1960 #ifdef CONFIG_NET_MGMT_EVENT_INFO
1961 const struct net_event_coap_observer net_event = {
1962 .resource = resource,
1963 .observer = observer,
1964 };
1965
1966 net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event));
1967 #else
1968 ARG_UNUSED(resource);
1969 ARG_UNUSED(observer);
1970
1971 net_mgmt_event_notify(mgmt_event, NULL);
1972 #endif
1973 }
1974
coap_register_observer(struct coap_resource * resource,struct coap_observer * observer)1975 bool coap_register_observer(struct coap_resource *resource,
1976 struct coap_observer *observer)
1977 {
1978 bool first;
1979
1980 sys_slist_append(&resource->observers, &observer->list);
1981
1982 first = resource->age == 0;
1983 if (first) {
1984 resource->age = COAP_OBSERVE_FIRST_OFFSET;
1985 }
1986
1987 coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_ADDED);
1988
1989 return first;
1990 }
1991
coap_remove_observer(struct coap_resource * resource,struct coap_observer * observer)1992 bool coap_remove_observer(struct coap_resource *resource,
1993 struct coap_observer *observer)
1994 {
1995 if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) {
1996 return false;
1997 }
1998
1999 coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_REMOVED);
2000
2001 return true;
2002 }
2003
sockaddr_equal(const struct sockaddr * a,const struct sockaddr * b)2004 static bool sockaddr_equal(const struct sockaddr *a,
2005 const struct sockaddr *b)
2006 {
2007 /* FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to
2008 * ipv4 addresses?
2009 */
2010 if (a->sa_family != b->sa_family) {
2011 return false;
2012 }
2013
2014 if (a->sa_family == AF_INET) {
2015 const struct sockaddr_in *a4 = net_sin(a);
2016 const struct sockaddr_in *b4 = net_sin(b);
2017
2018 if (a4->sin_port != b4->sin_port) {
2019 return false;
2020 }
2021
2022 return net_ipv4_addr_cmp(&a4->sin_addr, &b4->sin_addr);
2023 }
2024
2025 if (b->sa_family == AF_INET6) {
2026 const struct sockaddr_in6 *a6 = net_sin6(a);
2027 const struct sockaddr_in6 *b6 = net_sin6(b);
2028
2029 if (a6->sin6_port != b6->sin6_port) {
2030 return false;
2031 }
2032
2033 return net_ipv6_addr_cmp(&a6->sin6_addr, &b6->sin6_addr);
2034 }
2035
2036 /* Invalid address family */
2037 return false;
2038 }
2039
coap_find_observer(struct coap_observer * observers,size_t len,const struct sockaddr * addr,const uint8_t * token,uint8_t token_len)2040 struct coap_observer *coap_find_observer(
2041 struct coap_observer *observers, size_t len,
2042 const struct sockaddr *addr,
2043 const uint8_t *token, uint8_t token_len)
2044 {
2045 if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) {
2046 return NULL;
2047 }
2048
2049 for (size_t i = 0; i < len; i++) {
2050 struct coap_observer *o = &observers[i];
2051
2052 if (o->tkl == token_len &&
2053 memcmp(o->token, token, token_len) == 0 &&
2054 sockaddr_equal(&o->addr, addr)) {
2055 return o;
2056 }
2057 }
2058
2059 return NULL;
2060 }
2061
coap_find_observer_by_addr(struct coap_observer * observers,size_t len,const struct sockaddr * addr)2062 struct coap_observer *coap_find_observer_by_addr(
2063 struct coap_observer *observers, size_t len,
2064 const struct sockaddr *addr)
2065 {
2066 size_t i;
2067
2068 for (i = 0; i < len; i++) {
2069 struct coap_observer *o = &observers[i];
2070
2071 if (sockaddr_equal(&o->addr, addr)) {
2072 return o;
2073 }
2074 }
2075
2076 return NULL;
2077 }
2078
coap_find_observer_by_token(struct coap_observer * observers,size_t len,const uint8_t * token,uint8_t token_len)2079 struct coap_observer *coap_find_observer_by_token(
2080 struct coap_observer *observers, size_t len,
2081 const uint8_t *token, uint8_t token_len)
2082 {
2083 if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) {
2084 return NULL;
2085 }
2086
2087 for (size_t i = 0; i < len; i++) {
2088 struct coap_observer *o = &observers[i];
2089
2090 if (o->tkl == token_len && memcmp(o->token, token, token_len) == 0) {
2091 return o;
2092 }
2093 }
2094
2095 return NULL;
2096 }
2097
2098 /**
2099 * @brief Internal initialization function for CoAP library.
2100 *
2101 * Called by the network layer init procedure. Seeds the CoAP @message_id with a
2102 * random number in accordance with recommendations in CoAP specification.
2103 *
2104 * @note This function is not exposed in a public header, as it's for internal
2105 * use and should therefore not be exposed to applications.
2106 */
net_coap_init(void)2107 void net_coap_init(void)
2108 {
2109 /* Initialize message_id to a random number */
2110 message_id = (uint16_t)sys_rand32_get();
2111 }
2112
coap_next_id(void)2113 uint16_t coap_next_id(void)
2114 {
2115 return message_id++;
2116 }
2117
coap_get_transmission_parameters(void)2118 struct coap_transmission_parameters coap_get_transmission_parameters(void)
2119 {
2120 return coap_transmission_params;
2121 }
2122
coap_set_transmission_parameters(const struct coap_transmission_parameters * params)2123 void coap_set_transmission_parameters(const struct coap_transmission_parameters *params)
2124 {
2125 coap_transmission_params = *params;
2126 }
2127