fix(net/igmp): restore General Query handling broken by pointer compare

The group address in the IGMP header is declared as uint16_t grpaddr[2],
so it decays to a pointer.  Comparing it against INADDR_ANY compares the
address of a struct member against 0, which is always false.  The General
Query branch is therefore unreachable and GCC discards it entirely.

Commit 09bb292fa2 ("net/igmp: fix build warning on GCC 12.2.0") replaced
the original

    if (igmp->grpaddr == 0)

with

    if (net_ipv4addr_cmp(igmp->grpaddr, INADDR_ANY) != 0)

but net_ipv4addr_cmp(a, b) expands to (a == b) and INADDR_ANY expands to
((in_addr_t)0), so the emitted comparison is unchanged.  The -Waddress
diagnostic disappeared only because the comparison now originates inside
a macro expanded from a header included via -isystem, and GCC suppresses
warnings from system-header macros.  The defect was hidden, not fixed.

That commit also rewrote the unicast query test from group->grpaddr != 0,
which was well-formed, into the same pointer comparison, making it
unconditionally true.

Convert the header field with net_ip4addr_conv32() once, and compare the
resulting in_addr_t.  The conversion was already being done in the
group-specific branch, so this only hoists it and reuses it.

Impact: a General Query (destination 224.0.0.1, group address 0) is the
periodic query every IGMP querier sends.  It currently falls through to
the group-specific branch, where igmp_grpallocfind() allocates a group
for 0.0.0.0 and schedules a report for it, while joined groups never have
their report timers restarted.  The querier then ages out the membership
and multicast delivery to the device stops.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
This commit is contained in:
Jacob Dahl 2026-07-14 18:25:20 -06:00 committed by Alin Jerpelea
parent adf4a543e3
commit f20cf4aac3

View file

@ -174,6 +174,13 @@ void igmp_input(struct net_driver_s *dev)
* receivers.
*/
/* The group address lies in the IGMP header where it is stored as
* an unaligned uint16_t[2] in network order. Convert it to an
* in_addr_t before it is used in any comparison.
*/
grpaddr = net_ip4addr_conv32(igmp->grpaddr);
/* Check if the query was sent to all systems */
if (net_ipv4addr_cmp(destipaddr, g_ipv4_allsystems))
@ -195,7 +202,7 @@ void igmp_input(struct net_driver_s *dev)
* Query."
*/
if (net_ipv4addr_cmp(igmp->grpaddr, INADDR_ANY) != 0)
if (net_ipv4addr_cmp(grpaddr, INADDR_ANY))
{
FAR struct igmp_group_s *member;
@ -230,7 +237,7 @@ void igmp_input(struct net_driver_s *dev)
}
}
}
else /* if (net_ipv4addr_cmp(igmp->grpaddr, INADDR_ANY) == 0) */
else /* if (!net_ipv4addr_cmp(grpaddr, INADDR_ANY)) */
{
ninfo("Group-specific multicast query\n");
@ -240,8 +247,7 @@ void igmp_input(struct net_driver_s *dev)
IGMP_STATINCR(g_netstats.igmp.ucast_query);
grpaddr = net_ip4addr_conv32(igmp->grpaddr);
group = igmp_grpallocfind(dev, &grpaddr);
group = igmp_grpallocfind(dev, &grpaddr);
if (group != NULL)
{
@ -259,7 +265,7 @@ void igmp_input(struct net_driver_s *dev)
/* Not sent to all systems -- Unicast query */
else if (net_ipv4addr_cmp(igmp->grpaddr, INADDR_ANY) == 0)
else if (!net_ipv4addr_cmp(grpaddr, INADDR_ANY))
{
ninfo("Unicast query\n");
IGMP_STATINCR(g_netstats.igmp.ucast_query);