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