1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright (c) 2021 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_IPV4_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/net_if.h>
22 #include <zephyr/net/net_pkt.h>
23 #include <zephyr/net/net_ip.h>
24 #include <zephyr/net/net_core.h>
25 #include <zephyr/net/ethernet.h>
26 #include <zephyr/net/dummy.h>
27 #include <zephyr/net/net_mgmt.h>
28 #include <zephyr/net/net_event.h>
29 #include <zephyr/net/igmp.h>
30 #include <zephyr/net/socket.h>
31 
32 #include <zephyr/random/random.h>
33 
34 #include "ipv4.h"
35 #include "igmp.h"
36 
37 #define THREAD_SLEEP 50 /* ms */
38 
39 #define NET_LOG_ENABLED 1
40 #include "net_private.h"
41 
42 #if defined(CONFIG_NET_IPV4_LOG_LEVEL_DBG)
43 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
44 #else
45 #define DBG(fmt, ...)
46 #endif
47 
48 static const unsigned char igmp_v2_query[] = {
49 	/* IPv4 header */
50 	0x46, 0xc0, 0x00, 0x20, 0x1b, 0x58, 0x00, 0x00, 0x01, 0x02, 0x66, 0x79,
51 	0xc0, 0x00, 0x02, 0x45, 0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00,
52 
53 	/* IGMP header */
54 	0x11, 0xff, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00,
55 };
56 
57 static const unsigned char igmp_v3_query[] = {
58 	/* IPv4 header */
59 	0x46, 0xc0, 0x00, 0x24, 0xac, 0x72, 0x00, 0x00, 0x01, 0x02, 0xd5, 0x5a,
60 	0xc0, 0x00, 0x02, 0x45, 0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00,
61 
62 	/* IGMP header */
63 	0x11, 0x64, 0xec, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x02, 0x7d, 0x00, 0x00,
64 };
65 
66 static struct in_addr my_addr = { { { 192, 0, 2, 1 } } };
67 static struct in_addr mcast_addr = { { { 224, 0, 2, 63 } } };
68 static struct in_addr any_addr = INADDR_ANY_INIT;
69 
70 static struct net_if *net_iface;
71 static bool is_group_joined;
72 static bool is_group_left;
73 static bool is_join_msg_ok;
74 static bool is_leave_msg_ok;
75 static bool is_query_received;
76 static bool is_report_sent;
77 static bool is_igmpv2_query_sent;
78 static bool is_igmpv3_query_sent;
79 static bool ignore_already;
80 K_SEM_DEFINE(wait_data, 0, UINT_MAX);
81 
82 #define WAIT_TIME 500
83 #define WAIT_TIME_LONG MSEC_PER_SEC
84 #define MY_PORT 1969
85 #define PEER_PORT 13856
86 
87 struct net_test_igmp {
88 	uint8_t mac_addr[sizeof(struct net_eth_addr)];
89 	struct net_linkaddr ll_addr;
90 };
91 
net_test_dev_init(const struct device * dev)92 int net_test_dev_init(const struct device *dev)
93 {
94 	return 0;
95 }
96 
net_test_get_mac(const struct device * dev)97 static uint8_t *net_test_get_mac(const struct device *dev)
98 {
99 	struct net_test_igmp *context = dev->data;
100 
101 	if (context->mac_addr[2] == 0x00) {
102 		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
103 		context->mac_addr[0] = 0x00;
104 		context->mac_addr[1] = 0x00;
105 		context->mac_addr[2] = 0x5E;
106 		context->mac_addr[3] = 0x00;
107 		context->mac_addr[4] = 0x53;
108 		context->mac_addr[5] = sys_rand8_get();
109 	}
110 
111 	return context->mac_addr;
112 }
113 
net_test_iface_init(struct net_if * iface)114 static void net_test_iface_init(struct net_if *iface)
115 {
116 	uint8_t *mac = net_test_get_mac(net_if_get_device(iface));
117 
118 	net_if_set_link_addr(iface, mac, sizeof(struct net_eth_addr),
119 			     NET_LINK_ETHERNET);
120 }
121 
122 #if defined(CONFIG_NET_IPV4_IGMPV3)
get_igmp_hdr(struct net_pkt * pkt)123 static struct net_ipv4_igmp_v3_report *get_igmp_hdr(struct net_pkt *pkt)
124 #else
125 static struct net_ipv4_igmp_v2_query *get_igmp_hdr(struct net_pkt *pkt)
126 #endif
127 {
128 	net_pkt_cursor_init(pkt);
129 
130 	net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) +
131 		     net_pkt_ipv4_opts_len(pkt));
132 
133 #if defined(CONFIG_NET_IPV4_IGMPV3)
134 	return (struct net_ipv4_igmp_v3_report *)net_pkt_cursor_get_pos(pkt);
135 #else
136 	return (struct net_ipv4_igmp_v2_query *)net_pkt_cursor_get_pos(pkt);
137 #endif
138 }
139 
140 #if defined(CONFIG_NET_IPV4_IGMPV3)
get_igmp_group_record(struct net_pkt * pkt)141 static struct net_ipv4_igmp_v3_group_record *get_igmp_group_record(struct net_pkt *pkt)
142 {
143 	net_pkt_cursor_init(pkt);
144 
145 	net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) + net_pkt_ipv4_opts_len(pkt));
146 	net_pkt_skip(pkt, sizeof(struct net_ipv4_igmp_v3_report));
147 
148 	return (struct net_ipv4_igmp_v3_group_record *)net_pkt_cursor_get_pos(pkt);
149 }
150 #endif
151 
tester_send(const struct device * dev,struct net_pkt * pkt)152 static int tester_send(const struct device *dev, struct net_pkt *pkt)
153 {
154 #if defined(CONFIG_NET_IPV4_IGMPV3)
155 	struct net_ipv4_igmp_v3_report *igmp_header;
156 	struct net_ipv4_igmp_v3_group_record *igmp_group_record;
157 #else
158 	struct net_ipv4_igmp_v2_query *igmp_header;
159 #endif
160 
161 	if (!pkt->buffer) {
162 		TC_ERROR("No data to send!\n");
163 		return -ENODATA;
164 	}
165 
166 	igmp_header = get_igmp_hdr(pkt);
167 
168 	if (igmp_header->type == NET_IPV4_IGMP_QUERY) {
169 		NET_DBG("Received query....");
170 		is_query_received = true;
171 		k_sem_give(&wait_data);
172 	} else if (igmp_header->type == NET_IPV4_IGMP_REPORT_V2) {
173 		NET_DBG("Received v2 report....");
174 		zassert_true(!IS_ENABLED(CONFIG_NET_IPV4_IGMPV3) || is_igmpv2_query_sent,
175 			     "Wrong IGMP report received (IGMPv2)");
176 		is_join_msg_ok = true;
177 		is_report_sent = true;
178 		k_sem_give(&wait_data);
179 	} else if (igmp_header->type == NET_IPV4_IGMP_REPORT_V3) {
180 		NET_DBG("Received v3 report....");
181 		zassert_true(IS_ENABLED(CONFIG_NET_IPV4_IGMPV3),
182 			     "Wrong IGMP report received (IGMPv3)");
183 		zassert_false(is_igmpv2_query_sent, "IGMPv3 response to IGMPv2 request");
184 
185 #if defined(CONFIG_NET_IPV4_IGMPV3)
186 		zassert_equal(ntohs(igmp_header->groups_len), 1,
187 			      "Invalid group length of IGMPv3 report (%d)",
188 			      igmp_header->groups_len);
189 
190 		igmp_group_record = get_igmp_group_record(pkt);
191 		zassert_equal(igmp_group_record->sources_len, 0,
192 			      "Invalid sources length of IGMPv3 group record");
193 
194 		if (igmp_group_record->type == IGMPV3_CHANGE_TO_EXCLUDE_MODE) {
195 			is_join_msg_ok = true;
196 		} else if (igmp_group_record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE) {
197 			is_leave_msg_ok = true;
198 		}
199 #else
200 		is_join_msg_ok = true;
201 #endif
202 		is_report_sent = true;
203 		k_sem_give(&wait_data);
204 	} else if (igmp_header->type == NET_IPV4_IGMP_LEAVE) {
205 		NET_DBG("Received leave....");
206 		is_leave_msg_ok = true;
207 		k_sem_give(&wait_data);
208 	}
209 
210 	return 0;
211 }
212 
213 struct net_test_igmp net_test_data;
214 
215 static struct dummy_api net_test_if_api = {
216 	.iface_api.init = net_test_iface_init,
217 	.send = tester_send,
218 };
219 
220 #define _ETH_L2_LAYER DUMMY_L2
221 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
222 
223 NET_DEVICE_INIT(net_test_igmp, "net_test_igmp",
224 		net_test_dev_init, NULL, &net_test_data, NULL,
225 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
226 		&net_test_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE,
227 		127);
228 
group_joined(struct net_mgmt_event_callback * cb,uint32_t nm_event,struct net_if * iface)229 static void group_joined(struct net_mgmt_event_callback *cb,
230 			 uint32_t nm_event, struct net_if *iface)
231 {
232 	if (nm_event != NET_EVENT_IPV4_MCAST_JOIN) {
233 		/* Spurious callback. */
234 		return;
235 	}
236 
237 	is_group_joined = true;
238 
239 	k_sem_give(&wait_data);
240 }
241 
group_left(struct net_mgmt_event_callback * cb,uint32_t nm_event,struct net_if * iface)242 static void group_left(struct net_mgmt_event_callback *cb,
243 			 uint32_t nm_event, struct net_if *iface)
244 {
245 	if (nm_event != NET_EVENT_IPV4_MCAST_LEAVE) {
246 		/* Spurious callback. */
247 		return;
248 	}
249 
250 	is_group_left = true;
251 
252 	k_sem_give(&wait_data);
253 }
254 
255 static struct mgmt_events {
256 	uint32_t event;
257 	net_mgmt_event_handler_t handler;
258 	struct net_mgmt_event_callback cb;
259 } mgmt_events[] = {
260 	{ .event = NET_EVENT_IPV4_MCAST_JOIN, .handler = group_joined },
261 	{ .event = NET_EVENT_IPV4_MCAST_LEAVE, .handler = group_left },
262 	{ 0 }
263 };
264 
setup_mgmt_events(void)265 static void setup_mgmt_events(void)
266 {
267 	int i;
268 
269 	for (i = 0; mgmt_events[i].event; i++) {
270 		net_mgmt_init_event_callback(&mgmt_events[i].cb,
271 					     mgmt_events[i].handler,
272 					     mgmt_events[i].event);
273 
274 		net_mgmt_add_event_callback(&mgmt_events[i].cb);
275 	}
276 }
277 
igmp_setup(void)278 static void *igmp_setup(void)
279 {
280 	struct net_if_addr *ifaddr;
281 
282 	setup_mgmt_events();
283 
284 	net_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
285 
286 	zassert_not_null(net_iface, "Interface is NULL");
287 
288 	ifaddr = net_if_ipv4_addr_add(net_iface, &my_addr, NET_ADDR_MANUAL, 0);
289 
290 	zassert_not_null(ifaddr, "Cannot add IPv4 address");
291 
292 	return NULL;
293 }
294 
igmp_teardown(void * dummy)295 static void igmp_teardown(void *dummy)
296 {
297 	ARG_UNUSED(dummy);
298 
299 	int i;
300 
301 	for (i = 0; mgmt_events[i].event; i++) {
302 		net_mgmt_del_event_callback(&mgmt_events[i].cb);
303 	}
304 
305 	net_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
306 
307 	net_if_ipv4_addr_rm(net_iface, &my_addr);
308 }
309 
prepare_igmp_query(struct net_if * iface,bool is_igmpv3)310 static struct net_pkt *prepare_igmp_query(struct net_if *iface, bool is_igmpv3)
311 {
312 	struct net_pkt *pkt;
313 
314 	const unsigned char *igmp_query = is_igmpv3 ? igmp_v3_query : igmp_v2_query;
315 	size_t igmp_query_size = is_igmpv3 ? sizeof(igmp_v3_query) : sizeof(igmp_v2_query);
316 
317 	pkt = net_pkt_alloc_with_buffer(iface, igmp_query_size, AF_INET, IPPROTO_IGMP, K_FOREVER);
318 	zassert_not_null(pkt, "Failed to allocate buffer");
319 
320 	zassert_ok(net_pkt_write(pkt, igmp_query, igmp_query_size));
321 
322 	net_pkt_set_overwrite(pkt, true);
323 	net_pkt_cursor_init(pkt);
324 
325 	return pkt;
326 }
327 
join_group(void)328 static void join_group(void)
329 {
330 	int ret;
331 
332 	ret = net_ipv4_igmp_join(net_iface, &mcast_addr, NULL);
333 
334 	if (ignore_already) {
335 		zassert_true(ret == 0 || ret == -EALREADY,
336 			     "Cannot join IPv4 multicast group");
337 	} else {
338 		zassert_ok(ret, "Cannot join IPv4 multicast group");
339 	}
340 
341 	/* Let the network stack to proceed */
342 	k_msleep(THREAD_SLEEP);
343 }
344 
leave_group(void)345 static void leave_group(void)
346 {
347 	int ret;
348 
349 	ret = net_ipv4_igmp_leave(net_iface, &mcast_addr);
350 
351 	zassert_ok(ret, "Cannot leave IPv4 multicast group");
352 
353 	if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) {
354 		/* Let the network stack to proceed */
355 		k_msleep(THREAD_SLEEP);
356 	} else {
357 		k_yield();
358 	}
359 }
360 
catch_join_group(void)361 static void catch_join_group(void)
362 {
363 	is_group_joined = false;
364 
365 	ignore_already = false;
366 
367 	join_group();
368 
369 	zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting join event");
370 
371 	zassert_true(is_group_joined, "Did not catch join event");
372 
373 	is_group_joined = false;
374 }
375 
catch_leave_group(void)376 static void catch_leave_group(void)
377 {
378 	is_group_joined = false;
379 
380 	leave_group();
381 
382 	zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting leave event");
383 
384 	zassert_true(is_group_left, "Did not catch leave event");
385 
386 	is_group_left = false;
387 }
388 
verify_join_group(void)389 static void verify_join_group(void)
390 {
391 	is_join_msg_ok = false;
392 
393 	ignore_already = false;
394 
395 	join_group();
396 
397 	zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting join event");
398 
399 	zassert_true(is_join_msg_ok, "Join msg invalid");
400 
401 	is_join_msg_ok = false;
402 }
403 
verify_leave_group(void)404 static void verify_leave_group(void)
405 {
406 	is_leave_msg_ok = false;
407 
408 	leave_group();
409 
410 	zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting leave event");
411 
412 	zassert_true(is_leave_msg_ok, "Leave msg invalid");
413 
414 	is_leave_msg_ok = false;
415 }
416 
ZTEST(net_igmp,test_igmp_catch_join)417 ZTEST(net_igmp, test_igmp_catch_join)
418 {
419 	join_group();
420 	leave_group();
421 }
422 
ZTEST(net_igmp,test_igmp_catch_catch_join)423 ZTEST(net_igmp, test_igmp_catch_catch_join)
424 {
425 	catch_join_group();
426 	catch_leave_group();
427 }
428 
ZTEST(net_igmp,test_igmp_verify_catch_join)429 ZTEST(net_igmp, test_igmp_verify_catch_join)
430 {
431 	verify_join_group();
432 	verify_leave_group();
433 }
434 
socket_group_with_address(struct in_addr * local_addr,bool do_join)435 static void socket_group_with_address(struct in_addr *local_addr, bool do_join)
436 {
437 	struct ip_mreqn mreqn = { 0 };
438 	int option;
439 	int ret, fd;
440 
441 	if (do_join) {
442 		option = IP_ADD_MEMBERSHIP;
443 	} else {
444 		option = IP_DROP_MEMBERSHIP;
445 	}
446 
447 	fd = zsock_socket(AF_INET, SOCK_DGRAM, 0);
448 	zassert_true(fd >= 0, "Cannot get socket (%d)", -errno);
449 
450 	ret = zsock_setsockopt(fd, IPPROTO_IP, option,
451 			       NULL, sizeof(mreqn));
452 	zassert_equal(ret, -1, "Incorrect return value (%d)", ret);
453 	zassert_equal(errno, EINVAL, "Incorrect errno value (%d)", -errno);
454 
455 	ret = zsock_setsockopt(fd, IPPROTO_IP, option,
456 			       (void *)&mreqn, 1);
457 	zassert_equal(ret, -1, "Incorrect return value (%d)", ret);
458 	zassert_equal(errno, EINVAL, "Incorrect errno value (%d)", -errno);
459 
460 	/* First try with empty mreqn */
461 	ret = zsock_setsockopt(fd, IPPROTO_IP, option,
462 			       (void *)&mreqn, sizeof(mreqn));
463 	zassert_equal(ret, -1, "Incorrect return value (%d)", ret);
464 	zassert_equal(errno, EINVAL, "Incorrect errno value (%d)", -errno);
465 
466 	memcpy(&mreqn.imr_address, local_addr, sizeof(mreqn.imr_address));
467 	memcpy(&mreqn.imr_multiaddr, &mcast_addr, sizeof(mreqn.imr_multiaddr));
468 
469 	ret = zsock_setsockopt(fd, IPPROTO_IP, option,
470 			       (void *)&mreqn, sizeof(mreqn));
471 
472 	if (do_join) {
473 		if (ignore_already) {
474 			zassert_true(ret == 0 || ret == -EALREADY,
475 				     "Cannot join IPv4 multicast group (%d)", -errno);
476 		} else {
477 			zassert_ok(ret,
478 				   "Cannot join IPv4 multicast group (%d) "
479 				   "with local addr %s",
480 				   -errno, net_sprint_ipv4_addr(local_addr));
481 		}
482 	} else {
483 		zassert_ok(ret, "Cannot leave IPv4 multicast group (%d)", -errno);
484 
485 		if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) {
486 			/* Let the network stack to proceed */
487 			k_msleep(THREAD_SLEEP);
488 		} else {
489 			k_yield();
490 		}
491 	}
492 
493 	zsock_close(fd);
494 
495 	/* Let the network stack to proceed */
496 	k_msleep(THREAD_SLEEP);
497 }
498 
socket_group_with_index(struct in_addr * local_addr,bool do_join)499 static void socket_group_with_index(struct in_addr *local_addr, bool do_join)
500 {
501 	struct ip_mreqn mreqn = { 0 };
502 	int option;
503 	int ret, fd;
504 
505 	if (do_join) {
506 		option = IP_ADD_MEMBERSHIP;
507 	} else {
508 		option = IP_DROP_MEMBERSHIP;
509 	}
510 
511 	fd = zsock_socket(AF_INET, SOCK_DGRAM, 0);
512 	zassert_true(fd >= 0, "Cannot get socket (%d)", -errno);
513 
514 	mreqn.imr_ifindex = net_if_ipv4_addr_lookup_by_index(local_addr);
515 	memcpy(&mreqn.imr_multiaddr, &mcast_addr, sizeof(mreqn.imr_multiaddr));
516 
517 	ret = zsock_setsockopt(fd, IPPROTO_IP, option,
518 			       (void *)&mreqn, sizeof(mreqn));
519 
520 	if (do_join) {
521 		if (ignore_already) {
522 			zassert_true(ret == 0 || ret == -EALREADY,
523 				     "Cannot join IPv4 multicast group (%d)", -errno);
524 		} else {
525 			zassert_ok(ret, "Cannot join IPv4 multicast group (%d)", -errno);
526 		}
527 	} else {
528 		zassert_ok(ret, "Cannot leave IPv4 multicast group (%d)", -errno);
529 
530 		if (IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)) {
531 			/* Let the network stack to proceed */
532 			k_msleep(THREAD_SLEEP);
533 		} else {
534 			k_yield();
535 		}
536 	}
537 
538 	zsock_close(fd);
539 
540 	/* Let the network stack to proceed */
541 	k_msleep(THREAD_SLEEP);
542 }
543 
socket_join_group_with_address(struct in_addr * addr)544 static void socket_join_group_with_address(struct in_addr *addr)
545 {
546 	socket_group_with_address(addr, true);
547 }
548 
socket_leave_group_with_address(struct in_addr * addr)549 static void socket_leave_group_with_address(struct in_addr *addr)
550 {
551 	socket_group_with_address(addr, false);
552 }
553 
socket_join_group_with_index(struct in_addr * addr)554 static void socket_join_group_with_index(struct in_addr *addr)
555 {
556 	socket_group_with_index(addr, true);
557 }
558 
socket_leave_group_with_index(struct in_addr * addr)559 static void socket_leave_group_with_index(struct in_addr *addr)
560 {
561 	socket_group_with_index(addr, false);
562 }
563 
ZTEST_USER(net_igmp,test_socket_catch_join_with_address)564 ZTEST_USER(net_igmp, test_socket_catch_join_with_address)
565 {
566 	socket_join_group_with_address(&any_addr);
567 	socket_leave_group_with_address(&any_addr);
568 	socket_join_group_with_address(&my_addr);
569 	socket_leave_group_with_address(&my_addr);
570 }
571 
ZTEST_USER(net_igmp,test_socket_catch_join_with_index)572 ZTEST_USER(net_igmp, test_socket_catch_join_with_index)
573 {
574 	socket_join_group_with_index(&any_addr);
575 	socket_leave_group_with_index(&any_addr);
576 	socket_join_group_with_index(&my_addr);
577 	socket_leave_group_with_index(&my_addr);
578 }
579 
igmp_send_query(bool is_imgpv3)580 static void igmp_send_query(bool is_imgpv3)
581 {
582 	struct net_pkt *pkt;
583 
584 	is_report_sent = false;
585 	is_join_msg_ok = false;
586 
587 	is_igmpv2_query_sent = false;
588 	is_igmpv3_query_sent = false;
589 
590 	/* Joining group first to get reply on query*/
591 	join_group();
592 
593 	is_igmpv2_query_sent = !is_imgpv3;
594 	is_igmpv3_query_sent = is_imgpv3;
595 
596 	pkt = prepare_igmp_query(net_iface, is_imgpv3);
597 	zassert_not_null(pkt, "IGMPv2 query packet prep failed");
598 
599 	zassert_equal(net_ipv4_input(pkt, false), NET_OK, "Failed to send");
600 
601 	zassert_ok(k_sem_take(&wait_data, K_MSEC(WAIT_TIME)), "Timeout while waiting query event");
602 
603 	zassert_true(is_report_sent, "Did not catch query event");
604 
605 	zassert_true(is_join_msg_ok, "Join msg invalid");
606 
607 	is_igmpv2_query_sent = false;
608 	is_igmpv3_query_sent = false;
609 
610 	leave_group();
611 }
612 
ZTEST_USER(net_igmp,test_igmpv3_query)613 ZTEST_USER(net_igmp, test_igmpv3_query)
614 {
615 	igmp_send_query(true);
616 }
617 
ZTEST_USER(net_igmp,test_igmpv2_query)618 ZTEST_USER(net_igmp, test_igmpv2_query)
619 {
620 	igmp_send_query(false);
621 }
622 
ZTEST_USER(net_igmp,test_group_rejoin)623 ZTEST_USER(net_igmp, test_group_rejoin)
624 {
625 	/* It is enough if this is tested with IGMPv2 only because we do not
626 	 * really care about specific IGMP version here.
627 	 */
628 	if (IS_ENABLED(CONFIG_NET_IPV4_IGMPV3)) {
629 		ztest_test_skip();
630 	}
631 
632 	socket_join_group_with_index(&my_addr);
633 
634 	is_report_sent = false;
635 
636 	net_if_carrier_off(net_iface);
637 	net_if_carrier_on(net_iface);
638 
639 	zassert_true(is_report_sent, "Did not catch query event");
640 
641 	socket_leave_group_with_index(&my_addr);
642 }
643 
644 ZTEST_SUITE(net_igmp, NULL, igmp_setup, NULL, NULL, igmp_teardown);
645