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 <moura.fmo@gmail.com>
This commit is contained in:
Felipe Moura 2026-08-16 17:28:55 -03:00 committed by Xiang Xiao
parent b6583cc4b6
commit cd4712a2f0

View file

@ -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)
{