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_test, LOG_LEVEL_DBG);
9 
10 #include <errno.h>
11 #include <zephyr/types.h>
12 #include <stdbool.h>
13 #include <stddef.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <zephyr/sys/printk.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/sys/util.h>
19 #include <zephyr/net/coap.h>
20 
21 #include <zephyr/tc_util.h>
22 #include <zephyr/ztest.h>
23 
24 #include "net_private.h"
25 
26 #define COAP_BUF_SIZE 128
27 #define COAP_FIXED_HEADER_SIZE 4
28 
29 #define NUM_PENDINGS 3
30 #define NUM_OBSERVERS 3
31 #define NUM_REPLIES 3
32 
33 static struct coap_pending pendings[NUM_PENDINGS];
34 static struct coap_observer observers[NUM_OBSERVERS];
35 static struct coap_reply replies[NUM_REPLIES];
36 
37 /* This is exposed for this test in subsys/net/lib/coap/coap_link_format.c */
38 bool _coap_match_path_uri(const char * const *path,
39 			  const char *uri, uint16_t len);
40 
41 /* Some forward declarations */
42 static void server_resource_1_callback(struct coap_resource *resource,
43 				       struct coap_observer *observer);
44 
45 static void server_resource_2_callback(struct coap_resource *resource,
46 				       struct coap_observer *observer);
47 
48 static int server_resource_1_get(struct coap_resource *resource,
49 				 struct coap_packet *request,
50 				 struct sockaddr *addr, socklen_t addr_len);
51 
52 static const char * const server_resource_1_path[] = { "s", "1", NULL };
53 static const char *const server_resource_2_path[] = { "s", "2", NULL };
54 static struct coap_resource server_resources[] = {
55 	{ .path = server_resource_1_path,
56 	  .get = server_resource_1_get,
57 	  .notify = server_resource_1_callback },
58 	{ .path = server_resource_2_path,
59 	  .get = server_resource_1_get, /* Get can be shared with the first resource */
60 	  .notify = server_resource_2_callback },
61 	{ },
62 };
63 
64 #define MY_PORT 12345
65 #define peer_addr { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \
66 			0, 0, 0, 0, 0, 0, 0, 0x2 } } }
67 static struct sockaddr_in6 dummy_addr = {
68 	.sin6_family = AF_INET6,
69 	.sin6_addr = peer_addr };
70 
71 static uint8_t data_buf[2][COAP_BUF_SIZE];
72 
73 #define COAP_ROLLOVER_AGE (1 << 23)
74 #define COAP_MAX_AGE      0xffffff
75 #define COAP_FIRST_AGE    2
76 
77 extern bool coap_age_is_newer(int v1, int v2);
78 
ZTEST(coap,test_build_empty_pdu)79 ZTEST(coap, test_build_empty_pdu)
80 {
81 	uint8_t result_pdu[] = { 0x40, 0x01, 0x0, 0x0 };
82 	struct coap_packet cpkt;
83 	uint8_t *data = data_buf[0];
84 	int r;
85 
86 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE,
87 			     COAP_VERSION_1, COAP_TYPE_CON, 0, NULL,
88 			     COAP_METHOD_GET, 0);
89 
90 	zassert_equal(r, 0, "Could not initialize packet");
91 	zassert_equal(cpkt.offset, sizeof(result_pdu),
92 		     "Different size from the reference packet");
93 	zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE,
94 		      "Invalid header length");
95 	zassert_equal(cpkt.opt_len, 0, "Invalid options length");
96 	zassert_mem_equal(result_pdu, cpkt.data, cpkt.offset,
97 			  "Built packet doesn't match reference packet");
98 }
99 
ZTEST(coap,test_build_simple_pdu)100 ZTEST(coap, test_build_simple_pdu)
101 {
102 	uint8_t result_pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e',
103 				 'n', 0xC0, 0xFF, 'p', 'a', 'y', 'l',
104 				 'o', 'a', 'd', 0x00 };
105 	struct coap_packet cpkt;
106 	const char token[] = "token";
107 	static const char payload[] = "payload";
108 	uint8_t *data = data_buf[0];
109 	const uint8_t *payload_start;
110 	uint16_t payload_len;
111 	int r;
112 
113 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE,
114 			     COAP_VERSION_1, COAP_TYPE_NON_CON,
115 			     strlen(token), token,
116 			     COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
117 			     0x1234);
118 	zassert_equal(r, 0, "Could not initialize packet");
119 
120 	r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT,
121 				   COAP_CONTENT_FORMAT_TEXT_PLAIN);
122 	zassert_equal(r, 0, "Could not append option");
123 
124 	r = coap_packet_append_payload_marker(&cpkt);
125 	zassert_equal(r, 0, "Failed to set the payload marker");
126 
127 	r = coap_packet_append_payload(&cpkt, payload, sizeof(payload));
128 	zassert_equal(r, 0, "Failed to set the payload");
129 
130 	zassert_equal(cpkt.offset, sizeof(result_pdu),
131 		     "Different size from the reference packet");
132 	zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE + strlen(token),
133 		      "Invalid header length");
134 	zassert_equal(cpkt.opt_len, 1, "Invalid options length");
135 	zassert_mem_equal(result_pdu, cpkt.data, cpkt.offset,
136 			  "Built packet doesn't match reference packet");
137 
138 	payload_start = coap_packet_get_payload(&cpkt, &payload_len);
139 
140 	zassert_equal(payload_len, sizeof(payload), "Invalid payload length");
141 	zassert_equal_ptr(payload_start, cpkt.data + cpkt.offset - payload_len,
142 			  "Invalid payload pointer");
143 }
144 
145 /* No options, No payload */
ZTEST(coap,test_parse_empty_pdu)146 ZTEST(coap, test_parse_empty_pdu)
147 {
148 	uint8_t pdu[] = { 0x40, 0x01, 0, 0 };
149 	struct coap_packet cpkt;
150 	uint8_t *data = data_buf[0];
151 	uint8_t ver;
152 	uint8_t type;
153 	uint8_t code;
154 	uint16_t id;
155 	int r;
156 
157 	memcpy(data, pdu, sizeof(pdu));
158 
159 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
160 	zassert_equal(r, 0, "Could not parse packet");
161 
162 	zassert_equal(cpkt.offset, sizeof(pdu),
163 		     "Different size from the reference packet");
164 	zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE,
165 		      "Invalid header length");
166 	zassert_equal(cpkt.opt_len, 0, "Invalid options length");
167 
168 	ver = coap_header_get_version(&cpkt);
169 	type = coap_header_get_type(&cpkt);
170 	code = coap_header_get_code(&cpkt);
171 	id = coap_header_get_id(&cpkt);
172 
173 	zassert_equal(ver, 1U, "Invalid version for parsed packet");
174 	zassert_equal(type, COAP_TYPE_CON,
175 		      "Packet type doesn't match reference");
176 	zassert_equal(code, COAP_METHOD_GET,
177 		      "Packet code doesn't match reference");
178 	zassert_equal(id, 0U, "Packet id doesn't match reference");
179 }
180 
181 /* 1 option, No payload (No payload marker) */
ZTEST(coap,test_parse_empty_pdu_1)182 ZTEST(coap, test_parse_empty_pdu_1)
183 {
184 	uint8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40};
185 	struct coap_packet cpkt;
186 	uint8_t *data = data_buf[0];
187 	uint8_t ver;
188 	uint8_t type;
189 	uint8_t code;
190 	uint16_t id;
191 	int r;
192 
193 	memcpy(data, pdu, sizeof(pdu));
194 
195 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
196 	zassert_equal(r, 0, "Could not parse packet");
197 
198 	zassert_equal(cpkt.offset, sizeof(pdu),
199 		     "Different size from the reference packet");
200 	zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE,
201 		      "Invalid header length");
202 	zassert_equal(cpkt.opt_len, 1, "Invalid options length");
203 
204 	ver = coap_header_get_version(&cpkt);
205 	type = coap_header_get_type(&cpkt);
206 	code = coap_header_get_code(&cpkt);
207 	id = coap_header_get_id(&cpkt);
208 
209 	zassert_equal(ver, 1U, "Invalid version for parsed packet");
210 	zassert_equal(type, COAP_TYPE_CON,
211 		      "Packet type doesn't match reference");
212 	zassert_equal(code, COAP_METHOD_GET,
213 		      "Packet code doesn't match reference");
214 	zassert_equal(id, 0U, "Packet id doesn't match reference");
215 }
216 
ZTEST(coap,test_parse_simple_pdu)217 ZTEST(coap, test_parse_simple_pdu)
218 {
219 	uint8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
220 		       0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o',
221 		       'a', 'd', 0x00 };
222 	struct coap_packet cpkt;
223 	struct coap_option options[16] = {};
224 	const uint8_t token[8];
225 	const uint8_t payload[] = "payload";
226 	uint8_t *data = data_buf[0];
227 	uint8_t ver;
228 	uint8_t type;
229 	uint8_t code;
230 	uint8_t tkl;
231 	uint16_t id;
232 	const uint8_t *payload_start;
233 	uint16_t payload_len;
234 	int r, count = ARRAY_SIZE(options) - 1;
235 
236 	memcpy(data, pdu, sizeof(pdu));
237 
238 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
239 	zassert_equal(r, 0, "Could not parse packet");
240 
241 	zassert_equal(cpkt.offset, sizeof(pdu),
242 		     "Different size from the reference packet");
243 	zassert_equal(cpkt.hdr_len, COAP_FIXED_HEADER_SIZE + strlen("token"),
244 		      "Invalid header length");
245 	zassert_equal(cpkt.opt_len, 3, "Invalid options length");
246 
247 	payload_start = coap_packet_get_payload(&cpkt, &payload_len);
248 
249 	zassert_equal(payload_len, sizeof(payload), "Invalid payload length");
250 	zassert_equal_ptr(payload_start, cpkt.data + cpkt.offset - payload_len,
251 			  "Invalid payload pointer");
252 
253 	ver = coap_header_get_version(&cpkt);
254 	type = coap_header_get_type(&cpkt);
255 	code = coap_header_get_code(&cpkt);
256 	id = coap_header_get_id(&cpkt);
257 
258 	zassert_equal(ver, 1U, "Invalid version for parsed packet");
259 	zassert_equal(type, COAP_TYPE_NON_CON,
260 		      "Packet type doesn't match reference");
261 	zassert_equal(code, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
262 		      "Packet code doesn't match reference");
263 	zassert_equal(id, 0x1234, "Packet id doesn't match reference");
264 
265 	tkl = coap_header_get_token(&cpkt, (uint8_t *)token);
266 
267 	zassert_equal(tkl, 5U, "Token length doesn't match reference");
268 	zassert_mem_equal(token, "token", tkl,
269 			  "Token value doesn't match the reference");
270 
271 	count = coap_find_options(&cpkt, COAP_OPTION_CONTENT_FORMAT,
272 				   options, count);
273 
274 	zassert_equal(count, 1, "Unexpected number of options in the packet");
275 	zassert_equal(options[0].len, 1U,
276 		     "Option length doesn't match the reference");
277 	zassert_equal(((uint8_t *)options[0].value)[0],
278 		      COAP_CONTENT_FORMAT_TEXT_PLAIN,
279 		      "Option value doesn't match the reference");
280 
281 	/* Not existent */
282 	count = coap_find_options(&cpkt, COAP_OPTION_ETAG, options, count);
283 
284 	zassert_equal(count, 0,
285 		      "There shouldn't be any ETAG option in the packet");
286 }
287 
ZTEST(coap,test_parse_malformed_pkt)288 ZTEST(coap, test_parse_malformed_pkt)
289 {
290 	uint8_t opt[] = { 0x55, 0xA5, 0x12 };
291 
292 	struct coap_packet cpkt;
293 	uint8_t *data = data_buf[0];
294 	int r;
295 
296 	r = coap_packet_parse(&cpkt, NULL, sizeof(opt), NULL, 0);
297 	zassert_equal(r, -EINVAL, "Should've failed to parse a packet");
298 
299 	r = coap_packet_parse(&cpkt, data, 0, NULL, 0);
300 	zassert_equal(r, -EINVAL, "Should've failed to parse a packet");
301 
302 	memcpy(data, opt, sizeof(opt));
303 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
304 	zassert_equal(r, -EINVAL, "Should've failed to parse a packet");
305 }
306 
ZTEST(coap,test_parse_malformed_coap_hdr)307 ZTEST(coap, test_parse_malformed_coap_hdr)
308 {
309 	uint8_t opt[] = { 0x55, 0x24, 0x49, 0x55, 0xff, 0x66, 0x77, 0x99};
310 
311 	struct coap_packet cpkt;
312 	uint8_t *data = data_buf[0];
313 	int r;
314 
315 	memcpy(data, opt, sizeof(opt));
316 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
317 	zassert_equal(r, -EBADMSG, "Should've failed to parse a packet");
318 }
319 
ZTEST(coap,test_parse_malformed_opt)320 ZTEST(coap, test_parse_malformed_opt)
321 {
322 	uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
323 		       0xD0 };
324 	struct coap_packet cpkt;
325 	uint8_t *data = data_buf[0];
326 	int r;
327 
328 	memcpy(data, opt, sizeof(opt));
329 
330 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
331 	zassert_equal(r, -EILSEQ, "Should've failed to parse a packet");
332 }
333 
ZTEST(coap,test_parse_malformed_opt_len)334 ZTEST(coap, test_parse_malformed_opt_len)
335 {
336 	uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
337 		       0xC1 };
338 	struct coap_packet cpkt;
339 	uint8_t *data = data_buf[0];
340 	int r;
341 
342 	memcpy(data, opt, sizeof(opt));
343 
344 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
345 	zassert_equal(r, -EILSEQ, "Should've failed to parse a packet");
346 }
347 
ZTEST(coap,test_parse_malformed_opt_ext)348 ZTEST(coap, test_parse_malformed_opt_ext)
349 {
350 	uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
351 		       0xE0, 0x01 };
352 	struct coap_packet cpkt;
353 	uint8_t *data = data_buf[0];
354 	int r;
355 
356 	memcpy(data, opt, sizeof(opt));
357 
358 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
359 	zassert_equal(r, -EILSEQ, "Should've failed to parse a packet");
360 }
361 
ZTEST(coap,test_parse_malformed_opt_len_ext)362 ZTEST(coap, test_parse_malformed_opt_len_ext)
363 {
364 	uint8_t opt[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
365 		       0xEE, 0x01, 0x02, 0x01};
366 	struct coap_packet cpkt;
367 	uint8_t *data = data_buf[0];
368 	int r;
369 
370 	memcpy(data, opt, sizeof(opt));
371 
372 	r = coap_packet_parse(&cpkt, data, sizeof(opt), NULL, 0);
373 	zassert_equal(r, -EILSEQ, "Should've failed to parse a packet");
374 }
375 
376 /* 1 option, No payload (with payload marker) */
ZTEST(coap,test_parse_malformed_marker)377 ZTEST(coap, test_parse_malformed_marker)
378 {
379 	uint8_t pdu[] = { 0x40, 0x01, 0, 0, 0x40, 0xFF};
380 	struct coap_packet cpkt;
381 	uint8_t *data = data_buf[0];
382 	int r;
383 
384 	memcpy(data, pdu, sizeof(pdu));
385 
386 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
387 	zassert_not_equal(r, 0, "Should've failed to parse a packet");
388 }
389 
ZTEST(coap,test_parse_req_build_ack)390 ZTEST(coap, test_parse_req_build_ack)
391 {
392 	uint8_t pdu[] = { 0x45, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n',
393 		       0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o',
394 		       'a', 'd', 0x00 };
395 	uint8_t ack_pdu[] = { 0x65, 0x80, 0x12, 0x34, 't', 'o', 'k', 'e', 'n' };
396 	struct coap_packet cpkt;
397 	struct coap_packet ack_cpkt;
398 	uint8_t *data = data_buf[0];
399 	uint8_t *ack_data = data_buf[1];
400 	int r;
401 
402 	memcpy(data, pdu, sizeof(pdu));
403 
404 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
405 	zassert_equal(r, 0, "Could not parse packet");
406 
407 	r = coap_ack_init(&ack_cpkt, &cpkt, ack_data, COAP_BUF_SIZE,
408 			  COAP_RESPONSE_CODE_BAD_REQUEST);
409 	zassert_equal(r, 0, "Could not initialize ACK packet");
410 
411 	zassert_equal(ack_cpkt.offset, sizeof(ack_pdu),
412 		     "Different size from the reference packet");
413 	zassert_mem_equal(ack_pdu, ack_cpkt.data, ack_cpkt.offset,
414 			  "Built packet doesn't match reference packet");
415 }
416 
ZTEST(coap,test_parse_req_build_empty_ack)417 ZTEST(coap, test_parse_req_build_empty_ack)
418 {
419 	uint8_t pdu[] = { 0x45, 0xA5, 0xDE, 0xAD, 't', 'o', 'k', 'e', 'n',
420 		       0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o',
421 		       'a', 'd', 0x00 };
422 	uint8_t ack_pdu[] = { 0x60, 0x00, 0xDE, 0xAD };
423 	struct coap_packet cpkt;
424 	struct coap_packet ack_cpkt;
425 	uint8_t *data = data_buf[0];
426 	uint8_t *ack_data = data_buf[1];
427 	int r;
428 
429 	memcpy(data, pdu, sizeof(pdu));
430 
431 	r = coap_packet_parse(&cpkt, data, sizeof(pdu), NULL, 0);
432 	zassert_equal(r, 0, "Could not parse packet");
433 
434 	r = coap_ack_init(&ack_cpkt, &cpkt, ack_data, COAP_BUF_SIZE,
435 			  COAP_CODE_EMPTY);
436 	zassert_equal(r, 0, "Could not initialize ACK packet");
437 
438 	zassert_equal(ack_cpkt.offset, sizeof(ack_pdu),
439 		      "Different size from the reference packet");
440 	zassert_mem_equal(ack_pdu, ack_cpkt.data, ack_cpkt.offset,
441 			  "Built packet doesn't match reference packet");
442 }
443 
ZTEST(coap,test_match_path_uri)444 ZTEST(coap, test_match_path_uri)
445 {
446 	const char * const resource_path[] = {
447 		"s",
448 		"1",
449 		"foobar",
450 		"foobar3a",
451 		"foobar3",
452 		"devnull",
453 		NULL
454 	};
455 	const char *uri;
456 	int r;
457 
458 	uri = "/k";
459 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
460 	zassert_false(r, "Matching %s failed", uri);
461 
462 	uri = "/s";
463 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
464 	zassert_true(r, "Matching %s failed", uri);
465 
466 	uri = "/foobar";
467 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
468 	zassert_true(r, "Matching %s failed", uri);
469 
470 	uri = "/foobar2";
471 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
472 	zassert_false(r, "Matching %s failed", uri);
473 
474 	uri = "/foobar*";
475 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
476 	zassert_true(r, "Matching %s failed", uri);
477 
478 	uri = "/foobar3*";
479 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
480 	zassert_true(r, "Matching %s failed", uri);
481 
482 	uri = "/devnull*";
483 	r = _coap_match_path_uri(resource_path, uri, strlen(uri));
484 	zassert_false(r, "Matching %s failed", uri);
485 }
486 
487 #define BLOCK_WISE_TRANSFER_SIZE_GET 150
488 
prepare_block1_request(struct coap_packet * req,struct coap_block_context * req_ctx,int * more)489 static void prepare_block1_request(struct coap_packet *req,
490 				   struct coap_block_context *req_ctx,
491 				   int *more)
492 {
493 	const char token[] = "token";
494 	uint8_t payload[32] = { 0 };
495 	uint8_t *data = data_buf[0];
496 	bool first;
497 	int r;
498 	int block_size = coap_block_size_to_bytes(COAP_BLOCK_32);
499 	int payload_len;
500 
501 	/* Request Context */
502 	if (req_ctx->total_size == 0) {
503 		first = true;
504 		coap_block_transfer_init(req_ctx, COAP_BLOCK_32,
505 					 BLOCK_WISE_TRANSFER_SIZE_GET);
506 	} else {
507 		first = false;
508 	}
509 
510 	r = coap_packet_init(req, data, COAP_BUF_SIZE, COAP_VERSION_1,
511 			     COAP_TYPE_CON, strlen(token),
512 			     token, COAP_METHOD_POST,
513 			     coap_next_id());
514 	zassert_equal(r, 0, "Unable to initialize request");
515 
516 	r = coap_append_block1_option(req, req_ctx);
517 	zassert_equal(r, 0, "Unable to append block1 option");
518 
519 	if (first) {
520 		r = coap_append_size1_option(req, req_ctx);
521 		zassert_equal(r, 0, "Unable to append size1 option");
522 	}
523 
524 	r = coap_packet_append_payload_marker(req);
525 	zassert_equal(r, 0, "Unable to append payload marker");
526 
527 	payload_len = req_ctx->total_size - req_ctx->current;
528 	if (payload_len > block_size) {
529 		payload_len = block_size;
530 	}
531 
532 	r = coap_packet_append_payload(req, payload, payload_len);
533 	zassert_equal(r, 0, "Unable to append payload");
534 
535 	*more = coap_next_block(req, req_ctx);
536 }
537 
prepare_block1_response(struct coap_packet * rsp,struct coap_block_context * rsp_ctx,struct coap_packet * req)538 static void prepare_block1_response(struct coap_packet *rsp,
539 				    struct coap_block_context *rsp_ctx,
540 				    struct coap_packet *req)
541 {
542 	uint8_t token[8];
543 	uint8_t *data = data_buf[1];
544 	uint16_t id;
545 	uint8_t tkl;
546 	int r;
547 
548 	if (rsp_ctx->total_size == 0) {
549 		coap_block_transfer_init(rsp_ctx, COAP_BLOCK_32,
550 					 BLOCK_WISE_TRANSFER_SIZE_GET);
551 	}
552 
553 	r = coap_update_from_block(req, rsp_ctx);
554 	zassert_equal(r, 0, "Failed to read block option");
555 
556 	id = coap_header_get_id(req);
557 	tkl = coap_header_get_token(req, token);
558 
559 	r = coap_packet_init(rsp, data, COAP_BUF_SIZE, COAP_VERSION_1,
560 			     COAP_TYPE_ACK, tkl, token,
561 			     COAP_RESPONSE_CODE_CREATED, id);
562 	zassert_equal(r, 0, "Unable to initialize request");
563 
564 	r = coap_append_block1_option(rsp, rsp_ctx);
565 	zassert_equal(r, 0, "Unable to append block1 option");
566 }
567 
568 #define ITER_COUNT(len, block_len) DIV_ROUND_UP(len, block_len)
569 
verify_block1_request(struct coap_block_context * req_ctx,uint8_t iter)570 static void verify_block1_request(struct coap_block_context *req_ctx,
571 				  uint8_t iter)
572 {
573 	int block_size = coap_block_size_to_bytes(COAP_BLOCK_32);
574 	int iter_max = ITER_COUNT(BLOCK_WISE_TRANSFER_SIZE_GET, block_size);
575 
576 	zassert_equal(req_ctx->block_size, COAP_BLOCK_32,
577 		      "req:%d,Couldn't get block size", iter);
578 
579 	/* In last iteration "current" must match "total_size" */
580 	if (iter < iter_max) {
581 		zassert_equal(
582 			req_ctx->current, block_size * iter,
583 			"req:%d,Couldn't get the current block position", iter);
584 	} else {
585 		zassert_equal(
586 			req_ctx->current, req_ctx->total_size,
587 			"req:%d,Couldn't get the current block position", iter);
588 	}
589 
590 	zassert_equal(req_ctx->total_size, BLOCK_WISE_TRANSFER_SIZE_GET,
591 		      "req:%d,Couldn't packet total size", iter);
592 }
593 
verify_block1_response(struct coap_block_context * rsp_ctx,uint8_t iter)594 static void verify_block1_response(struct coap_block_context *rsp_ctx,
595 				   uint8_t iter)
596 {
597 	zassert_equal(rsp_ctx->block_size, COAP_BLOCK_32,
598 		      "rsp:%d,Couldn't get block size", iter);
599 	zassert_equal(rsp_ctx->current,
600 		      coap_block_size_to_bytes(COAP_BLOCK_32) * (iter - 1U),
601 		      "rsp:%d, Couldn't get the current block position", iter);
602 	zassert_equal(rsp_ctx->total_size, BLOCK_WISE_TRANSFER_SIZE_GET,
603 		      "rsp:%d, Couldn't packet total size", iter);
604 }
605 
ZTEST(coap,test_block1_size)606 ZTEST(coap, test_block1_size)
607 {
608 	struct coap_block_context req_ctx;
609 	struct coap_block_context rsp_ctx;
610 	struct coap_packet req;
611 	struct coap_packet rsp;
612 	int more;
613 	uint8_t i;
614 
615 	i = 0U;
616 	more = 1;
617 	memset(&req_ctx, 0, sizeof(req_ctx));
618 	memset(&rsp_ctx, 0, sizeof(rsp_ctx));
619 
620 	while (more) {
621 		prepare_block1_request(&req, &req_ctx, &more);
622 		prepare_block1_response(&rsp, &rsp_ctx, &req);
623 
624 		i++;
625 
626 		verify_block1_request(&req_ctx, i);
627 		verify_block1_response(&rsp_ctx, i);
628 	}
629 }
630 
631 #define BLOCK2_WISE_TRANSFER_SIZE_GET 300
632 
prepare_block2_request(struct coap_packet * req,struct coap_block_context * req_ctx,struct coap_packet * rsp)633 static void prepare_block2_request(struct coap_packet *req,
634 				   struct coap_block_context *req_ctx,
635 				   struct coap_packet *rsp)
636 {
637 	const char token[] = "token";
638 	uint8_t *data = data_buf[0];
639 	int r;
640 
641 	/* Request Context */
642 	if (req_ctx->total_size == 0) {
643 		coap_block_transfer_init(req_ctx, COAP_BLOCK_64,
644 					 BLOCK2_WISE_TRANSFER_SIZE_GET);
645 	} else {
646 		coap_next_block(rsp, req_ctx);
647 	}
648 
649 	r = coap_packet_init(req, data, COAP_BUF_SIZE, COAP_VERSION_1,
650 			     COAP_TYPE_CON, strlen(token),
651 			     token, COAP_METHOD_GET,
652 			     coap_next_id());
653 	zassert_equal(r, 0, "Unable to initialize request");
654 
655 	r = coap_append_block2_option(req, req_ctx);
656 	zassert_equal(r, 0, "Unable to append block2 option");
657 }
658 
prepare_block2_response(struct coap_packet * rsp,struct coap_block_context * rsp_ctx,struct coap_packet * req,int * more)659 static void prepare_block2_response(struct coap_packet *rsp,
660 				   struct coap_block_context *rsp_ctx,
661 				   struct coap_packet *req,
662 				   int *more)
663 {
664 	uint8_t payload[64];
665 	uint8_t token[8];
666 	uint8_t *data = data_buf[1];
667 	uint16_t id;
668 	uint8_t tkl;
669 	bool first;
670 	int r;
671 	int block_size = coap_block_size_to_bytes(COAP_BLOCK_64);
672 	int payload_len;
673 
674 	if (rsp_ctx->total_size == 0) {
675 		first = true;
676 		coap_block_transfer_init(rsp_ctx, COAP_BLOCK_64,
677 					 BLOCK2_WISE_TRANSFER_SIZE_GET);
678 	} else {
679 		first = false;
680 	}
681 
682 	id = coap_header_get_id(req);
683 	tkl = coap_header_get_token(req, token);
684 
685 	r = coap_packet_init(rsp, data, COAP_BUF_SIZE, COAP_VERSION_1,
686 			     COAP_TYPE_ACK, tkl, token,
687 			     COAP_RESPONSE_CODE_CONTENT, id);
688 	zassert_equal(r, 0, "Unable to initialize request");
689 
690 	r = coap_append_block2_option(rsp, rsp_ctx);
691 	zassert_equal(r, 0, "Unable to append block2 option");
692 
693 	if (first) {
694 		r = coap_append_size2_option(rsp, rsp_ctx);
695 		zassert_equal(r, 0, "Unable to append size2 option");
696 	}
697 
698 	r = coap_packet_append_payload_marker(rsp);
699 	zassert_equal(r, 0, "Unable to append payload marker");
700 
701 	payload_len = rsp_ctx->total_size - rsp_ctx->current;
702 	if (payload_len > block_size) {
703 		payload_len = block_size;
704 	}
705 
706 	r = coap_packet_append_payload(rsp, payload, payload_len);
707 	zassert_equal(r, 0, "Unable to append payload");
708 
709 	*more = coap_next_block(rsp, rsp_ctx);
710 }
711 
verify_block2_request(struct coap_block_context * req_ctx,uint8_t iter)712 static void verify_block2_request(struct coap_block_context *req_ctx,
713 				 uint8_t iter)
714 {
715 	zassert_equal(req_ctx->block_size, COAP_BLOCK_64,
716 		      "req:%d,Couldn't get block size", iter);
717 	zassert_equal(req_ctx->current,
718 		      coap_block_size_to_bytes(COAP_BLOCK_64) * (iter - 1U),
719 		      "req:%d, Couldn't get the current block position", iter);
720 	zassert_equal(req_ctx->total_size, BLOCK2_WISE_TRANSFER_SIZE_GET,
721 		      "req:%d,Couldn't packet total size", iter);
722 }
723 
verify_block2_response(struct coap_block_context * rsp_ctx,uint8_t iter)724 static void verify_block2_response(struct coap_block_context *rsp_ctx,
725 				  uint8_t iter)
726 {
727 	int block_size = coap_block_size_to_bytes(COAP_BLOCK_64);
728 	int iter_max = ITER_COUNT(BLOCK2_WISE_TRANSFER_SIZE_GET, block_size);
729 
730 	zassert_equal(rsp_ctx->block_size, COAP_BLOCK_64,
731 		      "rsp:%d,Couldn't get block size", iter);
732 
733 	/* In last iteration "current" must match "total_size" */
734 	if (iter < iter_max) {
735 		zassert_equal(
736 			rsp_ctx->current, block_size * iter,
737 			"req:%d,Couldn't get the current block position", iter);
738 	} else {
739 		zassert_equal(
740 			rsp_ctx->current, rsp_ctx->total_size,
741 			"req:%d,Current block position does not match total size", iter);
742 	}
743 
744 	zassert_equal(rsp_ctx->total_size, BLOCK2_WISE_TRANSFER_SIZE_GET,
745 		      "rsp:%d, Couldn't packet total size", iter);
746 }
747 
ZTEST(coap,test_block2_size)748 ZTEST(coap, test_block2_size)
749 {
750 	struct coap_block_context req_ctx;
751 	struct coap_block_context rsp_ctx;
752 	struct coap_packet req;
753 	struct coap_packet rsp;
754 	int more;
755 	uint8_t i;
756 
757 	i = 0U;
758 	more = 1;
759 	memset(&req_ctx, 0, sizeof(req_ctx));
760 	memset(&rsp_ctx, 0, sizeof(rsp_ctx));
761 
762 	while (more) {
763 		prepare_block2_request(&req, &req_ctx, &rsp);
764 		prepare_block2_response(&rsp, &rsp_ctx, &req, &more);
765 
766 		i++;
767 
768 		verify_block2_request(&req_ctx, i);
769 		verify_block2_response(&rsp_ctx, i);
770 	}
771 }
772 
ZTEST(coap,test_retransmit_second_round)773 ZTEST(coap, test_retransmit_second_round)
774 {
775 	struct coap_packet cpkt;
776 	struct coap_packet rsp;
777 	struct coap_pending *pending;
778 	struct coap_pending *rsp_pending;
779 	uint8_t *data = data_buf[0];
780 	uint8_t *rsp_data = data_buf[1];
781 	int r;
782 	uint16_t id;
783 
784 	id = coap_next_id();
785 
786 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1,
787 			     COAP_TYPE_CON, 0, coap_next_token(),
788 			     COAP_METHOD_GET, id);
789 	zassert_equal(r, 0, "Could not initialize packet");
790 
791 	pending = coap_pending_next_unused(pendings, NUM_PENDINGS);
792 	zassert_not_null(pending, "No free pending");
793 
794 	r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr,
795 			      NULL);
796 	zassert_equal(r, 0, "Could not initialize packet");
797 
798 	/* We "send" the packet the first time here */
799 	zassert_true(coap_pending_cycle(pending), "Pending expired too early");
800 
801 	/* We simulate that the first transmission got lost */
802 	zassert_true(coap_pending_cycle(pending), "Pending expired too early");
803 
804 	r = coap_packet_init(&rsp, rsp_data, COAP_BUF_SIZE,
805 			     COAP_VERSION_1, COAP_TYPE_ACK, 0, NULL,
806 			     COAP_METHOD_GET, id);
807 	zassert_equal(r, 0, "Could not initialize packet");
808 
809 	/* Now we get the ack from the remote side */
810 	rsp_pending = coap_pending_received(&rsp, pendings, NUM_PENDINGS);
811 	zassert_equal_ptr(pending, rsp_pending,
812 			  "Invalid pending %p should be %p",
813 			  rsp_pending, pending);
814 
815 	coap_pending_clear(rsp_pending);
816 
817 	rsp_pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS);
818 	zassert_is_null(rsp_pending, "There should be no active pendings");
819 }
820 
ipaddr_cmp(const struct sockaddr * a,const struct sockaddr * b)821 static bool ipaddr_cmp(const struct sockaddr *a, const struct sockaddr *b)
822 {
823 	if (a->sa_family != b->sa_family) {
824 		return false;
825 	}
826 
827 	if (a->sa_family == AF_INET6) {
828 		return net_ipv6_addr_cmp(&net_sin6(a)->sin6_addr,
829 					 &net_sin6(b)->sin6_addr);
830 	} else if (a->sa_family == AF_INET) {
831 		return net_ipv4_addr_cmp(&net_sin(a)->sin_addr,
832 					 &net_sin(b)->sin_addr);
833 	}
834 
835 	return false;
836 }
837 
server_resource_1_callback(struct coap_resource * resource,struct coap_observer * observer)838 static void server_resource_1_callback(struct coap_resource *resource,
839 				       struct coap_observer *observer)
840 {
841 	bool r;
842 
843 	r = ipaddr_cmp(&observer->addr, (const struct sockaddr *)&dummy_addr);
844 	zassert_true(r, "The address of the observer doesn't match");
845 
846 	coap_remove_observer(resource, observer);
847 }
server_resource_2_callback(struct coap_resource * resource,struct coap_observer * observer)848 static void server_resource_2_callback(struct coap_resource *resource,
849 				       struct coap_observer *observer)
850 {
851 	bool r;
852 
853 	r = ipaddr_cmp(&observer->addr, (const struct sockaddr *)&dummy_addr);
854 	zassert_true(r, "The address of the observer doesn't match");
855 }
856 
server_resource_1_get(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)857 static int server_resource_1_get(struct coap_resource *resource,
858 				 struct coap_packet *request,
859 				 struct sockaddr *addr, socklen_t addr_len)
860 {
861 	struct coap_packet response;
862 	struct coap_observer *observer;
863 	uint8_t *data = data_buf[1];
864 	char payload[] = "This is the payload";
865 	uint8_t token[8];
866 	uint8_t tkl;
867 	uint16_t id;
868 	int r;
869 
870 	zassert_true(coap_request_is_observe(request),
871 		     "The request should enable observing");
872 
873 	observer = coap_observer_next_unused(observers, NUM_OBSERVERS);
874 	zassert_not_null(observer, "There should be an available observer");
875 
876 	tkl = coap_header_get_token(request, (uint8_t *) token);
877 	id = coap_header_get_id(request);
878 
879 	coap_observer_init(observer, request, addr);
880 	coap_register_observer(resource, observer);
881 
882 	r = coap_packet_init(&response, data, COAP_BUF_SIZE,
883 			     COAP_VERSION_1, COAP_TYPE_ACK, tkl, token,
884 			     COAP_RESPONSE_CODE_OK, id);
885 	zassert_equal(r, 0, "Unable to initialize packet");
886 
887 	r = coap_append_option_int(&response, COAP_OPTION_OBSERVE,
888 				   resource->age);
889 	zassert_equal(r, 0, "Failed to append observe option");
890 
891 	r = coap_packet_append_payload_marker(&response);
892 	zassert_equal(r, 0, "Failed to set the payload marker");
893 
894 	r = coap_packet_append_payload(&response, (uint8_t *)payload,
895 				       strlen(payload));
896 	zassert_equal(r, 0, "Unable to append payload");
897 
898 	resource->user_data = data;
899 
900 	return 0;
901 }
902 
ZTEST(coap,test_observer_server)903 ZTEST(coap, test_observer_server)
904 {
905 	uint8_t valid_request_pdu[] = {
906 		0x45, 0x01, 0x12, 0x34,
907 		't', 'o', 'k', 'e', 'n',
908 		0x60, /* enable observe option */
909 		0x51, 's', 0x01, '1', /* path */
910 	};
911 	uint8_t not_found_request_pdu[] = {
912 		0x45, 0x01, 0x12, 0x34,
913 		't', 'o', 'k', 'e', 'n',
914 		0x60, /* enable observe option */
915 		0x51, 's', 0x01, '3', /* path */
916 	};
917 	struct coap_packet req;
918 	struct coap_option options[4] = {};
919 	uint8_t *data = data_buf[0];
920 	uint8_t opt_num = ARRAY_SIZE(options) - 1;
921 	int r;
922 
923 	memcpy(data, valid_request_pdu, sizeof(valid_request_pdu));
924 
925 	r = coap_packet_parse(&req, data, sizeof(valid_request_pdu),
926 			      options, opt_num);
927 	zassert_equal(r, 0, "Could not initialize packet");
928 
929 	r = coap_handle_request(&req, server_resources, options, opt_num,
930 				(struct sockaddr *) &dummy_addr,
931 				sizeof(dummy_addr));
932 	zassert_equal(r, 0, "Could not handle packet");
933 
934 	/* Suppose some time passes */
935 	r = coap_resource_notify(&server_resources[0]);
936 	zassert_equal(r, 0, "Could not notify resource");
937 
938 	memcpy(data, not_found_request_pdu, sizeof(not_found_request_pdu));
939 
940 	r = coap_packet_parse(&req, data, sizeof(not_found_request_pdu),
941 			      options, opt_num);
942 	zassert_equal(r, 0, "Could not initialize packet");
943 
944 	r = coap_handle_request(&req, server_resources, options, opt_num,
945 				(struct sockaddr *) &dummy_addr,
946 				sizeof(dummy_addr));
947 	zassert_equal(r, -ENOENT,
948 		      "There should be no handler for this resource");
949 }
950 
resource_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)951 static int resource_reply_cb(const struct coap_packet *response,
952 			     struct coap_reply *reply,
953 			     const struct sockaddr *from)
954 {
955 	TC_PRINT("You should see this");
956 
957 	return 0;
958 }
959 
ZTEST(coap,test_observer_client)960 ZTEST(coap, test_observer_client)
961 {
962 	struct coap_packet req;
963 	struct coap_packet rsp;
964 	struct coap_reply *reply;
965 	struct coap_option options[4] = {};
966 	const char token[] = "token";
967 	const char * const *p;
968 	uint8_t *data = data_buf[0];
969 	uint8_t *rsp_data = data_buf[1];
970 	uint8_t opt_num = ARRAY_SIZE(options) - 1;
971 	int observe = 0;
972 	int r;
973 
974 	r = coap_packet_init(&req, data, COAP_BUF_SIZE,
975 			     COAP_VERSION_1, COAP_TYPE_CON,
976 			     strlen(token), token,
977 			     COAP_METHOD_GET, coap_next_id());
978 	zassert_equal(r, 0, "Unable to initialize request");
979 
980 	/* Enable observing the resource. */
981 	r = coap_append_option_int(&req, COAP_OPTION_OBSERVE, observe);
982 	zassert_equal(r, 0, "Unable to add option to request int");
983 
984 	for (p = server_resource_1_path; p && *p; p++) {
985 		r = coap_packet_append_option(&req, COAP_OPTION_URI_PATH,
986 					      *p, strlen(*p));
987 		zassert_equal(r, 0, "Unable to add option to request");
988 	}
989 
990 	reply = coap_reply_next_unused(replies, NUM_REPLIES);
991 	zassert_not_null(reply, "No resources for waiting for replies");
992 
993 	coap_reply_init(reply, &req);
994 	reply->reply = resource_reply_cb;
995 
996 	/* Server side, not interesting for this test */
997 	r = coap_packet_parse(&req, data, req.offset, options, opt_num);
998 	zassert_equal(r, 0, "Could not parse req packet");
999 
1000 	r = coap_handle_request(&req, server_resources, options, opt_num,
1001 				(struct sockaddr *) &dummy_addr,
1002 				sizeof(dummy_addr));
1003 	zassert_equal(r, 0, "Could not handle packet");
1004 
1005 	/* We cheat, and communicate using the resource's user_data */
1006 	rsp_data = server_resources[0].user_data;
1007 
1008 	/* 'rsp_pkt' contains the response now */
1009 
1010 	r = coap_packet_parse(&rsp, rsp_data, req.offset, options, opt_num);
1011 	zassert_equal(r, 0, "Could not parse rsp packet");
1012 
1013 	reply = coap_response_received(&rsp,
1014 				       (const struct sockaddr *) &dummy_addr,
1015 				       replies, NUM_REPLIES);
1016 	zassert_not_null(reply, "Couldn't find a matching waiting reply");
1017 }
1018 
ZTEST(coap,test_handle_invalid_coap_req)1019 ZTEST(coap, test_handle_invalid_coap_req)
1020 {
1021 	struct coap_packet pkt;
1022 	uint8_t *data = data_buf[0];
1023 	struct coap_option options[4] = {};
1024 	uint8_t opt_num = 4;
1025 	int r;
1026 	const char *const *p;
1027 
1028 	r = coap_packet_init(&pkt, data, COAP_BUF_SIZE, COAP_VERSION_1,
1029 					COAP_TYPE_CON, 0, NULL, 0xFF, coap_next_id());
1030 
1031 	zassert_equal(r, 0, "Unable to init req");
1032 
1033 	for (p = server_resource_1_path; p && *p; p++) {
1034 		r = coap_packet_append_option(&pkt, COAP_OPTION_URI_PATH,
1035 					*p, strlen(*p));
1036 		zassert_equal(r, 0, "Unable to append option");
1037 	}
1038 
1039 	r = coap_packet_parse(&pkt, data, pkt.offset, options, opt_num);
1040 	zassert_equal(r, 0, "Could not parse req packet");
1041 
1042 	r = coap_handle_request(&pkt, server_resources, options, opt_num,
1043 					(struct sockaddr *) &dummy_addr, sizeof(dummy_addr));
1044 	zassert_equal(r, -ENOTSUP, "Request handling should fail with -ENOTSUP");
1045 }
1046 
ZTEST(coap,test_build_options_out_of_order_0)1047 ZTEST(coap, test_build_options_out_of_order_0)
1048 {
1049 	uint8_t result[] = {0x45, 0x02, 0x12, 0x34, 't', 'o', 'k',  'e', 'n', 0xC0, 0xB1, 0x19,
1050 			    0xC5, 'p',	'r',  'o',  'x', 'y', 0x44, 'c', 'o', 'a',  'p'};
1051 	struct coap_packet cpkt;
1052 	static const char token[] = "token";
1053 	uint8_t *data = data_buf[0];
1054 	int r;
1055 
1056 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1057 			     strlen(token), token, COAP_METHOD_POST, 0x1234);
1058 	zassert_equal(r, 0, "Could not initialize packet");
1059 
1060 	r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT,
1061 				   COAP_CONTENT_FORMAT_TEXT_PLAIN);
1062 	zassert_equal(r, 0, "Could not append option");
1063 
1064 	static const uint8_t expected_options_0 = 0xc0; /* content format */
1065 
1066 	zassert_mem_equal(&expected_options_0, &cpkt.data[cpkt.hdr_len], cpkt.opt_len);
1067 
1068 	const char *proxy_uri = "proxy";
1069 
1070 	r = coap_packet_append_option(&cpkt, COAP_OPTION_PROXY_URI, proxy_uri, strlen(proxy_uri));
1071 	zassert_equal(r, 0, "Could not append option");
1072 	static const uint8_t expected_options_1[] = {
1073 		0xc0,				    /* content format */
1074 		0xd5, 0x0a, 'p', 'r', 'o', 'x', 'y' /* proxy url */
1075 	};
1076 	zassert_mem_equal(expected_options_1, &cpkt.data[cpkt.hdr_len], cpkt.opt_len);
1077 
1078 	const char *proxy_scheme = "coap";
1079 
1080 	r = coap_packet_append_option(&cpkt, COAP_OPTION_PROXY_SCHEME, proxy_scheme,
1081 				      strlen(proxy_scheme));
1082 	zassert_equal(r, 0, "Could not append option");
1083 	static const uint8_t expected_options_2[] = {
1084 		0xc0,				     /*  content format */
1085 		0xd5, 0x0a, 'p', 'r', 'o', 'x', 'y', /*  proxy url */
1086 		0x44, 'c',  'o', 'a', 'p'	     /*  proxy scheme */
1087 	};
1088 	zassert_mem_equal(expected_options_2, &cpkt.data[cpkt.hdr_len], cpkt.opt_len);
1089 
1090 	/*  option out of order */
1091 	const uint8_t block_option = 0b11001;
1092 
1093 	r = coap_append_option_int(&cpkt, COAP_OPTION_BLOCK2, block_option);
1094 	zassert_equal(r, 0, "Could not append option");
1095 	static const uint8_t expected_options_3[] = {
1096 		0xc0,				/*  content format */
1097 		0xb1, 0x19,			/*  block2 */
1098 		0xc5, 'p',  'r', 'o', 'x', 'y', /*  proxy url */
1099 		0x44, 'c',  'o', 'a', 'p'	/*  proxy scheme */
1100 	};
1101 	zassert_mem_equal(expected_options_3, &cpkt.data[cpkt.hdr_len], cpkt.opt_len);
1102 
1103 	/*  look for options */
1104 	struct coap_option opt;
1105 
1106 	r = coap_find_options(&cpkt, COAP_OPTION_CONTENT_FORMAT, &opt, 1);
1107 	zassert_equal(r, 1, "Could not find option");
1108 
1109 	r = coap_find_options(&cpkt, COAP_OPTION_PROXY_URI, &opt, 1);
1110 	zassert_equal(r, 1, "Could not find option");
1111 	zassert_equal(opt.len, strlen(proxy_uri), "Wrong option len");
1112 	zassert_mem_equal(opt.value, proxy_uri, strlen(proxy_uri), "Wrong option content");
1113 
1114 	r = coap_find_options(&cpkt, COAP_OPTION_PROXY_SCHEME, &opt, 1);
1115 	zassert_equal(r, 1, "Could not find option");
1116 	zassert_equal(opt.len, strlen(proxy_scheme), "Wrong option len");
1117 	zassert_mem_equal(opt.value, proxy_scheme, strlen(proxy_scheme), "Wrong option content");
1118 
1119 	r = coap_find_options(&cpkt, COAP_OPTION_BLOCK2, &opt, 1);
1120 	zassert_equal(r, 1, "Could not find option");
1121 	zassert_equal(opt.len, 1, "Wrong option len");
1122 	zassert_equal(*opt.value, block_option, "Wrong option content");
1123 
1124 	zassert_equal(cpkt.hdr_len, 9, "Wrong header len");
1125 	zassert_equal(cpkt.opt_len, 14, "Wrong options size");
1126 	zassert_equal(cpkt.delta, 39, "Wrong delta");
1127 
1128 	zassert_equal(cpkt.offset, 23, "Wrong data size");
1129 
1130 	zassert_mem_equal(result, cpkt.data, cpkt.offset,
1131 			  "Built packet doesn't match reference packet");
1132 }
1133 
1134 #define ASSERT_OPTIONS(cpkt, expected_opt_len, expected_data, expected_data_len)                   \
1135 	do {                                                                                       \
1136 		static const uint8_t expected_hdr_len = 9;                                         \
1137 		zassert_equal(expected_hdr_len, cpkt.hdr_len, "Wrong header length");              \
1138 		zassert_equal(expected_opt_len, cpkt.opt_len, "Wrong option length");              \
1139 		zassert_equal(expected_hdr_len + expected_opt_len, cpkt.offset, "Wrong offset");   \
1140 		zassert_equal(expected_data_len, cpkt.offset, "Wrong offset");                     \
1141 		zassert_mem_equal(expected_data, cpkt.data, expected_data_len, "Wrong data");      \
1142 	} while (0)
1143 
ZTEST(coap,test_build_options_out_of_order_1)1144 ZTEST(coap, test_build_options_out_of_order_1)
1145 {
1146 	struct coap_packet cpkt;
1147 
1148 	static const char token[] = "token";
1149 
1150 	uint8_t *data = data_buf[0];
1151 
1152 	memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0]));
1153 
1154 	int r;
1155 
1156 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1157 			     strlen(token), token, COAP_METHOD_POST, 0x1234);
1158 	zassert_equal(r, 0, "Could not initialize packet");
1159 
1160 	r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE2,
1161 				   coap_block_size_to_bytes(COAP_BLOCK_128));
1162 	zassert_equal(r, 0, "Could not append option");
1163 	static const uint8_t expected_0[] = {0x45, 0x02, 0x12, 0x34, 't',  'o',
1164 					     'k',  'e',	 'n',  0xd1, 0x0f, 0x80};
1165 	ASSERT_OPTIONS(cpkt, 3, expected_0, 12);
1166 
1167 	const char *uri_path = "path";
1168 
1169 	r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path));
1170 	zassert_equal(r, 0, "Could not append option");
1171 
1172 	static const uint8_t expected_1[] = {
1173 		0x45, 0x02, 0x12, 0x34, 't', 'o',  'k',	 'e',  'n',
1174 		0xb4, 'p',  'a',  't',	'h', 0xd1, 0x04, 0x80,
1175 	};
1176 
1177 	ASSERT_OPTIONS(cpkt, 8, expected_1, 17);
1178 
1179 	r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_JSON);
1180 	zassert_equal(r, 0, "Could not append option");
1181 
1182 	static const uint8_t expected_2[] = {
1183 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0xb4,
1184 		'p',  'a',  't',  'h',	0x11, 0x32, 0xd1, 0x03, 0x80,
1185 	};
1186 
1187 	ASSERT_OPTIONS(cpkt, 10, expected_2, 19);
1188 
1189 	const char *uri_host = "hostname";
1190 
1191 	r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_HOST, uri_host, strlen(uri_host));
1192 	zassert_equal(r, 0, "Could not append option");
1193 
1194 	static const uint8_t expected_3[] = {
1195 		0x45, 0x02, 0x12, 0x34, 't',  'o', 'k', 'e', 'n', 0x38, 'h',  'o',  's',  't',
1196 		'n',  'a',  'm',  'e',	0x84, 'p', 'a', 't', 'h', 0x11, 0x32, 0xd1, 0x03, 0x80,
1197 	};
1198 
1199 	ASSERT_OPTIONS(cpkt, 19, expected_3, 28);
1200 
1201 	r = coap_append_option_int(&cpkt, COAP_OPTION_URI_PORT, 5638);
1202 	zassert_equal(r, 0, "Could not append option");
1203 
1204 	static const uint8_t expected_4[] = {
1205 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',
1206 		'o',  's',  't',  'n',	'a',  'm',  'e',  'B',	0x16, 0x06, 'D',
1207 		'p',  'a',  't',  'h',	0x11, 0x32, 0xd1, 0x03, 0x80,
1208 	};
1209 
1210 	ASSERT_OPTIONS(cpkt, 22, expected_4, 31);
1211 
1212 	const char *uri_query0 = "query0";
1213 
1214 	r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_QUERY, uri_query0, strlen(uri_query0));
1215 	zassert_equal(r, 0, "Could not append option");
1216 
1217 	const char *uri_query1 = "query1";
1218 
1219 	r = coap_packet_append_option(&cpkt, COAP_OPTION_URI_QUERY, uri_query1, strlen(uri_query1));
1220 	zassert_equal(r, 0, "Could not append option");
1221 
1222 	static const uint8_t expected_5[] = {
1223 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',  'o',
1224 		's',  't',  'n',  'a',	'm',  'e',  'B',  0x16, 0x06, 'D',  'p',  'a',
1225 		't',  'h',  0x11, 0x32, 0x36, 'q',  'u',  'e',	'r',  'y',  0x30, 0x06,
1226 		'q',  'u',  'e',  'r',	'y',  0x31, 0xd1, 0x00, 0x80,
1227 	};
1228 
1229 	ASSERT_OPTIONS(cpkt, 36, expected_5, 45);
1230 
1231 	r = coap_append_option_int(&cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_CBOR);
1232 	zassert_equal(r, 0, "Could not append option");
1233 
1234 	static const uint8_t expected_6[] = {
1235 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',  'o',
1236 		's',  't',  'n',  'a',	'm',  'e',  'B',  0x16, 0x06, 'D',  'p',  'a',
1237 		't',  'h',  0x11, 0x32, 0x36, 'q',  'u',  'e',	'r',  'y',  0x30, 0x06,
1238 		'q',  'u',  'e',  'r',	'y',  0x31, 0x21, 0x3c, 0xb1, 0x80,
1239 	};
1240 
1241 	ASSERT_OPTIONS(cpkt, 37, expected_6, 46);
1242 
1243 	r = coap_append_option_int(&cpkt, COAP_OPTION_OBSERVE, 0);
1244 	zassert_equal(r, 0, "Could not append option");
1245 
1246 	static const uint8_t expected_7[] = {
1247 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',  'o',
1248 		's',  't',  'n',  'a',	'm',  'e',  0x30, 0x12, 0x16, 0x06, 'D',  'p',
1249 		'a',  't',  'h',  0x11, 0x32, 0x36, 'q',  'u',	'e',  'r',  'y',  0x30,
1250 		0x06, 'q',  'u',  'e',	'r',  'y',  0x31, 0x21, 0x3c, 0xb1, 0x80,
1251 	};
1252 
1253 	ASSERT_OPTIONS(cpkt, 38, expected_7, 47);
1254 
1255 	r = coap_append_option_int(&cpkt, COAP_OPTION_MAX_AGE, 3);
1256 	zassert_equal(r, 0, "Could not append option");
1257 
1258 	static const uint8_t expected_8[] = {
1259 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h', 'o',  's',
1260 		't',  'n',  'a',  'm',	'e',  0x30, 0x12, 0x16, 0x06, 'D',  'p', 'a',  't',
1261 		'h',  0x11, 0x32, 0x21, 0x03, 0x16, 'q',  'u',	'e',  'r',  'y', 0x30, 0x06,
1262 		'q',  'u',  'e',  'r',	'y',  0x31, 0x21, 0x3c, 0xb1, 0x80,
1263 	};
1264 
1265 	ASSERT_OPTIONS(cpkt, 40, expected_8, 49);
1266 
1267 	r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE1, 64);
1268 	zassert_equal(r, 0, "Could not append option");
1269 
1270 	static const uint8_t expected_9[] = {
1271 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',  'o',	's',
1272 		't',  'n',  'a',  'm',	'e',  0x30, 0x12, 0x16, 0x06, 'D',  'p',  'a',	't',
1273 		'h',  0x11, 0x32, 0x21, 0x03, 0x16, 'q',  'u',	'e',  'r',  'y',  0x30, 0x06,
1274 		'q',  'u',  'e',  'r',	'y',  0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40,
1275 	};
1276 
1277 	ASSERT_OPTIONS(cpkt, 43, expected_9, 52);
1278 
1279 	zassert_equal(cpkt.hdr_len, 9, "Wrong header len");
1280 	zassert_equal(cpkt.opt_len, 43, "Wrong options size");
1281 	zassert_equal(cpkt.delta, 60, "Wrong delta");
1282 	zassert_equal(cpkt.offset, 52, "Wrong data size");
1283 }
1284 
1285 #define ASSERT_OPTIONS_AND_PAYLOAD(cpkt, expected_opt_len, expected_data, expected_offset,         \
1286 				   expected_delta)                                                 \
1287 	do {                                                                                       \
1288 		size_t expected_data_l = ARRAY_SIZE(expected_data);                                \
1289 		zassert_equal(expected_offset, expected_data_l);                                   \
1290 		static const uint8_t expected_hdr_len = 9;                                         \
1291 		zassert_equal(expected_hdr_len, cpkt.hdr_len, "Wrong header length");              \
1292 		zassert_equal(expected_opt_len, cpkt.opt_len, "Wrong option length");              \
1293 		zassert_equal(expected_offset, cpkt.offset, "Wrong offset");                       \
1294 		zassert_mem_equal(expected_data, cpkt.data, expected_offset, "Wrong data");        \
1295 		zassert_equal(expected_delta, cpkt.delta, "Wrong delta");                          \
1296 	} while (0)
1297 
init_basic_test_msg(struct coap_packet * cpkt,uint8_t * data)1298 static void init_basic_test_msg(struct coap_packet *cpkt, uint8_t *data)
1299 {
1300 	static const char token[] = "token";
1301 	const char *uri_path = "path";
1302 	const char *uri_host = "hostname";
1303 	const char *uri_query0 = "query0";
1304 	const char *uri_query1 = "query1";
1305 
1306 	memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0]));
1307 
1308 	int r;
1309 
1310 	r = coap_packet_init(cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1311 			     strlen(token), token, COAP_METHOD_POST, 0x1234);
1312 	zassert_equal(r, 0, "Could not initialize packet");
1313 
1314 	r = coap_append_option_int(cpkt, COAP_OPTION_SIZE2,
1315 				   coap_block_size_to_bytes(COAP_BLOCK_128));
1316 	zassert_equal(r, 0, "Could not append option");
1317 
1318 	r = coap_packet_append_option(cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path));
1319 	zassert_equal(r, 0, "Could not append option");
1320 
1321 	r = coap_append_option_int(cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_JSON);
1322 	zassert_equal(r, 0, "Could not append option");
1323 
1324 	r = coap_packet_append_option(cpkt, COAP_OPTION_URI_HOST, uri_host, strlen(uri_host));
1325 	zassert_equal(r, 0, "Could not append option");
1326 
1327 	r = coap_append_option_int(cpkt, COAP_OPTION_URI_PORT, 5638);
1328 	zassert_equal(r, 0, "Could not append option");
1329 
1330 	r = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY, uri_query0, strlen(uri_query0));
1331 	zassert_equal(r, 0, "Could not append option");
1332 
1333 	r = coap_packet_append_option(cpkt, COAP_OPTION_URI_QUERY, uri_query1, strlen(uri_query1));
1334 	zassert_equal(r, 0, "Could not append option");
1335 
1336 	r = coap_append_option_int(cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_CBOR);
1337 	zassert_equal(r, 0, "Could not append option");
1338 
1339 	r = coap_append_option_int(cpkt, COAP_OPTION_OBSERVE, 0);
1340 	zassert_equal(r, 0, "Could not append option");
1341 
1342 	r = coap_append_option_int(cpkt, COAP_OPTION_MAX_AGE, 3);
1343 	zassert_equal(r, 0, "Could not append option");
1344 
1345 	r = coap_append_option_int(cpkt, COAP_OPTION_SIZE1, 64);
1346 	zassert_equal(r, 0, "Could not append option");
1347 
1348 	static const uint8_t expected_9[] = {
1349 		0x45, 0x02, 0x12, 0x34, 't',  'o',  'k',  'e',	'n',  0x38, 'h',  'o',	's',
1350 		't',  'n',  'a',  'm',	'e',  0x30, 0x12, 0x16, 0x06, 'D',  'p',  'a',	't',
1351 		'h',  0x11, 0x32, 0x21, 0x03, 0x16, 'q',  'u',	'e',  'r',  'y',  0x30, 0x06,
1352 		'q',  'u',  'e',  'r',	'y',  0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40,
1353 	};
1354 
1355 	ASSERT_OPTIONS((*cpkt), 43, expected_9, 52);
1356 
1357 	r = coap_packet_append_payload_marker(cpkt);
1358 	zassert_equal(r, 0, "Could not append payload marker");
1359 
1360 	static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef};
1361 
1362 	r = coap_packet_append_payload(cpkt, test_payload, ARRAY_SIZE(test_payload));
1363 	zassert_equal(r, 0, "Could not append test payload");
1364 
1365 	zassert_equal((*cpkt).hdr_len, 9, "Wrong header len");
1366 	zassert_equal((*cpkt).opt_len, 43, "Wrong options size");
1367 	zassert_equal((*cpkt).delta, 60, "Wrong delta");
1368 	zassert_equal((*cpkt).offset, 57, "Wrong data size");
1369 }
1370 
ZTEST(coap,test_remove_first_coap_option)1371 ZTEST(coap, test_remove_first_coap_option)
1372 {
1373 	int r;
1374 	struct coap_packet cpkt;
1375 	uint8_t *data = data_buf[0];
1376 
1377 	init_basic_test_msg(&cpkt, data);
1378 
1379 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_HOST);
1380 	zassert_equal(r, 0, "Could not remove option");
1381 
1382 	static const uint8_t expected_0[] = {
1383 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x60, 0x12, 0x16,
1384 		0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71,
1385 		0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31,
1386 		0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef};
1387 
1388 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 34, expected_0, 48, 60);
1389 }
1390 
ZTEST(coap,test_remove_middle_coap_option)1391 ZTEST(coap, test_remove_middle_coap_option)
1392 {
1393 	int r;
1394 	struct coap_packet cpkt;
1395 	uint8_t *data = data_buf[0];
1396 
1397 	init_basic_test_msg(&cpkt, data);
1398 
1399 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_OBSERVE);
1400 	zassert_equal(r, 0, "Could not remove option");
1401 
1402 	static const uint8_t expected_0[] = {
1403 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74,
1404 		0x6e, 0x61, 0x6d, 0x65, 0x42, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32,
1405 		0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72,
1406 		0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef};
1407 
1408 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 42, expected_0, 56, 60);
1409 }
1410 
ZTEST(coap,test_remove_last_coap_option)1411 ZTEST(coap, test_remove_last_coap_option)
1412 {
1413 	int r;
1414 	struct coap_packet cpkt;
1415 	uint8_t *data = data_buf[0];
1416 
1417 	init_basic_test_msg(&cpkt, data);
1418 
1419 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE1);
1420 	zassert_equal(r, 0, "Could not remove option");
1421 
1422 	static const uint8_t expected_0[] = {
1423 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73, 0x74,
1424 		0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74, 0x68, 0x11,
1425 		0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65,
1426 		0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xff, 0xde, 0xad, 0xbe, 0xef};
1427 
1428 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 40, expected_0, 54, 28);
1429 
1430 	r = coap_append_option_int(&cpkt, COAP_OPTION_SIZE1, 65);
1431 	zassert_equal(r, 0, "Could not add option at end");
1432 
1433 	static const uint8_t expected_1[] = {
1434 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f,
1435 		0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70,
1436 		0x61, 0x74, 0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72,
1437 		0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xb1,
1438 		0x80, 0xd1, 0x13, 0x41, 0xff, 0xde, 0xad, 0xbe, 0xef};
1439 
1440 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 43, expected_1, 57, 60);
1441 }
1442 
ZTEST(coap,test_remove_single_coap_option)1443 ZTEST(coap, test_remove_single_coap_option)
1444 {
1445 	struct coap_packet cpkt;
1446 	uint8_t *data = data_buf[0];
1447 
1448 	static const char token[] = "token";
1449 	const char *uri_path = "path";
1450 
1451 	memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0]));
1452 
1453 	int r1;
1454 
1455 	r1 = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1456 			      strlen(token), token, COAP_METHOD_POST, 0x1234);
1457 	zassert_equal(r1, 0, "Could not initialize packet");
1458 
1459 	r1 = coap_packet_append_option(&cpkt, COAP_OPTION_URI_PATH, uri_path, strlen(uri_path));
1460 	zassert_equal(r1, 0, "Could not append option");
1461 
1462 	r1 = coap_packet_append_payload_marker(&cpkt);
1463 	zassert_equal(r1, 0, "Could not append payload marker");
1464 
1465 	static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef};
1466 
1467 	r1 = coap_packet_append_payload(&cpkt, test_payload, ARRAY_SIZE(test_payload));
1468 	zassert_equal(r1, 0, "Could not append test payload");
1469 
1470 	static const uint8_t expected_0[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b,
1471 					     0x65, 0x6e, 0xb4, 0x70, 0x61, 0x74, 0x68,
1472 					     0xff, 0xde, 0xad, 0xbe, 0xef};
1473 
1474 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 5, expected_0, 19, 11);
1475 
1476 	/* remove the one and only option */
1477 	r1 = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH);
1478 	zassert_equal(r1, 0, "Could not remove option");
1479 
1480 	static const uint8_t expected_1[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b,
1481 					     0x65, 0x6e, 0xff, 0xde, 0xad, 0xbe, 0xef};
1482 
1483 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_1, 14, 0);
1484 }
1485 
ZTEST(coap,test_remove_repeatable_coap_option)1486 ZTEST(coap, test_remove_repeatable_coap_option)
1487 {
1488 	int r;
1489 	struct coap_packet cpkt;
1490 	uint8_t *data = data_buf[0];
1491 
1492 	init_basic_test_msg(&cpkt, data);
1493 
1494 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY);
1495 	zassert_equal(r, 0, "Could not remove option");
1496 
1497 	static const uint8_t expected_0[] = {
1498 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73,
1499 		0x74, 0x6e, 0x61, 0x6d, 0x65, 0x30, 0x12, 0x16, 0x06, 0x44, 0x70, 0x61, 0x74,
1500 		0x68, 0x11, 0x32, 0x21, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x31, 0x21,
1501 		0x3c, 0xb1, 0x80, 0xd1, 0x13, 0x40, 0xff, 0xde, 0xad, 0xbe, 0xef};
1502 
1503 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 36, expected_0, 50, 60);
1504 }
1505 
ZTEST(coap,test_remove_all_coap_options)1506 ZTEST(coap, test_remove_all_coap_options)
1507 {
1508 	int r;
1509 	struct coap_packet cpkt;
1510 	uint8_t *data = data_buf[0];
1511 
1512 	init_basic_test_msg(&cpkt, data);
1513 
1514 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PORT);
1515 	zassert_equal(r, 0, "Could not remove option");
1516 
1517 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_OBSERVE);
1518 	zassert_equal(r, 0, "Could not remove option");
1519 
1520 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE1);
1521 	zassert_equal(r, 0, "Could not remove option");
1522 
1523 	static const uint8_t expected_0[] = {
1524 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x38, 0x68, 0x6f, 0x73,
1525 		0x74, 0x6e, 0x61, 0x6d, 0x65, 0x84, 0x70, 0x61, 0x74, 0x68, 0x11, 0x32, 0x21,
1526 		0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75, 0x65, 0x72,
1527 		0x79, 0x31, 0x21, 0x3c, 0xb1, 0x80, 0xff, 0xde, 0xad, 0xbe, 0xef};
1528 
1529 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 36, expected_0, 50, 28);
1530 
1531 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_HOST);
1532 	zassert_equal(r, 0, "Could not remove option");
1533 
1534 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_SIZE2);
1535 	zassert_equal(r, 0, "Could not remove option");
1536 
1537 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_CONTENT_FORMAT);
1538 	zassert_equal(r, 0, "Could not remove option");
1539 
1540 	static const uint8_t expected_1[] = {
1541 		0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0xb4, 0x70, 0x61, 0x74,
1542 		0x68, 0x31, 0x03, 0x16, 0x71, 0x75, 0x65, 0x72, 0x79, 0x30, 0x06, 0x71, 0x75,
1543 		0x65, 0x72, 0x79, 0x31, 0x21, 0x3c, 0xff, 0xde, 0xad, 0xbe, 0xef};
1544 
1545 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 23, expected_1, 37, 17);
1546 
1547 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_ACCEPT);
1548 	zassert_equal(r, 0, "Could not remove option");
1549 
1550 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH);
1551 	zassert_equal(r, 0, "Could not remove option");
1552 
1553 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY);
1554 	zassert_equal(r, 0, "Could not remove option");
1555 
1556 	static const uint8_t expected_2[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b, 0x65,
1557 					     0x6e, 0xd1, 0x01, 0x03, 0x16, 0x71, 0x75, 0x65,
1558 					     0x72, 0x79, 0x31, 0xff, 0xde, 0xad, 0xbe, 0xef};
1559 
1560 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 10, expected_2, 24, 15);
1561 
1562 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE);
1563 	zassert_equal(r, 0, "Could not remove option");
1564 
1565 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_QUERY);
1566 	zassert_equal(r, 0, "Could not remove option");
1567 
1568 	static const uint8_t expected_3[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f, 0x6b,
1569 					     0x65, 0x6e, 0xff, 0xde, 0xad, 0xbe, 0xef};
1570 
1571 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_3, 14, 0);
1572 
1573 	/* remove option that is not there anymore */
1574 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE);
1575 	zassert_equal(r, 0, "Could not remove option");
1576 
1577 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 0, expected_3, 14, 0);
1578 }
1579 
ZTEST(coap,test_remove_non_existent_coap_option)1580 ZTEST(coap, test_remove_non_existent_coap_option)
1581 {
1582 	int r;
1583 	struct coap_packet cpkt;
1584 	uint8_t *data = data_buf[0];
1585 	static const char token[] = "token";
1586 
1587 	memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0]));
1588 
1589 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1590 			     strlen(token), token, COAP_METHOD_POST, 0x1234);
1591 	zassert_equal(r, 0, "Could not initialize packet");
1592 
1593 	r = coap_append_option_int(&cpkt, COAP_OPTION_CONTENT_FORMAT, COAP_CONTENT_FORMAT_APP_CBOR);
1594 	zassert_equal(r, 0, "Could not append option");
1595 
1596 	r = coap_append_option_int(&cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_OCTET_STREAM);
1597 	zassert_equal(r, 0, "Could not append option");
1598 
1599 	r = coap_packet_append_payload_marker(&cpkt);
1600 	zassert_equal(r, 0, "Could not append payload marker");
1601 
1602 	static const uint8_t test_payload[] = {0xde, 0xad, 0xbe, 0xef};
1603 
1604 	r = coap_packet_append_payload(&cpkt, test_payload, ARRAY_SIZE(test_payload));
1605 
1606 	static const uint8_t expected_original_msg[] = {0x45, 0x02, 0x12, 0x34, 0x74, 0x6f,
1607 							0x6b, 0x65, 0x6e, 0xc1, 0x3c, 0x51,
1608 							0x2a, 0xff, 0xde, 0xad, 0xbe, 0xef};
1609 
1610 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17);
1611 
1612 	/* remove option that is not there but would be before existing options */
1613 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_URI_PATH);
1614 	zassert_equal(r, 0, "Could not remove option");
1615 
1616 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17);
1617 
1618 	/* remove option that is not there but would be between existing options */
1619 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_MAX_AGE);
1620 	zassert_equal(r, 0, "Could not remove option");
1621 
1622 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17);
1623 
1624 	/* remove option that is not there but would be after existing options */
1625 	r = coap_packet_remove_option(&cpkt, COAP_OPTION_LOCATION_QUERY);
1626 	zassert_equal(r, 0, "Could not remove option");
1627 
1628 	ASSERT_OPTIONS_AND_PAYLOAD(cpkt, 4, expected_original_msg, 18, 17);
1629 }
1630 
assert_coap_packet_set_path_query_options(const char * path,const char * const * expected,size_t expected_len,uint16_t code)1631 static void assert_coap_packet_set_path_query_options(const char *path,
1632 						      const char * const *expected,
1633 						      size_t expected_len, uint16_t code)
1634 {
1635 	struct coap_packet cpkt;
1636 	uint8_t *data = data_buf[0];
1637 	struct coap_option options[16] = {0};
1638 	int res;
1639 
1640 	memset(data_buf[0], 0, ARRAY_SIZE(data_buf[0]));
1641 	TC_PRINT("Assert path: %s\n", path);
1642 
1643 	res = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1, COAP_TYPE_CON,
1644 			       COAP_TOKEN_MAX_LEN, coap_next_token(),
1645 			       COAP_METHOD_GET, 0x1234);
1646 	zassert_equal(res, 0, "Could not initialize packet");
1647 
1648 	res = coap_packet_set_path(&cpkt, path);
1649 	zassert_equal(res, 0, "Could not set path/query, path: %s", path);
1650 
1651 	res = coap_find_options(&cpkt, code, options, ARRAY_SIZE(options));
1652 	if (res <= 0) {
1653 		/* fail if we expect options */
1654 		zassert_true(((expected == NULL) && (expected_len == 0U)),
1655 			     "Expected options but found none, path: %s", path);
1656 	}
1657 
1658 	for (unsigned int i = 0U; i < expected_len; ++i) {
1659 		/* validate expected options, the rest shall be 0 */
1660 		if (i < expected_len) {
1661 			zassert_true((options[i].len == strlen(expected[i])),
1662 				     "Expected and parsed option lengths don't match"
1663 				     ", path: %s",
1664 				     path);
1665 
1666 			zassert_mem_equal(options[i].value, expected[i], options[i].len,
1667 					  "Expected and parsed option values don't match"
1668 					  ", path: %s",
1669 					  path);
1670 		} else {
1671 			zassert_true((options[i].len == 0U),
1672 				     "Unexpected options shall be empty"
1673 				     ", path: %s",
1674 				     path);
1675 		}
1676 	}
1677 }
1678 
ZTEST(coap,test_coap_packet_set_path)1679 ZTEST(coap, test_coap_packet_set_path)
1680 {
1681 	assert_coap_packet_set_path_query_options(" ", NULL, 0U, COAP_OPTION_URI_PATH);
1682 	assert_coap_packet_set_path_query_options("", NULL, 0U, COAP_OPTION_URI_PATH);
1683 	assert_coap_packet_set_path_query_options("/", NULL, 0U, COAP_OPTION_URI_PATH);
1684 	assert_coap_packet_set_path_query_options("?", NULL, 0U, COAP_OPTION_URI_QUERY);
1685 
1686 	assert_coap_packet_set_path_query_options("?a",
1687 						  (const char *const[]){"a"}, 1U,
1688 						  COAP_OPTION_URI_QUERY);
1689 	assert_coap_packet_set_path_query_options("?a&b",
1690 						 (const char *const[]){"a", "b"}, 2U,
1691 						  COAP_OPTION_URI_QUERY);
1692 
1693 	assert_coap_packet_set_path_query_options("a",
1694 						  (const char *const[]){"a"}, 1U,
1695 						  COAP_OPTION_URI_PATH);
1696 	assert_coap_packet_set_path_query_options("a", NULL, 0, COAP_OPTION_URI_QUERY);
1697 	assert_coap_packet_set_path_query_options("a/",
1698 						  (const char *const[]){"a"}, 1U,
1699 						  COAP_OPTION_URI_PATH);
1700 
1701 	assert_coap_packet_set_path_query_options("a?b=t&a",
1702 						  (const char *const[]){"a"}, 1U,
1703 						  COAP_OPTION_URI_PATH);
1704 	assert_coap_packet_set_path_query_options("a?b=t&a",
1705 						  (const char *const[]){"b=t", "a"}, 2U,
1706 						  COAP_OPTION_URI_QUERY);
1707 	assert_coap_packet_set_path_query_options("a?b=t&aa",
1708 						  (const char *const[]){"b=t", "aa"},
1709 						  2U, COAP_OPTION_URI_QUERY);
1710 
1711 	assert_coap_packet_set_path_query_options("a?b&a",
1712 						  (const char *const[]){"a"}, 1U,
1713 						  COAP_OPTION_URI_PATH);
1714 	assert_coap_packet_set_path_query_options("a?b&a",
1715 						  (const char *const[]){"b", "a"}, 2U,
1716 						  COAP_OPTION_URI_QUERY);
1717 	assert_coap_packet_set_path_query_options("a?b&aa",
1718 						  (const char *const[]){"b", "aa"}, 2U,
1719 						  COAP_OPTION_URI_QUERY);
1720 
1721 	assert_coap_packet_set_path_query_options("a/b",
1722 						  (const char *const[]){"a", "b"}, 2U,
1723 						  COAP_OPTION_URI_PATH);
1724 	assert_coap_packet_set_path_query_options("a/b/",
1725 						  (const char *const[]){"a", "b"}, 2U,
1726 						  COAP_OPTION_URI_PATH);
1727 	assert_coap_packet_set_path_query_options("a/b?b&a",
1728 						  (const char *const[]){"b", "a"}, 2U,
1729 						  COAP_OPTION_URI_QUERY);
1730 	assert_coap_packet_set_path_query_options("a/b?b&aa",
1731 						  (const char *const[]){"b", "aa"}, 2U,
1732 						  COAP_OPTION_URI_QUERY);
1733 
1734 	assert_coap_packet_set_path_query_options("a/bb",
1735 						  (const char *const[]){"a", "bb"}, 2U,
1736 						  COAP_OPTION_URI_PATH);
1737 	assert_coap_packet_set_path_query_options("a/bb/",
1738 						  (const char *const[]){"a", "bb"}, 2U,
1739 						  COAP_OPTION_URI_PATH);
1740 }
1741 
ZTEST(coap,test_transmission_parameters)1742 ZTEST(coap, test_transmission_parameters)
1743 {
1744 	struct coap_packet cpkt;
1745 	struct coap_pending *pending;
1746 	struct coap_transmission_parameters params;
1747 	uint8_t *data = data_buf[0];
1748 	int r;
1749 	uint16_t id;
1750 
1751 	params = coap_get_transmission_parameters();
1752 	zassert_equal(params.ack_timeout, CONFIG_COAP_INIT_ACK_TIMEOUT_MS, "Wrong ACK timeout");
1753 	zassert_equal(params.ack_random_percent, CONFIG_COAP_ACK_RANDOM_PERCENT,
1754 		      "Wrong ACK random percent");
1755 	zassert_equal(params.coap_backoff_percent, CONFIG_COAP_BACKOFF_PERCENT,
1756 		      "Wrong backoff percent");
1757 	zassert_equal(params.max_retransmission, CONFIG_COAP_MAX_RETRANSMIT,
1758 		      "Wrong max retransmission value");
1759 
1760 	params.ack_timeout = 1000;
1761 	params.ack_random_percent = 110;
1762 	params.coap_backoff_percent = 150;
1763 	params.max_retransmission = 2;
1764 
1765 	coap_set_transmission_parameters(&params);
1766 
1767 	id = coap_next_id();
1768 
1769 	r = coap_packet_init(&cpkt, data, COAP_BUF_SIZE, COAP_VERSION_1,
1770 			     COAP_TYPE_CON, 0, coap_next_token(),
1771 			     COAP_METHOD_GET, id);
1772 	zassert_equal(r, 0, "Could not initialize packet");
1773 
1774 	pending = coap_pending_next_unused(pendings, NUM_PENDINGS);
1775 	zassert_not_null(pending, "No free pending");
1776 
1777 	params.ack_timeout = 3000;
1778 	params.ack_random_percent = 130;
1779 	params.coap_backoff_percent = 250;
1780 	params.max_retransmission = 3;
1781 
1782 	r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr,
1783 			      &params);
1784 	zassert_equal(r, 0, "Could not initialize packet");
1785 
1786 	zassert_equal(pending->params.ack_timeout, 3000, "Wrong ACK timeout");
1787 	zassert_equal(pending->params.ack_random_percent, 130, "Wrong ACK random percent");
1788 	zassert_equal(pending->params.coap_backoff_percent, 250, "Wrong backoff percent");
1789 	zassert_equal(pending->params.max_retransmission, 3, "Wrong max retransmission value");
1790 
1791 	r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr,
1792 			      NULL);
1793 	zassert_equal(r, 0, "Could not initialize packet");
1794 
1795 	zassert_equal(pending->params.ack_timeout, 1000, "Wrong ACK timeout");
1796 	zassert_equal(pending->params.ack_random_percent, 110, "Wrong ACK random percent");
1797 	zassert_equal(pending->params.coap_backoff_percent, 150, "Wrong backoff percent");
1798 	zassert_equal(pending->params.max_retransmission, 2, "Wrong max retransmission value");
1799 }
1800 
ZTEST(coap,test_notify_age)1801 ZTEST(coap, test_notify_age)
1802 {
1803 	uint8_t valid_request_pdu[] = {
1804 		0x45, 0x01, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x60, /* enable observe option */
1805 		0x51, 's',  0x01, '2',                                 /* path */
1806 	};
1807 
1808 	struct coap_packet req;
1809 	struct coap_option options[4] = {};
1810 	uint8_t *data = data_buf[0];
1811 	uint8_t opt_num = ARRAY_SIZE(options) - 1;
1812 	struct coap_resource *resource = &server_resources[1];
1813 	int r;
1814 	struct coap_observer *observer;
1815 	int last_age;
1816 
1817 	memcpy(data, valid_request_pdu, sizeof(valid_request_pdu));
1818 
1819 	r = coap_packet_parse(&req, data, sizeof(valid_request_pdu), options, opt_num);
1820 	zassert_equal(r, 0, "Could not initialize packet");
1821 
1822 	r = coap_handle_request(&req, server_resources, options, opt_num,
1823 				(struct sockaddr *)&dummy_addr, sizeof(dummy_addr));
1824 	zassert_equal(r, 0, "Could not handle packet");
1825 
1826 	/* Forward time a bit, as not to run this 8 million time */
1827 	resource->age = COAP_OBSERVE_MAX_AGE - 10;
1828 
1829 	last_age = resource->age;
1830 
1831 	for (int i = 0; i < 15; i++) {
1832 		r = coap_resource_notify(resource);
1833 		zassert_true(coap_age_is_newer(last_age, resource->age),
1834 			     "Resource age expected to be newer");
1835 		last_age = resource->age;
1836 	}
1837 
1838 	observer =
1839 		CONTAINER_OF(sys_slist_peek_head(&resource->observers), struct coap_observer, list);
1840 	coap_remove_observer(resource, observer);
1841 }
1842 
ZTEST(coap,test_age_is_newer)1843 ZTEST(coap, test_age_is_newer)
1844 {
1845 	for (int i = COAP_FIRST_AGE; i < COAP_MAX_AGE; ++i) {
1846 		zassert_true(coap_age_is_newer(i, i + 1),
1847 			     "Resource age expected to be marked as newer");
1848 	}
1849 
1850 	zassert_true(coap_age_is_newer(COAP_MAX_AGE, COAP_FIRST_AGE),
1851 		     "First age should be marked as newer");
1852 	zassert_true(coap_age_is_newer(COAP_FIRST_AGE, COAP_ROLLOVER_AGE),
1853 		     "Rollover age should be marked as newer");
1854 	zassert_true(coap_age_is_newer(COAP_ROLLOVER_AGE, COAP_MAX_AGE),
1855 		     "Max age should be marked as newer");
1856 }
1857 
1858 ZTEST_SUITE(coap, NULL, NULL, NULL, NULL, NULL);
1859