Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / mac80211 / rx.c
index 6175db3..a47bbc9 100644 (file)
@@ -2298,6 +2298,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        __le16 fc = hdr->frame_control;
        struct sk_buff_head frame_list;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       struct ethhdr ethhdr;
+       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -2308,24 +2310,53 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(status->rx_flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       if (ieee80211_has_a4(hdr->frame_control) &&
-           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-           !rx->sdata->u.vlan.sta)
-               return RX_DROP_UNUSABLE;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP_VLAN:
+                       if (!rx->sdata->u.vlan.sta)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sdata->u.mgd.use_4addr)
+                               return RX_DROP_UNUSABLE;
+                       break;
+               default:
+                       return RX_DROP_UNUSABLE;
+               }
+               check_da = NULL;
+               check_sa = NULL;
+       } else switch (rx->sdata->vif.type) {
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+                       check_da = NULL;
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       if (!rx->sta ||
+                           !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+                               check_sa = NULL;
+                       break;
+               case NL80211_IFTYPE_MESH_POINT:
+                       check_sa = NULL;
+                       break;
+               default:
+                       break;
+       }
 
-       if (is_multicast_ether_addr(hdr->addr1) &&
-           ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-             rx->sdata->u.vlan.sta) ||
-            (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-             rx->sdata->u.mgd.use_4addr)))
+       if (is_multicast_ether_addr(hdr->addr1))
                return RX_DROP_UNUSABLE;
 
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
+       if (ieee80211_data_to_8023_exthdr(skb, &ethhdr,
+                                         rx->sdata->vif.addr,
+                                         rx->sdata->vif.type))
+               return RX_DROP_UNUSABLE;
+
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom, true);
+                                rx->local->hw.extra_tx_headroom,
+                                check_da, check_sa);
 
        while (!skb_queue_empty(&frame_list)) {
                rx->skb = __skb_dequeue(&frame_list);