*** linux-2.2.5/net/ipv4/arp.c	Sun Mar 21 10:22:00 1999
--- linux/net/ipv4/arp.c	Fri Sep 24 17:08:37 1999
***************
*** 65,70 ****
--- 65,76 ----
   *					clean up the APFDDI & gen. FDDI bits.
   *		Alexey Kuznetsov:	new arp state machine;
   *					now it is in net/core/neighbour.c.
+  *		Stephen D. Williams:	Prevent arp_send() from sending
+  *					responses when the indirect interface
+  *					involved has an inhibit (IFF_NOARP) flag.
+  *              Axel Dunkel     :       fixes requests from local clients to farm addresses.
+  *              Wensong Zhang   :       NOARP device (such as tunl) arp fix.
+  *		David Couture	:	Don't ARP when IIF_LOOPBACK.
   */
  
  /* RFC1122 Status:
***************
*** 427,432 ****
--- 438,445 ----
  	struct sk_buff *skb;
  	struct arphdr *arp;
  	unsigned char *arp_ptr;
+ 	struct device *dev_real; /* The real device this ARP is for, if not dev */
+ 	char cbuf[320];
  
  	/*
  	 *	No arp on this interface.
***************
*** 436,441 ****
--- 449,496 ----
  		return;
  
  	/*
+ 	 *       If this ARP is for another device that doesn't want to arp,
+ 	 *       honor that also. (sdw@lig.net)
+ 	 *	 All of the next few blocks prevent a number of ARP bugs from
+ 	 *	 causing problems, especially in reverse NAT configurations.
+ 	 *	 See http://www.LinuxVirtualServer.org for details.
+ 	 */
+ 
+ 	/* Let's watch ARP's for fun and profit. */
+ 	sprintf(cbuf, "%s arp_send:Re%s src_ip: %s, dest_ip: %s\n", KERN_INFO,
+ 		(type==ARPOP_REQUEST)?"quest":"sponse", in_ntoa(src_ip), in_ntoa(dest_ip));
+ 	printk(cbuf);
+ 
+ 	dev_real = ip_dev_find(src_ip);
+ 
+ 	/* quick fix: warn if down interface is returned */
+ 	if (dev_real != NULL && ( ! (dev_real->flags & IFF_UP))) {
+ 		sprintf(cbuf, "%s arp_send: fixme: multiple interfaces with different"
+ 			 " up/down status but same ip %s detected\n", KERN_INFO, in_ntoa(src_ip));
+ 		printk(cbuf);
+ 		dev_real = dev;
+ 	}
+ 
+ 	if (dev_real != NULL && dev_real != dev) {
+ 		char complaint[120]; strcpy(complaint, "arp_send is called with another device's address");
+ 		if (dev_real->flags&IFF_NOARP) {
+ 			/* bug fix: arp req for local clients that connect to a farm address 1999-09-17  <ad@Dunkel.de> */
+ 			if (type == ARPOP_REQUEST) {
+ 				src_ip = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
+ 				sprintf (cbuf, "%s arp_send: changing source ip to %s\n", KERN_INFO, in_ntoa(src_ip));
+ 				printk(cbuf);
+ 			} else { /* Must be a mistaken response. */
+ 				strcpy(complaint, " that doesn't want to arp\n");
+ 				printk(complaint);
+ 				return;
+ 			}
+ 		} else { /* allows ARP, just note */
+ 			strcpy(complaint, "\n");
+ 			printk(complaint);
+ 		}
+ 	} /* Otherwise device matches IP */
+ 
+ 	/*
  	 *	Allocate a buffer
  	 */
  	
***************
*** 534,539 ****
--- 590,596 ----
  	struct rtable *rt;
  	unsigned char *sha, *tha;
  	u32 sip, tip;
+ 	struct device *tdev;
  	u16 dev_type = dev->type;
  	int addr_type;
  	struct in_device *in_dev = dev->ip_ptr;
***************
*** 627,632 ****
--- 684,699 ----
   *	addresses.  If this is one such, delete it.
   */
  	if (LOOPBACK(tip) || MULTICAST(tip))
+ 		goto out;
+ 
+ /* 
+  *      Check for the device flags for the target IP. If the IFF_NOARP
+  *      is set, just delete it. No arp reply is sent.    -- WZ
+  *
+  *      If IFF_LOOPBACK is set, then delete it too.   /dc.
+  */ 
+ 	if ((tdev = ip_dev_find(tip)) &&
+ 	    ((tdev->flags & IFF_NOARP) || (tdev->flags & IFF_LOOPBACK)))
  		goto out;
  
  /*

