patch-2.1.129 linux/net/appletalk/aarp.c

Next file: linux/net/appletalk/ddp.c
Previous file: linux/net/802/fddi.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.128/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
@@ -23,6 +23,8 @@
  *		Inside AppleTalk (2nd Ed).
  *	Fixes:
  *		Jaume Grau	-	flush caches on AARP_PROBE
+ *		Rob Newberry	-	Added proxy AARP and AARP proc fs, 
+ *					moved probing from DDP module.
  *
  */
 
@@ -53,6 +55,7 @@
 #include <net/psnap.h>
 #include <linux/atalk.h>
 #include <linux/init.h>
+#include <linux/proc_fs.h>
 
  
 int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
@@ -69,6 +72,7 @@
 	/* These first two are only used for unresolved entries */
 	unsigned long last_sent;		/* Last time we xmitted the aarp request */
 	struct sk_buff_head packet_queue;	/* Queue of frames wait for resolution */
+	int status;				/* Used for proxy AARP */
 	unsigned long expires_at;		/* Entry expiry time */
 	struct at_addr target_addr;		/* DDP Address */
 	struct device *dev;			/* Device to use */
@@ -77,12 +81,11 @@
 	struct aarp_entry *next;		/* Next entry in chain */
 };
 
-
 /*
- *	Hashed list of resolved and unresolved entries
+ *	Hashed list of resolved, unresolved and proxy entries
  */
 
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
 static int unresolved_count=0;
 
 /*
@@ -224,7 +227,7 @@
 }
 
 /*
- *	Send probe frames. Called from atif_probe_device.
+ *	Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
  */
  
 void aarp_send_probe(struct device *dev, struct at_addr *us)
@@ -360,6 +363,7 @@
 		aarp_expire_timer(&resolved[ct]);
 		aarp_kick(&unresolved[ct]);
 		aarp_expire_timer(&unresolved[ct]);
+		aarp_expire_timer(&proxies[ct]);
 	}
 	del_timer(&aarp_timer);
 	if(unresolved_count==0)
@@ -382,6 +386,7 @@
 		{
 			aarp_expire_device(&resolved[ct],ptr);
 			aarp_expire_device(&unresolved[ct],ptr);
+			aarp_expire_device(&proxies[ct],ptr);
 		}
 	}
 	return NOTIFY_DONE;
@@ -420,6 +425,156 @@
 	return list;
 }
 
+void aarp_proxy_remove(struct device *dev, struct at_addr *sa)
+{
+	struct aarp_entry *a;
+	int hash;
+	
+	hash = 	sa->s_node % (AARP_HASH_SIZE-1);
+	a = aarp_find_entry(proxies[hash], dev, sa);
+	if (a)
+	{
+		a->expires_at = 0;
+		
+	}
+}
+
+struct at_addr* aarp_proxy_find(struct device *dev, struct at_addr *sa)
+{
+	struct aarp_entry *a;
+	int hash;
+
+	hash = 	sa->s_node % (AARP_HASH_SIZE-1);
+	a = aarp_find_entry(proxies[hash], dev, sa);
+	if (a != NULL)
+		return sa;
+	
+	return NULL;
+}
+
+	
+/*
+ * Probe a Phase 1 device or a device that requires its Net:Node to
+ * be set via an ioctl.
+ */
+void aarp_send_probe_phase1(struct atalk_iface *iface)
+{
+    struct ifreq atreq;
+    struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr;
+
+    sa->sat_addr.s_node = iface->address.s_node;
+    sa->sat_addr.s_net  = ntohs(iface->address.s_net);
+
+	/* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+	if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
+    {
+    	(void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+    	if((iface->address.s_net != htons(sa->sat_addr.s_net))
+				|| (iface->address.s_node != sa->sat_addr.s_node))
+			iface->status |= ATIF_PROBE_FAIL;
+
+		iface->address.s_net  = htons(sa->sat_addr.s_net);
+		iface->address.s_node = sa->sat_addr.s_node;
+	}
+
+	return;
+}
+
+
+void aarp_probe_network(struct atalk_iface *atif)
+{
+	if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+		aarp_send_probe_phase1(atif);
+	else
+	{
+		unsigned int count;
+		for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+		{
+			aarp_send_probe(atif->dev, &atif->address);
+
+			/*
+			 * Defer 1/10th
+			 */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ/10);
+							
+			if (atif->status & ATIF_PROBE_FAIL)
+				break;
+		}
+	}
+}
+
+int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
+{
+	struct	aarp_entry	*entry;
+	unsigned int count;
+	int	hash;
+	
+	/*
+	 * we don't currently support LocalTalk or PPP for proxy AARP;
+	 * if someone wants to try and add it, have fun
+	 */
+	if (atif->dev->type == ARPHRD_LOCALTLK)
+		return (-EPROTONOSUPPORT);
+		
+	if (atif->dev->type == ARPHRD_PPP)
+		return (-EPROTONOSUPPORT);
+		
+	/* 
+	 * create a new AARP entry with the flags set to be published -- 
+	 * we need this one to hang around even if it's in use
+	 */
+	entry = aarp_alloc();
+	if (entry == NULL)
+		return (-ENOMEM);
+	
+	entry->expires_at = -1;
+	entry->status = ATIF_PROBE;
+	entry->target_addr.s_node = sa->s_node;
+	entry->target_addr.s_net = sa->s_net;
+	entry->dev = atif->dev;
+
+	hash = sa->s_node % (AARP_HASH_SIZE-1);
+	entry->next = proxies[hash];
+	proxies[hash] = entry;
+	
+	for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
+	{
+		aarp_send_probe(atif->dev, sa);
+
+		/*
+		 * Defer 1/10th
+		 */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+						
+		if (entry->status & ATIF_PROBE_FAIL)
+			break;
+	}
+	
+	/*
+	 * FIX ME: I think we need exclusive access to the status flags,
+	 * 		in case some one fails the probe while we're removing
+	 *		the probe flag.
+	 */
+	if (entry->status & ATIF_PROBE_FAIL)
+	{
+		/* free the entry */
+		entry->expires_at = 0;
+		
+		/* return network full */
+		return (-EADDRINUSE);
+	}
+	else
+	{
+		/* clear the probing flag */
+		entry->status &= ~ATIF_PROBE;
+	}
+
+	return 1;	
+}
+
+
 /*
  *	Send a DDP frame
  */
@@ -654,7 +809,7 @@
 {
 	struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
 	struct aarp_entry *a;
-	struct at_addr sa, *ma;
+	struct at_addr sa, *ma, da;
 	unsigned long flags;
 	int hash;
 	struct atalk_iface *ifa;
@@ -736,8 +891,34 @@
 			kfree_skb(skb);
 			return 1;		
 		}
-	}				 
+	}
 	
+	/*
+	 * Check for replies of proxy AARP entries
+	 */
+
+	/*
+	 * FIX ME: do we need a cli() here? 
+	 * aarp_find_entry does one on its own, between saving and restoring flags, so
+	 * I don't think it is necessary, but I could be wrong -- it's happened before
+	 */
+	da.s_node = ea->pa_dst_node;
+	da.s_net = ea->pa_dst_net;
+	a = aarp_find_entry(proxies[hash], dev, &da);
+	if (a != NULL)
+		if (a->status & ATIF_PROBE)
+		{
+			a->status |= ATIF_PROBE_FAIL;
+			
+			/*
+			 * we do not respond to probe or request packets for 
+			 * this address while we are probing this address
+			 */
+			restore_flags(flags);
+			kfree_skb(skb);
+			return 1;
+		}
+
 	switch(ea->function)
 	{
 		case AARP_REPLY:	
@@ -747,7 +928,7 @@
 			 *	Find the entry	
 			 */
 			 
-			cli();
+			cli();	/* FIX ME: is this cli() necessary? aarp_find_entry does one on its own... */
 			if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
 				break;
 			/*
@@ -770,12 +951,32 @@
 			 *	If it is my address set ma to my address and reply. We can treat probe and
 			 *	request the same. Probe simply means we shouldn't cache the querying host, 
 			 *	as in a probe they are proposing an address not using one.
+			 *	
+			 *	Support for proxy-AARP added.  We check if the address is one
+			 *	of our proxies before we toss the packet out.
 			 */
 			 
-			ma=&ifa->address;
 			sa.s_node=ea->pa_dst_node;
 			sa.s_net=ea->pa_dst_net;
-			
+
+			/*
+			 * see if we have a matching proxy
+			 */
+			ma = aarp_proxy_find(dev, &sa);
+			if (!ma)
+			{
+				ma=&ifa->address;
+			}
+			else
+			{
+				/*
+				 * we need to make a copy of the entry
+				 */
+				da.s_node = sa.s_node;
+				da.s_net = da.s_net;
+				ma = &da;
+			}
+
 			if(ea->function==AARP_PROBE)
 			{
 				/* A probe implies someone trying to get an
@@ -845,11 +1046,104 @@
 	{
 		aarp_expire_device(&resolved[ct], dev);
 		aarp_expire_device(&unresolved[ct], dev);
+		aarp_expire_device(&proxies[ct], dev);
 	}
 
 	return;
 }
 
+/*
+ * Called from proc fs
+ */
+int aarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	/* we should dump all our AARP entries */
+	struct aarp_entry	*entry;
+	int			len, ct;
+
+	len = sprintf(buffer,
+		"%-10.10s  ""%-10.10s""%-18.18s""%12.12s""%12.12s"" xmit_count  status\n",
+		"address","device","hw addr","last_sent", "expires");
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = resolved[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+
+			len+=sprintf(buffer+len,"   resolved\n");
+		}
+	}
+
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = unresolved[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+			len+=sprintf(buffer+len," unresolved\n");
+		}
+	}
+
+	for (ct = 0; ct < AARP_HASH_SIZE; ct++)
+	{
+		for (entry = proxies[ct]; entry; entry = entry->next)
+		{
+			len+= sprintf(buffer+len,"%6u:%-3u  ",
+				(unsigned int)ntohs(entry->target_addr.s_net),
+				(unsigned int)(entry->target_addr.s_node));
+			len+= sprintf(buffer+len,"%-10.10s",
+				entry->dev->name);
+			len+= sprintf(buffer+len,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+				(int)(entry->hwaddr[0] & 0x000000FF),
+				(int)(entry->hwaddr[1] & 0x000000FF),
+				(int)(entry->hwaddr[2] & 0x000000FF),
+				(int)(entry->hwaddr[3] & 0x000000FF),
+				(int)(entry->hwaddr[4] & 0x000000FF),
+				(int)(entry->hwaddr[5] & 0x000000FF));
+			len+= sprintf(buffer+len,"%12lu ""%12lu ",
+				(unsigned long)entry->last_sent,
+				(unsigned long)entry->expires_at);
+			len+=sprintf(buffer+len,"%10u",
+				(unsigned int)entry->xmit_count);
+			len+=sprintf(buffer+len,"      proxy\n");
+		}
+	}
+
+
+	return len;
+}
+
 #ifdef MODULE
 /*
  * General module cleanup. Called from cleanup_module() in ddp.c.
@@ -862,4 +1156,27 @@
 }
 
 #endif  /* MODULE */
+
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry proc_aarp_entries=
+{
+	PROC_NET_AT_AARP, 4, "aarp",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_net_inode_operations,
+	aarp_get_info
+};
+
+void aarp_register_proc_fs(void)
+{
+	proc_net_register(&proc_aarp_entries);
+}
+
+void aarp_unregister_proc_fs(void)
+{
+	proc_net_unregister(PROC_NET_AT_AARP);
+}
+
+#endif
+
 #endif  /* CONFIG_ATALK || CONFIG_ATALK_MODULE */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov