net/devif: Reorder ipv4_input packet classification.

Rework ipv4_input() packet classification to make the control flow
clearer and keep the common local-unicast case first.

This change:
- handles local packets first
- keeps broadcast/multicast handling in dedicated branches

It also prevents broadcast and multicast packets from falling through
into the unicast forward path.

Signed-off-by: Shunchao Hu <ankohuu@gmail.com>
This commit is contained in:
Shunchao Hu
2026-04-19 10:25:15 +08:00
committed by archer
parent 629d0fe356
commit 5428220062
+65 -105
View File
@@ -311,140 +311,100 @@ static int ipv4_in(FAR struct net_driver_s *dev)
destipaddr = net_ip4addr_conv32(ipv4->destipaddr);
#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
/* If IP broadcast support is configured, we check for a broadcast
* UDP packet, which may be destined to us (even if there is no IP
* address yet assigned to the device as is the case when we are
* negotiating over DHCP for an address).
/* Keep the common local-unicast case on the fast path, then classify
* non-local packets as broadcast, multicast, or forwardable unicast.
*/
if (ipv4->proto == IP_PROTO_UDP &&
net_ipv4addr_cmp(destipaddr, INADDR_BROADCAST))
if (net_ipv4addr_cmp(destipaddr, dev->d_ipaddr))
{
#ifdef CONFIG_NET_ICMP
if (net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY))
{
nwarn("WARNING: No IP address assigned\n");
goto drop;
}
#endif
}
else if (net_ipv4addr_cmp(destipaddr, INADDR_BROADCAST) ||
(net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr,
dev->d_netmask) &&
net_ipv4addr_broadcast(destipaddr, dev->d_netmask)))
{
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
/* Forward broadcast packets */
ipv4_forward_broadcast(dev, ipv4);
/* Process the incoming packet if not forwardable */
if (dev->d_len > 0)
#endif
{
ret = udp_ipv4_input(dev);
}
goto done;
}
else
#endif
#if defined(CONFIG_NET_BROADCAST) && defined(NET_UDP_HAVE_STACK)
/* The address is not the broadcast address and we have been assigned a
* address. So there is also the possibility that the destination address
* is a sub-net broadcast address which we will need to handle just as for
* the broadcast address above.
*/
if (ipv4->proto == IP_PROTO_UDP &&
net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr, dev->d_netmask) &&
net_ipv4addr_broadcast(destipaddr, dev->d_netmask))
{
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
/* Forward broadcast packets */
ipv4_forward_broadcast(dev, ipv4);
/* Process the incoming packet if not forwardable */
if (dev->d_len > 0)
#endif
if (ipv4->proto == IP_PROTO_UDP)
{
ret = udp_ipv4_input(dev);
goto done;
}
goto done;
}
else
#endif
/* Check if the packet is destined for our IP address. */
if (!net_ipv4addr_cmp(destipaddr, dev->d_ipaddr))
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.drop++;
#endif
goto drop;
}
else if (IN_MULTICAST(NTOHL(destipaddr)))
{
/* No.. This is not our IP address. Check for an IPv4 IGMP group
* address
*/
#ifdef CONFIG_NET_IGMP
in_addr_t destip = net_ip4addr_conv32(ipv4->destipaddr);
if (igmp_grpfind(dev, &destip) != NULL)
if (igmp_grpfind(dev, &destipaddr) != NULL)
{
#ifdef CONFIG_NET_IPFORWARD_BROADCAST
/* Forward multicast packets */
ipv4_forward_broadcast(dev, ipv4);
/* Return success if the packet was forwarded. */
if (dev->d_len == 0)
{
goto done;
}
#endif
}
else
#endif
{
/* No.. The packet is not destined for us. */
#ifdef CONFIG_NET_IPFORWARD
/* Try to forward the packet */
if (ipv4_forward(dev, ipv4) >= 0)
{
/* The packet was forwarded. Return success; d_len will
* be set appropriately by the forwarding logic: Cleared
* if the packet is forward via anoother device or non-
* zero if it will be forwarded by the same device that
* it was received on.
*/
goto done;
}
else
#endif
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_BINDTODEVICE)
/* If the protocol specific socket option NET_BINDTODEVICE
* is selected, then we must forward all UDP packets to the bound
* socket.
*/
if (ipv4->proto != IP_PROTO_UDP)
#endif
{
/* Not destined for us and not forwardable... Drop the
* packet.
*/
ninfo("WARNING: Not destined for us; not forwardable... "
"Dropping!\n");
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.drop++;
g_netstats.ipv4.drop++;
#endif
goto drop;
}
goto drop;
}
}
#ifdef CONFIG_NET_ICMP
/* In other cases, the device must be assigned a non-zero IP address. */
else if (net_ipv4addr_cmp(dev->d_ipaddr, INADDR_ANY))
else
{
nwarn("WARNING: No IP address assigned\n");
goto drop;
}
#ifdef CONFIG_NET_IPFORWARD
/* Try to forward the unicast packet. */
if (ipv4_forward(dev, ipv4) >= 0)
{
/* The packet was forwarded. Return success; d_len will
* be set appropriately by the forwarding logic: Cleared
* if the packet is forward via another device or non-zero
* if it will be forwarded by the same device that it was
* received on.
*/
goto done;
}
else
#endif
#if defined(NET_UDP_HAVE_STACK) && defined(CONFIG_NET_BINDTODEVICE)
/* If the protocol specific socket option NET_BINDTODEVICE
* is selected, then we must forward all UDP packets to the bound
* socket.
*/
if (ipv4->proto != IP_PROTO_UDP)
#endif
{
/* Not destined for us and not forwardable... Drop the
* packet.
*/
ninfo("WARNING: Not destined for us; not forwardable... "
"Dropping!\n");
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.drop++;
#endif
goto drop;
}
}
#ifdef CONFIG_NET_IPV4_CHECKSUMS
if (((dev->d_features & NETDEV_RX_CSUM) == 0)