Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
[linux-2.6.git] / net / mac80211 / rx.c
index 2862428..4eafbfd 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/rcupdate.h>
+#include <linux/export.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 
@@ -77,7 +78,7 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
        /* always present fields */
        len = sizeof(struct ieee80211_radiotap_header) + 9;
 
-       if (status->flag & RX_FLAG_TSFT)
+       if (status->flag & RX_FLAG_MACTIME_MPDU)
                len += 8;
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
@@ -85,6 +86,9 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
        if (len & 1) /* padding for RX_FLAGS if necessary */
                len++;
 
+       if (status->flag & RX_FLAG_HT) /* HT info */
+               len += 3;
+
        return len;
 }
 
@@ -120,7 +124,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        /* the order of the following fields is important */
 
        /* IEEE80211_RADIOTAP_TSFT */
-       if (status->flag & RX_FLAG_TSFT) {
+       if (status->flag & RX_FLAG_MACTIME_MPDU) {
                put_unaligned_le64(status->mactime, pos);
                rthdr->it_present |=
                        cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
@@ -139,11 +143,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        /* IEEE80211_RADIOTAP_RATE */
        if (status->flag & RX_FLAG_HT) {
                /*
-                * TODO: add following information into radiotap header once
-                * suitable fields are defined for it:
-                * - MCS index (status->rate_idx)
-                * - HT40 (status->flag & RX_FLAG_40MHZ)
-                * - short-GI (status->flag & RX_FLAG_SHORT_GI)
+                * MCS information is a separate field in radiotap,
+                * added below. The byte here is needed as padding
+                * for the channel though, so initialise it to 0.
                 */
                *pos = 0;
        } else {
@@ -193,6 +195,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
        put_unaligned_le16(rx_flags, pos);
        pos += 2;
+
+       if (status->flag & RX_FLAG_HT) {
+               rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
+               *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
+                        IEEE80211_RADIOTAP_MCS_HAVE_GI |
+                        IEEE80211_RADIOTAP_MCS_HAVE_BW;
+               *pos = 0;
+               if (status->flag & RX_FLAG_SHORT_GI)
+                       *pos |= IEEE80211_RADIOTAP_MCS_SGI;
+               if (status->flag & RX_FLAG_40MHZ)
+                       *pos |= IEEE80211_RADIOTAP_MCS_BW_40;
+               pos++;
+               *pos++ = status->rate_idx;
+       }
 }
 
 /*
@@ -315,17 +331,19 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       int tid;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int tid, seqno_idx, security_idx;
 
        /* does the frame have a qos control field? */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *qc = ieee80211_get_qos_ctl(hdr);
                /* frame has qos control */
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
-               if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-                       rx->flags |= IEEE80211_RX_AMSDU;
-               else
-                       rx->flags &= ~IEEE80211_RX_AMSDU;
+               if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
+                       status->rx_flags |= IEEE80211_RX_AMSDU;
+
+               seqno_idx = tid;
+               security_idx = tid;
        } else {
                /*
                 * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
@@ -338,10 +356,15 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                 *
                 * We also use that counter for non-QoS STAs.
                 */
-               tid = NUM_RX_DATA_QUEUES - 1;
+               seqno_idx = NUM_RX_DATA_QUEUES;
+               security_idx = 0;
+               if (ieee80211_is_mgmt(hdr->frame_control))
+                       security_idx = NUM_RX_DATA_QUEUES;
+               tid = 0;
        }
 
-       rx->queue = tid;
+       rx->seqno_idx = seqno_idx;
+       rx->security_idx = security_idx;
        /* Set skb->priority to 1d tag if highest order bit of TID is not set.
         * For now, set skb->priority to 0 for other cases. */
        rx->skb->priority = (tid > 7) ? 0 : tid;
@@ -368,7 +391,7 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
  * specs were sane enough this time around to require padding each A-MSDU
  * subframe to a length that is a multiple of four.
  *
- * Padding like Atheros hardware adds which is inbetween the 802.11 header and
+ * Padding like Atheros hardware adds which is between the 802.11 header and
  * the payload is not supported, the driver is required to move the 802.11
  * header to be directly in front of the payload in that case.
  */
@@ -387,26 +410,21 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
        struct sk_buff *skb = rx->skb;
 
-       if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
-               return ieee80211_scan_rx(rx->sdata, skb);
-
-       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) &&
-                    (rx->flags & IEEE80211_RX_IN_SCAN))) {
-               /* drop all the other packets during a software scan anyway */
-               if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
-                       dev_kfree_skb(skb);
-               return RX_QUEUED;
-       }
+       if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
+                  !local->sched_scanning))
+               return RX_CONTINUE;
 
-       if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
-               /* scanning finished during invoking of handlers */
-               I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
-               return RX_DROP_UNUSABLE;
-       }
+       if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+           test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+           local->sched_scanning)
+               return ieee80211_scan_rx(rx->sdata, skb);
 
-       return RX_CONTINUE;
+       /* scanning finished during invoking of handlers */
+       I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+       return RX_DROP_UNUSABLE;
 }
 
 
@@ -459,7 +477,6 @@ static ieee80211_rx_result
 ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
        char *dev_addr = rx->sdata->vif.addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
@@ -481,36 +498,32 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
         * establisment frame, beacon or probe, drop the frame.
         */
 
-       if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
+       if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) {
                struct ieee80211_mgmt *mgmt;
 
                if (!ieee80211_is_mgmt(hdr->frame_control))
                        return RX_DROP_MONITOR;
 
                if (ieee80211_is_action(hdr->frame_control)) {
+                       u8 category;
                        mgmt = (struct ieee80211_mgmt *)hdr;
-                       if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK)
+                       category = mgmt->u.action.category;
+                       if (category != WLAN_CATEGORY_MESH_ACTION &&
+                               category != WLAN_CATEGORY_SELF_PROTECTED)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
 
                if (ieee80211_is_probe_req(hdr->frame_control) ||
                    ieee80211_is_probe_resp(hdr->frame_control) ||
-                   ieee80211_is_beacon(hdr->frame_control))
+                   ieee80211_is_beacon(hdr->frame_control) ||
+                   ieee80211_is_auth(hdr->frame_control))
                        return RX_CONTINUE;
 
                return RX_DROP_MONITOR;
 
        }
 
-#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
-
-       if (ieee80211_is_data(hdr->frame_control) &&
-           is_multicast_ether_addr(hdr->addr1) &&
-           mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
-               return RX_DROP_MONITOR;
-#undef msh_h_get
-
        return RX_CONTINUE;
 }
 
@@ -535,26 +548,23 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
 
 static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
                                            struct tid_ampdu_rx *tid_agg_rx,
-                                           int index,
-                                           struct sk_buff_head *frames)
+                                           int index)
 {
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *rate = NULL;
+       struct ieee80211_local *local = hw_to_local(hw);
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
        struct ieee80211_rx_status *status;
 
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
        if (!skb)
                goto no_frame;
 
-       status = IEEE80211_SKB_RXCB(skb);
-
-       /* release the reordered frames to stack */
-       sband = hw->wiphy->bands[status->band];
-       if (!(status->flag & RX_FLAG_HT))
-               rate = &sband->bitrates[status->rate_idx];
+       /* release the frame from the reorder ring buffer */
        tid_agg_rx->stored_mpdu_num--;
        tid_agg_rx->reorder_buf[index] = NULL;
-       __skb_queue_tail(frames, skb);
+       status = IEEE80211_SKB_RXCB(skb);
+       status->rx_flags |= IEEE80211_RX_DEFERRED_RELEASE;
+       skb_queue_tail(&local->rx_skb_queue, skb);
 
 no_frame:
        tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
@@ -562,15 +572,16 @@ no_frame:
 
 static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
                                             struct tid_ampdu_rx *tid_agg_rx,
-                                            u16 head_seq_num,
-                                            struct sk_buff_head *frames)
+                                            u16 head_seq_num)
 {
        int index;
 
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
        while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
-               ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
+               ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
        }
 }
 
@@ -580,9 +591,79 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
  * frames that have not yet been received are assumed to be lost and the skb
  * can be released for processing. This may also release other skb's from the
  * reorder buffer if there are no additional gaps between the frames.
+ *
+ * Callers must hold tid_agg_rx->reorder_lock.
  */
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
+static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
+                                         struct tid_ampdu_rx *tid_agg_rx)
+{
+       int index, j;
+
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
+       /* release the buffer until next missing frame */
+       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                               tid_agg_rx->buf_size;
+       if (!tid_agg_rx->reorder_buf[index] &&
+           tid_agg_rx->stored_mpdu_num > 1) {
+               /*
+                * No buffers ready to be released, but check whether any
+                * frames in the reorder buffer have timed out.
+                */
+               int skipped = 1;
+               for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (!tid_agg_rx->reorder_buf[j]) {
+                               skipped++;
+                               continue;
+                       }
+                       if (skipped &&
+                           !time_after(jiffies, tid_agg_rx->reorder_time[j] +
+                                       HT_RX_REORDER_BUF_TIMEOUT))
+                               goto set_release_timer;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+                       if (net_ratelimit())
+                               wiphy_debug(hw->wiphy,
+                                           "release an RX reorder frame due to timeout on earlier frames\n");
+#endif
+                       ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
+
+                       /*
+                        * Increment the head seq# also for the skipped slots.
+                        */
+                       tid_agg_rx->head_seq_num =
+                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
+                       skipped = 0;
+               }
+       } else while (tid_agg_rx->reorder_buf[index]) {
+               ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+                                                       tid_agg_rx->buf_size;
+       }
+
+       if (tid_agg_rx->stored_mpdu_num) {
+               j = index = seq_sub(tid_agg_rx->head_seq_num,
+                                   tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
+               for (; j != (index - 1) % tid_agg_rx->buf_size;
+                    j = (j + 1) % tid_agg_rx->buf_size) {
+                       if (tid_agg_rx->reorder_buf[j])
+                               break;
+               }
+
+ set_release_timer:
+
+               mod_timer(&tid_agg_rx->reorder_timer,
+                         tid_agg_rx->reorder_time[j] + 1 +
+                         HT_RX_REORDER_BUF_TIMEOUT);
+       } else {
+               del_timer(&tid_agg_rx->reorder_timer);
+       }
+}
+
 /*
  * As this function belongs to the RX path it must be under
  * rcu_read_lock protection. It returns false if the frame
@@ -590,14 +671,16 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
  */
 static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                             struct tid_ampdu_rx *tid_agg_rx,
-                                            struct sk_buff *skb,
-                                            struct sk_buff_head *frames)
+                                            struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u16 sc = le16_to_cpu(hdr->seq_ctrl);
        u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
        u16 head_seq_num, buf_size;
        int index;
+       bool ret = true;
+
+       spin_lock(&tid_agg_rx->reorder_lock);
 
        buf_size = tid_agg_rx->buf_size;
        head_seq_num = tid_agg_rx->head_seq_num;
@@ -605,7 +688,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        /* frame with out of date sequence number */
        if (seq_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
-               return true;
+               goto out;
        }
 
        /*
@@ -615,8 +698,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
                head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
                /* release stored frames up to new head to stack */
-               ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num,
-                                                frames);
+               ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
        }
 
        /* Now the new frame is always in the range of the reordering buffer */
@@ -626,85 +708,48 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
                dev_kfree_skb(skb);
-               return true;
+               goto out;
        }
 
        /*
         * If the current MPDU is in the right order and nothing else
         * is stored we can process it directly, no need to buffer it.
+        * If it is first but there's something stored, we may be able
+        * to release frames after this one.
         */
        if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
            tid_agg_rx->stored_mpdu_num == 0) {
                tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
-               return false;
+               ret = false;
+               goto out;
        }
 
        /* put the frame in the reordering buffer */
        tid_agg_rx->reorder_buf[index] = skb;
        tid_agg_rx->reorder_time[index] = jiffies;
        tid_agg_rx->stored_mpdu_num++;
-       /* release the buffer until next missing frame */
-       index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
-                                               tid_agg_rx->buf_size;
-       if (!tid_agg_rx->reorder_buf[index] &&
-           tid_agg_rx->stored_mpdu_num > 1) {
-               /*
-                * No buffers ready to be released, but check whether any
-                * frames in the reorder buffer have timed out.
-                */
-               int j;
-               int skipped = 1;
-               for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
-                    j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (!tid_agg_rx->reorder_buf[j]) {
-                               skipped++;
-                               continue;
-                       }
-                       if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
-                                       HT_RX_REORDER_BUF_TIMEOUT))
-                               break;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "%s: release an RX reorder "
-                                      "frame due to timeout on earlier "
-                                      "frames\n",
-                                      wiphy_name(hw->wiphy));
-#endif
-                       ieee80211_release_reorder_frame(hw, tid_agg_rx,
-                                                       j, frames);
-
-                       /*
-                        * Increment the head seq# also for the skipped slots.
-                        */
-                       tid_agg_rx->head_seq_num =
-                               (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
-                       skipped = 0;
-               }
-       } else while (tid_agg_rx->reorder_buf[index]) {
-               ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
-               index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
-                                                       tid_agg_rx->buf_size;
-       }
+       ieee80211_sta_reorder_release(hw, tid_agg_rx);
 
-       return true;
+ out:
+       spin_unlock(&tid_agg_rx->reorder_lock);
+       return ret;
 }
 
 /*
  * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
  * true if the MPDU was buffered, false if it should be processed.
  */
-static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
-                                      struct sk_buff_head *frames)
+static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
 {
        struct sk_buff *skb = rx->skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       int tid;
+       u8 tid, ack_policy;
 
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
@@ -717,6 +762,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        if (!sta)
                goto dont_reorder;
 
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -727,6 +774,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
 
+       /* not part of a BA session */
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
+       /* not actually part of this BA session */
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               goto dont_reorder;
+
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
@@ -750,30 +806,31 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
         * sure that we cannot get to it any more before doing
         * anything with it.
         */
-       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
+       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb))
                return;
 
  dont_reorder:
-       __skb_queue_tail(frames, skb);
+       skb_queue_tail(&local->rx_skb_queue, skb);
 }
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
        /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
        if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
-                            rx->sta->last_seq_ctrl[rx->queue] ==
+                            rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
-                       if (rx->flags & IEEE80211_RX_RA_MATCH) {
+                       if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
                                rx->local->dot11FrameDuplicateCount++;
                                rx->sta->num_duplicates++;
                        }
-                       return RX_DROP_MONITOR;
+                       return RX_DROP_UNUSABLE;
                } else
-                       rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
+                       rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
        }
 
        if (unlikely(rx->skb->len < 16)) {
@@ -796,16 +853,27 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        if (unlikely((ieee80211_is_data(hdr->frame_control) ||
                      ieee80211_is_pspoll(hdr->frame_control)) &&
                     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-                    (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
-               if ((!ieee80211_has_fromds(hdr->frame_control) &&
-                    !ieee80211_has_tods(hdr->frame_control) &&
-                    ieee80211_is_data(hdr->frame_control)) ||
-                   !(rx->flags & IEEE80211_RX_RA_MATCH)) {
-                       /* Drop IBSS frames and frames for other hosts
-                        * silently. */
-                       return RX_DROP_MONITOR;
+                    rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
+                    (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
+               if (rx->sta && rx->sta->dummy &&
+                   ieee80211_is_data_present(hdr->frame_control)) {
+                       u16 ethertype;
+                       u8 *payload;
+
+                       payload = rx->skb->data +
+                               ieee80211_hdrlen(hdr->frame_control);
+                       ethertype = (payload[6] << 8) | payload[7];
+                       if (cpu_to_be16(ethertype) ==
+                           rx->sdata->control_port_protocol)
+                               return RX_CONTINUE;
                }
 
+               if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+                   cfg80211_rx_spurious_frame(rx->sdata->dev,
+                                              hdr->addr2,
+                                              GFP_ATOMIC))
+                       return RX_DROP_UNUSABLE;
+
                return RX_DROP_MONITOR;
        }
 
@@ -822,7 +890,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        int keyidx;
        int hdrlen;
        ieee80211_rx_result result = RX_DROP_UNUSABLE;
-       struct ieee80211_key *stakey = NULL;
+       struct ieee80211_key *sta_ptk = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
 
@@ -857,22 +925,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
         * No point in finding a key and decrypting if the frame is neither
         * addressed to us nor a multicast frame.
         */
-       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
        /* start without a key */
        rx->key = NULL;
 
        if (rx->sta)
-               stakey = rcu_dereference(rx->sta->key);
+               sta_ptk = rcu_dereference(rx->sta->ptk);
 
        fc = hdr->frame_control;
 
        if (!ieee80211_has_protected(fc))
                mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 
-       if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
-               rx->key = stakey;
+       if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
+               rx->key = sta_ptk;
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
+                       return RX_CONTINUE;
                /* Skip decryption if the frame is not protected. */
                if (!ieee80211_has_protected(fc))
                        return RX_CONTINUE;
@@ -885,7 +956,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                if (mmie_keyidx < NUM_DEFAULT_KEYS ||
                    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
                        return RX_DROP_MONITOR; /* unexpected BIP keyidx */
-               rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
+               if (rx->sta)
+                       rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
+               if (!rx->key)
+                       rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
        } else if (!ieee80211_has_protected(fc)) {
                /*
                 * The frame was not protected, so skip decryption. However, we
@@ -894,12 +968,31 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * have been expected.
                 */
                struct ieee80211_key *key = NULL;
+               struct ieee80211_sub_if_data *sdata = rx->sdata;
+               int i;
+
                if (ieee80211_is_mgmt(fc) &&
                    is_multicast_ether_addr(hdr->addr1) &&
                    (key = rcu_dereference(rx->sdata->default_mgmt_key)))
                        rx->key = key;
-               else if ((key = rcu_dereference(rx->sdata->default_key)))
-                       rx->key = key;
+               else {
+                       if (rx->sta) {
+                               for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+                                       key = rcu_dereference(rx->sta->gtk[i]);
+                                       if (key)
+                                               break;
+                               }
+                       }
+                       if (!key) {
+                               for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+                                       key = rcu_dereference(sdata->keys[i]);
+                                       if (key)
+                                               break;
+                               }
+                       }
+                       if (key)
+                               rx->key = key;
+               }
                return RX_CONTINUE;
        } else {
                u8 keyid;
@@ -928,19 +1021,31 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
                keyidx = keyid >> 6;
 
-               rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+               /* check per-station GTK first, if multicast packet */
+               if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
+                       rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
 
-               /*
-                * RSNA-protected unicast frames should always be sent with
-                * pairwise or station-to-station keys, but for WEP we allow
-                * using a key index as well.
-                */
-               if (rx->key && rx->key->conf.alg != ALG_WEP &&
-                   !is_multicast_ether_addr(hdr->addr1))
-                       rx->key = NULL;
+               /* if not found, try default key */
+               if (!rx->key) {
+                       rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
+
+                       /*
+                        * RSNA-protected unicast frames should always be
+                        * sent with pairwise or station-to-station keys,
+                        * but for WEP we allow using a key index as well.
+                        */
+                       if (rx->key &&
+                           rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
+                           rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
+                           !is_multicast_ether_addr(hdr->addr1))
+                               rx->key = NULL;
+               }
        }
 
        if (rx->key) {
+               if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+                       return RX_DROP_MONITOR;
+
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
@@ -951,8 +1056,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_UNUSABLE;
        /* the hdr variable is invalid now! */
 
-       switch (rx->key->conf.alg) {
-       case ALG_WEP:
+       switch (rx->key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
                /* Check for weak IVs if possible */
                if (rx->sta && ieee80211_is_data(fc) &&
                    (!(status->flag & RX_FLAG_IV_STRIPPED) ||
@@ -962,15 +1068,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                result = ieee80211_crypto_wep_decrypt(rx);
                break;
-       case ALG_TKIP:
+       case WLAN_CIPHER_SUITE_TKIP:
                result = ieee80211_crypto_tkip_decrypt(rx);
                break;
-       case ALG_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP:
                result = ieee80211_crypto_ccmp_decrypt(rx);
                break;
-       case ALG_AES_CMAC:
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                result = ieee80211_crypto_aes_cmac_decrypt(rx);
                break;
+       default:
+               /*
+                * We can reach here only with HW-only algorithms
+                * but why didn't it decrypt the frame?!
+                */
+               return RX_DROP_UNUSABLE;
        }
 
        /* either the frame has been decrypted or will be dropped */
@@ -1018,8 +1130,9 @@ static void ap_sta_ps_start(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
 
        atomic_inc(&sdata->bss->num_sta_ps);
-       set_sta_flags(sta, WLAN_STA_PS_STA);
-       drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
+       set_sta_flag(sta, WLAN_STA_PS_STA);
+       if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
+               drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n",
               sdata->name, sta->sta.addr, sta->sta.aid);
@@ -1032,14 +1145,12 @@ static void ap_sta_ps_end(struct sta_info *sta)
 
        atomic_dec(&sdata->bss->num_sta_ps);
 
-       clear_sta_flags(sta, WLAN_STA_PS_STA);
-
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n",
               sdata->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
-       if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
+       if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
                       sdata->name, sta->sta.addr, sta->sta.aid);
@@ -1050,6 +1161,102 @@ static void ap_sta_ps_end(struct sta_info *sta)
        ieee80211_sta_ps_deliver_wakeup(sta);
 }
 
+int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
+{
+       struct sta_info *sta_inf = container_of(sta, struct sta_info, sta);
+       bool in_ps;
+
+       WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS));
+
+       /* Don't let the same PS state be set twice */
+       in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA);
+       if ((start && in_ps) || (!start && !in_ps))
+               return -EINVAL;
+
+       if (start)
+               ap_sta_ps_start(sta_inf);
+       else
+               ap_sta_ps_end(sta_inf);
+
+       return 0;
+}
+EXPORT_SYMBOL(ieee80211_sta_ps_transition);
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int tid, ac;
+
+       if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               return RX_CONTINUE;
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP &&
+           sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
+               return RX_CONTINUE;
+
+       /*
+        * The device handles station powersave, so don't do anything about
+        * uAPSD and PS-Poll frames (the latter shouldn't even come up from
+        * it to mac80211 since they're handled.)
+        */
+       if (sdata->local->hw.flags & IEEE80211_HW_AP_LINK_PS)
+               return RX_CONTINUE;
+
+       /*
+        * Don't do anything if the station isn't already asleep. In
+        * the uAPSD case, the station will probably be marked asleep,
+        * in the PS-Poll case the station must be confused ...
+        */
+       if (!test_sta_flag(rx->sta, WLAN_STA_PS_STA))
+               return RX_CONTINUE;
+
+       if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
+               if (!test_sta_flag(rx->sta, WLAN_STA_SP)) {
+                       if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+                               ieee80211_sta_ps_deliver_poll_response(rx->sta);
+                       else
+                               set_sta_flag(rx->sta, WLAN_STA_PSPOLL);
+               }
+
+               /* Free PS Poll skb here instead of returning RX_DROP that would
+                * count as an dropped frame. */
+               dev_kfree_skb(rx->skb);
+
+               return RX_QUEUED;
+       } else if (!ieee80211_has_morefrags(hdr->frame_control) &&
+                  !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+                  ieee80211_has_pm(hdr->frame_control) &&
+                  (ieee80211_is_data_qos(hdr->frame_control) ||
+                   ieee80211_is_qos_nullfunc(hdr->frame_control))) {
+               tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+               ac = ieee802_1d_to_ac[tid & 7];
+
+               /*
+                * If this AC is not trigger-enabled do nothing.
+                *
+                * NB: This could/should check a separate bitmap of trigger-
+                * enabled queues, but for now we only implement uAPSD w/o
+                * TSPEC changes to the ACs, so they're always the same.
+                */
+               if (!(rx->sta->sta.uapsd_queues & BIT(ac)))
+                       return RX_CONTINUE;
+
+               /* if we are in a service period, do nothing */
+               if (test_sta_flag(rx->sta, WLAN_STA_SP))
+                       return RX_CONTINUE;
+
+               if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
+                       ieee80211_sta_ps_deliver_uapsd(rx->sta);
+               else
+                       set_sta_flag(rx->sta, WLAN_STA_UAPSD);
+       }
+
+       return RX_CONTINUE;
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
@@ -1069,17 +1276,26 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
-               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
+               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) {
                        sta->last_rx = jiffies;
+                       if (ieee80211_is_data(hdr->frame_control)) {
+                               sta->last_rx_rate_idx = status->rate_idx;
+                               sta->last_rx_rate_flag = status->flag;
+                       }
+               }
        } else if (!is_multicast_ether_addr(hdr->addr1)) {
                /*
                 * Mesh beacons will update last_rx when if they are found to
                 * match the current local configuration when processed.
                 */
                sta->last_rx = jiffies;
+               if (ieee80211_is_data(hdr->frame_control)) {
+                       sta->last_rx_rate_idx = status->rate_idx;
+                       sta->last_rx_rate_flag = status->flag;
+               }
        }
 
-       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_CONTINUE;
 
        if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
@@ -1088,15 +1304,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
        sta->last_signal = status->signal;
+       ewma_add(&sta->avg_signal, -status->signal);
 
        /*
         * Change STA power saving mode only at the end of a frame
         * exchange sequence.
         */
-       if (!ieee80211_has_morefrags(hdr->frame_control) &&
+       if (!(sta->local->hw.flags & IEEE80211_HW_AP_LINK_PS) &&
+           !ieee80211_has_morefrags(hdr->frame_control) &&
+           !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
             rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-               if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
+               if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
                        /*
                         * Ignore doze->wake transitions that are
                         * indicated by non-data frames, the standard
@@ -1124,15 +1343,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
                /*
                 * If we receive a 4-addr nullfunc frame from a STA
-                * that was not moved to a 4-addr STA vlan yet, drop
-                * the frame to the monitor interface, to make sure
-                * that hostapd sees it
+                * that was not moved to a 4-addr STA vlan yet send
+                * the event to userspace and for older hostapd drop
+                * the frame to the monitor interface.
                 */
                if (ieee80211_has_a4(hdr->frame_control) &&
                    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
                     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-                     !rx->sdata->u.vlan.sta)))
+                     !rx->sdata->u.vlan.sta))) {
+                       if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
+                               cfg80211_rx_unexpected_4addr_frame(
+                                       rx->sdata->dev, sta->sta.addr,
+                                       GFP_ATOMIC);
                        return RX_DROP_MONITOR;
+               }
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@ -1236,6 +1460,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        unsigned int frag, seq;
        struct ieee80211_fragment_entry *entry;
        struct sk_buff *skb;
+       struct ieee80211_rx_status *status;
 
        hdr = (struct ieee80211_hdr *)rx->skb->data;
        fc = hdr->frame_control;
@@ -1264,11 +1489,10 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        if (frag == 0) {
                /* This is the first fragment of a new frame. */
                entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
-                                                rx->queue, &(rx->skb));
-               if (rx->key && rx->key->conf.alg == ALG_CCMP &&
+                                                rx->seqno_idx, &(rx->skb));
+               if (rx->key && rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP &&
                    ieee80211_has_protected(fc)) {
-                       int queue = ieee80211_is_mgmt(fc) ?
-                               NUM_RX_DATA_QUEUES : rx->queue;
+                       int queue = rx->security_idx;
                        /* Store CCMP PN so that we can verify that the next
                         * fragment has a sequential PN value. */
                        entry->ccmp = 1;
@@ -1282,7 +1506,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        /* This is a fragment for a frame that should already be pending in
         * fragment cache. Add this fragment to the end of the pending entry.
         */
-       entry = ieee80211_reassemble_find(rx->sdata, frag, seq, rx->queue, hdr);
+       entry = ieee80211_reassemble_find(rx->sdata, frag, seq,
+                                         rx->seqno_idx, hdr);
        if (!entry) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
                return RX_DROP_MONITOR;
@@ -1294,7 +1519,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                int i;
                u8 pn[CCMP_PN_LEN], *rpn;
                int queue;
-               if (!rx->key || rx->key->conf.alg != ALG_CCMP)
+               if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP)
                        return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, CCMP_PN_LEN);
                for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -1302,8 +1527,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                        if (pn[i])
                                break;
                }
-               queue = ieee80211_is_mgmt(fc) ?
-                       NUM_RX_DATA_QUEUES : rx->queue;
+               queue = rx->security_idx;
                rpn = rx->key->u.ccmp.rx_pn[queue];
                if (memcmp(pn, rpn, CCMP_PN_LEN))
                        return RX_DROP_UNUSABLE;
@@ -1335,7 +1559,8 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        }
 
        /* Complete frame has been reassembled - process it now */
-       rx->flags |= IEEE80211_RX_FRAGMENTED;
+       status = IEEE80211_SKB_RXCB(rx->skb);
+       status->rx_flags |= IEEE80211_RX_FRAGMENTED;
 
  out:
        if (rx->sta)
@@ -1348,32 +1573,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 }
 
 static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
-{
-       struct ieee80211_sub_if_data *sdata = rx->sdata;
-       __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control;
-
-       if (likely(!rx->sta || !ieee80211_is_pspoll(fc) ||
-                  !(rx->flags & IEEE80211_RX_RA_MATCH)))
-               return RX_CONTINUE;
-
-       if ((sdata->vif.type != NL80211_IFTYPE_AP) &&
-           (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
-               return RX_DROP_UNUSABLE;
-
-       if (!test_sta_flags(rx->sta, WLAN_STA_PS_DRIVER))
-               ieee80211_sta_ps_deliver_poll_response(rx->sta);
-       else
-               set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
-
-       /* Free PS Poll skb here instead of returning RX_DROP that would
-        * count as an dropped frame. */
-       dev_kfree_skb(rx->skb);
-
-       return RX_QUEUED;
-}
-
-static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
 {
        u8 *data = rx->skb->data;
@@ -1396,7 +1595,7 @@ static int
 ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
        if (unlikely(!rx->sta ||
-           !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED)))
+           !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
                return -EACCES;
 
        return 0;
@@ -1439,15 +1638,33 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
        if (status->flag & RX_FLAG_DECRYPTED)
                return 0;
 
-       if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+       if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) {
                if (unlikely(!ieee80211_has_protected(fc) &&
                             ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
-                            rx->key))
+                            rx->key)) {
+                       if (ieee80211_is_deauth(fc))
+                               cfg80211_send_unprot_deauth(rx->sdata->dev,
+                                                           rx->skb->data,
+                                                           rx->skb->len);
+                       else if (ieee80211_is_disassoc(fc))
+                               cfg80211_send_unprot_disassoc(rx->sdata->dev,
+                                                             rx->skb->data,
+                                                             rx->skb->len);
                        return -EACCES;
+               }
                /* BIP does not use Protected field, so need to check MMIE */
                if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
-                            ieee80211_get_mmie_keyidx(rx->skb) < 0))
+                            ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
+                       if (ieee80211_is_deauth(fc))
+                               cfg80211_send_unprot_deauth(rx->sdata->dev,
+                                                           rx->skb->data,
+                                                           rx->skb->len);
+                       else if (ieee80211_is_disassoc(fc))
+                               cfg80211_send_unprot_disassoc(rx->sdata->dev,
+                                                             rx->skb->data,
+                                                             rx->skb->len);
                        return -EACCES;
+               }
                /*
                 * When using MFP, Action frames are not allowed prior to
                 * having configured keys.
@@ -1462,21 +1679,43 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 }
 
 static int
-__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control)
 {
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       bool check_port_control = false;
+       struct ethhdr *ehdr;
+       int ret;
 
+       *port_control = false;
        if (ieee80211_has_a4(hdr->frame_control) &&
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
                return -1;
 
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !!sdata->u.mgd.use_4addr != !!ieee80211_has_a4(hdr->frame_control)) {
+
+               if (!sdata->u.mgd.use_4addr)
+                       return -1;
+               else
+                       check_port_control = true;
+       }
+
        if (is_multicast_ether_addr(hdr->addr1) &&
-           ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) ||
-            (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta)
+               return -1;
+
+       ret = ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
+       if (ret < 0)
+               return ret;
+
+       ehdr = (struct ethhdr *) rx->skb->data;
+       if (ehdr->h_proto == rx->sdata->control_port_protocol)
+               *port_control = true;
+       else if (check_port_control)
                return -1;
 
-       return ieee80211_data_to_8023(rx->skb, sdata->vif.addr, sdata->vif.type);
+       return 0;
 }
 
 /*
@@ -1492,7 +1731,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * Allow EAPOL frames to us/the PAE group address regardless
         * of whether the frame was encrypted or not.
         */
-       if (ehdr->h_proto == htons(ETH_P_PAE) &&
+       if (ehdr->h_proto == rx->sdata->control_port_protocol &&
            (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
@@ -1515,6 +1754,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        struct sk_buff *skb, *xmit_skb;
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
        skb = rx->skb;
        xmit_skb = NULL;
@@ -1522,7 +1762,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
        if ((sdata->vif.type == NL80211_IFTYPE_AP ||
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
            !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-           (rx->flags & IEEE80211_RX_RA_MATCH) &&
+           (status->rx_flags & IEEE80211_RX_RA_MATCH) &&
            (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
                if (is_multicast_ether_addr(ehdr->h_dest)) {
                        /*
@@ -1599,6 +1839,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc = hdr->frame_control;
        struct sk_buff_head frame_list;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
        if (unlikely(!ieee80211_is_data(fc)))
                return RX_CONTINUE;
@@ -1606,7 +1847,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (unlikely(!ieee80211_is_data_present(fc)))
                return RX_DROP_MONITOR;
 
-       if (!(rx->flags & IEEE80211_RX_AMSDU))
+       if (!(status->rx_flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
        if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1629,7 +1870,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom);
+                                rx->local->hw.extra_tx_headroom, true);
 
        while (!skb_queue_empty(&frame_list)) {
                rx->skb = __skb_dequeue(&frame_list);
@@ -1657,11 +1898,18 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
 
+       /* frame is in RMC, don't forward */
+       if (ieee80211_is_data(hdr->frame_control) &&
+           is_multicast_ether_addr(hdr->addr1) &&
+           mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata))
+               return RX_DROP_MONITOR;
+
        if (!ieee80211_is_data(hdr->frame_control))
                return RX_CONTINUE;
 
@@ -1669,6 +1917,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                /* illegal frame */
                return RX_DROP_MONITOR;
 
+       if (ieee80211_queue_stopped(&local->hw, skb_get_queue_mapping(skb))) {
+               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                               dropped_frames_congestion);
+               return RX_DROP_MONITOR;
+       }
+
        if (mesh_hdr->flags & MESH_FLAGS_AE) {
                struct mesh_path *mppath;
                char *proxied_addr;
@@ -1700,9 +1954,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
+       skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
        mesh_hdr->ttl--;
 
-       if (rx->flags & IEEE80211_RX_RA_MATCH) {
+       if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
                if (!mesh_hdr->ttl)
                        IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
                                                     dropped_frames_ttl);
@@ -1715,6 +1970,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
                                                   sdata->name);
+                       if (!fwd_skb)
+                               goto out;
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
                        memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
@@ -1722,13 +1979,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        info->control.vif = &rx->sdata->vif;
-                       skb_set_queue_mapping(skb,
-                               ieee80211_select_queue(rx->sdata, fwd_skb));
-                       ieee80211_set_qos_hdr(local, skb);
-                       if (is_multicast_ether_addr(fwd_hdr->addr1))
+                       info->control.jiffies = jiffies;
+                       if (is_multicast_ether_addr(fwd_hdr->addr1)) {
                                IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
                                                                fwded_mcast);
-                       else {
+                       } else {
                                int err;
                                /*
                                 * Save TA to addr1 to send TA a path error if a
@@ -1752,6 +2007,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                }
        }
 
+ out:
        if (is_multicast_ether_addr(hdr->addr1) ||
            sdata->dev->flags & IFF_PROMISC)
                return RX_CONTINUE;
@@ -1768,6 +2024,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        __le16 fc = hdr->frame_control;
+       bool port_control;
        int err;
 
        if (unlikely(!ieee80211_is_data(hdr->frame_control)))
@@ -1777,28 +2034,43 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        /*
-        * Allow the cooked monitor interface of an AP to see 4-addr frames so
-        * that a 4-addr station can be detected and moved into a separate VLAN
+        * Send unexpected-4addr-frame event to hostapd. For older versions,
+        * also drop the frame to cooked monitor interfaces.
         */
        if (ieee80211_has_a4(hdr->frame_control) &&
-           sdata->vif.type == NL80211_IFTYPE_AP)
+           sdata->vif.type == NL80211_IFTYPE_AP) {
+               if (rx->sta &&
+                   !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+                       cfg80211_rx_unexpected_4addr_frame(
+                               rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
                return RX_DROP_MONITOR;
+       }
 
-       err = __ieee80211_data_to_8023(rx);
+       err = __ieee80211_data_to_8023(rx, &port_control);
        if (unlikely(err))
                return RX_DROP_UNUSABLE;
 
        if (!ieee80211_frame_allowed(rx, fc))
                return RX_DROP_MONITOR;
 
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+           unlikely(port_control) && sdata->bss) {
+               sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+                                    u.ap);
+               dev = sdata->dev;
+               rx->sdata = sdata;
+       }
+
        rx->skb->dev = dev;
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += rx->skb->len;
 
-       if (ieee80211_is_data(hdr->frame_control) &&
-           !is_multicast_ether_addr(hdr->addr1) &&
-           local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) {
+       if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
+           !is_multicast_ether_addr(
+                   ((struct ethhdr *)rx->skb->data)->h_dest) &&
+           (!local->scanning &&
+            !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {
                        mod_timer(&local->dynamic_ps_timer, jiffies +
                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
@@ -1809,7 +2081,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 }
 
 static ieee80211_rx_result debug_noinline
-ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
+ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
@@ -1847,9 +2119,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                        mod_timer(&tid_agg_rx->session_timer,
                                  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
+               spin_lock(&tid_agg_rx->reorder_lock);
                /* release stored frames up to start of BAR */
-               ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
-                                                frames);
+               ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
+               spin_unlock(&tid_agg_rx->reorder_lock);
+
                kfree_skb(skb);
                return RX_QUEUED;
        }
@@ -1909,13 +2183,50 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
 }
 
 static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+       /*
+        * From here on, look only at management frames.
+        * Data and control frames are already handled,
+        * and unknown (reserved) frames are useless.
+        */
+       if (rx->skb->len < 24)
+               return RX_DROP_MONITOR;
+
+       if (!ieee80211_is_mgmt(mgmt->frame_control))
+               return RX_DROP_MONITOR;
+
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+           ieee80211_is_beacon(mgmt->frame_control) &&
+           !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB(rx->skb);
+               cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+                                           rx->skb->data, rx->skb->len,
+                                           status->freq, GFP_ATOMIC);
+               rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+       }
+
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               return RX_DROP_MONITOR;
+
+       if (ieee80211_drop_unencrypted_mgmt(rx))
+               return RX_DROP_UNUSABLE;
+
+       return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
-       struct sk_buff *nskb;
-       struct ieee80211_rx_status *status;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
        int len = rx->skb->len;
 
        if (!ieee80211_is_action(mgmt->frame_control))
@@ -1928,21 +2239,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
        if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
                return RX_DROP_UNUSABLE;
 
-       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
-               return RX_DROP_UNUSABLE;
-
-       if (ieee80211_drop_unencrypted_mgmt(rx))
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_UNUSABLE;
 
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
-               /*
-                * The aggregation code is not prepared to handle
-                * anything but STA/AP due to the BSSID handling;
-                * IBSS could work in the code but isn't supported
-                * by drivers or the standard.
-                */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP)
                        break;
@@ -2017,24 +2320,63 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        goto handled;
                }
                break;
-       case WLAN_CATEGORY_MESH_PLINK:
-       case WLAN_CATEGORY_MESH_PATH_SEL:
+       case WLAN_CATEGORY_SELF_PROTECTED:
+               switch (mgmt->u.action.u.self_prot.action_code) {
+               case WLAN_SP_MESH_PEERING_OPEN:
+               case WLAN_SP_MESH_PEERING_CLOSE:
+               case WLAN_SP_MESH_PEERING_CONFIRM:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+                               /* userspace handles this frame */
+                               break;
+                       goto queue;
+               case WLAN_SP_MGK_INFORM:
+               case WLAN_SP_MGK_ACK:
+                       if (!ieee80211_vif_is_mesh(&sdata->vif))
+                               goto invalid;
+                       break;
+               }
+               break;
+       case WLAN_CATEGORY_MESH_ACTION:
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
+               if (mesh_action_is_path_sel(mgmt) &&
+                 (!mesh_path_sel_is_hwmp(sdata)))
+                       break;
                goto queue;
        }
 
+       return RX_CONTINUE;
+
  invalid:
-       /*
-        * For AP mode, hostapd is responsible for handling any action
-        * frames that we didn't handle, including returning unknown
-        * ones. For all other modes we will return them to the sender,
-        * setting the 0x80 bit in the action category, as required by
-        * 802.11-2007 7.3.1.11.
-        */
-       if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               return RX_DROP_MONITOR;
+       status->rx_flags |= IEEE80211_RX_MALFORMED_ACTION_FRM;
+       /* will return in the next handlers */
+       return RX_CONTINUE;
+
+ handled:
+       if (rx->sta)
+               rx->sta->rx_packets++;
+       dev_kfree_skb(rx->skb);
+       return RX_QUEUED;
+
+ queue:
+       rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+       skb_queue_tail(&sdata->skb_queue, rx->skb);
+       ieee80211_queue_work(&local->hw, &sdata->work);
+       if (rx->sta)
+               rx->sta->rx_packets++;
+       return RX_QUEUED;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+       /* skip known-bad action frames and return them in the next handler */
+       if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM)
+               return RX_CONTINUE;
 
        /*
         * Getting here means the kernel doesn't know how to handle
@@ -2042,12 +2384,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
         * so userspace can register for those to know whether ones
         * it transmitted were processed or returned.
         */
-       status = IEEE80211_SKB_RXCB(rx->skb);
 
-       if (cfg80211_rx_action(rx->sdata->dev, status->freq,
-                              rx->skb->data, rx->skb->len,
-                              GFP_ATOMIC))
-               goto handled;
+       if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
+                            rx->skb->data, rx->skb->len,
+                            GFP_ATOMIC)) {
+               if (rx->sta)
+                       rx->sta->rx_packets++;
+               dev_kfree_skb(rx->skb);
+               return RX_QUEUED;
+       }
+
+
+       return RX_CONTINUE;
+}
+
+static ieee80211_rx_result debug_noinline
+ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
+       struct sk_buff *nskb;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+
+       if (!ieee80211_is_action(mgmt->frame_control))
+               return RX_CONTINUE;
+
+       /*
+        * For AP mode, hostapd is responsible for handling any action
+        * frames that we didn't handle, including returning unknown
+        * ones. For all other modes we will return them to the sender,
+        * setting the 0x80 bit in the action category, as required by
+        * 802.11-2007 7.3.1.11.
+        * Newer versions of hostapd shall also use the management frame
+        * registration mechanisms, but older ones still use cooked
+        * monitor interfaces so push all frames there.
+        */
+       if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) &&
+           (sdata->vif.type == NL80211_IFTYPE_AP ||
+            sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
+               return RX_DROP_MONITOR;
 
        /* do not return rejected action frames */
        if (mgmt->u.action.category & 0x80)
@@ -2066,20 +2442,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
                ieee80211_tx_skb(rx->sdata, nskb);
        }
-
- handled:
-       if (rx->sta)
-               rx->sta->rx_packets++;
        dev_kfree_skb(rx->skb);
        return RX_QUEUED;
-
- queue:
-       rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
-       skb_queue_tail(&sdata->skb_queue, rx->skb);
-       ieee80211_queue_work(&local->hw, &sdata->work);
-       if (rx->sta)
-               rx->sta->rx_packets++;
-       return RX_QUEUED;
 }
 
 static ieee80211_rx_result debug_noinline
@@ -2090,15 +2454,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
        __le16 stype;
 
-       if (!(rx->flags & IEEE80211_RX_RA_MATCH))
-               return RX_DROP_MONITOR;
-
-       if (rx->skb->len < 24)
-               return RX_DROP_MONITOR;
-
-       if (ieee80211_drop_unencrypted_mgmt(rx))
-               return RX_DROP_UNUSABLE;
-
        rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
        if (rxs != RX_CONTINUE)
                return rxs;
@@ -2117,6 +2472,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
                break;
        case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
        case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+               if (is_multicast_ether_addr(mgmt->da) &&
+                   !is_broadcast_ether_addr(mgmt->da))
+                       return RX_DROP_MONITOR;
+
                /* process only for station */
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        return RX_DROP_MONITOR;
@@ -2141,47 +2500,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
        return RX_QUEUED;
 }
 
-static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
-                                           struct ieee80211_rx_data *rx)
-{
-       int keyidx;
-       unsigned int hdrlen;
-
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       if (rx->skb->len >= hdrlen + 4)
-               keyidx = rx->skb->data[hdrlen + 3] >> 6;
-       else
-               keyidx = -1;
-
-       if (!rx->sta) {
-               /*
-                * Some hardware seem to generate incorrect Michael MIC
-                * reports; ignore them to avoid triggering countermeasures.
-                */
-               return;
-       }
-
-       if (!ieee80211_has_protected(hdr->frame_control))
-               return;
-
-       if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
-               /*
-                * APs with pairwise keys should never receive Michael MIC
-                * errors for non-zero keyidx because these are reserved for
-                * group keys and only the AP is sending real multicast
-                * frames in the BSS.
-                */
-               return;
-       }
-
-       if (!ieee80211_is_data(hdr->frame_control) &&
-           !ieee80211_is_auth(hdr->frame_control))
-               return;
-
-       mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
-                                       GFP_ATOMIC);
-}
-
 /* TODO: use IEEE80211_RX_FRAGMENTED */
 static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                                        struct ieee80211_rate *rate)
@@ -2199,6 +2517,18 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        struct net_device *prev_dev = NULL;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
+       /*
+        * If cooked monitor has been processed already, then
+        * don't do it again. If not, set the flag.
+        */
+       if (rx->flags & IEEE80211_RX_CMNTR)
+               goto out_free_skb;
+       rx->flags |= IEEE80211_RX_CMNTR;
+
+       /* If there are no cooked monitor interfaces, just free the SKB */
+       if (!local->cooked_mntrs)
+               goto out_free_skb;
+
        if (skb_headroom(skb) < sizeof(*rthdr) &&
            pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
                goto out_free_skb;
@@ -2253,29 +2583,52 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        if (prev_dev) {
                skb->dev = prev_dev;
                netif_receive_skb(skb);
-               skb = NULL;
-       } else
-               goto out_free_skb;
-
-       return;
+               return;
+       }
 
  out_free_skb:
        dev_kfree_skb(skb);
 }
 
+static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
+                                        ieee80211_rx_result res)
+{
+       switch (res) {
+       case RX_DROP_MONITOR:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+               if (rx->sta)
+                       rx->sta->rx_dropped++;
+               /* fall through */
+       case RX_CONTINUE: {
+               struct ieee80211_rate *rate = NULL;
+               struct ieee80211_supported_band *sband;
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB((rx->skb));
+
+               sband = rx->local->hw.wiphy->bands[status->band];
+               if (!(status->flag & RX_FLAG_HT))
+                       rate = &sband->bitrates[status->rate_idx];
+
+               ieee80211_rx_cooked_monitor(rx, rate);
+               break;
+               }
+       case RX_DROP_UNUSABLE:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_drop);
+               if (rx->sta)
+                       rx->sta->rx_dropped++;
+               dev_kfree_skb(rx->skb);
+               break;
+       case RX_QUEUED:
+               I802_DEBUG_INC(rx->sdata->local->rx_handlers_queued);
+               break;
+       }
+}
 
-static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_rx_data *rx,
-                                        struct sk_buff *skb,
-                                        struct ieee80211_rate *rate)
+static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
 {
-       struct sk_buff_head reorder_release;
        ieee80211_rx_result res = RX_DROP_MONITOR;
-
-       __skb_queue_head_init(&reorder_release);
-
-       rx->skb = skb;
-       rx->sdata = sdata;
+       struct sk_buff *skb;
 
 #define CALL_RXH(rxh)                  \
        do {                            \
@@ -2284,17 +2637,15 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                        goto rxh_next;  \
        } while (0);
 
-       /*
-        * NB: the rxh_next label works even if we jump
-        *     to it from here because then the list will
-        *     be empty, which is a trivial check
-        */
-       CALL_RXH(ieee80211_rx_h_passive_scan)
-       CALL_RXH(ieee80211_rx_h_check)
+       spin_lock(&rx->local->rx_skb_queue.lock);
+       if (rx->local->running_rx_handler)
+               goto unlock;
 
-       ieee80211_rx_reorder_ampdu(rx, &reorder_release);
+       rx->local->running_rx_handler = true;
+
+       while ((skb = __skb_dequeue(&rx->local->rx_skb_queue))) {
+               spin_unlock(&rx->local->rx_skb_queue.lock);
 
-       while ((skb = __skb_dequeue(&reorder_release))) {
                /*
                 * all the other fields are valid across frames
                 * that belong to an aMPDU since they are on the
@@ -2304,58 +2655,96 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
 
                CALL_RXH(ieee80211_rx_h_decrypt)
                CALL_RXH(ieee80211_rx_h_check_more_data)
+               CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll)
                CALL_RXH(ieee80211_rx_h_sta_process)
                CALL_RXH(ieee80211_rx_h_defragment)
-               CALL_RXH(ieee80211_rx_h_ps_poll)
                CALL_RXH(ieee80211_rx_h_michael_mic_verify)
                /* must be after MMIC verify so header is counted in MPDU mic */
-               CALL_RXH(ieee80211_rx_h_remove_qos_control)
-               CALL_RXH(ieee80211_rx_h_amsdu)
 #ifdef CONFIG_MAC80211_MESH
-               if (ieee80211_vif_is_mesh(&sdata->vif))
+               if (ieee80211_vif_is_mesh(&rx->sdata->vif))
                        CALL_RXH(ieee80211_rx_h_mesh_fwding);
 #endif
+               CALL_RXH(ieee80211_rx_h_remove_qos_control)
+               CALL_RXH(ieee80211_rx_h_amsdu)
                CALL_RXH(ieee80211_rx_h_data)
-
-               /* special treatment -- needs the queue */
-               res = ieee80211_rx_h_ctrl(rx, &reorder_release);
-               if (res != RX_CONTINUE)
-                       goto rxh_next;
-
+               CALL_RXH(ieee80211_rx_h_ctrl);
+               CALL_RXH(ieee80211_rx_h_mgmt_check)
                CALL_RXH(ieee80211_rx_h_action)
+               CALL_RXH(ieee80211_rx_h_userspace_mgmt)
+               CALL_RXH(ieee80211_rx_h_action_return)
                CALL_RXH(ieee80211_rx_h_mgmt)
 
+ rxh_next:
+               ieee80211_rx_handlers_result(rx, res);
+               spin_lock(&rx->local->rx_skb_queue.lock);
 #undef CALL_RXH
+       }
+
+       rx->local->running_rx_handler = false;
+
+ unlock:
+       spin_unlock(&rx->local->rx_skb_queue.lock);
+}
+
+static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
+{
+       ieee80211_rx_result res = RX_DROP_MONITOR;
+
+#define CALL_RXH(rxh)                  \
+       do {                            \
+               res = rxh(rx);          \
+               if (res != RX_CONTINUE) \
+                       goto rxh_next;  \
+       } while (0);
+
+       CALL_RXH(ieee80211_rx_h_passive_scan)
+       CALL_RXH(ieee80211_rx_h_check)
+
+       ieee80211_rx_reorder_ampdu(rx);
+
+       ieee80211_rx_handlers(rx);
+       return;
 
  rxh_next:
-               switch (res) {
-               case RX_DROP_MONITOR:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
-                       if (rx->sta)
-                               rx->sta->rx_dropped++;
-                       /* fall through */
-               case RX_CONTINUE:
-                       ieee80211_rx_cooked_monitor(rx, rate);
-                       break;
-               case RX_DROP_UNUSABLE:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_drop);
-                       if (rx->sta)
-                               rx->sta->rx_dropped++;
-                       dev_kfree_skb(rx->skb);
-                       break;
-               case RX_QUEUED:
-                       I802_DEBUG_INC(sdata->local->rx_handlers_queued);
-                       break;
-               }
-       }
+       ieee80211_rx_handlers_result(rx, res);
+
+#undef CALL_RXH
+}
+
+/*
+ * This function makes calls into the RX path, therefore
+ * it has to be invoked under RCU read lock.
+ */
+void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
+{
+       struct ieee80211_rx_data rx = {
+               .sta = sta,
+               .sdata = sta->sdata,
+               .local = sta->local,
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
+               .flags = 0,
+       };
+       struct tid_ampdu_rx *tid_agg_rx;
+
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+               return;
+
+       spin_lock(&tid_agg_rx->reorder_lock);
+       ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx);
+       spin_unlock(&tid_agg_rx->reorder_lock);
+
+       ieee80211_rx_handlers(&rx);
 }
 
 /* main receive path */
 
-static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
-                               struct ieee80211_rx_data *rx,
+static int prepare_for_handlers(struct ieee80211_rx_data *rx,
                                struct ieee80211_hdr *hdr)
 {
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
@@ -2367,9 +2756,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        return 0;
                if (!multicast &&
                    compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
-                       if (!(sdata->dev->flags & IFF_PROMISC))
+                       if (!(sdata->dev->flags & IFF_PROMISC) ||
+                           sdata->u.mgd.use_4addr)
                                return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                }
                break;
        case NL80211_IFTYPE_ADHOC:
@@ -2379,15 +2769,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        return 1;
                }
                else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
-                       if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+                       if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
                                return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!multicast &&
                           compare_ether_addr(sdata->vif.addr,
                                              hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta) {
                        int rate_idx;
                        if (status->flag & RX_FLAG_HT)
@@ -2405,7 +2795,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
 
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                }
                break;
        case NL80211_IFTYPE_AP_VLAN:
@@ -2416,9 +2806,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                return 0;
                } else if (!ieee80211_bssid_match(bssid,
                                        sdata->vif.addr)) {
-                       if (!(rx->flags & IEEE80211_RX_IN_SCAN))
+                       if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
+                           !ieee80211_is_beacon(hdr->frame_control) &&
+                           !(ieee80211_is_action(hdr->frame_control) &&
+                             sdata->vif.p2p))
                                return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+                       status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                }
                break;
        case NL80211_IFTYPE_WDS:
@@ -2427,9 +2820,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
                        return 0;
                break;
-       case NL80211_IFTYPE_MONITOR:
-       case NL80211_IFTYPE_UNSPECIFIED:
-       case __NL80211_IFTYPE_AFTER_LAST:
+       default:
                /* should never get here */
                WARN_ON(1);
                break;
@@ -2439,12 +2830,50 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 }
 
 /*
+ * This function returns whether or not the SKB
+ * was destined for RX processing or not, which,
+ * if consume is true, is equivalent to whether
+ * or not the skb was consumed.
+ */
+static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
+                                           struct sk_buff *skb, bool consume)
+{
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       int prepares;
+
+       rx->skb = skb;
+       status->rx_flags |= IEEE80211_RX_RA_MATCH;
+       prepares = prepare_for_handlers(rx, hdr);
+
+       if (!prepares)
+               return false;
+
+       if (!consume) {
+               skb = skb_copy(skb, GFP_ATOMIC);
+               if (!skb) {
+                       if (net_ratelimit())
+                               wiphy_debug(local->hw.wiphy,
+                                       "failed to copy skb for %s\n",
+                                       sdata->name);
+                       return true;
+               }
+
+               rx->skb = skb;
+       }
+
+       ieee80211_invoke_rx_handlers(rx);
+       return true;
+}
+
+/*
  * This is the actual Rx frames handler. as it blongs to Rx path it must
  * be called with rcu_read_lock protection.
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
-                                        struct sk_buff *skb,
-                                        struct ieee80211_rate *rate)
+                                        struct sk_buff *skb)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_local *local = hw_to_local(hw);
@@ -2452,11 +2881,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr;
        __le16 fc;
        struct ieee80211_rx_data rx;
-       int prepares;
-       struct ieee80211_sub_if_data *prev = NULL;
-       struct sk_buff *skb_new;
-       struct sta_info *sta, *tmp;
-       bool found_sta = false;
+       struct ieee80211_sub_if_data *prev;
+       struct sta_info *sta, *tmp, *prev_sta;
        int err = 0;
 
        fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -2468,8 +2894,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                local->dot11ReceivedFragmentCount++;
 
        if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-                    test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
-               rx.flags |= IEEE80211_RX_IN_SCAN;
+                    test_bit(SCAN_SW_SCANNING, &local->scanning)))
+               status->rx_flags |= IEEE80211_RX_IN_SCAN;
 
        if (ieee80211_is_mgmt(fc))
                err = skb_linearize(skb);
@@ -2486,91 +2912,69 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        ieee80211_verify_alignment(&rx);
 
        if (ieee80211_is_data(fc)) {
-               for_each_sta_info(local, hdr->addr2, sta, tmp) {
-                       rx.sta = sta;
-                       found_sta = true;
-                       rx.sdata = sta->sdata;
-
-                       rx.flags |= IEEE80211_RX_RA_MATCH;
-                       prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
-                       if (prepares) {
-                               if (status->flag & RX_FLAG_MMIC_ERROR) {
-                                       if (rx.flags & IEEE80211_RX_RA_MATCH)
-                                               ieee80211_rx_michael_mic_report(hdr, &rx);
-                               } else
-                                       prev = rx.sdata;
-                       }
-               }
-       }
-       if (!found_sta) {
-               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-                       if (!ieee80211_sdata_running(sdata))
-                               continue;
+               prev_sta = NULL;
 
-                       if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
-                           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
+                       if (!prev_sta) {
+                               prev_sta = sta;
                                continue;
+                       }
 
-                       /*
-                        * frame is destined for this interface, but if it's
-                        * not also for the previous one we handle that after
-                        * the loop to avoid copying the SKB once too much
-                        */
+                       rx.sta = prev_sta;
+                       rx.sdata = prev_sta->sdata;
+                       ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
-                       if (!prev) {
-                               prev = sdata;
-                               continue;
-                       }
+                       prev_sta = sta;
+               }
 
-                       rx.sta = sta_info_get_bss(prev, hdr->addr2);
+               if (prev_sta) {
+                       rx.sta = prev_sta;
+                       rx.sdata = prev_sta->sdata;
 
-                       rx.flags |= IEEE80211_RX_RA_MATCH;
-                       prepares = prepare_for_handlers(prev, &rx, hdr);
+                       if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+                               return;
+                       goto out;
+               }
+       }
 
-                       if (!prepares)
-                               goto next;
+       prev = NULL;
 
-                       if (status->flag & RX_FLAG_MMIC_ERROR) {
-                               rx.sdata = prev;
-                               if (rx.flags & IEEE80211_RX_RA_MATCH)
-                                       ieee80211_rx_michael_mic_report(hdr,
-                                                                       &rx);
-                               goto next;
-                       }
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
 
-                       /*
-                        * frame was destined for the previous interface
-                        * so invoke RX handlers for it
-                        */
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       continue;
 
-                       skb_new = skb_copy(skb, GFP_ATOMIC);
-                       if (!skb_new) {
-                               if (net_ratelimit())
-                                       printk(KERN_DEBUG "%s: failed to copy "
-                                              "multicast frame for %s\n",
-                                              wiphy_name(local->hw.wiphy),
-                                              prev->name);
-                               goto next;
-                       }
-                       ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
-next:
+               /*
+                * frame is destined for this interface, but if it's
+                * not also for the previous one we handle that after
+                * the loop to avoid copying the SKB once too much
+                */
+
+               if (!prev) {
                        prev = sdata;
+                       continue;
                }
 
-               if (prev) {
-                       rx.sta = sta_info_get_bss(prev, hdr->addr2);
+               rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+               rx.sdata = prev;
+               ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
-                       rx.flags |= IEEE80211_RX_RA_MATCH;
-                       prepares = prepare_for_handlers(prev, &rx, hdr);
+               prev = sdata;
+       }
 
-                       if (!prepares)
-                               prev = NULL;
-               }
+       if (prev) {
+               rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+               rx.sdata = prev;
+
+               if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+                       return;
        }
-       if (prev)
-               ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
-       else
-               dev_kfree_skb(skb);
+
+ out:
+       dev_kfree_skb(skb);
 }
 
 /*
@@ -2611,30 +3015,41 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (WARN_ON(!local->started))
                goto drop;
 
-       if (status->flag & RX_FLAG_HT) {
+       if (likely(!(status->flag & RX_FLAG_FAILED_PLCP_CRC))) {
                /*
-                * rate_idx is MCS index, which can be [0-76] as documented on:
-                *
-                * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
-                *
-                * Anything else would be some sort of driver or hardware error.
-                * The driver should catch hardware errors.
+                * Validate the rate, unless a PLCP error means that
+                * we probably can't have a valid rate here anyway.
                 */
-               if (WARN((status->rate_idx < 0 ||
-                        status->rate_idx > 76),
-                        "Rate marked as an HT rate but passed "
-                        "status->rate_idx is not "
-                        "an MCS index [0-76]: %d (0x%02x)\n",
-                        status->rate_idx,
-                        status->rate_idx))
-                       goto drop;
-       } else {
-               if (WARN_ON(status->rate_idx < 0 ||
-                           status->rate_idx >= sband->n_bitrates))
-                       goto drop;
-               rate = &sband->bitrates[status->rate_idx];
+
+               if (status->flag & RX_FLAG_HT) {
+                       /*
+                        * rate_idx is MCS index, which can be [0-76]
+                        * as documented on:
+                        *
+                        * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+                        *
+                        * Anything else would be some sort of driver or
+                        * hardware error. The driver should catch hardware
+                        * errors.
+                        */
+                       if (WARN((status->rate_idx < 0 ||
+                                status->rate_idx > 76),
+                                "Rate marked as an HT rate but passed "
+                                "status->rate_idx is not "
+                                "an MCS index [0-76]: %d (0x%02x)\n",
+                                status->rate_idx,
+                                status->rate_idx))
+                               goto drop;
+               } else {
+                       if (WARN_ON(status->rate_idx < 0 ||
+                                   status->rate_idx >= sband->n_bitrates))
+                               goto drop;
+                       rate = &sband->bitrates[status->rate_idx];
+               }
        }
 
+       status->rx_flags = 0;
+
        /*
         * key references and virtual interfaces are protected using RCU
         * and this requires that we are in a read-side RCU section during
@@ -2654,7 +3069,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
-       __ieee80211_rx_handle_packet(hw, skb, rate);
+       ieee80211_tpt_led_trig_rx(local,
+                       ((struct ieee80211_hdr *)skb->data)->frame_control,
+                       skb->len);
+       __ieee80211_rx_handle_packet(hw, skb);
 
        rcu_read_unlock();