1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <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 <random/rand32.h>
16 #include <sys/atomic.h>
17 #include <sys/util.h>
18 
19 #include <zephyr/types.h>
20 #include <sys/byteorder.h>
21 #include <sys/math_extras.h>
22 
23 #include <net/net_ip.h>
24 #include <net/net_core.h>
25 #include <net/coap.h>
26 
27 /* Values as per RFC 7252, section-3.1.
28  *
29  * Option Delta/Length: 4-bit unsigned integer. A value between 0 and
30  * 12 indicates the Option Delta/Length.  Three values are reserved for
31  * special constructs:
32  * 13: An 8-bit unsigned integer precedes the Option Value and indicates
33  *     the Option Delta/Length minus 13.
34  * 14: A 16-bit unsigned integer in network byte order precedes the
35  *     Option Value and indicates the Option Delta/Length minus 269.
36  * 15: Reserved for future use.
37  */
38 #define COAP_OPTION_NO_EXT 12 /* Option's Delta/Length without extended data */
39 #define COAP_OPTION_EXT_13 13
40 #define COAP_OPTION_EXT_14 14
41 #define COAP_OPTION_EXT_15 15
42 #define COAP_OPTION_EXT_269 269
43 
44 /* CoAP Payload Marker */
45 #define COAP_MARKER		0xFF
46 
47 #define BASIC_HEADER_SIZE	4
48 
49 /* The CoAP message ID that is incremented each time coap_next_id() is called. */
50 static uint16_t message_id;
51 
append_u8(struct coap_packet * cpkt,uint8_t data)52 static inline bool append_u8(struct coap_packet *cpkt, uint8_t data)
53 {
54 	if (!cpkt) {
55 		return false;
56 	}
57 
58 	if (cpkt->max_len - cpkt->offset < 1) {
59 		return false;
60 	}
61 
62 	cpkt->data[cpkt->offset++] = data;
63 
64 	return true;
65 }
66 
append_be16(struct coap_packet * cpkt,uint16_t data)67 static inline bool append_be16(struct coap_packet *cpkt, uint16_t data)
68 {
69 	if (!cpkt) {
70 		return false;
71 	}
72 
73 	if (cpkt->max_len - cpkt->offset < 2) {
74 		return false;
75 	}
76 
77 	cpkt->data[cpkt->offset++] = data >> 8;
78 	cpkt->data[cpkt->offset++] = (uint8_t) data;
79 
80 	return true;
81 }
82 
append(struct coap_packet * cpkt,const uint8_t * data,uint16_t len)83 static inline bool append(struct coap_packet *cpkt, const uint8_t *data, uint16_t len)
84 {
85 	if (!cpkt || !data) {
86 		return false;
87 	}
88 
89 	if (cpkt->max_len - cpkt->offset < len) {
90 		return false;
91 	}
92 
93 	memcpy(cpkt->data + cpkt->offset, data, len);
94 	cpkt->offset += len;
95 
96 	return true;
97 }
98 
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)99 int coap_packet_init(struct coap_packet *cpkt, uint8_t *data, uint16_t max_len,
100 		     uint8_t ver, uint8_t type, uint8_t token_len,
101 		     const uint8_t *token, uint8_t code, uint16_t id)
102 {
103 	uint8_t hdr;
104 	bool res;
105 
106 	if (!cpkt || !data || !max_len) {
107 		return -EINVAL;
108 	}
109 
110 	memset(cpkt, 0, sizeof(*cpkt));
111 
112 	cpkt->data = data;
113 	cpkt->offset = 0U;
114 	cpkt->max_len = max_len;
115 	cpkt->delta = 0U;
116 
117 	hdr = (ver & 0x3) << 6;
118 	hdr |= (type & 0x3) << 4;
119 	hdr |= token_len & 0xF;
120 
121 	res = append_u8(cpkt, hdr);
122 	if (!res) {
123 		return -EINVAL;
124 	}
125 
126 	res = append_u8(cpkt, code);
127 	if (!res) {
128 		return -EINVAL;
129 	}
130 
131 	res = append_be16(cpkt, id);
132 	if (!res) {
133 		return -EINVAL;
134 	}
135 
136 	if (token && token_len) {
137 		res = append(cpkt, token, token_len);
138 		if (!res) {
139 			return -EINVAL;
140 		}
141 	}
142 
143 	/* Header length : (version + type + tkl) + code + id + [token] */
144 	cpkt->hdr_len = 1 + 1 + 2 + token_len;
145 
146 	return 0;
147 }
148 
coap_ack_init(struct coap_packet * cpkt,const struct coap_packet * req,uint8_t * data,uint16_t max_len,uint8_t code)149 int coap_ack_init(struct coap_packet *cpkt, const struct coap_packet *req,
150 		  uint8_t *data, uint16_t max_len, uint8_t code)
151 {
152 	uint16_t id;
153 	uint8_t ver;
154 	uint8_t tkl;
155 	uint8_t token[COAP_TOKEN_MAX_LEN];
156 
157 	ver = coap_header_get_version(req);
158 	id = coap_header_get_id(req);
159 	tkl = code ? coap_header_get_token(req, token) : 0;
160 
161 	return coap_packet_init(cpkt, data, max_len, ver, COAP_TYPE_ACK, tkl,
162 				token, code, id);
163 }
164 
option_header_set_delta(uint8_t * opt,uint8_t delta)165 static void option_header_set_delta(uint8_t *opt, uint8_t delta)
166 {
167 	*opt = (delta & 0xF) << 4;
168 }
169 
option_header_set_len(uint8_t * opt,uint8_t len)170 static void option_header_set_len(uint8_t *opt, uint8_t len)
171 {
172 	*opt |= (len & 0xF);
173 }
174 
encode_extended_option(uint16_t num,uint8_t * opt,uint16_t * ext)175 static uint8_t encode_extended_option(uint16_t num, uint8_t *opt, uint16_t *ext)
176 {
177 	if (num < COAP_OPTION_EXT_13) {
178 		*opt = num;
179 		*ext = 0U;
180 
181 		return 0;
182 	} else if (num < COAP_OPTION_EXT_269) {
183 		*opt = COAP_OPTION_EXT_13;
184 		*ext = num - COAP_OPTION_EXT_13;
185 
186 		return 1;
187 	}
188 
189 	*opt = COAP_OPTION_EXT_14;
190 	*ext = num - COAP_OPTION_EXT_269;
191 
192 	return 2;
193 }
194 
encode_option(struct coap_packet * cpkt,uint16_t code,const uint8_t * value,uint16_t len)195 static int encode_option(struct coap_packet *cpkt, uint16_t code,
196 			 const uint8_t *value, uint16_t len)
197 {
198 	uint16_t delta_ext; /* Extended delta */
199 	uint16_t len_ext; /* Extended length */
200 	uint8_t opt; /* delta | len */
201 	uint8_t opt_delta;
202 	uint8_t opt_len;
203 	uint8_t delta_size;
204 	uint8_t len_size;
205 	bool res;
206 
207 	delta_size = encode_extended_option(code, &opt_delta, &delta_ext);
208 	len_size = encode_extended_option(len, &opt_len, &len_ext);
209 
210 	option_header_set_delta(&opt, opt_delta);
211 	option_header_set_len(&opt, opt_len);
212 
213 	res = append_u8(cpkt, opt);
214 	if (!res) {
215 		return -EINVAL;
216 	}
217 
218 	if (delta_size == 1U) {
219 		res = append_u8(cpkt, (uint8_t)delta_ext);
220 		if (!res) {
221 			return -EINVAL;
222 		}
223 	} else if (delta_size == 2U) {
224 		res = append_be16(cpkt, delta_ext);
225 		if (!res) {
226 			return -EINVAL;
227 		}
228 	}
229 
230 	if (len_size == 1U) {
231 		res = append_u8(cpkt, (uint8_t)len_ext);
232 		if (!res) {
233 			return -EINVAL;
234 		}
235 	} else if (len_size == 2U) {
236 		res = append_be16(cpkt, len_ext);
237 		if (!res) {
238 			return -EINVAL;
239 		}
240 	}
241 
242 	if (len && value) {
243 		res = append(cpkt, value, len);
244 		if (!res) {
245 			return -EINVAL;
246 		}
247 	}
248 
249 	return  (1 + delta_size + len_size + len);
250 }
251 
252 /* TODO Add support for inserting options in proper place
253  * and modify other option's delta accordingly.
254  */
coap_packet_append_option(struct coap_packet * cpkt,uint16_t code,const uint8_t * value,uint16_t len)255 int coap_packet_append_option(struct coap_packet *cpkt, uint16_t code,
256 			      const uint8_t *value, uint16_t len)
257 {
258 	int r;
259 
260 	if (!cpkt) {
261 		return -EINVAL;
262 	}
263 
264 	if (len && !value) {
265 		return -EINVAL;
266 	}
267 
268 	if (code < cpkt->delta) {
269 		NET_ERR("Options should be in ascending order");
270 		return -EINVAL;
271 	}
272 
273 	/* Calculate delta, if this option is not the first one */
274 	if (cpkt->opt_len) {
275 		code = (code == cpkt->delta) ? 0 : code - cpkt->delta;
276 	}
277 
278 	r = encode_option(cpkt, code, value, len);
279 	if (r < 0) {
280 		return -EINVAL;
281 	}
282 
283 	cpkt->opt_len += r;
284 	cpkt->delta += code;
285 
286 	return 0;
287 }
288 
coap_append_option_int(struct coap_packet * cpkt,uint16_t code,unsigned int val)289 int coap_append_option_int(struct coap_packet *cpkt, uint16_t code,
290 			   unsigned int val)
291 {
292 	uint8_t data[4], len;
293 
294 	if (val == 0U) {
295 		data[0] = 0U;
296 		len = 0U;
297 	} else if (val < 0xFF) {
298 		data[0] = (uint8_t) val;
299 		len = 1U;
300 	} else if (val < 0xFFFF) {
301 		sys_put_be16(val, data);
302 		len = 2U;
303 	} else if (val < 0xFFFFFF) {
304 		sys_put_be16(val, &data[1]);
305 		data[0] = val >> 16;
306 		len = 3U;
307 	} else {
308 		sys_put_be32(val, data);
309 		len = 4U;
310 	}
311 
312 	return coap_packet_append_option(cpkt, code, data, len);
313 }
314 
coap_option_value_to_int(const struct coap_option * option)315 unsigned int coap_option_value_to_int(const struct coap_option *option)
316 {
317 	switch (option->len) {
318 	case 0:
319 		return 0;
320 	case 1:
321 		return option->value[0];
322 	case 2:
323 		return (option->value[1] << 0) | (option->value[0] << 8);
324 	case 3:
325 		return (option->value[2] << 0) | (option->value[1] << 8) |
326 			(option->value[0] << 16);
327 	case 4:
328 		return (option->value[3] << 0) | (option->value[2] << 8) |
329 			(option->value[1] << 16) | (option->value[0] << 24);
330 	default:
331 		return 0;
332 	}
333 
334 	return 0;
335 }
336 
coap_packet_append_payload_marker(struct coap_packet * cpkt)337 int coap_packet_append_payload_marker(struct coap_packet *cpkt)
338 {
339 	return append_u8(cpkt, COAP_MARKER) ? 0 : -EINVAL;
340 }
341 
coap_packet_append_payload(struct coap_packet * cpkt,const uint8_t * payload,uint16_t payload_len)342 int coap_packet_append_payload(struct coap_packet *cpkt, const uint8_t *payload,
343 			       uint16_t payload_len)
344 {
345 	return append(cpkt, payload, payload_len) ? 0 : -EINVAL;
346 }
347 
coap_next_token(void)348 uint8_t *coap_next_token(void)
349 {
350 	static uint8_t token[COAP_TOKEN_MAX_LEN];
351 
352 	sys_rand_get(token, COAP_TOKEN_MAX_LEN);
353 
354 	return token;
355 }
356 
option_header_get_delta(uint8_t opt)357 static uint8_t option_header_get_delta(uint8_t opt)
358 {
359 	return (opt & 0xF0) >> 4;
360 }
361 
option_header_get_len(uint8_t opt)362 static uint8_t option_header_get_len(uint8_t opt)
363 {
364 	return opt & 0x0F;
365 }
366 
read_u8(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint8_t * value)367 static int read_u8(uint8_t *data, uint16_t offset, uint16_t *pos,
368 		   uint16_t max_len, uint8_t *value)
369 {
370 	if (max_len - offset < 1) {
371 		return -EINVAL;
372 	}
373 
374 	*value = data[offset++];
375 	*pos = offset;
376 
377 	return max_len - offset;
378 }
379 
read_be16(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t * value)380 static int read_be16(uint8_t *data, uint16_t offset, uint16_t *pos,
381 		     uint16_t max_len, uint16_t *value)
382 {
383 	if (max_len - offset < 2) {
384 		return -EINVAL;
385 	}
386 
387 	*value = data[offset++] << 8;
388 	*value |= data[offset++];
389 	*pos = offset;
390 
391 	return max_len - offset;
392 }
393 
read(uint8_t * data,uint16_t offset,uint16_t * pos,uint16_t max_len,uint16_t len,uint8_t * value)394 static int read(uint8_t *data, uint16_t offset, uint16_t *pos,
395 		uint16_t max_len, uint16_t len, uint8_t *value)
396 {
397 	if (max_len - offset < len) {
398 		return -EINVAL;
399 	}
400 
401 	memcpy(value, data + offset, len);
402 	offset += len;
403 	*pos = offset;
404 
405 	return max_len - offset;
406 }
407 
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)408 static int decode_delta(uint8_t *data, uint16_t offset, uint16_t *pos, uint16_t max_len,
409 			uint16_t opt, uint16_t *opt_ext, uint16_t *hdr_len)
410 {
411 	int ret = 0;
412 
413 	if (opt == COAP_OPTION_EXT_13) {
414 		uint8_t val;
415 
416 		*hdr_len = 1U;
417 
418 		ret = read_u8(data, offset, pos, max_len, &val);
419 		if (ret < 0) {
420 			return -EINVAL;
421 		}
422 
423 		opt = val + COAP_OPTION_EXT_13;
424 	} else if (opt == COAP_OPTION_EXT_14) {
425 		uint16_t val;
426 
427 		*hdr_len = 2U;
428 
429 		ret = read_be16(data, offset, pos, max_len, &val);
430 		if (ret < 0) {
431 			return -EINVAL;
432 		}
433 
434 		opt = val + COAP_OPTION_EXT_269;
435 	} else if (opt == COAP_OPTION_EXT_15) {
436 		return -EINVAL;
437 	}
438 
439 	*opt_ext = opt;
440 
441 	return ret;
442 }
443 
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)444 static int parse_option(uint8_t *data, uint16_t offset, uint16_t *pos,
445 			uint16_t max_len, uint16_t *opt_delta, uint16_t *opt_len,
446 			struct coap_option *option)
447 {
448 	uint16_t hdr_len;
449 	uint16_t delta;
450 	uint16_t len;
451 	uint8_t opt;
452 	int r;
453 
454 	r = read_u8(data, offset, pos, max_len, &opt);
455 	if (r < 0) {
456 		return r;
457 	}
458 
459 	/* This indicates that options have ended */
460 	if (opt == COAP_MARKER) {
461 		/* packet w/ marker but no payload is malformed */
462 		return r > 0 ? 0 : -EINVAL;
463 	}
464 
465 	*opt_len += 1U;
466 
467 	delta = option_header_get_delta(opt);
468 	len = option_header_get_len(opt);
469 
470 	/* r == 0 means no more data to read from fragment, but delta
471 	 * field shows that packet should contain more data, it must
472 	 * be a malformed packet.
473 	 */
474 	if (r == 0 && delta > COAP_OPTION_NO_EXT) {
475 		return -EINVAL;
476 	}
477 
478 	if (delta > COAP_OPTION_NO_EXT) {
479 		/* In case 'delta' doesn't fit the option fixed header. */
480 		r = decode_delta(data, *pos, pos, max_len,
481 				 delta, &delta, &hdr_len);
482 		if ((r < 0) || (r == 0 && len > COAP_OPTION_NO_EXT)) {
483 			return -EINVAL;
484 		}
485 
486 		if (u16_add_overflow(*opt_len, hdr_len, opt_len)) {
487 			return -EINVAL;
488 		}
489 	}
490 
491 	if (len > COAP_OPTION_NO_EXT) {
492 		/* In case 'len' doesn't fit the option fixed header. */
493 		r = decode_delta(data, *pos, pos, max_len,
494 				 len, &len, &hdr_len);
495 		if (r < 0) {
496 			return -EINVAL;
497 		}
498 
499 		if (u16_add_overflow(*opt_len, hdr_len, opt_len)) {
500 			return -EINVAL;
501 		}
502 	}
503 
504 	if (u16_add_overflow(*opt_delta, delta, opt_delta) ||
505 	    u16_add_overflow(*opt_len, len, opt_len)) {
506 		return -EINVAL;
507 	}
508 
509 	if (r == 0 && len != 0U) {
510 		/* r == 0 means no more data to read from fragment, but len
511 		 * field shows that packet should contain more data, it must
512 		 * be a malformed packet.
513 		 */
514 		return -EINVAL;
515 	}
516 
517 	if (option) {
518 		/*
519 		 * Make sure the option data will fit into the value field of
520 		 * coap_option.
521 		 * NOTE: To expand the size of the value field set:
522 		 * CONFIG_COAP_EXTENDED_OPTIONS_LEN=y
523 		 * CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE=<size>
524 		 */
525 		if (len > sizeof(option->value)) {
526 			NET_ERR("%u is > sizeof(coap_option->value)(%zu)!",
527 				len, sizeof(option->value));
528 			return -EINVAL;
529 		}
530 
531 		option->delta = *opt_delta;
532 		option->len = len;
533 		r = read(data, *pos, pos, max_len, len, &option->value[0]);
534 		if (r < 0) {
535 			return -EINVAL;
536 		}
537 	} else {
538 		if (u16_add_overflow(*pos, len, pos)) {
539 			return -EINVAL;
540 		}
541 
542 		r = max_len - *pos;
543 	}
544 
545 	return r;
546 }
547 
coap_packet_parse(struct coap_packet * cpkt,uint8_t * data,uint16_t len,struct coap_option * options,uint8_t opt_num)548 int coap_packet_parse(struct coap_packet *cpkt, uint8_t *data, uint16_t len,
549 		      struct coap_option *options, uint8_t opt_num)
550 {
551 	uint16_t opt_len;
552 	uint16_t offset;
553 	uint16_t delta;
554 	uint8_t num;
555 	uint8_t tkl;
556 	int ret;
557 
558 	if (!cpkt || !data) {
559 		return -EINVAL;
560 	}
561 
562 	if (len < BASIC_HEADER_SIZE) {
563 		return -EINVAL;
564 	}
565 
566 	if (options) {
567 		memset(options, 0, opt_num * sizeof(struct coap_option));
568 	}
569 
570 	cpkt->data = data;
571 	cpkt->offset = len;
572 	cpkt->max_len = len;
573 	cpkt->opt_len = 0U;
574 	cpkt->hdr_len = 0U;
575 	cpkt->delta = 0U;
576 
577 	/* Token lengths 9-15 are reserved. */
578 	tkl = cpkt->data[0] & 0x0f;
579 	if (tkl > 8) {
580 		return -EINVAL;
581 	}
582 
583 	cpkt->hdr_len = BASIC_HEADER_SIZE + tkl;
584 	if (cpkt->hdr_len > len) {
585 		return -EINVAL;
586 	}
587 
588 	if (cpkt->hdr_len == len) {
589 		return 0;
590 	}
591 
592 	offset = cpkt->hdr_len;
593 	opt_len = 0U;
594 	delta = 0U;
595 	num = 0U;
596 
597 	while (1) {
598 		struct coap_option *option;
599 
600 		option = num < opt_num ? &options[num++] : NULL;
601 		ret = parse_option(cpkt->data, offset, &offset, cpkt->max_len,
602 				   &delta, &opt_len, option);
603 		if (ret < 0) {
604 			return ret;
605 		} else if (ret == 0) {
606 			break;
607 		}
608 	}
609 
610 	cpkt->opt_len = opt_len;
611 	cpkt->delta = delta;
612 
613 	return 0;
614 }
615 
coap_find_options(const struct coap_packet * cpkt,uint16_t code,struct coap_option * options,uint16_t veclen)616 int coap_find_options(const struct coap_packet *cpkt, uint16_t code,
617 		      struct coap_option *options, uint16_t veclen)
618 {
619 	uint16_t opt_len;
620 	uint16_t offset;
621 	uint16_t delta;
622 	uint8_t num;
623 	int r;
624 
625 	/* Check if there are options to parse */
626 	if (cpkt->hdr_len == cpkt->max_len) {
627 		return 0;
628 	}
629 
630 	offset = cpkt->hdr_len;
631 	opt_len = 0U;
632 	delta = 0U;
633 	num = 0U;
634 
635 	while (delta <= code && num < veclen) {
636 		r = parse_option(cpkt->data, offset, &offset,
637 				 cpkt->max_len, &delta, &opt_len,
638 				 &options[num]);
639 		if (r < 0) {
640 			return -EINVAL;
641 		}
642 
643 		if (code == options[num].delta) {
644 			num++;
645 		}
646 
647 		if (r == 0) {
648 			break;
649 		}
650 	}
651 
652 	return num;
653 }
654 
coap_header_get_version(const struct coap_packet * cpkt)655 uint8_t coap_header_get_version(const struct coap_packet *cpkt)
656 {
657 	if (!cpkt || !cpkt->data) {
658 		return 0;
659 	}
660 
661 	return (cpkt->data[0] & 0xC0) >> 6;
662 }
663 
coap_header_get_type(const struct coap_packet * cpkt)664 uint8_t coap_header_get_type(const struct coap_packet *cpkt)
665 {
666 	if (!cpkt || !cpkt->data) {
667 		return 0;
668 	}
669 
670 	return (cpkt->data[0] & 0x30) >> 4;
671 }
672 
__coap_header_get_code(const struct coap_packet * cpkt)673 static uint8_t __coap_header_get_code(const struct coap_packet *cpkt)
674 {
675 	if (!cpkt || !cpkt->data) {
676 		return 0;
677 	}
678 
679 	return cpkt->data[1];
680 }
681 
coap_header_get_token(const struct coap_packet * cpkt,uint8_t * token)682 uint8_t coap_header_get_token(const struct coap_packet *cpkt, uint8_t *token)
683 {
684 	uint8_t tkl;
685 
686 	if (!cpkt || !cpkt->data) {
687 		return 0;
688 	}
689 
690 	tkl = cpkt->data[0] & 0x0f;
691 	if (tkl) {
692 		memcpy(token, cpkt->data + BASIC_HEADER_SIZE, tkl);
693 	}
694 
695 	return tkl;
696 }
697 
coap_header_get_code(const struct coap_packet * cpkt)698 uint8_t coap_header_get_code(const struct coap_packet *cpkt)
699 {
700 	uint8_t code = __coap_header_get_code(cpkt);
701 
702 	switch (code) {
703 	/* Methods are encoded in the code field too */
704 	case COAP_METHOD_GET:
705 	case COAP_METHOD_POST:
706 	case COAP_METHOD_PUT:
707 	case COAP_METHOD_DELETE:
708 
709 	/* All the defined response codes */
710 	case COAP_RESPONSE_CODE_OK:
711 	case COAP_RESPONSE_CODE_CREATED:
712 	case COAP_RESPONSE_CODE_DELETED:
713 	case COAP_RESPONSE_CODE_VALID:
714 	case COAP_RESPONSE_CODE_CHANGED:
715 	case COAP_RESPONSE_CODE_CONTENT:
716 	case COAP_RESPONSE_CODE_CONTINUE:
717 	case COAP_RESPONSE_CODE_BAD_REQUEST:
718 	case COAP_RESPONSE_CODE_UNAUTHORIZED:
719 	case COAP_RESPONSE_CODE_BAD_OPTION:
720 	case COAP_RESPONSE_CODE_FORBIDDEN:
721 	case COAP_RESPONSE_CODE_NOT_FOUND:
722 	case COAP_RESPONSE_CODE_NOT_ALLOWED:
723 	case COAP_RESPONSE_CODE_NOT_ACCEPTABLE:
724 	case COAP_RESPONSE_CODE_INCOMPLETE:
725 	case COAP_RESPONSE_CODE_PRECONDITION_FAILED:
726 	case COAP_RESPONSE_CODE_REQUEST_TOO_LARGE:
727 	case COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT:
728 	case COAP_RESPONSE_CODE_INTERNAL_ERROR:
729 	case COAP_RESPONSE_CODE_NOT_IMPLEMENTED:
730 	case COAP_RESPONSE_CODE_BAD_GATEWAY:
731 	case COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE:
732 	case COAP_RESPONSE_CODE_GATEWAY_TIMEOUT:
733 	case COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED:
734 	case COAP_CODE_EMPTY:
735 		return code;
736 	default:
737 		return COAP_CODE_EMPTY;
738 	}
739 }
740 
coap_header_get_id(const struct coap_packet * cpkt)741 uint16_t coap_header_get_id(const struct coap_packet *cpkt)
742 {
743 	if (!cpkt || !cpkt->data) {
744 		return 0;
745 	}
746 
747 	return (cpkt->data[2] << 8) | cpkt->data[3];
748 }
749 
coap_packet_get_payload(const struct coap_packet * cpkt,uint16_t * len)750 const uint8_t *coap_packet_get_payload(const struct coap_packet *cpkt, uint16_t *len)
751 {
752 	int payload_len;
753 
754 	if (!cpkt || !len) {
755 		return NULL;
756 	}
757 
758 	payload_len = cpkt->offset - cpkt->hdr_len - cpkt->opt_len;
759 	if (payload_len > 1) {
760 		*len = payload_len - 1;	/* subtract payload marker length */
761 	} else {
762 		*len = 0U;
763 	}
764 
765 	return *len == 0 ? NULL :
766 		cpkt->data + cpkt->hdr_len + cpkt->opt_len + 1;
767 }
768 
uri_path_eq(const struct coap_packet * cpkt,const char * const * path,struct coap_option * options,uint8_t opt_num)769 static bool uri_path_eq(const struct coap_packet *cpkt,
770 			const char * const *path,
771 			struct coap_option *options,
772 			uint8_t opt_num)
773 {
774 	uint8_t i;
775 	uint8_t j = 0U;
776 
777 	for (i = 0U; i < opt_num && path[j]; i++) {
778 		if (options[i].delta != COAP_OPTION_URI_PATH) {
779 			continue;
780 		}
781 
782 		if (IS_ENABLED(CONFIG_COAP_URI_WILDCARD) && strlen(path[j]) == 1) {
783 			if (*path[j] == '+') {
784 				/* Single-level wildcard */
785 				j++;
786 				continue;
787 			} else if (*path[j] == '#') {
788 				/* Multi-level wildcard */
789 				return true;
790 			}
791 		}
792 
793 		if (options[i].len != strlen(path[j])) {
794 			return false;
795 		}
796 
797 		if (memcmp(options[i].value, path[j], options[i].len)) {
798 			return false;
799 		}
800 
801 		j++;
802 	}
803 
804 	if (path[j]) {
805 		return false;
806 	}
807 
808 	for (; i < opt_num; i++) {
809 		if (options[i].delta == COAP_OPTION_URI_PATH) {
810 			return false;
811 		}
812 	}
813 
814 	return true;
815 }
816 
method_from_code(const struct coap_resource * resource,uint8_t code)817 static coap_method_t method_from_code(const struct coap_resource *resource,
818 				      uint8_t code)
819 {
820 	switch (code) {
821 	case COAP_METHOD_GET:
822 		return resource->get;
823 	case COAP_METHOD_POST:
824 		return resource->post;
825 	case COAP_METHOD_PUT:
826 		return resource->put;
827 	case COAP_METHOD_DELETE:
828 		return resource->del;
829 	default:
830 		return NULL;
831 	}
832 }
833 
is_request(const struct coap_packet * cpkt)834 static bool is_request(const struct coap_packet *cpkt)
835 {
836 	uint8_t code = coap_header_get_code(cpkt);
837 
838 	return !(code & ~COAP_REQUEST_MASK);
839 }
840 
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)841 int coap_handle_request(struct coap_packet *cpkt,
842 			struct coap_resource *resources,
843 			struct coap_option *options,
844 			uint8_t opt_num,
845 			struct sockaddr *addr, socklen_t addr_len)
846 {
847 	struct coap_resource *resource;
848 
849 	if (!is_request(cpkt)) {
850 		return 0;
851 	}
852 
853 	/* FIXME: deal with hierarchical resources */
854 	for (resource = resources; resource && resource->path; resource++) {
855 		coap_method_t method;
856 		uint8_t code;
857 
858 		if (!uri_path_eq(cpkt, resource->path, options, opt_num)) {
859 			continue;
860 		}
861 
862 		code = coap_header_get_code(cpkt);
863 		method = method_from_code(resource, code);
864 		if (!method) {
865 			return -EPERM;
866 		}
867 
868 		return method(resource, cpkt, addr, addr_len);
869 	}
870 
871 	NET_DBG("%d", __LINE__);
872 	return -ENOENT;
873 }
874 
coap_block_transfer_init(struct coap_block_context * ctx,enum coap_block_size block_size,size_t total_size)875 int coap_block_transfer_init(struct coap_block_context *ctx,
876 			      enum coap_block_size block_size,
877 			      size_t total_size)
878 {
879 	ctx->block_size = block_size;
880 	ctx->total_size = total_size;
881 	ctx->current = 0;
882 
883 	return 0;
884 }
885 
886 #define GET_BLOCK_SIZE(v) (((v) & 0x7))
887 #define GET_MORE(v) (!!((v) & 0x08))
888 #define GET_NUM(v) ((v) >> 4)
889 
890 #define SET_BLOCK_SIZE(v, b) (v |= ((b) & 0x07))
891 #define SET_MORE(v, m) ((v) |= (m) ? 0x08 : 0x00)
892 #define SET_NUM(v, n) ((v) |= ((n) << 4))
893 
coap_append_block1_option(struct coap_packet * cpkt,struct coap_block_context * ctx)894 int coap_append_block1_option(struct coap_packet *cpkt,
895 			      struct coap_block_context *ctx)
896 {
897 	uint16_t bytes = coap_block_size_to_bytes(ctx->block_size);
898 	unsigned int val = 0U;
899 	int r;
900 
901 	if (is_request(cpkt)) {
902 		SET_BLOCK_SIZE(val, ctx->block_size);
903 		SET_MORE(val, ctx->current + bytes < ctx->total_size);
904 		SET_NUM(val, ctx->current / bytes);
905 	} else {
906 		SET_BLOCK_SIZE(val, ctx->block_size);
907 		SET_NUM(val, ctx->current / bytes);
908 	}
909 
910 	r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK1, val);
911 
912 	return r;
913 }
914 
coap_append_block2_option(struct coap_packet * cpkt,struct coap_block_context * ctx)915 int coap_append_block2_option(struct coap_packet *cpkt,
916 			      struct coap_block_context *ctx)
917 {
918 	int r, val = 0;
919 	uint16_t bytes = coap_block_size_to_bytes(ctx->block_size);
920 
921 	if (is_request(cpkt)) {
922 		SET_BLOCK_SIZE(val, ctx->block_size);
923 		SET_NUM(val, ctx->current / bytes);
924 	} else {
925 		SET_BLOCK_SIZE(val, ctx->block_size);
926 		SET_MORE(val, ctx->current + bytes < ctx->total_size);
927 		SET_NUM(val, ctx->current / bytes);
928 	}
929 
930 	r = coap_append_option_int(cpkt, COAP_OPTION_BLOCK2, val);
931 
932 	return r;
933 }
934 
coap_append_size1_option(struct coap_packet * cpkt,struct coap_block_context * ctx)935 int coap_append_size1_option(struct coap_packet *cpkt,
936 			     struct coap_block_context *ctx)
937 {
938 	return coap_append_option_int(cpkt, COAP_OPTION_SIZE1, ctx->total_size);
939 }
940 
coap_append_size2_option(struct coap_packet * cpkt,struct coap_block_context * ctx)941 int coap_append_size2_option(struct coap_packet *cpkt,
942 			     struct coap_block_context *ctx)
943 {
944 	return coap_append_option_int(cpkt, COAP_OPTION_SIZE2, ctx->total_size);
945 }
946 
coap_get_option_int(const struct coap_packet * cpkt,uint16_t code)947 int coap_get_option_int(const struct coap_packet *cpkt, uint16_t code)
948 {
949 	struct coap_option option = {};
950 	unsigned int val;
951 	int count = 1;
952 
953 	count = coap_find_options(cpkt, code, &option, count);
954 	if (count <= 0) {
955 		return -ENOENT;
956 	}
957 
958 	val = coap_option_value_to_int(&option);
959 
960 	return val;
961 }
962 
update_descriptive_block(struct coap_block_context * ctx,int block,int size)963 static int update_descriptive_block(struct coap_block_context *ctx,
964 				    int block, int size)
965 {
966 	size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
967 
968 	if (block == -ENOENT) {
969 		return 0;
970 	}
971 
972 	if (size && ctx->total_size && ctx->total_size != size) {
973 		return -EINVAL;
974 	}
975 
976 	if (ctx->current > 0 && GET_BLOCK_SIZE(block) > ctx->block_size) {
977 		return -EINVAL;
978 	}
979 
980 	if (ctx->total_size && new_current > ctx->total_size) {
981 		return -EINVAL;
982 	}
983 
984 	if (size) {
985 		ctx->total_size = size;
986 	}
987 	ctx->current = new_current;
988 	ctx->block_size = MIN(GET_BLOCK_SIZE(block), ctx->block_size);
989 
990 	return 0;
991 }
992 
update_control_block1(struct coap_block_context * ctx,int block,int size)993 static int update_control_block1(struct coap_block_context *ctx,
994 				     int block, int size)
995 {
996 	size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
997 
998 	if (block == -ENOENT) {
999 		return 0;
1000 	}
1001 
1002 	if (new_current != ctx->current) {
1003 		return -EINVAL;
1004 	}
1005 
1006 	if (GET_BLOCK_SIZE(block) > ctx->block_size) {
1007 		return -EINVAL;
1008 	}
1009 
1010 	ctx->block_size = GET_BLOCK_SIZE(block);
1011 	ctx->total_size = size;
1012 
1013 	return 0;
1014 }
1015 
update_control_block2(struct coap_block_context * ctx,int block,int size)1016 static int update_control_block2(struct coap_block_context *ctx,
1017 				 int block, int size)
1018 {
1019 	size_t new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1020 
1021 	if (block == -ENOENT) {
1022 		return 0;
1023 	}
1024 
1025 	if (GET_MORE(block)) {
1026 		return -EINVAL;
1027 	}
1028 
1029 	if (GET_NUM(block) > 0 && GET_BLOCK_SIZE(block) != ctx->block_size) {
1030 		return -EINVAL;
1031 	}
1032 
1033 	ctx->current = new_current;
1034 	ctx->block_size = MIN(GET_BLOCK_SIZE(block), ctx->block_size);
1035 
1036 	return 0;
1037 }
1038 
coap_update_from_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1039 int coap_update_from_block(const struct coap_packet *cpkt,
1040 			   struct coap_block_context *ctx)
1041 {
1042 	int r, block1, block2, size1, size2;
1043 
1044 	block1 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1045 	block2 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1046 	size1 = coap_get_option_int(cpkt, COAP_OPTION_SIZE1);
1047 	size2 = coap_get_option_int(cpkt, COAP_OPTION_SIZE2);
1048 
1049 	size1 = size1 == -ENOENT ? 0 : size1;
1050 	size2 = size2 == -ENOENT ? 0 : size2;
1051 
1052 	if (is_request(cpkt)) {
1053 		r = update_control_block2(ctx, block2, size2);
1054 		if (r) {
1055 			return r;
1056 		}
1057 
1058 		return update_descriptive_block(ctx, block1, size1);
1059 	}
1060 
1061 	r = update_control_block1(ctx, block1, size1);
1062 	if (r) {
1063 		return r;
1064 	}
1065 
1066 	return update_descriptive_block(ctx, block2, size2);
1067 }
1068 
coap_next_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1069 size_t coap_next_block(const struct coap_packet *cpkt,
1070 		       struct coap_block_context *ctx)
1071 {
1072 	int block;
1073 
1074 	if (is_request(cpkt)) {
1075 		block = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1076 	} else {
1077 		block = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1078 	}
1079 
1080 	if (!GET_MORE(block)) {
1081 		return 0;
1082 	}
1083 
1084 	ctx->current += coap_block_size_to_bytes(ctx->block_size);
1085 
1086 	return ctx->current;
1087 }
1088 
coap_pending_init(struct coap_pending * pending,const struct coap_packet * request,const struct sockaddr * addr,uint8_t retries)1089 int coap_pending_init(struct coap_pending *pending,
1090 		      const struct coap_packet *request,
1091 		      const struct sockaddr *addr,
1092 		      uint8_t retries)
1093 {
1094 	memset(pending, 0, sizeof(*pending));
1095 
1096 	pending->id = coap_header_get_id(request);
1097 
1098 	memcpy(&pending->addr, addr, sizeof(*addr));
1099 
1100 	pending->data = request->data;
1101 	pending->len = request->offset;
1102 	pending->t0 = k_uptime_get_32();
1103 	pending->retries = retries;
1104 
1105 	return 0;
1106 }
1107 
coap_pending_next_unused(struct coap_pending * pendings,size_t len)1108 struct coap_pending *coap_pending_next_unused(
1109 	struct coap_pending *pendings, size_t len)
1110 {
1111 	struct coap_pending *p;
1112 	size_t i;
1113 
1114 	for (i = 0, p = pendings; i < len; i++, p++) {
1115 		if (p->timeout == 0) {
1116 			return p;
1117 		}
1118 	}
1119 
1120 	return NULL;
1121 }
1122 
coap_reply_next_unused(struct coap_reply * replies,size_t len)1123 struct coap_reply *coap_reply_next_unused(
1124 	struct coap_reply *replies, size_t len)
1125 {
1126 	struct coap_reply *r;
1127 	size_t i;
1128 
1129 	for (i = 0, r = replies; i < len; i++, r++) {
1130 		if (!r->reply) {
1131 			return r;
1132 		}
1133 	}
1134 
1135 	return NULL;
1136 }
1137 
is_addr_unspecified(const struct sockaddr * addr)1138 static inline bool is_addr_unspecified(const struct sockaddr *addr)
1139 {
1140 	if (addr->sa_family == AF_UNSPEC) {
1141 		return true;
1142 	}
1143 
1144 	if (addr->sa_family == AF_INET6) {
1145 		return net_ipv6_is_addr_unspecified(
1146 			&(net_sin6(addr)->sin6_addr));
1147 	} else if (addr->sa_family == AF_INET) {
1148 		return net_sin(addr)->sin_addr.s4_addr32[0] == 0U;
1149 	}
1150 
1151 	return false;
1152 }
1153 
coap_observer_next_unused(struct coap_observer * observers,size_t len)1154 struct coap_observer *coap_observer_next_unused(
1155 	struct coap_observer *observers, size_t len)
1156 {
1157 	struct coap_observer *o;
1158 	size_t i;
1159 
1160 	for (i = 0, o = observers; i < len; i++, o++) {
1161 		if (is_addr_unspecified(&o->addr)) {
1162 			return o;
1163 		}
1164 	}
1165 
1166 	return NULL;
1167 }
1168 
coap_pending_received(const struct coap_packet * response,struct coap_pending * pendings,size_t len)1169 struct coap_pending *coap_pending_received(
1170 	const struct coap_packet *response,
1171 	struct coap_pending *pendings, size_t len)
1172 {
1173 	struct coap_pending *p;
1174 	uint16_t resp_id = coap_header_get_id(response);
1175 	size_t i;
1176 
1177 	for (i = 0, p = pendings; i < len; i++, p++) {
1178 		if (!p->timeout) {
1179 			continue;
1180 		}
1181 
1182 		if (resp_id != p->id) {
1183 			continue;
1184 		}
1185 
1186 		return p;
1187 	}
1188 
1189 	return NULL;
1190 }
1191 
coap_pending_next_to_expire(struct coap_pending * pendings,size_t len)1192 struct coap_pending *coap_pending_next_to_expire(
1193 	struct coap_pending *pendings, size_t len)
1194 {
1195 	struct coap_pending *p, *found = NULL;
1196 	size_t i;
1197 	uint32_t expiry, min_expiry;
1198 
1199 	for (i = 0, p = pendings; i < len; i++, p++) {
1200 		if (!p->timeout) {
1201 			continue;
1202 		}
1203 
1204 		expiry = p->t0 + p->timeout;
1205 
1206 		if (!found || (int32_t)(expiry - min_expiry) < 0) {
1207 			min_expiry = expiry;
1208 			found = p;
1209 		}
1210 	}
1211 
1212 	return found;
1213 }
1214 
init_ack_timeout(void)1215 static uint32_t init_ack_timeout(void)
1216 {
1217 #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT)
1218 	const uint32_t max_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS *
1219 				 COAP_DEFAULT_ACK_RANDOM_FACTOR;
1220 	const uint32_t min_ack = CONFIG_COAP_INIT_ACK_TIMEOUT_MS;
1221 
1222 	/* Randomly generated initial ACK timeout
1223 	 * ACK_TIMEOUT < INIT_ACK_TIMEOUT < ACK_TIMEOUT * ACK_RANDOM_FACTOR
1224 	 * Ref: https://tools.ietf.org/html/rfc7252#section-4.8
1225 	 */
1226 	return min_ack + (sys_rand32_get() % (max_ack - min_ack));
1227 #else
1228 	return CONFIG_COAP_INIT_ACK_TIMEOUT_MS;
1229 #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */
1230 }
1231 
coap_pending_cycle(struct coap_pending * pending)1232 bool coap_pending_cycle(struct coap_pending *pending)
1233 {
1234 	if (pending->timeout == 0) {
1235 		/* Initial transmission. */
1236 		pending->timeout = init_ack_timeout();
1237 
1238 		return true;
1239 	}
1240 
1241 	if (pending->retries == 0) {
1242 		return false;
1243 	}
1244 
1245 	pending->t0 += pending->timeout;
1246 	pending->timeout = pending->timeout << 1;
1247 	pending->retries--;
1248 
1249 	return true;
1250 }
1251 
coap_pending_clear(struct coap_pending * pending)1252 void coap_pending_clear(struct coap_pending *pending)
1253 {
1254 	pending->timeout = 0;
1255 	pending->data = NULL;
1256 }
1257 
coap_pendings_clear(struct coap_pending * pendings,size_t len)1258 void coap_pendings_clear(struct coap_pending *pendings, size_t len)
1259 {
1260 	struct coap_pending *p;
1261 	size_t i;
1262 
1263 	for (i = 0, p = pendings; i < len; i++, p++) {
1264 		coap_pending_clear(p);
1265 	}
1266 }
1267 
1268 /* Reordering according to RFC7641 section 3.4 but without timestamp comparison */
is_newer(int v1,int v2)1269 static inline bool is_newer(int v1, int v2)
1270 {
1271 	return (v1 < v2 && v2 - v1 < (1 << 23))
1272 	    || (v1 > v2 && v1 - v2 > (1 << 23));
1273 }
1274 
coap_response_received(const struct coap_packet * response,const struct sockaddr * from,struct coap_reply * replies,size_t len)1275 struct coap_reply *coap_response_received(
1276 	const struct coap_packet *response,
1277 	const struct sockaddr *from,
1278 	struct coap_reply *replies, size_t len)
1279 {
1280 	struct coap_reply *r;
1281 	uint8_t token[COAP_TOKEN_MAX_LEN];
1282 	uint16_t id;
1283 	uint8_t tkl;
1284 	size_t i;
1285 
1286 	id = coap_header_get_id(response);
1287 	tkl = coap_header_get_token(response, token);
1288 
1289 	for (i = 0, r = replies; i < len; i++, r++) {
1290 		int age;
1291 
1292 		if ((r->id == 0U) && (r->tkl == 0U)) {
1293 			continue;
1294 		}
1295 
1296 		/* Piggybacked must match id when token is empty */
1297 		if ((r->id != id) && (tkl == 0U)) {
1298 			continue;
1299 		}
1300 
1301 		if (tkl > 0 && memcmp(r->token, token, tkl)) {
1302 			continue;
1303 		}
1304 
1305 		age = coap_get_option_int(response, COAP_OPTION_OBSERVE);
1306 		/* handle observed requests only if received in order */
1307 		if (age == -ENOENT || is_newer(r->age, age)) {
1308 			r->age = age;
1309 			r->reply(response, r, from);
1310 		}
1311 
1312 		return r;
1313 	}
1314 
1315 	return NULL;
1316 }
1317 
coap_reply_init(struct coap_reply * reply,const struct coap_packet * request)1318 void coap_reply_init(struct coap_reply *reply,
1319 		     const struct coap_packet *request)
1320 {
1321 	uint8_t token[COAP_TOKEN_MAX_LEN];
1322 	uint8_t tkl;
1323 
1324 	reply->id = coap_header_get_id(request);
1325 	tkl = coap_header_get_token(request, token);
1326 
1327 	if (tkl > 0) {
1328 		memcpy(reply->token, token, tkl);
1329 	}
1330 
1331 	reply->tkl = tkl;
1332 
1333 	/* Any initial observe response should be accepted */
1334 	reply->age = -1;
1335 }
1336 
coap_reply_clear(struct coap_reply * reply)1337 void coap_reply_clear(struct coap_reply *reply)
1338 {
1339 	(void)memset(reply, 0, sizeof(*reply));
1340 }
1341 
coap_replies_clear(struct coap_reply * replies,size_t len)1342 void coap_replies_clear(struct coap_reply *replies, size_t len)
1343 {
1344 	struct coap_reply *r;
1345 	size_t i;
1346 
1347 	for (i = 0, r = replies; i < len; i++, r++) {
1348 		coap_reply_clear(r);
1349 	}
1350 }
1351 
coap_resource_notify(struct coap_resource * resource)1352 int coap_resource_notify(struct coap_resource *resource)
1353 {
1354 	struct coap_observer *o;
1355 
1356 	if (!resource->notify) {
1357 		return -ENOENT;
1358 	}
1359 
1360 	resource->age++;
1361 
1362 	SYS_SLIST_FOR_EACH_CONTAINER(&resource->observers, o, list) {
1363 		resource->notify(resource, o);
1364 	}
1365 
1366 	return 0;
1367 }
1368 
coap_request_is_observe(const struct coap_packet * request)1369 bool coap_request_is_observe(const struct coap_packet *request)
1370 {
1371 	return coap_get_option_int(request, COAP_OPTION_OBSERVE) == 0;
1372 }
1373 
coap_observer_init(struct coap_observer * observer,const struct coap_packet * request,const struct sockaddr * addr)1374 void coap_observer_init(struct coap_observer *observer,
1375 			const struct coap_packet *request,
1376 			const struct sockaddr *addr)
1377 {
1378 	observer->tkl = coap_header_get_token(request, observer->token);
1379 
1380 	net_ipaddr_copy(&observer->addr, addr);
1381 }
1382 
coap_register_observer(struct coap_resource * resource,struct coap_observer * observer)1383 bool coap_register_observer(struct coap_resource *resource,
1384 			    struct coap_observer *observer)
1385 {
1386 	bool first;
1387 
1388 	sys_slist_append(&resource->observers, &observer->list);
1389 
1390 	first = resource->age == 0;
1391 	if (first) {
1392 		resource->age = 2;
1393 	}
1394 
1395 	return first;
1396 }
1397 
coap_remove_observer(struct coap_resource * resource,struct coap_observer * observer)1398 void coap_remove_observer(struct coap_resource *resource,
1399 			  struct coap_observer *observer)
1400 {
1401 	sys_slist_find_and_remove(&resource->observers, &observer->list);
1402 }
1403 
sockaddr_equal(const struct sockaddr * a,const struct sockaddr * b)1404 static bool sockaddr_equal(const struct sockaddr *a,
1405 			   const struct sockaddr *b)
1406 {
1407 	/* FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to
1408 	 * ipv4 addresses?
1409 	 */
1410 	if (a->sa_family != b->sa_family) {
1411 		return false;
1412 	}
1413 
1414 	if (a->sa_family == AF_INET) {
1415 		const struct sockaddr_in *a4 = net_sin(a);
1416 		const struct sockaddr_in *b4 = net_sin(b);
1417 
1418 		if (a4->sin_port != b4->sin_port) {
1419 			return false;
1420 		}
1421 
1422 		return net_ipv4_addr_cmp(&a4->sin_addr, &b4->sin_addr);
1423 	}
1424 
1425 	if (b->sa_family == AF_INET6) {
1426 		const struct sockaddr_in6 *a6 = net_sin6(a);
1427 		const struct sockaddr_in6 *b6 = net_sin6(b);
1428 
1429 		if (a6->sin6_port != b6->sin6_port) {
1430 			return false;
1431 		}
1432 
1433 		return net_ipv6_addr_cmp(&a6->sin6_addr, &b6->sin6_addr);
1434 	}
1435 
1436 	/* Invalid address family */
1437 	return false;
1438 }
1439 
coap_find_observer_by_addr(struct coap_observer * observers,size_t len,const struct sockaddr * addr)1440 struct coap_observer *coap_find_observer_by_addr(
1441 	struct coap_observer *observers, size_t len,
1442 	const struct sockaddr *addr)
1443 {
1444 	size_t i;
1445 
1446 	for (i = 0; i < len; i++) {
1447 		struct coap_observer *o = &observers[i];
1448 
1449 		if (sockaddr_equal(&o->addr, addr)) {
1450 			return o;
1451 		}
1452 	}
1453 
1454 	return NULL;
1455 }
1456 
1457 /**
1458  * @brief Internal initialization function for CoAP library.
1459  *
1460  * Called by the network layer init procedure. Seeds the CoAP @message_id with a
1461  * random number in accordance with recommendations in CoAP specification.
1462  *
1463  * @note This function is not exposed in a public header, as it's for internal
1464  * use and should therefore not be exposed to applications.
1465  *
1466  * @return N/A
1467  */
net_coap_init(void)1468 void net_coap_init(void)
1469 {
1470 	/* Initialize message_id to a random number */
1471 	message_id = (uint16_t)sys_rand32_get();
1472 }
1473 
coap_next_id(void)1474 uint16_t coap_next_id(void)
1475 {
1476 	return message_id++;
1477 }
1478