diff options
Diffstat (limited to 'net/atm/lec.c')
-rw-r--r-- | net/atm/lec.c | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/net/atm/lec.c b/net/atm/lec.c index a0752487026d..47e1eae97461 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c | |||
@@ -686,9 +686,19 @@ static unsigned char lec_ctrl_magic[] = { | |||
686 | 0x01, | 686 | 0x01, |
687 | 0x01 }; | 687 | 0x01 }; |
688 | 688 | ||
689 | #define LEC_DATA_DIRECT_8023 2 | ||
690 | #define LEC_DATA_DIRECT_8025 3 | ||
691 | |||
692 | static int lec_is_data_direct(struct atm_vcc *vcc) | ||
693 | { | ||
694 | return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) || | ||
695 | (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025)); | ||
696 | } | ||
697 | |||
689 | static void | 698 | static void |
690 | lec_push(struct atm_vcc *vcc, struct sk_buff *skb) | 699 | lec_push(struct atm_vcc *vcc, struct sk_buff *skb) |
691 | { | 700 | { |
701 | unsigned long flags; | ||
692 | struct net_device *dev = (struct net_device *)vcc->proto_data; | 702 | struct net_device *dev = (struct net_device *)vcc->proto_data; |
693 | struct lec_priv *priv = (struct lec_priv *)dev->priv; | 703 | struct lec_priv *priv = (struct lec_priv *)dev->priv; |
694 | 704 | ||
@@ -728,7 +738,8 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) | |||
728 | skb_queue_tail(&sk->sk_receive_queue, skb); | 738 | skb_queue_tail(&sk->sk_receive_queue, skb); |
729 | sk->sk_data_ready(sk, skb->len); | 739 | sk->sk_data_ready(sk, skb->len); |
730 | } else { /* Data frame, queue to protocol handlers */ | 740 | } else { /* Data frame, queue to protocol handlers */ |
731 | unsigned char *dst; | 741 | struct lec_arp_table *entry; |
742 | unsigned char *src, *dst; | ||
732 | 743 | ||
733 | atm_return(vcc,skb->truesize); | 744 | atm_return(vcc,skb->truesize); |
734 | if (*(uint16_t *)skb->data == htons(priv->lecid) || | 745 | if (*(uint16_t *)skb->data == htons(priv->lecid) || |
@@ -741,10 +752,30 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) | |||
741 | return; | 752 | return; |
742 | } | 753 | } |
743 | #ifdef CONFIG_TR | 754 | #ifdef CONFIG_TR |
744 | if (priv->is_trdev) dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest; | 755 | if (priv->is_trdev) |
756 | dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest; | ||
745 | else | 757 | else |
746 | #endif | 758 | #endif |
747 | dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest; | 759 | dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest; |
760 | |||
761 | /* If this is a Data Direct VCC, and the VCC does not match | ||
762 | * the LE_ARP cache entry, delete the LE_ARP cache entry. | ||
763 | */ | ||
764 | spin_lock_irqsave(&priv->lec_arp_lock, flags); | ||
765 | if (lec_is_data_direct(vcc)) { | ||
766 | #ifdef CONFIG_TR | ||
767 | if (priv->is_trdev) | ||
768 | src = ((struct lecdatahdr_8025 *) skb->data)->h_source; | ||
769 | else | ||
770 | #endif | ||
771 | src = ((struct lecdatahdr_8023 *) skb->data)->h_source; | ||
772 | entry = lec_arp_find(priv, src); | ||
773 | if (entry && entry->vcc != vcc) { | ||
774 | lec_arp_remove(priv, entry); | ||
775 | kfree(entry); | ||
776 | } | ||
777 | } | ||
778 | spin_unlock_irqrestore(&priv->lec_arp_lock, flags); | ||
748 | 779 | ||
749 | if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */ | 780 | if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */ |
750 | !priv->is_proxy && /* Proxy wants all the packets */ | 781 | !priv->is_proxy && /* Proxy wants all the packets */ |