Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions subsys/net/l2/ethernet/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,19 @@ static void arp_request_timeout(struct k_work *work)
k_mutex_unlock(&arp_mutex);
}

static inline bool is_same_subnet(uint32_t addr1,
uint32_t addr2,
uint32_t netmask)
{
return ((addr1 & netmask) == (addr2 & netmask));
}

static inline struct net_in_addr *if_get_addr(struct net_if *iface,
const uint8_t *addr)
const uint8_t *own_addr,
const struct net_in_addr *dst_addr)
{
struct net_if_ipv4 *ipv4 = iface->config.ip.ipv4;
struct net_in_addr *fall_back = NULL;

if (!ipv4) {
return NULL;
Expand All @@ -241,14 +250,23 @@ static inline struct net_in_addr *if_get_addr(struct net_if *iface,
if (ipv4->unicast[i].ipv4.is_used &&
ipv4->unicast[i].ipv4.address.family == NET_AF_INET &&
ipv4->unicast[i].ipv4.addr_state == NET_ADDR_PREFERRED &&
(!addr ||
((own_addr == NULL) ||
net_ipv4_addr_cmp_raw(
addr, ipv4->unicast[i].ipv4.address.in_addr.s4_addr))) {
return &ipv4->unicast[i].ipv4.address.in_addr;
own_addr, ipv4->unicast[i].ipv4.address.in_addr.s4_addr))) {
if ((dst_addr == NULL) ||
is_same_subnet(dst_addr->s_addr,
ipv4->unicast[i].ipv4.address.in_addr.s_addr,
ipv4->unicast[i].netmask.s_addr)) {
/* Use preferred address on the same subnet as destination */
return &ipv4->unicast[i].ipv4.address.in_addr;
} else if (fall_back == NULL) {
/* Use address as fallback, if no match for subnet is found */
fall_back = &ipv4->unicast[i].ipv4.address.in_addr;
}
}
}

return NULL;
return fall_back;
}

static inline struct net_pkt *arp_prepare(struct net_if *iface,
Expand Down Expand Up @@ -339,7 +357,7 @@ static inline struct net_pkt *arp_prepare(struct net_if *iface,
} else if (!entry) {
my_addr = (struct net_in_addr *)NET_IPV4_HDR(pending)->src;
} else {
my_addr = if_get_addr(entry->iface, (const uint8_t *)current_ip);
my_addr = if_get_addr(entry->iface, (const uint8_t *)current_ip, next_addr);
}

if (my_addr) {
Expand Down Expand Up @@ -852,7 +870,7 @@ enum net_verdict net_arp_input(struct net_pkt *pkt,
}

/* Someone wants to know our ll address */
addr = if_get_addr(net_pkt_iface(pkt), arp_hdr->dst_ipaddr);
addr = if_get_addr(net_pkt_iface(pkt), arp_hdr->dst_ipaddr, NULL);
if (!addr) {
/* Not for us so drop the packet silently */
return NET_DROP;
Expand Down