1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/net/dummy.h>
9 #include <zephyr/net/ethernet.h>
10 #include <zephyr/net/net_if.h>
11 #include <zephyr/net/net_mgmt.h>
12 
13 #include "../../../subsys/net/lib/dhcpv6/dhcpv6.c"
14 
15 static struct in6_addr test_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
16 					 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
17 static struct in6_addr test_prefix = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
18 					   0, 0, 0, 0, 0, 0, 0, 0 } } };
19 static uint8_t test_prefix_len = 64;
20 static uint8_t test_preference;
21 static struct net_dhcpv6_duid_storage test_serverid;
22 static struct net_mgmt_event_callback net_mgmt_cb;
23 
24 typedef void (*test_dhcpv6_pkt_fn_t)(struct net_if *iface,
25 				     struct net_pkt *pkt);
26 
27 typedef int (*test_dhcpv6_options_fn_t)(struct net_if *iface,
28 					struct net_pkt *pkt,
29 					enum dhcpv6_msg_type msg_type);
30 
31 struct test_dhcpv6_context {
32 	uint8_t mac[sizeof(struct net_eth_addr)];
33 	struct net_if *iface;
34 	test_dhcpv6_pkt_fn_t test_fn;
35 	struct k_sem tx_sem;
36 	struct k_sem exchange_complete_sem;
37 	bool reset_dhcpv6;
38 };
39 
40 struct test_dhcpv6_context test_ctx;
41 
test_iface_init(struct net_if * iface)42 static void test_iface_init(struct net_if *iface)
43 {
44 	struct test_dhcpv6_context *ctx = net_if_get_device(iface)->data;
45 
46 	/* Generate and assign MAC. */
47 	/* 00-00-5E-00-53-xx Documentation RFC 7042 */
48 	ctx->mac[0] = 0x00;
49 	ctx->mac[1] = 0x00;
50 	ctx->mac[2] = 0x5E;
51 	ctx->mac[3] = 0x00;
52 	ctx->mac[4] = 0x53;
53 	ctx->mac[5] = 0x00;
54 
55 	net_if_set_link_addr(iface, ctx->mac, sizeof(ctx->mac), NET_LINK_ETHERNET);
56 }
57 
test_send(const struct device * dev,struct net_pkt * pkt)58 static int test_send(const struct device *dev, struct net_pkt *pkt)
59 {
60 	struct test_dhcpv6_context *ctx = dev->data;
61 
62 	if (ctx->test_fn != NULL) {
63 		ctx->test_fn(net_pkt_iface(pkt), pkt);
64 	}
65 
66 	k_sem_give(&ctx->tx_sem);
67 
68 	return 0;
69 }
70 
71 static struct dummy_api test_if_api = {
72 	.iface_api.init = test_iface_init,
73 	.send = test_send,
74 };
75 
76 NET_DEVICE_INIT(test_dhcpv6, "test_dhcpv6", NULL, NULL, &test_ctx, NULL,
77 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &test_if_api,
78 		DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), NET_IPV6_MTU);
79 
set_dhcpv6_test_fn(test_dhcpv6_pkt_fn_t test_fn)80 static void set_dhcpv6_test_fn(test_dhcpv6_pkt_fn_t test_fn)
81 {
82 	test_ctx.test_fn = test_fn;
83 }
84 
set_test_addr_on_iface(struct net_if * iface)85 static void set_test_addr_on_iface(struct net_if *iface)
86 {
87 	memcpy(&test_ctx.iface->config.dhcpv6.addr, &test_addr,
88 	       sizeof(test_ctx.iface->config.dhcpv6.addr));
89 	memcpy(&test_ctx.iface->config.dhcpv6.prefix, &test_prefix,
90 	       sizeof(test_ctx.iface->config.dhcpv6.prefix));
91 	test_ctx.iface->config.dhcpv6.prefix_len = test_prefix_len;
92 }
93 
clear_test_addr_on_iface(struct net_if * iface)94 static void clear_test_addr_on_iface(struct net_if *iface)
95 {
96 	memset(&test_ctx.iface->config.dhcpv6.addr, 0,
97 	       sizeof(test_ctx.iface->config.dhcpv6.addr));
98 	memset(&test_ctx.iface->config.dhcpv6.prefix, 0,
99 	       sizeof(test_ctx.iface->config.dhcpv6.prefix));
100 	test_ctx.iface->config.dhcpv6.prefix_len = 0;
101 }
102 
generate_fake_server_duid(void)103 static void generate_fake_server_duid(void)
104 {
105 	struct net_dhcpv6_duid_storage *serverid = &test_serverid;
106 	struct dhcpv6_duid_ll *duid_ll =
107 				(struct dhcpv6_duid_ll *)&serverid->duid.buf;
108 	uint8_t fake_mac[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
109 
110 	memset(serverid, 0, sizeof(*serverid));
111 
112 	UNALIGNED_PUT(htons(DHCPV6_DUID_TYPE_LL), &serverid->duid.type);
113 	UNALIGNED_PUT(htons(DHCPV6_HARDWARE_ETHERNET_TYPE), &duid_ll->hw_type);
114 	memcpy(duid_ll->ll_addr, fake_mac, sizeof(fake_mac));
115 
116 	serverid->length = DHCPV6_DUID_LL_HEADER_SIZE + sizeof(fake_mac);
117 }
118 
set_fake_server_duid(struct net_if * iface)119 static void set_fake_server_duid(struct net_if *iface)
120 {
121 	memcpy(&iface->config.dhcpv6.serverid, &test_serverid,
122 	       sizeof(test_serverid));
123 }
124 
125 #define TEST_MSG_SIZE 256
126 
test_dhcpv6_create_message(struct net_if * iface,enum dhcpv6_msg_type msg_type,test_dhcpv6_options_fn_t set_options_fn)127 static struct net_pkt *test_dhcpv6_create_message(
128 		struct net_if *iface, enum dhcpv6_msg_type msg_type,
129 		test_dhcpv6_options_fn_t set_options_fn)
130 {
131 	struct in6_addr *local_addr;
132 	struct in6_addr peer_addr;
133 	struct net_pkt *pkt;
134 
135 	local_addr = net_if_ipv6_get_ll(iface, NET_ADDR_ANY_STATE);
136 	if (local_addr == NULL) {
137 		return NULL;
138 	}
139 
140 	/* Create a peer address from my address but invert the last byte
141 	 * so that the address is not the same. This is needed as we drop
142 	 * the packet if source address is our own address.
143 	 */
144 	memcpy(&peer_addr, local_addr, sizeof(peer_addr));
145 	peer_addr.s6_addr[15] = ~peer_addr.s6_addr[15];
146 
147 	pkt = net_pkt_alloc_with_buffer(iface, TEST_MSG_SIZE, AF_INET6,
148 					IPPROTO_UDP, K_FOREVER);
149 	if (pkt == NULL) {
150 		return NULL;
151 	}
152 
153 	if (net_ipv6_create(pkt, &peer_addr, local_addr) < 0 ||
154 	    net_udp_create(pkt, htons(DHCPV6_SERVER_PORT),
155 			   htons(DHCPV6_CLIENT_PORT)) < 0) {
156 		goto fail;
157 	}
158 
159 	dhcpv6_generate_tid(iface);
160 
161 	if (dhcpv6_add_header(pkt, msg_type, iface->config.dhcpv6.tid) < 0) {
162 		goto fail;
163 	}
164 
165 	if (set_options_fn(iface, pkt, msg_type) < 0) {
166 		goto fail;
167 	}
168 
169 	net_pkt_cursor_init(pkt);
170 	net_ipv6_finalize(pkt, IPPROTO_UDP);
171 	net_pkt_cursor_init(pkt);
172 
173 	return pkt;
174 
175 fail:
176 	net_pkt_unref(pkt);
177 
178 	return NULL;
179 }
180 
evt_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)181 static void evt_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
182 			struct net_if *iface)
183 {
184 	ARG_UNUSED(cb);
185 
186 	if (mgmt_event == NET_EVENT_IF_UP) {
187 		struct in6_addr lladdr;
188 
189 		net_ipv6_addr_create_iid(&lladdr, net_if_get_link_addr(test_ctx.iface));
190 		(void)net_if_ipv6_addr_add(test_ctx.iface, &lladdr, NET_ADDR_AUTOCONF, 0);
191 	}
192 }
193 
dhcpv6_tests_setup(void)194 static void *dhcpv6_tests_setup(void)
195 {
196 	struct in6_addr lladdr;
197 
198 	test_ctx.iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
199 
200 	net_ipv6_addr_create_iid(&lladdr, net_if_get_link_addr(test_ctx.iface));
201 	(void)net_if_ipv6_addr_add(test_ctx.iface, &lladdr, NET_ADDR_AUTOCONF, 0);
202 
203 	k_sem_init(&test_ctx.tx_sem, 0, 1);
204 	k_sem_init(&test_ctx.exchange_complete_sem, 0, 1);
205 
206 	generate_fake_server_duid();
207 
208 	net_mgmt_init_event_callback(&net_mgmt_cb, evt_handler, NET_EVENT_IF_UP);
209 	net_mgmt_add_event_callback(&net_mgmt_cb);
210 
211 	return NULL;
212 }
213 
dhcpv6_tests_before(void * fixture)214 static void dhcpv6_tests_before(void *fixture)
215 {
216 	ARG_UNUSED(fixture);
217 
218 	test_ctx.reset_dhcpv6 = false;
219 
220 	set_dhcpv6_test_fn(NULL);
221 	k_sem_reset(&test_ctx.tx_sem);
222 	k_sem_reset(&test_ctx.exchange_complete_sem);
223 
224 	memset(&test_ctx.iface->config.dhcpv6, 0,
225 	       sizeof(test_ctx.iface->config.dhcpv6));
226 
227 	dhcpv6_generate_client_duid(test_ctx.iface);
228 	test_ctx.iface->config.dhcpv6.state = NET_DHCPV6_DISABLED;
229 	test_ctx.iface->config.dhcpv6.addr_iaid = 10;
230 	test_ctx.iface->config.dhcpv6.prefix_iaid = 20;
231 	test_ctx.iface->config.dhcpv6.exchange_start = k_uptime_get();
232 	test_ctx.iface->config.dhcpv6.params = (struct net_dhcpv6_params){
233 		.request_addr = true,
234 		.request_prefix = true,
235 	};
236 
237 	test_preference = 100;
238 
239 	net_if_ipv6_addr_rm(test_ctx.iface, &test_addr);
240 	net_if_ipv6_prefix_rm(test_ctx.iface, &test_prefix, test_prefix_len);
241 }
242 
dhcpv6_tests_after(void * fixture)243 static void dhcpv6_tests_after(void *fixture)
244 {
245 	ARG_UNUSED(fixture);
246 
247 	set_dhcpv6_test_fn(NULL);
248 
249 	if (test_ctx.reset_dhcpv6) {
250 		net_dhcpv6_stop(test_ctx.iface);
251 	}
252 }
253 
verify_dhcpv6_header(struct net_if * iface,struct net_pkt * pkt,enum dhcpv6_msg_type msg_type)254 static void verify_dhcpv6_header(struct net_if *iface, struct net_pkt *pkt,
255 				 enum dhcpv6_msg_type msg_type)
256 {
257 	uint8_t tid[DHCPV6_TID_SIZE];
258 	uint8_t type;
259 	int ret;
260 
261 	(void)net_pkt_skip(pkt, NET_IPV6UDPH_LEN);
262 
263 	ret = net_pkt_read_u8(pkt, &type);
264 	zassert_ok(ret, "DHCPv6 header incomplete (type)");
265 	zassert_equal(type, msg_type, "Invalid message type");
266 
267 	ret = net_pkt_read(pkt, tid, sizeof(tid));
268 	zassert_ok(ret, "DHCPv6 header incomplete (tid)");
269 	zassert_mem_equal(tid, iface->config.dhcpv6.tid, sizeof(tid),
270 			  "Transaction ID doesn't match ID of the current exchange");
271 }
272 
verify_dhcpv6_clientid(struct net_if * iface,struct net_pkt * pkt)273 static void verify_dhcpv6_clientid(struct net_if *iface, struct net_pkt *pkt)
274 {
275 	struct net_dhcpv6_duid_storage duid;
276 	int ret;
277 
278 	ret = dhcpv6_find_clientid(pkt, &duid);
279 	zassert_ok(ret, "Missing Client ID option");
280 	zassert_equal(duid.length, iface->config.dhcpv6.clientid.length,
281 		      "Invalid Client ID length");
282 	zassert_mem_equal(&duid.duid, &iface->config.dhcpv6.clientid.duid,
283 			  duid.length, "Invalid Client ID value");
284 }
285 
verify_dhcpv6_serverid(struct net_if * iface,struct net_pkt * pkt)286 static void verify_dhcpv6_serverid(struct net_if *iface, struct net_pkt *pkt)
287 {
288 	struct net_dhcpv6_duid_storage duid;
289 	int ret;
290 
291 	ret = dhcpv6_find_serverid(pkt, &duid);
292 	zassert_ok(ret, "Missing Server ID option");
293 	zassert_equal(duid.length, iface->config.dhcpv6.serverid.length,
294 		      "Invalid Server ID length");
295 	zassert_mem_equal(&duid.duid, &iface->config.dhcpv6.serverid.duid,
296 			  duid.length, "Invalid Server ID value");
297 }
298 
verify_dhcpv6_no_serverid(struct net_if * iface,struct net_pkt * pkt)299 static void verify_dhcpv6_no_serverid(struct net_if *iface, struct net_pkt *pkt)
300 {
301 	struct net_dhcpv6_duid_storage duid;
302 	int ret;
303 
304 	ret = dhcpv6_find_serverid(pkt, &duid);
305 	zassert_not_equal(ret, 0, "Server ID option should not be present");
306 }
307 
verify_dhcpv6_elapsed_time(struct net_if * iface,struct net_pkt * pkt,uint16_t min_accepted,uint16_t max_accepted)308 static void verify_dhcpv6_elapsed_time(struct net_if *iface, struct net_pkt *pkt,
309 				       uint16_t min_accepted, uint16_t max_accepted)
310 {
311 	struct net_pkt_cursor backup;
312 	uint16_t elapsed_time;
313 	uint16_t length;
314 	int ret;
315 
316 	net_pkt_cursor_backup(pkt, &backup);
317 
318 	ret = dhcpv6_find_option(pkt, DHCPV6_OPTION_CODE_ELAPSED_TIME, &length);
319 	zassert_ok(ret, "Missing Elapsed time option");
320 	zassert_equal(length, sizeof(uint16_t), "Invalid Elapsed time length");
321 
322 	ret = net_pkt_read_be16(pkt, &elapsed_time);
323 	zassert_ok(ret, "Failed to read Elapsed time option");
324 	zassert_between_inclusive(elapsed_time, min_accepted, max_accepted,
325 				  "Elapsed time not in accepted range");
326 
327 	net_pkt_cursor_restore(pkt, &backup);
328 }
329 
verify_dhcpv6_ia_na(struct net_if * iface,struct net_pkt * pkt,struct in6_addr * addr)330 static void verify_dhcpv6_ia_na(struct net_if *iface, struct net_pkt *pkt,
331 				struct in6_addr *addr)
332 {
333 	struct dhcpv6_ia_na ia_na;
334 	int ret;
335 
336 	ret = dhcpv6_find_ia_na(pkt, &ia_na);
337 	zassert_ok(ret, "Missing IA NA option");
338 	zassert_equal(ia_na.iaid, iface->config.dhcpv6.addr_iaid,
339 		      "Incorrect IA NA IAID");
340 	zassert_equal(ia_na.t1, 0, "T1 should be set to 0 by the client");
341 	zassert_equal(ia_na.t2, 0, "T2 should be set to 0 by the client");
342 
343 	if (addr == NULL) {
344 		zassert_equal(ia_na.iaaddr.status, DHCPV6_STATUS_NO_ADDR_AVAIL,
345 			      "Adddress should not be present");
346 		return;
347 	}
348 
349 	zassert_equal(ia_na.iaaddr.status, DHCPV6_STATUS_SUCCESS, "Invalid status");
350 	zassert_equal(ia_na.iaaddr.preferred_lifetime, 0,
351 		      "Preferred lifetime should be set to 0 by the client");
352 	zassert_equal(ia_na.iaaddr.valid_lifetime, 0,
353 		      "Valid lifetime should be set to 0 by the client");
354 	zassert_mem_equal(&ia_na.iaaddr.addr, addr, sizeof(ia_na.iaaddr.addr),
355 			  "Incorrect address");
356 }
357 
verify_dhcpv6_ia_pd(struct net_if * iface,struct net_pkt * pkt,struct in6_addr * prefix,uint8_t prefix_len)358 static void verify_dhcpv6_ia_pd(struct net_if *iface, struct net_pkt *pkt,
359 				struct in6_addr *prefix, uint8_t prefix_len)
360 {
361 	struct dhcpv6_ia_pd ia_pd;
362 	int ret;
363 
364 	ret = dhcpv6_find_ia_pd(pkt, &ia_pd);
365 	zassert_ok(ret, "Missing IA PD option");
366 		zassert_equal(ia_pd.iaid, iface->config.dhcpv6.prefix_iaid,
367 		      "Incorrect IA PD IAID");
368 	zassert_equal(ia_pd.t1, 0, "T1 should be set to 0 by the client");
369 	zassert_equal(ia_pd.t2, 0, "T2 should be set to 0 by the client");
370 
371 	if (prefix == NULL) {
372 		zassert_equal(ia_pd.iaprefix.status, DHCPV6_STATUS_NO_PREFIX_AVAIL,
373 			      "Prefix should not be present");
374 		return;
375 	}
376 
377 	zassert_equal(ia_pd.iaprefix.status, DHCPV6_STATUS_SUCCESS, "Invalid status");
378 	zassert_equal(ia_pd.iaprefix.preferred_lifetime, 0,
379 		      "Preferred lifetime should be set to 0 by the client");
380 	zassert_equal(ia_pd.iaprefix.valid_lifetime, 0,
381 		      "Valid lifetime should be set to 0 by the client");
382 	zassert_equal(ia_pd.iaprefix.prefix_len, prefix_len,
383 		      "Incorrect prefix length");
384 	zassert_mem_equal(&ia_pd.iaprefix.prefix, prefix,
385 			  sizeof(ia_pd.iaprefix.prefix), "Incorrect prefix");
386 }
387 
verify_dhcpv6_no_reconfigure_accept(struct net_if * iface,struct net_pkt * pkt)388 static void verify_dhcpv6_no_reconfigure_accept(struct net_if *iface,
389 						struct net_pkt *pkt)
390 {
391 	struct net_pkt_cursor backup;
392 	uint16_t length;
393 	int ret;
394 
395 	net_pkt_cursor_backup(pkt, &backup);
396 
397 	ret = dhcpv6_find_option(pkt, DHCPV6_OPTION_CODE_RECONF_ACCEPT, &length);
398 	zassert_not_equal(ret, 0, "Reconfigure accept option should not be present");
399 
400 	net_pkt_cursor_restore(pkt, &backup);
401 }
402 
verify_dhcpv6_oro_sol_max_rt(struct net_if * iface,struct net_pkt * pkt)403 static void verify_dhcpv6_oro_sol_max_rt(struct net_if *iface,
404 					 struct net_pkt *pkt)
405 {
406 	struct net_pkt_cursor backup;
407 	uint16_t length;
408 	uint16_t oro;
409 	int ret;
410 
411 	net_pkt_cursor_backup(pkt, &backup);
412 
413 	ret = dhcpv6_find_option(pkt, DHCPV6_OPTION_CODE_ORO, &length);
414 	zassert_ok(ret, 0, "ORO option not found");
415 	zassert_true(length >= sizeof(uint16_t) && length % sizeof(uint16_t) == 0,
416 		     "Invalid ORO length");
417 
418 	while (length >= sizeof(uint16_t)) {
419 		ret = net_pkt_read_be16(pkt, &oro);
420 		zassert_ok(ret, 0, "ORO read error");
421 		length -= sizeof(uint16_t);
422 
423 		if (oro == DHCPV6_OPTION_CODE_SOL_MAX_RT) {
424 			break;
425 		}
426 	}
427 
428 	zassert_equal(oro, DHCPV6_OPTION_CODE_SOL_MAX_RT,
429 		      "No SOL_MAX_RT option request present");
430 
431 	net_pkt_cursor_restore(pkt, &backup);
432 }
433 
verify_solicit_message(struct net_if * iface,struct net_pkt * pkt)434 static void verify_solicit_message(struct net_if *iface, struct net_pkt *pkt)
435 {
436 	/* Verify header */
437 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_SOLICIT);
438 
439 	/* Verify options */
440 	verify_dhcpv6_clientid(iface, pkt);
441 	verify_dhcpv6_no_serverid(iface, pkt);
442 	verify_dhcpv6_elapsed_time(iface, pkt, 0, 10);
443 	verify_dhcpv6_ia_na(iface, pkt, NULL);
444 	verify_dhcpv6_ia_pd(iface, pkt, NULL, 0);
445 	verify_dhcpv6_no_reconfigure_accept(iface, pkt);
446 	verify_dhcpv6_oro_sol_max_rt(iface, pkt);
447 }
448 
449 /* Verify that outgoing DHCPv6 Solicit has a valid format and includes all
450  * mandatory options.
451  */
ZTEST(dhcpv6_tests,test_solicit_message_format)452 ZTEST(dhcpv6_tests, test_solicit_message_format)
453 {
454 	int ret;
455 
456 	set_dhcpv6_test_fn(verify_solicit_message);
457 
458 	ret = dhcpv6_send_solicit(test_ctx.iface);
459 	zassert_ok(ret, "dhcpv6_send_solicit failed");
460 
461 	ret = k_sem_take(&test_ctx.tx_sem, K_SECONDS(1));
462 	zassert_ok(ret, "Packet not transmitted");
463 }
464 
verify_request_message(struct net_if * iface,struct net_pkt * pkt)465 static void verify_request_message(struct net_if *iface, struct net_pkt *pkt)
466 {
467 	/* Verify header */
468 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_REQUEST);
469 
470 	/* Verify options */
471 	verify_dhcpv6_clientid(iface, pkt);
472 	verify_dhcpv6_serverid(iface, pkt);
473 	verify_dhcpv6_elapsed_time(iface, pkt, 0, 10);
474 	verify_dhcpv6_ia_na(iface, pkt, NULL);
475 	verify_dhcpv6_ia_pd(iface, pkt, NULL, 0);
476 	verify_dhcpv6_no_reconfigure_accept(iface, pkt);
477 	verify_dhcpv6_oro_sol_max_rt(iface, pkt);
478 }
479 
480 /* Verify that outgoing DHCPv6 Request has a valid format and includes all
481  * mandatory options.
482  */
ZTEST(dhcpv6_tests,test_request_message_format)483 ZTEST(dhcpv6_tests, test_request_message_format)
484 {
485 	int ret;
486 
487 	set_fake_server_duid(test_ctx.iface);
488 	set_dhcpv6_test_fn(verify_request_message);
489 
490 	ret = dhcpv6_send_request(test_ctx.iface);
491 	zassert_ok(ret, "dhcpv6_send_request failed");
492 
493 	ret = k_sem_take(&test_ctx.tx_sem, K_SECONDS(1));
494 	zassert_ok(ret, "Packet not transmitted");
495 }
496 
verify_confirm_message(struct net_if * iface,struct net_pkt * pkt)497 static void verify_confirm_message(struct net_if *iface, struct net_pkt *pkt)
498 {
499 	/* Verify header */
500 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_CONFIRM);
501 
502 	/* Verify options */
503 	verify_dhcpv6_clientid(iface, pkt);
504 	verify_dhcpv6_no_serverid(iface, pkt);
505 	verify_dhcpv6_elapsed_time(iface, pkt, 0, 10);
506 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
507 }
508 
509 /* Verify that outgoing DHCPv6 Confirm has a valid format and includes all
510  * mandatory options.
511  */
ZTEST(dhcpv6_tests,test_confirm_message_format)512 ZTEST(dhcpv6_tests, test_confirm_message_format)
513 {
514 	int ret;
515 
516 	set_test_addr_on_iface(test_ctx.iface);
517 	set_dhcpv6_test_fn(verify_confirm_message);
518 
519 	ret = dhcpv6_send_confirm(test_ctx.iface);
520 	zassert_ok(ret, "dhcpv6_send_confirm failed");
521 
522 	ret = k_sem_take(&test_ctx.tx_sem, K_SECONDS(1));
523 	zassert_ok(ret, "Packet not transmitted");
524 }
525 
verify_renew_message(struct net_if * iface,struct net_pkt * pkt)526 void verify_renew_message(struct net_if *iface, struct net_pkt *pkt)
527 {
528 	/* Verify header */
529 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_RENEW);
530 
531 	/* Verify options */
532 	verify_dhcpv6_clientid(iface, pkt);
533 	verify_dhcpv6_serverid(iface, pkt);
534 	verify_dhcpv6_elapsed_time(iface, pkt, 0, 10);
535 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
536 	verify_dhcpv6_ia_pd(iface, pkt, &test_prefix, test_prefix_len);
537 	verify_dhcpv6_oro_sol_max_rt(iface, pkt);
538 }
539 
540 /* Verify that outgoing DHCPv6 Renew has a valid format and includes all
541  * mandatory options.
542  */
ZTEST(dhcpv6_tests,test_renew_message_format)543 ZTEST(dhcpv6_tests, test_renew_message_format)
544 {
545 	int ret;
546 
547 	set_test_addr_on_iface(test_ctx.iface);
548 	set_fake_server_duid(test_ctx.iface);
549 	set_dhcpv6_test_fn(verify_renew_message);
550 
551 	ret = dhcpv6_send_renew(test_ctx.iface);
552 	zassert_ok(ret, "dhcpv6_send_renew failed");
553 
554 	ret = k_sem_take(&test_ctx.tx_sem, K_SECONDS(1));
555 	zassert_ok(ret, "Packet not transmitted");
556 }
557 
verify_rebind_message(struct net_if * iface,struct net_pkt * pkt)558 static void verify_rebind_message(struct net_if *iface, struct net_pkt *pkt)
559 {
560 	/* Verify header */
561 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_REBIND);
562 
563 	/* Verify options */
564 	verify_dhcpv6_clientid(iface, pkt);
565 	verify_dhcpv6_no_serverid(iface, pkt);
566 	verify_dhcpv6_elapsed_time(iface, pkt, 0, 10);
567 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
568 	verify_dhcpv6_ia_pd(iface, pkt, &test_prefix, test_prefix_len);
569 	verify_dhcpv6_oro_sol_max_rt(iface, pkt);
570 }
571 
572 /* Verify that outgoing DHCPv6 Rebind has a valid format and includes all
573  * mandatory options.
574  */
ZTEST(dhcpv6_tests,test_rebind_message_format)575 ZTEST(dhcpv6_tests, test_rebind_message_format)
576 {
577 	int ret;
578 
579 	set_test_addr_on_iface(test_ctx.iface);
580 	set_dhcpv6_test_fn(verify_rebind_message);
581 
582 	ret = dhcpv6_send_rebind(test_ctx.iface);
583 	zassert_ok(ret, "dhcpv6_send_rebind failed");
584 
585 	ret = k_sem_take(&test_ctx.tx_sem, K_SECONDS(1));
586 	zassert_ok(ret, "Packet not transmitted");
587 }
588 
set_generic_client_options(struct net_if * iface,struct net_pkt * pkt,enum dhcpv6_msg_type msg_type)589 static int set_generic_client_options(struct net_if *iface, struct net_pkt *pkt,
590 				      enum dhcpv6_msg_type msg_type)
591 {
592 	int ret;
593 
594 	/* Simulate a minimum subset of valid options */
595 	ret = dhcpv6_add_option_clientid(pkt, &iface->config.dhcpv6.clientid);
596 	if (ret < 0) {
597 		return ret;
598 	}
599 
600 	if (msg_type == DHCPV6_MSG_TYPE_REQUEST ||
601 	    msg_type == DHCPV6_MSG_TYPE_RENEW ||
602 	    msg_type == DHCPV6_MSG_TYPE_RELEASE ||
603 	    msg_type == DHCPV6_MSG_TYPE_DECLINE) {
604 		ret = dhcpv6_add_option_serverid(pkt, &test_serverid);
605 		if (ret < 0) {
606 			return ret;
607 		}
608 	}
609 
610 	return 0;
611 }
612 
613 /* Verify that DHCPv6 client rejects all messages other than Advertise, Reply
614  * and Reconfigure.
615  */
ZTEST(dhcpv6_tests,test_input_reject_client_initiated_messages)616 ZTEST(dhcpv6_tests, test_input_reject_client_initiated_messages)
617 {
618 
619 	enum dhcpv6_msg_type type;
620 	enum net_verdict result;
621 	struct net_pkt *pkt;
622 
623 	test_ctx.iface->config.dhcpv6.state = NET_DHCPV6_INIT;
624 
625 	for (type = DHCPV6_MSG_TYPE_SOLICIT;
626 	     type <= DHCPV6_MSG_TYPE_RELAY_REPL; type++) {
627 		if (type == DHCPV6_MSG_TYPE_ADVERTISE ||
628 		    type == DHCPV6_MSG_TYPE_REPLY ||
629 		    type == DHCPV6_MSG_TYPE_RECONFIGURE) {
630 			continue;
631 		}
632 
633 		pkt = test_dhcpv6_create_message(test_ctx.iface, type,
634 						 set_generic_client_options);
635 		zassert_not_null(pkt, "Failed to create fake pkt");
636 
637 		result = net_ipv6_input(pkt, false);
638 		zassert_equal(result, NET_DROP, "Should've drop the message");
639 
640 		net_pkt_unref(pkt);
641 	}
642 }
643 
set_advertise_options(struct net_if * iface,struct net_pkt * pkt,enum dhcpv6_msg_type msg_type)644 static int set_advertise_options(struct net_if *iface, struct net_pkt *pkt,
645 				 enum dhcpv6_msg_type msg_type)
646 {
647 	struct dhcpv6_ia_na test_ia_na = {
648 		.iaid = iface->config.dhcpv6.addr_iaid,
649 		.t1 = 60,
650 		.t2 = 120,
651 		.iaaddr.addr = test_addr,
652 		.iaaddr.preferred_lifetime = 120,
653 		.iaaddr.valid_lifetime = 240,
654 	};
655 	struct dhcpv6_ia_pd test_ia_pd = {
656 		.iaid = iface->config.dhcpv6.prefix_iaid,
657 		.t1 = 60,
658 		.t2 = 120,
659 		.iaprefix.prefix = test_prefix,
660 		.iaprefix.prefix_len = test_prefix_len,
661 		.iaprefix.preferred_lifetime = 120,
662 		.iaprefix.valid_lifetime = 240,
663 	};
664 	int ret;
665 
666 	ret = dhcpv6_add_option_clientid(pkt, &iface->config.dhcpv6.clientid);
667 	if (ret < 0) {
668 		return ret;
669 	}
670 
671 	ret = dhcpv6_add_option_serverid(pkt, &test_serverid);
672 	if (ret < 0) {
673 		return ret;
674 	}
675 
676 	if (test_ctx.iface->config.dhcpv6.params.request_addr) {
677 		ret = dhcpv6_add_option_ia_na(pkt, &test_ia_na, true);
678 		if (ret < 0) {
679 			return ret;
680 		}
681 	}
682 
683 	if (test_ctx.iface->config.dhcpv6.params.request_prefix) {
684 		ret = dhcpv6_add_option_ia_pd(pkt, &test_ia_pd, true);
685 		if (ret < 0) {
686 			return ret;
687 		}
688 	}
689 
690 	/* Server specific options */
691 	ret = dhcpv6_add_option_header(pkt, DHCPV6_OPTION_CODE_PREFERENCE,
692 				       DHCPV6_OPTION_PREFERENCE_SIZE);
693 	if (ret < 0) {
694 		return ret;
695 	}
696 
697 	ret = net_pkt_write_u8(pkt, test_preference);
698 	if (ret < 0) {
699 		return ret;
700 	}
701 
702 	return 0;
703 }
704 
705 /* Verify that DHCPv6 client only accepts Advertise messages in Soliciting state */
ZTEST(dhcpv6_tests,test_input_advertise)706 ZTEST(dhcpv6_tests, test_input_advertise)
707 {
708 	enum net_verdict result;
709 	struct net_pkt *pkt;
710 	enum net_dhcpv6_state state;
711 
712 	for (state = NET_DHCPV6_DISABLED; state <= NET_DHCPV6_BOUND; state++) {
713 		test_ctx.iface->config.dhcpv6.state = state;
714 
715 		pkt = test_dhcpv6_create_message(test_ctx.iface,
716 						 DHCPV6_MSG_TYPE_ADVERTISE,
717 						 set_advertise_options);
718 		zassert_not_null(pkt, "Failed to create pkt");
719 
720 		result = net_ipv6_input(pkt, false);
721 
722 		switch (state) {
723 		case NET_DHCPV6_SOLICITING:
724 			zassert_equal(result, NET_OK, "Message should've been processed");
725 
726 			/* Verify that Advertise actually updated DHPCv6 context. */
727 			zassert_equal(test_ctx.iface->config.dhcpv6.server_preference,
728 				      test_preference, "Preference not set");
729 			zassert_equal(test_ctx.iface->config.dhcpv6.serverid.length,
730 				      test_serverid.length, "Invalid Server ID length");
731 			zassert_mem_equal(&test_ctx.iface->config.dhcpv6.serverid.duid,
732 					  &test_serverid.duid, test_serverid.length,
733 					  "Invalid Server ID value");
734 
735 			break;
736 		default:
737 			zassert_equal(result, NET_DROP, "Should've drop the message");
738 			break;
739 
740 		}
741 
742 		net_pkt_unref(pkt);
743 	}
744 }
745 
set_reply_options(struct net_if * iface,struct net_pkt * pkt,enum dhcpv6_msg_type msg_type)746 static int set_reply_options(struct net_if *iface, struct net_pkt *pkt,
747 			     enum dhcpv6_msg_type msg_type)
748 {
749 	struct dhcpv6_ia_na test_ia_na = {
750 		.iaid = iface->config.dhcpv6.addr_iaid,
751 		.t1 = 60,
752 		.t2 = 120,
753 		.iaaddr.addr = test_addr,
754 		.iaaddr.preferred_lifetime = 120,
755 		.iaaddr.valid_lifetime = 240,
756 	};
757 	struct dhcpv6_ia_pd test_ia_pd = {
758 		.iaid = iface->config.dhcpv6.prefix_iaid,
759 		.t1 = 60,
760 		.t2 = 120,
761 		.iaprefix.prefix = test_prefix,
762 		.iaprefix.prefix_len = test_prefix_len,
763 		.iaprefix.preferred_lifetime = 120,
764 		.iaprefix.valid_lifetime = 240,
765 	};
766 	int ret;
767 
768 	ret = dhcpv6_add_option_clientid(pkt, &iface->config.dhcpv6.clientid);
769 	if (ret < 0) {
770 		return ret;
771 	}
772 
773 	ret = dhcpv6_add_option_serverid(pkt, &test_serverid);
774 	if (ret < 0) {
775 		return ret;
776 	}
777 
778 	if (iface->config.dhcpv6.state == NET_DHCPV6_CONFIRMING) {
779 		ret = dhcpv6_add_option_header(
780 			pkt, DHCPV6_OPTION_CODE_STATUS_CODE,
781 			DHCPV6_OPTION_STATUS_CODE_HEADER_SIZE);
782 		if (ret < 0) {
783 			return ret;
784 		}
785 
786 		ret = net_pkt_write_be16(pkt, DHCPV6_STATUS_SUCCESS);
787 		if (ret < 0) {
788 			return ret;
789 		}
790 
791 		return 0;
792 	}
793 
794 	ret = dhcpv6_add_option_ia_na(pkt, &test_ia_na, true);
795 	if (ret < 0) {
796 		return ret;
797 	}
798 
799 	ret = dhcpv6_add_option_ia_pd(pkt, &test_ia_pd, true);
800 	if (ret < 0) {
801 		return ret;
802 	}
803 
804 	return 0;
805 }
806 
807 /* Verify that DHCPv6 client accepts Reply messages in Requesting, Confirming,
808  * Renewing and Rebinding states
809  */
ZTEST(dhcpv6_tests,test_input_reply)810 ZTEST(dhcpv6_tests, test_input_reply)
811 {
812 	enum net_verdict result;
813 	struct net_pkt *pkt;
814 	enum net_dhcpv6_state state;
815 
816 	for (state = NET_DHCPV6_DISABLED; state <= NET_DHCPV6_BOUND; state++) {
817 		test_ctx.iface->config.dhcpv6.state = state;
818 
819 		set_fake_server_duid(test_ctx.iface);
820 		clear_test_addr_on_iface(test_ctx.iface);
821 
822 		pkt = test_dhcpv6_create_message(test_ctx.iface,
823 						 DHCPV6_MSG_TYPE_REPLY,
824 						 set_reply_options);
825 		zassert_not_null(pkt, "Failed to create pkt");
826 
827 		result = net_ipv6_input(pkt, false);
828 
829 		switch (state) {
830 		case NET_DHCPV6_CONFIRMING:
831 		case NET_DHCPV6_REQUESTING:
832 		case NET_DHCPV6_RENEWING:
833 		case NET_DHCPV6_REBINDING:
834 			zassert_equal(result, NET_OK, "Message should've been processed");
835 
836 			/* Confirm is an exception, as it does not update
837 			 * address on an interface (only status OK is expected).
838 			 */
839 			if (state == NET_DHCPV6_CONFIRMING) {
840 				break;
841 			}
842 
843 			/* Verify that Reply actually updated DHPCv6 context. */
844 			zassert_mem_equal(&test_ctx.iface->config.dhcpv6.addr,
845 					  &test_addr, sizeof(test_addr),
846 					  "Invalid address (state %s)",
847 					  net_dhcpv6_state_name(state));
848 			zassert_mem_equal(&test_ctx.iface->config.dhcpv6.prefix,
849 					  &test_prefix, sizeof(test_prefix),
850 					  "Invalid prefix (state %s)",
851 					  net_dhcpv6_state_name(state));
852 			zassert_equal(test_ctx.iface->config.dhcpv6.prefix_len,
853 				      test_prefix_len, "Invalid prefix len (state %s)",
854 				      net_dhcpv6_state_name(state));
855 
856 			break;
857 		default:
858 			zassert_equal(result, NET_DROP, "Should've drop the message");
859 			break;
860 
861 		}
862 
863 		net_pkt_unref(pkt);
864 	}
865 }
866 
test_solicit_expect_request_send_reply(struct net_if * iface,struct net_pkt * pkt)867 static void test_solicit_expect_request_send_reply(struct net_if *iface,
868 						   struct net_pkt *pkt)
869 {
870 	struct net_pkt *reply;
871 	int result;
872 
873 	/* Verify header */
874 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_REQUEST);
875 
876 	/* Verify options */
877 	verify_dhcpv6_clientid(iface, pkt);
878 	verify_dhcpv6_serverid(iface, pkt);
879 	verify_dhcpv6_ia_na(iface, pkt, NULL);
880 	verify_dhcpv6_ia_pd(iface, pkt, NULL, 0);
881 
882 	/* Verify client state */
883 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_REQUESTING,
884 		      "Invalid state");
885 
886 	/* Reply with Reply message */
887 	reply = test_dhcpv6_create_message(test_ctx.iface,
888 					   DHCPV6_MSG_TYPE_REPLY,
889 					   set_reply_options);
890 	zassert_not_null(reply, "Failed to create pkt");
891 
892 	result = net_ipv6_input(reply, false);
893 	zassert_equal(result, NET_OK, "Message should've been processed");
894 
895 	/* Verify client state */
896 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_BOUND,
897 		      "Invalid state");
898 	zassert_mem_equal(&test_ctx.iface->config.dhcpv6.addr,
899 			  &test_addr, sizeof(test_addr), "Invalid address");
900 	zassert_mem_equal(&test_ctx.iface->config.dhcpv6.prefix,
901 			  &test_prefix, sizeof(test_prefix), "Invalid prefix");
902 	zassert_equal(test_ctx.iface->config.dhcpv6.prefix_len,
903 		      test_prefix_len, "Invalid prefix len");
904 
905 	k_sem_give(&test_ctx.exchange_complete_sem);
906 }
907 
test_solicit_expect_solicit_send_advertise(struct net_if * iface,struct net_pkt * pkt)908 static void test_solicit_expect_solicit_send_advertise(struct net_if *iface,
909 						       struct net_pkt *pkt)
910 {
911 	struct net_pkt *reply;
912 	int result;
913 
914 	/* Verify header */
915 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_SOLICIT);
916 
917 	/* Verify options */
918 	verify_dhcpv6_clientid(iface, pkt);
919 	verify_dhcpv6_ia_na(iface, pkt, NULL);
920 	verify_dhcpv6_ia_pd(iface, pkt, NULL, 0);
921 
922 	/* Verify client state */
923 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_SOLICITING,
924 		      "Invalid state");
925 	zassert_equal(iface->config.dhcpv6.server_preference, -1,
926 		      "Invalid initial preference");
927 
928 	/* Update next expected packet handler */
929 	set_dhcpv6_test_fn(test_solicit_expect_request_send_reply);
930 
931 	/* Reply with Advertise message */
932 	reply = test_dhcpv6_create_message(test_ctx.iface,
933 					   DHCPV6_MSG_TYPE_ADVERTISE,
934 					   set_advertise_options);
935 	zassert_not_null(reply, "Failed to create pkt");
936 
937 	result = net_ipv6_input(reply, false);
938 	zassert_equal(result, NET_OK, "Message should've been processed");
939 
940 	/* Verify client state */
941 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_SOLICITING,
942 		      "Invalid state");
943 	zassert_equal(iface->config.dhcpv6.server_preference, test_preference,
944 		      "Invalid initial preference");
945 	zassert_equal(test_serverid.length, iface->config.dhcpv6.serverid.length,
946 		      "Invalid Server ID length");
947 	zassert_mem_equal(&test_serverid.duid, &iface->config.dhcpv6.serverid.duid,
948 			  test_serverid.length, "Invalid Server ID value");
949 }
950 
951 /* Verify that DHCPv6 client can handle standard exchange (Solicit/Request) */
ZTEST(dhcpv6_tests,test_solicit_exchange)952 ZTEST(dhcpv6_tests, test_solicit_exchange)
953 {
954 	struct net_dhcpv6_params params = {
955 		.request_addr = true,
956 		.request_prefix = true,
957 	};
958 	struct net_if_ipv6_prefix *prefix;
959 	struct net_if_addr *addr;
960 	int ret;
961 
962 	test_ctx.reset_dhcpv6 = true;
963 	memset(&test_ctx.iface->config.dhcpv6, 0,
964 	       sizeof(test_ctx.iface->config.dhcpv6));
965 
966 	set_dhcpv6_test_fn(test_solicit_expect_solicit_send_advertise);
967 
968 	net_dhcpv6_start(test_ctx.iface, &params);
969 
970 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
971 	zassert_ok(ret, "Exchange not completed in required time");
972 
973 	addr = net_if_ipv6_addr_lookup_by_iface(test_ctx.iface, &test_addr);
974 	prefix = net_if_ipv6_prefix_lookup(test_ctx.iface, &test_prefix,
975 					   test_prefix_len);
976 	zassert_not_null(addr, "Address not configured on the interface");
977 	zassert_not_null(prefix, "Prefix not configured on the interface");
978 }
979 
expect_request_send_reply(struct net_if * iface,struct net_pkt * pkt)980 static void expect_request_send_reply(struct net_if *iface, struct net_pkt *pkt)
981 {
982 	struct net_pkt *reply;
983 	int result;
984 
985 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_REQUEST);
986 	set_dhcpv6_test_fn(NULL);
987 
988 	/* Reply with Reply message */
989 	reply = test_dhcpv6_create_message(test_ctx.iface,
990 					   DHCPV6_MSG_TYPE_REPLY,
991 					   set_reply_options);
992 	zassert_not_null(reply, "Failed to create pkt");
993 
994 	result = net_ipv6_input(reply, false);
995 	zassert_equal(result, NET_OK, "Message should've been processed");
996 
997 	k_sem_give(&test_ctx.exchange_complete_sem);
998 }
999 
expect_solicit_send_advertise(struct net_if * iface,struct net_pkt * pkt)1000 static void expect_solicit_send_advertise(struct net_if *iface, struct net_pkt *pkt)
1001 {
1002 	struct net_pkt *reply;
1003 	int result;
1004 
1005 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_SOLICIT);
1006 	set_dhcpv6_test_fn(expect_request_send_reply);
1007 
1008 	/* Reply with Advertise message */
1009 	reply = test_dhcpv6_create_message(test_ctx.iface,
1010 					   DHCPV6_MSG_TYPE_ADVERTISE,
1011 					   set_advertise_options);
1012 	zassert_not_null(reply, "Failed to create pkt");
1013 
1014 	result = net_ipv6_input(reply, false);
1015 	zassert_equal(result, NET_OK, "Message should've been processed");
1016 }
1017 
test_dhcpv6_start_and_enter_bound(struct net_dhcpv6_params * params)1018 static void test_dhcpv6_start_and_enter_bound(struct net_dhcpv6_params *params)
1019 {
1020 	int ret;
1021 
1022 	/* Set maximum preference to speed up the process. */
1023 	test_preference = DHCPV6_MAX_SERVER_PREFERENCE;
1024 
1025 	set_dhcpv6_test_fn(expect_solicit_send_advertise);
1026 	net_dhcpv6_start(test_ctx.iface, params);
1027 
1028 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
1029 	zassert_ok(ret, "Exchange not completed in required time");
1030 	zassert_equal(test_ctx.iface->config.dhcpv6.state, NET_DHCPV6_BOUND,
1031 		      "Invalid state");
1032 }
1033 
test_confirm_expect_confirm_send_reply(struct net_if * iface,struct net_pkt * pkt)1034 static void test_confirm_expect_confirm_send_reply(struct net_if *iface,
1035 						   struct net_pkt *pkt)
1036 {
1037 	struct net_pkt *reply;
1038 	int result;
1039 
1040 	/* Verify header */
1041 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_CONFIRM);
1042 
1043 	/* Verify options */
1044 	verify_dhcpv6_clientid(iface, pkt);
1045 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
1046 
1047 	/* Verify client state */
1048 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_CONFIRMING,
1049 		      "Invalid state");
1050 
1051 	set_dhcpv6_test_fn(NULL);
1052 
1053 	/* Reply with Advertise message */
1054 	reply = test_dhcpv6_create_message(test_ctx.iface,
1055 					   DHCPV6_MSG_TYPE_REPLY,
1056 					   set_reply_options);
1057 	zassert_not_null(reply, "Failed to create pkt");
1058 
1059 	result = net_ipv6_input(reply, false);
1060 	zassert_equal(result, NET_OK, "Message should've been processed");
1061 
1062 	/* Verify client state */
1063 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_BOUND,
1064 		      "Invalid state");
1065 	zassert_equal(test_serverid.length, iface->config.dhcpv6.serverid.length,
1066 		      "Invalid Server ID length");
1067 	zassert_mem_equal(&test_serverid.duid, &iface->config.dhcpv6.serverid.duid,
1068 			  test_serverid.length, "Invalid Server ID value");
1069 
1070 	k_sem_give(&test_ctx.exchange_complete_sem);
1071 }
1072 
1073 /* Verify that DHCPv6 client starts with Confirm when interface goes down and
1074  * up again (no prefix).
1075  */
ZTEST(dhcpv6_tests,test_confirm_exchange_after_iface_down)1076 ZTEST(dhcpv6_tests, test_confirm_exchange_after_iface_down)
1077 {
1078 	struct net_dhcpv6_params params = {
1079 		.request_addr = true,
1080 		.request_prefix = false,
1081 	};
1082 	struct net_if_addr *addr;
1083 	int ret;
1084 
1085 	test_ctx.reset_dhcpv6 = true;
1086 	memset(&test_ctx.iface->config.dhcpv6, 0,
1087 	       sizeof(test_ctx.iface->config.dhcpv6));
1088 
1089 	test_dhcpv6_start_and_enter_bound(&params);
1090 	set_dhcpv6_test_fn(test_confirm_expect_confirm_send_reply);
1091 
1092 	net_if_down(test_ctx.iface);
1093 	net_if_up(test_ctx.iface);
1094 
1095 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
1096 	zassert_ok(ret, "Exchange not completed in required time");
1097 
1098 	addr = net_if_ipv6_addr_lookup_by_iface(test_ctx.iface, &test_addr);
1099 	zassert_not_null(addr, "Address not configured on the interface");
1100 }
1101 
test_rebind_expect_rebind_send_reply(struct net_if * iface,struct net_pkt * pkt)1102 static void test_rebind_expect_rebind_send_reply(struct net_if *iface,
1103 						 struct net_pkt *pkt)
1104 {
1105 	struct net_pkt *reply;
1106 	int result;
1107 
1108 	/* Verify header */
1109 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_REBIND);
1110 
1111 	/* Verify options */
1112 	verify_dhcpv6_clientid(iface, pkt);
1113 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
1114 	verify_dhcpv6_ia_pd(iface, pkt, &test_prefix, test_prefix_len);
1115 
1116 	/* Verify client state */
1117 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_REBINDING,
1118 		      "Invalid state");
1119 
1120 	set_dhcpv6_test_fn(NULL);
1121 
1122 	/* Reply with Advertise message */
1123 	reply = test_dhcpv6_create_message(test_ctx.iface,
1124 					   DHCPV6_MSG_TYPE_REPLY,
1125 					   set_reply_options);
1126 	zassert_not_null(reply, "Failed to create pkt");
1127 
1128 	result = net_ipv6_input(reply, false);
1129 	zassert_equal(result, NET_OK, "Message should've been processed");
1130 
1131 	/* Verify client state */
1132 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_BOUND,
1133 		      "Invalid state");
1134 	zassert_equal(test_serverid.length, iface->config.dhcpv6.serverid.length,
1135 		      "Invalid Server ID length");
1136 	zassert_mem_equal(&test_serverid.duid, &iface->config.dhcpv6.serverid.duid,
1137 			  test_serverid.length, "Invalid Server ID value");
1138 
1139 	k_sem_give(&test_ctx.exchange_complete_sem);
1140 }
1141 
1142 /* Verify that DHCPv6 client starts with Rebind when interface goes down and
1143  * up again (w/ prefix).
1144  */
ZTEST(dhcpv6_tests,test_rebind_exchange_after_iface_down)1145 ZTEST(dhcpv6_tests, test_rebind_exchange_after_iface_down)
1146 {
1147 	struct net_dhcpv6_params params = {
1148 		.request_addr = true,
1149 		.request_prefix = true,
1150 	};
1151 	struct net_if_ipv6_prefix *prefix;
1152 	struct net_if_addr *addr;
1153 	int ret;
1154 
1155 	test_ctx.reset_dhcpv6 = true;
1156 	memset(&test_ctx.iface->config.dhcpv6, 0,
1157 	       sizeof(test_ctx.iface->config.dhcpv6));
1158 
1159 	test_dhcpv6_start_and_enter_bound(&params);
1160 	set_dhcpv6_test_fn(test_rebind_expect_rebind_send_reply);
1161 
1162 	net_if_down(test_ctx.iface);
1163 	net_if_up(test_ctx.iface);
1164 
1165 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
1166 	zassert_ok(ret, "Exchange not completed in required time");
1167 
1168 	addr = net_if_ipv6_addr_lookup_by_iface(test_ctx.iface, &test_addr);
1169 	prefix = net_if_ipv6_prefix_lookup(test_ctx.iface, &test_prefix,
1170 					   test_prefix_len);
1171 	zassert_not_null(addr, "Address not configured on the interface");
1172 	zassert_not_null(prefix, "Prefix not configured on the interface");
1173 }
1174 
test_renew_expect_renew_send_reply(struct net_if * iface,struct net_pkt * pkt)1175 static void test_renew_expect_renew_send_reply(struct net_if *iface,
1176 					       struct net_pkt *pkt)
1177 {
1178 	struct net_pkt *reply;
1179 	int result;
1180 
1181 	/* Verify header */
1182 	verify_dhcpv6_header(iface, pkt, DHCPV6_MSG_TYPE_RENEW);
1183 
1184 	/* Verify options */
1185 	verify_dhcpv6_clientid(iface, pkt);
1186 	verify_dhcpv6_serverid(iface, pkt);
1187 	verify_dhcpv6_ia_na(iface, pkt, &test_addr);
1188 	verify_dhcpv6_ia_pd(iface, pkt, &test_prefix, test_prefix_len);
1189 
1190 	/* Verify client state */
1191 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_RENEWING,
1192 		      "Invalid state");
1193 
1194 	set_dhcpv6_test_fn(NULL);
1195 
1196 	/* Reply with Advertise message */
1197 	reply = test_dhcpv6_create_message(test_ctx.iface,
1198 					   DHCPV6_MSG_TYPE_REPLY,
1199 					   set_reply_options);
1200 	zassert_not_null(reply, "Failed to create pkt");
1201 
1202 	result = net_ipv6_input(reply, false);
1203 	zassert_equal(result, NET_OK, "Message should've been processed");
1204 
1205 	/* Verify client state */
1206 	zassert_equal(iface->config.dhcpv6.state, NET_DHCPV6_BOUND,
1207 		      "Invalid state");
1208 	zassert_equal(test_serverid.length, iface->config.dhcpv6.serverid.length,
1209 		      "Invalid Server ID length");
1210 	zassert_mem_equal(&test_serverid.duid, &iface->config.dhcpv6.serverid.duid,
1211 			  test_serverid.length, "Invalid Server ID value");
1212 
1213 	k_sem_give(&test_ctx.exchange_complete_sem);
1214 }
1215 
1216 /* Verify that DHCPv6 client proceeds with Renew when T1 timeout expires. */
ZTEST(dhcpv6_tests,test_renew_exchange_after_t1)1217 ZTEST(dhcpv6_tests, test_renew_exchange_after_t1)
1218 {
1219 	struct net_dhcpv6_params params = {
1220 		.request_addr = true,
1221 		.request_prefix = true,
1222 	};
1223 	struct net_if_ipv6_prefix *prefix;
1224 	struct net_if_addr *addr;
1225 	int ret;
1226 
1227 	test_ctx.reset_dhcpv6 = true;
1228 	memset(&test_ctx.iface->config.dhcpv6, 0,
1229 	       sizeof(test_ctx.iface->config.dhcpv6));
1230 
1231 	test_dhcpv6_start_and_enter_bound(&params);
1232 	set_dhcpv6_test_fn(test_renew_expect_renew_send_reply);
1233 
1234 	/* Simulate T1 timeout */
1235 	test_ctx.iface->config.dhcpv6.t1 = k_uptime_get();
1236 	test_ctx.iface->config.dhcpv6.timeout = test_ctx.iface->config.dhcpv6.t1;
1237 	dhcpv6_reschedule();
1238 
1239 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
1240 	zassert_ok(ret, "Exchange not completed in required time");
1241 
1242 	addr = net_if_ipv6_addr_lookup_by_iface(test_ctx.iface, &test_addr);
1243 	prefix = net_if_ipv6_prefix_lookup(test_ctx.iface, &test_prefix,
1244 					   test_prefix_len);
1245 	zassert_not_null(addr, "Address not configured on the interface");
1246 	zassert_not_null(prefix, "Prefix not configured on the interface");
1247 }
1248 
1249 /* Verify that DHCPv6 client proceeds with Rebind when T2 timeout expires. */
ZTEST(dhcpv6_tests,test_rebind_exchange_after_t2)1250 ZTEST(dhcpv6_tests, test_rebind_exchange_after_t2)
1251 {
1252 	struct net_dhcpv6_params params = {
1253 		.request_addr = true,
1254 		.request_prefix = true,
1255 	};
1256 	struct net_if_ipv6_prefix *prefix;
1257 	struct net_if_addr *addr;
1258 	int ret;
1259 
1260 	test_ctx.reset_dhcpv6 = true;
1261 	memset(&test_ctx.iface->config.dhcpv6, 0,
1262 	       sizeof(test_ctx.iface->config.dhcpv6));
1263 
1264 	test_dhcpv6_start_and_enter_bound(&params);
1265 	set_dhcpv6_test_fn(NULL);
1266 
1267 	/* Simulate T1 timeout */
1268 	test_ctx.iface->config.dhcpv6.t1 = k_uptime_get();
1269 	test_ctx.iface->config.dhcpv6.timeout = test_ctx.iface->config.dhcpv6.t1;
1270 	dhcpv6_reschedule();
1271 
1272 	/* Give a state machine a chance to run, we ignore Renew message. */
1273 	k_msleep(10);
1274 
1275 	set_dhcpv6_test_fn(test_rebind_expect_rebind_send_reply);
1276 
1277 	/* Simulate T2 timeout */
1278 	test_ctx.iface->config.dhcpv6.t2 = k_uptime_get();
1279 	test_ctx.iface->config.dhcpv6.timeout = test_ctx.iface->config.dhcpv6.t2;
1280 	dhcpv6_reschedule();
1281 
1282 	ret = k_sem_take(&test_ctx.exchange_complete_sem, K_SECONDS(2));
1283 	zassert_ok(ret, "Exchange not completed in required time");
1284 
1285 	addr = net_if_ipv6_addr_lookup_by_iface(test_ctx.iface, &test_addr);
1286 	prefix = net_if_ipv6_prefix_lookup(test_ctx.iface, &test_prefix,
1287 					   test_prefix_len);
1288 	zassert_not_null(addr, "Address not configured on the interface");
1289 	zassert_not_null(prefix, "Prefix not configured on the interface");
1290 }
1291 
1292 ZTEST_SUITE(dhcpv6_tests, NULL, dhcpv6_tests_setup, dhcpv6_tests_before,
1293 	    dhcpv6_tests_after, NULL);
1294