From d5ebc94958526aee2ece8ee2455a229d57181460 Mon Sep 17 00:00:00 2001
From: Amir Shalem <amir.shalem@gmail.com>
Date: Sat, 29 Oct 2011 12:25:52 +0200
Subject: [PATCH 2/3] ARP entries should be separated not only by destination
 IP address, but also by the network interface.

Signed-off-by: Amir Shalem <amir.shalem@gmail.com>
---
 src/netif/etharp.c |   23 +++++++++--------------
 1 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/src/netif/etharp.c b/src/netif/etharp.c
index 1a15fae..8018d0f 100644
--- a/src/netif/etharp.c
+++ b/src/netif/etharp.c
@@ -112,9 +112,7 @@ struct etharp_entry {
   struct pbuf *q;
 #endif /* ARP_QUEUEING */
   ip_addr_t ipaddr;
-#if LWIP_SNMP
   struct netif *netif;
-#endif /* LWIP_SNMP */
   struct eth_addr ethaddr;
   u8_t state;
   u8_t ctime;
@@ -193,9 +191,7 @@ etharp_free_entry(int i)
 #ifdef LWIP_DEBUG
   /* for debugging, clean out the complete entry */
   arp_table[i].ctime = 0;
-#if LWIP_SNMP
   arp_table[i].netif = NULL;
-#endif /* LWIP_SNMP */
   ip_addr_set_zero(&arp_table[i].ipaddr);
   arp_table[i].ethaddr = ethzero;
 #endif /* LWIP_DEBUG */
@@ -268,7 +264,7 @@ etharp_tmr(void)
  * entry is found or could be recycled.
  */
 static s8_t
-etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
+etharp_find_entry(ip_addr_t *ipaddr, u8_t flags, struct netif *netif)
 {
   s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
   s8_t empty = ARP_TABLE_SIZE;
@@ -304,7 +300,8 @@ etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
       LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
         state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
       /* if given, does IP address match IP address in ARP entry? */
-      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr) &&
+          (netif == NULL || arp_table[i].netif == netif)) {
         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i));
         /* found exact IP address match, simply bail out */
         return i;
@@ -466,7 +463,7 @@ etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr
     return ERR_ARG;
   }
   /* find or create ARP entry */
-  i = etharp_find_entry(ipaddr, flags);
+  i = etharp_find_entry(ipaddr, flags, netif);
   /* bail out if no entry could be found */
   if (i < 0) {
     return (err_t)i;
@@ -484,9 +481,7 @@ etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr
   }
 
   /* record network interface */
-#if LWIP_SNMP
   arp_table[i].netif = netif;
-#endif /* LWIP_SNMP */
   /* insert in SNMP ARP index tree */
   snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
 
@@ -562,7 +557,7 @@ etharp_remove_static_entry(ip_addr_t *ipaddr)
     ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
 
   /* find or create ARP entry */
-  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL);
   /* bail out if no entry could be found */
   if (i < 0) {
     return (err_t)i;
@@ -598,9 +593,7 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
   LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
     eth_ret != NULL && ip_ret != NULL);
 
-  LWIP_UNUSED_ARG(netif);
-
-  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif);
   if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
       *eth_ret = &arp_table[i].ethaddr;
       *ip_ret = &arp_table[i].ipaddr;
@@ -917,6 +910,7 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
     if (etharp_cached_entry < ARP_TABLE_SIZE) {
 #endif /* LWIP_NETIF_HWADDRHINT */
       if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
+		  (arp_table[etharp_cached_entry].netif == netif) &&
           (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
         /* the per-pcb-cached entry is stable and the right one! */
         ETHARP_STATS_INC(etharp.cachehit);
@@ -952,6 +946,7 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
        throughput and etharp_find_entry() is kind of slow */
     for (i = 0; i < ARP_TABLE_SIZE; i++) {
       if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
+		  (arp_table[i].netif == netif) &&
           (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
         /* found an existing, stable entry */
         ETHARP_SET_HINT(netif, i);
@@ -1018,7 +1013,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
   }
 
   /* find entry in ARP cache, ask to create entry if queueing packet */
-  i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, NULL);
 
   /* could not find or create entry? */
   if (i < 0) {
-- 
1.7.6.msysgit.0

