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