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, 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;
1475 
1476 	if (block == -ENOENT) {
1477 		return 0;
1478 	}
1479 
1480 	if (block < 0) {
1481 		return -EINVAL;
1482 	}
1483 
1484 	new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1485 	if (new_current != ctx->current) {
1486 		return -EINVAL;
1487 	}
1488 
1489 	if (GET_BLOCK_SIZE(block) > ctx->block_size) {
1490 		return -EINVAL;
1491 	}
1492 
1493 	ctx->block_size = GET_BLOCK_SIZE(block);
1494 
1495 	if (size >= 0) {
1496 		ctx->total_size = size;
1497 	}
1498 
1499 	return 0;
1500 }
1501 
update_control_block2(struct coap_block_context * ctx,int block,int size)1502 static int update_control_block2(struct coap_block_context *ctx,
1503 				 int block, int size)
1504 {
1505 	size_t new_current;
1506 
1507 	if (block == -ENOENT) {
1508 		return 0;
1509 	}
1510 
1511 	if (block < 0) {
1512 		return -EINVAL;
1513 	}
1514 
1515 	new_current = GET_NUM(block) << (GET_BLOCK_SIZE(block) + 4);
1516 
1517 	if (GET_MORE(block)) {
1518 		return -EINVAL;
1519 	}
1520 
1521 	if (GET_NUM(block) > 0 && GET_BLOCK_SIZE(block) != ctx->block_size) {
1522 		return -EINVAL;
1523 	}
1524 
1525 	ctx->current = new_current;
1526 	ctx->block_size = MIN(GET_BLOCK_SIZE(block), ctx->block_size);
1527 
1528 	return 0;
1529 }
1530 
coap_update_from_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1531 int coap_update_from_block(const struct coap_packet *cpkt,
1532 			   struct coap_block_context *ctx)
1533 {
1534 	int r, block1, block2, size1, size2;
1535 
1536 	block1 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK1);
1537 	block2 = coap_get_option_int(cpkt, COAP_OPTION_BLOCK2);
1538 	size1 = coap_get_option_int(cpkt, COAP_OPTION_SIZE1);
1539 	size2 = coap_get_option_int(cpkt, COAP_OPTION_SIZE2);
1540 
1541 	if (coap_packet_is_request(cpkt)) {
1542 		r = update_control_block2(ctx, block2, size2);
1543 		if (r) {
1544 			return r;
1545 		}
1546 
1547 		return update_descriptive_block(ctx, block1, size1 == -ENOENT ? 0 : size1);
1548 	}
1549 
1550 	r = update_control_block1(ctx, block1, size1);
1551 	if (r) {
1552 		return r;
1553 	}
1554 
1555 	return update_descriptive_block(ctx, block2, size2 == -ENOENT ? 0 : size2);
1556 }
1557 
coap_next_block_for_option(const struct coap_packet * cpkt,struct coap_block_context * ctx,enum coap_option_num option)1558 int coap_next_block_for_option(const struct coap_packet *cpkt,
1559 			       struct coap_block_context *ctx,
1560 			       enum coap_option_num option)
1561 {
1562 	int block;
1563 	uint16_t block_len = 0;
1564 
1565 	if (option != COAP_OPTION_BLOCK1 && option != COAP_OPTION_BLOCK2) {
1566 		return -EINVAL;
1567 	}
1568 
1569 	block = coap_get_option_int(cpkt, option);
1570 
1571 	if (block < 0) {
1572 		return block;
1573 	}
1574 
1575 	coap_packet_get_payload(cpkt, &block_len);
1576 	/* Check that the package does not exceed the expected size ONLY */
1577 	if ((ctx->total_size > 0) &&
1578 	    (ctx->total_size < (ctx->current + block_len))) {
1579 		return -EMSGSIZE;
1580 	}
1581 	ctx->current += block_len;
1582 
1583 	if (!GET_MORE(block)) {
1584 		return 0;
1585 	}
1586 
1587 	return (int)ctx->current;
1588 }
1589 
coap_next_block(const struct coap_packet * cpkt,struct coap_block_context * ctx)1590 size_t coap_next_block(const struct coap_packet *cpkt,
1591 		       struct coap_block_context *ctx)
1592 {
1593 	enum coap_option_num option;
1594 	int ret;
1595 
1596 	option = coap_packet_is_request(cpkt) ? COAP_OPTION_BLOCK1 : COAP_OPTION_BLOCK2;
1597 	ret = coap_next_block_for_option(cpkt, ctx, option);
1598 
1599 	return MAX(ret, 0);
1600 }
1601 
coap_pending_init(struct coap_pending * pending,const struct coap_packet * request,const struct sockaddr * addr,const struct coap_transmission_parameters * params)1602 int coap_pending_init(struct coap_pending *pending,
1603 		      const struct coap_packet *request,
1604 		      const struct sockaddr *addr,
1605 		      const struct coap_transmission_parameters *params)
1606 {
1607 	memset(pending, 0, sizeof(*pending));
1608 
1609 	pending->id = coap_header_get_id(request);
1610 
1611 	memcpy(&pending->addr, addr, sizeof(*addr));
1612 
1613 	if (params) {
1614 		pending->params = *params;
1615 	} else {
1616 		pending->params = coap_transmission_params;
1617 	}
1618 
1619 	pending->data = request->data;
1620 	pending->len = request->offset;
1621 	pending->t0 = k_uptime_get();
1622 	pending->retries = pending->params.max_retransmission;
1623 
1624 	return 0;
1625 }
1626 
coap_pending_next_unused(struct coap_pending * pendings,size_t len)1627 struct coap_pending *coap_pending_next_unused(
1628 	struct coap_pending *pendings, size_t len)
1629 {
1630 	struct coap_pending *p;
1631 	size_t i;
1632 
1633 	for (i = 0, p = pendings; i < len; i++, p++) {
1634 		if (p->data == 0) {
1635 			return p;
1636 		}
1637 	}
1638 
1639 	return NULL;
1640 }
1641 
coap_reply_next_unused(struct coap_reply * replies,size_t len)1642 struct coap_reply *coap_reply_next_unused(
1643 	struct coap_reply *replies, size_t len)
1644 {
1645 	struct coap_reply *r;
1646 	size_t i;
1647 
1648 	for (i = 0, r = replies; i < len; i++, r++) {
1649 		if (!r->reply) {
1650 			return r;
1651 		}
1652 	}
1653 
1654 	return NULL;
1655 }
1656 
is_addr_unspecified(const struct sockaddr * addr)1657 static inline bool is_addr_unspecified(const struct sockaddr *addr)
1658 {
1659 	if (addr->sa_family == AF_UNSPEC) {
1660 		return true;
1661 	}
1662 
1663 	if (addr->sa_family == AF_INET6) {
1664 		return net_ipv6_is_addr_unspecified(
1665 			&(net_sin6(addr)->sin6_addr));
1666 	} else if (addr->sa_family == AF_INET) {
1667 		return net_sin(addr)->sin_addr.s4_addr32[0] == 0U;
1668 	}
1669 
1670 	return false;
1671 }
1672 
coap_observer_next_unused(struct coap_observer * observers,size_t len)1673 struct coap_observer *coap_observer_next_unused(
1674 	struct coap_observer *observers, size_t len)
1675 {
1676 	struct coap_observer *o;
1677 	size_t i;
1678 
1679 	for (i = 0, o = observers; i < len; i++, o++) {
1680 		if (is_addr_unspecified(&o->addr)) {
1681 			return o;
1682 		}
1683 	}
1684 
1685 	return NULL;
1686 }
1687 
coap_pending_received(const struct coap_packet * response,struct coap_pending * pendings,size_t len)1688 struct coap_pending *coap_pending_received(
1689 	const struct coap_packet *response,
1690 	struct coap_pending *pendings, size_t len)
1691 {
1692 	struct coap_pending *p;
1693 	uint16_t resp_id = coap_header_get_id(response);
1694 	size_t i;
1695 
1696 	for (i = 0, p = pendings; i < len; i++, p++) {
1697 		if (!p->timeout) {
1698 			continue;
1699 		}
1700 
1701 		if (resp_id != p->id) {
1702 			continue;
1703 		}
1704 
1705 		return p;
1706 	}
1707 
1708 	return NULL;
1709 }
1710 
coap_pending_next_to_expire(struct coap_pending * pendings,size_t len)1711 struct coap_pending *coap_pending_next_to_expire(
1712 	struct coap_pending *pendings, size_t len)
1713 {
1714 	struct coap_pending *p, *found = NULL;
1715 	size_t i;
1716 	int64_t expiry, min_expiry = INT64_MAX;
1717 
1718 	for (i = 0, p = pendings; i < len; i++, p++) {
1719 		if (!p->timeout) {
1720 			continue;
1721 		}
1722 
1723 		expiry = p->t0 + p->timeout;
1724 
1725 		if (expiry < min_expiry) {
1726 			min_expiry = expiry;
1727 			found = p;
1728 		}
1729 	}
1730 
1731 	return found;
1732 }
1733 
init_ack_timeout(const struct coap_transmission_parameters * params)1734 static uint32_t init_ack_timeout(const struct coap_transmission_parameters *params)
1735 {
1736 #if defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT)
1737 	const uint16_t random_percent = params->ack_random_percent ? params->ack_random_percent
1738 								   : CONFIG_COAP_ACK_RANDOM_PERCENT;
1739 	const uint32_t max_ack = params->ack_timeout * random_percent / 100U;
1740 	const uint32_t min_ack = params->ack_timeout;
1741 
1742 	if (max_ack > min_ack) {
1743 		/* Randomly generated initial ACK timeout
1744 		 * ACK_TIMEOUT <= INIT_ACK_TIMEOUT <= ACK_TIMEOUT * ACK_RANDOM_FACTOR
1745 		 * Ref: https://tools.ietf.org/html/rfc7252#section-4.8
1746 		 */
1747 		return min_ack + (sys_rand32_get() % (max_ack - min_ack + 1));
1748 	}
1749 #endif /* defined(CONFIG_COAP_RANDOMIZE_ACK_TIMEOUT) */
1750 	return params->ack_timeout;
1751 }
1752 
coap_pending_cycle(struct coap_pending * pending)1753 bool coap_pending_cycle(struct coap_pending *pending)
1754 {
1755 	if (pending->timeout == 0) {
1756 		/* Initial transmission. */
1757 		pending->timeout = init_ack_timeout(&pending->params);
1758 		return true;
1759 	}
1760 
1761 	if (pending->retries == 0) {
1762 		return false;
1763 	}
1764 
1765 	pending->t0 += pending->timeout;
1766 	pending->timeout = pending->timeout * pending->params.coap_backoff_percent / 100;
1767 	pending->retries--;
1768 
1769 	return true;
1770 }
1771 
coap_pending_clear(struct coap_pending * pending)1772 void coap_pending_clear(struct coap_pending *pending)
1773 {
1774 	pending->timeout = 0;
1775 	pending->data = NULL;
1776 }
1777 
coap_pendings_clear(struct coap_pending * pendings,size_t len)1778 void coap_pendings_clear(struct coap_pending *pendings, size_t len)
1779 {
1780 	struct coap_pending *p;
1781 	size_t i;
1782 
1783 	for (i = 0, p = pendings; i < len; i++, p++) {
1784 		coap_pending_clear(p);
1785 	}
1786 }
1787 
coap_pendings_count(struct coap_pending * pendings,size_t len)1788 size_t coap_pendings_count(struct coap_pending *pendings, size_t len)
1789 {
1790 	struct coap_pending *p = pendings;
1791 	size_t c = 0;
1792 
1793 	for (size_t i = 0; i < len && p; i++, p++) {
1794 		if (p->timeout) {
1795 			c++;
1796 		}
1797 	}
1798 	return c;
1799 }
1800 
1801 /* Reordering according to RFC7641 section 3.4 but without timestamp comparison */
1802 IF_DISABLED(CONFIG_ZTEST, (static inline))
coap_age_is_newer(int v1,int v2)1803 bool coap_age_is_newer(int v1, int v2)
1804 {
1805 	return (v1 < v2 && v2 - v1 < (1 << 23))
1806 	    || (v1 > v2 && v1 - v2 > (1 << 23));
1807 }
1808 
coap_observer_increment_age(struct coap_resource * resource)1809 static inline void coap_observer_increment_age(struct coap_resource *resource)
1810 {
1811 	resource->age++;
1812 	if (resource->age > COAP_OBSERVE_MAX_AGE) {
1813 		resource->age = COAP_OBSERVE_FIRST_OFFSET;
1814 	}
1815 }
1816 
coap_response_received(const struct coap_packet * response,const struct sockaddr * from,struct coap_reply * replies,size_t len)1817 struct coap_reply *coap_response_received(
1818 	const struct coap_packet *response,
1819 	const struct sockaddr *from,
1820 	struct coap_reply *replies, size_t len)
1821 {
1822 	struct coap_reply *r;
1823 	uint8_t token[COAP_TOKEN_MAX_LEN];
1824 	bool piggybacked = false;
1825 	uint8_t type;
1826 	uint16_t id;
1827 	uint8_t tkl;
1828 	size_t i;
1829 
1830 	type = coap_header_get_type(response);
1831 	id = coap_header_get_id(response);
1832 	tkl = coap_header_get_token(response, token);
1833 
1834 	if ((type == COAP_TYPE_ACK && is_empty_message(response)) ||
1835 	    coap_packet_is_request(response)) {
1836 		/* Request or empty ACK can't be response */
1837 		return NULL;
1838 	}
1839 
1840 	if (type == COAP_TYPE_ACK) {
1841 		piggybacked = true;
1842 	}
1843 
1844 	for (i = 0, r = replies; i < len; i++, r++) {
1845 		int age;
1846 
1847 		/* Skip unused entry. */
1848 		if (r->reply == NULL) {
1849 			continue;
1850 		}
1851 
1852 		/* Reset should only be handled if Message ID matches. */
1853 		if (type == COAP_TYPE_RESET) {
1854 			if (r->id != id) {
1855 				continue;
1856 			}
1857 
1858 			goto handle_reply;
1859 		}
1860 
1861 		/* In a piggybacked response, the Message ID of the Confirmable
1862 		 * request and the Acknowledgment MUST match, and the tokens of
1863 		 * the response and original request MUST match.  In a separate
1864 		 * response, just the tokens of the response and original request
1865 		 * MUST match.
1866 		 */
1867 		if (piggybacked) {
1868 			if (r->id != id) {
1869 				continue;
1870 			}
1871 		}
1872 
1873 		if (r->tkl != tkl) {
1874 			continue;
1875 		}
1876 
1877 		if (r->tkl > 0) {
1878 			if (memcmp(r->token, token, r->tkl) != 0) {
1879 				continue;
1880 			}
1881 		}
1882 
1883 		age = coap_get_option_int(response, COAP_OPTION_OBSERVE);
1884 		/* handle observed requests only if received in order */
1885 		if (age == -ENOENT || coap_age_is_newer(r->age, age)) {
1886 			r->age = age;
1887 			if (coap_header_get_code(response) != COAP_RESPONSE_CODE_CONTINUE) {
1888 handle_reply:
1889 				r->reply(response, r, from);
1890 			}
1891 		}
1892 
1893 		return r;
1894 	}
1895 
1896 	return NULL;
1897 }
1898 
coap_reply_init(struct coap_reply * reply,const struct coap_packet * request)1899 void coap_reply_init(struct coap_reply *reply,
1900 		     const struct coap_packet *request)
1901 {
1902 	uint8_t token[COAP_TOKEN_MAX_LEN];
1903 	uint8_t tkl;
1904 
1905 	reply->id = coap_header_get_id(request);
1906 	tkl = coap_header_get_token(request, token);
1907 
1908 	if (tkl > 0) {
1909 		memcpy(reply->token, token, tkl);
1910 	}
1911 
1912 	reply->tkl = tkl;
1913 
1914 	/* Any initial observe response should be accepted */
1915 	reply->age = -1;
1916 }
1917 
coap_reply_clear(struct coap_reply * reply)1918 void coap_reply_clear(struct coap_reply *reply)
1919 {
1920 	(void)memset(reply, 0, sizeof(*reply));
1921 }
1922 
coap_replies_clear(struct coap_reply * replies,size_t len)1923 void coap_replies_clear(struct coap_reply *replies, size_t len)
1924 {
1925 	struct coap_reply *r;
1926 	size_t i;
1927 
1928 	for (i = 0, r = replies; i < len; i++, r++) {
1929 		coap_reply_clear(r);
1930 	}
1931 }
1932 
coap_resource_notify(struct coap_resource * resource)1933 int coap_resource_notify(struct coap_resource *resource)
1934 {
1935 	struct coap_observer *o;
1936 
1937 	if (!resource->notify) {
1938 		return -ENOENT;
1939 	}
1940 
1941 	if (sys_slist_is_empty(&resource->observers)) {
1942 		return 0;
1943 	}
1944 
1945 	coap_observer_increment_age(resource);
1946 
1947 	SYS_SLIST_FOR_EACH_CONTAINER(&resource->observers, o, list) {
1948 		resource->notify(resource, o);
1949 	}
1950 
1951 	return 0;
1952 }
1953 
coap_request_is_observe(const struct coap_packet * request)1954 bool coap_request_is_observe(const struct coap_packet *request)
1955 {
1956 	return coap_get_option_int(request, COAP_OPTION_OBSERVE) == 0;
1957 }
1958 
coap_observer_init(struct coap_observer * observer,const struct coap_packet * request,const struct sockaddr * addr)1959 void coap_observer_init(struct coap_observer *observer,
1960 			const struct coap_packet *request,
1961 			const struct sockaddr *addr)
1962 {
1963 	observer->tkl = coap_header_get_token(request, observer->token);
1964 
1965 	memcpy(&observer->addr, addr, sizeof(*addr));
1966 }
1967 
coap_observer_raise_event(struct coap_resource * resource,struct coap_observer * observer,uint64_t mgmt_event)1968 static inline void coap_observer_raise_event(struct coap_resource *resource,
1969 					     struct coap_observer *observer,
1970 					     uint64_t mgmt_event)
1971 {
1972 #ifdef CONFIG_NET_MGMT_EVENT_INFO
1973 	const struct net_event_coap_observer net_event = {
1974 		.resource = resource,
1975 		.observer = observer,
1976 	};
1977 
1978 	net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event));
1979 #else
1980 	ARG_UNUSED(resource);
1981 	ARG_UNUSED(observer);
1982 
1983 	net_mgmt_event_notify(mgmt_event, NULL);
1984 #endif
1985 }
1986 
coap_register_observer(struct coap_resource * resource,struct coap_observer * observer)1987 bool coap_register_observer(struct coap_resource *resource,
1988 			    struct coap_observer *observer)
1989 {
1990 	bool first;
1991 
1992 	sys_slist_append(&resource->observers, &observer->list);
1993 
1994 	first = resource->age == 0;
1995 	if (first) {
1996 		resource->age = COAP_OBSERVE_FIRST_OFFSET;
1997 	}
1998 
1999 	coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_ADDED);
2000 
2001 	return first;
2002 }
2003 
coap_remove_observer(struct coap_resource * resource,struct coap_observer * observer)2004 bool coap_remove_observer(struct coap_resource *resource,
2005 			  struct coap_observer *observer)
2006 {
2007 	if (!sys_slist_find_and_remove(&resource->observers, &observer->list)) {
2008 		return false;
2009 	}
2010 
2011 	coap_observer_raise_event(resource, observer, NET_EVENT_COAP_OBSERVER_REMOVED);
2012 
2013 	return true;
2014 }
2015 
sockaddr_equal(const struct sockaddr * a,const struct sockaddr * b)2016 static bool sockaddr_equal(const struct sockaddr *a,
2017 			   const struct sockaddr *b)
2018 {
2019 	/* FIXME: Should we consider ipv6-mapped ipv4 addresses as equal to
2020 	 * ipv4 addresses?
2021 	 */
2022 	if (a->sa_family != b->sa_family) {
2023 		return false;
2024 	}
2025 
2026 	if (a->sa_family == AF_INET) {
2027 		const struct sockaddr_in *a4 = net_sin(a);
2028 		const struct sockaddr_in *b4 = net_sin(b);
2029 
2030 		if (a4->sin_port != b4->sin_port) {
2031 			return false;
2032 		}
2033 
2034 		return net_ipv4_addr_cmp(&a4->sin_addr, &b4->sin_addr);
2035 	}
2036 
2037 	if (b->sa_family == AF_INET6) {
2038 		const struct sockaddr_in6 *a6 = net_sin6(a);
2039 		const struct sockaddr_in6 *b6 = net_sin6(b);
2040 
2041 		if (a6->sin6_port != b6->sin6_port) {
2042 			return false;
2043 		}
2044 
2045 		return net_ipv6_addr_cmp(&a6->sin6_addr, &b6->sin6_addr);
2046 	}
2047 
2048 	/* Invalid address family */
2049 	return false;
2050 }
2051 
coap_find_observer(struct coap_observer * observers,size_t len,const struct sockaddr * addr,const uint8_t * token,uint8_t token_len)2052 struct coap_observer *coap_find_observer(
2053 	struct coap_observer *observers, size_t len,
2054 	const struct sockaddr *addr,
2055 	const uint8_t *token, uint8_t token_len)
2056 {
2057 	if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) {
2058 		return NULL;
2059 	}
2060 
2061 	for (size_t i = 0; i < len; i++) {
2062 		struct coap_observer *o = &observers[i];
2063 
2064 		if (o->tkl == token_len &&
2065 		    memcmp(o->token, token, token_len) == 0 &&
2066 		    sockaddr_equal(&o->addr, addr)) {
2067 			return o;
2068 		}
2069 	}
2070 
2071 	return NULL;
2072 }
2073 
coap_find_observer_by_addr(struct coap_observer * observers,size_t len,const struct sockaddr * addr)2074 struct coap_observer *coap_find_observer_by_addr(
2075 	struct coap_observer *observers, size_t len,
2076 	const struct sockaddr *addr)
2077 {
2078 	size_t i;
2079 
2080 	for (i = 0; i < len; i++) {
2081 		struct coap_observer *o = &observers[i];
2082 
2083 		if (sockaddr_equal(&o->addr, addr)) {
2084 			return o;
2085 		}
2086 	}
2087 
2088 	return NULL;
2089 }
2090 
coap_find_observer_by_token(struct coap_observer * observers,size_t len,const uint8_t * token,uint8_t token_len)2091 struct coap_observer *coap_find_observer_by_token(
2092 	struct coap_observer *observers, size_t len,
2093 	const uint8_t *token, uint8_t token_len)
2094 {
2095 	if (token_len == 0U || token_len > COAP_TOKEN_MAX_LEN) {
2096 		return NULL;
2097 	}
2098 
2099 	for (size_t i = 0; i < len; i++) {
2100 		struct coap_observer *o = &observers[i];
2101 
2102 		if (o->tkl == token_len && memcmp(o->token, token, token_len) == 0) {
2103 			return o;
2104 		}
2105 	}
2106 
2107 	return NULL;
2108 }
2109 
2110 /**
2111  * @brief Internal initialization function for CoAP library.
2112  *
2113  * Called by the network layer init procedure. Seeds the CoAP @message_id with a
2114  * random number in accordance with recommendations in CoAP specification.
2115  *
2116  * @note This function is not exposed in a public header, as it's for internal
2117  * use and should therefore not be exposed to applications.
2118  */
net_coap_init(void)2119 void net_coap_init(void)
2120 {
2121 	/* Initialize message_id to a random number */
2122 	message_id = (uint16_t)sys_rand32_get();
2123 }
2124 
coap_next_id(void)2125 uint16_t coap_next_id(void)
2126 {
2127 	return message_id++;
2128 }
2129 
coap_get_transmission_parameters(void)2130 struct coap_transmission_parameters coap_get_transmission_parameters(void)
2131 {
2132 	return coap_transmission_params;
2133 }
2134 
coap_set_transmission_parameters(const struct coap_transmission_parameters * params)2135 void coap_set_transmission_parameters(const struct coap_transmission_parameters *params)
2136 {
2137 	coap_transmission_params = *params;
2138 }
2139