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

Next file: linux/net/ax25/ax25_ip.c
Previous file: linux/net/appletalk/aarp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.128/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
@@ -29,6 +29,8 @@
  *						driver file. (ipddp.c & ipddp.h)
  *		Jay Schulist		:	Made work as module with 
  *						AppleTalk drivers, cleaned it.
+ *		Rob Newberry		:	Added proxy AARP and AARP proc fs, 
+ *						moved probing to AARP module.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -76,6 +78,16 @@
 #include <linux/init.h>
 
 
+#ifdef CONFIG_PROC_FS
+extern void aarp_register_proc_fs(void);
+extern void aarp_unregister_proc_fs(void);
+#endif
+
+extern void aarp_probe_network(struct atalk_iface *atif);
+extern int  aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa);
+extern void aarp_proxy_remove(struct device *dev, struct at_addr *sa);
+
+
 #undef APPLETALK_DEBUG
 
 #ifdef APPLETALK_DEBUG
@@ -301,32 +313,6 @@
 	return (iface);
 }
 
-/*
- * Probe a Phase 1 device or a device that requires its Net:Node to
- * be set via an ioctl.
- */
-void atif_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;
-}
 
 /*
  * Perform phase 2 AARP probing on our tentative address.
@@ -336,7 +322,7 @@
 	int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
 	int probe_net=ntohs(atif->address.s_net);
 	int probe_node=atif->address.s_node;
-	int ct, netct, nodect;
+	int netct, nodect;
 
 	/*
 	 * Offset the network we start probing with.
@@ -372,23 +358,8 @@
 				/*
 				 * Probe a proposed address.
 				 */
+				aarp_probe_network(atif);
 
-				if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
-                                        atif_send_probe_phase1(atif);
-                                else
-                                {
-					for(ct = 0; ct < AARP_RETRANSMIT_LIMIT; ct++)
-					{
-						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;
-					}
-				}
 				if(!(atif->status & ATIF_PROBE_FAIL))
 					return (0);
 			}
@@ -402,6 +373,69 @@
 	return (-EADDRINUSE);	/* Network is full... */
 }
 
+
+/*
+ * Perform AARP probing for a proxy address
+ */
+static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* proxy_addr)
+{
+	int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
+	int probe_net=ntohs(atif->address.s_net);	// we probe the interface's network
+	int probe_node=ATADDR_ANYNODE;				// we'll take anything
+	int netct, nodect;
+
+	/*
+	 * Offset the network we start probing with.
+	 */
+
+	if(probe_net == ATADDR_ANYNET)
+	{
+		if(!netrange)
+			probe_net = ntohs(atif->nets.nr_firstnet);
+		else
+			probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+	}
+
+	if(probe_node == ATADDR_ANYNODE)
+		probe_node = jiffies&0xFF;
+		
+	/*
+	 * Scan the networks.
+	 */
+
+	for(netct = 0; netct <= netrange; netct++)
+	{
+		/*
+		 * Sweep the available nodes from a given start.
+		 */
+
+		proxy_addr->s_net = htons(probe_net);
+		for(nodect = 0; nodect < 256; nodect++)
+		{
+			proxy_addr->s_node = ((nodect+probe_node) & 0xFF);
+			if((proxy_addr->s_node>0) && (proxy_addr->s_node<254))
+			{
+				/*
+				 * Tell AARP to probe a proposed address.
+				 */
+				int probe_result = aarp_proxy_probe_network(atif, proxy_addr);
+
+				if (probe_result == 0)
+					return 0;
+					
+				if (probe_result != -EADDRINUSE)
+					return probe_result;
+			}
+		}
+		probe_net++;
+		if(probe_net > ntohs(atif->nets.nr_lastnet))
+			probe_net = ntohs(atif->nets.nr_firstnet);
+	}
+
+	return (-EADDRINUSE);	/* Network is full... */
+}
+
+
 struct at_addr *atalk_find_dev_addr(struct device *dev)
 {
 	struct atalk_iface *iface=dev->atalk_ptr;
@@ -481,19 +515,46 @@
  */
 static struct atalk_route *atrtr_find(struct at_addr *target)
 {
+	/*
+	 * we must search through all routes unless we find a 
+	 * host route, because some host routes might overlap
+	 * network routes
+	 */
 	struct atalk_route *r;
-
+	struct atalk_route *net_route = NULL;
+	
 	for(r=atalk_router_list; r != NULL; r=r->next)
 	{
 		if(!(r->flags & RTF_UP))
 			continue;
 		if(r->target.s_net == target->s_net)
 		{
-			if(!(r->flags&RTF_HOST) 
-				|| r->target.s_node == target->s_node)
-				return (r);
+			if (r->flags & RTF_HOST)
+			{
+				/*
+				 * if this host route is for the target,
+				 * the we're done
+				 */
+				if (r->target.s_node == target->s_node)
+					return (r);
+			}
+			else
+			{
+				/*
+				 * this route will work if there isn't a
+				 * direct host route, so cache it
+				 */
+				net_route = r;
+			}
 		}
 	}
+	
+	/* 
+	 * if we found a network route but not a direct host
+	 * route, then return it
+	 */
+	if (net_route != NULL)
+		return (net_route);
 
 	if(atrtr_default.dev)
 		return (&atrtr_default);
@@ -705,6 +766,7 @@
 	int ct;
 	int limit;
 	struct rtentry rtdef;
+	int	add_route;
 
 	if(copy_from_user(&atreq,arg,sizeof(atreq)))
 		return (-EFAULT);
@@ -730,6 +792,18 @@
 
 			nr=(struct netrange *)&sa->sat_zero[0];
 
+			add_route = 1;
+
+			/*
+			 * if this is a point-to-point iface, and we already have an 
+			 * iface for this AppleTalk address, then we should not add a route
+			 */
+			if (dev->flags & IFF_POINTOPOINT && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node))
+			{
+				printk(KERN_DEBUG "AppleTalk: point-to-point interface added with existing address\n");
+				add_route = 0;
+			}
+			
 			/*
 			 * Phase 1 is fine on LocalTalk but we don't do
 			 * EtherTalk phase 1. Anyone wanting to add it go ahead.
@@ -764,7 +838,7 @@
 			 * error and atalkd will try another.
 			 */
 
-			if(!(dev->flags & IFF_LOOPBACK) && atif_probe_device(atif) < 0)
+			if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0)
 			{
 				atif_drop_device(dev);
 				return (-EADDRINUSE);
@@ -782,7 +856,7 @@
 			rtdef.rt_flags = RTF_UP;
 			sa->sat_family = AF_APPLETALK;
 			sa->sat_addr.s_node = ATADDR_ANYNODE;
-			if(dev->flags & IFF_LOOPBACK)
+			if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
 				rtdef.rt_flags |= RTF_HOST;
 
 			/*
@@ -803,11 +877,12 @@
 					printk(KERN_WARNING "Too many routes/iface.\n");
 					return (-EINVAL);
 				}
-				for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
-				{
-					sa->sat_addr.s_net = htons(ct);
-					atrtr_create(&rtdef, dev);
-				}
+				if (add_route)
+					for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
+					{
+						sa->sat_addr.s_net = htons(ct);
+						atrtr_create(&rtdef, dev);
+					}
 			}
 			dev_mc_add(dev, aarp_mcast, 6, 1);
 			return (0);
@@ -835,6 +910,68 @@
 				return (-EINVAL);
 			atalk_dev_down(dev);
 			break;			
+
+		case SIOCSARP:
+			if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * for now, we only support proxy AARP on ELAP;
+                         * we should be able to do it for LocalTalk, too.
+                         */
+                        if(dev->type != ARPHRD_ETHER)
+                                return (-EPROTONOSUPPORT);
+
+                        /*
+                         * atif points to the current interface on this network;
+                         * we aren't concerned about its current status (at least for now),
+                         * but it has all the settings about the network we're going
+                         * to probe.  consequently, it must exist.
+                         */
+                        if (!atif)
+                                return (-EADDRNOTAVAIL);
+
+                        nr=(struct netrange *)&(atif->nets);
+                        /*
+                         * Phase 1 is fine on Localtalk but we don't do
+                         * Ethertalk phase 1. Anyone wanting to add it go ahead.
+                         */
+                        if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+                                return (-EPROTONOSUPPORT);
+
+                        if(sa->sat_addr.s_node == ATADDR_BCAST
+                                || sa->sat_addr.s_node == 254)
+                                return (-EINVAL);
+
+                        /*
+                         * Check if the chosen address is used. If so we
+                         * error and ATCP will try another.
+                         */
+                      	if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+                      		return (-EADDRINUSE);
+                      	
+                       /*
+                         * We now have an address on the local network, and the AARP
+                         * code will defend it for us until we take it down.
+                         * We don't set up any routes right now, because ATCP will
+                         * install them manually via SIOCADDRT.
+                         */
+                        break;
+
+                case SIOCDARP:
+                        if(!suser())
+                                return (-EPERM);
+                        if(sa->sat_family != AF_APPLETALK)
+                                return (-EINVAL);
+
+                        /*
+                         * give to aarp module to remove proxy entry
+                         */
+                        aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+
+                        return (0);
 	}
 
 	if(copy_to_user(arg, &atreq, sizeof(atreq)))
@@ -849,6 +986,7 @@
 static int atrtr_ioctl(unsigned int cmd, void *arg)
 {
 	struct rtentry rt;
+	struct device *dev = NULL;
 
 	if(copy_from_user(&rt, arg, sizeof(rt)))
 		return (-EFAULT);
@@ -861,7 +999,12 @@
 			return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
 
 		case SIOCADDRT:
-			return (atrtr_create(&rt, NULL));
+			/* FIX ME: the name of the device is still in user space, isn't it? */
+			if (rt.rt_dev != NULL)
+				if ((dev = dev_get(rt.rt_dev)) == NULL)
+					return -(ENODEV);
+			
+			return (atrtr_create(&rt, dev));
 
 		default:
 			return (-EINVAL);
@@ -1004,7 +1147,15 @@
 		case SOCK_DGRAM:
 			sock->ops = &atalk_dgram_ops;
 			break;
-
+			
+		case SOCK_STREAM:
+			/*
+			 * TO DO: if you want to implement ADSP, here's the place to start
+			 */
+			/*
+			sock->ops = &atalk_stream_ops;
+			break;
+			*/
 		default:
 			sk_free((void *)sk);
 			return (-ESOCKTNOSUPPORT);
@@ -1330,6 +1481,13 @@
 		 */
 		if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
 		{
+			/*
+			 * FIX ME:
+			 * Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network?
+			 */
+			if (dev->type == ARPHRD_PPP)
+				printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
+			
 			kfree_skb(skb);
 			return (0);
 		}
@@ -1821,6 +1979,8 @@
 		case SIOCGIFBRDADDR:
 		case SIOCATALKDIFADDR:
 		case SIOCDIFADDR:
+		case SIOCSARP:	/* proxy AARP */
+		case SIOCDARP:	/* proxy AARP */
 			return (atif_ioctl(cmd,(void *)arg));
 
 		/*
@@ -1966,6 +2126,8 @@
 	proc_net_register(&proc_appletalk);
 	proc_net_register(&proc_atalk_route);
 	proc_net_register(&proc_atalk_iface);
+
+	aarp_register_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SYSCTL
@@ -2006,6 +2168,8 @@
 	proc_net_unregister(PROC_NET_ATALK);
 	proc_net_unregister(PROC_NET_AT_ROUTE);
 	proc_net_unregister(PROC_NET_ATIF);
+
+	aarp_unregister_proc_fs();
 #endif /* CONFIG_PROC_FS */
 
 	aarp_cleanup_module();	/* General aarp clean-up. */

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