From 75265a07b583332eed3171f516855c6c629750ac Mon Sep 17 00:00:00 2001
From: Andrew Tridgell <andrew@tridgell.net>
Date: Tue, 9 Jan 2024 15:16:10 +1100
Subject: [PATCH 1/3] arp: support a proxy ARP IP address on the netif

allows (for example) for a PPP <-> ethernet gateway to support proxy
ARP. This is simpler than the (currently disabled) proxyarp support
built into PPP in lwip and more general purpose.

To use this the application should call netif_set_proxyarp() on the
interface that should present the extra IP address, this will usually
be a primary ethernet interface. When used with PPP the IP passed in
should be the IP address of the remote end of the PPP link.

This feature is enabled with the ARP_PROXYARP_SUPPORT define.
---
 src/core/ipv4/etharp.c   | 11 ++++++++++-
 src/core/netif.c         | 17 +++++++++++++++++
 src/include/lwip/netif.h | 14 ++++++++++++++
 src/include/lwip/opt.h   |  9 +++++++++
 4 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/core/ipv4/etharp.c b/src/core/ipv4/etharp.c
index 3092dc94..011e13b2 100644
--- a/src/core/ipv4/etharp.c
+++ b/src/core/ipv4/etharp.c
@@ -694,6 +694,15 @@ etharp_input(struct pbuf *p, struct netif *netif)
     from_us = (u8_t)ip4_addr_eq(&sipaddr, netif_ip4_addr(netif));
   }
 
+#if ARP_PROXYARP_SUPPORT
+  if (netif->flags & NETIF_FLAG_PROXYARP) {
+    /*
+      allow answering ARP queries for a configured proxy arp address
+    */
+    for_us |= (u8_t)ip4_addr_eq(&dipaddr, netif_ip4_proxyarp(netif));
+  }
+#endif
+
   /* ARP message directed to us?
       -> add IP address in ARP cache; assume requester wants to talk to us,
          can result in directly sending the queued packets for this host.
@@ -716,7 +725,7 @@ etharp_input(struct pbuf *p, struct netif *netif)
         /* send ARP response */
         etharp_raw(netif,
                    (struct eth_addr *)netif->hwaddr, &hdr->shwaddr,
-                   (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif),
+                   (struct eth_addr *)netif->hwaddr, &dipaddr,
                    &hdr->shwaddr, &sipaddr,
                    ARP_REPLY);
         /* we are not configured? */
diff --git a/src/core/netif.c b/src/core/netif.c
index 98e0553f..69f42665 100644
--- a/src/core/netif.c
+++ b/src/core/netif.c
@@ -752,6 +752,23 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
   }
 #endif
 }
+
+#if ARP_PROXYARP_SUPPORT
+/**
+ * @ingroup netif_ip4
+ * set a proxyarp IP on an interface
+ *
+ * @param netif the network interface to change
+ * @param proxyarp_ip the new proxyarp address
+ */
+void
+netif_set_proxyarp(struct netif *netif, const ip4_addr_t *proxyarp_ip)
+{
+    netif->proxyarp_ip = *proxyarp_ip;
+    netif->flags |= NETIF_FLAG_PROXYARP;
+}
+#endif // ARP_PROXYARP_SUPPORT
+
 #endif /* LWIP_IPV4*/
 
 /**
diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h
index 0cde2c2a..34edefe4 100644
--- a/src/include/lwip/netif.h
+++ b/src/include/lwip/netif.h
@@ -106,6 +106,11 @@ extern "C" {
  * Set by the netif driver in its init function. */
 #define NETIF_FLAG_MLD6         0x40U
 
+/** If set then the proxyarp_ip in the netif has been set.
+ * set by netif_set_proxyarp()
+*/
+#define NETIF_FLAG_PROXYARP     0x80U
+
 /**
  * @}
  */
@@ -277,6 +282,9 @@ struct netif {
   ip_addr_t ip_addr;
   ip_addr_t netmask;
   ip_addr_t gw;
+#if ARP_PROXYARP_SUPPORT
+  ip_addr_t proxyarp_ip; // valid if NETIF_FLAG_PROXYARP set
+#endif
 #endif /* LWIP_IPV4 */
 #if LWIP_IPV6
   /** Array of IPv6 addresses for this netif. */
@@ -465,6 +473,12 @@ void netif_set_gw(struct netif *netif, const ip4_addr_t *gw);
 #define netif_ip_netmask4(netif) ((const ip_addr_t*)&((netif)->netmask))
 /** @ingroup netif_ip4 */
 #define netif_ip_gw4(netif)      ((const ip_addr_t*)&((netif)->gw))
+
+#if ARP_PROXYARP_SUPPORT
+// support for a single proxy ARP IP address
+void netif_set_proxyarp(struct netif *netif, const ip4_addr_t *proxyarp_ip);
+#define netif_ip4_proxyarp(netif) ((const ip_addr_t*)&((netif)->proxyarp_ip))
+#endif /* ARP_PROXYARP_SUPPORT */
 #endif /* LWIP_IPV4 */
 
 #define netif_set_flags(netif, set_flags)     do { (netif)->flags = (u8_t)((netif)->flags |  (set_flags)); } while(0)
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index 2573285f..28e41b89 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -674,6 +674,15 @@
 #define ARP_QUEUE_LEN                   3
 #endif
 
+/**
+ * ARP_PROXYARP_SUPPORT: Enable proxy ARP functonality. This allows
+ * for netif_set_proxyarp() to add an additional IP4 address to a
+ * network interface which will be responded to for ARP queries
+ */
+#if !defined ARP_PROXYARP_SUPPORT || defined __DOXYGEN__
+#define ARP_PROXYARP_SUPPORT            0
+#endif
+
 /**
  * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with
  * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and
-- 
2.34.1

