Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / atm / lec.c
index b005e1a..c4fc722 100644 (file)
@@ -1,12 +1,13 @@
 /*
  * lec.c: Lan Emulation driver 
- * Marko Kiiskila carnil@cs.tut.fi
+ * Marko Kiiskila mkiiskila@yahoo.com
  *
  */
 
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/capability.h>
 
 /* We are ethernet device */
 #include <linux/if_ether.h>
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #include <linux/if_bridge.h>
 #include "../bridge/br_private.h"
-static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 
-extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
-       unsigned char *addr);
-extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
 #endif
 
 /* Modular too */
@@ -71,9 +69,9 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int lec_close(struct net_device *dev);
 static struct net_device_stats *lec_get_stats(struct net_device *dev);
 static void lec_init(struct net_device *dev);
-static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
+static struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
                                                      unsigned char *mac_addr);
-static inline int lec_arp_remove(struct lec_priv *priv,
+static int lec_arp_remove(struct lec_priv *priv,
                                     struct lec_arp_table *to_remove);
 /* LANE2 functions */
 static void lane2_associate_ind (struct net_device *dev, u8 *mac_address,
@@ -83,6 +81,29 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
 static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
                          u8 *tlvs, u32 sizeoftlvs);
 
+static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, 
+                          unsigned long permanent);
+static void lec_arp_check_empties(struct lec_priv *priv,
+                                 struct atm_vcc *vcc, struct sk_buff *skb);
+static void lec_arp_destroy(struct lec_priv *priv);
+static void lec_arp_init(struct lec_priv *priv);
+static struct atm_vcc* lec_arp_resolve(struct lec_priv *priv,
+                                      unsigned char *mac_to_find,
+                                      int is_rdesc,
+                                      struct lec_arp_table **ret_entry);
+static void lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
+                          unsigned char *atm_addr, unsigned long remoteflag,
+                          unsigned int targetless_le_arp);
+static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
+static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
+static void lec_set_flush_tran_id(struct lec_priv *priv,
+                                 unsigned char *atm_addr,
+                                 unsigned long tran_id);
+static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
+                         struct atm_vcc *vcc,
+                         void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb));
+static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
+
 static struct lane2_ops lane2_ops = {
        lane2_resolve,         /* resolve,             spec 3.1.3 */
        lane2_associate_req,   /* associate_req,       spec 3.1.4 */
@@ -94,21 +115,6 @@ static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
 /* Device structures */
 static struct net_device *dev_lec[MAX_LEC_ITF];
 
-/* This will be called from proc.c via function pointer */
-struct net_device *get_dev_lec(int itf)
-{
-       struct net_device *dev;
-
-       if (itf >= MAX_LEC_ITF)
-               return NULL;
-       rtnl_lock();
-       dev = dev_lec[itf];
-       if (dev)
-               dev_hold(dev);
-       rtnl_unlock();
-       return dev;
-}
-
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
 {
@@ -122,6 +128,7 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
         eth = (struct ethhdr *)skb->data;
         buff = skb->data + skb->dev->hard_header_len;
         if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
+               struct sock *sk;
                 struct sk_buff *skb2;
                 struct atmlec_msg *mesg;
 
@@ -135,8 +142,9 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
 
                 priv = (struct lec_priv *)dev->priv;
                 atm_force_charge(priv->lecd, skb2->truesize);
-                skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2);
-                priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb2->len);
+               sk = sk_atm(priv->lecd);
+                skb_queue_tail(&sk->sk_receive_queue, skb2);
+                sk->sk_data_ready(sk, skb2->len);
         }
 
         return;
@@ -153,7 +161,7 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
  * and returns NULL.
  */
 #ifdef CONFIG_TR
-unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
+static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
 {
         struct trh_hdr *trh;
         int riflen, num_rdsc;
@@ -214,7 +222,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
        ATM_SKB(skb)->vcc = vcc;
        ATM_SKB(skb)->atm_options = vcc->atm_options;
 
-       atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+       atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
        if (vcc->send(vcc, skb) < 0) {
                priv->stats.tx_dropped++;
                return;
@@ -422,6 +430,7 @@ lec_get_stats(struct net_device *dev)
 static int 
 lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 {
+       unsigned long flags;
         struct net_device *dev = (struct net_device*)vcc->proto_data;
         struct lec_priv *priv = (struct lec_priv*)dev->priv;
         struct atmlec_msg *mesg;
@@ -429,7 +438,7 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
         int i;
         char *tmp; /* FIXME */
 
-       atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc);
+       atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
         mesg = (struct atmlec_msg *)skb->data;
         tmp = skb->data;
         tmp += sizeof(struct atmlec_msg);
@@ -456,8 +465,10 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                 lec_flush_complete(priv, mesg->content.normal.flag);
                 break;
         case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
+               spin_lock_irqsave(&priv->lec_arp_lock, flags);
                 entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
                 lec_arp_remove(priv, entry);
+               spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 
                 if (mesg->content.normal.no_source_le_narp)
                         break;
@@ -525,6 +536,7 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                     f->dst->state == BR_STATE_FORWARDING) {
                                 /* hit from bridge table, send LE_ARP_RESPONSE */
                         struct sk_buff *skb2;
+                       struct sock *sk;
 
                         DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
                         skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
@@ -535,8 +547,9 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                         skb2->len = sizeof(struct atmlec_msg);
                         memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
                         atm_force_charge(priv->lecd, skb2->truesize);
-                        skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2);
-                        priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb2->len);
+                       sk = sk_atm(priv->lecd);
+                        skb_queue_tail(&sk->sk_receive_queue, skb2);
+                        sk->sk_data_ready(sk, skb2->len);
                 }
                 if (f != NULL) br_fdb_put_hook(f);
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
@@ -564,10 +577,10 @@ lec_atm_close(struct atm_vcc *vcc)
         netif_stop_queue(dev);
         lec_arp_destroy(priv);
 
-        if (skb_peek(&vcc->sk->sk_receive_queue))
+        if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
                printk("%s lec_atm_close: closing with messages pending\n",
                        dev->name);
-        while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
+        while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
                 atm_return(vcc, skb->truesize);
                dev_kfree_skb(skb);
         }
@@ -592,11 +605,12 @@ static struct atm_dev lecatm_dev = {
  * LANE2: new argument struct sk_buff *data contains
  * the LE_ARP based TLVs introduced in the LANE2 spec
  */
-int 
+static int 
 send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, 
              unsigned char *mac_addr, unsigned char *atm_addr,
              struct sk_buff *data)
 {
+       struct sock *sk;
        struct sk_buff *skb;
        struct atmlec_msg *mesg;
 
@@ -620,14 +634,15 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
                memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
 
         atm_force_charge(priv->lecd, skb->truesize);
-       skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb);
-        priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb->len);
+       sk = sk_atm(priv->lecd);
+       skb_queue_tail(&sk->sk_receive_queue, skb);
+        sk->sk_data_ready(sk, skb->len);
 
         if (data != NULL) {
                 DPRINTK("lec: about to send %d bytes of data\n", data->len);
                 atm_force_charge(priv->lecd, data->truesize);
-                skb_queue_tail(&priv->lecd->sk->sk_receive_queue, data);
-                priv->lecd->sk->sk_data_ready(priv->lecd->sk, skb->len);
+                skb_queue_tail(&sk->sk_receive_queue, data);
+                sk->sk_data_ready(sk, skb->len);
         }
 
         return 0;
@@ -672,9 +687,19 @@ static unsigned char lec_ctrl_magic[] = {
         0x01,
         0x01 };
 
-void 
+#define LEC_DATA_DIRECT_8023  2
+#define LEC_DATA_DIRECT_8025  3
+
+static int lec_is_data_direct(struct atm_vcc *vcc)
+{ 
+       return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
+               (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
+} 
+
+static void 
 lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
 {
+       unsigned long flags;
         struct net_device *dev = (struct net_device *)vcc->proto_data;
         struct lec_priv *priv = (struct lec_priv *)dev->priv; 
 
@@ -708,11 +733,14 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
                 printk("%s...\n",buf);
 #endif /* DUMP_PACKETS > 0 */
         if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
+               struct sock *sk = sk_atm(vcc);
+
                 DPRINTK("%s: To daemon\n",dev->name);
-                skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
-                vcc->sk->sk_data_ready(vcc->sk, skb->len);
+                skb_queue_tail(&sk->sk_receive_queue, skb);
+                sk->sk_data_ready(sk, skb->len);
         } else { /* Data frame, queue to protocol handlers */
-                unsigned char *dst;
+               struct lec_arp_table *entry;
+                unsigned char *src, *dst;
 
                 atm_return(vcc,skb->truesize);
                 if (*(uint16_t *)skb->data == htons(priv->lecid) ||
@@ -725,10 +753,30 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
                         return;
                 }
 #ifdef CONFIG_TR
-                if (priv->is_trdev) dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
+                if (priv->is_trdev)
+                       dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest;
                 else
 #endif
-                dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
+               dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest;
+
+               /* If this is a Data Direct VCC, and the VCC does not match
+                * the LE_ARP cache entry, delete the LE_ARP cache entry.
+                */
+               spin_lock_irqsave(&priv->lec_arp_lock, flags);
+               if (lec_is_data_direct(vcc)) {
+#ifdef CONFIG_TR
+                       if (priv->is_trdev)
+                               src = ((struct lecdatahdr_8025 *) skb->data)->h_source;
+                       else
+#endif
+                       src = ((struct lecdatahdr_8023 *) skb->data)->h_source;
+                       entry = lec_arp_find(priv, src);
+                       if (entry && entry->vcc != vcc) {
+                               lec_arp_remove(priv, entry);
+                               kfree(entry);
+                       }
+               }
+               spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 
                 if (!(dst[0]&0x01) &&   /* Never filter Multi/Broadcast */
                     !priv->is_proxy &&  /* Proxy wants all the packets */
@@ -753,7 +801,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
         }
 }
 
-void
+static void
 lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
@@ -773,7 +821,7 @@ lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
        }
 }
 
-int 
+static int 
 lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
 {
        struct lec_vcc_priv *vpriv;
@@ -802,7 +850,7 @@ lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
         return 0;
 }
 
-int 
+static int 
 lec_mcast_attach(struct atm_vcc *vcc, int arg)
 {
         if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
@@ -812,7 +860,7 @@ lec_mcast_attach(struct atm_vcc *vcc, int arg)
 }
 
 /* Initialize device. */
-int 
+static int 
 lecd_attach(struct atm_vcc *vcc, int arg)
 {  
         int i;
@@ -863,7 +911,7 @@ lecd_attach(struct atm_vcc *vcc, int arg)
        priv->itfnum = i;  /* LANE2 addition */
         priv->lecd = vcc;
         vcc->dev = &lecatm_dev;
-        vcc_insert_socket(vcc->sk);
+        vcc_insert_socket(sk_atm(vcc));
         
         vcc->proto_data = dev_lec[i];
        set_bit(ATM_VF_META,&vcc->flags);
@@ -1222,17 +1270,20 @@ module_exit(lane_module_cleanup);
 static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
     u8 **tlvs, u32 *sizeoftlvs)
 {
+       unsigned long flags;
         struct lec_priv *priv = (struct lec_priv *)dev->priv;
         struct lec_arp_table *table;
         struct sk_buff *skb;
         int retval;
 
         if (force == 0) {
+               spin_lock_irqsave(&priv->lec_arp_lock, flags);
                 table = lec_arp_find(priv, dst_mac);
+               spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 if(table == NULL)
                         return -1;
                 
-                *tlvs = kmalloc(table->sizeoftlvs, GFP_KERNEL);
+                *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
                 if (*tlvs == NULL)
                         return -1;
                 
@@ -1271,7 +1322,7 @@ static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
         struct sk_buff *skb;
         struct lec_priv *priv = (struct lec_priv*)dev->priv;
 
-        if ( memcmp(lan_dst, dev->dev_addr, ETH_ALEN) != 0 )
+        if (compare_ether_addr(lan_dst, dev->dev_addr))
                 return (0);       /* not our mac address */
 
         kfree(priv->tlvs); /* NULL if there was no previous association */
@@ -1369,7 +1420,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
 
 static void lec_arp_check_expire(unsigned long data);
 static void lec_arp_expire_arp(unsigned long data);
-void dump_arp_table(struct lec_priv *priv);
 
 /* 
  * Arp table funcs
@@ -1377,38 +1427,26 @@ void dump_arp_table(struct lec_priv *priv);
 
 #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
 
-static __inline__ void 
-lec_arp_get(struct lec_priv *priv)
-{
-        atomic_inc(&priv->lec_arp_users);
-}
-
-static __inline__ void 
-lec_arp_put(struct lec_priv *priv)
-{
-        atomic_dec(&priv->lec_arp_users);
-}
-
 /*
  * Initialization of arp-cache
  */
-void 
+static void 
 lec_arp_init(struct lec_priv *priv)
 {
         unsigned short i;
 
-        for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
                 priv->lec_arp_tables[i] = NULL;
         }        
        spin_lock_init(&priv->lec_arp_lock);
         init_timer(&priv->lec_arp_timer);
-        priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL;
+        priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
         priv->lec_arp_timer.data = (unsigned long)priv;
         priv->lec_arp_timer.function = lec_arp_check_expire;
         add_timer(&priv->lec_arp_timer);
 }
 
-void
+static void
 lec_arp_clear_vccs(struct lec_arp_table *entry)
 {
         if (entry->vcc) {
@@ -1439,12 +1477,9 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
 static inline void 
 lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
 {
-        unsigned long flags;
         unsigned short place;
         struct lec_arp_table *tmp;
 
-        spin_lock_irqsave(&priv->lec_arp_lock, flags);
-
         place = HASH(to_add->mac_addr[ETH_ALEN-1]);
         tmp = priv->lec_arp_tables[place];
         to_add->next = NULL;
@@ -1457,8 +1492,6 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
                 tmp->next = to_add;
         }
 
-        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
         DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
                 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
                 0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
@@ -1468,19 +1501,15 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
 /*
  * Remove entry from lec_arp_table
  */
-static inline in
+static int 
 lec_arp_remove(struct lec_priv *priv,
                struct lec_arp_table *to_remove)
 {
-        unsigned long flags;
         unsigned short place;
         struct lec_arp_table *tmp;
         int remove_vcc=1;
 
-        spin_lock_irqsave(&priv->lec_arp_lock, flags);
-
         if (!to_remove) {
-                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 return -1;
         }
         place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
@@ -1492,7 +1521,6 @@ lec_arp_remove(struct lec_priv *priv,
                         tmp = tmp->next;
                 }
                 if (!tmp) {/* Entry was not found */
-                        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                         return -1;
                 }
         }
@@ -1505,7 +1533,7 @@ lec_arp_remove(struct lec_priv *priv,
                 /*
                  * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
                  */
-                for(place=0;place<LEC_ARP_TABLE_SIZE;place++) {
+                for(place = 0; place < LEC_ARP_TABLE_SIZE; place++) {
                         for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
                                 if (memcmp(tmp->atm_addr, to_remove->atm_addr,
                                            ATM_ESA_LEN)==0) {
@@ -1519,8 +1547,6 @@ lec_arp_remove(struct lec_priv *priv,
         }
         skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
 
-        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
         DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
                 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
                 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
@@ -1549,7 +1575,7 @@ get_status_string(unsigned char st)
 }
 #endif
 
-void
+static void
 dump_arp_table(struct lec_priv *priv)
 {
 #if DEBUG_ARP_TABLE
@@ -1701,9 +1727,10 @@ dump_arp_table(struct lec_priv *priv)
 /*
  * Destruction of arp-cache
  */
-void
+static void
 lec_arp_destroy(struct lec_priv *priv)
 {
+       unsigned long flags;
         struct lec_arp_table *entry, *next;
         int i;
 
@@ -1712,8 +1739,10 @@ lec_arp_destroy(struct lec_priv *priv)
         /*
          * Remove all entries
          */
-        for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry =priv->lec_arp_tables[i];entry != NULL; entry=next) {
+
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
+        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+                for(entry = priv->lec_arp_tables[i]; entry != NULL; entry=next) {
                         next = entry->next;
                         lec_arp_remove(priv, entry);
                         kfree(entry);
@@ -1748,14 +1777,15 @@ lec_arp_destroy(struct lec_priv *priv)
         priv->mcast_fwds = NULL;
         priv->mcast_vcc = NULL;
         memset(priv->lec_arp_tables, 0, 
-               sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE);
+               sizeof(struct lec_arp_table *) * LEC_ARP_TABLE_SIZE);
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
 
 /* 
  * Find entry by mac_address
  */
-static inline struct lec_arp_table*
+static struct lec_arp_table*
 lec_arp_find(struct lec_priv *priv,
              unsigned char *mac_addr)
 {
@@ -1765,18 +1795,15 @@ lec_arp_find(struct lec_priv *priv,
         DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
                 mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff, 
                 mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
-        lec_arp_get(priv);
         place = HASH(mac_addr[ETH_ALEN-1]);
   
         to_return = priv->lec_arp_tables[place];
         while(to_return) {
-                if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) {
-                        lec_arp_put(priv);
+                if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
                         return to_return;
                 }
                 to_return = to_return->next;
         }
-        lec_arp_put(priv);
         return NULL;
 }
 
@@ -1785,17 +1812,16 @@ make_entry(struct lec_priv *priv, unsigned char *mac_addr)
 {
         struct lec_arp_table *to_return;
 
-        to_return=(struct lec_arp_table *)kmalloc(sizeof(struct lec_arp_table),
-                                                  GFP_ATOMIC);
+        to_return = kmalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
         if (!to_return) {
                 printk("LEC: Arp entry kmalloc failed\n");
                 return NULL;
         }
-        memset(to_return,0,sizeof(struct lec_arp_table));
+        memset(to_return, 0, sizeof(struct lec_arp_table));
         memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
         init_timer(&to_return->timer);
         to_return->timer.function = lec_arp_expire_arp;
-        to_return->timer.data = (unsigned long)to_return;
+        to_return->timer.data = (unsigned long) to_return;
         to_return->last_used = jiffies;
         to_return->priv = priv;
         skb_queue_head_init(&to_return->tx_wait);
@@ -1835,6 +1861,7 @@ lec_arp_expire_arp(unsigned long data)
 static void
 lec_arp_expire_vcc(unsigned long data)
 {
+       unsigned long flags;
         struct lec_arp_table *to_remove = (struct lec_arp_table*)data;
         struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
         struct lec_arp_table *entry = NULL;
@@ -1846,6 +1873,8 @@ lec_arp_expire_vcc(unsigned long data)
                 to_remove->vcc?to_remove->recv_vcc->vpi:0,
                 to_remove->vcc?to_remove->recv_vcc->vci:0);
         DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward);
+
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         if (to_remove == priv->lec_arp_empty_ones)
                 priv->lec_arp_empty_ones = to_remove->next;
         else {
@@ -1866,6 +1895,8 @@ lec_arp_expire_vcc(unsigned long data)
                                 entry->next = to_remove->next;
                 }
        }
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+
         lec_arp_clear_vccs(to_remove);
         kfree(to_remove);
 }
@@ -1889,69 +1920,67 @@ lec_arp_expire_vcc(unsigned long data)
 static void
 lec_arp_check_expire(unsigned long data)
 {
+       unsigned long flags;
         struct lec_priv *priv = (struct lec_priv *)data;
         struct lec_arp_table *entry, *next;
         unsigned long now;
         unsigned long time_to_check;
         int i;
 
-        DPRINTK("lec_arp_check_expire %p,%d\n",priv,
-                atomic_read(&priv->lec_arp_users));
+        DPRINTK("lec_arp_check_expire %p\n",priv);
         DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
                 priv->lec_no_forward);
-        if (!atomic_read(&priv->lec_arp_users)) {
-                lec_arp_get(priv);
-                now = jiffies;
-                for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                        for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
-                                if ((entry->flags) & LEC_REMOTE_FLAG && 
-                                    priv->topology_change)
-                                        time_to_check=priv->forward_delay_time;
-                                else
-                                        time_to_check = priv->aging_time;
-
-                                DPRINTK("About to expire: %lx - %lx > %lx\n",
-                                        now,entry->last_used, time_to_check);
-                                if( time_after(now, entry->last_used+
-                                   time_to_check) && 
-                                    !(entry->flags & LEC_PERMANENT_FLAG) &&
-                                    !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
-                                        /* Remove entry */
-                                        DPRINTK("LEC:Entry timed out\n");
-                                        next = entry->next;      
-                                        lec_arp_remove(priv, entry);
-                                        kfree(entry);
-                                        entry = next;
-                                } else {
-                                        /* Something else */
-                                        if ((entry->status == ESI_VC_PENDING ||
-                                             entry->status == ESI_ARP_PENDING) 
-                                            && time_after_eq(now,
-                                            entry->timestamp +
-                                            priv->max_unknown_frame_time)) {
-                                                entry->timestamp = jiffies;
-                                                entry->packets_flooded = 0;
-                                                if (entry->status == ESI_VC_PENDING)
-                                                        send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
-                                        }
-                                        if (entry->status == ESI_FLUSH_PENDING 
-                                           &&
-                                           time_after_eq(now, entry->timestamp+
-                                           priv->path_switching_delay)) {
-                                               struct sk_buff *skb;
-
-                                               while ((skb = skb_dequeue(&entry->tx_wait)))
-                                                       lec_send(entry->vcc, skb, entry->priv);
-                                                entry->last_used = jiffies;
-                                                entry->status = 
-                                                        ESI_FORWARD_DIRECT;
-                                        }
-                                        entry = entry->next;
-                                }
-                        }
-                }
-                lec_arp_put(priv);
-        }
+       now = jiffies;
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
+       for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+               for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
+                       if ((entry->flags) & LEC_REMOTE_FLAG && 
+                           priv->topology_change)
+                               time_to_check = priv->forward_delay_time;
+                       else
+                               time_to_check = priv->aging_time;
+
+                       DPRINTK("About to expire: %lx - %lx > %lx\n",
+                               now,entry->last_used, time_to_check);
+                       if( time_after(now, entry->last_used+
+                          time_to_check) && 
+                           !(entry->flags & LEC_PERMANENT_FLAG) &&
+                           !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
+                               /* Remove entry */
+                               DPRINTK("LEC:Entry timed out\n");
+                               next = entry->next;      
+                               lec_arp_remove(priv, entry);
+                               kfree(entry);
+                               entry = next;
+                       } else {
+                               /* Something else */
+                               if ((entry->status == ESI_VC_PENDING ||
+                                    entry->status == ESI_ARP_PENDING) 
+                                   && time_after_eq(now,
+                                   entry->timestamp +
+                                   priv->max_unknown_frame_time)) {
+                                       entry->timestamp = jiffies;
+                                       entry->packets_flooded = 0;
+                                       if (entry->status == ESI_VC_PENDING)
+                                               send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
+                               }
+                               if (entry->status == ESI_FLUSH_PENDING 
+                                  &&
+                                  time_after_eq(now, entry->timestamp+
+                                  priv->path_switching_delay)) {
+                                       struct sk_buff *skb;
+
+                                       while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+                                               lec_send(entry->vcc, skb, entry->priv);
+                                       entry->last_used = jiffies;
+                                       entry->status = 
+                                               ESI_FORWARD_DIRECT;
+                               }
+                               entry = entry->next;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 
         mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
 }
@@ -1959,19 +1988,21 @@ lec_arp_check_expire(unsigned long data)
  * Try to find vcc where mac_address is attached.
  * 
  */
-struct atm_vcc*
-lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
-                struct lec_arp_table **ret_entry)
+static struct atm_vcc*
+lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
+               int is_rdesc, struct lec_arp_table **ret_entry)
 {
+       unsigned long flags;
         struct lec_arp_table *entry;
+       struct atm_vcc *found;
 
-        if (mac_to_find[0]&0x01) {
+        if (mac_to_find[0] & 0x01) {
                 switch (priv->lane_version) {
                 case 1:
                         return priv->mcast_vcc;
                         break;
                 case 2:  /* LANE2 wants arp for multicast addresses */
-                        if ( memcmp(mac_to_find, bus_mac, ETH_ALEN) == 0)
+                        if (!compare_ether_addr(mac_to_find, bus_mac))
                                 return priv->mcast_vcc;
                         break;
                 default:
@@ -1979,6 +2010,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                 }
         }
 
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         entry = lec_arp_find(priv, mac_to_find);
   
         if (entry) {
@@ -1986,8 +2018,15 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                         /* Connection Ok */
                         entry->last_used = jiffies;
                         *ret_entry = entry;
-                        return entry->vcc;
+                        found = entry->vcc;
+                       goto out;
                 }
+               /* If the LE_ARP cache entry is still pending, reset count to 0
+                * so another LE_ARP request can be made for this frame.
+                */
+               if (entry->status == ESI_ARP_PENDING) {
+                       entry->no_tries = 0;
+               }
                 /* Data direct VC not yet set up, check to see if the unknown
                    frame count is greater than the limit. If the limit has
                    not been reached, allow the caller to send packet to
@@ -1996,7 +2035,8 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                     entry->packets_flooded<priv->maximum_unknown_frame_count) {
                         entry->packets_flooded++;
                         DPRINTK("LEC_ARP: Flooding..\n");
-                        return priv->mcast_vcc;
+                        found = priv->mcast_vcc;
+                       goto out;
                 }
                /* We got here because entry->status == ESI_FLUSH_PENDING
                 * or BUS flood limit was reached for an entry which is
@@ -2004,13 +2044,14 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                 */
                 *ret_entry = entry;
                 DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc);
-                return NULL;
+                found = NULL;
         } else {
                 /* No matching entry was found */
                 entry = make_entry(priv, mac_to_find);
                 DPRINTK("LEC_ARP: Making entry\n");
                 if (!entry) {
-                        return priv->mcast_vcc;
+                        found = priv->mcast_vcc;
+                       goto out;
                 }
                 lec_arp_add(priv, entry);
                 /* We want arp-request(s) to be sent */
@@ -2026,44 +2067,50 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
                 entry->timer.expires = jiffies + (1*HZ);
                 entry->timer.function = lec_arp_expire_arp;
                 add_timer(&entry->timer);
-                return priv->mcast_vcc;
+                found = priv->mcast_vcc;
         }
+
+out:
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+       return found;
 }
 
-int
+static int
 lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, 
                 unsigned long permanent)
 {
+       unsigned long flags;
         struct lec_arp_table *entry, *next;
         int i;
 
-        lec_arp_get(priv);
         DPRINTK("lec_addr_delete\n");
-        for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry=priv->lec_arp_tables[i];entry != NULL; entry=next) {
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
+        for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+                for(entry = priv->lec_arp_tables[i]; entry != NULL; entry = next) {
                         next = entry->next;
                         if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
                             && (permanent || 
                                 !(entry->flags & LEC_PERMANENT_FLAG))) {
-                                lec_arp_remove(priv, entry);
+                               lec_arp_remove(priv, entry);
                                 kfree(entry);
                         }
-                        lec_arp_put(priv);
+                       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                         return 0;
                 }
         }
-        lec_arp_put(priv);
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
         return -1;
 }
 
 /*
  * Notifies:  Response to arp_request (atm_addr != NULL) 
  */
-void
+static void
 lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
                unsigned char *atm_addr, unsigned long remoteflag,
                unsigned int targetless_le_arp)
 {
+       unsigned long flags;
         struct lec_arp_table *entry, *tmp;
         int i;
 
@@ -2072,12 +2119,12 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
                 mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],
                 mac_addr[4],mac_addr[5]);
 
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         entry = lec_arp_find(priv, mac_addr);
         if (entry == NULL && targetless_le_arp)
-                return;   /* LANE2: ignore targetless LE_ARPs for which
-                           * we have no entry in the cache. 7.1.30
-                           */
-        lec_arp_get(priv);
+                goto out;   /* LANE2: ignore targetless LE_ARPs for which
+                             * we have no entry in the cache. 7.1.30
+                             */
         if (priv->lec_arp_empty_ones) {
                 entry = priv->lec_arp_empty_ones;
                 if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
@@ -2117,27 +2164,24 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
                                 entry->flags|=LEC_REMOTE_FLAG;
                         else
                                 entry->flags&=~LEC_REMOTE_FLAG;
-                        lec_arp_put(priv);
                         DPRINTK("After update\n");
                         dump_arp_table(priv);
-                        return;
+                        goto out;
                 }
         }
         entry = lec_arp_find(priv, mac_addr);
         if (!entry) {
                 entry = make_entry(priv, mac_addr);
-                if (!entry) {
-                        lec_arp_put(priv);
-                        return;
-                }
+                if (!entry)
+                       goto out;
                 entry->status = ESI_UNKNOWN;
                 lec_arp_add(priv, entry);
                 /* Temporary, changes before end of function */
         }
         memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
         del_timer(&entry->timer);
-        for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(tmp=priv->lec_arp_tables[i];tmp;tmp=tmp->next) {
+        for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+                for(tmp = priv->lec_arp_tables[i]; tmp; tmp=tmp->next) {
                         if (entry != tmp &&
                             !memcmp(tmp->atm_addr, atm_addr,
                                     ATM_ESA_LEN)) { 
@@ -2166,21 +2210,23 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
         }
         DPRINTK("After update2\n");
         dump_arp_table(priv);
-        lec_arp_put(priv);
+out:
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
 /*
  * Notifies: Vcc setup ready 
  */
-void
+static void
 lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
               struct atm_vcc *vcc,
               void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb))
 {
+       unsigned long flags;
         struct lec_arp_table *entry;
         int i, found_entry=0;
 
-        lec_arp_get(priv);
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         if (ioc_data->receive == 2) {
                 /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
 
@@ -2189,26 +2235,22 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                 entry = lec_arp_find(priv, bus_mac);
                 if (!entry) {
                         printk("LEC_ARP: Multicast entry not found!\n");
-                        lec_arp_put(priv);
-                        return;
+                       goto out;
                 }
                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
                 entry->recv_vcc = vcc;
                 entry->old_recv_push = old_push;
 #endif
                 entry = make_entry(priv, bus_mac);
-                if (entry == NULL) {
-                        lec_arp_put(priv);
-                        return;
-                }
+                if (entry == NULL)
+                       goto out;
                 del_timer(&entry->timer);
                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
                 entry->recv_vcc = vcc;
                 entry->old_recv_push = old_push;
                 entry->next = priv->mcast_fwds;
                 priv->mcast_fwds = entry;
-                lec_arp_put(priv);
-                return;
+                goto out;
         } else if (ioc_data->receive == 1) {
                 /* Vcc which we don't want to make default vcc, attach it
                    anyway. */
@@ -2224,10 +2266,8 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                         ioc_data->atm_addr[16],ioc_data->atm_addr[17],
                         ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
                 entry = make_entry(priv, bus_mac);
-                if (entry == NULL) {
-                        lec_arp_put(priv);
-                        return;
-                }
+                if (entry == NULL)
+                       goto out;
                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
                 memset(entry->mac_addr, 0, ETH_ALEN);
                 entry->recv_vcc = vcc;
@@ -2238,9 +2278,8 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                 add_timer(&entry->timer);
                 entry->next = priv->lec_no_forward;
                 priv->lec_no_forward = entry;
-                lec_arp_put(priv);
                dump_arp_table(priv);
-                return;
+               goto out;
         }
         DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
                 ioc_data->atm_addr[0],ioc_data->atm_addr[1],
@@ -2253,8 +2292,8 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                 ioc_data->atm_addr[14],ioc_data->atm_addr[15],
                 ioc_data->atm_addr[16],ioc_data->atm_addr[17],
                 ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
-        for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for (entry = priv->lec_arp_tables[i];entry;entry=entry->next) {
+        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+                for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
                         if (memcmp(ioc_data->atm_addr, entry->atm_addr, 
                                    ATM_ESA_LEN)==0) {
                                 DPRINTK("LEC_ARP: Attaching data direct\n");
@@ -2297,18 +2336,15 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
                 }
         }
         if (found_entry) {
-                lec_arp_put(priv);
                 DPRINTK("After vcc was added\n");
                 dump_arp_table(priv);
-                return;
+               goto out;
         }
         /* Not found, snatch address from first data packet that arrives from
            this vcc */
         entry = make_entry(priv, bus_mac);
-        if (!entry) {
-                lec_arp_put(priv);
-                return;
-        }
+        if (!entry)
+               goto out;
         entry->vcc = vcc;
         entry->old_push = old_push;
         memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
@@ -2319,56 +2355,65 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
         entry->timer.expires = jiffies + priv->vcc_timeout_period;
         entry->timer.function = lec_arp_expire_vcc;
         add_timer(&entry->timer);
-        lec_arp_put(priv);
         DPRINTK("After vcc was added\n");
        dump_arp_table(priv);
+out:
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
-void
+static void
 lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
 {
+       unsigned long flags;
         struct lec_arp_table *entry;
         int i;
   
         DPRINTK("LEC:lec_flush_complete %lx\n",tran_id);
-        for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) {
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
+        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+                for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
                         if (entry->flush_tran_id == tran_id &&
                             entry->status == ESI_FLUSH_PENDING) {
                                struct sk_buff *skb;
 
-                               while ((skb = skb_dequeue(&entry->tx_wait)))
+                               while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
                                        lec_send(entry->vcc, skb, entry->priv);
                                 entry->status = ESI_FORWARD_DIRECT;
                                 DPRINTK("LEC_ARP: Flushed\n");
                         }
                 }
         }
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
         dump_arp_table(priv);
 }
 
-void
+static void
 lec_set_flush_tran_id(struct lec_priv *priv,
                       unsigned char *atm_addr, unsigned long tran_id)
 {
+       unsigned long flags;
         struct lec_arp_table *entry;
         int i;
 
-        for (i=0;i<LEC_ARP_TABLE_SIZE;i++)
-                for(entry=priv->lec_arp_tables[i];entry;entry=entry->next)
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
+        for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
+                for(entry = priv->lec_arp_tables[i]; entry; entry=entry->next)
                         if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
                                 entry->flush_tran_id = tran_id;
                                 DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry);
                         }
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 
-int 
+static int 
 lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
 {
+       unsigned long flags;
         unsigned char mac_addr[] = {
                 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
         struct lec_arp_table *to_add;
        struct lec_vcc_priv *vpriv;
+       int err = 0;
   
        if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
                return -ENOMEM;
@@ -2376,13 +2421,13 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
        vpriv->old_pop = vcc->pop;
        vcc->user_back = vpriv;
         vcc->pop = lec_pop;
-        lec_arp_get(priv);
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         to_add = make_entry(priv, mac_addr);
         if (!to_add) {
-                lec_arp_put(priv);
                vcc->pop = vpriv->old_pop;
                kfree(vpriv);
-                return -ENOMEM;
+                err = -ENOMEM;
+               goto out;
         }
         memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
         to_add->status = ESI_FORWARD_DIRECT;
@@ -2392,19 +2437,21 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
         vcc->push = lec_push;
         priv->mcast_vcc = vcc;
         lec_arp_add(priv, to_add);
-        lec_arp_put(priv);
-        return 0;
+out:
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+        return err;
 }
 
-void
+static void
 lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
 {
+       unsigned long flags;
         struct lec_arp_table *entry, *next;
         int i;
 
         DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
         dump_arp_table(priv);
-        lec_arp_get(priv);
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
                 for(entry = priv->lec_arp_tables[i];entry; entry=next) {
                         next = entry->next;
@@ -2466,11 +2513,11 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
                 entry = next;
         }
 
-        lec_arp_put(priv);
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
        dump_arp_table(priv);
 }
 
-void
+static void
 lec_arp_check_empties(struct lec_priv *priv,
                       struct atm_vcc *vcc, struct sk_buff *skb)
 {
@@ -2486,26 +2533,22 @@ lec_arp_check_empties(struct lec_priv *priv,
 #endif
         src = hdr->h_source;
 
-        lec_arp_get(priv);
+       spin_lock_irqsave(&priv->lec_arp_lock, flags);
         entry = priv->lec_arp_empty_ones;
         if (vcc == entry->vcc) {
-               spin_lock_irqsave(&priv->lec_arp_lock, flags);
                 del_timer(&entry->timer);
                 memcpy(entry->mac_addr, src, ETH_ALEN);
                 entry->status = ESI_FORWARD_DIRECT;
                 entry->last_used = jiffies;
                 priv->lec_arp_empty_ones = entry->next;
-                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 /* We might have got an entry */
-                if ((prev=lec_arp_find(priv,src))) {
+                if ((prev = lec_arp_find(priv,src))) {
                         lec_arp_remove(priv, prev);
                         kfree(prev);
                 }
                 lec_arp_add(priv, entry);
-                lec_arp_put(priv);
-                return;
+               goto out;
         }
-        spin_lock_irqsave(&priv->lec_arp_lock, flags);
         prev = entry;
         entry = entry->next;
         while (entry && entry->vcc != vcc) {
@@ -2514,21 +2557,19 @@ lec_arp_check_empties(struct lec_priv *priv,
         }
         if (!entry) {
                 DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
-                lec_arp_put(priv);
-                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-                return;
+               goto out;
         }
         del_timer(&entry->timer);
         memcpy(entry->mac_addr, src, ETH_ALEN);
         entry->status = ESI_FORWARD_DIRECT;
         entry->last_used = jiffies;
         prev->next = entry->next;
-        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
         if ((prev = lec_arp_find(priv, src))) {
                 lec_arp_remove(priv, prev);
                 kfree(prev);
         }
         lec_arp_add(priv, entry);
-        lec_arp_put(priv);  
+out:
+       spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 }
 MODULE_LICENSE("GPL");