Call for 2.3.x Appletalk testers...

From: David S. Miller (davem@redhat.com)
Date: Thu Feb 17 2000 - 09:47:29 EST


Hi, I've made an attempt to make the Appletalk protocol
code SMP safe in the new 2.3.x networking stack. However,
I lack both the kit and knowledge necessary to test my
changes.

So I'm calling out for volunteers to test out the code
below. I really don't want to put this into the real
tree until someone properly tests it out and finds that
it at least works for general functionality.

So if someone could test, this would be fantastic. The patch is
appended below, and it should apply to any recent 2.3.x release.

Thanks again.

diff -u --recursive --new-file --exclude=CVS --exclude=.cvsignore vanilla/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- vanilla/linux/net/appletalk/aarp.c Fri Nov 19 11:33:29 1999
+++ linux/net/appletalk/aarp.c Tue Feb 15 08:21:45 2000
@@ -50,6 +50,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 #include <net/sock.h>
 #include <net/datalink.h>
 #include <net/psnap.h>
@@ -67,8 +68,7 @@
  * Lists of aarp entries
  */
  
-struct aarp_entry
-{
+struct aarp_entry {
         /* 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 */
@@ -85,8 +85,13 @@
  * Hashed list of resolved, unresolved and proxy entries
  */
 
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
-static int unresolved_count=0;
+static struct aarp_entry *resolved[AARP_HASH_SIZE];
+static struct aarp_entry *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *proxies[AARP_HASH_SIZE];
+static int unresolved_count = 0;
+
+/* One lock protects it all. */
+static spinlock_t aarp_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Used to walk the list and purge/kick entries.
@@ -96,38 +101,49 @@
 
 /*
  * Delete an aarp queue
+ *
+ * Must run under aarp_lock.
  */
-static void aarp_expire(struct aarp_entry *a)
+static void __aarp_expire(struct aarp_entry *a)
 {
         struct sk_buff *skb;
         
- while((skb=skb_dequeue(&a->packet_queue))!=NULL)
+ while ((skb=skb_dequeue(&a->packet_queue)) != NULL)
                 kfree_skb(skb);
- kfree_s(a,sizeof(*a));
+
+ kfree_s(a, sizeof(*a));
 }
 
 /*
  * Send an aarp queue entry request
+ *
+ * Must run under aarp_lock.
  */
  
-static void aarp_send_query(struct aarp_entry *a)
+static void __aarp_send_query(struct aarp_entry *a)
 {
- static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
- struct net_device *dev=a->dev;
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ static char aarp_eth_multicast[ETH_ALEN] =
+ { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+ struct net_device *dev = a->dev;
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
         struct elapaarp *eah;
- struct at_addr *sat=atalk_find_dev_addr(dev);
+ struct at_addr *sat = atalk_find_dev_addr(dev);
         
- if(skb==NULL || sat==NULL)
+ if (skb == NULL)
+ return;
+
+ if (sat == NULL) {
+ kfree_skb(skb);
                 return;
+ }
         
         /*
          * Set up the buffer.
          */
 
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
         skb->protocol = htons(ETH_P_ATALK);
         skb->nh.raw = skb->h.raw = (void *) eah;
         skb->dev = dev;
@@ -173,21 +189,25 @@
         a->xmit_count++;
 }
 
-static void aarp_send_reply(struct net_device *dev, struct at_addr *us, struct at_addr *them, unsigned char *sha)
+/* This runs under aarp_lock and in softint context, so only
+ * atomic memory allocations can be used.
+ */
+static void aarp_send_reply(struct net_device *dev, struct at_addr *us,
+ struct at_addr *them, unsigned char *sha)
 {
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
         struct elapaarp *eah;
         
- if(skb==NULL)
+ if (skb == NULL)
                 return;
         
         /*
          * Set up the buffer.
          */
 
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
         skb->protocol = htons(ETH_P_ATALK);
         skb->nh.raw = skb->h.raw = (void *) eah;
         skb->dev = dev;
@@ -208,7 +228,7 @@
         eah->pa_src_net = us->s_net;
         eah->pa_src_node= us->s_node;
         
- if(sha==NULL)
+ if (sha == NULL)
                 memset(eah->hw_dst, '\0', ETH_ALEN);
         else
                 memcpy(eah->hw_dst, sha, ETH_ALEN);
@@ -227,110 +247,110 @@
          * Send it.
          */
         dev_queue_xmit(skb);
-
 }
 
 /*
  * Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
  */
-
+
 void aarp_send_probe(struct net_device *dev, struct at_addr *us)
 {
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
         struct elapaarp *eah;
- static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-
- if(skb==NULL)
+ static char aarp_eth_multicast[ETH_ALEN] =
+ { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+
+ if (skb == NULL)
                 return;
-
+
         /*
          * Set up the buffer.
- */
+ */
 
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
         skb->protocol = htons(ETH_P_ATALK);
         skb->nh.raw = skb->h.raw = (void *) eah;
         skb->dev = dev;
-
+
         /*
          * Set up the ARP.
          */
-
+
         eah->hw_type = htons(AARP_HW_TYPE_ETHERNET);
         eah->pa_type = htons(ETH_P_ATALK);
- eah->hw_len = ETH_ALEN;
+ eah->hw_len = ETH_ALEN;
         eah->pa_len = AARP_PA_ALEN;
         eah->function = htons(AARP_PROBE);
-
+
         memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-
+
         eah->pa_src_zero= 0;
         eah->pa_src_net = us->s_net;
         eah->pa_src_node= us->s_node;
-
+
         memset(eah->hw_dst, '\0', ETH_ALEN);
-
+
         eah->pa_dst_zero= 0;
         eah->pa_dst_net = us->s_net;
         eah->pa_dst_node= us->s_node;
-
+
         /*
          * Add ELAP headers and set target to the AARP multicast.
          */
-
- aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);
+
+ aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);
 
         /*
          * Send it.
- */
+ */
         dev_queue_xmit(skb);
-
 }
         
 /*
  * Handle an aarp timer expire
+ *
+ * Must run under the aarp_lock.
  */
 
-static void aarp_expire_timer(struct aarp_entry **n)
+static void __aarp_expire_timer(struct aarp_entry **n)
 {
         struct aarp_entry *t;
- while((*n)!=NULL)
- {
+
+ while ((*n) != NULL) {
                 /* Expired ? */
- if(time_after(jiffies, (*n)->expires_at))
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
+ if(time_after(jiffies, (*n)->expires_at)) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ n = &((*n)->next);
                 }
- else
- n=&((*n)->next);
         }
 }
 
 /*
  * Kick all pending requests 5 times a second.
+ *
+ * Must run under the aarp_lock.
  */
  
-static void aarp_kick(struct aarp_entry **n)
+static void __aarp_kick(struct aarp_entry **n)
 {
         struct aarp_entry *t;
- while((*n)!=NULL)
- {
+
+ while ((*n) != NULL) {
                 /* Expired - if this will be the 11th transmit, we delete
- instead */
- if((*n)->xmit_count>=sysctl_aarp_retransmit_limit)
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
- }
- else
- {
- aarp_send_query(*n);
- n=&((*n)->next);
+ * instead.
+ */
+ if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ __aarp_send_query(*n);
+ n = &((*n)->next);
                 }
         }
 }
@@ -338,21 +358,22 @@
 /*
  * A device has gone down. Take all entries referring to the device
  * and remove them.
+ *
+ * Must run under the aarp_lock.
  */
  
-static void aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
+static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
 {
         struct aarp_entry *t;
- while((*n)!=NULL)
- {
- if((*n)->dev==dev)
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
+
+ while ((*n) != NULL) {
+ if ((*n)->dev == dev) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ n = &((*n)->next);
                 }
- else
- n=&((*n)->next);
         }
 }
                 
@@ -362,15 +383,19 @@
  
 static void aarp_expire_timeout(unsigned long unused)
 {
- int ct=0;
- for(ct=0;ct<AARP_HASH_SIZE;ct++)
- {
- aarp_expire_timer(&resolved[ct]);
- aarp_kick(&unresolved[ct]);
- aarp_expire_timer(&unresolved[ct]);
- aarp_expire_timer(&proxies[ct]);
+ int ct;
+
+ spin_lock_bh(&aarp_lock);
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_timer(&resolved[ct]);
+ __aarp_kick(&unresolved[ct]);
+ __aarp_expire_timer(&unresolved[ct]);
+ __aarp_expire_timer(&proxies[ct]);
         }
 
+ spin_unlock_bh(&aarp_lock);
+
         mod_timer(&aarp_timer, jiffies +
                   (unresolved_count ? sysctl_aarp_tick_time:
                    sysctl_aarp_expiry_time));
@@ -382,77 +407,92 @@
  
 static int aarp_device_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
- int ct=0;
- if(event==NETDEV_DOWN)
- {
- for(ct=0;ct<AARP_HASH_SIZE;ct++)
- {
- aarp_expire_device(&resolved[ct],ptr);
- aarp_expire_device(&unresolved[ct],ptr);
- aarp_expire_device(&proxies[ct],ptr);
+ int ct;
+
+ if (event == NETDEV_DOWN) {
+ spin_lock_bh(&aarp_lock);
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_device(&resolved[ct], ptr);
+ __aarp_expire_device(&unresolved[ct], ptr);
+ __aarp_expire_device(&proxies[ct], ptr);
                 }
+
+ spin_unlock_bh(&aarp_lock);
         }
         return NOTIFY_DONE;
 }
 
 /*
- * Create a new aarp entry.
+ * Create a new aarp entry. This must use GFP_ATOMIC because it
+ * runs while holding spinlocks.
  */
  
 static struct aarp_entry *aarp_alloc(void)
 {
- struct aarp_entry *a=kmalloc(sizeof(struct aarp_entry), GFP_ATOMIC);
- if(a==NULL)
+ struct aarp_entry *a = kmalloc(sizeof(struct aarp_entry), GFP_ATOMIC);
+
+ if (a == NULL)
                 return NULL;
+
         skb_queue_head_init(&a->packet_queue);
+
         return a;
 }
 
 /*
  * Find an entry. We might return an expired but not yet purged entry. We
  * don't care as it will do no harm.
+ *
+ * This must run under the aarp_lock.
  */
-static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct net_device *dev, struct at_addr *sat)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
- while(list)
- {
- if(list->target_addr.s_net==sat->s_net &&
- list->target_addr.s_node==sat->s_node && list->dev==dev)
+static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list,
+ struct net_device *dev,
+ struct at_addr *sat)
+{
+ while (list) {
+ if (list->target_addr.s_net == sat->s_net &&
+ list->target_addr.s_node == sat->s_node &&
+ list->dev == dev)
                         break;
- list=list->next;
+ list = list->next;
         }
- restore_flags(flags);
+
         return list;
 }
 
+/* Called from the DDP code, and thus must be exported. */
 void aarp_proxy_remove(struct net_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);
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(proxies[hash], dev, sa);
         if (a)
- {
- a->expires_at = 0;
-
- }
+ a->expires_at = jiffies - 1;
+
+ spin_unlock_bh(&aarp_lock);
 }
 
-struct at_addr* aarp_proxy_find(struct net_device *dev, struct at_addr *sa)
+/* This must run under aarp_lock. */
+static struct at_addr *__aarp_proxy_find(struct net_device *dev, struct at_addr *sa)
 {
+ struct at_addr *retval;
         struct aarp_entry *a;
         int hash;
 
         hash = sa->s_node % (AARP_HASH_SIZE-1);
- a = aarp_find_entry(proxies[hash], dev, sa);
+
+ retval = NULL;
+ a = __aarp_find_entry(proxies[hash], dev, sa);
         if (a != NULL)
- return sa;
-
- return NULL;
+ retval = sa;
+
+ return retval;
 }
 
         
@@ -468,31 +508,27 @@
     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;
+ /* 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;
+ }
 }
 
 
 void aarp_probe_network(struct atalk_iface *atif)
 {
- if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+ if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) {
                 aarp_send_probe_phase1(atif);
- else
- {
+ } else {
                 unsigned int count;
- for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
- {
+
+ for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
                         aarp_send_probe(atif->dev, &atif->address);
 
                         /*
@@ -511,17 +547,17 @@
 {
         struct aarp_entry *entry;
         unsigned int count;
- int hash;
+ int hash, retval;
         
         /*
          * 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);
+ return -EPROTONOSUPPORT;
                 
         if (atif->dev->type == ARPHRD_PPP)
- return (-EPROTONOSUPPORT);
+ return -EPROTONOSUPPORT;
                 
         /*
          * create a new AARP entry with the flags set to be published --
@@ -529,7 +565,7 @@
          */
         entry = aarp_alloc();
         if (entry == NULL)
- return (-ENOMEM);
+ return -ENOMEM;
         
         entry->expires_at = -1;
         entry->status = ATIF_PROBE;
@@ -537,44 +573,46 @@
         entry->target_addr.s_net = sa->s_net;
         entry->dev = atif->dev;
 
- hash = sa->s_node % (AARP_HASH_SIZE-1);
+ spin_lock_bh(&aarp_lock);
+
+ hash = sa->s_node % (AARP_HASH_SIZE - 1);
         entry->next = proxies[hash];
         proxies[hash] = entry;
         
- for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
- {
+ for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
                 aarp_send_probe(atif->dev, sa);
 
                 /*
                  * Defer 1/10th
                  */
                 current->state = TASK_INTERRUPTIBLE;
+
+ spin_unlock_bh(&aarp_lock);
+
                 schedule_timeout(HZ/10);
                                                 
+ spin_lock_bh(&aarp_lock);
+
                 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)
- {
+ retval = 1;
+
+ if (entry->status & ATIF_PROBE_FAIL) {
                 /* free the entry */
- entry->expires_at = 0;
+ entry->expires_at = jiffies - 1;
                 
                 /* return network full */
- return (-EADDRINUSE);
- }
- else
- {
+ retval = -EADDRINUSE;
+ } else {
                 /* clear the probing flag */
                 entry->status &= ~ATIF_PROBE;
         }
 
- return 1;
+ spin_unlock_bh(&aarp_lock);
+
+ return retval;
 }
 
 
@@ -583,23 +621,21 @@
  */
 int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr)
 {
- static char ddp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+ static char ddp_eth_multicast[ETH_ALEN] = { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
         int hash;
         struct aarp_entry *a;
- unsigned long flags;
         
- skb->nh.raw=skb->data;
+ skb->nh.raw = skb->data;
         
         /*
          * Check for LocalTalk first
          */
          
          
- if(dev->type==ARPHRD_LOCALTLK)
- {
- struct at_addr *at=atalk_find_dev_addr(dev);
- struct ddpehdr *ddp=(struct ddpehdr *)skb->data;
- int ft=2;
+ if (dev->type == ARPHRD_LOCALTLK) {
+ struct at_addr *at = atalk_find_dev_addr(dev);
+ struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
+ int ft = 2;
                 
                 /*
                  * Compressible ?
@@ -608,29 +644,29 @@
                  * (zero matches anything)
                  */
                  
- if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet)
- &&( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) )
- {
- skb_pull(skb,sizeof(struct ddpehdr)-4);
+ if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet) &&
+ ( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) ) {
+ skb_pull(skb, sizeof(struct ddpehdr) - 4);
+
                         /*
                          * The upper two remaining bytes are the port
                          * numbers we just happen to need. Now put the
                          * length in the lower two.
                          */
- *((__u16 *)skb->data)=htons(skb->len);
- ft=1;
+ *((__u16 *)skb->data) = htons(skb->len);
+ ft = 1;
                 }
                 /*
                  * Nice and easy. No AARP type protocols occur here
                  * so we can just shovel it out with a 3 byte LLAP header
                  */
                  
- skb_push(skb,3);
- skb->data[0]=sa->s_node;
- skb->data[1]=at->s_node;
- skb->data[2]=ft;
+ skb_push(skb, 3);
+ skb->data[0] = sa->s_node;
+ skb->data[1] = at->s_node;
+ skb->data[2] = ft;
                  
- if(skb->sk)
+ if (skb->sk)
                         skb->priority = skb->sk->priority;
                 skb->dev = dev;
                 dev_queue_xmit(skb);
@@ -640,10 +676,9 @@
         /*
          * On a PPP link we neither compress nor aarp.
          */
- if(dev->type==ARPHRD_PPP)
- {
+ if (dev->type == ARPHRD_PPP) {
                 skb->protocol = htons(ETH_P_PPPTALK);
- if(skb->sk)
+ if (skb->sk)
                         skb->priority = skb->sk->priority;
                 skb->dev = dev;
                 dev_queue_xmit(skb);
@@ -654,44 +689,43 @@
          * Non ELAP we cannot do.
          */
 
- if(dev->type!=ARPHRD_ETHER)
- {
+ if (dev->type != ARPHRD_ETHER)
                 return -1;
- }
 
         skb->dev = dev;
         skb->protocol = htons(ETH_P_ATALK);
                         
- hash=sa->s_node%(AARP_HASH_SIZE-1);
- save_flags(flags);
- cli();
+ hash = sa->s_node % (AARP_HASH_SIZE - 1);
         
         /*
          * Do we have a resolved entry ?
          */
          
- if(sa->s_node==ATADDR_BCAST)
- {
+ if (sa->s_node == ATADDR_BCAST) {
                 ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast);
- if(skb->sk)
+
+ if (skb->sk)
                         skb->priority = skb->sk->priority;
                 dev_queue_xmit(skb);
- restore_flags(flags);
                 return 1;
         }
- a=aarp_find_entry(resolved[hash],dev,sa);
- if(a!=NULL)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(resolved[hash], dev, sa);
+
+ if (a != NULL) {
                 /*
                  * Return 1 and fill in the address
                  */
 
- a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
+ a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
                 ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
                 if(skb->sk)
                         skb->priority = skb->sk->priority;
                 dev_queue_xmit(skb);
- restore_flags(flags);
+
+ spin_unlock_bh(&aarp_lock);
                 return 1;
         }
 
@@ -699,15 +733,15 @@
          * Do we have an unresolved entry: This is the less common path
          */
 
- a=aarp_find_entry(unresolved[hash],dev,sa);
- if(a!=NULL)
- {
+ a = __aarp_find_entry(unresolved[hash], dev, sa);
+ if (a != NULL) {
                 /*
                  * Queue onto the unresolved queue
                  */
 
                 skb_queue_tail(&a->packet_queue, skb);
- restore_flags(flags);
+
+ spin_unlock_bh(&aarp_lock);
                 return 0;
         }
 
@@ -715,14 +749,13 @@
          * Allocate a new entry
          */
 
- a=aarp_alloc();
- if(a==NULL)
- {
+ a = aarp_alloc();
+ if (a == NULL) {
                 /*
                  * Whoops slipped... good job it's an unreliable
                  * protocol 8)
                  */
- restore_flags(flags);
+ spin_unlock_bh(&aarp_lock);
                 return -1;
         }
 
@@ -731,30 +764,34 @@
          */
 
         skb_queue_tail(&a->packet_queue, skb);
- a->expires_at=jiffies+sysctl_aarp_resolve_time;
- a->dev=dev;
- a->next=unresolved[hash];
- a->target_addr= *sa;
- a->xmit_count=0;
- unresolved[hash]=a;
+ a->expires_at = jiffies + sysctl_aarp_resolve_time;
+ a->dev = dev;
+ a->next = unresolved[hash];
+ a->target_addr = *sa;
+ a->xmit_count = 0;
+ unresolved[hash] = a;
         unresolved_count++;
- restore_flags(flags);
 
         /*
          * Send an initial request for the address
          */
 
- aarp_send_query(a);
+ __aarp_send_query(a);
 
         /*
          * Switch to fast timer if needed (That is if this is the
          * first unresolved entry to get added)
          */
 
- if(unresolved_count==1)
- {
+ if (unresolved_count == 1)
                 mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
- }
+
+
+ /*
+ * Now finally, it is safe to drop the lock.
+ */
+
+ spin_unlock_bh(&aarp_lock);
 
         /*
          * Tell the ddp layer we have taken over for this frame.
@@ -766,39 +803,40 @@
 /*
  * An entry in the aarp unresolved queue has become resolved. Send
  * all the frames queued under it.
+ *
+ * Must run under aarp_lock.
  */
-static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash)
+static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash)
 {
         struct sk_buff *skb;
- while(*list!=NULL)
- {
- if(*list==a)
- {
+
+ while (*list != NULL) {
+ if (*list == a) {
                         unresolved_count--;
- *list=a->next;
-
+
+ *list = a->next;
+
                         /*
                          * Move into the resolved list
                          */
-
- a->next=resolved[hash];
- resolved[hash]=a;
-
+
+ a->next = resolved[hash];
+ resolved[hash] = a;
+
                         /*
                          * Kick frames off
                          */
-
- while((skb=skb_dequeue(&a->packet_queue))!=NULL)
- {
- a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
- ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
- if(skb->sk)
+
+ while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
+ a->expires_at = jiffies + (sysctl_aarp_expiry_time*10);
+ ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
+ if (skb->sk)
                                         skb->priority = skb->sk->priority;
                                 dev_queue_xmit(skb);
                         }
+ } else {
+ list = &((*list)->next);
                 }
- else
- list=&((*list)->next);
         }
 }
 
@@ -811,138 +849,129 @@
         struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
         struct aarp_entry *a;
         struct at_addr sa, *ma, da;
- unsigned long flags;
         int hash;
         struct atalk_iface *ifa;
-
-
+
         /*
- * We only do Ethernet SNAP AARP
+ * We only do Ethernet SNAP AARP.
          */
-
- if(dev->type!=ARPHRD_ETHER)
- {
+
+ if (dev->type != ARPHRD_ETHER) {
                 kfree_skb(skb);
                 return 0;
         }
-
+
         /*
          * Frame size ok ?
          */
-
- if(!skb_pull(skb,sizeof(*ea)))
- {
+
+ if (!skb_pull(skb, sizeof(*ea))) {
                 kfree_skb(skb);
                 return 0;
         }
 
- ea->function=ntohs(ea->function);
-
+ ea->function = ntohs(ea->function);
+
         /*
          * Sanity check fields.
          */
-
- if(ea->function<AARP_REQUEST || ea->function > AARP_PROBE || ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
- ea->pa_src_zero != 0 || ea->pa_dst_zero != 0)
- {
+
+ if (ea->function < AARP_REQUEST ||
+ ea->function > AARP_PROBE ||
+ ea->hw_len != ETH_ALEN ||
+ ea->pa_len != AARP_PA_ALEN ||
+ ea->pa_src_zero != 0 ||
+ ea->pa_dst_zero != 0) {
                 kfree_skb(skb);
                 return 0;
         }
-
- /*
- * Looks good
- */
-
- hash=ea->pa_src_node%(AARP_HASH_SIZE-1);
 
         /*
- * Build an address
+ * Looks good.
          */
-
- sa.s_node=ea->pa_src_node;
- sa.s_net=ea->pa_src_net;
-
+
+ hash = ea->pa_src_node % (AARP_HASH_SIZE - 1);
+
         /*
- * Process the packet
+ * Build an address.
          */
-
- save_flags(flags);
+
+ sa.s_node = ea->pa_src_node;
+ sa.s_net = ea->pa_src_net;
 
         /*
- * Check for replies of me
+ * Process the packet.
+ * Check for replies of me.
          */
-
- ifa=atalk_find_dev(dev);
- if(ifa==NULL)
- {
- restore_flags(flags);
+
+ ifa = atalk_find_dev(dev);
+ if (ifa == NULL) {
                 kfree_skb(skb);
- return 1;
+ return 1;
         }
- if(ifa->status&ATIF_PROBE)
- {
- if(ifa->address.s_node==ea->pa_dst_node && ifa->address.s_net==ea->pa_dst_net)
- {
+
+ if (ifa->status & ATIF_PROBE) {
+ if (ifa->address.s_node == ea->pa_dst_node &&
+ ifa->address.s_net == ea->pa_dst_net) {
                         /*
                          * Fail the probe (in use)
                          */
-
- ifa->status|=ATIF_PROBE_FAIL;
- restore_flags(flags);
+
+ ifa->status |= ATIF_PROBE_FAIL;
                         kfree_skb(skb);
- return 1;
+ 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)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(proxies[hash], dev, &da);
+
+ if (a != NULL) {
+ if (a->status & ATIF_PROBE) {
                         a->status |= ATIF_PROBE_FAIL;
-
+
+ spin_unlock_bh(&aarp_lock);
+
                         /*
- * we do not respond to probe or request packets for
+ * 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)
- {
+ switch (ea->function) {
                 case AARP_REPLY:
- if(unresolved_count==0) /* Speed up */
+ if (unresolved_count == 0) /* Speed up */
                                 break;
+
                         /*
- * Find the entry
+ * Find the entry.
                          */
                          
- 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)
+ if ((a = __aarp_find_entry(unresolved[hash],dev,&sa)) == NULL ||
+ (dev != a->dev))
                                 break;
+
                         /*
- * We can fill one in - this is good
+ * We can fill one in - this is good.
                          */
                          
                         memcpy(a->hwaddr,ea->hw_src,ETH_ALEN);
- aarp_resolved(&unresolved[hash],a,hash);
- if(unresolved_count==0)
- {
- mod_timer(&aarp_timer, jiffies +
- sysctl_aarp_expiry_time);
- }
+ __aarp_resolved(&unresolved[hash],a,hash);
+ if (unresolved_count == 0)
+ mod_timer(&aarp_timer,
+ jiffies + sysctl_aarp_expiry_time);
                         break;
                         
                 case AARP_REQUEST:
@@ -956,100 +985,101 @@
                          * of our proxies before we toss the packet out.
                          */
                          
- sa.s_node=ea->pa_dst_node;
- sa.s_net=ea->pa_dst_net;
+ sa.s_node = ea->pa_dst_node;
+ sa.s_net = ea->pa_dst_net;
 
                         /*
- * see if we have a matching proxy
+ * See if we have a matching proxy.
                          */
- ma = aarp_proxy_find(dev, &sa);
- if (!ma)
- {
- ma=&ifa->address;
- }
- else
- {
+ ma = __aarp_proxy_find(dev, &sa);
+ if (!ma) {
+ ma = &ifa->address;
+ } else {
                                 /*
- * we need to make a copy of the entry
+ * 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)
- {
+ if (ea->function == AARP_PROBE) {
                                 /* A probe implies someone trying to get an
- address. So as a precaution flush any
- entries we have for this address */
- struct aarp_entry *a=aarp_find_entry(
+ * address. So as a precaution flush any
+ * entries we have for this address.
+ */
+ struct aarp_entry *a = __aarp_find_entry(
                                                 resolved[sa.s_node%(AARP_HASH_SIZE-1)],
                                                 skb->dev,
                                                 &sa);
                                 /* Make it expire next tick - that avoids us
- getting into a probe/flush/learn/probe/flush/learn
- cycle during probing of a slow to respond host addr */
- if(a!=NULL)
- a->expires_at=jiffies-1;
+ * getting into a probe/flush/learn/probe/flush/learn
+ * cycle during probing of a slow to respond host addr.
+ */
+ if (a != NULL)
+ a->expires_at = jiffies - 1;
                         }
- if(sa.s_node!=ma->s_node)
+
+ if (sa.s_node != ma->s_node)
                                 break;
- if(sa.s_net && ma->s_net && sa.s_net!=ma->s_net)
+
+ if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
                                 break;
 
- sa.s_node=ea->pa_src_node;
- sa.s_net=ea->pa_src_net;
+ sa.s_node = ea->pa_src_node;
+ sa.s_net = ea->pa_src_net;
                         
                         /*
                          * aarp_my_address has found the address to use for us.
                          */
                          
- aarp_send_reply(dev,ma,&sa,ea->hw_src);
+ aarp_send_reply(dev, ma, &sa, ea->hw_src);
                         break;
- }
- restore_flags(flags);
+ };
+
+ spin_unlock_bh(&aarp_lock);
+
         kfree_skb(skb);
- return 1;
+ return 1;
 }
 
-static struct notifier_block aarp_notifier={
+static struct notifier_block aarp_notifier = {
         aarp_device_event,
         NULL,
         0
 };
 
-static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3};
+static char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
 
 
 void __init aarp_proto_init(void)
 {
- if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
+ if ((aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv)) == NULL)
                 printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
         init_timer(&aarp_timer);
- aarp_timer.function=aarp_expire_timeout;
- aarp_timer.data=0;
- aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
+ aarp_timer.function = aarp_expire_timeout;
+ aarp_timer.data = 0;
+ aarp_timer.expires = jiffies + sysctl_aarp_expiry_time;
         add_timer(&aarp_timer);
         register_netdevice_notifier(&aarp_notifier);
 }
 
-
-
 /*
  * Remove the AARP entries associated with a device.
  */
 void aarp_device_down(struct net_device *dev)
 {
- int ct = 0;
+ int ct;
+
+ spin_lock_bh(&aarp_lock);
 
- for(ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- aarp_expire_device(&resolved[ct], dev);
- aarp_expire_device(&unresolved[ct], dev);
- aarp_expire_device(&proxies[ct], dev);
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_device(&resolved[ct], dev);
+ __aarp_expire_device(&unresolved[ct], dev);
+ __aarp_expire_device(&proxies[ct], dev);
         }
 
- return;
+ spin_unlock_bh(&aarp_lock);
 }
 
 /*
@@ -1064,10 +1094,11 @@
         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)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ 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));
@@ -1090,10 +1121,8 @@
                 }
         }
 
- for (ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- for (entry = unresolved[ct]; entry; entry = entry->next)
- {
+ 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));
@@ -1115,10 +1144,8 @@
                 }
         }
 
- for (ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- for (entry = proxies[ct]; entry; entry = entry->next)
- {
+ 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));
@@ -1140,6 +1167,7 @@
                 }
         }
 
+ spin_unlock_bh(&aarp_lock);
 
         return len;
 }
diff -u --recursive --new-file --exclude=CVS --exclude=.cvsignore vanilla/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- vanilla/linux/net/appletalk/ddp.c Fri Nov 19 11:33:29 1999
+++ linux/net/appletalk/ddp.c Tue Feb 15 09:25:55 2000
@@ -71,6 +71,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 #include <linux/termios.h> /* For TIOCOUTQ/INQ */
 #include <net/datalink.h>
 #include <net/p8022.h>
@@ -118,49 +119,50 @@
 * *
 \**************************************************************************/
 
-static struct sock *atalk_socket_list = NULL;
+static struct sock *atalk_sockets = NULL;
+static spinlock_t atalk_sockets_lock = SPIN_LOCK_UNLOCKED;
 
-/*
- * Note: Sockets may not be removed _during_ an interrupt or inet_bh
- * handler using this technique. They can be added although we do not
- * use this facility.
- */
-
-extern inline void atalk_remove_socket(struct sock *sk)
+extern inline void atalk_insert_socket(struct sock *sk)
 {
- sklist_remove_socket(&atalk_socket_list,sk);
+ spin_lock_bh(&atalk_sockets_lock);
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
+ spin_unlock_bh(&atalk_sockets_lock);
 }
 
-extern inline void atalk_insert_socket(struct sock *sk)
+extern inline void atalk_remove_socket(struct sock *sk)
 {
- sklist_insert_socket(&atalk_socket_list,sk);
+ spin_lock_bh(&atalk_sockets_lock);
+ if (sk->pprev != NULL) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ }
+ spin_unlock_bh(&atalk_sockets_lock);
 }
 
 static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif)
 {
         struct sock *s;
 
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
- if(to->sat_port != s->protinfo.af_at.src_port)
- {
+ spin_lock_bh(&atalk_sockets_lock);
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (to->sat_port != s->protinfo.af_at.src_port)
                         continue;
- }
 
- if(to->sat_addr.s_net == ATADDR_ANYNET
- && to->sat_addr.s_node == ATADDR_BCAST
- && s->protinfo.af_at.src_net == atif->address.s_net)
- {
+ if (to->sat_addr.s_net == ATADDR_ANYNET &&
+ to->sat_addr.s_node == ATADDR_BCAST &&
+ s->protinfo.af_at.src_net == atif->address.s_net)
                         break;
- }
 
- if(to->sat_addr.s_net == s->protinfo.af_at.src_net
- && (to->sat_addr.s_node == s->protinfo.af_at.src_node
- || to->sat_addr.s_node == ATADDR_BCAST
- || to->sat_addr.s_node == ATADDR_ANYNODE))
- {
+ if (to->sat_addr.s_net == s->protinfo.af_at.src_net &&
+ (to->sat_addr.s_node == s->protinfo.af_at.src_node ||
+ to->sat_addr.s_node == ATADDR_BCAST ||
+ to->sat_addr.s_node == ATADDR_ANYNODE))
                         break;
- }
 
                     /* XXXX.0 -- we got a request for this router. make sure
                  * that the node is appropriately set. */
@@ -171,44 +173,80 @@
                         break;
                 }
         }
+ spin_unlock_bh(&atalk_sockets_lock);
 
- return (s);
+ return s;
 }
 
 /*
- * Find a socket in the list.
+ * Try to find a socket matching ADDR in the socket list,
+ * if found then return it. If not, insert SK into the
+ * socket list.
+ *
+ * This entire operation must execute atomically.
  */
-static struct sock *atalk_find_socket(struct sockaddr_at *sat)
+static struct sock *atalk_find_or_insert_socket(struct sock *sk, struct sockaddr_at *sat)
 {
         struct sock *s;
 
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
- if(s->protinfo.af_at.src_net != sat->sat_addr.s_net)
- {
- continue;
- }
+ spin_lock_bh(&atalk_sockets_lock);
 
- if(s->protinfo.af_at.src_node != sat->sat_addr.s_node)
- {
- continue;
- }
-
- if(s->protinfo.af_at.src_port != sat->sat_port)
- {
- continue;
- }
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (s->protinfo.af_at.src_net == sat->sat_addr.s_net &&
+ s->protinfo.af_at.src_node == sat->sat_addr.s_node &&
+ s->protinfo.af_at.src_port == sat->sat_port)
+ break;
+ }
 
- break;
+ if (!s) {
+ /* Wheee, it's free, assign and insert. */
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
         }
 
- return (s);
+ spin_unlock_bh(&atalk_sockets_lock);
+
+ return s;
+}
+
+static void atalk_destroy_timer(unsigned long data)
+{
+ struct sock *sk = (struct sock *) data;
+
+ if (atomic_read(&sk->wmem_alloc) == 0 &&
+ atomic_read(&sk->rmem_alloc) == 0 &&
+ sk->dead) {
+ sock_put(sk);
+ MOD_DEC_USE_COUNT;
+ } else {
+ sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
+ add_timer(&sk->timer);
+ }
 }
 
 extern inline void atalk_destroy_socket(struct sock *sk)
 {
- sklist_destroy_socket(&atalk_socket_list, sk);
- MOD_DEC_USE_COUNT;
+ struct sk_buff *skb;
+
+ atalk_remove_socket(sk);
+
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+ kfree_skb(skb);
+
+ if (atomic_read(&sk->wmem_alloc) == 0 &&
+ atomic_read(&sk->rmem_alloc) == 0 &&
+ sk->dead) {
+ sock_put(sk);
+ MOD_DEC_USE_COUNT;
+ } else {
+ init_timer(&sk->timer);
+ sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
+ sk->timer.function = atalk_destroy_timer;
+ sk->timer.data = (unsigned long) sk;
+ add_timer(&sk->timer);
+ }
 }
 
 /*
@@ -217,51 +255,52 @@
 static int atalk_get_info(char *buffer, char **start, off_t offset, int length)
 {
         struct sock *s;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
 
         /*
          * Output the AppleTalk data for the /proc filesystem.
          */
 
         len += sprintf(buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n");
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
+
+ spin_lock_bh(&atalk_sockets_lock);
+ for (s = atalk_sockets; s != NULL; s = s->next) {
                 len += sprintf(buffer+len,"%02X ", s->type);
                 len += sprintf(buffer+len,"%04X:%02X:%02X ",
- ntohs(s->protinfo.af_at.src_net),
- s->protinfo.af_at.src_node,
- s->protinfo.af_at.src_port);
+ ntohs(s->protinfo.af_at.src_net),
+ s->protinfo.af_at.src_node,
+ s->protinfo.af_at.src_port);
                 len += sprintf(buffer+len,"%04X:%02X:%02X ",
- ntohs(s->protinfo.af_at.dest_net),
- s->protinfo.af_at.dest_node,
- s->protinfo.af_at.dest_port);
+ ntohs(s->protinfo.af_at.dest_net),
+ s->protinfo.af_at.dest_node,
+ s->protinfo.af_at.dest_port);
                 len += sprintf(buffer+len,"%08X:%08X ",
- atomic_read(&s->wmem_alloc),
- atomic_read(&s->rmem_alloc));
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&s->rmem_alloc));
                 len += sprintf(buffer+len,"%02X %d\n", s->state,
- SOCK_INODE(s->socket)->i_uid);
+ SOCK_INODE(s->socket)->i_uid);
 
                 /* Are we still dumping unwanted data then discard the record */
                 pos = begin + len;
 
- if(pos < offset)
- {
+ if (pos < offset) {
                         len = 0; /* Keep dumping into the buffer start */
                         begin = pos;
                 }
- if(pos > offset + length) /* We have dumped enough */
+ if (pos > offset + length) /* We have dumped enough */
                         break;
         }
+ spin_lock_bh(&atalk_sockets_lock);
 
         /* The data in question runs from begin to begin+len */
         *start = buffer + (offset - begin); /* Start of wanted data */
         len -= (offset - begin); /* Remove unwanted header data from length */
- if(len > length)
+ if (len > length)
                 len = length; /* Remove unwanted tail data from length */
 
- return (len);
+ return len;
 }
 
 /**************************************************************************\
@@ -270,8 +309,13 @@
 * *
 \**************************************************************************/
 
+/* Anti-deadlock ordering is router_lock --> iface_lock -DaveM */
 static struct atalk_route *atalk_router_list = NULL;
+static rwlock_t atalk_router_lock = RW_LOCK_UNLOCKED;
+
 static struct atalk_iface *atalk_iface_list = NULL;
+static spinlock_t atalk_iface_lock = SPIN_LOCK_UNLOCKED;
+
 static struct atalk_route atrtr_default; /* For probing devices or in a routerless network */
 
 /*
@@ -287,43 +331,40 @@
         struct atalk_iface **iface = &atalk_iface_list;
         struct atalk_iface *tmp;
 
- while((tmp = *iface) != NULL)
- {
- if(tmp->dev == dev)
- {
+ spin_lock_bh(&atalk_iface_lock);
+ while ((tmp = *iface) != NULL) {
+ if (tmp->dev == dev) {
                         *iface = tmp->next;
                         kfree_s(tmp, sizeof(struct atalk_iface));
- dev->atalk_ptr=NULL;
+ dev->atalk_ptr = NULL;
                         MOD_DEC_USE_COUNT;
- }
- else
+ } else
                         iface = &tmp->next;
         }
-
+ spin_unlock_bh(&atalk_iface_lock);
 }
 
 static struct atalk_iface *atif_add_device(struct net_device *dev, struct at_addr *sa)
 {
         struct atalk_iface *iface = (struct atalk_iface *)
                 kmalloc(sizeof(*iface), GFP_KERNEL);
- unsigned long flags;
 
- if(iface==NULL)
- return (NULL);
+ if (iface == NULL)
+ return NULL;
 
- iface->dev=dev;
- dev->atalk_ptr=iface;
- iface->address= *sa;
- iface->status=0;
- save_flags(flags);
- cli();
- iface->next=atalk_iface_list;
- atalk_iface_list=iface;
- restore_flags(flags);
+ iface->dev = dev;
+ dev->atalk_ptr = iface;
+ iface->address = *sa;
+ iface->status = 0;
+
+ spin_lock_bh(&atalk_iface_lock);
+ iface->next = atalk_iface_list;
+ atalk_iface_list = iface;
+ spin_unlock_bh(&atalk_iface_lock);
 
         MOD_INC_USE_COUNT;
 
- return (iface);
+ return iface;
 }
 
 
@@ -332,60 +373,57 @@
  */
 static int atif_probe_device(struct atalk_iface *atif)
 {
- 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 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 netct, nodect;
 
         /*
          * Offset the network we start probing with.
          */
 
- if(probe_net == ATADDR_ANYNET)
- {
- if(!netrange)
+ if (probe_net == ATADDR_ANYNET) {
+ if (!netrange)
                         probe_net = ntohs(atif->nets.nr_firstnet);
                 else
- probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+ probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies % netrange);
         }
 
- if(probe_node == ATADDR_ANYNODE)
- probe_node = jiffies&0xFF;
+ if (probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies & 0xFF;
 
         /*
          * Scan the networks.
          */
         atif->status |= ATIF_PROBE;
- for(netct = 0; netct <= netrange; netct++)
- {
+ for (netct = 0; netct <= netrange; netct++) {
                 /*
                  * Sweep the available nodes from a given start.
                  */
 
                 atif->address.s_net = htons(probe_net);
- for(nodect = 0; nodect < 256; nodect++)
- {
+ for (nodect = 0; nodect < 256; nodect++) {
                         atif->address.s_node = ((nodect+probe_node) & 0xFF);
- if(atif->address.s_node > 0 && atif->address.s_node<254)
- {
+ if (atif->address.s_node > 0 && atif->address.s_node < 254) {
                                 /*
                                  * Probe a proposed address.
                                  */
                                 aarp_probe_network(atif);
 
- if(!(atif->status & ATIF_PROBE_FAIL)) {
+ if (!(atif->status & ATIF_PROBE_FAIL)) {
                                         atif->status &= ~ATIF_PROBE;
- return (0);
+ return 0;
                                 }
                         }
                         atif->status &= ~ATIF_PROBE_FAIL;
                 }
                 probe_net++;
- if(probe_net > ntohs(atif->nets.nr_lastnet))
+ if (probe_net > ntohs(atif->nets.nr_lastnet))
                         probe_net = ntohs(atif->nets.nr_firstnet);
         }
         atif->status &= ~ATIF_PROBE;
- return (-EADDRINUSE); /* Network is full... */
+
+ return -EADDRINUSE; /* Network is full... */
 }
 
 
@@ -394,46 +432,43 @@
  */
 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 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)
+ if (probe_net == ATADDR_ANYNET) {
+ if (!netrange)
                         probe_net = ntohs(atif->nets.nr_firstnet);
                 else
- probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+ probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies % netrange);
         }
 
- if(probe_node == ATADDR_ANYNODE)
- probe_node = jiffies&0xFF;
+ if (probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies & 0xFF;
                 
         /*
          * Scan the networks.
          */
 
- for(netct = 0; netct <= netrange; netct++)
- {
+ 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))
- {
+ 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);
+ int probe_result = aarp_proxy_probe_network(atif,
+ proxy_addr);
 
                                 if (probe_result == 0)
                                         return 0;
@@ -447,22 +482,23 @@
                         probe_net = ntohs(atif->nets.nr_firstnet);
         }
 
- return (-EADDRINUSE); /* Network is full... */
+ return -EADDRINUSE; /* Network is full... */
 }
 
 
 struct at_addr *atalk_find_dev_addr(struct net_device *dev)
 {
- struct atalk_iface *iface=dev->atalk_ptr;
+ struct atalk_iface *iface = dev->atalk_ptr;
 
         if(iface)
- return (&iface->address);
+ return &iface->address;
 
- return (NULL);
+ return NULL;
 }
 
 static struct at_addr *atalk_find_primary(void)
 {
+ struct at_addr *retval;
         struct atalk_iface *iface;
         struct atalk_iface *fiface = NULL;
 
@@ -470,20 +506,27 @@
          * Return a point-to-point interface only if
          * there is no non-ptp interface available.
          */
- for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
- {
- if(!fiface && !(iface->dev->flags & IFF_LOOPBACK))
- fiface=iface;
- if(!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
- return (&iface->address);
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
+ if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
+ fiface = iface;
+ if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+ retval = &iface->address;
+ goto out;
+ }
         }
 
- if(fiface)
- return (&fiface->address);
- if(atalk_iface_list != NULL)
- return (&atalk_iface_list->address);
- else
- return (NULL);
+ if (fiface) {
+ retval = &fiface->address;
+ } else if (atalk_iface_list != NULL) {
+ retval = &atalk_iface_list->address;
+ } else {
+ retval = NULL;
+ }
+out:
+ spin_unlock_bh(&atalk_iface_lock);
+
+ return retval;
 }
 
 /*
@@ -494,13 +537,15 @@
 {
         struct atalk_iface *iface=dev->atalk_ptr;
 
- if(iface==NULL || (iface->status & ATIF_PROBE))
- return (NULL);
- if(node == ATADDR_BCAST || iface->address.s_node == node
- || node == ATADDR_ANYNODE)
- return (iface);
+ if (iface==NULL || (iface->status & ATIF_PROBE))
+ return NULL;
 
- return (NULL);
+ if (node == ATADDR_BCAST ||
+ iface->address.s_node == node ||
+ node == ATADDR_ANYNODE)
+ return iface;
+
+ return NULL;
 }
 
 /*
@@ -510,22 +555,24 @@
 {
         struct atalk_iface *iface;
 
- for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
- {
- if((node==ATADDR_BCAST || node==ATADDR_ANYNODE
- || iface->address.s_node==node)
- && iface->address.s_net==net
- && !(iface->status & ATIF_PROBE))
- return (iface);
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
+ if ((node == ATADDR_BCAST ||
+ node == ATADDR_ANYNODE ||
+ iface->address.s_node == node) &&
+ iface->address.s_net == net &&
+ !(iface->status & ATIF_PROBE))
+ break;
 
                 /* XXXX.0 -- net.0 returns the iface associated with net */
- if ((node==ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
+ if ((node == ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
                     (ntohs(iface->nets.nr_firstnet) <= ntohs(net)) &&
                     (ntohs(net) <= ntohs(iface->nets.nr_lastnet)))
- return (iface);
+ break;
         }
+ spin_unlock_bh(&atalk_iface_lock);
 
- return (NULL);
+ return iface;
 }
 
 
@@ -544,23 +591,20 @@
         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))
+ read_lock_bh(&atalk_router_lock);
+ 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)
- {
+
+ if (r->target.s_net == target->s_net) {
+ 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
- {
+ goto out;
+ } else {
                                 /*
                                  * this route will work if there isn't a
                                  * direct host route, so cache it
@@ -574,13 +618,20 @@
          * 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);
+ if (net_route != NULL) {
+ r = net_route;
+ } else if (atrtr_default.dev) {
+ r = &atrtr_default;
+ } else {
+ /*
+ * No route can be found.
+ */
+ r = NULL;
+ }
 
- return (NULL);
+out:
+ read_unlock_bh(&atalk_router_lock);
+ return r;
 }
 
 
@@ -590,12 +641,12 @@
  */
 struct net_device *atrtr_get_dev(struct at_addr *sa)
 {
- struct atalk_route *atr=atrtr_find(sa);
+ struct atalk_route *atr = atrtr_find(sa);
 
- if(atr == NULL)
- return (NULL);
+ if (atr == NULL)
+ return NULL;
         else
- return (atr->dev);
+ return atr->dev;
 }
 
 /*
@@ -616,13 +667,11 @@
  */
 static int atrtr_create(struct rtentry *r, struct net_device *devhint)
 {
- struct sockaddr_at *ta=(struct sockaddr_at *)&r->rt_dst;
- struct sockaddr_at *ga=(struct sockaddr_at *)&r->rt_gateway;
+ struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;
+ struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;
         struct atalk_route *rt;
         struct atalk_iface *iface, *riface;
- unsigned long flags;
-
- save_flags(flags);
+ int retval;
 
         /*
          * Fixme: Raise/Lower a routing change semaphore for these
@@ -632,53 +681,59 @@
         /*
          * Validate the request
          */
- if(ta->sat_family != AF_APPLETALK)
- return (-EINVAL);
- if(devhint == NULL && ga->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (ta->sat_family != AF_APPLETALK)
+ return -EINVAL;
+
+ if (devhint == NULL && ga->sat_family != AF_APPLETALK)
+ return -EINVAL;
 
         /*
          * Now walk the routing table and make our decisions.
          */
- for(rt=atalk_router_list; rt!=NULL; rt=rt->next)
- {
- if(r->rt_flags != rt->flags)
+ write_lock_bh(&atalk_router_lock);
+ for (rt = atalk_router_list; rt != NULL; rt = rt->next) {
+ if (r->rt_flags != rt->flags)
                         continue;
 
- if(ta->sat_addr.s_net == rt->target.s_net)
- {
- if(!(rt->flags & RTF_HOST))
+ if (ta->sat_addr.s_net == rt->target.s_net) {
+ if (!(rt->flags & RTF_HOST))
                                 break;
- if(ta->sat_addr.s_node == rt->target.s_node)
+ if (ta->sat_addr.s_node == rt->target.s_node)
                                 break;
                 }
         }
 
- if(devhint == NULL)
- {
- for(riface = NULL, iface = atalk_iface_list; iface; iface = iface->next)
- {
- if(riface == NULL && ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) &&
- ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet))
- {
+ if(devhint == NULL) {
+ riface = NULL;
+
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface; iface = iface->next) {
+ if (riface == NULL &&
+ ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) &&
+ ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet))
                                 riface = iface;
- }
- if(ga->sat_addr.s_net == iface->address.s_net
- && ga->sat_addr.s_node == iface->address.s_node)
+
+ if (ga->sat_addr.s_net == iface->address.s_net &&
+ ga->sat_addr.s_node == iface->address.s_node)
                                 riface = iface;
- }
+ }
+ spin_unlock_bh(&atalk_iface_lock);
+
+ retval = -ENETUNREACH;
+ if (riface == NULL)
+ goto out;
 
- if(riface == NULL)
- return (-ENETUNREACH);
                 devhint = riface->dev;
         }
 
- if(rt == NULL)
- {
- rt = (struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_KERNEL);
- if(rt == NULL)
- return (-ENOBUFS);
- cli();
+ if (rt == NULL) {
+ rt = (struct atalk_route *)
+ kmalloc(sizeof(struct atalk_route), GFP_ATOMIC);
+
+ retval = -ENOBUFS;
+ if (rt == NULL)
+ goto out;
+
                 rt->next = atalk_router_list;
                 atalk_router_list = rt;
         }
@@ -691,33 +746,38 @@
         rt->flags = r->rt_flags;
         rt->gateway = ga->sat_addr;
 
- restore_flags(flags);
+ retval = 0;
 
- return (0);
+out:
+ write_unlock_bh(&atalk_router_lock);
+
+ return retval;
 }
 
 /*
  * Delete a route. Find it and discard it.
  */
-static int atrtr_delete( struct at_addr *addr )
+static int atrtr_delete(struct at_addr * addr)
 {
         struct atalk_route **r = &atalk_router_list;
         struct atalk_route *tmp;
+ int retval = 0;
 
- while((tmp = *r) != NULL)
- {
- if(tmp->target.s_net == addr->s_net
- && (!(tmp->flags&RTF_GATEWAY)
- || tmp->target.s_node == addr->s_node))
- {
+ write_lock_bh(&atalk_router_lock);
+ while ((tmp = *r) != NULL) {
+ if (tmp->target.s_net == addr->s_net &&
+ (!(tmp->flags&RTF_GATEWAY) ||
+ tmp->target.s_node == addr->s_node)) {
                         *r = tmp->next;
                         kfree_s(tmp, sizeof(struct atalk_route));
- return (0);
+ goto out;
                 }
                 r = &tmp->next;
         }
-
- return (-ENOENT);
+ retval = -ENOENT;
+out:
+ write_unlock_bh(&atalk_router_lock);
+ return retval;
 }
 
 /*
@@ -729,18 +789,18 @@
         struct atalk_route **r = &atalk_router_list;
         struct atalk_route *tmp;
 
- while((tmp = *r) != NULL)
- {
- if(tmp->dev == dev)
- {
+ write_lock_bh(&atalk_router_lock);
+ while ((tmp = *r) != NULL) {
+ if (tmp->dev == dev) {
                         *r = tmp->next;
                         kfree_s(tmp, sizeof(struct atalk_route));
- }
- else
+ } else {
                         r = &tmp->next;
+ }
         }
+ write_unlock_bh(&atalk_router_lock);
 
- if(atrtr_default.dev == dev)
+ if (atrtr_default.dev == dev)
                 atrtr_set_default(NULL);
 }
 
@@ -760,13 +820,12 @@
  */
 static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
- if(event == NETDEV_DOWN)
- {
+ if (event == NETDEV_DOWN) {
                 /* Discard any use of this */
                 atalk_dev_down((struct net_device *) ptr);
         }
 
- return (NOTIFY_DONE);
+ return NOTIFY_DONE;
 }
 
 /*
@@ -789,29 +848,28 @@
         struct rtentry rtdef;
         int add_route;
 
- if(copy_from_user(&atreq,arg,sizeof(atreq)))
- return (-EFAULT);
+ if (copy_from_user(&atreq, arg, sizeof(atreq)))
+ return -EFAULT;
 
- if((dev = __dev_get_by_name(atreq.ifr_name)) == NULL)
- return (-ENODEV);
+ if ((dev = __dev_get_by_name(atreq.ifr_name)) == NULL)
+ return -ENODEV;
 
- sa=(struct sockaddr_at*)&atreq.ifr_addr;
- atif=atalk_find_dev(dev);
+ sa = (struct sockaddr_at*) &atreq.ifr_addr;
+ atif = atalk_find_dev(dev);
 
- switch(cmd)
- {
+ switch (cmd) {
                 case SIOCSIFADDR:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
- if(dev->type != ARPHRD_ETHER
- && dev->type != ARPHRD_LOOPBACK
- && dev->type != ARPHRD_LOCALTLK
- && dev->type != ARPHRD_PPP)
- return (-EPROTONOSUPPORT);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
+ if (dev->type != ARPHRD_ETHER &&
+ dev->type != ARPHRD_LOOPBACK &&
+ dev->type != ARPHRD_LOCALTLK &&
+ dev->type != ARPHRD_PPP)
+ return -EPROTONOSUPPORT;
 
- nr=(struct netrange *)&sa->sat_zero[0];
+ nr = (struct netrange *) &sa->sat_zero[0];
 
                         add_route = 1;
 
@@ -819,8 +877,8 @@
                          * 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))
- {
+ 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;
                         }
@@ -829,123 +887,123 @@
                          * 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);
- if(atif)
- {
+ 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;
+ if (atif) {
                                 /*
                                  * Already setting address.
                                  */
- if(atif->status&ATIF_PROBE)
- return (-EBUSY);
+ if (atif->status & ATIF_PROBE)
+ return -EBUSY;
 
                                 atif->address.s_net = sa->sat_addr.s_net;
                                 atif->address.s_node = sa->sat_addr.s_node;
                                 atrtr_device_down(dev); /* Flush old routes */
- }
- else
- {
- atif=atif_add_device(dev, &sa->sat_addr);
+ } else {
+ atif = atif_add_device(dev, &sa->sat_addr);
                                 if (atif == NULL)
- return (-ENOMEM);
+ return -ENOMEM;
                         }
- atif->nets= *nr;
+ atif->nets = *nr;
 
                         /*
                          * Check if the chosen address is used. If so we
                          * error and atalkd will try another.
                          */
 
- if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && 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);
+ return -EADDRINUSE;
                         }
 
                         /*
                          * Hey it worked - add the direct routes.
                          */
 
- sa = (struct sockaddr_at *)&rtdef.rt_gateway;
+ sa = (struct sockaddr_at *) &rtdef.rt_gateway;
                         sa->sat_family = AF_APPLETALK;
                         sa->sat_addr.s_net = atif->address.s_net;
                         sa->sat_addr.s_node = atif->address.s_node;
- sa = (struct sockaddr_at *)&rtdef.rt_dst;
+ sa = (struct sockaddr_at *) &rtdef.rt_dst;
                         rtdef.rt_flags = RTF_UP;
                         sa->sat_family = AF_APPLETALK;
                         sa->sat_addr.s_node = ATADDR_ANYNODE;
- if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
+ if ((dev->flags & IFF_LOOPBACK) ||
+ (dev->flags & IFF_POINTOPOINT))
                                 rtdef.rt_flags |= RTF_HOST;
 
                         /*
                          * Routerless initial state.
                          */
- if(nr->nr_firstnet == htons(0)
- && nr->nr_lastnet == htons(0xFFFE))
- {
+ if (nr->nr_firstnet == htons(0) &&
+ nr->nr_lastnet == htons(0xFFFE)) {
                                 sa->sat_addr.s_net = atif->address.s_net;
                                 atrtr_create(&rtdef, dev);
                                 atrtr_set_default(dev);
- }
- else
- {
+ } else {
                                 limit = ntohs(nr->nr_lastnet);
- if(limit - ntohs(nr->nr_firstnet) > 4096)
- {
+ if (limit - ntohs(nr->nr_firstnet) > 4096) {
                                         printk(KERN_WARNING "Too many routes/iface.\n");
- return (-EINVAL);
+ return -EINVAL;
                                 }
- if (add_route)
- for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
- {
+ 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);
+ return 0;
 
                 case SIOCGIFADDR:
- if(atif == NULL)
- return (-EADDRNOTAVAIL);
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr=atif->address;
+ if (atif == NULL)
+ return -EADDRNOTAVAIL;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =
+ AF_APPLETALK;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr =
+ atif->address;
                         break;
 
                 case SIOCGIFBRDADDR:
- if(atif == NULL)
- return (-EADDRNOTAVAIL);
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST;
+ if (atif == NULL)
+ return -EADDRNOTAVAIL;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =
+ AF_APPLETALK;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net =
+ atif->address.s_net;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node =
+ ATADDR_BCAST;
                         break;
 
                 case SIOCATALKDIFADDR:
                 case SIOCDIFADDR:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
                         atalk_dev_down(dev);
                         break;
 
                 case SIOCSARP:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
                         if (atif == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
 
                         /*
                          * 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);
+ if (dev->type != ARPHRD_ETHER)
+ return -EPROTONOSUPPORT;
 
                         /*
                          * atif points to the current interface on this network;
@@ -954,28 +1012,28 @@
                          * to probe. consequently, it must exist.
                          */
                         if (!atif)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
 
- nr=(struct netrange *)&(atif->nets);
+ 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 (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);
+ 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);
+ 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
@@ -984,25 +1042,25 @@
                         break;
 
                 case SIOCDARP:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
                         if (atif == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
 
                         /*
                          * give to aarp module to remove proxy entry
                          */
                         aarp_proxy_remove(atif->dev, &(sa->sat_addr));
 
- return (0);
- }
+ return 0;
+ };
 
- if(copy_to_user(arg, &atreq, sizeof(atreq)))
- return (-EFAULT);
+ if (copy_to_user(arg, &atreq, sizeof(atreq)))
+ return -EFAULT;
 
- return (0);
+ return 0;
 }
 
 /*
@@ -1013,27 +1071,26 @@
         struct rtentry rt;
         struct net_device *dev = NULL;
 
- if(copy_from_user(&rt, arg, sizeof(rt)))
- return (-EFAULT);
+ if (copy_from_user(&rt, arg, sizeof(rt)))
+ return -EFAULT;
 
- switch(cmd)
- {
+ switch (cmd) {
                 case SIOCDELRT:
- if(rt.rt_dst.sa_family != AF_APPLETALK)
- return (-EINVAL);
- return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
+ if (rt.rt_dst.sa_family != AF_APPLETALK)
+ return -EINVAL;
+ return atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr);
 
                 case SIOCADDRT:
                         /* FIX ME: the name of the device is still in user space, isn't it? */
- if (rt.rt_dev != NULL)
+ if (rt.rt_dev != NULL) {
                                 if ((dev = __dev_get_by_name(rt.rt_dev)) == NULL)
- return -(ENODEV);
-
- return (atrtr_create(&rt, dev));
+ return -ENODEV;
+ }
+ return atrtr_create(&rt, dev);
 
                 default:
- return (-EINVAL);
- }
+ return -EINVAL;
+ };
 }
 
 /* Called from proc fs - just make it print the ifaces neatly */
@@ -1041,29 +1098,31 @@
 static int atalk_if_get_info(char *buffer, char **start, off_t offset, int length)
 {
         struct atalk_iface *iface;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
 
         len += sprintf(buffer,"Interface Address Networks Status\n");
- for(iface = atalk_iface_list; iface != NULL; iface = iface->next)
- {
+
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
                 len += sprintf(buffer+len,"%-16s %04X:%02X %04X-%04X %d\n",
- iface->dev->name, ntohs(iface->address.s_net),
- iface->address.s_node, ntohs(iface->nets.nr_firstnet),
- ntohs(iface->nets.nr_lastnet), iface->status);
+ iface->dev->name, ntohs(iface->address.s_net),
+ iface->address.s_node, ntohs(iface->nets.nr_firstnet),
+ ntohs(iface->nets.nr_lastnet), iface->status);
                 pos = begin + len;
- if(pos < offset)
- {
+ if (pos < offset) {
                         len = 0;
                         begin = pos;
                 }
- if(pos > offset + length)
+ if (pos > offset + length)
                         break;
         }
+ spin_unlock_bh(&atalk_iface_lock);
+
         *start = buffer + (offset - begin);
         len -= (offset - begin);
- if(len > length)
+ if (len > length)
                 len = length;
 
         return (len);
@@ -1074,41 +1133,40 @@
 static int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length)
 {
         struct atalk_route *rt;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
 
         len += sprintf(buffer,"Target Router Flags Dev\n");
- if(atrtr_default.dev)
- {
+ if (atrtr_default.dev) {
                 rt = &atrtr_default;
                 len += sprintf(buffer+len,"Default %04X:%02X %-4d %s\n",
- ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
- rt->dev->name);
+ ntohs(rt->gateway.s_net), rt->gateway.s_node,
+ rt->flags, rt->dev->name);
         }
 
- for(rt = atalk_router_list; rt != NULL; rt = rt->next)
- {
+ read_lock_bh(&atalk_router_lock);
+ for (rt = atalk_router_list; rt != NULL; rt = rt->next) {
                 len += sprintf(buffer+len,"%04X:%02X %04X:%02X %-4d %s\n",
- ntohs(rt->target.s_net),rt->target.s_node,
- ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
- rt->dev->name);
+ ntohs(rt->target.s_net), rt->target.s_node,
+ ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
+ rt->dev->name);
                 pos = begin + len;
- if(pos < offset)
- {
+ if (pos < offset) {
                         len = 0;
                         begin = pos;
                 }
- if(pos > offset + length)
+ if (pos > offset + length)
                         break;
         }
+ read_unlock_bh(&atalk_router_lock);
 
         *start = buffer + (offset - begin);
         len -= (offset - begin);
- if(len > length)
+ if (len > length)
                 len = length;
 
- return (len);
+ return len;
 }
 
 /**************************************************************************\
@@ -1124,27 +1182,25 @@
  */
 unsigned short atalk_checksum(struct ddpehdr *ddp, int len)
 {
- unsigned long sum=0; /* Assume unsigned long is >16 bits */
- unsigned char *data=(unsigned char *)ddp;
+ unsigned long sum = 0; /* Assume unsigned long is >16 bits */
+ unsigned char *data = (unsigned char *) ddp;
 
         len -= 4; /* skip header 4 bytes */
         data += 4;
 
         /* This ought to be unwrapped neatly. I'll trust gcc for now */
- while(len--)
- {
+ while (len--) {
                 sum += *data;
                 sum <<= 1;
- if(sum & 0x10000)
- {
+ if (sum & 0x10000) {
                         sum++;
                         sum &= 0xFFFF;
                 }
                 data++;
         }
 
- if(sum)
- return htons((unsigned short)sum);
+ if (sum)
+ return htons((unsigned short) sum);
 
         return 0xFFFF; /* Use 0xFFFF for 0. 0 itself means none */
 }
@@ -1158,11 +1214,10 @@
         struct sock *sk;
 
         sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1);
- if(sk == NULL)
- return (-ENOMEM);
+ if (sk == NULL)
+ return -ENOMEM;
 
- switch(sock->type)
- {
+ switch (sock->type) {
                 /*
                  * We permit SOCK_DGRAM and RAW is an extension. It is
                  * trivial to do and gives you the full ELAP frame.
@@ -1182,19 +1237,19 @@
                         break;
                         */
                 default:
- sk_free((void *)sk);
- return (-ESOCKTNOSUPPORT);
- }
+ sk_free((void *) sk);
+ return -ESOCKTNOSUPPORT;
+ };
 
         MOD_INC_USE_COUNT;
 
- sock_init_data(sock,sk);
+ sock_init_data(sock, sk);
 
         sk->destruct = NULL;
         /* Checksums on by default */
         sk->zapped = 1;
 
- return (0);
+ return 0;
 }
 
 /*
@@ -1204,32 +1259,63 @@
 {
         struct sock *sk=sock->sk;
 
- if(sk == NULL)
- return (0);
+ if (sk == NULL)
+ return 0;
 
- if(!sk->dead)
+ if (!sk->dead)
                 sk->state_change(sk);
 
         sk->dead = 1;
         sock->sk = NULL;
         atalk_destroy_socket(sk);
 
- return (0);
+ return 0;
 }
 
 /*
- * Pick a source address if one is not given. Just return
- * an error if not supportable.
+ * Pick a source port when one is not given. If we can
+ * find a suitable free one, we insert the socket into
+ * the tables using it.
+ *
+ * This whole operation must be atomic.
  */
-static int atalk_pick_port(struct sockaddr_at *sat)
+static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat)
 {
- for(sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++)
- {
- if(atalk_find_socket(sat) == NULL)
- return sat->sat_port;
+ struct sock *s;
+ int retval;
+
+ spin_lock_bh(&atalk_sockets_lock);
+
+ for (sat->sat_port = ATPORT_RESERVED;
+ sat->sat_port < ATPORT_LAST;
+ sat->sat_port++) {
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (s->protinfo.af_at.src_net == sat->sat_addr.s_net &&
+ s->protinfo.af_at.src_node == sat->sat_addr.s_node &&
+ s->protinfo.af_at.src_port == sat->sat_port)
+ goto try_next_port;
+ }
+
+ /* Wheee, it's free, assign and insert. */
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
+
+ sk->protinfo.af_at.src_port = sat->sat_port;
+
+ retval = 0;
+ goto out;
+
+ try_next_port:
+ ;
         }
 
- return (-EBUSY);
+ retval = -EBUSY;
+out:
+ spin_unlock_bh(&atalk_sockets_lock);
+
+ return retval;
 }
 
 static int atalk_autobind(struct sock *sk)
@@ -1238,20 +1324,18 @@
         struct sockaddr_at sat;
         int n;
 
- if(ap == NULL || ap->s_net == htons(ATADDR_ANYNET))
- return (-EADDRNOTAVAIL);
+ if (ap == NULL || ap->s_net == htons(ATADDR_ANYNET))
+ return -EADDRNOTAVAIL;
 
         sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net;
         sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node;
 
- if((n = atalk_pick_port(&sat)) < 0)
- return (n);
+ if ((n = atalk_pick_and_bind_port(sk, &sat)) < 0)
+ return n;
 
- sk->protinfo.af_at.src_port = n;
- atalk_insert_socket(sk);
         sk->zapped = 0;
 
- return (0);
+ return 0;
 }
 
 /*
@@ -1260,95 +1344,87 @@
 static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
         struct sock *sk;
- struct sockaddr_at *addr=(struct sockaddr_at *)uaddr;
+ struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;
 
         sk = sock->sk;
 
         if(sk->zapped == 0)
- return (-EINVAL);
+ return -EINVAL;
 
         if(addr_len != sizeof(struct sockaddr_at))
- return (-EINVAL);
+ return -EINVAL;
 
         if(addr->sat_family != AF_APPLETALK)
- return (-EAFNOSUPPORT);
+ return -EAFNOSUPPORT;
 
- if(addr->sat_addr.s_net == htons(ATADDR_ANYNET))
- {
- struct at_addr *ap=atalk_find_primary();
+ if(addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {
+ struct at_addr *ap = atalk_find_primary();
 
                 if(ap == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
 
                 sk->protinfo.af_at.src_net = addr->sat_addr.s_net = ap->s_net;
                 sk->protinfo.af_at.src_node = addr->sat_addr.s_node= ap->s_node;
- }
- else
- {
- if(atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL)
- return (-EADDRNOTAVAIL);
+ } else {
+ if (atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL)
+ return -EADDRNOTAVAIL;
 
                 sk->protinfo.af_at.src_net = addr->sat_addr.s_net;
                 sk->protinfo.af_at.src_node = addr->sat_addr.s_node;
         }
 
- if(addr->sat_port == ATADDR_ANYPORT)
- {
- int n = atalk_pick_port(addr);
- if(n < 0)
- return (n);
+ if (addr->sat_port == ATADDR_ANYPORT) {
+ int n = atalk_pick_and_bind_port(sk, addr);
 
- sk->protinfo.af_at.src_port = addr->sat_port = n;
- }
- else
+ if (n < 0)
+ return n;
+ } else
                 sk->protinfo.af_at.src_port = addr->sat_port;
 
- if(atalk_find_socket(addr) != NULL)
- return (-EADDRINUSE);
+ if (atalk_find_or_insert_socket(sk, addr) != NULL)
+ return -EADDRINUSE;
 
- atalk_insert_socket(sk);
         sk->zapped = 0;
 
- return (0);
+ return 0;
 }
 
 /*
  * Set the address we talk to.
  */
 static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
+ int addr_len, int flags)
 {
- struct sock *sk=sock->sk;
+ struct sock *sk = sock->sk;
         struct sockaddr_at *addr;
 
         sk->state = TCP_CLOSE;
         sock->state = SS_UNCONNECTED;
 
- if(addr_len != sizeof(*addr))
- return (-EINVAL);
+ if (addr_len != sizeof(*addr))
+ return -EINVAL;
+
         addr = (struct sockaddr_at *)uaddr;
 
- if(addr->sat_family != AF_APPLETALK)
- return (-EAFNOSUPPORT);
+ if (addr->sat_family != AF_APPLETALK)
+ return -EAFNOSUPPORT;
 
- if(addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast)
- {
+ if (addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) {
 #if 1
                 printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n",
                         current->comm);
 #else
- return (-EACCES);
+ return -EACCES;
 #endif
         }
 
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-EBUSY);
+ if (sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -EBUSY;
         }
 
- if(atrtr_get_dev(&addr->sat_addr) == NULL)
- return (-ENETUNREACH);
+ if (atrtr_get_dev(&addr->sat_addr) == NULL)
+ return -ENETUNREACH;
 
         sk->protinfo.af_at.dest_port = addr->sat_port;
         sk->protinfo.af_at.dest_net = addr->sat_addr.s_net;
@@ -1357,7 +1433,7 @@
         sock->state = SS_CONNECTED;
         sk->state = TCP_ESTABLISHED;
 
- return (0);
+ return 0;
 }
 
 
@@ -1366,30 +1442,27 @@
  * fields into the sockaddr.
  */
 static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
+ int *uaddr_len, int peer)
 {
         struct sockaddr_at sat;
         struct sock *sk;
 
         sk = sock->sk;
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-ENOBUFS);
+ if (sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -ENOBUFS;
         }
 
         *uaddr_len = sizeof(struct sockaddr_at);
 
- if(peer)
- {
- if(sk->state != TCP_ESTABLISHED)
- return (-ENOTCONN);
+ if (peer) {
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+
                 sat.sat_addr.s_net = sk->protinfo.af_at.dest_net;
                 sat.sat_addr.s_node = sk->protinfo.af_at.dest_node;
                 sat.sat_port = sk->protinfo.af_at.dest_port;
- }
- else
- {
+ } else {
                 sat.sat_addr.s_net = sk->protinfo.af_at.src_net;
                 sat.sat_addr.s_node = sk->protinfo.af_at.src_node;
                 sat.sat_port = sk->protinfo.af_at.src_port;
@@ -1398,7 +1471,7 @@
         sat.sat_family = AF_APPLETALK;
         memcpy(uaddr, &sat, sizeof(sat));
 
- return (0);
+ return 0;
 }
 
 /*
@@ -1411,17 +1484,16 @@
 static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
 {
         struct sock *sock;
- struct ddpehdr *ddp=(void *)skb->h.raw;
+ struct ddpehdr *ddp = (void *) skb->h.raw;
         struct atalk_iface *atif;
         struct sockaddr_at tosat;
         int origlen;
         struct ddpebits ddphv;
 
         /* Size check */
- if(skb->len < sizeof(*ddp))
- {
+ if (skb->len < sizeof(*ddp)) {
                 kfree_skb(skb);
- return (0);
+ return 0;
         }
 
         /*
@@ -1449,26 +1521,24 @@
          * (Otherwise we'll detonate most spectacularly
          * in the middle of recvmsg()).
          */
- if(skb->len < sizeof(*ddp))
- {
+ if (skb->len < sizeof(*ddp)) {
                 kfree_skb(skb);
- return (0);
+ return 0;
         }
 
         /*
          * Any checksums. Note we don't do htons() on this == is assumed to be
          * valid for net byte orders all over the networking code...
          */
- if(ddp->deh_sum && atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum)
- {
+ if (ddp->deh_sum && atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum) {
                 /* Not a valid AppleTalk frame - dustbin time */
                 kfree_skb(skb);
- return (0);
+ return 0;
         }
 
         /* Check the packet is aimed at us */
 
- if(ddp->deh_dnet == 0) /* Net 0 is 'this network' */
+ if (ddp->deh_dnet == 0) /* Net 0 is 'this network' */
                 atif = atalk_find_anynet(ddp->deh_dnode, dev);
         else
                 atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
@@ -1476,8 +1546,7 @@
         /*
          * Not ours, so we route the packet via the correct AppleTalk interface.
          */
- if(atif == NULL)
- {
+ if (atif == NULL) {
                 struct atalk_route *rt;
                 struct at_addr ta;
 
@@ -1485,8 +1554,7 @@
                  * Don't route multicast, etc., packets, or packets
                  * sent to "this network"
                  */
- if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
- {
+ 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?
@@ -1495,7 +1563,7 @@
                                 printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
                         
                         kfree_skb(skb);
- return (0);
+ return 0;
                 }
 
                 ta.s_net = ddp->deh_dnet;
@@ -1503,10 +1571,9 @@
 
                 /* Route the packet */
                 rt = atrtr_find(&ta);
- if(rt == NULL || ddphv.deh_hops == DDP_MAXHOPS)
- {
+ if (rt == NULL || ddphv.deh_hops == DDP_MAXHOPS) {
                         kfree_skb(skb);
- return (0);
+ return 0;
                 }
                 ddphv.deh_hops++;
 
@@ -1514,8 +1581,7 @@
                  * Route goes through another gateway, so
                  * set the target to the gateway instead.
                  */
- if(rt->flags & RTF_GATEWAY)
- {
+ if (rt->flags & RTF_GATEWAY) {
                         ta.s_net = rt->gateway.s_net;
                         ta.s_node = rt->gateway.s_node;
                 }
@@ -1539,7 +1605,7 @@
                  *
                  * Note. ddp-> becomes invalid at the realloc.
                  */
- if(skb_headroom(skb) < 22)
+ if (skb_headroom(skb) < 22)
                         /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
                         skb = skb_realloc_headroom(skb, 32);
                 else
@@ -1549,26 +1615,24 @@
                  * If the buffer didn't vanish into the lack of
                  * space bitbucket we can send it.
                  */
- if(skb)
- {
- if(aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)
+ if (skb) {
+ if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)
                                 kfree_skb(skb);
                 }
 
- return (0);
+ return 0;
         }
 
 #if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
         /*
          * Check if IP-over-DDP
          */
- if(skb->data[12] == 22)
- {
+ if (skb->data[12] == 22) {
                 struct net_device *dev;
 
                 /* This needs to be able to handle ipddp"N" devices */
- if((dev = __dev_get_by_name("ipddp0")) == NULL)
- return (-ENODEV);
+ if ((dev = __dev_get_by_name("ipddp0")) == NULL)
+ return -ENODEV;
 
                 skb->protocol = htons(ETH_P_IP);
                 skb_pull(skb, 13);
@@ -1576,10 +1640,10 @@
                 skb->h.raw = skb->data;
 
                 ((struct net_device_stats *)dev->priv)->rx_packets++;
- ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len+13;
+ ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len + 13;
                 netif_rx(skb); /* Send the SKB up to a higher place. */
 
- return (0);
+ return 0;
         }
 #endif
 
@@ -1593,10 +1657,10 @@
 
         sock = atalk_search_socket(&tosat, atif);
         
- if(sock == NULL) /* But not one of our sockets */
- {
+ if (sock == NULL) {
+ /* But not one of our sockets */
                 kfree_skb(skb);
- return (0);
+ return 0;
         }
 
         /*
@@ -1605,10 +1669,10 @@
          
         skb->sk = sock;
 
- if(sock_queue_rcv_skb(sock, skb) < 0)
+ if (sock_queue_rcv_skb(sock, skb) < 0)
                 kfree_skb(skb);
 
- return (0);
+ return 0;
 }
 
 /*
@@ -1624,17 +1688,15 @@
         /*
          * Expand any short form frames.
          */
- if(skb->mac.raw[2] == 1)
- {
+ if (skb->mac.raw[2] == 1) {
                 /*
                  * Find our address.
                  */
 
                 ap = atalk_find_dev_addr(dev);
- if(ap == NULL || skb->len < sizeof(struct ddpshdr))
- {
+ if (ap == NULL || skb->len < sizeof(struct ddpshdr)) {
                         kfree_skb(skb);
- return (0);
+ return 0;
                 }
 
                 /*
@@ -1673,57 +1735,51 @@
         }
         skb->h.raw = skb->data;
 
- return (atalk_rcv(skb, dev, pt));
+ return atalk_rcv(skb, dev, pt);
 }
 
-static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
- struct scm_cookie *scm)
+static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
 {
- struct sock *sk=sock->sk;
- struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name;
+ struct sock *sk = sock->sk;
+ struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;
         struct sockaddr_at local_satalk, gsat;
         struct sk_buff *skb;
         struct net_device *dev;
         struct ddpehdr *ddp;
         int size;
         struct atalk_route *rt;
- int loopback=0;
+ int loopback = 0;
         int err;
         int flags = msg->msg_flags;
 
- if(flags & ~MSG_DONTWAIT)
- return (-EINVAL);
+ if (flags & ~MSG_DONTWAIT)
+ return -EINVAL;
 
- if(len > DDP_MAXSZ)
- return (-EMSGSIZE);
+ if (len > DDP_MAXSZ)
+ return -EMSGSIZE;
 
- if(usat)
- {
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-EBUSY);
- }
-
- if(msg->msg_namelen < sizeof(*usat))
- return (-EINVAL);
- if(usat->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (usat) {
+ if(sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -EBUSY;
+ }
+
+ if (msg->msg_namelen < sizeof(*usat))
+ return -EINVAL;
+ if (usat->sat_family != AF_APPLETALK)
+ return -EINVAL;
 
                 /* netatalk doesn't implement this check */
- if(usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast)
- {
+ if (usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) {
                         printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as it will break before 2.2\n");
 #if 0
- return (-EPERM);
+ return -EPERM;
 #endif
                 }
- }
- else
- {
- if(sk->state != TCP_ESTABLISHED)
- return (-ENOTCONN);
- usat =& local_satalk;
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+ usat = &local_satalk;
                 usat->sat_family = AF_APPLETALK;
                 usat->sat_port = sk->protinfo.af_at.dest_port;
                 usat->sat_addr.s_node = sk->protinfo.af_at.dest_node;
@@ -1732,26 +1788,27 @@
 
         /* Build a packet */
 
- SOCK_DEBUG(sk, "SK %p: Got address.\n",sk);
+ SOCK_DEBUG(sk, "SK %p: Got address.\n", sk);
 
         /* For headers */
         size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;
 
- if(usat->sat_addr.s_net != 0 || usat->sat_addr.s_node == ATADDR_ANYNODE)
- {
+ if (usat->sat_addr.s_net != 0 || usat->sat_addr.s_node == ATADDR_ANYNODE) {
                 rt = atrtr_find(&usat->sat_addr);
- if(rt == NULL)
- return (-ENETUNREACH);
+ if (rt == NULL)
+ return -ENETUNREACH;
+
                 dev = rt->dev;
- }
- else
- {
+ } else {
                 struct at_addr at_hint;
+
                 at_hint.s_node = 0;
                 at_hint.s_net = sk->protinfo.af_at.src_net;
+
                 rt = atrtr_find(&at_hint);
- if(rt == NULL)
- return (-ENETUNREACH);
+ if (rt == NULL)
+ return -ENETUNREACH;
+
                 dev = rt->dev;
         }
 
@@ -1759,9 +1816,9 @@
 
         size += dev->hard_header_len;
 
- skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
- if(skb == NULL)
- return (err);
+ skb = sock_alloc_send_skb(sk, size, 0, (flags & MSG_DONTWAIT), &err);
+ if (skb == NULL)
+ return err;
         
         skb->sk = sk;
         skb_reserve(skb, ddp_dl->header_length);
@@ -1771,7 +1828,7 @@
 
         SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
 
- ddp = (struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr));
+ ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
         ddp->deh_pad = 0;
         ddp->deh_hops = 0;
         ddp->deh_len = len + sizeof(*ddp);
@@ -1791,14 +1848,13 @@
 
         SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len);
 
- err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
- if(err)
- {
+ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+ if (err) {
                 kfree_skb(skb);
- return (-EFAULT);
+ return -EFAULT;
         }
 
- if(sk->no_check == 1)
+ if (sk->no_check == 1)
                 ddp->deh_sum = 0;
         else
                 ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp));
@@ -1807,24 +1863,20 @@
          * Loopback broadcast packets to non gateway targets (ie routes
          * to group we are in)
          */
- if(ddp->deh_dnode == ATADDR_BCAST)
- {
- if((!(rt->flags&RTF_GATEWAY)) && (!(dev->flags&IFF_LOOPBACK)))
- {
+ if (ddp->deh_dnode == ATADDR_BCAST) {
+ if ((!(rt->flags&RTF_GATEWAY)) && (!(dev->flags&IFF_LOOPBACK))) {
                         struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);
- if(skb2)
- {
+ if (skb2) {
                                 loopback = 1;
                                 SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
- if(aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1)
+ if (aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1)
                                         kfree_skb(skb2);
                                 /* else queued/sent above in the aarp queue */
                         }
                 }
         }
 
- if((dev->flags & IFF_LOOPBACK) || loopback)
- {
+ if ((dev->flags & IFF_LOOPBACK) || loopback) {
                 SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
                 /* loop back */
                 skb_orphan(skb);
@@ -1834,70 +1886,60 @@
                 skb_pull(skb,dev->hard_header_len);
                 skb_pull(skb,ddp_dl->header_length);
                 atalk_rcv(skb, dev, NULL);
- }
- else
- {
+ } else {
                 SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
- if (rt->flags & RTF_GATEWAY)
- {
+ if (rt->flags & RTF_GATEWAY) {
                     gsat.sat_addr = rt->gateway;
                     usat = &gsat;
                 }
 
- if(aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1)
+ if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1)
                         kfree_skb(skb);
                 /* else queued/sent above in the aarp queue */
         }
         SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len);
 
- return (len);
+ return len;
 }
 
 static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size,
- int flags, struct scm_cookie *scm)
+ int flags, struct scm_cookie *scm)
 {
- struct sock *sk=sock->sk;
- struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name;
+ struct sock *sk = sock->sk;
+ struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
         struct ddpehdr *ddp = NULL;
         struct ddpebits ddphv;
         int copied = 0;
         struct sk_buff *skb;
         int err = 0;
 
-
- skb = skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err);
- if(skb == NULL)
- return (err);
+ skb = skb_recv_datagram(sk, (flags & ~MSG_DONTWAIT),
+ (flags & MSG_DONTWAIT), &err);
+ if (skb == NULL)
+ return err;
 
         ddp = (struct ddpehdr *)(skb->h.raw);
         *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
 
- if(sk->type == SOCK_RAW)
- {
+ if (sk->type == SOCK_RAW) {
                 copied = ddphv.deh_len;
- if(copied > size)
- {
+ if (copied > size) {
                         copied = size;
                         msg->msg_flags |= MSG_TRUNC;
                 }
 
                 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- }
- else
- {
+ } else {
                 copied = ddphv.deh_len - sizeof(*ddp);
- if(copied > size)
- {
+ if (copied > size) {
                         copied = size;
                         msg->msg_flags |= MSG_TRUNC;
                 }
- err = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
+ err = skb_copy_datagram_iovec(skb, sizeof(*ddp), msg->msg_iov, copied);
         }
 
- if(!err)
- {
- if(sat)
- {
+ if (!err) {
+ if (sat) {
                         sat->sat_family = AF_APPLETALK;
                         sat->sat_port = ddp->deh_sport;
                         sat->sat_addr.s_node = ddp->deh_snode;
@@ -1908,7 +1950,7 @@
 
         skb_free_datagram(sk, skb); /* Free the datagram. */
 
- return (err ? err : (copied));
+ return err ? err : copied;
 }
 
 

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Feb 23 2000 - 21:00:19 EST