1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2015 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(net_test, CONFIG_NET_IPV6_LOG_LEVEL);
11
12 #include <zephyr/types.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <zephyr/linker/sections.h>
18
19 #include <zephyr/ztest.h>
20
21 #include <zephyr/net/mld.h>
22 #include <zephyr/net/net_if.h>
23 #include <zephyr/net/net_pkt.h>
24 #include <zephyr/net/net_ip.h>
25 #include <zephyr/net/net_core.h>
26 #include <zephyr/net/ethernet.h>
27 #include <zephyr/net/dummy.h>
28 #include <zephyr/net/net_mgmt.h>
29 #include <zephyr/net/net_event.h>
30 #include <zephyr/net/socket.h>
31
32 #include <zephyr/random/random.h>
33
34 #include "icmpv6.h"
35 #include "ipv6.h"
36 #include "route.h"
37
38 #define THREAD_SLEEP 50 /* ms */
39 #define MLD_REPORT_ADDR_COUNT 8
40
41 #define NET_LOG_ENABLED 1
42 #include "net_private.h"
43
44 #if defined(CONFIG_NET_IPV6_LOG_LEVEL_DBG)
45 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
46 #else
47 #define DBG(fmt, ...)
48 #endif
49
50 struct mld_report_mcast_record {
51 uint8_t record_type;
52 uint8_t aux_data_len;
53 uint16_t num_of_sources;
54 struct in6_addr mcast_addr;
55 } __packed;
56
57 struct mld_report_info {
58 uint16_t records_count;
59 struct mld_report_mcast_record records[MLD_REPORT_ADDR_COUNT];
60 };
61
62 typedef void (*mld_report_callback)(struct net_pkt *pkt, void *user_data);
63
64 struct mld_report_handler {
65 mld_report_callback fn;
66 void *user_data;
67 };
68
69 static struct in6_addr my_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
71 static struct in6_addr peer_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0x2 } } };
73 static struct in6_addr mcast_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
74 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
75
76 static struct in6_addr *exp_mcast_group;
77 static struct net_if *net_iface;
78 static bool is_group_joined;
79 static bool is_group_left;
80 static bool is_join_msg_ok;
81 static bool is_leave_msg_ok;
82 static bool is_query_received;
83 static bool is_report_sent;
84 static bool ignore_already;
85
86 static struct mld_report_handler *report_handler;
87
88 K_SEM_DEFINE(wait_data, 0, UINT_MAX);
89 K_SEM_DEFINE(wait_joined, 0, UINT_MAX);
90 K_SEM_DEFINE(wait_left, 0, UINT_MAX);
91
92 #define WAIT_TIME 500
93 #define WAIT_TIME_LONG MSEC_PER_SEC
94 #define MY_PORT 1969
95 #define PEER_PORT 13856
96
97 struct net_test_mld {
98 uint8_t mac_addr[sizeof(struct net_eth_addr)];
99 struct net_linkaddr ll_addr;
100 };
101
net_test_dev_init(const struct device * dev)102 int net_test_dev_init(const struct device *dev)
103 {
104 return 0;
105 }
106
net_test_get_mac(const struct device * dev)107 static uint8_t *net_test_get_mac(const struct device *dev)
108 {
109 struct net_test_mld *context = dev->data;
110
111 if (context->mac_addr[2] == 0x00) {
112 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
113 context->mac_addr[0] = 0x00;
114 context->mac_addr[1] = 0x00;
115 context->mac_addr[2] = 0x5E;
116 context->mac_addr[3] = 0x00;
117 context->mac_addr[4] = 0x53;
118 context->mac_addr[5] = sys_rand8_get();
119 }
120
121 return context->mac_addr;
122 }
123
net_test_iface_init(struct net_if * iface)124 static void net_test_iface_init(struct net_if *iface)
125 {
126 uint8_t *mac = net_test_get_mac(net_if_get_device(iface));
127
128 net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr),
129 NET_LINK_ETHERNET);
130 }
131
get_icmp_hdr(struct net_pkt * pkt)132 static struct net_icmp_hdr *get_icmp_hdr(struct net_pkt *pkt)
133 {
134 net_pkt_cursor_init(pkt);
135
136 net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) +
137 net_pkt_ipv6_ext_len(pkt));
138
139 return (struct net_icmp_hdr *)net_pkt_cursor_get_pos(pkt);
140 }
141
tester_send(const struct device * dev,struct net_pkt * pkt)142 static int tester_send(const struct device *dev, struct net_pkt *pkt)
143 {
144 struct net_icmp_hdr *icmp;
145
146 if (!pkt->buffer) {
147 TC_ERROR("No data to send!\n");
148 return -ENODATA;
149 }
150
151 icmp = get_icmp_hdr(pkt);
152
153 if (icmp->type == NET_ICMPV6_MLDv2) {
154 /* FIXME, add more checks here */
155
156 NET_DBG("Received something....");
157 is_join_msg_ok = true;
158 is_leave_msg_ok = true;
159 is_report_sent = true;
160
161 if (report_handler) {
162 report_handler->fn(pkt, report_handler->user_data);
163 }
164
165 k_sem_give(&wait_data);
166 }
167
168 return 0;
169 }
170
tester_null_send(const struct device * dev,struct net_pkt * pkt)171 static int tester_null_send(const struct device *dev, struct net_pkt *pkt)
172 {
173 ARG_UNUSED(dev);
174 ARG_UNUSED(pkt);
175
176 return 0;
177 }
178
179 struct net_test_mld net_test_data;
180 struct net_test_mld net_test_null_data;
181
182 static struct dummy_api net_test_if_api = {
183 .iface_api.init = net_test_iface_init,
184 .send = tester_send,
185 };
186
init_null_iface(struct net_if * iface)187 static void init_null_iface(struct net_if *iface)
188 {
189 struct net_test_mld *context = iface->if_dev->dev->data;
190
191 memset(&context->mac_addr, 0, sizeof(context->mac_addr));
192
193 net_if_set_link_addr(iface, context->mac_addr, sizeof(struct net_eth_addr),
194 NET_LINK_ETHERNET);
195 }
196
197 static struct dummy_api net_test_null_if_api = {
198 .iface_api.init = init_null_iface,
199 .send = tester_null_send,
200 };
201
202 #define _ETH_L2_LAYER DUMMY_L2
203 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
204
205 NET_DEVICE_INIT(net_test_mld, "net_test_mld",
206 net_test_dev_init, NULL, &net_test_data, NULL,
207 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
208 &net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE,
209 127);
210
211 /* Interface without a device or API, only for usage of `struct net_if` */
212 NET_DEVICE_INIT(net_test_null_iface, "net_test_null_iface", net_test_dev_init, NULL,
213 &net_test_null_data, NULL, 99, &net_test_null_if_api, _ETH_L2_LAYER,
214 _ETH_L2_CTX_TYPE, 127);
215
test_iface_down_up(void)216 static void test_iface_down_up(void)
217 {
218 zassert_ok(net_if_down(net_iface), "Failed to bring iface down");
219 k_msleep(10);
220 zassert_ok(net_if_up(net_iface), "Failed to bring iface up");
221 }
222
test_iface_down_up_delayed_carrier(void)223 static void test_iface_down_up_delayed_carrier(void)
224 {
225 zassert_ok(net_if_down(net_iface), "Failed to bring iface down");
226 k_msleep(10);
227 net_if_carrier_off(net_iface);
228 zassert_ok(net_if_up(net_iface), "Failed to bring iface up");
229 k_msleep(10);
230 net_if_carrier_on(net_iface);
231 }
232
test_iface_carrier_off_on(void)233 static void test_iface_carrier_off_on(void)
234 {
235 net_if_carrier_off(net_iface);
236 k_msleep(10);
237 net_if_carrier_on(net_iface);
238 }
239
group_joined(struct net_mgmt_event_callback * cb,uint32_t nm_event,struct net_if * iface)240 static void group_joined(struct net_mgmt_event_callback *cb,
241 uint32_t nm_event, struct net_if *iface)
242 {
243 if (nm_event != NET_EVENT_IPV6_MCAST_JOIN) {
244 /* Spurious callback. */
245 return;
246 }
247
248 if (exp_mcast_group == NULL ||
249 net_ipv6_addr_cmp(exp_mcast_group, cb->info)) {
250 is_group_joined = true;
251
252 k_sem_give(&wait_joined);
253 }
254 }
255
group_left(struct net_mgmt_event_callback * cb,uint32_t nm_event,struct net_if * iface)256 static void group_left(struct net_mgmt_event_callback *cb,
257 uint32_t nm_event, struct net_if *iface)
258 {
259 if (nm_event != NET_EVENT_IPV6_MCAST_LEAVE) {
260 /* Spurious callback. */
261 return;
262 }
263
264 if (exp_mcast_group == NULL ||
265 net_ipv6_addr_cmp(exp_mcast_group, cb->info)) {
266 is_group_left = true;
267
268 k_sem_give(&wait_left);
269 }
270 }
271
272 static struct mgmt_events {
273 uint32_t event;
274 net_mgmt_event_handler_t handler;
275 struct net_mgmt_event_callback cb;
276 } mgmt_events[] = {
277 { .event = NET_EVENT_IPV6_MCAST_JOIN, .handler = group_joined },
278 { .event = NET_EVENT_IPV6_MCAST_LEAVE, .handler = group_left },
279 { 0 }
280 };
281
setup_mgmt_events(void)282 static void setup_mgmt_events(void)
283 {
284 int i;
285
286 for (i = 0; mgmt_events[i].event; i++) {
287 net_mgmt_init_event_callback(&mgmt_events[i].cb,
288 mgmt_events[i].handler,
289 mgmt_events[i].event);
290
291 net_mgmt_add_event_callback(&mgmt_events[i].cb);
292 }
293 }
294
test_mld_setup(void)295 static void *test_mld_setup(void)
296 {
297 struct net_if_addr *ifaddr;
298
299 setup_mgmt_events();
300
301 net_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
302
303 zassert_not_null(net_iface, "Interface is NULL");
304
305 ifaddr = net_if_ipv6_addr_add(net_iface, &my_addr,
306 NET_ADDR_MANUAL, 0);
307
308 zassert_not_null(ifaddr, "Cannot add IPv6 address");
309
310 return NULL;
311 }
312
test_mld_before(void * fixture)313 static void test_mld_before(void *fixture)
314 {
315 ARG_UNUSED(fixture);
316
317 report_handler = NULL;
318 exp_mcast_group = NULL;
319 }
320
test_join_group(void)321 static void test_join_group(void)
322 {
323 int ret;
324
325 /* Using adhoc multicast group outside standard range */
326 net_ipv6_addr_create(&mcast_addr, 0xff10, 0, 0, 0, 0, 0, 0, 0x0001);
327
328 ret = net_ipv6_mld_join(net_iface, &mcast_addr);
329
330 if (ignore_already) {
331 zassert_true(ret == 0 || ret == -EALREADY,
332 "Cannot join IPv6 multicast group");
333 } else {
334 zassert_equal(ret, 0, "Cannot join IPv6 multicast group");
335 }
336
337 /* Let the network stack to proceed */
338 k_msleep(THREAD_SLEEP);
339 }
340
test_leave_group(void)341 static void test_leave_group(void)
342 {
343 int ret;
344
345 net_ipv6_addr_create(&mcast_addr, 0xff10, 0, 0, 0, 0, 0, 0, 0x0001);
346
347 ret = net_ipv6_mld_leave(net_iface, &mcast_addr);
348
349 zassert_equal(ret, 0, "Cannot leave IPv6 multicast group");
350
351 k_msleep(THREAD_SLEEP);
352 }
353
test_catch_join_group(void)354 static void test_catch_join_group(void)
355 {
356 is_group_joined = false;
357
358 ignore_already = false;
359
360 test_join_group();
361
362 if (k_sem_take(&wait_joined, K_MSEC(WAIT_TIME))) {
363 zassert_true(0, "Timeout while waiting join event");
364 }
365
366 if (!is_group_joined) {
367 zassert_true(0, "Did not catch join event");
368 }
369
370 is_group_joined = false;
371 }
372
test_catch_leave_group(void)373 static void test_catch_leave_group(void)
374 {
375 is_group_joined = false;
376
377 test_leave_group();
378
379 if (k_sem_take(&wait_left, K_MSEC(WAIT_TIME))) {
380 zassert_true(0, "Timeout while waiting leave event");
381 }
382
383 if (!is_group_left) {
384 zassert_true(0, "Did not catch leave event");
385 }
386
387 is_group_left = false;
388 }
389
test_verify_join_group(void)390 static void test_verify_join_group(void)
391 {
392 is_join_msg_ok = false;
393
394 ignore_already = false;
395
396 test_join_group();
397
398 if (k_sem_take(&wait_joined, K_MSEC(WAIT_TIME))) {
399 zassert_true(0, "Timeout while waiting join event");
400 }
401
402 if (!is_join_msg_ok) {
403 zassert_true(0, "Join msg invalid");
404 }
405
406 is_join_msg_ok = false;
407 }
408
test_verify_leave_group(void)409 static void test_verify_leave_group(void)
410 {
411 is_leave_msg_ok = false;
412
413 test_leave_group();
414
415 if (k_sem_take(&wait_left, K_MSEC(WAIT_TIME))) {
416 zassert_true(0, "Timeout while waiting leave event");
417 }
418
419 if (!is_leave_msg_ok) {
420 zassert_true(0, "Leave msg invalid");
421 }
422
423 is_leave_msg_ok = false;
424 }
425
send_query(struct net_if * iface)426 static void send_query(struct net_if *iface)
427 {
428 struct net_pkt *pkt;
429 struct in6_addr dst;
430 int ret;
431
432 /* Sent to all MLDv2-capable routers */
433 net_ipv6_addr_create(&dst, 0xff02, 0, 0, 0, 0, 0, 0, 0x0016);
434
435 /* router alert opt + icmpv6 reserved space + mldv2 mcast record */
436 pkt = net_pkt_alloc_with_buffer(iface, 144, AF_INET6,
437 IPPROTO_ICMPV6, K_FOREVER);
438 zassert_not_null(pkt, "Cannot allocate pkt");
439
440 net_pkt_set_ipv6_hop_limit(pkt, 1); /* RFC 3810 ch 7.4 */
441 ret = net_ipv6_create(pkt, &peer_addr, &dst);
442 zassert_false(ret, "Cannot create ipv6 pkt");
443
444 /* Add hop-by-hop option and router alert option, RFC 3810 ch 5. */
445 ret = net_pkt_write_u8(pkt, IPPROTO_ICMPV6);
446 zassert_false(ret, "Failed to write");
447 ret = net_pkt_write_u8(pkt, 0); /* length (0 means 8 bytes) */
448 zassert_false(ret, "Failed to write");
449
450 #define ROUTER_ALERT_LEN 8
451
452 /* IPv6 router alert option is described in RFC 2711. */
453 ret = net_pkt_write_be16(pkt, 0x0502); /* RFC 2711 ch 2.1 */
454 zassert_false(ret, "Failed to write");
455 ret = net_pkt_write_be16(pkt, 0); /* pkt contains MLD msg */
456 zassert_false(ret, "Failed to write");
457
458 ret = net_pkt_write_u8(pkt, 1); /* padn */
459 zassert_false(ret, "Failed to write");
460 ret = net_pkt_write_u8(pkt, 0); /* padn len */
461 zassert_false(ret, "Failed to write");
462
463 net_pkt_set_ipv6_ext_len(pkt, ROUTER_ALERT_LEN);
464
465 /* ICMPv6 header */
466 ret = net_icmpv6_create(pkt, NET_ICMPV6_MLD_QUERY, 0);
467 zassert_false(ret, "Cannot create icmpv6 pkt");
468
469 ret = net_pkt_write_be16(pkt, 3); /* maximum response code */
470 zassert_false(ret, "Failed to write");
471 ret = net_pkt_write_be16(pkt, 0); /* reserved field */
472 zassert_false(ret, "Failed to write");
473
474 net_pkt_set_ipv6_next_hdr(pkt, NET_IPV6_NEXTHDR_HBHO);
475
476 ret = net_pkt_write_be16(pkt, 0); /* Resv, S, QRV and QQIC */
477 zassert_false(ret, "Failed to write");
478 ret = net_pkt_write_be16(pkt, 0); /* number of addresses */
479 zassert_false(ret, "Failed to write");
480
481 ret = net_pkt_write(pkt, net_ipv6_unspecified_address(),
482 sizeof(struct in6_addr));
483 zassert_false(ret, "Failed to write");
484
485 net_pkt_cursor_init(pkt);
486 ret = net_ipv6_finalize(pkt, IPPROTO_ICMPV6);
487 zassert_false(ret, "Failed to finalize ipv6 packet");
488
489 net_pkt_cursor_init(pkt);
490
491 ret = net_recv_data(iface, pkt);
492 zassert_false(ret, "Failed to receive data");
493 }
494
495 /* interface needs to join the MLDv2-capable routers multicast group before it
496 * can receive MLD queries
497 */
join_mldv2_capable_routers_group(void)498 static void join_mldv2_capable_routers_group(void)
499 {
500 struct net_if *iface;
501 int ret;
502
503 iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
504
505 net_ipv6_addr_create(&mcast_addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0016);
506 ret = net_ipv6_mld_join(iface, &mcast_addr);
507
508 zassert_true(ret == 0 || ret == -EALREADY,
509 "Cannot join MLDv2-capable routers multicast group");
510
511 k_msleep(THREAD_SLEEP);
512
513 }
514
leave_mldv2_capable_routers_group(void)515 static void leave_mldv2_capable_routers_group(void)
516 {
517 struct net_if *iface;
518 int ret;
519
520 iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
521
522 net_ipv6_addr_create(&mcast_addr, 0xff02, 0, 0, 0, 0, 0, 0, 0x0016);
523 ret = net_ipv6_mld_leave(iface, &mcast_addr);
524
525 zassert_equal(ret, 0,
526 "Cannot leave MLDv2-capable routers multicast group");
527
528 k_msleep(THREAD_SLEEP);
529 }
530
531 /* We are not really interested to parse the query at this point */
handle_mld_query(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)532 static int handle_mld_query(struct net_icmp_ctx *ctx,
533 struct net_pkt *pkt,
534 struct net_icmp_ip_hdr *hdr,
535 struct net_icmp_hdr *icmp_hdr,
536 void *user_data)
537 {
538 ARG_UNUSED(ctx);
539 ARG_UNUSED(pkt);
540 ARG_UNUSED(hdr);
541 ARG_UNUSED(icmp_hdr);
542 ARG_UNUSED(user_data);
543
544 is_query_received = true;
545
546 NET_DBG("Handling MLD query");
547
548 return NET_DROP;
549 }
550
test_catch_query(void)551 static void test_catch_query(void)
552 {
553 struct net_icmp_ctx ctx;
554 int ret;
555
556 join_mldv2_capable_routers_group();
557
558 is_query_received = false;
559
560 ret = net_icmp_init_ctx(&ctx, NET_ICMPV6_MLD_QUERY,
561 0, handle_mld_query);
562 zassert_equal(ret, 0, "Cannot register %s handler (%d)",
563 STRINGIFY(NET_ICMPV6_MLD_QUERY), ret);
564
565 send_query(net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)));
566
567 k_msleep(THREAD_SLEEP);
568
569 if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) {
570 zassert_true(0, "Timeout while waiting query event");
571 }
572
573 if (!is_query_received) {
574 zassert_true(0, "Query msg invalid");
575 }
576
577 is_query_received = false;
578
579 leave_mldv2_capable_routers_group();
580
581 net_icmp_cleanup_ctx(&ctx);
582 }
583
test_verify_send_report(void)584 static void test_verify_send_report(void)
585 {
586 join_mldv2_capable_routers_group();
587
588 is_query_received = false;
589 is_report_sent = false;
590
591 ignore_already = true;
592
593 k_sem_reset(&wait_data);
594
595 test_join_group();
596
597 k_yield();
598
599 /* Did we send a report? */
600 if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) {
601 zassert_true(0, "Timeout while waiting for report");
602 }
603
604 k_sem_reset(&wait_data);
605
606 is_report_sent = false;
607 send_query(net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)));
608
609 k_yield();
610
611 /* Did we send a report? */
612 if (k_sem_take(&wait_data, K_MSEC(WAIT_TIME))) {
613 zassert_true(0, "Timeout while waiting for report");
614 }
615
616 zassert_true(is_report_sent, "Report not sent");
617
618 leave_mldv2_capable_routers_group();
619 }
620
621 /* This value should be longer that the one in net_if.c when DAD timeouts */
622 #define DAD_TIMEOUT (MSEC_PER_SEC / 5U)
623
ZTEST(net_mld_test_suite,test_allnodes)624 ZTEST(net_mld_test_suite, test_allnodes)
625 {
626 struct net_if *iface = NULL;
627 struct net_if_mcast_addr *ifmaddr;
628 struct in6_addr addr;
629
630 net_ipv6_addr_create_ll_allnodes_mcast(&addr);
631
632 /* Let the DAD succeed so that the multicast address will be there */
633 k_sleep(K_MSEC(DAD_TIMEOUT));
634
635 ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface);
636
637 zassert_not_null(ifmaddr, "Interface does not contain "
638 "allnodes multicast address");
639 }
640
expect_exclude_mcast_report(struct net_pkt * pkt,void * user_data)641 static void expect_exclude_mcast_report(struct net_pkt *pkt, void *user_data)
642 {
643 struct mld_report_mcast_record record;
644 uint16_t records_count;
645 uint16_t res_bytes;
646 bool *report_sent = user_data;
647
648 zassert_not_null(exp_mcast_group, "Expected mcast group not sent");
649
650 net_pkt_set_overwrite(pkt, true);
651 net_pkt_skip(pkt, sizeof(struct net_icmp_hdr));
652
653 zassert_ok(net_pkt_read_be16(pkt, &res_bytes), "Failed to read reserved bytes");
654 zassert_equal(0, res_bytes, "Reserved bytes must be zeroed");
655
656 zassert_ok(net_pkt_read_be16(pkt, &records_count), "Failed to read addr count");
657 zexpect_equal(records_count, 1, "Incorrect record count ");
658
659 net_pkt_read(pkt, &record, sizeof(struct mld_report_mcast_record));
660
661 if (record.record_type == NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE &&
662 net_ipv6_addr_cmp_raw((const uint8_t *)exp_mcast_group,
663 (const uint8_t *)&record.mcast_addr)) {
664 *report_sent = true;
665 }
666 }
667
verify_allnodes_on_iface_event(void (* action)(void))668 static void verify_allnodes_on_iface_event(void (*action)(void))
669 {
670 struct net_if *iface = NULL;
671 struct net_if_mcast_addr *ifmaddr;
672 struct in6_addr addr;
673 bool exclude_report_sent = false;
674 struct mld_report_handler handler = {
675 .fn = expect_exclude_mcast_report,
676 .user_data = &exclude_report_sent
677 };
678
679 net_ipv6_addr_create_ll_allnodes_mcast(&addr);
680 k_sem_reset(&wait_joined);
681
682 is_group_joined = false;
683 exp_mcast_group = &addr;
684 report_handler = &handler;
685
686 action();
687
688 zassert_ok(k_sem_take(&wait_joined, K_MSEC(WAIT_TIME)),
689 "Timeout while waiting for an event");
690
691 ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface);
692 zassert_not_null(ifmaddr, "Interface does not contain "
693 "allnodes multicast address");
694
695 zassert_true(is_group_joined, "Did not join mcast group");
696 zassert_true(exclude_report_sent, "Did not send report");
697 }
698
699 /* Verify that mcast all nodes is present after interface admin state toggle */
ZTEST(net_mld_test_suite,test_allnodes_after_iface_up)700 ZTEST(net_mld_test_suite, test_allnodes_after_iface_up)
701 {
702 verify_allnodes_on_iface_event(test_iface_down_up);
703 }
704
705 /* Verify that mcast all nodes is present after delayed carrier on */
ZTEST(net_mld_test_suite,test_allnodes_after_iface_up_carrier_delayed)706 ZTEST(net_mld_test_suite, test_allnodes_after_iface_up_carrier_delayed)
707 {
708 verify_allnodes_on_iface_event(test_iface_down_up_delayed_carrier);
709 }
710
711 /* Verify that mcast all nodes is present after carrier toggle */
ZTEST(net_mld_test_suite,test_allnodes_after_carrier_toggle)712 ZTEST(net_mld_test_suite, test_allnodes_after_carrier_toggle)
713 {
714 verify_allnodes_on_iface_event(test_iface_carrier_off_on);
715 }
716
ZTEST(net_mld_test_suite,test_solicit_node)717 ZTEST(net_mld_test_suite, test_solicit_node)
718 {
719 struct net_if *iface = NULL;
720 struct net_if_mcast_addr *ifmaddr;
721 struct in6_addr addr;
722
723 net_ipv6_addr_create_solicited_node(&my_addr, &addr);
724
725 ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface);
726
727 zassert_not_null(ifmaddr, "Interface does not contain "
728 "solicit node multicast address");
729 }
730
verify_solicit_node_on_iface_event(void (* action)(void))731 static void verify_solicit_node_on_iface_event(void (*action)(void))
732 {
733 struct net_if *iface = NULL;
734 struct net_if_mcast_addr *ifmaddr;
735 struct in6_addr addr;
736 bool exclude_report_sent = false;
737 struct mld_report_handler handler = {
738 .fn = expect_exclude_mcast_report,
739 .user_data = &exclude_report_sent
740 };
741
742 net_ipv6_addr_create_solicited_node(&my_addr, &addr);
743 k_sem_reset(&wait_joined);
744
745 is_group_joined = false;
746 exp_mcast_group = &addr;
747 report_handler = &handler;
748
749 action();
750
751 zassert_ok(k_sem_take(&wait_joined, K_MSEC(WAIT_TIME)),
752 "Timeout while waiting for an event");
753
754 ifmaddr = net_if_ipv6_maddr_lookup(&addr, &iface);
755 zassert_not_null(ifmaddr, "Interface does not contain "
756 "solicit node multicast address");
757
758 zassert_true(is_group_joined, "Did not join mcast group");
759 zassert_true(exclude_report_sent, "Did not send report");
760 }
761
762 /* Verify that mcast solicited node is present after interface admin state toggle */
ZTEST(net_mld_test_suite,test_solicit_node_after_iface_up)763 ZTEST(net_mld_test_suite, test_solicit_node_after_iface_up)
764 {
765 verify_solicit_node_on_iface_event(test_iface_down_up);
766 }
767
768 /* Verify that mcast solicited node is present after delayed carrier on */
ZTEST(net_mld_test_suite,test_solicit_node_after_iface_up_carrier_delayed)769 ZTEST(net_mld_test_suite, test_solicit_node_after_iface_up_carrier_delayed)
770 {
771 verify_solicit_node_on_iface_event(test_iface_down_up_delayed_carrier);
772 }
773
774 /* Verify that mcast solicited node is present after delayed carrier toggle */
ZTEST(net_mld_test_suite,test_solicit_node_after_carrier_toggle)775 ZTEST(net_mld_test_suite, test_solicit_node_after_carrier_toggle)
776 {
777 verify_solicit_node_on_iface_event(test_iface_carrier_off_on);
778 }
779
ZTEST(net_mld_test_suite,test_join_leave)780 ZTEST(net_mld_test_suite, test_join_leave)
781 {
782 test_join_group();
783 test_leave_group();
784 }
785
ZTEST(net_mld_test_suite,test_catch_join_leave)786 ZTEST(net_mld_test_suite, test_catch_join_leave)
787 {
788 test_catch_join_group();
789 test_catch_leave_group();
790 }
791
ZTEST(net_mld_test_suite,test_verify_join_leave)792 ZTEST(net_mld_test_suite, test_verify_join_leave)
793 {
794 test_verify_join_group();
795 test_verify_leave_group();
796 test_catch_query();
797 test_verify_send_report();
798 }
799
ZTEST(net_mld_test_suite,test_no_mld_flag)800 ZTEST(net_mld_test_suite, test_no_mld_flag)
801 {
802 int ret;
803
804 is_join_msg_ok = false;
805 is_leave_msg_ok = false;
806
807 net_if_flag_set(net_iface, NET_IF_IPV6_NO_MLD);
808
809 /* Using adhoc multicast group outside standard range */
810 net_ipv6_addr_create(&mcast_addr, 0xff10, 0, 0, 0, 0, 0, 0, 0x0001);
811
812 ret = net_ipv6_mld_join(net_iface, &mcast_addr);
813 zassert_equal(ret, 0, "Cannot add multicast address");
814
815 /* Let the network stack to proceed */
816 k_msleep(THREAD_SLEEP);
817
818 zassert_false(is_join_msg_ok, "Received join message when not expected");
819
820 ret = net_ipv6_mld_leave(net_iface, &mcast_addr);
821 zassert_equal(ret, 0, "Cannot remove multicast address");
822
823 /* Let the network stack to proceed */
824 k_msleep(THREAD_SLEEP);
825
826 zassert_false(is_leave_msg_ok, "Received leave message when not expected");
827
828 net_if_flag_clear(net_iface, NET_IF_IPV6_NO_MLD);
829 }
830
handle_mld_report(struct net_pkt * pkt,void * user_data)831 static void handle_mld_report(struct net_pkt *pkt, void *user_data)
832 {
833 struct mld_report_info *info = (struct mld_report_info *)user_data;
834 uint16_t res_bytes;
835
836 net_pkt_set_overwrite(pkt, true);
837 net_pkt_skip(pkt, sizeof(struct net_icmp_hdr));
838
839 zassert_ok(net_pkt_read_be16(pkt, &res_bytes), "Failed to read reserved bytes");
840 zassert_equal(0, res_bytes, "Reserved bytes must be zeroed");
841
842 zassert_ok(net_pkt_read_be16(pkt, &info->records_count), "Failed to read addr count");
843 zexpect_between_inclusive(info->records_count, 0, MLD_REPORT_ADDR_COUNT,
844 "Cannot decode all addresses");
845
846 for (size_t i = 0; i < info->records_count; ++i) {
847 net_pkt_read(pkt, &info->records[i], sizeof(struct mld_report_mcast_record));
848 }
849 }
850
get_mcast_addr_count(struct net_if * iface)851 static size_t get_mcast_addr_count(struct net_if *iface)
852 {
853 size_t ret = 0;
854
855 ARRAY_FOR_EACH_PTR(iface->config.ip.ipv6->mcast, mcast_addr) {
856 if (mcast_addr->is_used) {
857 ret++;
858 }
859 }
860
861 return ret;
862 }
863
add_mcast_route_and_verify(struct net_if * iface,struct in6_addr * addr,struct mld_report_info * info)864 static void add_mcast_route_and_verify(struct net_if *iface, struct in6_addr *addr,
865 struct mld_report_info *info)
866 {
867 k_sem_reset(&wait_data);
868
869 zassert_not_null(net_route_mcast_add(iface, addr, 128), "Failed to add multicast route");
870
871 k_msleep(THREAD_SLEEP);
872
873 zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report");
874
875 zassert_equal(info->records_count, 1, "Invalid number of reported addresses");
876 zassert_equal(info->records[0].record_type, NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE,
877 "Invalid MLDv2 record type");
878 zassert_mem_equal(&info->records[0].mcast_addr, addr,
879 sizeof(struct in6_addr), "Invalid reported address");
880 }
881
del_mcast_route_and_verify(struct net_if * iface,struct in6_addr * addr,struct mld_report_info * info)882 static void del_mcast_route_and_verify(struct net_if *iface, struct in6_addr *addr,
883 struct mld_report_info *info)
884 {
885 struct net_route_entry_mcast *entry;
886
887 k_sem_reset(&wait_data);
888
889 entry = net_route_mcast_lookup(addr);
890
891 zassert_not_null(entry, "Could not find the multicast route entry");
892 zassert_true(net_route_mcast_del(entry), "Failed to delete a route");
893
894 k_msleep(THREAD_SLEEP);
895
896 zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report");
897
898 zassert_equal(info->records_count, 1, "Invalid number of reported addresses");
899 zassert_equal(info->records[0].record_type, NET_IPV6_MLDv2_CHANGE_TO_INCLUDE_MODE,
900 "Invalid MLDv2 record type");
901 zassert_mem_equal(&info->records[0].mcast_addr, addr,
902 sizeof(struct in6_addr), "Invalid reported address");
903 }
904
verify_mcast_routes_in_mld(struct mld_report_info * info)905 static void verify_mcast_routes_in_mld(struct mld_report_info *info)
906 {
907 struct net_if *dummy_iface = net_if_get_by_index(net_if_get_by_name("dummy0"));
908 struct net_if *null_iface = net_if_get_by_index(net_if_get_by_name("dummy1"));
909 struct in6_addr site_local_mcast_addr_abcd;
910 struct in6_addr site_local_mcast_addr_beef;
911 struct in6_addr site_local_mcast_addr_cafe;
912
913 zassert_not_null(dummy_iface, "Invalid dummy iface");
914 zassert_not_null(null_iface, "Invalid null iface");
915
916 net_if_flag_set(null_iface, NET_IF_FORWARD_MULTICASTS);
917
918 net_ipv6_addr_create(&site_local_mcast_addr_abcd, 0xff05, 0, 0, 0, 0, 0, 0, 0xabcd);
919 net_ipv6_addr_create(&site_local_mcast_addr_beef, 0xff05, 0, 0, 0, 0, 0, 0, 0xbeef);
920 net_ipv6_addr_create(&site_local_mcast_addr_cafe, 0xff05, 0, 0, 0, 0, 0, 0, 0xcafe);
921
922 /* Next steps: verify that adding a multicast routes to a complete IPv6 address emits
923 * MLDv2 reports with a single entries.
924 */
925 add_mcast_route_and_verify(null_iface, &site_local_mcast_addr_abcd, info);
926 add_mcast_route_and_verify(null_iface, &site_local_mcast_addr_beef, info);
927
928 /* Next steps: verify that report is not sent to an iface if it has already joined
929 * the group.
930 */
931 zassert_ok(net_ipv6_mld_join(dummy_iface, &site_local_mcast_addr_cafe),
932 "Failed to join a group");
933
934 k_msleep(THREAD_SLEEP);
935
936 k_sem_reset(&wait_data);
937
938 zassert_not_null(net_route_mcast_add(null_iface, &site_local_mcast_addr_cafe, 128),
939 "Failed to add multicast route");
940
941 k_msleep(THREAD_SLEEP);
942
943 zassert_equal(-EAGAIN, k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a timeout");
944
945 k_sem_reset(&wait_data);
946
947 /* Verify that multicast routes can be found in MLDv2 report and that there are
948 * no duplicates.
949 */
950 send_query(dummy_iface);
951
952 k_msleep(THREAD_SLEEP);
953
954 zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a report");
955
956 /* Expect 2 additional addresses as 3rd is a duplicate of iface's multicast address */
957 zassert_equal(info->records_count, get_mcast_addr_count(dummy_iface) + 2,
958 "Different number of reported addresses");
959
960 /* Next steps: Remove routes and expect MLDv2 reports as these addresses are not
961 * used by the interface.
962 */
963 del_mcast_route_and_verify(dummy_iface, &site_local_mcast_addr_abcd, info);
964 del_mcast_route_and_verify(dummy_iface, &site_local_mcast_addr_beef, info);
965
966 /* Next steps: Remove the last route and verify that report is NOT sent as this address
967 * is joined by the interface itself.
968 */
969 k_sem_reset(&wait_data);
970
971 zassert_true(net_route_mcast_del(net_route_mcast_lookup(&site_local_mcast_addr_cafe)),
972 "Failed to cleanup route to ff05::cafe");
973
974 k_msleep(THREAD_SLEEP);
975
976 zassert_equal(-EAGAIN, k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Expected a timeout");
977
978 /* Finalize cleanup */
979 net_ipv6_mld_leave(dummy_iface, &site_local_mcast_addr_cafe);
980 }
981
ZTEST(net_mld_test_suite,test_mcast_routes_in_mld)982 ZTEST(net_mld_test_suite, test_mcast_routes_in_mld)
983 {
984 struct mld_report_info info;
985 struct mld_report_handler handler = { .fn = handle_mld_report, .user_data = &info};
986 struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
987 char str[INET6_ADDRSTRLEN], *addr_str;
988
989 memset(&info, 0, sizeof(info));
990
991 join_mldv2_capable_routers_group();
992
993 /* Enable report handler */
994 report_handler = &handler;
995
996 k_msleep(THREAD_SLEEP);
997
998 k_sem_reset(&wait_data);
999
1000 send_query(iface);
1001
1002 k_msleep(THREAD_SLEEP);
1003
1004 zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting for a report");
1005
1006 for (int i = 0; i < info.records_count; ++i) {
1007 addr_str = zsock_inet_ntop(AF_INET6, &info.records[i].mcast_addr, str, sizeof(str));
1008 }
1009
1010 /* 1. Expect that report contains all iface's multicast addressses and no route */
1011 zassert_equal(info.records_count, get_mcast_addr_count(iface),
1012 "Different number of reported addresses");
1013
1014 /* 2. If CONFIG_NET_MCAST_ROUTE_MLD_REPORTS is enabled check that funtionality works */
1015 if (IS_ENABLED(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS)) {
1016 verify_mcast_routes_in_mld(&info);
1017 }
1018
1019 leave_mldv2_capable_routers_group();
1020 }
1021
socket_group_with_index(const struct in6_addr * local_addr,bool do_join)1022 static void socket_group_with_index(const struct in6_addr *local_addr, bool do_join)
1023 {
1024 struct ipv6_mreq mreq = { 0 };
1025 int option;
1026 int ret, fd;
1027
1028 if (do_join) {
1029 option = IPV6_ADD_MEMBERSHIP;
1030 } else {
1031 option = IPV6_DROP_MEMBERSHIP;
1032 }
1033
1034 fd = zsock_socket(AF_INET6, SOCK_DGRAM, 0);
1035 zassert_true(fd >= 0, "Cannot get socket (%d)", -errno);
1036
1037 ret = zsock_setsockopt(fd, IPPROTO_IPV6, option,
1038 NULL, sizeof(mreq));
1039 zassert_true(ret == -1 && errno == EINVAL,
1040 "Incorrect return value (%d)", -errno);
1041
1042 ret = zsock_setsockopt(fd, IPPROTO_IPV6, option,
1043 (void *)&mreq, 1);
1044 zassert_true(ret == -1 && errno == EINVAL,
1045 "Incorrect return value (%d)", -errno);
1046
1047 /* First try with empty mreq */
1048 ret = zsock_setsockopt(fd, IPPROTO_IPV6, option,
1049 (void *)&mreq, sizeof(mreq));
1050 zassert_true(ret == -1 && errno == EINVAL,
1051 "Incorrect return value (%d)", -errno);
1052
1053 mreq.ipv6mr_ifindex = net_if_ipv6_addr_lookup_by_index(local_addr);
1054 memcpy(&mreq.ipv6mr_multiaddr, &mcast_addr,
1055 sizeof(mreq.ipv6mr_multiaddr));
1056
1057 ret = zsock_setsockopt(fd, IPPROTO_IPV6, option,
1058 (void *)&mreq, sizeof(mreq));
1059
1060 if (do_join) {
1061 if (ignore_already) {
1062 zassert_true(ret == 0 || ret == -EALREADY,
1063 "Cannot join IPv6 multicast group (%d)",
1064 -errno);
1065 } else {
1066 zassert_equal(ret, 0,
1067 "Cannot join IPv6 multicast group (%d)",
1068 -errno);
1069 }
1070 } else {
1071 zassert_equal(ret, 0, "Cannot leave IPv6 multicast group (%d)",
1072 -errno);
1073
1074 if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) {
1075 /* Let the network stack to proceed */
1076 k_msleep(THREAD_SLEEP);
1077 } else {
1078 k_yield();
1079 }
1080 }
1081
1082 zsock_close(fd);
1083
1084 /* Let the network stack to proceed */
1085 k_msleep(THREAD_SLEEP);
1086 }
1087
socket_join_group_with_index(const struct in6_addr * addr)1088 static void socket_join_group_with_index(const struct in6_addr *addr)
1089 {
1090 socket_group_with_index(addr, true);
1091 }
1092
socket_leave_group_with_index(const struct in6_addr * addr)1093 static void socket_leave_group_with_index(const struct in6_addr *addr)
1094 {
1095 socket_group_with_index(addr, false);
1096 }
1097
ZTEST_USER(net_mld_test_suite,test_socket_catch_join_with_index)1098 ZTEST_USER(net_mld_test_suite, test_socket_catch_join_with_index)
1099 {
1100 socket_join_group_with_index(net_ipv6_unspecified_address());
1101 socket_leave_group_with_index(net_ipv6_unspecified_address());
1102 socket_join_group_with_index(&my_addr);
1103 socket_leave_group_with_index(&my_addr);
1104 }
1105
1106 ZTEST_SUITE(net_mld_test_suite, NULL, test_mld_setup, test_mld_before, NULL, NULL);
1107