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, ¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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