mac80211: allow software PS-Poll/U-APSD with AP_LINK_PS
[cascardo/linux.git] / net / mac80211 / rx.c
index bc08185..5e65e83 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/rcupdate.h>
 #include <linux/export.h>
+#include <linux/bitops.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <asm/unaligned.h>
@@ -122,7 +124,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
        hdr = (void *)(skb->data + rtap_vendor_space);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
-                           RX_FLAG_FAILED_PLCP_CRC))
+                           RX_FLAG_FAILED_PLCP_CRC |
+                           RX_FLAG_ONLY_MONITOR))
                return true;
 
        if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
@@ -319,7 +322,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        else if (status->flag & RX_FLAG_5MHZ)
                channel_flags |= IEEE80211_CHAN_QUARTER;
 
-       if (status->band == IEEE80211_BAND_5GHZ)
+       if (status->band == NL80211_BAND_5GHZ)
                channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
        else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
                channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
@@ -507,7 +510,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                return NULL;
        }
 
-       if (!local->monitors) {
+       if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
                if (should_drop_frame(origskb, present_fcs_len,
                                      rtap_vendor_space)) {
                        dev_kfree_skb(origskb);
@@ -719,8 +722,8 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return -1;
 }
 
-static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
-                                struct sk_buff *skb)
+static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
+                                 struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc;
@@ -797,6 +800,26 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
+static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
+                                             int index)
+{
+       struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
+       struct sk_buff *tail = skb_peek_tail(frames);
+       struct ieee80211_rx_status *status;
+
+       if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
+               return true;
+
+       if (!tail)
+               return false;
+
+       status = IEEE80211_SKB_RXCB(tail);
+       if (status->flag & RX_FLAG_AMSDU_MORE)
+               return false;
+
+       return true;
+}
+
 static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
                                            struct tid_ampdu_rx *tid_agg_rx,
                                            int index,
@@ -811,7 +834,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
        if (skb_queue_empty(skb_list))
                goto no_frame;
 
-       if (!ieee80211_rx_reorder_ready(skb_list)) {
+       if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                __skb_queue_purge(skb_list);
                goto no_frame;
        }
@@ -825,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
        }
 
 no_frame:
+       tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
        tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
 }
 
@@ -865,7 +889,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
        /* release the buffer until next missing frame */
        index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
-       if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) &&
+       if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
            tid_agg_rx->stored_mpdu_num) {
                /*
                 * No buffers ready to be released, but check whether any
@@ -874,8 +898,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                int skipped = 1;
                for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
                     j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (!ieee80211_rx_reorder_ready(
-                                       &tid_agg_rx->reorder_buf[j])) {
+                       if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
                                skipped++;
                                continue;
                        }
@@ -902,8 +925,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                                 skipped) & IEEE80211_SN_MASK;
                        skipped = 0;
                }
-       } else while (ieee80211_rx_reorder_ready(
-                               &tid_agg_rx->reorder_buf[index])) {
+       } else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
                index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
@@ -914,8 +936,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
                for (; j != (index - 1) % tid_agg_rx->buf_size;
                     j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (ieee80211_rx_reorder_ready(
-                                       &tid_agg_rx->reorder_buf[j]))
+                       if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
                                break;
                }
 
@@ -986,7 +1007,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
        index = mpdu_seq_num % tid_agg_rx->buf_size;
 
        /* check if we already stored this frame */
-       if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) {
+       if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                dev_kfree_skb(skb);
                goto out;
        }
@@ -1099,6 +1120,9 @@ ieee80211_rx_h_check_dup(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);
 
+       if (status->flag & RX_FLAG_DUP_VALIDATED)
+               return RX_CONTINUE;
+
        /*
         * Drop duplicate 802.11 retransmissions
         * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
@@ -1295,13 +1319,52 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
 }
 EXPORT_SYMBOL(ieee80211_sta_ps_transition);
 
+void ieee80211_sta_pspoll(struct ieee80211_sta *pubsta)
+{
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+       if (test_sta_flag(sta, WLAN_STA_SP))
+               return;
+
+       if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
+               ieee80211_sta_ps_deliver_poll_response(sta);
+       else
+               set_sta_flag(sta, WLAN_STA_PSPOLL);
+}
+EXPORT_SYMBOL(ieee80211_sta_pspoll);
+
+void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
+{
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+       u8 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 (!(sta->sta.uapsd_queues & BIT(ac)))
+               return;
+
+       /* if we are in a service period, do nothing */
+       if (test_sta_flag(sta, WLAN_STA_SP))
+               return;
+
+       if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
+               ieee80211_sta_ps_deliver_uapsd(sta);
+       else
+               set_sta_flag(sta, WLAN_STA_UAPSD);
+}
+EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
+
 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)
                return RX_CONTINUE;
@@ -1327,12 +1390,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
                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);
-               }
+               ieee80211_sta_pspoll(&rx->sta->sta);
 
                /* Free PS Poll skb here instead of returning RX_DROP that would
                 * count as an dropped frame. */
@@ -1344,27 +1402,11 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
                   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];
+               u8 tid;
 
-               /*
-                * 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;
+               tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
-               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);
+               ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
        }
 
        return RX_CONTINUE;
@@ -1397,16 +1439,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                    test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
                        sta->rx_stats.last_rx = jiffies;
                        if (ieee80211_is_data(hdr->frame_control) &&
-                           !is_multicast_ether_addr(hdr->addr1)) {
-                               sta->rx_stats.last_rate_idx =
-                                       status->rate_idx;
-                               sta->rx_stats.last_rate_flag =
-                                       status->flag;
-                               sta->rx_stats.last_rate_vht_flag =
-                                       status->vht_flag;
-                               sta->rx_stats.last_rate_vht_nss =
-                                       status->vht_nss;
-                       }
+                           !is_multicast_ether_addr(hdr->addr1))
+                               sta->rx_stats.last_rate =
+                                       sta_stats_encode_rate(status);
                }
        } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
                sta->rx_stats.last_rx = jiffies;
@@ -1416,22 +1451,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                 * match the current local configuration when processed.
                 */
                sta->rx_stats.last_rx = jiffies;
-               if (ieee80211_is_data(hdr->frame_control)) {
-                       sta->rx_stats.last_rate_idx = status->rate_idx;
-                       sta->rx_stats.last_rate_flag = status->flag;
-                       sta->rx_stats.last_rate_vht_flag = status->vht_flag;
-                       sta->rx_stats.last_rate_vht_nss = status->vht_nss;
-               }
+               if (ieee80211_is_data(hdr->frame_control))
+                       sta->rx_stats.last_rate = sta_stats_encode_rate(status);
        }
 
        if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
                ieee80211_sta_rx_notify(rx->sdata, hdr);
 
        sta->rx_stats.fragments++;
+
+       u64_stats_update_begin(&rx->sta->rx_stats.syncp);
        sta->rx_stats.bytes += rx->skb->len;
+       u64_stats_update_end(&rx->sta->rx_stats.syncp);
+
        if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
                sta->rx_stats.last_signal = status->signal;
-               ewma_signal_add(&sta->rx_stats.avg_signal, -status->signal);
+               ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
        }
 
        if (status->chains) {
@@ -1443,7 +1478,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                                continue;
 
                        sta->rx_stats.chain_signal_last[i] = signal;
-                       ewma_signal_add(&sta->rx_stats.chain_signal_avg[i],
+                       ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
                                        -signal);
                }
        }
@@ -1562,7 +1597,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
                        cs = rx->sta->cipher_scheme;
-                       keyid = iwl80211_get_cs_keyid(cs, rx->skb);
+                       keyid = ieee80211_get_cs_keyid(cs, rx->skb);
                        if (unlikely(keyid < 0))
                                return RX_DROP_UNUSABLE;
                }
@@ -1646,7 +1681,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                hdrlen = ieee80211_hdrlen(fc);
 
                if (cs) {
-                       keyidx = iwl80211_get_cs_keyid(cs, rx->skb);
+                       keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
 
                        if (unlikely(keyidx < 0))
                                return RX_DROP_UNUSABLE;
@@ -1753,7 +1788,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
        entry->seq = seq;
        entry->rx_queue = rx_queue;
        entry->last_frag = frag;
-       entry->ccmp = 0;
+       entry->check_sequential_pn = false;
        entry->extra_len = 0;
 
        return entry;
@@ -1849,15 +1884,27 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                                                 rx->seqno_idx, &(rx->skb));
                if (rx->key &&
                    (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
-                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256) &&
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
                    ieee80211_has_protected(fc)) {
                        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;
+
+                       /* Store CCMP/GCMP PN so that we can verify that the
+                        * next fragment has a sequential PN value.
+                        */
+                       entry->check_sequential_pn = true;
                        memcpy(entry->last_pn,
                               rx->key->u.ccmp.rx_pn[queue],
                               IEEE80211_CCMP_PN_LEN);
+                       BUILD_BUG_ON(offsetof(struct ieee80211_key,
+                                             u.ccmp.rx_pn) !=
+                                    offsetof(struct ieee80211_key,
+                                             u.gcmp.rx_pn));
+                       BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
+                                    sizeof(rx->key->u.gcmp.rx_pn[queue]));
+                       BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
+                                    IEEE80211_GCMP_PN_LEN);
                }
                return RX_QUEUED;
        }
@@ -1872,15 +1919,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
        }
 
-       /* Verify that MPDUs within one MSDU have sequential PN values.
-        * (IEEE 802.11i, 8.3.3.4.5) */
-       if (entry->ccmp) {
+       /* "The receiver shall discard MSDUs and MMPDUs whose constituent
+        *  MPDU PN values are not incrementing in steps of 1."
+        * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
+        * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
+        */
+       if (entry->check_sequential_pn) {
                int i;
                u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
                int queue;
+
                if (!rx->key ||
                    (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP &&
-                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256))
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP &&
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256))
                        return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
                for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -2087,6 +2140,17 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 
        ieee80211_rx_stats(dev, skb->len);
 
+       if (rx->sta) {
+               /* The seqno index has the same property as needed
+                * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+                * for non-QoS-data frames. Here we know it's a data
+                * frame, so count MSDUs.
+                */
+               u64_stats_update_begin(&rx->sta->rx_stats.syncp);
+               rx->sta->rx_stats.msdu[rx->seqno_idx]++;
+               u64_stats_update_end(&rx->sta->rx_stats.syncp);
+       }
+
        if ((sdata->vif.type == NL80211_IFTYPE_AP ||
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
            !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
@@ -2199,9 +2263,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
-       if (skb_linearize(skb))
-               return RX_DROP_UNUSABLE;
-
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
                                 rx->local->hw.extra_tx_headroom, true);
@@ -2231,7 +2292,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       u16 q, hdrlen;
+       u16 ac, q, hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -2290,6 +2351,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        spin_lock_bh(&mppath->state_lock);
                        if (!ether_addr_equal(mppath->mpp, mpp_addr))
                                memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
+                       mppath->exp_time = jiffies;
                        spin_unlock_bh(&mppath->state_lock);
                }
                rcu_read_unlock();
@@ -2300,7 +2362,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            ether_addr_equal(sdata->vif.addr, hdr->addr3))
                return RX_CONTINUE;
 
-       q = ieee80211_select_queue_80211(sdata, skb, hdr);
+       ac = ieee80211_select_queue_80211(sdata, skb, hdr);
+       q = sdata->vif.hw_queue[ac];
        if (ieee80211_queue_stopped(&local->hw, q)) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
                return RX_DROP_MONITOR;
@@ -2374,15 +2437,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
                return RX_DROP_MONITOR;
 
-       if (rx->sta) {
-               /* The seqno index has the same property as needed
-                * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
-                * for non-QoS-data frames. Here we know it's a data
-                * frame, so count MSDUs.
-                */
-               rx->sta->rx_stats.msdu[rx->seqno_idx]++;
-       }
-
        /*
         * Send unexpected-4addr-frame event to hostapd. For older versions,
         * also drop the frame to cooked monitor interfaces.
@@ -2433,14 +2487,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 
        rx->skb->dev = dev;
 
-       if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
+       if (!ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS) &&
+           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));
-       }
+            !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)))
+               mod_timer(&local->dynamic_ps_timer, jiffies +
+                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 
        ieee80211_deliver_skb(rx);
 
@@ -2738,6 +2792,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                                    opmode, status->band);
                        goto handled;
                }
+               case WLAN_VHT_ACTION_GROUPID_MGMT: {
+                       if (len < IEEE80211_MIN_ACTION_SIZE + 25)
+                               goto invalid;
+                       goto queue;
+               }
                default:
                        break;
                }
@@ -2782,7 +2841,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
                switch (mgmt->u.action.u.measurement.action_code) {
                case WLAN_ACTION_SPCT_MSR_REQ:
-                       if (status->band != IEEE80211_BAND_5GHZ)
+                       if (status->band != NL80211_BAND_5GHZ)
                                break;
 
                        if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -3073,7 +3132,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
                                         false);
 
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -3155,7 +3214,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
                res = rxh(rx);          \
                if (res != RX_CONTINUE) \
                        goto rxh_next;  \
-       } while (0);
+       } while (0)
 
        /* Lock here to avoid hitting all of the data used in the RX
         * path (e.g. key data, station data, ...) concurrently when
@@ -3173,30 +3232,30 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
                 */
                rx->skb = skb;
 
-               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_decrypt)
-               CALL_RXH(ieee80211_rx_h_defragment)
-               CALL_RXH(ieee80211_rx_h_michael_mic_verify)
+               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_decrypt);
+               CALL_RXH(ieee80211_rx_h_defragment);
+               CALL_RXH(ieee80211_rx_h_michael_mic_verify);
                /* must be after MMIC verify so header is counted in MPDU mic */
 #ifdef CONFIG_MAC80211_MESH
                if (ieee80211_vif_is_mesh(&rx->sdata->vif))
                        CALL_RXH(ieee80211_rx_h_mesh_fwding);
 #endif
-               CALL_RXH(ieee80211_rx_h_amsdu)
-               CALL_RXH(ieee80211_rx_h_data)
+               CALL_RXH(ieee80211_rx_h_amsdu);
+               CALL_RXH(ieee80211_rx_h_data);
 
                /* special treatment -- needs the queue */
                res = ieee80211_rx_h_ctrl(rx, frames);
                if (res != RX_CONTINUE)
                        goto rxh_next;
 
-               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)
+               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);
@@ -3219,10 +3278,10 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
                res = rxh(rx);          \
                if (res != RX_CONTINUE) \
                        goto rxh_next;  \
-       } while (0);
+       } while (0)
 
-       CALL_RXH(ieee80211_rx_h_check_dup)
-       CALL_RXH(ieee80211_rx_h_check)
+       CALL_RXH(ieee80211_rx_h_check_dup);
+       CALL_RXH(ieee80211_rx_h_check);
 
        ieee80211_rx_reorder_ampdu(rx, &reorder_release);
 
@@ -3275,6 +3334,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
        ieee80211_rx_handlers(&rx, &frames);
 }
 
+void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
+                                         u16 ssn, u64 filtered,
+                                         u16 received_mpdus)
+{
+       struct sta_info *sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       struct sk_buff_head frames;
+       struct ieee80211_rx_data rx = {
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
+       };
+       int i, diff;
+
+       if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
+               return;
+
+       __skb_queue_head_init(&frames);
+
+       sta = container_of(pubsta, struct sta_info, sta);
+
+       rx.sta = sta;
+       rx.sdata = sta->sdata;
+       rx.local = sta->local;
+
+       rcu_read_lock();
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+               goto out;
+
+       spin_lock_bh(&tid_agg_rx->reorder_lock);
+
+       if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
+               int release;
+
+               /* release all frames in the reorder buffer */
+               release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
+                          IEEE80211_SN_MODULO;
+               ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
+                                                release, &frames);
+               /* update ssn to match received ssn */
+               tid_agg_rx->head_seq_num = ssn;
+       } else {
+               ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
+                                                &frames);
+       }
+
+       /* handle the case that received ssn is behind the mac ssn.
+        * it can be tid_agg_rx->buf_size behind and still be valid */
+       diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
+       if (diff >= tid_agg_rx->buf_size) {
+               tid_agg_rx->reorder_buf_filtered = 0;
+               goto release;
+       }
+       filtered = filtered >> diff;
+       ssn += diff;
+
+       /* update bitmap */
+       for (i = 0; i < tid_agg_rx->buf_size; i++) {
+               int index = (ssn + i) % tid_agg_rx->buf_size;
+
+               tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
+               if (filtered & BIT_ULL(i))
+                       tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
+       }
+
+       /* now process also frames that the filter marking released */
+       ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
+
+release:
+       spin_unlock_bh(&tid_agg_rx->reorder_lock);
+
+       ieee80211_rx_handlers(&rx, &frames);
+
+ out:
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
+
 /* main receive path */
 
 static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
@@ -3366,6 +3504,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
                                return false;
                        /* ignore action frames to TDLS-peers */
                        if (ieee80211_is_action(hdr->frame_control) &&
+                           !is_broadcast_ether_addr(bssid) &&
                            !ether_addr_equal(bssid, hdr->addr1))
                                return false;
                }
@@ -3387,6 +3526,351 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
        return false;
 }
 
+void ieee80211_check_fast_rx(struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_key *key;
+       struct ieee80211_fast_rx fastrx = {
+               .dev = sdata->dev,
+               .vif_type = sdata->vif.type,
+               .control_port_protocol = sdata->control_port_protocol,
+       }, *old, *new = NULL;
+       bool assign = false;
+
+       /* use sparse to check that we don't return without updating */
+       __acquire(check_fast_rx);
+
+       BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != sizeof(rfc1042_header));
+       BUILD_BUG_ON(sizeof(fastrx.rfc1042_hdr) != ETH_ALEN);
+       ether_addr_copy(fastrx.rfc1042_hdr, rfc1042_header);
+       ether_addr_copy(fastrx.vif_addr, sdata->vif.addr);
+
+       fastrx.uses_rss = ieee80211_hw_check(&local->hw, USES_RSS);
+
+       /* fast-rx doesn't do reordering */
+       if (ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
+           !ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER))
+               goto clear;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_STATION:
+               /* 4-addr is harder to deal with, later maybe */
+               if (sdata->u.mgd.use_4addr)
+                       goto clear;
+               /* software powersave is a huge mess, avoid all of it */
+               if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
+                       goto clear;
+               if (ieee80211_hw_check(&local->hw, SUPPORTS_PS) &&
+                   !ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
+                       goto clear;
+               if (sta->sta.tdls) {
+                       fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
+                       fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+                       fastrx.expected_ds_bits = 0;
+               } else {
+                       fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0;
+                       fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
+                       fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
+                       fastrx.expected_ds_bits =
+                               cpu_to_le16(IEEE80211_FCTL_FROMDS);
+               }
+               break;
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_AP:
+               /* parallel-rx requires this, at least with calls to
+                * ieee80211_sta_ps_transition()
+                */
+               if (!ieee80211_hw_check(&local->hw, AP_LINK_PS))
+                       goto clear;
+               fastrx.da_offs = offsetof(struct ieee80211_hdr, addr3);
+               fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
+               fastrx.expected_ds_bits = cpu_to_le16(IEEE80211_FCTL_TODS);
+
+               fastrx.internal_forward =
+                       !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
+                       (sdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
+                        !sdata->u.vlan.sta);
+               break;
+       default:
+               goto clear;
+       }
+
+       if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+               goto clear;
+
+       rcu_read_lock();
+       key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+       if (key) {
+               switch (key->conf.cipher) {
+               case WLAN_CIPHER_SUITE_TKIP:
+                       /* we don't want to deal with MMIC in fast-rx */
+                       goto clear_rcu;
+               case WLAN_CIPHER_SUITE_CCMP:
+               case WLAN_CIPHER_SUITE_CCMP_256:
+               case WLAN_CIPHER_SUITE_GCMP:
+               case WLAN_CIPHER_SUITE_GCMP_256:
+                       break;
+               default:
+                       /* we also don't want to deal with WEP or cipher scheme
+                        * since those require looking up the key idx in the
+                        * frame, rather than assuming the PTK is used
+                        * (we need to revisit this once we implement the real
+                        * PTK index, which is now valid in the spec, but we
+                        * haven't implemented that part yet)
+                        */
+                       goto clear_rcu;
+               }
+
+               fastrx.key = true;
+               fastrx.icv_len = key->conf.icv_len;
+       }
+
+       assign = true;
+ clear_rcu:
+       rcu_read_unlock();
+ clear:
+       __release(check_fast_rx);
+
+       if (assign)
+               new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
+
+       spin_lock_bh(&sta->lock);
+       old = rcu_dereference_protected(sta->fast_rx, true);
+       rcu_assign_pointer(sta->fast_rx, new);
+       spin_unlock_bh(&sta->lock);
+
+       if (old)
+               kfree_rcu(old, rcu_head);
+}
+
+void ieee80211_clear_fast_rx(struct sta_info *sta)
+{
+       struct ieee80211_fast_rx *old;
+
+       spin_lock_bh(&sta->lock);
+       old = rcu_dereference_protected(sta->fast_rx, true);
+       RCU_INIT_POINTER(sta->fast_rx, NULL);
+       spin_unlock_bh(&sta->lock);
+
+       if (old)
+               kfree_rcu(old, rcu_head);
+}
+
+void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       lockdep_assert_held(&local->sta_mtx);
+
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (sdata != sta->sdata &&
+                   (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
+                       continue;
+               ieee80211_check_fast_rx(sta);
+       }
+}
+
+void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+
+       mutex_lock(&local->sta_mtx);
+       __ieee80211_check_fast_rx_iface(sdata);
+       mutex_unlock(&local->sta_mtx);
+}
+
+static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
+                                    struct ieee80211_fast_rx *fast_rx)
+{
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct sta_info *sta = rx->sta;
+       int orig_len = skb->len;
+       int snap_offs = ieee80211_hdrlen(hdr->frame_control);
+       struct {
+               u8 snap[sizeof(rfc1042_header)];
+               __be16 proto;
+       } *payload __aligned(2);
+       struct {
+               u8 da[ETH_ALEN];
+               u8 sa[ETH_ALEN];
+       } addrs __aligned(2);
+       struct ieee80211_sta_rx_stats *stats = &sta->rx_stats;
+
+       if (fast_rx->uses_rss)
+               stats = this_cpu_ptr(sta->pcpu_rx_stats);
+
+       /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
+        * to a common data structure; drivers can implement that per queue
+        * but we don't have that information in mac80211
+        */
+       if (!(status->flag & RX_FLAG_DUP_VALIDATED))
+               return false;
+
+#define FAST_RX_CRYPT_FLAGS    (RX_FLAG_PN_VALIDATED | RX_FLAG_DECRYPTED)
+
+       /* If using encryption, we also need to have:
+        *  - PN_VALIDATED: similar, but the implementation is tricky
+        *  - DECRYPTED: necessary for PN_VALIDATED
+        */
+       if (fast_rx->key &&
+           (status->flag & FAST_RX_CRYPT_FLAGS) != FAST_RX_CRYPT_FLAGS)
+               return false;
+
+       /* we don't deal with A-MSDU deaggregation here */
+       if (status->rx_flags & IEEE80211_RX_AMSDU)
+               return false;
+
+       if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+               return false;
+
+       if (unlikely(ieee80211_is_frag(hdr)))
+               return false;
+
+       /* Since our interface address cannot be multicast, this
+        * implicitly also rejects multicast frames without the
+        * explicit check.
+        *
+        * We shouldn't get any *data* frames not addressed to us
+        * (AP mode will accept multicast *management* frames), but
+        * punting here will make it go through the full checks in
+        * ieee80211_accept_frame().
+        */
+       if (!ether_addr_equal(fast_rx->vif_addr, hdr->addr1))
+               return false;
+
+       if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
+                                             IEEE80211_FCTL_TODS)) !=
+           fast_rx->expected_ds_bits)
+               goto drop;
+
+       /* assign the key to drop unencrypted frames (later)
+        * and strip the IV/MIC if necessary
+        */
+       if (fast_rx->key && !(status->flag & RX_FLAG_IV_STRIPPED)) {
+               /* GCMP header length is the same */
+               snap_offs += IEEE80211_CCMP_HDR_LEN;
+       }
+
+       if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
+               goto drop;
+       payload = (void *)(skb->data + snap_offs);
+
+       if (!ether_addr_equal(payload->snap, fast_rx->rfc1042_hdr))
+               return false;
+
+       /* Don't handle these here since they require special code.
+        * Accept AARP and IPX even though they should come with a
+        * bridge-tunnel header - but if we get them this way then
+        * there's little point in discarding them.
+        */
+       if (unlikely(payload->proto == cpu_to_be16(ETH_P_TDLS) ||
+                    payload->proto == fast_rx->control_port_protocol))
+               return false;
+
+       /* after this point, don't punt to the slowpath! */
+
+       if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
+           pskb_trim(skb, skb->len - fast_rx->icv_len))
+               goto drop;
+
+       if (unlikely(fast_rx->sta_notify)) {
+               ieee80211_sta_rx_notify(rx->sdata, hdr);
+               fast_rx->sta_notify = false;
+       }
+
+       /* statistics part of ieee80211_rx_h_sta_process() */
+       stats->last_rx = jiffies;
+       stats->last_rate = sta_stats_encode_rate(status);
+
+       stats->fragments++;
+
+       if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
+               stats->last_signal = status->signal;
+               if (!fast_rx->uses_rss)
+                       ewma_signal_add(&sta->rx_stats_avg.signal,
+                                       -status->signal);
+       }
+
+       if (status->chains) {
+               int i;
+
+               stats->chains = status->chains;
+               for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
+                       int signal = status->chain_signal[i];
+
+                       if (!(status->chains & BIT(i)))
+                               continue;
+
+                       stats->chain_signal_last[i] = signal;
+                       if (!fast_rx->uses_rss)
+                               ewma_signal_add(&sta->rx_stats_avg.chain_signal[i],
+                                               -signal);
+               }
+       }
+       /* end of statistics */
+
+       if (rx->key && !ieee80211_has_protected(hdr->frame_control))
+               goto drop;
+
+       /* do the header conversion - first grab the addresses */
+       ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
+       ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
+       /* remove the SNAP but leave the ethertype */
+       skb_pull(skb, snap_offs + sizeof(rfc1042_header));
+       /* push the addresses in front */
+       memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs));
+
+       skb->dev = fast_rx->dev;
+
+       ieee80211_rx_stats(fast_rx->dev, skb->len);
+
+       /* The seqno index has the same property as needed
+        * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+        * for non-QoS-data frames. Here we know it's a data
+        * frame, so count MSDUs.
+        */
+       u64_stats_update_begin(&stats->syncp);
+       stats->msdu[rx->seqno_idx]++;
+       stats->bytes += orig_len;
+       u64_stats_update_end(&stats->syncp);
+
+       if (fast_rx->internal_forward) {
+               struct sta_info *dsta = sta_info_get(rx->sdata, skb->data);
+
+               if (dsta) {
+                       /*
+                        * Send to wireless media and increase priority by 256
+                        * to keep the received priority instead of
+                        * reclassifying the frame (see cfg80211_classify8021d).
+                        */
+                       skb->priority += 256;
+                       skb->protocol = htons(ETH_P_802_3);
+                       skb_reset_network_header(skb);
+                       skb_reset_mac_header(skb);
+                       dev_queue_xmit(skb);
+                       return true;
+               }
+       }
+
+       /* deliver to local stack */
+       skb->protocol = eth_type_trans(skb, fast_rx->dev);
+       memset(skb->cb, 0, sizeof(skb->cb));
+       if (rx->napi)
+               napi_gro_receive(rx->napi, skb);
+       else
+               netif_receive_skb(skb);
+
+       return true;
+ drop:
+       dev_kfree_skb(skb);
+       stats->dropped++;
+       return true;
+}
+
 /*
  * This function returns whether or not the SKB
  * was destined for RX processing or not, which,
@@ -3401,6 +3885,21 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
 
        rx->skb = skb;
 
+       /* See if we can do fast-rx; if we have to copy we already lost,
+        * so punt in that case. We should never have to deliver a data
+        * frame to multiple interfaces anyway.
+        *
+        * We skip the ieee80211_accept_frame() call and do the necessary
+        * checking inside ieee80211_invoke_fast_rx().
+        */
+       if (consume && rx->sta) {
+               struct ieee80211_fast_rx *fast_rx;
+
+               fast_rx = rcu_dereference(rx->sta->fast_rx);
+               if (fast_rx && ieee80211_invoke_fast_rx(rx, fast_rx))
+                       return true;
+       }
+
        if (!ieee80211_accept_frame(rx))
                return false;
 
@@ -3426,6 +3925,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
  * be called with rcu_read_lock protection.
  */
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
+                                        struct ieee80211_sta *pubsta,
                                         struct sk_buff *skb,
                                         struct napi_struct *napi)
 {
@@ -3435,7 +3935,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        __le16 fc;
        struct ieee80211_rx_data rx;
        struct ieee80211_sub_if_data *prev;
-       struct sta_info *sta, *prev_sta;
        struct rhash_head *tmp;
        int err = 0;
 
@@ -3471,7 +3970,14 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                     ieee80211_is_beacon(hdr->frame_control)))
                ieee80211_scan_rx(local, skb);
 
-       if (ieee80211_is_data(fc)) {
+       if (pubsta) {
+               rx.sta = container_of(pubsta, struct sta_info, sta);
+               rx.sdata = rx.sta->sdata;
+               if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+                       return;
+               goto out;
+       } else if (ieee80211_is_data(fc)) {
+               struct sta_info *sta, *prev_sta;
                const struct bucket_table *tbl;
 
                prev_sta = NULL;
@@ -3545,8 +4051,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
  * 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_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
-                      struct napi_struct *napi)
+void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
+                      struct sk_buff *skb, struct napi_struct *napi)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate = NULL;
@@ -3555,7 +4061,7 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        WARN_ON_ONCE(softirq_count() == 0);
 
-       if (WARN_ON(status->band >= IEEE80211_NUM_BANDS))
+       if (WARN_ON(status->band >= NUM_NL80211_BANDS))
                goto drop;
 
        sband = local->hw.wiphy->bands[status->band];
@@ -3645,7 +4151,8 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb,
        ieee80211_tpt_led_trig_rx(local,
                        ((struct ieee80211_hdr *)skb->data)->frame_control,
                        skb->len);
-       __ieee80211_rx_handle_packet(hw, skb, napi);
+
+       __ieee80211_rx_handle_packet(hw, pubsta, skb, napi);
 
        rcu_read_unlock();