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