From c55d96b9aebf45fa7431c31c676f86d56da21afa Mon Sep 17 00:00:00 2001 From: Felipe Moura Date: Sun, 16 Aug 2026 17:28:55 -0300 Subject: [PATCH 1/2] net/arp: release the device lock before waiting for a resolution The -EINPROGRESS path jumps over the netdev_unlock() below it, so the caller waits holding d_lock. The receive path needs that same lock to dispatch the ARP reply, and the interface stalls for good. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Felipe Moura --- net/arp/arp_send.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/arp/arp_send.c b/net/arp/arp_send.c index 5f97a9807b058..01c5e5bb80b82 100644 --- a/net/arp/arp_send.c +++ b/net/arp/arp_send.c @@ -328,8 +328,13 @@ int arp_send(in_addr_t ipaddr) { /* ARP request for the same destination is in progress, directly * wait arp response notify. + * + * Drop the device lock: this path skips the netdev_unlock() + * below, and the receive path needs that same lock to deliver + * the reply. The waiter above is already installed. */ + netdev_unlock(dev); goto wait; } From 44a62a9580dde1789e9135790163a63389f6c470 Mon Sep 17 00:00:00 2001 From: Felipe Moura Date: Sun, 16 Aug 2026 17:28:55 -0300 Subject: [PATCH 2/2] net/arp: do not resolve an address to another interface's MAC On a cache miss arp_find() returns the MAC of any interface holding the address, ignoring the egress device. Two interfaces on one subnet then leave the peer unreachable until the entry is relearned. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Felipe Moura --- net/arp/arp_table.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/arp/arp_table.c b/net/arp/arp_table.c index a1728989e7769..3e2938b799331 100644 --- a/net/arp/arp_table.c +++ b/net/arp/arp_table.c @@ -81,8 +81,9 @@ struct arp_table_info_s { - in_addr_t ai_ipaddr; /* IP address for lookup */ - FAR uint8_t *ai_ethaddr; /* Location to return the MAC address */ + in_addr_t ai_ipaddr; /* IP address for lookup */ + FAR uint8_t *ai_ethaddr; /* Location to return the MAC address */ + FAR struct net_driver_s *ai_dev; /* The device the frame will be sent on */ }; /**************************************************************************** @@ -117,6 +118,16 @@ static int arp_match(FAR struct net_driver_s *dev, FAR void *arg) { FAR struct arp_table_info_s *info = arg; + /* Only the egress device may answer for its own address. Otherwise a + * frame sent on one interface takes the MAC of another that happens to + * hold the address, which breaks setups sharing a subnet. + */ + + if (info->ai_dev != NULL && dev != info->ai_dev) + { + return 0; + } + /* Make sure that this is an Ethernet device (or an IEEE 802.11 device * which is also Ethernet) */ @@ -529,6 +540,7 @@ int arp_find(in_addr_t ipaddr, FAR uint8_t *ethaddr, info.ai_ipaddr = ipaddr; info.ai_ethaddr = ethaddr; + info.ai_dev = dev; if (netdev_foreach(arp_match, &info) != 0) {