mac80211: add missing sanity checks for action frames
[safe/jmp/linux-2.6] / net / mac80211 / rx.c
index a5afb79..82a30c1 100644 (file)
@@ -19,6 +19,7 @@
 #include <net/ieee80211_radiotap.h>
 
 #include "ieee80211_i.h"
+#include "driver-ops.h"
 #include "led.h"
 #include "mesh.h"
 #include "wep.h"
 #include "tkip.h"
 #include "wme.h"
 
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-                                          struct tid_ampdu_rx *tid_agg_rx,
-                                          struct sk_buff *skb,
-                                          struct ieee80211_rx_status *status,
-                                          u16 mpdu_seq_num,
-                                          int bar_req);
 /*
  * monitor mode reception
  *
@@ -39,11 +34,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
  * only useful for monitoring.
  */
 static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
-                                          struct sk_buff *skb,
-                                          int rtap_len)
+                                          struct sk_buff *skb)
 {
-       skb_pull(skb, rtap_len);
-
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
                        skb_trim(skb, skb->len - FCS_LEN);
@@ -58,16 +50,15 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
        return skb;
 }
 
-static inline int should_drop_frame(struct ieee80211_rx_status *status,
-                                   struct sk_buff *skb,
-                                   int present_fcs_len,
-                                   int radiotap_len)
+static inline int should_drop_frame(struct sk_buff *skb,
+                                   int present_fcs_len)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
                return 1;
-       if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len))
+       if (unlikely(skb->len < 16 + present_fcs_len))
                return 1;
        if (ieee80211_is_ctl(hdr->frame_control) &&
            !ieee80211_is_pspoll(hdr->frame_control) &&
@@ -95,10 +86,6 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
        if (len & 1) /* padding for RX_FLAGS if necessary */
                len++;
 
-       /* make sure radiotap starts at a naturally aligned address */
-       if (len % 8)
-               len = roundup(len, 8);
-
        return len;
 }
 
@@ -110,12 +97,13 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
 static void
 ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                                 struct sk_buff *skb,
-                                struct ieee80211_rx_status *status,
                                 struct ieee80211_rate *rate,
                                 int rtap_len)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
+       u16 rx_flags = 0;
 
        rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
        memset(rthdr, 0, rtap_len);
@@ -134,7 +122,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 
        /* IEEE80211_RADIOTAP_TSFT */
        if (status->flag & RX_FLAG_TSFT) {
-               *(__le64 *)pos = cpu_to_le64(status->mactime);
+               put_unaligned_le64(status->mactime, pos);
                rthdr->it_present |=
                        cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
                pos += 8;
@@ -166,17 +154,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos++;
 
        /* IEEE80211_RADIOTAP_CHANNEL */
-       *(__le16 *)pos = cpu_to_le16(status->freq);
+       put_unaligned_le16(status->freq, pos);
        pos += 2;
        if (status->band == IEEE80211_BAND_5GHZ)
-               *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
-                                            IEEE80211_CHAN_5GHZ);
+               put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
+                                  pos);
+       else if (status->flag & RX_FLAG_HT)
+               put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
+                                  pos);
        else if (rate->flags & IEEE80211_RATE_ERP_G)
-               *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
-                                            IEEE80211_CHAN_2GHZ);
+               put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
+                                  pos);
        else
-               *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_CCK |
-                                            IEEE80211_CHAN_2GHZ);
+               put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
+                                  pos);
        pos += 2;
 
        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
@@ -205,10 +196,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 
        /* IEEE80211_RADIOTAP_RX_FLAGS */
        /* ensure 2 byte alignment for the 2 byte field as required */
-       if ((pos - (unsigned char *)rthdr) & 1)
+       if ((pos - (u8 *)rthdr) & 1)
                pos++;
        if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
-               *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP);
+               rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
+       put_unaligned_le16(rx_flags, pos);
        pos += 2;
 }
 
@@ -219,15 +211,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-                    struct ieee80211_rx_status *status,
                     struct ieee80211_rate *rate)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb);
        struct ieee80211_sub_if_data *sdata;
        int needed_headroom = 0;
        struct sk_buff *skb, *skb2;
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
-       int rtap_len = 0;
 
        /*
         * First, we may need to make a copy of the skb because
@@ -237,26 +228,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
         * We don't need to, of course, if we aren't going to return
         * the SKB because it has a bad FCS/PLCP checksum.
         */
-       if (status->flag & RX_FLAG_RADIOTAP)
-               rtap_len = ieee80211_get_radiotap_len(origskb->data);
-       else
-               /* room for the radiotap header based on driver features */
-               needed_headroom = ieee80211_rx_radiotap_len(local, status);
+
+       /* room for the radiotap header based on driver features */
+       needed_headroom = ieee80211_rx_radiotap_len(local, status);
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
        if (!local->monitors) {
-               if (should_drop_frame(status, origskb, present_fcs_len,
-                                     rtap_len)) {
+               if (should_drop_frame(origskb, present_fcs_len)) {
                        dev_kfree_skb(origskb);
                        return NULL;
                }
 
-               return remove_monitor_info(local, origskb, rtap_len);
+               return remove_monitor_info(local, origskb);
        }
 
-       if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {
+       if (should_drop_frame(origskb, present_fcs_len)) {
                /* only need to expand headroom if necessary */
                skb = origskb;
                origskb = NULL;
@@ -280,16 +268,14 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                 */
                skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);
 
-               origskb = remove_monitor_info(local, origskb, rtap_len);
+               origskb = remove_monitor_info(local, origskb);
 
                if (!skb)
                        return origskb;
        }
 
-       /* if necessary, prepend radiotap information */
-       if (!(status->flag & RX_FLAG_RADIOTAP))
-               ieee80211_add_rx_radiotap_header(local, skb, status, rate,
-                                                needed_headroom);
+       /* prepend radiotap information */
+       ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom);
 
        skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -419,13 +405,13 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct sk_buff *skb = rx->skb;
 
-       if (unlikely(local->hw_scanning))
-               return ieee80211_scan_rx(rx->sdata, skb, rx->status);
+       if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning)))
+               return ieee80211_scan_rx(rx->sdata, skb);
 
-       if (unlikely(local->sw_scanning)) {
+       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->status)
-                   != RX_QUEUED)
+               if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED)
                        dev_kfree_skb(skb);
                return RX_QUEUED;
        }
@@ -490,12 +476,21 @@ 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->dev->dev_addr;
 
        if (ieee80211_is_data(hdr->frame_control)) {
-               if (!ieee80211_has_a4(hdr->frame_control))
-                       return RX_DROP_MONITOR;
-               if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
-                       return RX_DROP_MONITOR;
+               if (is_multicast_ether_addr(hdr->addr1)) {
+                       if (ieee80211_has_tods(hdr->frame_control) ||
+                               !ieee80211_has_fromds(hdr->frame_control))
+                               return RX_DROP_MONITOR;
+                       if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+                               return RX_DROP_MONITOR;
+               } else {
+                       if (!ieee80211_has_a4(hdr->frame_control))
+                               return RX_DROP_MONITOR;
+                       if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+                               return RX_DROP_MONITOR;
+               }
        }
 
        /* If there is not an established peer link and this is not a peer link
@@ -510,7 +505,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        mgmt = (struct ieee80211_mgmt *)hdr;
-                       if (mgmt->u.action.category != PLINK_CATEGORY)
+                       if (mgmt->u.action.category != MESH_PLINK_CATEGORY)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -528,13 +523,249 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
-           mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
+           mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
                return RX_DROP_MONITOR;
 #undef msh_h_get
 
        return RX_CONTINUE;
 }
 
+#define SEQ_MODULO 0x1000
+#define SEQ_MASK   0xfff
+
+static inline int seq_less(u16 sq1, u16 sq2)
+{
+       return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
+}
+
+static inline u16 seq_inc(u16 sq)
+{
+       return (sq + 1) & SEQ_MASK;
+}
+
+static inline u16 seq_sub(u16 sq1, u16 sq2)
+{
+       return (sq1 - sq2) & SEQ_MASK;
+}
+
+
+static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
+                                           struct tid_ampdu_rx *tid_agg_rx,
+                                           int index,
+                                           struct sk_buff_head *frames)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_rate *rate = NULL;
+       struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
+       struct ieee80211_rx_status *status;
+
+       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];
+       tid_agg_rx->stored_mpdu_num--;
+       tid_agg_rx->reorder_buf[index] = NULL;
+       __skb_queue_tail(frames, skb);
+
+no_frame:
+       tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+}
+
+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)
+{
+       int index;
+
+       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);
+       }
+}
+
+/*
+ * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
+ * the skb was added to the buffer longer than this time ago, the earlier
+ * 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.
+ */
+#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
+
+/*
+ * As this function belongs to the RX path it must be under
+ * rcu_read_lock protection. It returns false if the frame
+ * can be processed immediately, true if it was consumed.
+ */
+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 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;
+
+       buf_size = tid_agg_rx->buf_size;
+       head_seq_num = tid_agg_rx->head_seq_num;
+
+       /* frame with out of date sequence number */
+       if (seq_less(mpdu_seq_num, head_seq_num)) {
+               dev_kfree_skb(skb);
+               return true;
+       }
+
+       /*
+        * If frame the sequence number exceeds our buffering window
+        * size release some previous frames to make room for this one.
+        */
+       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);
+       }
+
+       /* Now the new frame is always in the range of the reordering buffer */
+
+       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
+       /* check if we already stored this frame */
+       if (tid_agg_rx->reorder_buf[index]) {
+               dev_kfree_skb(skb);
+               return true;
+       }
+
+       /*
+        * 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 (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;
+       }
+
+       /* 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;
+       }
+
+       return true;
+}
+
+/*
+ * 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)
+{
+       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 sta_info *sta = rx->sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       u16 sc;
+       int tid;
+
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               goto dont_reorder;
+
+       /*
+        * filter the QoS data rx stream according to
+        * STA/TID and check if this STA/TID is on aggregation
+        */
+
+       if (!sta)
+               goto dont_reorder;
+
+       tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+
+       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
+               goto dont_reorder;
+
+       tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
+       /* qos null data frames are excluded */
+       if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
+               goto dont_reorder;
+
+       /* new, potentially un-ordered, ampdu frame - process it */
+
+       /* reset session timer */
+       if (tid_agg_rx->timeout)
+               mod_timer(&tid_agg_rx->session_timer,
+                         TU_TO_EXP_TIME(tid_agg_rx->timeout));
+
+       /* if this mpdu is fragmented - terminate rx aggregation session */
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       if (sc & IEEE80211_SCTL_FRAG) {
+               ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
+                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
+               return;
+
+ dont_reorder:
+       __skb_queue_tail(frames, skb);
+}
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
@@ -595,7 +826,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int keyidx;
        int hdrlen;
        ieee80211_rx_result result = RX_DROP_UNUSABLE;
@@ -629,15 +862,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
         * possible.
         */
 
-       if (!ieee80211_has_protected(hdr->frame_control)) {
-               if (!ieee80211_is_mgmt(hdr->frame_control) ||
-                   rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP))
-                       return RX_CONTINUE;
-               mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
-               if (mmie_keyidx < 0)
-                       return RX_CONTINUE;
-       }
-
        /*
         * No point in finding a key and decrypting if the frame is neither
         * addressed to us nor a multicast frame.
@@ -645,21 +869,45 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        if (!(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);
 
+       if (!ieee80211_has_protected(hdr->frame_control))
+               mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
+
        if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
                rx->key = stakey;
+               /* Skip decryption if the frame is not protected. */
+               if (!ieee80211_has_protected(hdr->frame_control))
+                       return RX_CONTINUE;
        } else if (mmie_keyidx >= 0) {
                /* Broadcast/multicast robust management frame / BIP */
-               if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-                   (rx->status->flag & RX_FLAG_IV_STRIPPED))
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
                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]);
+       } else if (!ieee80211_has_protected(hdr->frame_control)) {
+               /*
+                * The frame was not protected, so skip decryption. However, we
+                * need to set rx->key if there is a key that could have been
+                * used so that the frame may be dropped if encryption would
+                * have been expected.
+                */
+               struct ieee80211_key *key = NULL;
+               if (ieee80211_is_mgmt(hdr->frame_control) &&
+                   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;
+               return RX_CONTINUE;
        } else {
                /*
                 * The device doesn't give us the IV so we won't be
@@ -670,8 +918,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * we somehow allow the driver to tell us which key
                 * the hardware used if this flag is set?
                 */
-               if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-                   (rx->status->flag & RX_FLAG_IV_STRIPPED))
+               if ((status->flag & RX_FLAG_DECRYPTED) &&
+                   (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
                hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -707,8 +955,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        /* Check for weak IVs if possible */
        if (rx->sta && rx->key->conf.alg == ALG_WEP &&
            ieee80211_is_data(hdr->frame_control) &&
-           (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
-            !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
+           (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+            !(status->flag & RX_FLAG_DECRYPTED)) &&
            ieee80211_wep_is_weak_iv(rx->skb, rx->key))
                rx->sta->wep_weak_iv_count++;
 
@@ -728,7 +976,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        }
 
        /* either the frame has been decrypted or will be dropped */
-       rx->status->flag |= RX_FLAG_DECRYPTED;
+       status->flag |= RX_FLAG_DECRYPTED;
 
        return result;
 }
@@ -772,90 +1020,65 @@ static void ap_sta_ps_start(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
 
        atomic_inc(&sdata->bss->num_sta_ps);
-       set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
-       if (local->ops->sta_notify)
-               local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-                                       STA_NOTIFY_SLEEP, &sta->sta);
+       set_sta_flags(sta, WLAN_STA_PS_STA);
+       drv_sta_notify(local, &sdata->vif, 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->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 }
 
-static int ap_sta_ps_end(struct sta_info *sta)
+static void ap_sta_ps_end(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb;
-       int sent = 0;
 
        atomic_dec(&sdata->bss->num_sta_ps);
 
-       clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
-       if (local->ops->sta_notify)
-               local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-                                       STA_NOTIFY_AWAKE, &sta->sta);
-
-       if (!skb_queue_empty(&sta->ps_tx_buf))
-               sta_info_clear_tim_bit(sta);
+       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->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
-       /* Send all buffered frames to the station */
-       while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               sent++;
-               skb->requeue = 1;
-               dev_queue_xmit(skb);
-       }
-       while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               local->total_ps_buffered--;
-               sent++;
+       if (test_sta_flags(sta, WLAN_STA_PS_DRIVER)) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame "
-                      "since STA not sleeping anymore\n", sdata->dev->name,
-                      sta->sta.addr, sta->sta.aid);
+               printk(KERN_DEBUG "%s: STA %pM aid %d driver-ps-blocked\n",
+                      sdata->dev->name, sta->sta.addr, sta->sta.aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               skb->requeue = 1;
-               dev_queue_xmit(skb);
+               return;
        }
 
-       return sent;
+       ieee80211_sta_ps_deliver_wakeup(sta);
 }
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
        struct sta_info *sta = rx->sta;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
        if (!sta)
                return RX_CONTINUE;
 
-       /* Update last_rx only for IBSS packets which are for the current
-        * BSSID to avoid keeping the current IBSS network alive in cases where
-        * other STAs are using different BSSID. */
+       /*
+        * Update last_rx only for IBSS packets which are for the current
+        * BSSID to avoid keeping the current IBSS network alive in cases
+        * where other STAs start using different BSSID.
+        */
        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)
                        sta->last_rx = jiffies;
-       } else
-       if (!is_multicast_ether_addr(hdr->addr1) ||
-           rx->sdata->vif.type == NL80211_IFTYPE_STATION) {
-               /* Update last_rx only for unicast frames in order to prevent
-                * the Probe Request frames (the only broadcast frames from a
-                * STA in infrastructure mode) from keeping a connection alive.
+       } 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.
                 */
-               if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
-                   ieee80211_is_beacon(hdr->frame_control)) {
-                       rx->sdata->u.mgd.last_beacon = jiffies;
-               } else
-                       sta->last_rx = jiffies;
+               sta->last_rx = jiffies;
        }
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -866,9 +1089,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
-       sta->last_signal = rx->status->signal;
-       sta->last_qual = rx->status->qual;
-       sta->last_noise = rx->status->noise;
+       sta->last_signal = status->signal;
+       sta->last_noise = status->noise;
 
        /*
         * Change STA power saving mode only at the end of a frame
@@ -877,7 +1099,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (!ieee80211_has_morefrags(hdr->frame_control) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
             rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-               if (test_sta_flags(sta, WLAN_STA_PS)) {
+               if (test_sta_flags(sta, WLAN_STA_PS_STA)) {
                        /*
                         * Ignore doze->wake transitions that are
                         * indicated by non-data frames, the standard
@@ -888,19 +1110,24 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                         */
                        if (ieee80211_is_data(hdr->frame_control) &&
                            !ieee80211_has_pm(hdr->frame_control))
-                               rx->sent_ps_buffered += ap_sta_ps_end(sta);
+                               ap_sta_ps_end(sta);
                } else {
                        if (ieee80211_has_pm(hdr->frame_control))
                                ap_sta_ps_start(sta);
                }
        }
 
-       /* Drop data::nullfunc frames silently, since they are used only to
-        * control station power saving mode. */
-       if (ieee80211_is_nullfunc(hdr->frame_control)) {
+       /*
+        * Drop (qos-)data::nullfunc frames silently, since they
+        * are used only to control station power saving mode.
+        */
+       if (ieee80211_is_nullfunc(hdr->frame_control) ||
+           ieee80211_is_qos_nullfunc(hdr->frame_control)) {
                I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
-               /* Update counter and free packet here to avoid counting this
-                * as a dropped packed. */
+               /*
+                * Update counter and free packet here to avoid
+                * counting this as a dropped packed.
+                */
                sta->rx_packets++;
                dev_kfree_skb(rx->skb);
                return RX_QUEUED;
@@ -1100,9 +1327,7 @@ 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 = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       struct sk_buff *skb;
-       int no_pending_pkts;
+       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) ||
@@ -1113,56 +1338,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
            (sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
                return RX_DROP_UNUSABLE;
 
-       skb = skb_dequeue(&rx->sta->tx_filtered);
-       if (!skb) {
-               skb = skb_dequeue(&rx->sta->ps_tx_buf);
-               if (skb)
-                       rx->local->total_ps_buffered--;
-       }
-       no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
-               skb_queue_empty(&rx->sta->ps_tx_buf);
-
-       if (skb) {
-               struct ieee80211_hdr *hdr =
-                       (struct ieee80211_hdr *) skb->data;
-
-               /*
-                * Tell TX path to send one frame even though the STA may
-                * still remain is PS mode after this frame exchange.
-                */
+       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);
 
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n",
-                      rx->sta->sta.addr, rx->sta->sta.aid,
-                      skb_queue_len(&rx->sta->ps_tx_buf));
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
-               /* Use MoreData flag to indicate whether there are more
-                * buffered frames for this STA */
-               if (no_pending_pkts)
-                       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-               else
-                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-
-               dev_queue_xmit(skb);
-
-               if (no_pending_pkts)
-                       sta_info_clear_tim_bit(rx->sta);
-#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       } else if (!rx->sent_ps_buffered) {
-               /*
-                * FIXME: This can be the result of a race condition between
-                *        us expiring a frame and the station polling for it.
-                *        Should we send it a null-func frame indicating we
-                *        have nothing buffered for it?
-                */
-               printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
-                      "though there are no buffered frames for it\n",
-                      rx->dev->name, rx->sta->sta.addr);
-#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       }
-
        /* Free PS Poll skb here instead of returning RX_DROP that would
         * count as an dropped frame. */
        dev_kfree_skb(rx->skb);
@@ -1202,119 +1382,61 @@ ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 static int
 ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
        /*
         * Pass through unencrypted frames if the hardware has
         * decrypted them already.
         */
-       if (rx->status->flag & RX_FLAG_DECRYPTED)
+       if (status->flag & RX_FLAG_DECRYPTED)
                return 0;
 
        /* Drop unencrypted frames if key is set. */
        if (unlikely(!ieee80211_has_protected(fc) &&
                     !ieee80211_is_nullfunc(fc) &&
-                    (!ieee80211_is_mgmt(fc) ||
-                     (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
-                      rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) &&
-                    (rx->key || rx->sdata->drop_unencrypted)))
-               return -EACCES;
-       /* BIP does not use Protected field, so need to check MMIE */
-       if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) &&
-                    ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
-                    ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
+                    ieee80211_is_data(fc) &&
                     (rx->key || rx->sdata->drop_unencrypted)))
                return -EACCES;
+       if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+               if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
+                            rx->key))
+                       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 &&
+                            rx->key))
+                       return -EACCES;
+               /*
+                * When using MFP, Action frames are not allowed prior to
+                * having configured keys.
+                */
+               if (unlikely(ieee80211_is_action(fc) && !rx->key &&
+                            ieee80211_is_robust_mgmt_frame(
+                                    (struct ieee80211_hdr *) rx->skb->data)))
+                       return -EACCES;
+       }
 
        return 0;
 }
 
 static int
-ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
+__ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
-       u16 hdrlen, ethertype;
-       u8 *payload;
-       u8 dst[ETH_ALEN];
-       u8 src[ETH_ALEN] __aligned(2);
-       struct sk_buff *skb = rx->skb;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-       if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
                return -1;
 
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
-       /* convert IEEE 802.11 header + possible LLC headers into Ethernet
-        * header
-        * IEEE 802.11 address fields:
-        * ToDS FromDS Addr1 Addr2 Addr3 Addr4
-        *   0     0   DA    SA    BSSID n/a
-        *   0     1   DA    BSSID SA    n/a
-        *   1     0   BSSID SA    DA    n/a
-        *   1     1   RA    TA    DA    SA
-        */
-       memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
-       memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
-
-       switch (hdr->frame_control &
-               cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-       case cpu_to_le16(IEEE80211_FCTL_TODS):
-               if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP &&
-                            sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
-                       return -1;
-               break;
-       case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
-               if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
-                            sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
-                       return -1;
-               if (ieee80211_vif_is_mesh(&sdata->vif)) {
-                       struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
-                               (skb->data + hdrlen);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
-                       if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
-                               memcpy(dst, meshdr->eaddr1, ETH_ALEN);
-                               memcpy(src, meshdr->eaddr2, ETH_ALEN);
-                       }
-               }
-               break;
-       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
-               if (sdata->vif.type != NL80211_IFTYPE_STATION ||
-                   (is_multicast_ether_addr(dst) &&
-                    !compare_ether_addr(src, dev->dev_addr)))
-                       return -1;
-               break;
-       case cpu_to_le16(0):
-               if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
-                       return -1;
-               break;
-       }
-
-       if (unlikely(skb->len - hdrlen < 8))
+       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)))
                return -1;
 
-       payload = skb->data + hdrlen;
-       ethertype = (payload[6] << 8) | payload[7];
-
-       if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-                   ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                  compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
-               /* remove RFC1042 or Bridge-Tunnel encapsulation and
-                * replace EtherType */
-               skb_pull(skb, hdrlen + 6);
-               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-       } else {
-               struct ethhdr *ehdr;
-               __be16 len;
-
-               skb_pull(skb, hdrlen);
-               len = htons(skb->len);
-               ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-               memcpy(ehdr->h_dest, dst, ETH_ALEN);
-               memcpy(ehdr->h_source, src, ETH_ALEN);
-               ehdr->h_proto = len;
-       }
-       return 0;
+       return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
 }
 
 /*
@@ -1331,7 +1453,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
         * of whether the frame was encrypted or not.
         */
        if (ehdr->h_proto == htons(ETH_P_PAE) &&
-           (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+           (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
             compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
                return true;
 
@@ -1348,10 +1470,10 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
 static void
 ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
        struct ieee80211_local *local = rx->local;
        struct sk_buff *skb, *xmit_skb;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
        struct sta_info *dsta;
 
@@ -1361,7 +1483,8 @@ 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)) {
+           (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)) {
                        /*
                         * send multicast frames both to higher layers in
@@ -1397,17 +1520,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                 * mac80211. That also explains the __skb_push()
                 * below.
                 */
-               align = (unsigned long)skb->data & 3;
+               align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
                if (align) {
                        if (WARN_ON(skb_headroom(skb) < 3)) {
                                dev_kfree_skb(skb);
                                skb = NULL;
                        } else {
                                u8 *data = skb->data;
-                               size_t len = skb->len;
-                               u8 *new = __skb_push(skb, align);
-                               memmove(new, data, len);
-                               __skb_trim(skb, len);
+                               size_t len = skb_headlen(skb);
+                               skb->data -= align;
+                               memmove(skb->data, data, len);
+                               skb_set_tail_pointer(skb, len);
                        }
                }
 #endif
@@ -1432,7 +1555,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct net_device *dev = rx->sdata->dev;
        struct ieee80211_local *local = rx->local;
        u16 ethertype;
        u8 *payload;
@@ -1453,7 +1576,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        if (!(rx->flags & IEEE80211_RX_AMSDU))
                return RX_CONTINUE;
 
-       err = ieee80211_data_to_8023(rx);
+       err = __ieee80211_data_to_8023(rx);
        if (unlikely(err))
                return RX_DROP_UNUSABLE;
 
@@ -1556,6 +1679,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211s_hdr *mesh_hdr;
        unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -1568,26 +1693,35 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                /* illegal frame */
                return RX_DROP_MONITOR;
 
-       if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-               struct ieee80211_sub_if_data *sdata;
+       if (mesh_hdr->flags & MESH_FLAGS_AE) {
                struct mesh_path *mppath;
+               char *proxied_addr;
+               char *mpp_addr;
+
+               if (is_multicast_ether_addr(hdr->addr1)) {
+                       mpp_addr = hdr->addr3;
+                       proxied_addr = mesh_hdr->eaddr1;
+               } else {
+                       mpp_addr = hdr->addr4;
+                       proxied_addr = mesh_hdr->eaddr2;
+               }
 
-               sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
                rcu_read_lock();
-               mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
+               mppath = mpp_path_lookup(proxied_addr, sdata);
                if (!mppath) {
-                       mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
+                       mpp_path_add(proxied_addr, mpp_addr, sdata);
                } else {
                        spin_lock_bh(&mppath->state_lock);
-                       mppath->exp_time = jiffies;
-                       if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
-                               memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
+                       if (compare_ether_addr(mppath->mpp, mpp_addr) != 0)
+                               memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
                        spin_unlock_bh(&mppath->state_lock);
                }
                rcu_read_unlock();
        }
 
-       if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+       /* Frame has reached destination.  Don't forward */
+       if (!is_multicast_ether_addr(hdr->addr1) &&
+           compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
        mesh_hdr->ttl--;
@@ -1598,27 +1732,52 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                                                     dropped_frames_ttl);
                else {
                        struct ieee80211_hdr *fwd_hdr;
+                       struct ieee80211_tx_info *info;
+
                        fwd_skb = skb_copy(skb, GFP_ATOMIC);
 
                        if (!fwd_skb && net_ratelimit())
                                printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-                                                  rx->dev->name);
+                                                  sdata->dev->name);
 
                        fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-                       /*
-                        * Save TA to addr1 to send TA a path error if a
-                        * suitable next hop is not found
-                        */
-                       memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
-                       memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
-                       fwd_skb->dev = rx->local->mdev;
-                       fwd_skb->iif = rx->dev->ifindex;
-                       dev_queue_xmit(fwd_skb);
+                       memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
+                       info = IEEE80211_SKB_CB(fwd_skb);
+                       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))
+                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                               fwded_mcast);
+                       else {
+                               int err;
+                               /*
+                                * Save TA to addr1 to send TA a path error if a
+                                * suitable next hop is not found
+                                */
+                               memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
+                                               ETH_ALEN);
+                               err = mesh_nexthop_lookup(fwd_skb, sdata);
+                               /* Failed to immediately resolve next hop:
+                                * fwded frame was dropped or will be added
+                                * later to the pending skb queue.  */
+                               if (err)
+                                       return RX_DROP_MONITOR;
+
+                               IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                               fwded_unicast);
+                       }
+                       IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+                                                    fwded_frames);
+                       ieee80211_add_pending_skb(local, fwd_skb);
                }
        }
 
-       if (is_multicast_ether_addr(hdr->addr3) ||
-           rx->dev->flags & IFF_PROMISC)
+       if (is_multicast_ether_addr(hdr->addr1) ||
+           sdata->dev->flags & IFF_PROMISC)
                return RX_CONTINUE;
        else
                return RX_DROP_MONITOR;
@@ -1628,7 +1787,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
-       struct net_device *dev = rx->dev;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        __le16 fc = hdr->frame_control;
        int err;
@@ -1639,7 +1799,15 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
                return RX_DROP_MONITOR;
 
-       err = ieee80211_data_to_8023(rx);
+       /*
+        * 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
+        */
+       if (ieee80211_has_a4(hdr->frame_control) &&
+           sdata->vif.type == NL80211_IFTYPE_AP)
+               return RX_DROP_MONITOR;
+
+       err = __ieee80211_data_to_8023(rx);
        if (unlikely(err))
                return RX_DROP_UNUSABLE;
 
@@ -1657,7 +1825,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)
+ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
@@ -1672,11 +1840,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 
        if (ieee80211_is_back_req(bar->frame_control)) {
                if (!rx->sta)
-                       return RX_CONTINUE;
+                       return RX_DROP_MONITOR;
                tid = le16_to_cpu(bar->control) >> 12;
                if (rx->sta->ampdu_mlme.tid_state_rx[tid]
                                        != HT_AGG_STATE_OPERATIONAL)
-                       return RX_CONTINUE;
+                       return RX_DROP_MONITOR;
                tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
                start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
@@ -1686,13 +1854,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
                        mod_timer(&tid_agg_rx->session_timer,
                                  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
-               /* manage reordering buffer according to requested */
-               /* sequence number */
-               rcu_read_lock();
-               ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL,
-                                                start_seq_num, 1);
-               rcu_read_unlock();
-               return RX_DROP_UNUSABLE;
+               /* release stored frames up to start of BAR */
+               ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
+                                                frames);
+               kfree_skb(skb);
+               return RX_QUEUED;
        }
 
        return RX_CONTINUE;
@@ -1713,12 +1879,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
 
        if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
            compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
-               /* Not from the current AP. */
-               return;
-       }
-
-       if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
-               /* Association in progress; ignore SA Query */
+               /* Not from the current AP or not associated yet. */
                return;
        }
 
@@ -1746,16 +1907,15 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
               mgmt->u.action.u.sa_query.trans_id,
               WLAN_SA_QUERY_TR_ID_LEN);
 
-       ieee80211_tx_skb(sdata, skb, 1);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 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 = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
-       struct ieee80211_bss *bss;
        int len = rx->skb->len;
 
        if (!ieee80211_is_action(mgmt->frame_control))
@@ -1827,20 +1987,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                   sizeof(mgmt->u.action.u.chan_switch)))
                                return RX_DROP_MONITOR;
 
-                       if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
+                       if (sdata->vif.type != NL80211_IFTYPE_STATION)
                                return RX_DROP_MONITOR;
 
-                       bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
-                                          local->hw.conf.channel->center_freq,
-                                          sdata->u.mgd.ssid,
-                                          sdata->u.mgd.ssid_len);
-                       if (!bss)
+                       if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
                                return RX_DROP_MONITOR;
 
-                       ieee80211_process_chanswitch(sdata,
-                                    &mgmt->u.action.u.chan_switch.sw_elem, bss);
-                       ieee80211_rx_bss_put(local, bss);
-                       break;
+                       return ieee80211_sta_rx_mgmt(sdata, rx->skb);
                }
                break;
        case WLAN_CATEGORY_SA_QUERY:
@@ -1862,6 +2015,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                }
                break;
        default:
+               /* do not process rejected action frames */
+               if (mgmt->u.action.category & 0x80)
+                       return RX_DROP_MONITOR;
+
                return RX_CONTINUE;
        }
 
@@ -1873,7 +2030,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
 
        if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1883,19 +2040,18 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        if (ieee80211_vif_is_mesh(&sdata->vif))
-               return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
 
        if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-               return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_ibss_rx_mgmt(sdata, rx->skb);
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION)
-               return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
+               return ieee80211_sta_rx_mgmt(sdata, rx->skb);
 
        return RX_DROP_MONITOR;
 }
 
-static void ieee80211_rx_michael_mic_report(struct net_device *dev,
-                                           struct ieee80211_hdr *hdr,
+static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
                                            struct ieee80211_rx_data *rx)
 {
        int keyidx;
@@ -1912,11 +2068,11 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                 * Some hardware seem to generate incorrect Michael MIC
                 * reports; ignore them to avoid triggering countermeasures.
                 */
-               goto ignore;
+               return;
        }
 
        if (!ieee80211_has_protected(hdr->frame_control))
-               goto ignore;
+               return;
 
        if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
                /*
@@ -1925,36 +2081,35 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
                 * group keys and only the AP is sending real multicast
                 * frames in the BSS.
                 */
-               goto ignore;
+               return;
        }
 
        if (!ieee80211_is_data(hdr->frame_control) &&
            !ieee80211_is_auth(hdr->frame_control))
-               goto ignore;
+               return;
 
-       mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL);
- ignore:
-       dev_kfree_skb(rx->skb);
-       rx->skb = NULL;
+       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)
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
+                                       struct ieee80211_rate *rate)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_rtap_hdr {
                struct ieee80211_radiotap_header hdr;
                u8 flags;
-               u8 rate;
+               u8 rate_or_pad;
                __le16 chan_freq;
                __le16 chan_flags;
        } __attribute__ ((packed)) *rthdr;
        struct sk_buff *skb = rx->skb, *skb2;
        struct net_device *prev_dev = NULL;
-       struct ieee80211_rx_status *status = rx->status;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
-       if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
+       if (status->flag & RX_FLAG_INTERNAL_CMTR)
                goto out_free_skb;
 
        if (skb_headroom(skb) < sizeof(*rthdr) &&
@@ -1966,10 +2121,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
        rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
        rthdr->hdr.it_present =
                cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_RATE) |
                            (1 << IEEE80211_RADIOTAP_CHANNEL));
 
-       rthdr->rate = rx->rate->bitrate / 5;
+       if (rate) {
+               rthdr->rate_or_pad = rate->bitrate / 5;
+               rthdr->hdr.it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
+       }
        rthdr->chan_freq = cpu_to_le16(status->freq);
 
        if (status->band == IEEE80211_BAND_5GHZ)
@@ -2012,7 +2170,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
        } else
                goto out_free_skb;
 
-       rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
+       status->flag |= RX_FLAG_INTERNAL_CMTR;
        return;
 
  out_free_skb:
@@ -2022,62 +2180,87 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
 
 static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
                                         struct ieee80211_rx_data *rx,
-                                        struct sk_buff *skb)
+                                        struct sk_buff *skb,
+                                        struct ieee80211_rate *rate)
 {
+       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;
-       rx->dev = sdata->dev;
 
 #define CALL_RXH(rxh)                  \
        do {                            \
                res = rxh(rx);          \
                if (res != RX_CONTINUE) \
-                       goto rxh_done;  \
+                       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)
-       CALL_RXH(ieee80211_rx_h_decrypt)
-       CALL_RXH(ieee80211_rx_h_check_more_data)
-       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)
+
+       ieee80211_rx_reorder_ampdu(rx, &reorder_release);
+
+       while ((skb = __skb_dequeue(&reorder_release))) {
+               /*
+                * all the other fields are valid across frames
+                * that belong to an aMPDU since they are on the
+                * same TID from the same station
+                */
+               rx->skb = skb;
+
+               CALL_RXH(ieee80211_rx_h_decrypt)
+               CALL_RXH(ieee80211_rx_h_check_more_data)
+               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))
-               CALL_RXH(ieee80211_rx_h_mesh_fwding);
+               if (ieee80211_vif_is_mesh(&sdata->vif))
+                       CALL_RXH(ieee80211_rx_h_mesh_fwding);
 #endif
-       CALL_RXH(ieee80211_rx_h_data)
-       CALL_RXH(ieee80211_rx_h_ctrl)
-       CALL_RXH(ieee80211_rx_h_action)
-       CALL_RXH(ieee80211_rx_h_mgmt)
+               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_action)
+               CALL_RXH(ieee80211_rx_h_mgmt)
 
 #undef CALL_RXH
 
- rxh_done:
-       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);
-               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;
+ 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;
+               }
        }
 }
 
@@ -2087,20 +2270,17 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                                struct ieee80211_rx_data *rx,
                                struct ieee80211_hdr *hdr)
 {
-       u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
+       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);
        int multicast = is_multicast_ether_addr(hdr->addr1);
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
-               if (!bssid)
+               if (!bssid && !sdata->u.mgd.use_4addr)
                        return 0;
-               if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
-                       if (!(rx->flags & IEEE80211_RX_IN_SCAN))
-                               return 0;
-                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
-               } else if (!multicast &&
-                          compare_ether_addr(sdata->dev->dev_addr,
-                                             hdr->addr1) != 0) {
+               if (!multicast &&
+                   compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
                        if (!(sdata->dev->flags & IFF_PROMISC))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2124,10 +2304,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta) {
                        int rate_idx;
-                       if (rx->status->flag & RX_FLAG_HT)
+                       if (status->flag & RX_FLAG_HT)
                                rate_idx = 0; /* TODO: HT rates */
                        else
-                               rate_idx = rx->status->rate_idx;
+                               rate_idx = status->rate_idx;
                        rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
                                BIT(rate_idx));
                }
@@ -2162,8 +2342,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                        return 0;
                break;
        case NL80211_IFTYPE_MONITOR:
-               /* take everything */
-               break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case __NL80211_IFTYPE_AFTER_LAST:
                /* should never get here */
@@ -2180,9 +2358,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                         struct sk_buff *skb,
-                                        struct ieee80211_rx_status *status,
                                         struct ieee80211_rate *rate)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr;
@@ -2196,36 +2374,36 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        rx.skb = skb;
        rx.local = local;
 
-       rx.status = status;
-       rx.rate = rate;
-
        if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
                local->dot11ReceivedFragmentCount++;
 
-       rx.sta = sta_info_get(local, hdr->addr2);
-       if (rx.sta) {
-               rx.sdata = rx.sta->sdata;
-               rx.dev = rx.sta->sdata->dev;
-       }
-
-       if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-               ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
-               return;
-       }
-
-       if (unlikely(local->sw_scanning || local->hw_scanning))
+       if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+                    test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
                rx.flags |= IEEE80211_RX_IN_SCAN;
 
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       skb = rx.skb;
+       rx.sta = sta_info_get(local, hdr->addr2);
+       if (rx.sta)
+               rx.sdata = rx.sta->sdata;
 
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+       if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
+               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;
+               }
+       } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
                        continue;
 
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        continue;
 
                rx.flags |= IEEE80211_RX_RA_MATCH;
@@ -2234,6 +2412,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                if (!prepares)
                        continue;
 
+               if (status->flag & RX_FLAG_MMIC_ERROR) {
+                       rx.sdata = sdata;
+                       if (rx.flags & IEEE80211_RX_RA_MATCH)
+                               ieee80211_rx_michael_mic_report(hdr, &rx);
+                       continue;
+               }
+
                /*
                 * frame is destined for this interface, but if it's not
                 * also for the previous one we handle that after the
@@ -2259,242 +2444,74 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                       prev->dev->name);
                        continue;
                }
-               ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
                prev = sdata;
        }
        if (prev)
-               ieee80211_invoke_rx_handlers(prev, &rx, skb);
+               ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
        else
                dev_kfree_skb(skb);
 }
 
-#define SEQ_MODULO 0x1000
-#define SEQ_MASK   0xfff
-
-static inline int seq_less(u16 sq1, u16 sq2)
-{
-       return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
-}
-
-static inline u16 seq_inc(u16 sq)
-{
-       return (sq + 1) & SEQ_MASK;
-}
-
-static inline u16 seq_sub(u16 sq1, u16 sq2)
-{
-       return (sq1 - sq2) & SEQ_MASK;
-}
-
-
-/*
- * As it function blongs to Rx path it must be called with
- * the proper rcu_read_lock protection for its flow.
- */
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-                                          struct tid_ampdu_rx *tid_agg_rx,
-                                          struct sk_buff *skb,
-                                          struct ieee80211_rx_status *rxstatus,
-                                          u16 mpdu_seq_num,
-                                          int bar_req)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_rx_status status;
-       u16 head_seq_num, buf_size;
-       int index;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *rate;
-
-       buf_size = tid_agg_rx->buf_size;
-       head_seq_num = tid_agg_rx->head_seq_num;
-
-       /* frame with out of date sequence number */
-       if (seq_less(mpdu_seq_num, head_seq_num)) {
-               dev_kfree_skb(skb);
-               return 1;
-       }
-
-       /* if frame sequence number exceeds our buffering window size or
-        * block Ack Request arrived - release stored frames */
-       if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
-               /* new head to the ordering buffer */
-               if (bar_req)
-                       head_seq_num = mpdu_seq_num;
-               else
-                       head_seq_num =
-                               seq_inc(seq_sub(mpdu_seq_num, buf_size));
-               /* release stored frames up to new head to stack */
-               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;
-
-                       if (tid_agg_rx->reorder_buf[index]) {
-                               /* release the reordered frames to stack */
-                               memcpy(&status,
-                                       tid_agg_rx->reorder_buf[index]->cb,
-                                       sizeof(status));
-                               sband = local->hw.wiphy->bands[status.band];
-                               if (status.flag & RX_FLAG_HT) {
-                                       /* TODO: HT rates */
-                                       rate = sband->bitrates;
-                               } else {
-                                       rate = &sband->bitrates
-                                               [status.rate_idx];
-                               }
-                               __ieee80211_rx_handle_packet(hw,
-                                       tid_agg_rx->reorder_buf[index],
-                                       &status, rate);
-                               tid_agg_rx->stored_mpdu_num--;
-                               tid_agg_rx->reorder_buf[index] = NULL;
-                       }
-                       tid_agg_rx->head_seq_num =
-                               seq_inc(tid_agg_rx->head_seq_num);
-               }
-               if (bar_req)
-                       return 1;
-       }
-
-       /* now the new frame is always in the range of the reordering */
-       /* buffer window */
-       index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
-                               % tid_agg_rx->buf_size;
-       /* check if we already stored this frame */
-       if (tid_agg_rx->reorder_buf[index]) {
-               dev_kfree_skb(skb);
-               return 1;
-       }
-
-       /* if arrived mpdu is in the right order and nothing else stored */
-       /* release it immediately */
-       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 0;
-       }
-
-       /* put the frame in the reordering buffer */
-       tid_agg_rx->reorder_buf[index] = skb;
-       memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
-              sizeof(*rxstatus));
-       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;
-       while (tid_agg_rx->reorder_buf[index]) {
-               /* release the reordered frame back to stack */
-               memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
-                       sizeof(status));
-               sband = local->hw.wiphy->bands[status.band];
-               if (status.flag & RX_FLAG_HT)
-                       rate = sband->bitrates; /* TODO: HT rates */
-               else
-                       rate = &sband->bitrates[status.rate_idx];
-               __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
-                                            &status, rate);
-               tid_agg_rx->stored_mpdu_num--;
-               tid_agg_rx->reorder_buf[index] = NULL;
-               tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
-               index = seq_sub(tid_agg_rx->head_seq_num,
-                       tid_agg_rx->ssn) % tid_agg_rx->buf_size;
-       }
-       return 1;
-}
-
-static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-                                    struct sk_buff *skb,
-                                    struct ieee80211_rx_status *status)
-{
-       struct ieee80211_hw *hw = &local->hw;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct sta_info *sta;
-       struct tid_ampdu_rx *tid_agg_rx;
-       u16 sc;
-       u16 mpdu_seq_num;
-       u8 ret = 0;
-       int tid;
-
-       sta = sta_info_get(local, hdr->addr2);
-       if (!sta)
-               return ret;
-
-       /* filter the QoS data rx stream according to
-        * STA/TID and check if this STA/TID is on aggregation */
-       if (!ieee80211_is_data_qos(hdr->frame_control))
-               goto end_reorder;
-
-       tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
-
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
-               goto end_reorder;
-
-       tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
-
-       /* qos null data frames are excluded */
-       if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-               goto end_reorder;
-
-       /* new un-ordered ampdu frame - process it */
-
-       /* reset session timer */
-       if (tid_agg_rx->timeout)
-               mod_timer(&tid_agg_rx->session_timer,
-                         TU_TO_EXP_TIME(tid_agg_rx->timeout));
-
-       /* if this mpdu is fragmented - terminate rx aggregation session */
-       sc = le16_to_cpu(hdr->seq_ctrl);
-       if (sc & IEEE80211_SCTL_FRAG) {
-               ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
-               ret = 1;
-               goto end_reorder;
-       }
-
-       /* according to mpdu sequence number deal with reordering buffer */
-       mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-       ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status,
-                                               mpdu_seq_num, 0);
- end_reorder:
-       return ret;
-}
-
 /*
  * This is the receive path handler. It is called by a low level driver when an
  * 802.11 MPDU is received from the hardware.
  */
-void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ieee80211_rx_status *status)
+void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate = NULL;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
-       if (status->band < 0 ||
-           status->band >= IEEE80211_NUM_BANDS) {
-               WARN_ON(1);
-               return;
-       }
+       WARN_ON_ONCE(softirq_count() == 0);
+
+       if (WARN_ON(status->band < 0 ||
+                   status->band >= IEEE80211_NUM_BANDS))
+               goto drop;
 
        sband = local->hw.wiphy->bands[status->band];
-       if (!sband) {
-               WARN_ON(1);
-               return;
-       }
+       if (WARN_ON(!sband))
+               goto drop;
+
+       /*
+        * If we're suspending, it is possible although not too likely
+        * that we'd be receiving frames after having already partially
+        * quiesced the stack. We can't process such frames then since
+        * that might, for example, cause stations to be added or other
+        * driver callbacks be invoked.
+        */
+       if (unlikely(local->quiescing || local->suspended))
+               goto drop;
+
+       /*
+        * The same happens when we're not even started,
+        * but that's worth a warning.
+        */
+       if (WARN_ON(!local->started))
+               goto drop;
 
        if (status->flag & RX_FLAG_HT) {
-               /* rate_idx is MCS index */
-               if (WARN_ON(status->rate_idx < 0 ||
-                           status->rate_idx >= 76))
-                       return;
-               /* HT rates are not in the table - use the highest legacy rate
-                * for now since other parts of mac80211 may not yet be fully
-                * MCS aware. */
-               rate = &sband->bitrates[sband->n_bitrates - 1];
+               /*
+                * 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))
-                       return;
+                       goto drop;
                rate = &sband->bitrates[status->rate_idx];
        }
 
@@ -2511,31 +2528,30 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
         * if it was previously present.
         * Also, frames with less than 16 bytes are dropped.
         */
-       skb = ieee80211_rx_monitor(local, skb, status, rate);
+       skb = ieee80211_rx_monitor(local, skb, rate);
        if (!skb) {
                rcu_read_unlock();
                return;
        }
 
-       if (!ieee80211_rx_reorder_ampdu(local, skb, status))
-               __ieee80211_rx_handle_packet(hw, skb, status, rate);
+       __ieee80211_rx_handle_packet(hw, skb, rate);
 
        rcu_read_unlock();
+
+       return;
+ drop:
+       kfree_skb(skb);
 }
-EXPORT_SYMBOL(__ieee80211_rx);
+EXPORT_SYMBOL(ieee80211_rx);
 
 /* This is a version of the rx handler that can be called from hard irq
  * context. Post the skb on the queue and schedule the tasklet */
-void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
-                         struct ieee80211_rx_status *status)
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
        BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
 
-       skb->dev = local->mdev;
-       /* copy status into skb->cb for use by tasklet */
-       memcpy(skb->cb, status, sizeof(*status));
        skb->pkt_type = IEEE80211_RX_MSG;
        skb_queue_tail(&local->skb_queue, skb);
        tasklet_schedule(&local->tasklet);