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 a075248..c4fc722 100644 (file)
@@ -7,6 +7,7 @@
 #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>
@@ -686,9 +687,19 @@ static unsigned char lec_ctrl_magic[] = {
         0x01,
         0x01 };
 
+#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; 
 
@@ -728,7 +739,8 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
                 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) ||
@@ -741,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 */
@@ -1290,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 */
@@ -1767,7 +1799,7 @@ lec_arp_find(struct lec_priv *priv,
   
         to_return = priv->lec_arp_tables[place];
         while(to_return) {
-                if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) {
+                if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
                         return to_return;
                 }
                 to_return = to_return->next;
@@ -1780,8 +1812,7 @@ 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;
@@ -1971,7 +2002,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
                         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:
@@ -1990,6 +2021,12 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
                         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