diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index 9fdb44b042f..2d81a34f700 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -34,6 +34,7 @@ config NET_IF_UNICAST_IPV4_ADDR_COUNT config NET_IF_MCAST_IPV4_ADDR_COUNT int "Max number of multicast IPv4 addresses per network interface" + default 2 if NET_IPV4_IGMP default 1 config NET_ICMPV4_ACCEPT_BROADCAST diff --git a/subsys/net/ip/igmp.c b/subsys/net/ip/igmp.c index 9913030819e..e2b46b1e725 100644 --- a/subsys/net/ip/igmp.c +++ b/subsys/net/ip/igmp.c @@ -127,7 +127,15 @@ static int send_igmp_report(struct net_if *iface, } for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) { - if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&ipv4->mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { continue; } @@ -139,7 +147,15 @@ static int send_igmp_report(struct net_if *iface, } for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) { - if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined) { + /* We don't need to send an IGMP membership report to the IGMP + * all systems multicast address of 224.0.0.1 so skip over it. + * Since the IGMP all systems multicast address is marked as + * used and joined during init time, we have to check this + * address separately to skip over it. + */ + if (!ipv4->mcast[i].is_used || !ipv4->mcast[i].is_joined || + net_ipv4_addr_cmp_raw((uint8_t *)&ipv4->mcast[i].address.in_addr, + (uint8_t *)&all_systems)) { continue; } @@ -326,3 +342,39 @@ int net_ipv4_igmp_leave(struct net_if *iface, const struct in_addr *addr) sizeof(struct in_addr)); return ret; } + +void net_ipv4_igmp_init(struct net_if *iface) +{ + struct net_if_mcast_addr *maddr; + + /* Ensure multicast addresses are available */ + if (CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT < 1) { + return; + } + + /* This code adds the IGMP all systems 224.0.0.1 multicast address + * to the list of multicast addresses of the given interface. + * The address is marked as joined. However, an IGMP membership + * report is not generated for this address. Populating this + * address in the list of multicast addresses of the interface + * and marking it as joined is helpful for multicast hash filter + * implementations that need a list of multicast addresses it needs + * to add to the multicast hash filter after a multicast address + * has been removed from the membership list. + */ + maddr = net_if_ipv4_maddr_lookup(&all_systems, &iface); + if (maddr && net_if_ipv4_maddr_is_joined(maddr)) { + return; + } + + if (!maddr) { + maddr = net_if_ipv4_maddr_add(iface, &all_systems); + if (!maddr) { + return; + } + } + + net_if_ipv4_maddr_join(maddr); + + net_if_mcast_monitor(iface, &maddr->address, true); +} diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index f72b319658c..d181ba12e99 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -4159,6 +4159,21 @@ exit: } } +static void init_igmp(struct net_if *iface) +{ +#if defined(CONFIG_NET_IPV4_IGMP) + /* Ensure IPv4 is enabled for this interface */ + if (iface->config.ip.ipv4 == NULL) { + return; + } + + net_ipv4_igmp_init(iface); +#else + ARG_UNUSED(iface); + return; +#endif +} + int net_if_up(struct net_if *iface) { int status = 0; @@ -4187,6 +4202,8 @@ int net_if_up(struct net_if *iface) goto out; } + init_igmp(iface); + done: net_if_flag_set(iface, NET_IF_UP); net_mgmt_event_notify(NET_EVENT_IF_ADMIN_UP, iface); diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 92da1cb4a7b..918fa070f99 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -173,6 +173,15 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, extern uint16_t net_calc_chksum_ipv4(struct net_pkt *pkt); #endif /* CONFIG_NET_IPV4 */ +#if defined(CONFIG_NET_IPV4_IGMP) +/** + * @brief Initialise the IGMP module for a given interface + * + * @param iface Interface to init IGMP + */ +void net_ipv4_igmp_init(struct net_if *iface); +#endif /* CONFIG_NET_IPV4_IGMP */ + #if defined(CONFIG_NET_IPV4_IGMP) uint16_t net_calc_chksum_igmp(uint8_t *data, size_t len); enum net_verdict net_ipv4_igmp_input(struct net_pkt *pkt,