mac80211: fix a null pointer deref when querying station info when rate control is...
[openwrt/staging/yousong.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index a74bd2b3eb3b5269bb45c09780688538ed4f3535..ba05bde00572e8fa4edf9172111ae81fc0469bdd 100644 (file)
-commit c977493766310a825f406836636ffd66e1447783
+commit 38695a6e5a940e6a524523b88a33916b016fb2a1
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon Mar 10 19:52:56 2014 +0100
+Date:   Fri Jul 11 12:06:18 2014 +0200
 
-    ath9k_hw: remove ANI function restrictions for AP mode
+    mac80211: fix crash on getting sta info with uninitialized rate control
     
-    The primary purpose of this piece of code was to selectively disable
-    OFDM weak signal detection. The checks for this are elsewhere, and an
-    earlier commit relaxed the restrictions for older chips, which are more
-    sensitive to interference.
+    If the expected throughput is queried before rate control has been
+    initialized, the minstrel op for it will crash while trying to access
+    the rate table.
+    Check for WLAN_STA_RATE_CONTROL before attempting to use the rate
+    control op.
     
+    Reported-by: Jean-Pierre Tosoni <jp.tosoni@acksys.fr>
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 8d804f1af11e4e058b1e8453327777d73a585cb8
+commit c0ee7fa4c0da824ccccc172bf175fb1f86540921
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sun Mar 9 11:25:43 2014 +0100
+Date:   Wed Jul 16 18:00:31 2014 +0200
 
-    ath9k: clean up and enhance ANI debugfs file
+    ath9k: fix pending tx frames accounting
     
-    Unify scnprintf calls and include the current OFDM/CCK immunity level.
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit 22e298b5a3a8a49e33805d4e351965123dede35b
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sun Mar 9 10:58:47 2014 +0100
-
-    ath9k: fix ready time of the multicast buffer queue
-    
-    qi->tqi_readyTime is written directly to registers that expect
-    microseconds as unit instead of TU.
-    When setting the CABQ ready time, cur_conf->beacon_interval is in TU, so
-    convert it to microseconds before passing it to ath9k_hw.
-    
-    This should hopefully fix some Tx DMA issues with buffered multicast
-    frames in AP mode.
-    
-    Cc: stable@vger.kernel.org
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit fcb064fdd5a27bec8d24099bc0172468f34c97cb
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sun Mar 9 09:43:09 2014 +0100
-
-    ath9k_hw: fix unreachable code in baseband hang detection code
-    
-    The commit "ath9k: reduce baseband hang detection false positive rate"
-    added a delay in the loop checking the baseband state, however it was
-    unreachable due to previous 'continue' statements.
-    
-    Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit 31959d8df39319e32c6d5ba9c135727be90cfad7
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Fri Mar 7 08:09:38 2014 +0100
-
-    mac80211: fix possible NULL dereference
-    
-    If chanctx is missing on a given vif then the band
-    is assumed to be 2GHz. However if hw doesn't
-    support 2GHz band then mac80211 ended up with a
-    NULL dereference.
-    
-    This fixes a splat:
-    
-    [ 4605.207223] BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
-    [ 4605.210789] IP: [<ffffffffa07b5635>] ieee80211_parse_bitrates+0x65/0x110 [mac80211]
-    
-    The splat was preceeded by WARN_ON(!chanctx_conf)
-    in ieee80211_get_sdata_band().
-    
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-
-commit 6c5a3ffa0a2d22c091a2717f427259bacf77ac5e
-Author: Michael Braun <michael-dev@fami-braun.de>
-Date:   Thu Mar 6 15:08:43 2014 +0100
-
-    mac80211: fix WPA with VLAN on AP side with ps-sta again
-    
-    commit de74a1d9032f4d37ea453ad2a647e1aff4cd2591
-      "mac80211: fix WPA with VLAN on AP side with ps-sta"
-    fixed an issue where queued multicast packets would
-    be sent out encrypted with the key of an other bss.
-    
-    commit "7cbf9d017dbb5e3276de7d527925d42d4c11e732"
-      "mac80211: fix oops on mesh PS broadcast forwarding"
-    essentially reverted it, because vif.type cannot be AP_VLAN
-    due to the check to vif.type in ieee80211_get_buffered_bc before.
-    
-    As the later commit intended to fix the MESH case, fix it
-    by checking for IFTYPE_AP instead of IFTYPE_AP_VLAN.
-    
-    Fixes: 7cbf9d017dbb
-    Cc: <stable@vger.kernel.org> # 3.10.x
-    Cc: <stable@vger.kernel.org> # 3.11.x
-    Cc: <stable@vger.kernel.org> # 3.12.x
-    Cc: <stable@vger.kernel.org> # 3.13.x
-    Cc: <linux-wireless@vger.kernel.org>
-    Cc: <projekt-wlan@fem.tu-ilmenau.de>
-    Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
-
-commit 9d6ab9bdb9b368a6cf9519f0f92509b5b2c297ec
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon Mar 3 14:19:08 2014 +0100
-
-    cfg80211: remove racy beacon_interval assignment
-    
-    In case of AP mode, the beacon interval is already reset to
-    zero inside cfg80211_stop_ap(), and in the other modes it
-    isn't relevant. Remove the assignment to remove a potential
-    race since the assignment isn't properly locked.
-    
-    Reported-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 1abdeca3c6fb9cf1f84f85e78ed8d1c33bd69db0
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri Feb 28 18:52:56 2014 +0100
-
-    ath9k_hw: tweak noise immunity thresholds for older chipsets
-    
-    Older chipsets are more sensitive to high PHY error counts, and the
-    current noise immunity thresholds were based on tests run at QCA with
-    newer chipsets.
-    
-    This patch brings back the values from the old ANI implementation for
-    old chipsets, and it also disables weak signal detection on an earlier
-    noise immunity level, to improve overall radio stability on affected
-    devices.
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit 431e506da5953adc3b65af25f4b90873d528c115
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri Feb 28 18:44:13 2014 +0100
-
-    ath9k_hw: toggle weak signal detection in AP mode on older chipsets
-    
-    The commit 80b4205b "ath9k: Fix OFDM weak signal detection for AP mode"
-    prevented weak signal detection changes from taking effect in AP mode on
-    all chipsets, claiming it is "not allowed".
-    
-    The main reason for not disabling weak signal detection in AP mode is
-    that typically beacon RSSI is used to track whether it is needed to
-    boost range, and this is unavailable in AP mode for obvious reasons.
-    
-    The problem with not disabling weak signal detection is that older
-    chipsets are very sensitive to high PHY error counts. When faced with
-    heavy noise, this can lead to an excessive amount of "Failed to stop
-    TX DMA" errors in the field.
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit 98d1a6c5b14688ed030e81b889f607be308e0df9
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon Feb 24 22:20:32 2014 +0100
-
-    ath9k: fix invalid descriptor discarding
-    
-    Only set sc->rx.discard_next to rx_stats->rs_more when actually
-    discarding the current descriptor.
-    
-    Also, fix a detection of broken descriptors:
-    First the code checks if the current descriptor is not done.
-    Then it checks if the next descriptor is done.
-    Add a check that afterwards checks the first descriptor again, because
-    it might have been completed in the mean time.
-    
-    This fixes a regression introduced in
-    commit 723e711356b5a8a95728a890e254e8b0d47b55cf
-    "ath9k: fix handling of broken descriptors"
+    Packets originally buffered for the regular hardware tx queues can end
+    up being transmitted through the U-APSD queue (via PS-Poll or U-APSD).
+    When packets are dropped due to retransmit failures, the pending frames
+    counter is not always updated properly.
+    Fix this by keeping track of the queue that a frame was accounted for in
+    the ath_frame_info struct, and using that on completion to decide
+    whether the counter should be updated.
+    This fixes some spurious transmit queue hangs.
     
     Cc: stable@vger.kernel.org
-    Reported-by: Marco André Dinis <marcoandredinis@gmail.com>
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit 52a46300e782fe6994466523eb2b0b59091ea59f
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon Feb 24 11:43:50 2014 +0100
-
-    ath9k: reduce baseband hang detection false positive rate
-    
-    Check if the baseband state remains stable, and add a small delay
-    between register reads.
-    
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 118945bb12082e9d4edddc868d88143164e0f440
+commit edcdf0989410a05a6a4b8438df4010447eaa7d9a
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sat Feb 22 14:55:23 2014 +0100
+Date:   Sun Jun 22 13:36:20 2014 +0200
 
-    ath5k: set SURVEY_INFO_IN_USE on get_survey
+    Revert "cfg80211: Use 5MHz bandwidth by default when checking usable channels"
     
-    Only one channel is returned - the one currently being used.
+    It enables channels that are not supposed to be enabled according to the
+    regulatory rules.
     
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+    This reverts commit 8eca1fb692cc9557f386eddce75c300a3855d11a.
 
-commit ee41f72476e1ea44283dfe1cbf75b9543a1e15c8
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sat Feb 22 14:44:52 2014 +0100
+commit 6e7341074823d2a45b81f2742cbf75f1da790031
+Author: Rafał Miłecki <zajec5@gmail.com>
+Date:   Sat May 31 19:40:45 2014 +0200
 
-    ath9k: make some hardware reset log messages debug-only
+    b43: disable 5 GHz on G-PHY
     
-    On some chips, baseband watchdog hangs are more common than others, and
-    the driver has support for handling them.
-    Interrupts even after a watchdog hang are also quite common, so there's
-    not much point in spamming the user's logfiles.
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit b14fbb554fc65a2e0b5c41a319269b0350f187e7
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sat Feb 22 14:35:25 2014 +0100
-
-    ath9k: do not set half/quarter channel flags in AR_PHY_MODE
+    This fixes regression introduced by adding some G-PHY devices to the
+    list of dual band devices. There is simply no support for 5 GHz on
+    G-PHY devices in b43. It results in:
+    WARNING: CPU: 0 PID: 79 at drivers/net/wireless/b43/phy_g.c:75 b43_gphy_channel_switch+0x125/0x130 [b43]()
+    b43-phy1 ERROR: PHY init: Channel switch to default failed
     
-    5/10 MHz channel bandwidth is configured via the PLL clock, instead of
-    the AR_PHY_MODE register. Using that register is AR93xx specific, and
-    makes the mode incompatible with earlier chipsets.
+    Regression was introduced by the following commit:
     
-    In some early versions, these flags were apparently applied at the wrong
-    point in time and thus did not cause connectivity issues, however now
-    they are causing problems, as pointed out in this OpenWrt ticket:
+    commit 773cfc508f4d64c14547ff8751b5cbd473124364
+    Author: Rafał Miłecki <zajec5@gmail.com>
+    Date:   Mon May 19 23:18:55 2014 +0200
     
-    https://dev.openwrt.org/ticket/14916
+        b43: add more devices to the bands database
     
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+    Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit 0f1cb7be2551b30b02cd54c897e0e29e483cfda5
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Sat Feb 22 13:43:29 2014 +0100
-
-    ath9k: fix ps-poll responses under a-mpdu sessions
-    
-    When passing tx frames to the U-APSD queue for powersave poll responses,
-    the ath_atx_tid pointer needs to be passed to ath_tx_setup_buffer for
-    proper sequence number accounting.
-    
-    This fixes high latency and connection stability issues with ath9k
-    running as AP and a few kinds of mobile phones as client, when PS-Poll
-    is heavily used
+commit 1186edbef91f15722e5bdf56326ce0abc2935ce7
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Tue Jun 10 12:51:06 2014 +0200
+
+    rt2x00: disable TKIP on USB
+    
+    On USB we can not get atomically TKIP key. We have to disable support
+    for TKIP acceleration on USB hardware to avoid bug as showed bellow.
+    
+    [  860.827243] BUG: scheduling while atomic: hostapd/3397/0x00000002
+    <snip>
+    [  860.827280] Call Trace:
+    [  860.827282]  [<ffffffff81682ea6>] dump_stack+0x4d/0x66
+    [  860.827284]  [<ffffffff8167eb9b>] __schedule_bug+0x47/0x55
+    [  860.827285]  [<ffffffff81685bb3>] __schedule+0x733/0x7b0
+    [  860.827287]  [<ffffffff81685c59>] schedule+0x29/0x70
+    [  860.827289]  [<ffffffff81684f8a>] schedule_timeout+0x15a/0x2b0
+    [  860.827291]  [<ffffffff8105ac50>] ? ftrace_raw_event_tick_stop+0xc0/0xc0
+    [  860.827294]  [<ffffffff810c13c2>] ? __module_text_address+0x12/0x70
+    [  860.827296]  [<ffffffff81686823>] wait_for_completion_timeout+0xb3/0x140
+    [  860.827298]  [<ffffffff81080fc0>] ? wake_up_state+0x20/0x20
+    [  860.827301]  [<ffffffff814d5b3d>] usb_start_wait_urb+0x7d/0x150
+    [  860.827303]  [<ffffffff814d5cd5>] usb_control_msg+0xc5/0x110
+    [  860.827305]  [<ffffffffa02fb0c6>] rt2x00usb_vendor_request+0xc6/0x160  [rt2x00usb]
+    [  860.827307]  [<ffffffffa02fb215>] rt2x00usb_vendor_req_buff_lock+0x75/0x150 [rt2x00usb]
+    [  860.827309]  [<ffffffffa02fb393>] rt2x00usb_vendor_request_buff+0xa3/0xe0 [rt2x00usb]
+    [  860.827311]  [<ffffffffa023d1a3>] rt2x00usb_register_multiread+0x33/0x40 [rt2800usb]
+    [  860.827314]  [<ffffffffa05805f9>] rt2800_get_tkip_seq+0x39/0x50  [rt2800lib]
+    [  860.827321]  [<ffffffffa0480f88>] ieee80211_get_key+0x218/0x2a0  [mac80211]
+    [  860.827322]  [<ffffffff815cc68c>] ? __nlmsg_put+0x6c/0x80
+    [  860.827329]  [<ffffffffa051b02e>] nl80211_get_key+0x22e/0x360 [cfg80211]
     
     Cc: stable@vger.kernel.org
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+    Reported-and-tested-by: Peter Wu <lekensteyn@gmail.com>
+    Reported-and-tested-by: Pontus Fuchs <pontus.fuchs@gmail.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit d5d87a37bbd6066b2c3c5d0bd0fe2a6e2ea45cc5
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri Feb 21 11:39:59 2014 +0100
+commit 5f313a15da92dda80ac4c9a137bc42d7d0b49adf
+Author: Rafał Miłecki <zajec5@gmail.com>
+Date:   Thu Jun 12 09:28:38 2014 +0200
 
-    ath9k: list more reset causes in debugfs
-    
-    Number of MAC hangs and stuck beacons were missing
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+    b43: fix frequency reported on G-PHY with /new/ firmware
 
-commit d84856012e0f10fe598a5ad3b7b869397a089e07
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Thu Feb 20 11:19:58 2014 +0100
+commit d3a58df87a2e4c2301ac843604202d290a48440b
+Author: Avraham Stern <avraham.stern@intel.com>
+Date:   Thu May 22 12:17:47 2014 +0300
 
-    mac80211: fix station wakeup powersave race
+    mac80211: set new interfaces as idle upon init
     
-    Consider the following (relatively unlikely) scenario:
-     1) station goes to sleep while frames are buffered in driver
-     2) driver blocks wakeup (until no more frames are buffered)
-     3) station wakes up again
-     4) driver unblocks wakeup
-    
-    In this case, the current mac80211 code will do the following:
-     1) WLAN_STA_PS_STA set
-     2) WLAN_STA_PS_DRIVER set
-     3) - nothing -
-     4) WLAN_STA_PS_DRIVER cleared
-    
-    As a result, no frames will be delivered to the client, even
-    though it is awake, until it sends another frame to us that
-    triggers ieee80211_sta_ps_deliver_wakeup() in sta_ps_end().
-    
-    Since we now take the PS spinlock, we can fix this while at
-    the same time removing the complexity with the pending skb
-    queue function. This was broken since my commit 50a9432daeec
-    ("mac80211: fix powersaving clients races") due to removing
-    the clearing of WLAN_STA_PS_STA in the RX path.
-    
-    While at it, fix a cleanup path issue when a station is
-    removed while the driver is still blocking its wakeup.
+    Mark new interfaces as idle to allow operations that require that
+    interfaces are idle to take place. Interface types that are always
+    not idle (like AP interfaces) will be set as not idle when they are
+    assigned a channel context.
     
+    Signed-off-by: Avraham Stern <avraham.stern@intel.com>
+    Signed-off-by: Emmanuel Grumbach<emmanuel.grumbach@intel.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 798f2786602cbe93e6b928299614aa36ebf50692
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon Feb 17 20:49:03 2014 +0100
+commit 923eaf367206e01f22c97aee22300e332d071916
+Author: Arik Nemtsov <arik@wizery.com>
+Date:   Mon May 26 14:40:51 2014 +0300
 
-    mac80211: insert stations before adding to driver
-    
-    There's a race condition in mac80211 because we add stations
-    to the internal lists after adding them to the driver, which
-    means that (for example) the following can happen:
-     1. a station connects and is added
-     2. first, it is added to the driver
-     3. then, it is added to the mac80211 lists
-    
-    If the station goes to sleep between steps 2 and 3, and the
-    firmware/hardware records it as being asleep, mac80211 will
-    never instruct the driver to wake it up again as it never
-    realized it went to sleep since the RX path discarded the
-    frame as a "spurious class 3 frame", no station entry was
-    present yet.
-    
-    Fix this by adding the station in software first, and only
-    then adding it to the driver. That way, any state that the
-    driver changes will be reflected properly in mac80211's
-    station state. The problematic part is the roll-back if the
-    driver fails to add the station, in that case a bit more is
-    needed. To not make that overly complex prevent starting BA
-    sessions in the meantime.
+    mac80211: don't check netdev state for debugfs read/write
     
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit b9ba6a520cb07ab3aa7aaaf9ce4a0bc7a6bc06fe
-Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-Date:   Thu Feb 20 09:22:11 2014 +0200
-
-    mac80211: fix AP powersave TX vs. wakeup race
-    
-    There is a race between the TX path and the STA wakeup: while
-    a station is sleeping, mac80211 buffers frames until it wakes
-    up, then the frames are transmitted. However, the RX and TX
-    path are concurrent, so the packet indicating wakeup can be
-    processed while a packet is being transmitted.
-    
-    This can lead to a situation where the buffered frames list
-    is emptied on the one side, while a frame is being added on
-    the other side, as the station is still seen as sleeping in
-    the TX path.
-    
-    As a result, the newly added frame will not be send anytime
-    soon. It might be sent much later (and out of order) when the
-    station goes to sleep and wakes up the next time.
-    
-    Additionally, it can lead to the crash below.
-    
-    Fix all this by synchronising both paths with a new lock.
-    Both path are not fastpath since they handle PS situations.
-    
-    In a later patch we'll remove the extra skb queue locks to
-    reduce locking overhead.
-    
-    BUG: unable to handle kernel
-    NULL pointer dereference at 000000b0
-    IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
-    *pde = 00000000
-    Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
-    EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1
-    EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
-    EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000
-    ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0
-     DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
-    CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0
-    DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
-    DR6: ffff0ff0 DR7: 00000400
-    Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000)
-    iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9
-    Stack:
-     e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0
-     ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210
-     ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002
-    Call Trace:
-     [<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211]
-     [<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211]
-     [<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211]
-     [<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211]
-     [<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211]
-     [<c149ef70>] dev_hard_start_xmit+0x450/0x950
-     [<c14b9aa9>] sch_direct_xmit+0xa9/0x250
-     [<c14b9c9b>] __qdisc_run+0x4b/0x150
-     [<c149f732>] dev_queue_xmit+0x2c2/0xca0
+    Doing so will lead to an oops for a p2p-dev interface, since it has
+    no netdev.
     
     Cc: stable@vger.kernel.org
-    Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com>
+    Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
     Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-    Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com>
-    [reword commit log, use a separate lock]
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 80e419de0dff38436b30d363311c625766193f86
-Author: Inbal Hacohen <Inbal.Hacohen@intel.com>
-Date:   Wed Feb 12 09:32:27 2014 +0200
-
-    cfg80211: bugfix in regulatory user hint process
-    
-    After processing hint_user, we would want to schedule the
-    timeout work only if we are actually waiting to CRDA. This happens
-    when the status is not "IGNORE" nor "ALREADY_SET".
-    
-    Signed-off-by: Inbal Hacohen <Inbal.Hacohen@intel.com>
+commit a9fb54169b197f31aff24c8d6270dd1e56cde395
+Author: chaitanya.mgit@gmail.com <chaitanya.mgit@gmail.com>
+Date:   Mon May 26 18:01:44 2014 +0530
+
+    regdb: Generalize the mW to dBm power conversion
+    
+    Generalize the power conversion from mW to dBm
+    using log. This should fix the below compilation
+    error for country NO which adds a new power value
+    2000mW which is not handled earlier.
+    
+     CC [M]  net/wireless/wext-sme.o
+     CC [M]  net/wireless/regdb.o
+    net/wireless/regdb.c:1130:1: error: Unknown undeclared here (not in
+    a function)
+    net/wireless/regdb.c:1130:9: error: expected } before power
+    make[2]: *** [net/wireless/regdb.o] Error 1
+    make[1]: *** [net/wireless] Error 2
+    make: *** [net] Error 2
+    
+    Reported-By:  John Walker <john@x109.net>
+    Signed-off-by: Chaitanya T K <chaitanya.mgit@gmail.com>
+    Acked-by: John W. Linville <linville@tuxdriver.com>
+    [remove unneeded parentheses, fix rounding by using %.0f]
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 6514c93afede55284e2cb63359aadedb85884c80
-Author: Jouni Malinen <jouni@qca.qualcomm.com>
-Date:   Tue Feb 18 20:41:08 2014 +0200
-
-    ath9k: Enable U-APSD AP mode support
-    
-    mac80211 handles the actual operations, so ath9k can just indicate
-    support for this. Based on initial tests, this combination seems to
-    work fine.
-    
-    Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
-
-commit a63caf0a357ad5c1f08d6b7827dc76c451445017
-Author: Stanislaw Gruszka <sgruszka@redhat.com>
-Date:   Wed Feb 19 13:15:17 2014 +0100
-
-    ath9k: protect tid->sched check
-    
-    We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That
-    is race condition which can result of doing list_del(&tid->list) twice
-    (second time with poisoned list node) and cause crash like shown below:
-    
-    [424271.637220] BUG: unable to handle kernel paging request at 00100104
-    [424271.637328] IP: [<f90fc072>] ath_tx_aggr_sleep+0x62/0xe0 [ath9k]
-    ...
-    [424271.639953] Call Trace:
-    [424271.639998]  [<f90f6900>] ? ath9k_get_survey+0x110/0x110 [ath9k]
-    [424271.640083]  [<f90f6942>] ath9k_sta_notify+0x42/0x50 [ath9k]
-    [424271.640177]  [<f809cfef>] sta_ps_start+0x8f/0x1c0 [mac80211]
-    [424271.640258]  [<c10f730e>] ? free_compound_page+0x2e/0x40
-    [424271.640346]  [<f809e915>] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211]
-    [424271.640437]  [<c112f048>] ? kmem_cache_free+0x1d8/0x1f0
-    [424271.640510]  [<c1345a84>] ? kfree_skbmem+0x34/0x90
-    [424271.640578]  [<c10fc23c>] ? put_page+0x2c/0x40
-    [424271.640640]  [<c1345a84>] ? kfree_skbmem+0x34/0x90
-    [424271.640706]  [<c1345a84>] ? kfree_skbmem+0x34/0x90
-    [424271.640787]  [<f809dde3>] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211]
-    [424271.640897]  [<f80a07a0>] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211]
-    [424271.641009]  [<f809e22d>] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211]
-    [424271.641104]  [<c13846ce>] ? ip_output+0x7e/0xd0
-    [424271.641182]  [<f80a1057>] ieee80211_rx+0x307/0x7c0 [mac80211]
-    [424271.641266]  [<f90fa6ee>] ath_rx_tasklet+0x88e/0xf70 [ath9k]
-    [424271.641358]  [<f80a0f2c>] ? ieee80211_rx+0x1dc/0x7c0 [mac80211]
-    [424271.641445]  [<f90f82db>] ath9k_tasklet+0xcb/0x130 [ath9k]
-    
-    Bug report:
-    https://bugzilla.kernel.org/show_bug.cgi?id=70551
-    
-    Reported-and-tested-by: Max Sydorenko <maxim.stargazer@gmail.com>
-    Cc: stable@vger.kernel.org
-    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
-
-commit 82ed9e3ccc02797df2ffe4b78127c4cd5f799a41
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Tue Feb 11 15:54:13 2014 +0100
+commit c7d37a66e345df2fdf1aa7b2c9a6d3d53846ca5b
+Author: Krzysztof Hałasa <khalasa@piap.pl>
+Date:   Mon May 26 14:14:46 2014 +0200
 
-    mac80211: send control port protocol frames to the VO queue
+    mac80211: fix IBSS join by initializing last_scan_completed
     
-    Improves reliability of wifi connections with WPA, since authentication
-    frames are prioritized over normal traffic and also typically exempt
-    from aggregation.
+    Without this fix, freshly rebooted Linux creates a new IBSS
+    instead of joining an existing one. Only when jiffies counter
+    overflows after 5 minutes the IBSS can be successfully joined.
     
+    Signed-off-by: Krzysztof Hałasa <khalasa@piap.pl>
+    [edit commit message slightly]
     Cc: stable@vger.kernel.org
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit d4426800f71e972feaa33e04c5801fc730627bdd
-Author: Stanislaw Gruszka <stf_xl@wp.pl>
-Date:   Mon Feb 10 22:38:28 2014 +0100
-
-    rtl8187: fix regression on MIPS without coherent DMA
-    
-    This patch fixes regression caused by commit a16dad77634 "MIPS: Fix
-    potencial corruption". That commit fixes one corruption scenario in
-    cost of adding another one, which actually start to cause crashes
-    on Yeeloong laptop when rtl8187 driver is used.
-    
-    For correct DMA read operation on machines without DMA coherence, kernel
-    have to invalidate cache, such it will refill later with new data that
-    device wrote to memory, when that data is needed to process. We can only
-    invalidate full cache line. Hence when cache line includes both dma
-    buffer and some other data (written in cache, but not yet in main
-    memory), the other data can not hit memory due to invalidation. That
-    happen on rtl8187 where struct rtl8187_priv fields are located just
-    before and after small buffers that are passed to USB layer and DMA
-    is performed on them.
-    
-    To fix the problem we align buffers and reserve space after them to make
-    them match cache line.
-    
-    This patch does not resolve all possible MIPS problems entirely, for
-    that we have to assure that we always map cache aligned buffers for DMA,
-    what can be complex or even not possible. But patch fixes visible and
-    reproducible regression and seems other possible corruptions do not
-    happen in practice, since Yeeloong laptop works stable without rtl8187
-    driver.
-    
-    Bug report:
-    https://bugzilla.kernel.org/show_bug.cgi?id=54391
-    
-    Reported-by: Petr Pisar <petr.pisar@atlas.cz>
-    Bisected-by: Tom Li <biergaizi2009@gmail.com>
-    Reported-and-tested-by: Tom Li <biergaizi2009@gmail.com>
-    Cc: stable@vger.kernel.org
-    Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
-
-commit e2f141d67ad1e7fe10aaab61811e8a409dfb2442
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:55 2014 +0530
-
-    ath9k: Calculate IQ-CAL median
-    
-    This patch adds a routine to calculate the median IQ correction
-    values for AR955x, which is used for outlier detection.
-    The normal method which is used for all other chips is
-    bypassed for AR955x.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit c52a6fce0820c8d0687443ab86058ae03b478c8f
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:54 2014 +0530
-
-    ath9k: Expand the IQ coefficient array
-    
-    This will be used for storing data for mutiple
-    IQ calibration runs, for AR955x.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit 034969ff5c2b6431d10e07c1938f0b916da85cc3
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:53 2014 +0530
-
-    ath9k: Modify IQ calibration for AR955x
-    
-    IQ calibration post-processing for AR955x is different
-    from other chips - instead of just doing it as part
-    of AGC calibration once, it is triggered 3 times and
-    a median is determined. This patch adds initial support
-    for changing the calibration behavior for AR955x.
-    
-    Also, to simplify things, a helper routine to issue/poll
-    AGC calibration is used.
-    
-    For non-AR955x chips, the iqcal_idx (which will be used
-    in subsequent patches) is set to zero.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit 9b1ed6454e6f3511f24266be99b4e403f243f6a8
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:52 2014 +0530
-
-    ath9k: Fix magnitude/phase calculation
-    
-    Incorrect values are programmed in the registers
-    containing the IQ correction coefficients by the IQ-CAL
-    post-processing code. Fix this.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit 36f93484f96f79171dcecb67c5ef0c3de22531a6
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:51 2014 +0530
-
-    ath9k: Rename ar9003_hw_tx_iqcal_load_avg_2_passes
-    
-    Use ar9003_hw_tx_iq_cal_outlier_detection instead.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit 3af09a7f5d21dd5fd15b973ce6a91a575da30417
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:50 2014 +0530
-
-    ath9k: Check explicitly for IQ calibration
-    
-    In chips like AR955x, the initvals contain the information
-    whether IQ calibration is to be done in the HW when an
-    AGC calibration is triggered. Check if IQ-CAL is enabled
-    in the initvals before flagging 'txiqcal_done' as true.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit cb4969634b93c4643a32cc3fbd27d2b288b25771
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Fri Feb 7 10:29:49 2014 +0530
-
-    ath9k: Fix IQ cal post processing for SoC
-    
-    Calibration data is not reused for SoC chips, so
-    call ar9003_hw_tx_iq_cal_post_proc() with the correct
-    argument. The 'is_reusable' flag is currently used
-    only for PC-OEM chips, but it makes things clearer to
-    specify it explicity.
-    
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-
-commit e138e0ef9560c46ce93dbb22a728a57888e94d1c
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Mon Feb 3 13:31:37 2014 +0530
+    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-    ath9k: Fix TX power calculation
-    
-    The commit, "ath9k_hw: Fix incorrect Tx control power in AR9003 template"
-    fixed the incorrect values in the eeprom templates, but if
-    boards have already been calibrated with incorrect values,
-    they would still be using the wrong TX power. Fix this by assigning
-    a default value in such cases.
-    
-    Cc: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+commit 34171dc0d623be2c1032416bf7d3819f388ed70d
+Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date:   Sun May 25 15:35:41 2014 +0300
+
+    mac80211: fix virtual monitor interface addition
+    
+    Since the commit below, cfg80211_chandef_dfs_required()
+    will warn if it gets a an NL80211_IFTYPE_UNSPECIFIED iftype
+    as explicitely written in the commit log.
+    When an virtual monitor interface is added, its type is set
+    in ieee80211_sub_if_data.vif.type, but not in
+    ieee80211_sub_if_data.wdev.iftype which is passed to
+    cfg80211_chandef_dfs_required() hence resulting in the
+    following warning:
+    
+    WARNING: CPU: 1 PID: 21265 at net/wireless/chan.c:376 cfg80211_chandef_dfs_required+0xbc/0x130 [cfg80211]()
+    Modules linked in: [...]
+    CPU: 1 PID: 21265 Comm: ifconfig Tainted: G        W  O 3.13.11+ #12
+    Hardware name: Dell Inc. Latitude E6410/0667CC, BIOS A01 03/05/2010
+     0000000000000009 ffff88008f5fdb08 ffffffff817d4219 ffff88008f5fdb50
+     ffff88008f5fdb40 ffffffff8106f57d 0000000000000000 0000000000000000
+     ffff880081062fb8 ffff8800810604e0 0000000000000001 ffff88008f5fdba0
+    Call Trace:
+     [<ffffffff817d4219>] dump_stack+0x4d/0x66
+     [<ffffffff8106f57d>] warn_slowpath_common+0x7d/0xa0
+     [<ffffffff8106f5ec>] warn_slowpath_fmt+0x4c/0x50
+     [<ffffffffa04ea4ec>] cfg80211_chandef_dfs_required+0xbc/0x130 [cfg80211]
+     [<ffffffffa06b1024>] ieee80211_vif_use_channel+0x94/0x500 [mac80211]
+     [<ffffffffa0684e6b>] ieee80211_add_virtual_monitor+0x1ab/0x5c0 [mac80211]
+     [<ffffffffa0686ae5>] ieee80211_do_open+0xe75/0x1580 [mac80211]
+     [<ffffffffa0687259>] ieee80211_open+0x69/0x70 [mac80211]
+    [snip]
+    
+    Fixes: 00ec75fc5a64 ("cfg80211: pass the actual iftype when calling cfg80211_chandef_dfs_required()")
+    Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+    Acked-by: Luciano Coelho <luciano.coelho@intel.com>
+    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit b9f268b5b01331c3c82179abca551429450e9417
+commit d93cc72b37b4e2c314e1c499e80e8801907c2fea
 Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Jan 29 14:22:27 2014 +0100
+Date:   Thu Jun 5 14:21:37 2014 +0200
 
-    cfg80211: consider existing DFS interfaces
-    
-    It was possible to break interface combinations in
-    the following way:
-    
-     combo 1: iftype = AP, num_ifaces = 2, num_chans = 2,
-     combo 2: iftype = AP, num_ifaces = 1, num_chans = 1, radar = HT20
+    mac80211: use csa counter offsets instead of csa_active
     
-    With the above interface combinations it was
-    possible to:
+    vif->csa_active is protected by mutexes only. This
+    means it is unreliable to depend on it on codeflow
+    in non-sleepable beacon and CSA code. There was no
+    guarantee to have vif->csa_active update be
+    visible before beacons are updated on SMP systems.
     
-     step 1. start AP on DFS channel by matching combo 2
-     step 2. start AP on non-DFS channel by matching combo 1
-    
-    This was possible beacuse (step 2) did not consider
-    if other interfaces require radar detection.
-    
-    The patch changes how cfg80211 tracks channels -
-    instead of channel itself now a complete chandef
-    is stored.
+    Using csa counter offsets which are embedded in
+    beacon struct (and thus are protected with single
+    RCU assignment) is much safer.
     
     Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit bc9c62f5f511cc395c62dbf4cdd437f23db53b28
-Author: Antonio Quartulli <antonio@open-mesh.com>
-Date:   Wed Jan 29 17:53:43 2014 +0100
-
-    cfg80211: fix channel configuration in IBSS join
-    
-    When receiving an IBSS_JOINED event select the BSS object
-    based on the {bssid, channel} couple rather than the bssid
-    only.
-    With the current approach if another cell having the same
-    BSSID (but using a different channel) exists then cfg80211
-    picks up the wrong BSS object.
-    The result is a mismatching channel configuration between
-    cfg80211 and the driver, that can lead to any sort of
-    problem.
-    
-    The issue can be triggered by having an IBSS sitting on
-    given channel and then asking the driver to create a new
-    cell using the same BSSID but with a different frequency.
-    By passing the channel to cfg80211_get_bss() we can solve
-    this ambiguity and retrieve/create the correct BSS object.
-    All the users of cfg80211_ibss_joined() have been changed
-    accordingly.
-    
-    Moreover WARN when cfg80211_ibss_joined() gets a NULL
-    channel as argument and remove a bogus call of the same
-    function in ath6kl (it does not make sense to call
-    cfg80211_ibss_joined() with a zero BSSID on ibss-leave).
-    
-    Cc: Kalle Valo <kvalo@qca.qualcomm.com>
-    Cc: Arend van Spriel <arend@broadcom.com>
-    Cc: Bing Zhao <bzhao@marvell.com>
-    Cc: Jussi Kivilinna <jussi.kivilinna@iki.fi>
-    Cc: libertas-dev@lists.infradead.org
-    Acked-by: Kalle Valo <kvalo@qca.qualcomm.com>
-    Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
-    [minor code cleanup in ath6kl]
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 7e0c41cb41f215aba2c39b1c237bb4d42ec49a85
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Fri Jan 24 14:41:44 2014 +0100
+commit d2746694fcdef24e0a7a1947d8c70082cde81a26
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date:   Thu Jun 5 14:21:36 2014 +0200
 
-    mac80211: fix bufferable MMPDU RX handling
-    
-    Action, disassoc and deauth frames are bufferable, and as such don't
-    have the PM bit in the frame control field reserved which means we
-    need to react to the bit when receiving in such a frame.
+    mac80211: move csa counters from sdata to beacon/presp
     
-    Fix this by introducing a new helper ieee80211_is_bufferable_mmpdu()
-    and using it for the RX path that currently ignores the PM bit in
-    any non-data frames for doze->wake transitions, but listens to it in
-    all frames for wake->doze transitions, both of which are wrong.
+    Having csa counters part of beacon and probe_resp
+    structures makes it easier to get rid of possible
+    races between setting a beacon and updating
+    counters on SMP systems by guaranteeing counters
+    are always consistent against given beacon struct.
     
-    Also use the new helper in the TX path to clean up the code.
+    While at it relax WARN_ON into WARN_ON_ONCE to
+    prevent spamming logs and racing.
     
+    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit fc0df6d2343636e3f48a069330d5b972e3d8659d
+commit 5dcb54f3a1a8cd7e0331e773487574f9743615db
 Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
-Date:   Fri Jan 24 14:29:21 2014 +0100
+Date:   Thu Jun 5 08:12:57 2014 +0200
 
-    cfg80211: set preset_chandef after channel switch
+    mac80211: allow tx via monitor iface when DFS
+    
+    Allow send frames using monitor interface
+    when DFS chandef and we pass CAC (beaconing
+    allowed).
     
-    Set preset_chandef in channel switch notification.
-    In other case we will have old preset_chandef.
+    This fix problem when old kernel and new backports used,
+    in such case hostapd create/use also monitor interface.
+    Before this patch all frames hostapd send using monitor
+    iface were dropped when AP was configured on DFS channel.
     
     Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit cdec895e2344987ff171cece96e25d7407a3ebf6
-Author: Simon Wunderlich <simon@open-mesh.com>
-Date:   Fri Jan 24 23:48:29 2014 +0100
+commit 6f09a1beb0d2007572248c986780562219bd206f
+Author: Johannes Berg <johannes.berg@intel.com>
+Date:   Wed Jun 4 17:31:56 2014 +0200
 
-    mac80211: send ibss probe responses with noack flag
-    
-    Responding to probe requests for scanning clients will often create
-    excessive retries, as it happens quite often that the scanning client
-    already left the channel. Therefore do it like hostapd and send probe
-    responses for wildcard SSID only once by using the noack flag.
+    cfg80211: make ethtool the driver's responsibility
     
-    Signed-off-by: Simon Wunderlich <simon@open-mesh.com>
-    [fix typo & 'wildcard SSID' in commit log]
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 0b865d1e6b9c05052adae9315df7cb195dc60c3b
-Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Tue Jan 28 17:09:08 2014 +0200
-
-    mac80211: ibss: remove unnecessary call to release channel
+    Currently, cfg80211 tries to implement ethtool, but that doesn't
+    really scale well, with all the different operations. Make the
+    lower-level driver responsible for it, which currently only has
+    an effect on mac80211. It will similarly not scale well at that
+    level though, since mac80211 also has many drivers.
     
-    The ieee80211_vif_use_channel() function calls
-    ieee80211_vif_release_channel(), so there's no need to call it
-    explicitly in __ieee80211_sta_join_ibss().
+    To cleanly implement this in mac80211, introduce a new file and
+    move some code to appropriate places.
     
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit e1b6c17e971f0a51ff86c2dac2584c63cd999cd7
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Jan 29 07:56:21 2014 +0100
+commit 6b0c6f133de8f90caeb1c4a902e6140567c5bf96
+Author: Johannes Berg <johannes.berg@intel.com>
+Date:   Wed Jun 4 17:06:23 2014 +0200
 
-    mac80211: add missing CSA locking
+    mac80211: remove weak WEP IV accounting
     
-    The patch adds a missing sdata lock and adds a few
-    lockdeps for easier maintenance.
+    Since WEP is practically dead, there seems very little
+    point in keeping WEP weak IV accounting.
     
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit ad17ba7d14d225b109b73c177cd446afb8050598
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Jan 29 07:56:20 2014 +0100
+commit aecdc89fb4664c76baa4bbd46008f220532309ff
+Author: Luciano Coelho <luciano.coelho@intel.com>
+Date:   Fri May 23 11:04:50 2014 +0300
 
-    mac80211: fix sdata->radar_required locking
+    ath9k/ath10k: remove unnecessary channel_switch_beacon callbacks
     
-    radar_required setting wasn't protected by
-    local->mtx in some places. This should prevent
-    from scanning/radar detection/roc colliding.
+    The channel_switch_beacon callback is optional, so it doesn't have to
+    be defined if it's not going to do anything useful with it.  Both
+    ath9k and ath10k define the callback and just returns.  This commit
+    removes them.
     
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Cc: Michal Kazior <michal.kazior@tieto.com>
+    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
 
-commit 5fcd5f1808813a3d9e502fd756e01bee8a79c85d
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Jan 29 07:56:19 2014 +0100
+commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798
+Author: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
+Date:   Tue May 27 16:58:02 2014 +0530
 
-    mac80211: move csa_active setting in STA CSA
+    ath9k: Fix deadlock while updating p2p beacon timer
     
-    The sdata->vif.csa_active could be left set after,
-    e.g. channel context constraints check fail in STA
-    mode leaving the interface in a strange state for
-    a brief period of time until it is disconnected.
-    This was harmless but ugly.
+    pm_lock is taken twice while syncing HW TSF of p2p vif.
+    Fix this by taking the lock at caller side.
     
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Cc: Felix Fietkau <nbd@openwrt.org>
+    Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
+    Signed-off-by: John W. Linville <linville@tuxdriver.com>
 
-commit e486da4b7eed71821c6b4c1bb9ac62ffd3ab13e9
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Jan 29 07:56:18 2014 +0100
+commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:27 2014 +0200
 
-    mac80211: fix possible memory leak on AP CSA failure
+    rt2x00: do not initialize BCN_OFFSET registers
     
-    If CSA for AP interface failed and the interface
-    was not stopped afterwards another CSA request
-    would leak sdata->u.ap.next_beacon.
-    
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 3a77ba08940682bf3d52cf14f980337324af9d4a
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Sat Feb 1 00:33:29 2014 +0100
-
-    mac80211: fix fragmentation code, particularly for encryption
-    
-    The "new" fragmentation code (since my rewrite almost 5 years ago)
-    erroneously sets skb->len rather than using skb_trim() to adjust
-    the length of the first fragment after copying out all the others.
-    This leaves the skb tail pointer pointing to after where the data
-    originally ended, and thus causes the encryption MIC to be written
-    at that point, rather than where it belongs: immediately after the
-    data.
-    
-    The impact of this is that if software encryption is done, then
-     a) encryption doesn't work for the first fragment, the connection
-        becomes unusable as the first fragment will never be properly
-        verified at the receiver, the MIC is practically guaranteed to
-        be wrong
-     b) we leak up to 8 bytes of plaintext (!) of the packet out into
-        the air
-    
-    This is only mitigated by the fact that many devices are capable
-    of doing encryption in hardware, in which case this can't happen
-    as the tail pointer is irrelevant in that case. Additionally,
-    fragmentation is not used very frequently and would normally have
-    to be configured manually.
-    
-    Fix this by using skb_trim() properly.
+    We setup BCN_OFFSET{0,1} registers dynamically, don't have to
+    initialize them.
     
-    Cc: stable@vger.kernel.org
-    Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation")
-    Reported-by: Jouni Malinen <j@w1.fi>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit de5f242e0c10e841017e37eb8c38974a642dbca8
-Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
-Date:   Tue Jan 28 06:21:59 2014 +0530
+commit e5c58ca7a48d4c82f282749a978052c47fd95998
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:26 2014 +0200
 
-    ath9k: Fix build error on ARM
+    rt2x00: change order when stop beaconing
     
-    Use mdelay instead of udelay to fix this error:
+    When no beaconing is needed, first stop beacon queue (disable beaconing
+    globally) to avoid possible sending of not prepared beacon on short
+    period after clearing beacon and before stop of BCN queue.
     
-    ERROR: "__bad_udelay" [drivers/net/wireless/ath/ath9k/ath9k_hw.ko] undefined!
-    make[1]: *** [__modpost] Error 1
-    make: *** [modules] Error 2
-    
-    Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
-    Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 8e3ea7a51dfc61810fcefd947f6edcf61125252a
-Author: Geert Uytterhoeven <geert@linux-m68k.org>
-Date:   Sun Jan 26 11:53:21 2014 +0100
+commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:25 2014 +0200
 
-    ath9k: Fix uninitialized variable in ath9k_has_tx_pending()
-    
-    drivers/net/wireless/ath/ath9k/main.c: In function ‘ath9k_has_tx_pending’:
-    drivers/net/wireless/ath/ath9k/main.c:1869: warning: ‘npend’ may be used uninitialized in this function
+    rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM
     
-    Introduced by commit 10e2318103f5941aa70c318afe34bc41f1b98529 ("ath9k:
-    optimize ath9k_flush").
+    We setup MAC_BSSID_DW1_BSS_BCN_NUM dynamically when numbers of active
+    beacons increase. Change default to 0 to tell hardware that we want to
+    send only one beacon as default.
     
-    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit a4a634a6937ebdd827fa58e8fcdb8ca49a3769f6
-Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-Date:   Mon Jan 27 11:07:42 2014 +0200
+commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:24 2014 +0200
 
-    mac80211: release the channel in error path in start_ap
+    rt2x00: change beaconing setup on RT2800
     
-    When the driver cannot start the AP or when the assignement
-    of the beacon goes wrong, we need to unassign the vif.
+    As reported by Matthias, on 5572 chip, even if we clear up TXWI
+    of corresponding beacon, hardware still try to send it or do other
+    action that increase power consumption peak up to 1A.
     
-    Cc: stable@vger.kernel.org
-    Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit dfb6889a75c601aedb7450b7e606668e77da6679
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Wed Jan 22 11:14:19 2014 +0200
-
-    cfg80211: send scan results from work queue
-    
-    Due to the previous commit, when a scan finishes, it is in theory
-    possible to hit the following sequence:
-     1. interface starts being removed
-     2. scan is cancelled by driver and cfg80211 is notified
-     3. scan done work is scheduled
-     4. interface is removed completely, rdev->scan_req is freed,
-        event sent to userspace but scan done work remains pending
-     5. new scan is requested on another virtual interface
-     6. scan done work runs, freeing the still-running scan
-    
-    To fix this situation, hang on to the scan done message and block
-    new scans while that is the case, and only send the message from
-    the work function, regardless of whether the scan_req is already
-    freed from interface removal. This makes step 5 above impossible
-    and changes step 6 to be
-     5. scan done work runs, sending the scan done message
-    
-    As this can't work for wext, so we send the message immediately,
-    but this shouldn't be an issue since we still return -EBUSY.
+    To avoid the issue, setup beaconing dynamically by configuring offsets
+    of currently active beacons and MAC_BSSID_DW1_BSS_BCN_NUM variable,
+    which limit number of beacons that hardware will try to send.
     
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Reported-by: Matthias Fend <Matthias.Fend@wolfvision.net>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 45b7ab41fc08627d9a8428cb413d5d84662a9707
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Wed Jan 22 11:14:18 2014 +0200
+commit 916e591b2cc41f7e572992175ca56d866d7bc958
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:23 2014 +0200
 
-    cfg80211: fix scan done race
-    
-    When an interface/wdev is removed, any ongoing scan should be
-    cancelled by the driver. This will make it call cfg80211, which
-    only queues a work struct. If interface/wdev removal is quick
-    enough, this can leave the scan request pending and processed
-    only after the interface is gone, causing a use-after-free.
+    rt2x00: change beaconing locking
     
-    Fix this by making sure the scan request is not pending after
-    the interface is destroyed. We can't flush or cancel the work
-    item due to locking concerns, but when it'll run it shouldn't
-    find anything to do. This leaves a potential issue, if a new
-    scan gets requested before the work runs, it prematurely stops
-    the running scan, potentially causing another crash. I'll fix
-    that in the next patch.
+    This patch is needed for further changes to keep global variables
+    consistent when changing beaconing on diffrent vif's.
     
-    This was particularly observed with P2P_DEVICE wdevs, likely
-    because freeing them is quicker than freeing netdevs.
-    
-    Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Fixes: 4a58e7c38443 ("cfg80211: don't "leak" uncompleted scans")
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit ae04fa489ab31b5a10d3cc8399f52761175d4321
-Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-Date:   Thu Jan 23 14:28:16 2014 +0200
-
-    mac80211: avoid deadlock revealed by lockdep
-    
-    sdata->u.ap.request_smps_work can’t be flushed synchronously
-    under wdev_lock(wdev) since ieee80211_request_smps_ap_work
-    itself locks the same lock.
-    While at it, reset the driver_smps_mode when the ap is
-    stopped to its default: OFF.
-    
-    This solves:
-    
-    ======================================================
-    [ INFO: possible circular locking dependency detected ]
-    3.12.0-ipeer+ #2 Tainted: G           O
-    -------------------------------------------------------
-    rmmod/2867 is trying to acquire lock:
-      ((&sdata->u.ap.request_smps_work)){+.+...}, at: [<c105b8d0>] flush_work+0x0/0x90
-    
-    but task is already holding lock:
-      (&wdev->mtx){+.+.+.}, at: [<f9b32626>] cfg80211_stop_ap+0x26/0x230 [cfg80211]
-    
-    which lock already depends on the new lock.
-    
-    the existing dependency chain (in reverse order) is:
-    
-    -> #1 (&wdev->mtx){+.+.+.}:
-            [<c10aefa9>] lock_acquire+0x79/0xe0
-            [<c1607a1a>] mutex_lock_nested+0x4a/0x360
-            [<fb06288b>] ieee80211_request_smps_ap_work+0x2b/0x50 [mac80211]
-            [<c105cdd8>] process_one_work+0x198/0x450
-            [<c105d469>] worker_thread+0xf9/0x320
-            [<c10669ff>] kthread+0x9f/0xb0
-            [<c1613397>] ret_from_kernel_thread+0x1b/0x28
-    
-    -> #0 ((&sdata->u.ap.request_smps_work)){+.+...}:
-            [<c10ae9df>] __lock_acquire+0x183f/0x1910
-            [<c10aefa9>] lock_acquire+0x79/0xe0
-            [<c105b917>] flush_work+0x47/0x90
-            [<c105d867>] __cancel_work_timer+0x67/0xe0
-            [<c105d90f>] cancel_work_sync+0xf/0x20
-            [<fb0765cc>] ieee80211_stop_ap+0x8c/0x340 [mac80211]
-            [<f9b3268c>] cfg80211_stop_ap+0x8c/0x230 [cfg80211]
-            [<f9b0d8f9>] cfg80211_leave+0x79/0x100 [cfg80211]
-            [<f9b0da72>] cfg80211_netdev_notifier_call+0xf2/0x4f0 [cfg80211]
-            [<c160f2c9>] notifier_call_chain+0x59/0x130
-            [<c106c6de>] __raw_notifier_call_chain+0x1e/0x30
-            [<c106c70f>] raw_notifier_call_chain+0x1f/0x30
-            [<c14f8213>] call_netdevice_notifiers_info+0x33/0x70
-            [<c14f8263>] call_netdevice_notifiers+0x13/0x20
-            [<c14f82a4>] __dev_close_many+0x34/0xb0
-            [<c14f83fe>] dev_close_many+0x6e/0xc0
-            [<c14f9c77>] rollback_registered_many+0xa7/0x1f0
-            [<c14f9dd4>] unregister_netdevice_many+0x14/0x60
-            [<fb06f4d9>] ieee80211_remove_interfaces+0xe9/0x170 [mac80211]
-            [<fb055116>] ieee80211_unregister_hw+0x56/0x110 [mac80211]
-            [<fa3e9396>] iwl_op_mode_mvm_stop+0x26/0xe0 [iwlmvm]
-            [<f9b9d8ca>] _iwl_op_mode_stop+0x3a/0x70 [iwlwifi]
-            [<f9b9d96f>] iwl_opmode_deregister+0x6f/0x90 [iwlwifi]
-            [<fa405179>] __exit_compat+0xd/0x19 [iwlmvm]
-            [<c10b8bf9>] SyS_delete_module+0x179/0x2b0
-            [<c1613421>] sysenter_do_call+0x12/0x32
-    
-    Fixes: 687da132234f ("mac80211: implement SMPS for AP")
-    Cc: <stable@vger.kernel.org> [3.13]
-    Reported-by: Ilan Peer <ilan.peer@intel.com>
-    Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 178b205e96217164fd7c30113464250d0b6f5eca
+commit 930b0dffd1731f3f418f9132faea720a23b7af61
 Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Thu Jan 23 16:32:29 2014 +0100
-
-    cfg80211: re-enable 5/10 MHz support
-    
-    Unfortunately I forgot this during the merge window, but the
-    patch seems small enough to go in as a fix. The userspace API
-    bug that was the reason for disabling it has long been fixed.
+Date:   Tue Jun 3 11:18:47 2014 +0200
+
+    mac80211: fix station/driver powersave race
+    
+    It is currently possible to have a race due to the station PS
+    unblock work like this:
+     * station goes to sleep with frames buffered in the driver
+     * driver blocks wakeup
+     * station wakes up again
+     * driver flushes/returns frames, and unblocks, which schedules
+       the unblock work
+     * unblock work starts to run, and checks that the station is
+       awake (i.e. that the WLAN_STA_PS_STA flag isn't set)
+     * we process a received frame with PM=1, setting the flag again
+     * ieee80211_sta_ps_deliver_wakeup() runs, delivering all frames
+       to the driver, and then clearing the WLAN_STA_PS_DRIVER and
+       WLAN_STA_PS_STA flags
+    
+    In this scenario, mac80211 will think that the station is awake,
+    while it really is asleep, and any TX'ed frames should be filtered
+    by the device (it will know that the station is sleeping) but then
+    passed to mac80211 again, which will not buffer it either as it
+    thinks the station is awake, and eventually the packets will be
+    dropped.
+    
+    Fix this by moving the clearing of the flags to exactly where we
+    learn about the situation. This creates a problem of reordering,
+    so introduce another flag indicating that delivery is being done,
+    this new flag also queues frames and is cleared only while the
+    spinlock is held (which the queuing code also holds) so that any
+    concurrent delivery/TX is handled correctly.
     
+    Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 110a1c79acda14edc83b7c8dc5af9c7ddd23eb61
-Author: Pontus Fuchs <pontus.fuchs@gmail.com>
-Date:   Thu Jan 16 15:00:40 2014 +0100
+commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Fri May 23 19:58:14 2014 +0200
 
-    nl80211: Reset split_start when netlink skb is exhausted
+    mac80211: reduce packet loss notifications under load
     
-    When the netlink skb is exhausted split_start is left set. In the
-    subsequent retry, with a larger buffer, the dump is continued from the
-    failing point instead of from the beginning.
+    During strong signal fluctuations under high throughput, few consecutive
+    failed A-MPDU transmissions can easily trigger packet loss notification,
+    and thus (in AP mode) client disconnection.
     
-    This was causing my rt28xx based USB dongle to now show up when
-    running "iw list" with an old iw version without split dump support.
+    Reduce the number of false positives by checking the A-MPDU status flag
+    and treating a failed A-MPDU as a single packet.
     
-    Cc: stable@vger.kernel.org
-    Fixes: 3713b4e364ef ("nl80211: allow splitting wiphy information in dumps")
-    Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
-    [avoid the entire workaround when state->split is set]
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit b4c31b45ffc7ef110fa9ecc34d7878fe7c5b9da4
-Author: Eliad Peller <eliad@wizery.com>
-Date:   Sun Jan 12 11:06:37 2014 +0200
+commit 7b7843a36fbcc568834404c7430ff895d8502131
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Fri May 23 19:26:32 2014 +0200
 
-    mac80211: move roc cookie assignment earlier
-    
-    ieee80211_start_roc_work() might add a new roc
-    to existing roc, and tell cfg80211 it has already
-    started.
-    
-    However, this might happen before the roc cookie
-    was set, resulting in REMAIN_ON_CHANNEL (started)
-    event with null cookie. Consequently, it can make
-    wpa_supplicant go out of sync.
-    
-    Fix it by setting the roc cookie earlier.
+    mac80211: fix a memory leak on sta rate selection table
     
     Cc: stable@vger.kernel.org
-    Signed-off-by: Eliad Peller <eliad@wizery.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit cfdc9157bfd7bcf88ab4dae08873a9907eba984c
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Fri Jan 24 14:06:29 2014 +0100
-
-    nl80211: send event when AP operation is stopped
-    
-    There are a few cases, e.g. suspend, where an AP interface is
-    stopped by the kernel rather than by userspace request, most
-    commonly when suspending. To let userspace know about this,
-    send the NL80211_CMD_STOP_AP command as an event every time
-    an AP interface is stopped. This also happens when userspace
-    did in fact request the AP stop, but that's not a problem.
-    
-    For full-MAC drivers this may need to be extended to also
-    cover cases where the device stopped the AP operation for
-    some reason, this a bit more complicated because then all
-    cfg80211 state also needs to be reset; such API is not part
-    of this patch.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit d5d567eda7704f190379ca852a8f9a4112e3eee3
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Thu Jan 23 16:20:29 2014 +0100
-
-    mac80211: add length check in ieee80211_is_robust_mgmt_frame()
-    
-    A few places weren't checking that the frame passed to the
-    function actually has enough data even though the function
-    clearly documents it must have a payload byte. Make this
-    safer by changing the function to take an skb and checking
-    the length inside. The old version is preserved for now as
-    the rtl* drivers use it and don't have a correct skb.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit f8f6d212a047fc65c7d3442dfc038f65517236fc
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Fri Jan 24 10:53:53 2014 +0100
-
-    nl80211: fix scheduled scan RSSI matchset attribute confusion
-    
-    The scheduled scan matchsets were intended to be a list of filters,
-    with the found BSS having to pass at least one of them to be passed
-    to the host. When the RSSI attribute was added, however, this was
-    broken and currently wpa_supplicant adds that attribute in its own
-    matchset; however, it doesn't intend that to mean that anything
-    that passes the RSSI filter should be passed to the host, instead
-    it wants it to mean that everything needs to also have higher RSSI.
-    
-    This is semantically problematic because we have a list of filters
-    like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which
-    one should be OR'ed and which one AND'ed.
-    
-    To fix this, move the RSSI filter attribute into each matchset. As
-    we need to stay backward compatible, treat a matchset with only the
-    RSSI attribute as a "default RSSI filter" for all other matchsets,
-    but only if there are other matchsets (an RSSI-only matchset by
-    itself is still desirable.)
-    
-    To make driver implementation easier, keep a global min_rssi_thold
-    for the entire request as well. The only affected driver is ath6kl.
-    
-    I found this when I looked into the code after Raja Mani submitted
-    a patch fixing the n_match_sets calculation to disregard the RSSI,
-    but that patch didn't address the semantic issue.
-    
-    Reported-by: Raja Mani <rmani@qti.qualcomm.com>
-    Acked-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit de553e8545e65a6dc4e45f43df7e1443d4291922
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Fri Jan 24 10:17:47 2014 +0100
+commit 96892d6aa0a153423070addf3070bc79578b3897
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon May 19 21:20:49 2014 +0200
 
-    nl80211: check nla_parse() return values
+    ath9k: avoid passing buffers to the hardware during flush
     
-    If there's a policy, then nla_parse() return values must be
-    checked, otherwise the policy is useless and there's nothing
-    that ensures the attributes are actually what we expect them
-    to be.
+    The commit "ath9k: fix possible hang on flush" changed the receive code
+    to always link rx descriptors of processed frames, even when flushing.
+    In some cases, this leads to flushed rx buffers being passed to the
+    hardware while rx is already stopped.
     
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 652204a0733e9e1c54661d6f9d36e2e1e3b22bb1
-Author: Karl Beldan <karl.beldan@rivierawaves.com>
-Date:   Thu Jan 23 20:06:34 2014 +0100
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-    mac80211: send {ADD,DEL}BA on AC_VO like other mgmt frames, as per spec
-    
-    ATM, {ADD,DEL}BA and BAR frames are sent on the AC matching the TID of
-    the BA parameters. In the discussion [1] about this patch, Johannes
-    recalled that it fixed some races with the DELBA and indeed this
-    behavior was introduced in [2].
-    While [2] is right for the BARs, the part queueing the {ADD,DEL}BAs on
-    their BA params TID AC violates the spec and is more a workaround for
-    some drivers. Helmut expressed some concerns wrt such drivers, in
-    particular DELBAs in rt2x00.
-    
-    ATM, DELBAs are sent after a driver has called (hence "purposely")
-    ieee80211_start_tx_ba_cb_irqsafe and Johannes and Emmanuel gave some
-    details wrt intentions behind the split of the IEEE80211_AMPDU_TX_STOP_*
-    given to the driver ampdu_action supposed to call this function, which
-    could prove handy to people trying to do the right thing in faulty
-    drivers (if their fw/hw don't get in their way).
-    
-    [1] http://mid.gmane.org/1390391564-18481-1-git-send-email-karl.beldan@gmail.com
-    [2] Commit: cf6bb79ad828 ("mac80211: Use appropriate TID for sending BAR, ADDBA and DELBA frames")
-    
-    Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
-    Cc: Helmut Schaa <helmut.schaa@googlemail.com>
-    Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
-+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
-@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struc
-       if (nw_type & ADHOC_NETWORK) {
-               ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
-                          nw_type & ADHOC_CREATOR ? "creator" : "joiner");
--              cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
-+              cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
-               cfg80211_put_bss(ar->wiphy, bss);
-               return;
-       }
-@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(st
-       }
-       if (vif->nw_type & ADHOC_NETWORK) {
--              if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
-+              if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
-                       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
-                                  "%s: ath6k not in ibss mode\n", __func__);
--                      return;
--              }
--              memset(bssid, 0, ETH_ALEN);
--              cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
-               return;
-       }
-@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(s
-       struct ath6kl_vif *vif = netdev_priv(dev);
-       u16 interval;
-       int ret, rssi_thold;
-+      int n_match_sets = request->n_match_sets;
-+
-+      /*
-+       * If there's a matchset w/o an SSID, then assume it's just for
-+       * the RSSI (nothing else is currently supported) and ignore it.
-+       * The device only supports a global RSSI filter that we set below.
-+       */
-+      if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
-+              n_match_sets = 0;
-       if (ar->state != ATH6KL_STATE_ON)
-               return -EIO;
-@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(s
-       ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
-                                     request->n_ssids,
-                                     request->match_sets,
--                                    request->n_match_sets);
-+                                    n_match_sets);
-       if (ret < 0)
-               return ret;
--      if (!request->n_match_sets) {
-+      if (!n_match_sets) {
-               ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
-                                              ALL_BSS_FILTER, 0);
-               if (ret < 0)
-@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(s
-       if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
-                    ar->fw_capabilities)) {
--              if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
-+              if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
-                       rssi_thold = 0;
--              else if (request->rssi_thold < -127)
-+              else if (request->min_rssi_thold < -127)
-                       rssi_thold = -127;
-               else
--                      rssi_thold = request->rssi_thold;
-+                      rssi_thold = request->min_rssi_thold;
-               ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
-                                                    rssi_thold);
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1316,7 +1316,7 @@ static bool ath9k_hw_set_reset(struct at
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               udelay(50);
-       else if (AR_SREV_9100(ah))
--              udelay(10000);
-+              mdelay(10);
-       else
-               udelay(100);
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
+  * buffer (or rx fifo). This can incorrectly acknowledge packets
+  * to a sender if last desc is self-linked.
+  */
+-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
++static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
++                          bool flush)
+ {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
+                            common->rx_bufsize,
+                            0);
+-      if (sc->rx.rxlink == NULL)
+-              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+-      else
++      if (sc->rx.rxlink)
+               *sc->rx.rxlink = bf->bf_daddr;
++      else if (!flush)
++              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+       sc->rx.rxlink = &ds->ds_link;
+ }
  
-@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
- bool ath9k_hw_check_alive(struct ath_hw *ah)
+-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
++static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
++                            bool flush)
  {
-       int count = 50;
--      u32 reg;
-+      u32 reg, last_val;
-       if (AR_SREV_9300(ah))
-               return !ath9k_hw_detect_mac_hang(ah);
-@@ -1542,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw 
-       if (AR_SREV_9285_12_OR_LATER(ah))
-               return true;
-+      last_val = REG_READ(ah, AR_OBS_BUS_1);
-       do {
-               reg = REG_READ(ah, AR_OBS_BUS_1);
-+              if (reg != last_val)
-+                      return true;
-+              udelay(1);
-+              last_val = reg;
-               if ((reg & 0x7E7FFFEF) == 0x00702400)
-                       continue;
-@@ -2051,9 +2056,8 @@ static bool ath9k_hw_set_power_awake(str
-       REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-                   AR_RTC_FORCE_WAKE_EN);
--
-       if (AR_SREV_9100(ah))
--              udelay(10000);
-+              mdelay(10);
-       else
-               udelay(50);
+       if (sc->rx.buf_hold)
+-              ath_rx_buf_link(sc, sc->rx.buf_hold);
++              ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
  
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data)
-                * interrupts are enabled in the reset routine.
-                */
-               atomic_inc(&ah->intr_ref_cnt);
--              ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
-+              ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
-               goto out;
+       sc->rx.buf_hold = bf;
+ }
+@@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
+       sc->rx.buf_hold = NULL;
+       sc->rx.rxlink = NULL;
+       list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
+-              ath_rx_buf_link(sc, bf);
++              ath_rx_buf_link(sc, bf, false);
        }
  
-@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data)
-                        * interrupts are enabled in the reset routine.
-                        */
-                       atomic_inc(&ah->intr_ref_cnt);
--                      ath_dbg(common, ANY,
-+                      ath_dbg(common, RESET,
-                               "BB_WATCHDOG: Skipping interrupts\n");
-                       goto out;
-               }
-@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data)
-                       type = RESET_TYPE_TX_GTT;
-                       ath9k_queue_reset(sc, type);
-                       atomic_inc(&ah->intr_ref_cnt);
--                      ath_dbg(common, ANY,
-+                      ath_dbg(common, RESET,
-                               "GTT: Skipping interrupts\n");
-                       goto out;
+       /* We could have deleted elements so the list may be empty now */
+@@ -1118,12 +1120,12 @@ requeue_drop_frag:
+ requeue:
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+-              if (edma) {
+-                      ath_rx_edma_buf_link(sc, qtype);
+-              } else {
+-                      ath_rx_buf_relink(sc, bf);
++              if (!edma) {
++                      ath_rx_buf_relink(sc, bf, flush);
+                       if (!flush)
+                               ath9k_hw_rxena(ah);
++              } else if (!flush) {
++                      ath_rx_edma_buf_link(sc, qtype);
                }
-@@ -1866,7 +1866,7 @@ static void ath9k_set_coverage_class(str
  
- static bool ath9k_has_tx_pending(struct ath_softc *sc)
- {
--      int i, npend;
-+      int i, npend = 0;
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-               if (!ATH_TXQ_SETUP(sc, i))
---- a/drivers/net/wireless/iwlwifi/mvm/scan.c
-+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
-@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(
-        * config match list.
-        */
-       for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
-+              /* skip empty SSID matchsets */
-+              if (!req->match_sets[i].ssid.ssid_len)
-+                      continue;
-               scan->direct_scan[i].id = WLAN_EID_SSID;
-               scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
-               memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
---- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
-+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
-@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80
-                       /* During testing, hdr was NULL */
-                       return false;
-               }
--              if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
-+              if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-                   (ieee80211_has_protected(hdr->frame_control)))
-                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
-               else
---- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
-+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
-@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80
-                       /* In testing, hdr was NULL here */
-                       return false;
-               }
--              if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
-+              if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-                   (ieee80211_has_protected(hdr->frame_control)))
-                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
-               else
---- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
-+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
-@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80
-                       /* during testing, hdr was NULL here */
-                       return false;
-               }
--              if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
-+              if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-                       (ieee80211_has_protected(hdr->frame_control)))
-                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
-               else
---- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
-+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
-@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee
-                       /* during testing, hdr could be NULL here */
-                       return false;
-               }
--              if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
-+              if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-                       (ieee80211_has_protected(hdr->frame_control)))
-                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
-               else
---- a/include/linux/ieee80211.h
-+++ b/include/linux/ieee80211.h
-@@ -597,6 +597,20 @@ static inline int ieee80211_is_qos_nullf
- }
+               if (!budget--)
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct 
+       struct ps_data *ps;
  
- /**
-+ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
-+ * @fc: frame control field in little-endian byteorder
-+ */
-+static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
-+{
-+      /* IEEE 802.11-2012, definition of "bufferable management frame";
-+       * note that this ignores the IBSS special case. */
-+      return ieee80211_is_mgmt(fc) &&
-+             (ieee80211_is_action(fc) ||
-+              ieee80211_is_disassoc(fc) ||
-+              ieee80211_is_deauth(fc));
-+}
-+
-+/**
-  * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
-  * @seq_ctrl: frame sequence control bytes in little-endian byteorder
-  */
-@@ -2192,10 +2206,10 @@ static inline u8 *ieee80211_get_DA(struc
- }
+       if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
+-          test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
++          test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
++          test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
+               if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
+                   sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       ps = &sdata->bss->ps;
+@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct 
  
- /**
-- * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
-+ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
-  * @hdr: the frame (buffer must include at least the first octet of payload)
-  */
--static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
-+static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
- {
-       if (ieee80211_is_disassoc(hdr->frame_control) ||
-           ieee80211_is_deauth(hdr->frame_control))
-@@ -2224,6 +2238,17 @@ static inline bool ieee80211_is_robust_m
- }
+               clear_sta_flag(sta, WLAN_STA_PS_STA);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++              clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
  
- /**
-+ * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame
-+ * @skb: the skb containing the frame, length will be checked
-+ */
-+static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
-+{
-+      if (skb->len < 25)
-+              return false;
-+      return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
-+}
-+
-+/**
-  * ieee80211_is_public_action - check if frame is a public action frame
-  * @hdr: the frame
-  * @len: length of the frame
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1395,9 +1395,11 @@ struct cfg80211_scan_request {
-  * struct cfg80211_match_set - sets of attributes to match
-  *
-  * @ssid: SSID to be matched
-+ * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
-  */
- struct cfg80211_match_set {
-       struct cfg80211_ssid ssid;
-+      s32 rssi_thold;
- };
+               atomic_dec(&ps->num_sta_ps);
+               sta_info_recalc_tim(sta);
+@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct 
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               mesh_sta_cleanup(sta);
  
- /**
-@@ -1420,7 +1422,8 @@ struct cfg80211_match_set {
-  * @dev: the interface
-  * @scan_start: start time of the scheduled scan
-  * @channels: channels to scan
-- * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
-+ * @min_rssi_thold: for drivers only supporting a single threshold, this
-+ *    contains the minimum over all matchsets
-  */
- struct cfg80211_sched_scan_request {
-       struct cfg80211_ssid *ssids;
-@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request {
-       u32 flags;
-       struct cfg80211_match_set *match_sets;
-       int n_match_sets;
--      s32 rssi_thold;
-+      s32 min_rssi_thold;
-       /* internal */
-       struct wiphy *wiphy;
-@@ -3130,8 +3133,8 @@ struct cfg80211_cached_keys;
-  * @identifier: (private) Identifier used in nl80211 to identify this
-  *    wireless device if it has no netdev
-  * @current_bss: (private) Used by the internal configuration code
-- * @channel: (private) Used by the internal configuration code to track
-- *    the user-set AP, monitor and WDS channel
-+ * @chandef: (private) Used by the internal configuration code to track
-+ *    the user-set channel definition.
-  * @preset_chandef: (private) Used by the internal configuration code to
-  *    track the channel to be used for AP later
-  * @bssid: (private) Used by the internal configuration code
-@@ -3195,9 +3198,7 @@ struct wireless_dev {
-       struct cfg80211_internal_bss *current_bss; /* associated / joined */
-       struct cfg80211_chan_def preset_chandef;
--
--      /* for AP and mesh channel tracking */
--      struct ieee80211_channel *channel;
-+      struct cfg80211_chan_def chandef;
+-      cancel_work_sync(&sta->drv_unblock_wk);
++      cancel_work_sync(&sta->drv_deliver_wk);
  
-       bool ibss_fixed;
-       bool ibss_dfs_possible;
-@@ -3879,6 +3880,7 @@ void cfg80211_michael_mic_failure(struct
-  *
-  * @dev: network device
-  * @bssid: the BSSID of the IBSS joined
-+ * @channel: the channel of the IBSS joined
-  * @gfp: allocation flags
-  *
-  * This function notifies cfg80211 that the device joined an IBSS or
-@@ -3888,7 +3890,8 @@ void cfg80211_michael_mic_failure(struct
-  * with the locally generated beacon -- this guarantees that there is
-  * always a scan result for this IBSS. cfg80211 will handle the rest.
+       /*
+        * Destroy aggregation state here. It would be nice to wait for the
+@@ -227,6 +229,7 @@ struct sta_info *sta_info_get_by_idx(str
   */
--void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
-+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
-+                        struct ieee80211_channel *channel, gfp_t gfp);
- /**
-  * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -2442,9 +2442,15 @@ enum nl80211_reg_rule_attr {
-  * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
-  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
-  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
-- * only report BSS with matching SSID.
-+ *    only report BSS with matching SSID.
-  * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
-- *    BSS in scan results. Filtering is turned off if not specified.
-+ *    BSS in scan results. Filtering is turned off if not specified. Note that
-+ *    if this attribute is in a match set of its own, then it is treated as
-+ *    the default value for all matchsets with an SSID, rather than being a
-+ *    matchset of its own without an RSSI filter. This is due to problems with
-+ *    how this API was implemented in the past. Also, due to the same problem,
-+ *    the only way to create a matchset with only an RSSI filter (with this
-+ *    attribute) is if there's only a single matchset with the RSSI attribute.
-  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
-  *    attribute number currently defined
-  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -107,7 +107,7 @@ static void ieee80211_send_addba_request
-       mgmt->u.action.u.addba_req.start_seq_num =
-                                       cpu_to_le16(start_seq_num << 4);
--      ieee80211_tx_skb_tid(sdata, skb, tid);
-+      ieee80211_tx_skb(sdata, skb);
- }
- void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wip
-       /* TODO: make hostapd tell us what it wants */
-       sdata->smps_mode = IEEE80211_SMPS_OFF;
-       sdata->needed_rx_chains = sdata->local->rx_chains;
--      sdata->radar_required = params->radar_required;
-       mutex_lock(&local->mtx);
-+      sdata->radar_required = params->radar_required;
-       err = ieee80211_vif_use_channel(sdata, &params->chandef,
-                                       IEEE80211_CHANCTX_SHARED);
-       mutex_unlock(&local->mtx);
-@@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wip
-                                       IEEE80211_P2P_OPPPS_ENABLE_BIT;
+ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
+ {
++      struct ieee80211_sta_rates *rates;
+       int i;
  
-       err = ieee80211_assign_beacon(sdata, &params->beacon);
--      if (err < 0)
-+      if (err < 0) {
-+              ieee80211_vif_release_channel(sdata);
-               return err;
-+      }
-       changed |= err;
-       err = drv_start_ap(sdata->local, sdata);
-@@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wip
-               if (old)
-                       kfree_rcu(old, rcu_head);
-               RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
-+              ieee80211_vif_release_channel(sdata);
-               return err;
+       if (sta->rate_ctrl)
+@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca
+               kfree(sta->tx_lat);
        }
  
-@@ -1053,6 +1056,7 @@ static int ieee80211_change_beacon(struc
-       int err;
++      rates = rcu_dereference_protected(sta->sta.rates, true);
++      if (rates)
++              kfree(rates);
++
+       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
  
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      sdata_assert_lock(sdata);
+       kfree(sta);
+@@ -252,33 +259,23 @@ static void sta_info_hash_add(struct iee
+       rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+ }
  
-       /* don't allow changing the beacon while CSA is in place - offset
-        * of channel switch counter may change
-@@ -1080,6 +1084,8 @@ static int ieee80211_stop_ap(struct wiph
-       struct probe_resp *old_probe_resp;
-       struct cfg80211_chan_def chandef;
+-static void sta_unblock(struct work_struct *wk)
++static void sta_deliver_ps_frames(struct work_struct *wk)
+ {
+       struct sta_info *sta;
  
-+      sdata_assert_lock(sdata);
-+
-       old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
-       if (!old_beacon)
-               return -ENOENT;
-@@ -1090,8 +1096,6 @@ static int ieee80211_stop_ap(struct wiph
-       kfree(sdata->u.ap.next_beacon);
-       sdata->u.ap.next_beacon = NULL;
+-      sta = container_of(wk, struct sta_info, drv_unblock_wk);
++      sta = container_of(wk, struct sta_info, drv_deliver_wk);
+       if (sta->dead)
+               return;
  
--      cancel_work_sync(&sdata->u.ap.request_smps_work);
+-      if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
+-              local_bh_disable();
++      local_bh_disable();
++      if (!test_sta_flag(sta, WLAN_STA_PS_STA))
+               ieee80211_sta_ps_deliver_wakeup(sta);
+-              local_bh_enable();
+-      } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
+-              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+-
+-              local_bh_disable();
++      else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL))
+               ieee80211_sta_ps_deliver_poll_response(sta);
+-              local_bh_enable();
+-      } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
+-              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
 -
-       /* turn off carrier for this interface and dependent VLANs */
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-               netif_carrier_off(vlan->dev);
-@@ -1103,6 +1107,7 @@ static int ieee80211_stop_ap(struct wiph
-       kfree_rcu(old_beacon, rcu_head);
-       if (old_probe_resp)
-               kfree_rcu(old_probe_resp, rcu_head);
-+      sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
+-              local_bh_disable();
++      else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD))
+               ieee80211_sta_ps_deliver_uapsd(sta);
+-              local_bh_enable();
+-      } else
+-              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++      local_bh_enable();
+ }
  
-       __sta_info_flush(sdata, true);
-       ieee80211_free_keys(sdata, true);
-@@ -1988,6 +1993,9 @@ static int ieee80211_change_bss(struct w
+ static int sta_prepare_rate_control(struct ieee80211_local *local,
+@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i
  
-       band = ieee80211_get_sdata_band(sdata);
+       spin_lock_init(&sta->lock);
+       spin_lock_init(&sta->ps_lock);
+-      INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
++      INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
+       INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+       mutex_init(&sta->ampdu_mlme.mtx);
+ #ifdef CPTCFG_MAC80211_MESH
+@@ -1140,8 +1137,15 @@ void ieee80211_sta_ps_deliver_wakeup(str
+       }
  
-+      if (WARN_ON(!wiphy->bands[band]))
-+              return -EINVAL;
+       ieee80211_add_pending_skbs(local, &pending);
+-      clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+-      clear_sta_flag(sta, WLAN_STA_PS_STA);
 +
-       if (params->use_cts_prot >= 0) {
-               sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
-               changed |= BSS_CHANGED_ERP_CTS_PROT;
-@@ -2638,6 +2646,24 @@ static int ieee80211_start_roc_work(stru
-       INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
-       INIT_LIST_HEAD(&roc->dependents);
-+      /*
-+       * cookie is either the roc cookie (for normal roc)
-+       * or the SKB (for mgmt TX)
-+       */
-+      if (!txskb) {
-+              /* local->mtx protects this */
-+              local->roc_cookie_counter++;
-+              roc->cookie = local->roc_cookie_counter;
-+              /* wow, you wrapped 64 bits ... more likely a bug */
-+              if (WARN_ON(roc->cookie == 0)) {
-+                      roc->cookie = 1;
-+                      local->roc_cookie_counter++;
-+              }
-+              *cookie = roc->cookie;
-+      } else {
-+              *cookie = (unsigned long)txskb;
-+      }
++      /* now we're no longer in the deliver code */
++      clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
 +
-       /* if there's one pending or we're scanning, queue this one */
-       if (!list_empty(&local->roc_list) ||
-           local->scanning || local->radar_detect_enabled)
-@@ -2772,24 +2798,6 @@ static int ieee80211_start_roc_work(stru
-       if (!queued)
-               list_add_tail(&roc->list, &local->roc_list);
++      /* The station might have polled and then woken up before we responded,
++       * so clear these flags now to avoid them sticking around.
++       */
++      clear_sta_flag(sta, WLAN_STA_PSPOLL);
++      clear_sta_flag(sta, WLAN_STA_UAPSD);
+       spin_unlock(&sta->ps_lock);
  
--      /*
--       * cookie is either the roc cookie (for normal roc)
--       * or the SKB (for mgmt TX)
--       */
--      if (!txskb) {
--              /* local->mtx protects this */
--              local->roc_cookie_counter++;
--              roc->cookie = local->roc_cookie_counter;
--              /* wow, you wrapped 64 bits ... more likely a bug */
--              if (WARN_ON(roc->cookie == 0)) {
--                      roc->cookie = 1;
--                      local->roc_cookie_counter++;
--              }
--              *cookie = roc->cookie;
--      } else {
--              *cookie = (unsigned long)txskb;
--      }
--
-       return 0;
- }
+       atomic_dec(&ps->num_sta_ps);
+@@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie
  
-@@ -3004,8 +3012,10 @@ void ieee80211_csa_finalize_work(struct 
-       if (!ieee80211_sdata_running(sdata))
-               goto unlock;
+       trace_api_sta_block_awake(sta->local, pubsta, block);
  
--      sdata->radar_required = sdata->csa_radar_required;
-+      sdata_assert_lock(sdata);
+-      if (block)
++      if (block) {
+               set_sta_flag(sta, WLAN_STA_PS_DRIVER);
+-      else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
+-              ieee80211_queue_work(hw, &sta->drv_unblock_wk);
++              return;
++      }
 +
-       mutex_lock(&local->mtx);
-+      sdata->radar_required = sdata->csa_radar_required;
-       err = ieee80211_vif_change_channel(sdata, &changed);
-       mutex_unlock(&local->mtx);
-       if (WARN_ON(err < 0))
-@@ -3022,13 +3032,13 @@ void ieee80211_csa_finalize_work(struct 
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-               err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
-+              kfree(sdata->u.ap.next_beacon);
-+              sdata->u.ap.next_beacon = NULL;
++      if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
++              return;
 +
-               if (err < 0)
-                       goto unlock;
-               changed |= err;
--              kfree(sdata->u.ap.next_beacon);
--              sdata->u.ap.next_beacon = NULL;
--
-               ieee80211_bss_info_change_notify(sdata, err);
-               break;
-       case NL80211_IFTYPE_ADHOC:
-@@ -3066,7 +3076,7 @@ int ieee80211_channel_switch(struct wiph
-       struct ieee80211_if_mesh __maybe_unused *ifmsh;
-       int err, num_chanctx;
--      lockdep_assert_held(&sdata->wdev.mtx);
-+      sdata_assert_lock(sdata);
-       if (!list_empty(&local->roc_list) || local->scanning)
-               return -EBUSY;
---- a/net/mac80211/ht.c
-+++ b/net/mac80211/ht.c
-@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee802
-       mgmt->u.action.u.delba.params = cpu_to_le16(params);
-       mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
--      ieee80211_tx_skb_tid(sdata, skb, tid);
-+      ieee80211_tx_skb(sdata, skb);
++      if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
++              set_sta_flag(sta, WLAN_STA_PS_DELIVER);
++              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++              ieee80211_queue_work(hw, &sta->drv_deliver_wk);
++      } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) ||
++                 test_sta_flag(sta, WLAN_STA_UAPSD)) {
++              /* must be asleep in this case */
++              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++              ieee80211_queue_work(hw, &sta->drv_deliver_wk);
++      } else {
++              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++      }
  }
+ EXPORT_SYMBOL(ieee80211_sta_block_awake);
  
- void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
-@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(stru
-                            u.ap.request_smps_work);
-       sdata_lock(sdata);
--      __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
-+      if (sdata_dereference(sdata->u.ap.beacon, sdata))
-+              __ieee80211_request_smps_ap(sdata,
-+                                          sdata->u.ap.driver_smps_mode);
-       sdata_unlock(sdata);
+@@ -1703,3 +1723,140 @@ u8 sta_info_tx_streams(struct sta_info *
+       return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+                       >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
  }
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -770,12 +770,19 @@ static void ieee80211_do_stop(struct iee
-       ieee80211_roc_purge(local, sdata);
--      if (sdata->vif.type == NL80211_IFTYPE_STATION)
-+      switch (sdata->vif.type) {
-+      case NL80211_IFTYPE_STATION:
-               ieee80211_mgd_stop(sdata);
--
--      if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
-+              break;
-+      case NL80211_IFTYPE_ADHOC:
-               ieee80211_ibss_stop(sdata);
--
-+              break;
-+      case NL80211_IFTYPE_AP:
-+              cancel_work_sync(&sdata->u.ap.request_smps_work);
-+              break;
-+      default:
-+              break;
++
++void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
++{
++      struct ieee80211_sub_if_data *sdata = sta->sdata;
++      struct ieee80211_local *local = sdata->local;
++      struct rate_control_ref *ref = NULL;
++      struct timespec uptime;
++      u64 packets = 0;
++      u32 thr = 0;
++      int i, ac;
++
++      if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
++              ref = local->rate_ctrl;
++
++      sinfo->generation = sdata->local->sta_generation;
++
++      sinfo->filled = STATION_INFO_INACTIVE_TIME |
++                      STATION_INFO_RX_BYTES64 |
++                      STATION_INFO_TX_BYTES64 |
++                      STATION_INFO_RX_PACKETS |
++                      STATION_INFO_TX_PACKETS |
++                      STATION_INFO_TX_RETRIES |
++                      STATION_INFO_TX_FAILED |
++                      STATION_INFO_TX_BITRATE |
++                      STATION_INFO_RX_BITRATE |
++                      STATION_INFO_RX_DROP_MISC |
++                      STATION_INFO_BSS_PARAM |
++                      STATION_INFO_CONNECTED_TIME |
++                      STATION_INFO_STA_FLAGS |
++                      STATION_INFO_BEACON_LOSS_COUNT;
++
++      do_posix_clock_monotonic_gettime(&uptime);
++      sinfo->connected_time = uptime.tv_sec - sta->last_connected;
++
++      sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
++      sinfo->tx_bytes = 0;
++      for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++              sinfo->tx_bytes += sta->tx_bytes[ac];
++              packets += sta->tx_packets[ac];
 +      }
++      sinfo->tx_packets = packets;
++      sinfo->rx_bytes = sta->rx_bytes;
++      sinfo->rx_packets = sta->rx_packets;
++      sinfo->tx_retries = sta->tx_retry_count;
++      sinfo->tx_failed = sta->tx_retry_failed;
++      sinfo->rx_dropped_misc = sta->rx_dropped;
++      sinfo->beacon_loss_count = sta->beacon_loss_count;
++
++      if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
++          (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
++              sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
++              if (!local->ops->get_rssi ||
++                  drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
++                      sinfo->signal = (s8)sta->last_signal;
++              sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
++      }
++      if (sta->chains) {
++              sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
++                               STATION_INFO_CHAIN_SIGNAL_AVG;
++
++              sinfo->chains = sta->chains;
++              for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
++                      sinfo->chain_signal[i] = sta->chain_signal_last[i];
++                      sinfo->chain_signal_avg[i] =
++                              (s8) -ewma_read(&sta->chain_signal_avg[i]);
++              }
++      }
++
++      sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
++      sta_set_rate_info_rx(sta, &sinfo->rxrate);
++
++      if (ieee80211_vif_is_mesh(&sdata->vif)) {
++#ifdef CPTCFG_MAC80211_MESH
++              sinfo->filled |= STATION_INFO_LLID |
++                               STATION_INFO_PLID |
++                               STATION_INFO_PLINK_STATE |
++                               STATION_INFO_LOCAL_PM |
++                               STATION_INFO_PEER_PM |
++                               STATION_INFO_NONPEER_PM;
++
++              sinfo->llid = sta->llid;
++              sinfo->plid = sta->plid;
++              sinfo->plink_state = sta->plink_state;
++              if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
++                      sinfo->filled |= STATION_INFO_T_OFFSET;
++                      sinfo->t_offset = sta->t_offset;
++              }
++              sinfo->local_pm = sta->local_pm;
++              sinfo->peer_pm = sta->peer_pm;
++              sinfo->nonpeer_pm = sta->nonpeer_pm;
++#endif
++      }
++
++      sinfo->bss_param.flags = 0;
++      if (sdata->vif.bss_conf.use_cts_prot)
++              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
++      if (sdata->vif.bss_conf.use_short_preamble)
++              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
++      if (sdata->vif.bss_conf.use_short_slot)
++              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
++      sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
++      sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
++
++      sinfo->sta_flags.set = 0;
++      sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
++                              BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
++                              BIT(NL80211_STA_FLAG_WME) |
++                              BIT(NL80211_STA_FLAG_MFP) |
++                              BIT(NL80211_STA_FLAG_AUTHENTICATED) |
++                              BIT(NL80211_STA_FLAG_ASSOCIATED) |
++                              BIT(NL80211_STA_FLAG_TDLS_PEER);
++      if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
++      if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
++      if (test_sta_flag(sta, WLAN_STA_WME))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
++      if (test_sta_flag(sta, WLAN_STA_MFP))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
++      if (test_sta_flag(sta, WLAN_STA_AUTH))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
++      if (test_sta_flag(sta, WLAN_STA_ASSOC))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
++      if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
++              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
++
++      /* check if the driver has a SW RC implementation */
++      if (ref && ref->ops->get_expected_throughput)
++              thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
++      else
++              thr = drv_get_expected_throughput(local, &sta->sta);
++
++      if (thr != 0) {
++              sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
++              sinfo->expected_throughput = thr;
++      }
++}
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
+  */
+ #define STA_LOST_PKT_THRESHOLD        50
  
-       /*
-        * Remove all stations associated with this interface.
-@@ -827,7 +834,9 @@ static void ieee80211_do_stop(struct iee
-       cancel_work_sync(&local->dynamic_ps_enable_work);
-       cancel_work_sync(&sdata->recalc_smps);
-+      sdata_lock(sdata);
-       sdata->vif.csa_active = false;
-+      sdata_unlock(sdata);
-       cancel_work_sync(&sdata->csa_finalize_work);
++static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
++{
++      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++
++      /* This packet was aggregated but doesn't carry status info */
++      if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
++          !(info->flags & IEEE80211_TX_STAT_AMPDU))
++              return;
++
++      if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
++              return;
++
++      cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
++                                  sta->lost_packets, GFP_ATOMIC);
++      sta->lost_packets = 0;
++}
++
+ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+ {
+       struct sk_buff *skb2;
+@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
+                       if (info->flags & IEEE80211_TX_STAT_ACK) {
+                               if (sta->lost_packets)
+                                       sta->lost_packets = 0;
+-                      } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
+-                              cfg80211_cqm_pktloss_notify(sta->sdata->dev,
+-                                                          sta->sta.addr,
+-                                                          sta->lost_packets,
+-                                                          GFP_ATOMIC);
+-                              sta->lost_packets = 0;
++                      } else {
++                              ieee80211_lost_packet(sta, skb);
+                       }
+               }
  
-       cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -599,10 +599,10 @@ static int ieee80211_is_unicast_robust_m
- {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
--      if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1))
-+      if (is_multicast_ether_addr(hdr->addr1))
-               return 0;
+@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *
+               return;
+       }
  
--      return ieee80211_is_robust_mgmt_frame(hdr);
-+      return ieee80211_is_robust_mgmt_frame(skb);
++      set_sta_flag(sta, WLAN_STA_PS_DELIVER);
++      clear_sta_flag(sta, WLAN_STA_PS_STA);
+       ieee80211_sta_ps_deliver_wakeup(sta);
  }
  
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags {
+       WLAN_STA_TOFFSET_KNOWN,
+       WLAN_STA_MPSP_OWNER,
+       WLAN_STA_MPSP_RECIPIENT,
++      WLAN_STA_PS_DELIVER,
+ };
+ #define ADDBA_RESP_INTERVAL HZ
+@@ -265,7 +266,7 @@ struct ieee80211_tx_latency_stat {
+  * @last_rx_rate_vht_nss: rx status nss of last data packet
+  * @lock: used for locking all fields that require locking, see comments
+  *    in the header file.
+- * @drv_unblock_wk: used for driver PS unblocking
++ * @drv_deliver_wk: used for delivering frames after driver PS unblocking
+  * @listen_interval: listen interval of this station, when we're acting as AP
+  * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+  * @ps_lock: used for powersave (when mac80211 is the AP) related locking
+@@ -278,7 +279,6 @@ struct ieee80211_tx_latency_stat {
+  * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
+  * @rx_packets: Number of MSDUs received from this STA
+  * @rx_bytes: Number of bytes received from this STA
+- * @wep_weak_iv_count: number of weak WEP IVs received from this station
+  * @last_rx: time (in jiffies) when last frame was received from this STA
+  * @last_connected: time (in seconds) when a station got connected
+  * @num_duplicates: number of duplicate frames received from this STA
+@@ -345,7 +345,7 @@ struct sta_info {
+       void *rate_ctrl_priv;
+       spinlock_t lock;
+-      struct work_struct drv_unblock_wk;
++      struct work_struct drv_deliver_wk;
+       u16 listen_interval;
+@@ -367,7 +367,6 @@ struct sta_info {
+       /* Updated from RX path only, no locking requirements */
+       unsigned long rx_packets;
+       u64 rx_bytes;
+-      unsigned long wep_weak_iv_count;
+       unsigned long last_rx;
+       long last_connected;
+       unsigned long num_duplicates;
+@@ -628,6 +627,8 @@ void sta_set_rate_info_tx(struct sta_inf
+                         struct rate_info *rinfo);
+ void sta_set_rate_info_rx(struct sta_info *sta,
+                         struct rate_info *rinfo);
++void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo);
++
+ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+                         unsigned long exp_time);
+ u8 sta_info_tx_streams(struct sta_info *sta);
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+               return TX_CONTINUE;
  
-@@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust
- {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
+-                    test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
++                    test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
++                    test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
+                    !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
+               int ac = skb_get_queue_mapping(tx->skb);
  
--      if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1))
-+      if (!is_multicast_ether_addr(hdr->addr1))
-               return 0;
+@@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
+                * ahead and Tx the packet.
+                */
+               if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
+-                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
++                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
++                  !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
+                       spin_unlock(&sta->ps_lock);
+                       return TX_CONTINUE;
+               }
+@@ -1618,12 +1620,12 @@ netdev_tx_t ieee80211_monitor_start_xmit
+ {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_chanctx_conf *chanctx_conf;
+-      struct ieee80211_channel *chan;
+       struct ieee80211_radiotap_header *prthdr =
+               (struct ieee80211_radiotap_header *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_sub_if_data *tmp_sdata, *sdata;
++      struct cfg80211_chan_def *chandef;
+       u16 len_rthdr;
+       int hdrlen;
  
--      return ieee80211_is_robust_mgmt_frame(hdr);
-+      return ieee80211_is_robust_mgmt_frame(skb);
- }
+@@ -1721,9 +1723,9 @@ netdev_tx_t ieee80211_monitor_start_xmit
+       }
  
+       if (chanctx_conf)
+-              chan = chanctx_conf->def.chan;
++              chandef = &chanctx_conf->def;
+       else if (!local->use_chanctx)
+-              chan = local->_oper_chandef.chan;
++              chandef = &local->_oper_chandef;
+       else
+               goto fail_rcu;
  
-@@ -626,7 +626,7 @@ static int ieee80211_get_mmie_keyidx(str
-       if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
-               return -1;
+@@ -1743,10 +1745,11 @@ netdev_tx_t ieee80211_monitor_start_xmit
+        * radar detection by itself. We can do that later by adding a
+        * monitor flag interfaces used for AP support.
+        */
+-      if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)))
++      if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef,
++                                   sdata->vif.type))
+               goto fail_rcu;
  
--      if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
-+      if (!ieee80211_is_robust_mgmt_frame(skb))
-               return -1; /* not a robust management frame */
+-      ieee80211_xmit(sdata, skb, chan->band);
++      ieee80211_xmit(sdata, skb, chandef->chan->band);
+       rcu_read_unlock();
  
-       mmie = (struct ieee80211_mmie *)
-@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *
-              sta->sta.addr, sta->sta.aid);
+       return NETDEV_TX_OK;
+@@ -2425,7 +2428,7 @@ static void ieee80211_set_csa(struct iee
+       u8 *beacon_data;
+       size_t beacon_data_len;
+       int i;
+-      u8 count = sdata->csa_current_counter;
++      u8 count = beacon->csa_current_counter;
  
-       if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-+              /*
-+               * Clear the flag only if the other one is still set
-+               * so that the TX path won't start TX'ing new frames
-+               * directly ... In the case that the driver flag isn't
-+               * set ieee80211_sta_ps_deliver_wakeup() will clear it.
-+               */
-+              clear_sta_flag(sta, WLAN_STA_PS_STA);
-               ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
-                      sta->sta.addr, sta->sta.aid);
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+@@ -2444,46 +2447,54 @@ static void ieee80211_set_csa(struct iee
                return;
-@@ -1311,18 +1318,15 @@ ieee80211_rx_h_sta_process(struct ieee80
-           !ieee80211_has_morefrags(hdr->frame_control) &&
-           !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
-           (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
--           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
-+           rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
-+          /* PM bit is only checked in frames where it isn't reserved,
-+           * in AP mode it's reserved in non-bufferable management frames
-+           * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field)
-+           */
-+          (!ieee80211_is_mgmt(hdr->frame_control) ||
-+           ieee80211_is_bufferable_mmpdu(hdr->frame_control))) {
-               if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
--                      /*
--                       * Ignore doze->wake transitions that are
--                       * indicated by non-data frames, the standard
--                       * is unclear here, but for example going to
--                       * PS mode and then scanning would cause a
--                       * doze->wake transition for the probe request,
--                       * and that is clearly undesirable.
--                       */
--                      if (ieee80211_is_data(hdr->frame_control) &&
--                          !ieee80211_has_pm(hdr->frame_control))
-+                      if (!ieee80211_has_pm(hdr->frame_control))
-                               sta_ps_end(sta);
-               } else {
-                       if (ieee80211_has_pm(hdr->frame_control))
-@@ -1845,8 +1849,7 @@ static int ieee80211_drop_unencrypted_mg
-                * having configured keys.
-                */
-               if (unlikely(ieee80211_is_action(fc) && !rx->key &&
--                           ieee80211_is_robust_mgmt_frame(
--                                   (struct ieee80211_hdr *) rx->skb->data)))
-+                           ieee80211_is_robust_mgmt_frame(rx->skb)))
-                       return -EACCES;
        }
  
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, 
-       if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
-               return 0;
--      if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
--                                          skb->data))
-+      if (!ieee80211_is_robust_mgmt_frame(skb))
-               return 0;
-       return 1;
-@@ -478,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
-                      sta->sta.addr, sta->sta.aid, ac);
-               if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
-                       purge_old_ps_buffers(tx->local);
-+
-+              /* sync with ieee80211_sta_ps_deliver_wakeup */
-+              spin_lock(&sta->ps_lock);
-+              /*
-+               * STA woke up the meantime and all the frames on ps_tx_buf have
-+               * been queued to pending queue. No reordering can happen, go
-+               * ahead and Tx the packet.
-+               */
-+              if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
-+                  !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-+                      spin_unlock(&sta->ps_lock);
-+                      return TX_CONTINUE;
-+              }
++      rcu_read_lock();
+       for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) {
+-              u16 counter_offset_beacon =
+-                      sdata->csa_counter_offset_beacon[i];
+-              u16 counter_offset_presp = sdata->csa_counter_offset_presp[i];
+-
+-              if (counter_offset_beacon) {
+-                      if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+-                              return;
+-
+-                      beacon_data[counter_offset_beacon] = count;
+-              }
+-
+-              if (sdata->vif.type == NL80211_IFTYPE_AP &&
+-                  counter_offset_presp) {
+-                      rcu_read_lock();
+-                      resp = rcu_dereference(sdata->u.ap.probe_resp);
++              resp = rcu_dereference(sdata->u.ap.probe_resp);
+-                      /* If nl80211 accepted the offset, this should
+-                       * not happen.
+-                       */
+-                      if (WARN_ON(!resp)) {
++              if (beacon->csa_counter_offsets[i]) {
++                      if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >=
++                                       beacon_data_len)) {
+                               rcu_read_unlock();
+                               return;
+                       }
+-                      resp->data[counter_offset_presp] = count;
+-                      rcu_read_unlock();
 +
-               if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
-                       struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
-                       ps_dbg(tx->sdata,
-@@ -492,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
-               info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
-               info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
-               skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
-+              spin_unlock(&sta->ps_lock);
-               if (!timer_pending(&local->sta_cleanup))
-                       mod_timer(&local->sta_cleanup,
-@@ -525,9 +539,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t
-       /* only deauth, disassoc and action are bufferable MMPDUs */
-       if (ieee80211_is_mgmt(hdr->frame_control) &&
--          !ieee80211_is_deauth(hdr->frame_control) &&
--          !ieee80211_is_disassoc(hdr->frame_control) &&
--          !ieee80211_is_action(hdr->frame_control)) {
-+          !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
-               if (tx->flags & IEEE80211_TX_UNICAST)
-                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
-               return TX_CONTINUE;
-@@ -567,7 +579,7 @@ ieee80211_tx_h_select_key(struct ieee802
-               tx->key = key;
-       else if (ieee80211_is_mgmt(hdr->frame_control) &&
-                is_multicast_ether_addr(hdr->addr1) &&
--               ieee80211_is_robust_mgmt_frame(hdr) &&
-+               ieee80211_is_robust_mgmt_frame(tx->skb) &&
-                (key = rcu_dereference(tx->sdata->default_mgmt_key)))
-               tx->key = key;
-       else if (is_multicast_ether_addr(hdr->addr1) &&
-@@ -582,12 +594,12 @@ ieee80211_tx_h_select_key(struct ieee802
-               tx->key = NULL;
-       else if (tx->skb->protocol == tx->sdata->control_port_protocol)
-               tx->key = NULL;
--      else if (ieee80211_is_robust_mgmt_frame(hdr) &&
-+      else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
-                !(ieee80211_is_action(hdr->frame_control) &&
-                  tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
-               tx->key = NULL;
-       else if (ieee80211_is_mgmt(hdr->frame_control) &&
--               !ieee80211_is_robust_mgmt_frame(hdr))
-+               !ieee80211_is_robust_mgmt_frame(tx->skb))
-               tx->key = NULL;
-       else {
-               I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-@@ -878,7 +890,7 @@ static int ieee80211_fragment(struct iee
++                      beacon_data[beacon->csa_counter_offsets[i]] = count;
+               }
++
++              if (sdata->vif.type == NL80211_IFTYPE_AP && resp &&
++                  resp->csa_counter_offsets)
++                      resp->data[resp->csa_counter_offsets[i]] = count;
        }
++      rcu_read_unlock();
+ }
  
-       /* adjust first fragment's length */
--      skb->len = hdrlen + per_fragm;
-+      skb_trim(skb, hdrlen + per_fragm);
-       return 0;
+ u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif)
+ {
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
++      struct beacon_data *beacon = NULL;
++      u8 count = 0;
++
++      rcu_read_lock();
++
++      if (sdata->vif.type == NL80211_IFTYPE_AP)
++              beacon = rcu_dereference(sdata->u.ap.beacon);
++      else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++              beacon = rcu_dereference(sdata->u.ibss.presp);
++      else if (ieee80211_vif_is_mesh(&sdata->vif))
++              beacon = rcu_dereference(sdata->u.mesh.beacon);
++
++      if (!beacon)
++              goto unlock;
+-      sdata->csa_current_counter--;
++      beacon->csa_current_counter--;
+       /* the counter should never reach 0 */
+-      WARN_ON(!sdata->csa_current_counter);
++      WARN_ON_ONCE(!beacon->csa_current_counter);
++      count = beacon->csa_current_counter;
+-      return sdata->csa_current_counter;
++unlock:
++      rcu_read_unlock();
++      return count;
  }
+ EXPORT_SYMBOL(ieee80211_csa_update_counter);
  
-@@ -2900,7 +2912,7 @@ ieee80211_get_buffered_bc(struct ieee802
-                               cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-               }
+@@ -2493,7 +2504,6 @@ bool ieee80211_csa_is_complete(struct ie
+       struct beacon_data *beacon = NULL;
+       u8 *beacon_data;
+       size_t beacon_data_len;
+-      int counter_beacon = sdata->csa_counter_offset_beacon[0];
+       int ret = false;
  
--              if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-+              if (sdata->vif.type == NL80211_IFTYPE_AP)
-                       sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
-               if (!ieee80211_tx_prepare(sdata, &tx, skb))
-                       break;
---- a/net/mac80211/wpa.c
-+++ b/net/mac80211/wpa.c
-@@ -499,7 +499,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       if (!ieee80211_is_data(hdr->frame_control) &&
--          !ieee80211_is_robust_mgmt_frame(hdr))
-+          !ieee80211_is_robust_mgmt_frame(skb))
-               return RX_CONTINUE;
-       data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN -
---- a/net/wireless/ap.c
-+++ b/net/wireless/ap.c
-@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg
-       err = rdev_stop_ap(rdev, dev);
-       if (!err) {
-               wdev->beacon_interval = 0;
--              wdev->channel = NULL;
-+              memset(&wdev->chandef, 0, sizeof(wdev->chandef));
-               wdev->ssid_len = 0;
-               rdev_set_qos_map(rdev, dev, NULL);
-+              nl80211_send_ap_stopped(wdev);
+       if (!ieee80211_sdata_running(sdata))
+@@ -2531,10 +2541,13 @@ bool ieee80211_csa_is_complete(struct ie
+               goto out;
        }
  
-       return err;
---- a/net/wireless/core.c
-+++ b/net/wireless/core.c
-@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg
-       rdev->opencount--;
+-      if (WARN_ON(counter_beacon > beacon_data_len))
++      if (!beacon->csa_counter_offsets[0])
++              goto out;
++
++      if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len))
+               goto out;
  
--      WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
--              !rdev->scan_req->notified);
-+      if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
-+              if (WARN_ON(!rdev->scan_req->notified))
-+                      rdev->scan_req->aborted = true;
-+              ___cfg80211_scan_done(rdev, false);
-+      }
- }
+-      if (beacon_data[counter_beacon] == 1)
++      if (beacon_data[beacon->csa_counter_offsets[0]] == 1)
+               ret = true;
+  out:
+       rcu_read_unlock();
+@@ -2550,6 +2563,7 @@ __ieee80211_beacon_get(struct ieee80211_
+                      bool is_template)
+ {
+       struct ieee80211_local *local = hw_to_local(hw);
++      struct beacon_data *beacon = NULL;
+       struct sk_buff *skb = NULL;
+       struct ieee80211_tx_info *info;
+       struct ieee80211_sub_if_data *sdata = NULL;
+@@ -2571,10 +2585,10 @@ __ieee80211_beacon_get(struct ieee80211_
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct ieee80211_if_ap *ap = &sdata->u.ap;
+-              struct beacon_data *beacon = rcu_dereference(ap->beacon);
++              beacon = rcu_dereference(ap->beacon);
+               if (beacon) {
+-                      if (sdata->vif.csa_active) {
++                      if (beacon->csa_counter_offsets[0]) {
+                               if (!is_template)
+                                       ieee80211_csa_update_counter(vif);
+@@ -2615,37 +2629,37 @@ __ieee80211_beacon_get(struct ieee80211_
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+               struct ieee80211_hdr *hdr;
+-              struct beacon_data *presp = rcu_dereference(ifibss->presp);
+-              if (!presp)
++              beacon = rcu_dereference(ifibss->presp);
++              if (!beacon)
+                       goto out;
  
- static int cfg80211_rfkill_set_block(void *data, bool blocked)
-@@ -447,9 +450,6 @@ int wiphy_register(struct wiphy *wiphy)
-       int i;
-       u16 ifmodes = wiphy->interface_modes;
+-              if (sdata->vif.csa_active) {
++              if (beacon->csa_counter_offsets[0]) {
+                       if (!is_template)
+                               ieee80211_csa_update_counter(vif);
  
--      /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
--      wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
--
-       /*
-        * There are major locking problems in nl80211/mac80211 for CSA,
-        * disable for all drivers until this has been reworked.
-@@ -795,8 +795,6 @@ void cfg80211_leave(struct cfg80211_regi
-       default:
-               break;
-       }
--
--      wdev->beacon_interval = 0;
- }
+-                      ieee80211_set_csa(sdata, presp);
++                      ieee80211_set_csa(sdata, beacon);
+               }
  
- static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
-@@ -875,8 +873,11 @@ static int cfg80211_netdev_notifier_call
-               break;
-       case NETDEV_DOWN:
-               cfg80211_update_iface_num(rdev, wdev->iftype, -1);
--              WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
--                      !rdev->scan_req->notified);
-+              if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
-+                      if (WARN_ON(!rdev->scan_req->notified))
-+                              rdev->scan_req->aborted = true;
-+                      ___cfg80211_scan_done(rdev, false);
-+              }
+-              skb = dev_alloc_skb(local->tx_headroom + presp->head_len +
++              skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+                                   local->hw.extra_beacon_tailroom);
+               if (!skb)
+                       goto out;
+               skb_reserve(skb, local->tx_headroom);
+-              memcpy(skb_put(skb, presp->head_len), presp->head,
+-                     presp->head_len);
++              memcpy(skb_put(skb, beacon->head_len), beacon->head,
++                     beacon->head_len);
+               hdr = (struct ieee80211_hdr *) skb->data;
+               hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                                IEEE80211_STYPE_BEACON);
+       } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+               struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+-              struct beacon_data *bcn = rcu_dereference(ifmsh->beacon);
+-              if (!bcn)
++              beacon = rcu_dereference(ifmsh->beacon);
++              if (!beacon)
+                       goto out;
  
-               if (WARN_ON(rdev->sched_scan_req &&
-                           rdev->sched_scan_req->dev == wdev->netdev)) {
---- a/net/wireless/core.h
-+++ b/net/wireless/core.h
-@@ -62,6 +62,7 @@ struct cfg80211_registered_device {
-       struct rb_root bss_tree;
-       u32 bss_generation;
-       struct cfg80211_scan_request *scan_req; /* protected by RTNL */
-+      struct sk_buff *scan_msg;
-       struct cfg80211_sched_scan_request *sched_scan_req;
-       unsigned long suspend_at;
-       struct work_struct scan_done_wk;
-@@ -210,6 +211,7 @@ struct cfg80211_event {
-               } dc;
-               struct {
-                       u8 bssid[ETH_ALEN];
-+                      struct ieee80211_channel *channel;
-               } ij;
-       };
- };
-@@ -257,7 +259,8 @@ int __cfg80211_leave_ibss(struct cfg8021
-                         struct net_device *dev, bool nowext);
- int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
-                       struct net_device *dev, bool nowext);
--void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
-+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
-+                          struct ieee80211_channel *channel);
- int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
-                           struct wireless_dev *wdev);
-@@ -361,7 +364,8 @@ int cfg80211_validate_key_settings(struc
-                                  struct key_params *params, int key_idx,
-                                  bool pairwise, const u8 *mac_addr);
- void __cfg80211_scan_done(struct work_struct *wk);
--void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
-+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
-+                         bool send_message);
- void __cfg80211_sched_scan_results(struct work_struct *wk);
- int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
-                              bool driver_initiated);
-@@ -441,7 +445,8 @@ static inline unsigned int elapsed_jiffi
- void
- cfg80211_get_chan_state(struct wireless_dev *wdev,
-                       struct ieee80211_channel **chan,
--                      enum cfg80211_chan_mode *chanmode);
-+                      enum cfg80211_chan_mode *chanmode,
-+                      u8 *radar_detect);
- int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
-                                struct cfg80211_chan_def *chandef);
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -1723,9 +1723,10 @@ static int nl80211_dump_wiphy(struct sk_
-                                * We can then retry with the larger buffer.
+-              if (sdata->vif.csa_active) {
++              if (beacon->csa_counter_offsets[0]) {
+                       if (!is_template)
+                               /* TODO: For mesh csa_counter is in TU, so
+                                * decrementing it by one isn't correct, but
+@@ -2654,40 +2668,42 @@ __ieee80211_beacon_get(struct ieee80211_
                                 */
-                               if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
--                                  !skb->len &&
-+                                  !skb->len && !state->split &&
-                                   cb->min_dump_alloc < 4096) {
-                                       cb->min_dump_alloc = 4096;
-+                                      state->split_start = 0;
-                                       rtnl_unlock();
-                                       return 1;
-                               }
-@@ -2047,10 +2048,12 @@ static int nl80211_set_wiphy(struct sk_b
-               nla_for_each_nested(nl_txq_params,
-                                   info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
-                                   rem_txq_params) {
--                      nla_parse(tb, NL80211_TXQ_ATTR_MAX,
--                                nla_data(nl_txq_params),
--                                nla_len(nl_txq_params),
--                                txq_params_policy);
-+                      result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
-+                                         nla_data(nl_txq_params),
-+                                         nla_len(nl_txq_params),
-+                                         txq_params_policy);
-+                      if (result)
-+                              goto bad_res;
-                       result = parse_txq_params(tb, &txq_params);
-                       if (result)
-                               goto bad_res;
-@@ -3289,7 +3292,7 @@ static int nl80211_start_ap(struct sk_bu
-       if (!err) {
-               wdev->preset_chandef = params.chandef;
-               wdev->beacon_interval = params.beacon_interval;
--              wdev->channel = params.chandef.chan;
-+              wdev->chandef = params.chandef;
-               wdev->ssid_len = params.ssid_len;
-               memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
-       }
-@@ -5210,9 +5213,11 @@ static int nl80211_set_reg(struct sk_buf
-       nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
-                           rem_reg_rules) {
--              nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
--                        nla_data(nl_reg_rule), nla_len(nl_reg_rule),
--                        reg_rule_policy);
-+              r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
-+                            nla_data(nl_reg_rule), nla_len(nl_reg_rule),
-+                            reg_rule_policy);
-+              if (r)
-+                      goto bad_reg;
-               r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
-               if (r)
-                       goto bad_reg;
-@@ -5277,7 +5282,7 @@ static int nl80211_trigger_scan(struct s
-       if (!rdev->ops->scan)
-               return -EOPNOTSUPP;
+                               ieee80211_csa_update_counter(vif);
+-                      ieee80211_set_csa(sdata, bcn);
++                      ieee80211_set_csa(sdata, beacon);
+               }
  
--      if (rdev->scan_req) {
-+      if (rdev->scan_req || rdev->scan_msg) {
-               err = -EBUSY;
-               goto unlock;
+               if (ifmsh->sync_ops)
+-                      ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
++                      ifmsh->sync_ops->adjust_tbtt(sdata, beacon);
+               skb = dev_alloc_skb(local->tx_headroom +
+-                                  bcn->head_len +
++                                  beacon->head_len +
+                                   256 + /* TIM IE */
+-                                  bcn->tail_len +
++                                  beacon->tail_len +
+                                   local->hw.extra_beacon_tailroom);
+               if (!skb)
+                       goto out;
+               skb_reserve(skb, local->tx_headroom);
+-              memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len);
++              memcpy(skb_put(skb, beacon->head_len), beacon->head,
++                     beacon->head_len);
+               ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template);
+               if (offs) {
+-                      offs->tim_offset = bcn->head_len;
+-                      offs->tim_length = skb->len - bcn->head_len;
++                      offs->tim_offset = beacon->head_len;
++                      offs->tim_length = skb->len - beacon->head_len;
+               }
+-              memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len);
++              memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
++                     beacon->tail_len);
+       } else {
+               WARN_ON(1);
+               goto out;
        }
-@@ -5475,6 +5480,7 @@ static int nl80211_start_sched_scan(stru
-       enum ieee80211_band band;
-       size_t ie_len;
-       struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
-+      s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
-       if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
-           !rdev->ops->sched_scan_start)
-@@ -5509,11 +5515,40 @@ static int nl80211_start_sched_scan(stru
-       if (n_ssids > wiphy->max_sched_scan_ssids)
-               return -EINVAL;
--      if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
+       /* CSA offsets */
+-      if (offs) {
++      if (offs && beacon) {
+               int i;
+               for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) {
+-                      u16 csa_off = sdata->csa_counter_offset_beacon[i];
++                      u16 csa_off = beacon->csa_counter_offsets[i];
+                       if (!csa_off)
+                               continue;
+--- a/drivers/net/wireless/rt2x00/rt2800lib.c
++++ b/drivers/net/wireless/rt2x00/rt2800lib.c
+@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offse
+       return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index));
+ }
++static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
++{
++      struct data_queue *queue = rt2x00dev->bcn;
++      struct queue_entry *entry;
++      int i, bcn_num = 0;
++      u64 off, reg = 0;
++      u32 bssid_dw1;
++
 +      /*
-+       * First, count the number of 'real' matchsets. Due to an issue with
-+       * the old implementation, matchsets containing only the RSSI attribute
-+       * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
-+       * RSSI for all matchsets, rather than their own matchset for reporting
-+       * all APs with a strong RSSI. This is needed to be compatible with
-+       * older userspace that treated a matchset with only the RSSI as the
-+       * global RSSI for all other matchsets - if there are other matchsets.
++       * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
 +       */
-+      if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
-               nla_for_each_nested(attr,
-                                   info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
--                                  tmp)
--                      n_match_sets++;
-+                                  tmp) {
-+                      struct nlattr *rssi;
-+
-+                      err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
-+                                      nla_data(attr), nla_len(attr),
-+                                      nl80211_match_policy);
-+                      if (err)
-+                              return err;
-+                      /* add other standalone attributes here */
-+                      if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
-+                              n_match_sets++;
-+                              continue;
-+                      }
-+                      rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
-+                      if (rssi)
-+                              default_match_rssi = nla_get_s32(rssi);
-+              }
++      for (i = 0; i < queue->limit; i++) {
++              entry = &queue->entries[i];
++              if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags))
++                      continue;
++              off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx);
++              reg |= off << (8 * bcn_num);
++              bcn_num++;
 +      }
 +
-+      /* However, if there's no other matchset, add the RSSI one */
-+      if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
-+              n_match_sets = 1;
-       if (n_match_sets > wiphy->max_match_sets)
-               return -EINVAL;
-@@ -5634,11 +5669,22 @@ static int nl80211_start_sched_scan(stru
-                                   tmp) {
-                       struct nlattr *ssid, *rssi;
--                      nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
--                                nla_data(attr), nla_len(attr),
--                                nl80211_match_policy);
-+                      err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
-+                                      nla_data(attr), nla_len(attr),
-+                                      nl80211_match_policy);
-+                      if (err)
-+                              goto out_free;
-                       ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
-                       if (ssid) {
-+                              if (WARN_ON(i >= n_match_sets)) {
-+                                      /* this indicates a programming error,
-+                                       * the loop above should have verified
-+                                       * things properly
-+                                       */
-+                                      err = -EINVAL;
-+                                      goto out_free;
-+                              }
-+
-                               if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
-                                       err = -EINVAL;
-                                       goto out_free;
-@@ -5647,15 +5693,28 @@ static int nl80211_start_sched_scan(stru
-                                      nla_data(ssid), nla_len(ssid));
-                               request->match_sets[i].ssid.ssid_len =
-                                       nla_len(ssid);
-+                              /* special attribute - old implemenation w/a */
-+                              request->match_sets[i].rssi_thold =
-+                                      default_match_rssi;
-+                              rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
-+                              if (rssi)
-+                                      request->match_sets[i].rssi_thold =
-+                                              nla_get_s32(rssi);
-                       }
--                      rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
--                      if (rssi)
--                              request->rssi_thold = nla_get_u32(rssi);
--                      else
--                              request->rssi_thold =
--                                                 NL80211_SCAN_RSSI_THOLD_OFF;
-                       i++;
-               }
++      WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing);
 +
-+              /* there was no other matchset, so the RSSI one is alone */
-+              if (i == 0)
-+                      request->match_sets[0].rssi_thold = default_match_rssi;
++      rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
++      rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));
 +
-+              request->min_rssi_thold = INT_MAX;
-+              for (i = 0; i < n_match_sets; i++)
-+                      request->min_rssi_thold =
-+                              min(request->match_sets[i].rssi_thold,
-+                                  request->min_rssi_thold);
-+      } else {
-+              request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
-       }
-       if (info->attrs[NL80211_ATTR_IE]) {
-@@ -5751,7 +5810,7 @@ static int nl80211_start_radar_detection
++      /*
++       * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons.
++       */
++      rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1);
++      rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM,
++                         bcn_num > 0 ? bcn_num - 1 : 0);
++      rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1);
++}
++
+ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+ {
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_en
  
-       err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
-       if (!err) {
--              wdev->channel = chandef.chan;
-+              wdev->chandef = chandef;
-               wdev->cac_started = true;
-               wdev->cac_start_time = jiffies;
-       }
-@@ -7502,16 +7561,19 @@ static int nl80211_set_tx_bitrate_mask(s
-        * directly to the enum ieee80211_band values used in cfg80211.
+       rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+                                  entry->skb->len + padding_len);
++      __set_bit(ENTRY_BCN_ENABLED, &entry->flags);
++
++      /*
++       * Change global beacons settings.
++       */
++      rt2800_update_beacons_setup(rt2x00dev);
+       /*
+        * Restore beaconing state.
+@@ -1053,8 +1093,13 @@ void rt2800_clear_beacon(struct queue_en
+        * Clear beacon.
         */
-       BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
--      nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
--      {
-+      nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
-               enum ieee80211_band band = nla_type(tx_rates);
-+              int err;
-+
-               if (band < 0 || band >= IEEE80211_NUM_BANDS)
-                       return -EINVAL;
-               sband = rdev->wiphy.bands[band];
-               if (sband == NULL)
-                       return -EINVAL;
--              nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
--                        nla_len(tx_rates), nl80211_txattr_policy);
-+              err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
-+                              nla_len(tx_rates), nl80211_txattr_policy);
-+              if (err)
-+                      return err;
-               if (tb[NL80211_TXRATE_LEGACY]) {
-                       mask.control[band].legacy = rateset_to_mask(
-                               sband,
-@@ -10054,40 +10116,31 @@ void nl80211_send_scan_start(struct cfg8
-                               NL80211_MCGRP_SCAN, GFP_KERNEL);
+       rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
++      __clear_bit(ENTRY_BCN_ENABLED, &entry->flags);
+       /*
++       * Change global beacons settings.
++       */
++      rt2800_update_beacons_setup(rt2x00dev);
++      /*
+        * Restore beaconing state.
+        */
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
+@@ -1556,7 +1601,7 @@ void rt2800_config_intf(struct rt2x00_de
+               if (!is_zero_ether_addr((const u8 *)conf->bssid)) {
+                       reg = le32_to_cpu(conf->bssid[1]);
+                       rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_ID_MASK, 3);
+-                      rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 7);
++                      rt2x00_set_field32(&reg, MAC_BSSID_DW1_BSS_BCN_NUM, 0);
+                       conf->bssid[1] = cpu_to_le32(reg);
+               }
+@@ -4517,28 +4562,6 @@ static int rt2800_init_registers(struct 
+       if (ret)
+               return ret;
+-      rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
+-      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0,
+-                         rt2800_get_beacon_offset(rt2x00dev, 0));
+-      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN1,
+-                         rt2800_get_beacon_offset(rt2x00dev, 1));
+-      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN2,
+-                         rt2800_get_beacon_offset(rt2x00dev, 2));
+-      rt2x00_set_field32(&reg, BCN_OFFSET0_BCN3,
+-                         rt2800_get_beacon_offset(rt2x00dev, 3));
+-      rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg);
+-
+-      rt2800_register_read(rt2x00dev, BCN_OFFSET1, &reg);
+-      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN4,
+-                         rt2800_get_beacon_offset(rt2x00dev, 4));
+-      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN5,
+-                         rt2800_get_beacon_offset(rt2x00dev, 5));
+-      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN6,
+-                         rt2800_get_beacon_offset(rt2x00dev, 6));
+-      rt2x00_set_field32(&reg, BCN_OFFSET1_BCN7,
+-                         rt2800_get_beacon_offset(rt2x00dev, 7));
+-      rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg);
+-
+       rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
+       rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
+--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
+@@ -141,8 +141,11 @@ static void rt2x00lib_intf_scheduled_ite
+       if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
+               return;
+-      if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
++      if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) {
++              mutex_lock(&intf->beacon_skb_mutex);
+               rt2x00queue_update_beacon(rt2x00dev, vif);
++              mutex_unlock(&intf->beacon_skb_mutex);
++      }
  }
  
--void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
--                          struct wireless_dev *wdev)
-+struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
-+                                     struct wireless_dev *wdev, bool aborted)
- {
-       struct sk_buff *msg;
+ static void rt2x00lib_intf_scheduled(struct work_struct *work)
+@@ -216,7 +219,7 @@ static void rt2x00lib_beaconupdate_iter(
+        * never be called for USB devices.
+        */
+       WARN_ON(rt2x00_is_usb(rt2x00dev));
+-      rt2x00queue_update_beacon_locked(rt2x00dev, vif);
++      rt2x00queue_update_beacon(rt2x00dev, vif);
+ }
  
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
--              return;
-+              return NULL;
+ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
+--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
+@@ -487,6 +487,8 @@ int rt2x00mac_set_key(struct ieee80211_h
+       crypto.cipher = rt2x00crypto_key_to_cipher(key);
+       if (crypto.cipher == CIPHER_NONE)
+               return -EOPNOTSUPP;
++      if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev))
++              return -EOPNOTSUPP;
  
-       if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
--                                NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
-+                                aborted ? NL80211_CMD_SCAN_ABORTED :
-+                                          NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
-               nlmsg_free(msg);
--              return;
-+              return NULL;
+       crypto.cmd = cmd;
+@@ -624,25 +626,24 @@ void rt2x00mac_bss_info_changed(struct i
+        * Start/stop beaconing.
+        */
+       if (changes & BSS_CHANGED_BEACON_ENABLED) {
++              mutex_lock(&intf->beacon_skb_mutex);
+               if (!bss_conf->enable_beacon && intf->enable_beacon) {
+                       rt2x00dev->intf_beaconing--;
+                       intf->enable_beacon = false;
+-                      /*
+-                       * Clear beacon in the H/W for this vif. This is needed
+-                       * to disable beaconing on this particular interface
+-                       * and keep it running on other interfaces.
+-                       */
+-                      rt2x00queue_clear_beacon(rt2x00dev, vif);
+                       if (rt2x00dev->intf_beaconing == 0) {
+                               /*
+                                * Last beaconing interface disabled
+                                * -> stop beacon queue.
+                                */
+-                              mutex_lock(&intf->beacon_skb_mutex);
+                               rt2x00queue_stop_queue(rt2x00dev->bcn);
+-                              mutex_unlock(&intf->beacon_skb_mutex);
+                       }
++                      /*
++                       * Clear beacon in the H/W for this vif. This is needed
++                       * to disable beaconing on this particular interface
++                       * and keep it running on other interfaces.
++                       */
++                      rt2x00queue_clear_beacon(rt2x00dev, vif);
+               } else if (bss_conf->enable_beacon && !intf->enable_beacon) {
+                       rt2x00dev->intf_beaconing++;
+                       intf->enable_beacon = true;
+@@ -658,11 +659,10 @@ void rt2x00mac_bss_info_changed(struct i
+                                * First beaconing interface enabled
+                                * -> start beacon queue.
+                                */
+-                              mutex_lock(&intf->beacon_skb_mutex);
+                               rt2x00queue_start_queue(rt2x00dev->bcn);
+-                              mutex_unlock(&intf->beacon_skb_mutex);
+                       }
+               }
++              mutex_unlock(&intf->beacon_skb_mutex);
        }
  
--      genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
--                              NL80211_MCGRP_SCAN, GFP_KERNEL);
-+      return msg;
- }
+       /*
+--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
+@@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x
+       if (unlikely(!intf->beacon))
+               return -ENOBUFS;
  
--void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
--                             struct wireless_dev *wdev)
-+void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
-+                            struct sk_buff *msg)
- {
--      struct sk_buff *msg;
+-      mutex_lock(&intf->beacon_skb_mutex);
 -
--      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return;
+       /*
+        * Clean up the beacon skb.
+        */
+@@ -768,13 +766,11 @@ int rt2x00queue_clear_beacon(struct rt2x
+       if (rt2x00dev->ops->lib->clear_beacon)
+               rt2x00dev->ops->lib->clear_beacon(intf->beacon);
  
--      if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
--                                NL80211_CMD_SCAN_ABORTED) < 0) {
--              nlmsg_free(msg);
--              return;
--      }
+-      mutex_unlock(&intf->beacon_skb_mutex);
 -
-       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-                               NL80211_MCGRP_SCAN, GFP_KERNEL);
+       return 0;
  }
-@@ -11158,7 +11211,8 @@ void cfg80211_ch_switch_notify(struct ne
-                   wdev->iftype != NL80211_IFTYPE_MESH_POINT))
-               return;
  
--      wdev->channel = chandef->chan;
-+      wdev->chandef = *chandef;
-+      wdev->preset_chandef = *chandef;
-       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
- }
- EXPORT_SYMBOL(cfg80211_ch_switch_notify);
-@@ -11673,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct 
- }
- EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
+-int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
+-                                   struct ieee80211_vif *vif)
++int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
++                            struct ieee80211_vif *vif)
+ {
+       struct rt2x00_intf *intf = vif_to_intf(vif);
+       struct skb_frame_desc *skbdesc;
+@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str
  
-+void nl80211_send_ap_stopped(struct wireless_dev *wdev)
-+{
-+      struct wiphy *wiphy = wdev->wiphy;
-+      struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-+      struct sk_buff *msg;
-+      void *hdr;
-+
-+      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-+      if (!msg)
-+              return;
-+
-+      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
-+      if (!hdr)
-+              goto out;
-+
-+      if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-+          nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
-+          nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
-+              goto out;
-+
-+      genlmsg_end(msg, hdr);
-+
-+      genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
-+                              NL80211_MCGRP_MLME, GFP_KERNEL);
-+      return;
-+ out:
-+      nlmsg_free(msg);
-+}
-+
- /* initialisation/exit functions */
- int nl80211_init(void)
---- a/net/wireless/nl80211.h
-+++ b/net/wireless/nl80211.h
-@@ -8,10 +8,10 @@ void nl80211_exit(void);
- void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
- void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
-                            struct wireless_dev *wdev);
--void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
--                          struct wireless_dev *wdev);
--void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
--                             struct wireless_dev *wdev);
-+struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
-+                                     struct wireless_dev *wdev, bool aborted);
-+void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
-+                            struct sk_buff *msg);
- void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
-                            struct net_device *netdev, u32 cmd);
- void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
-@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_reg
-                    enum nl80211_radar_event event,
-                    struct net_device *netdev, gfp_t gfp);
-+void nl80211_send_ap_stopped(struct wireless_dev *wdev);
-+
- void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
- #endif /* __NET_WIRELESS_NL80211_H */
---- a/net/wireless/scan.c
-+++ b/net/wireless/scan.c
-@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct
-               dev->bss_generation++;
  }
  
--void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
-+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
-+                         bool send_message)
+-int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+-                            struct ieee80211_vif *vif)
+-{
+-      struct rt2x00_intf *intf = vif_to_intf(vif);
+-      int ret;
+-
+-      mutex_lock(&intf->beacon_skb_mutex);
+-      ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif);
+-      mutex_unlock(&intf->beacon_skb_mutex);
+-
+-      return ret;
+-}
+-
+ bool rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
++++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
+@@ -353,6 +353,7 @@ struct txentry_desc {
+  */
+ enum queue_entry_flags {
+       ENTRY_BCN_ASSIGNED,
++      ENTRY_BCN_ENABLED,
+       ENTRY_OWNER_DEVICE_DATA,
+       ENTRY_DATA_PENDING,
+       ENTRY_DATA_IO_FAILED,
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1757,7 +1757,6 @@ out:
+ void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
  {
-       struct cfg80211_scan_request *request;
-       struct wireless_dev *wdev;
-+      struct sk_buff *msg;
- #ifdef CPTCFG_CFG80211_WEXT
-       union iwreq_data wrqu;
- #endif
-       ASSERT_RTNL();
--      request = rdev->scan_req;
-+      if (rdev->scan_msg) {
-+              nl80211_send_scan_result(rdev, rdev->scan_msg);
-+              rdev->scan_msg = NULL;
-+              return;
-+      }
+       struct ath_vif *avp = (void *)vif->drv_priv;
+-      unsigned long flags;
+       u32 tsf;
  
-+      request = rdev->scan_req;
-       if (!request)
+       if (!sc->p2p_ps_timer)
+@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft
                return;
  
-@@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg802
-       if (wdev->netdev)
-               cfg80211_sme_scan_done(wdev->netdev);
+       sc->p2p_ps_vif = avp;
+-
+-      spin_lock_irqsave(&sc->sc_pm_lock, flags);
+-      if (!(sc->ps_flags & PS_BEACON_SYNC)) {
+-              tsf = ath9k_hw_gettsf32(sc->sc_ah);
+-              ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+-              ath9k_update_p2p_ps_timer(sc, avp);
+-      }
+-      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
++      tsf = ath9k_hw_gettsf32(sc->sc_ah);
++      ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
++      ath9k_update_p2p_ps_timer(sc, avp);
+ }
  
--      if (request->aborted) {
--              nl80211_send_scan_aborted(rdev, wdev);
--      } else {
--              if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
--                      /* flush entries from previous scans */
--                      spin_lock_bh(&rdev->bss_lock);
--                      __cfg80211_bss_expire(rdev, request->scan_start);
--                      spin_unlock_bh(&rdev->bss_lock);
--              }
--              nl80211_send_scan_done(rdev, wdev);
-+      if (!request->aborted &&
-+          request->flags & NL80211_SCAN_FLAG_FLUSH) {
-+              /* flush entries from previous scans */
-+              spin_lock_bh(&rdev->bss_lock);
-+              __cfg80211_bss_expire(rdev, request->scan_start);
-+              spin_unlock_bh(&rdev->bss_lock);
+ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
+@@ -1791,6 +1785,7 @@ static void ath9k_bss_info_changed(struc
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_vif *avp = (void *)vif->drv_priv;
++      unsigned long flags;
+       int slottime;
+       ath9k_ps_wakeup(sc);
+@@ -1853,7 +1848,10 @@ static void ath9k_bss_info_changed(struc
+       if (changed & BSS_CHANGED_P2P_PS) {
+               spin_lock_bh(&sc->sc_pcu_lock);
+-              ath9k_update_p2p_ps(sc, vif);
++              spin_lock_irqsave(&sc->sc_pm_lock, flags);
++              if (!(sc->ps_flags & PS_BEACON_SYNC))
++                      ath9k_update_p2p_ps(sc, vif);
++              spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+               spin_unlock_bh(&sc->sc_pcu_lock);
        }
  
-+      msg = nl80211_build_scan_msg(rdev, wdev, request->aborted);
-+
- #ifdef CPTCFG_CFG80211_WEXT
-       if (wdev->netdev && !request->aborted) {
-               memset(&wrqu, 0, sizeof(wrqu));
-@@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg802
+@@ -2232,14 +2230,6 @@ static void ath9k_sw_scan_complete(struc
+       clear_bit(ATH_OP_SCANNING, &common->op_flags);
+ }
  
-       rdev->scan_req = NULL;
-       kfree(request);
-+
-+      if (!send_message)
-+              rdev->scan_msg = msg;
-+      else
-+              nl80211_send_scan_result(rdev, msg);
+-static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
+-                                      struct ieee80211_vif *vif,
+-                                      struct cfg80211_chan_def *chandef)
+-{
+-      /* depend on vif->csa_active only */
+-      return;
+-}
+-
+ struct ieee80211_ops ath9k_ops = {
+       .tx                 = ath9k_tx,
+       .start              = ath9k_start,
+@@ -2287,5 +2277,4 @@ struct ieee80211_ops ath9k_ops = {
+ #endif
+       .sw_scan_start      = ath9k_sw_scan_start,
+       .sw_scan_complete   = ath9k_sw_scan_complete,
+-      .channel_switch_beacon     = ath9k_channel_switch_beacon,
+ };
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -4142,14 +4142,6 @@ static int ath10k_set_bitrate_mask(struc
+                                          fixed_nss, force_sgi);
  }
  
- void __cfg80211_scan_done(struct work_struct *wk)
-@@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_st
-                           scan_done_wk);
+-static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
+-                                       struct ieee80211_vif *vif,
+-                                       struct cfg80211_chan_def *chandef)
+-{
+-      /* there's no need to do anything here. vif->csa_active is enough */
+-      return;
+-}
+-
+ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta,
+@@ -4256,7 +4248,6 @@ static const struct ieee80211_ops ath10k
+       .restart_complete               = ath10k_restart_complete,
+       .get_survey                     = ath10k_get_survey,
+       .set_bitrate_mask               = ath10k_set_bitrate_mask,
+-      .channel_switch_beacon          = ath10k_channel_switch_beacon,
+       .sta_rc_update                  = ath10k_sta_rc_update,
+       .get_tsf                        = ath10k_get_tsf,
+ #ifdef CONFIG_PM
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -468,327 +468,6 @@ void sta_set_rate_info_rx(struct sta_inf
+               rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ }
  
-       rtnl_lock();
--      ___cfg80211_scan_done(rdev);
-+      ___cfg80211_scan_done(rdev, true);
-       rtnl_unlock();
+-static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
+-{
+-      struct ieee80211_sub_if_data *sdata = sta->sdata;
+-      struct ieee80211_local *local = sdata->local;
+-      struct rate_control_ref *ref = local->rate_ctrl;
+-      struct timespec uptime;
+-      u64 packets = 0;
+-      u32 thr = 0;
+-      int i, ac;
+-
+-      sinfo->generation = sdata->local->sta_generation;
+-
+-      sinfo->filled = STATION_INFO_INACTIVE_TIME |
+-                      STATION_INFO_RX_BYTES64 |
+-                      STATION_INFO_TX_BYTES64 |
+-                      STATION_INFO_RX_PACKETS |
+-                      STATION_INFO_TX_PACKETS |
+-                      STATION_INFO_TX_RETRIES |
+-                      STATION_INFO_TX_FAILED |
+-                      STATION_INFO_TX_BITRATE |
+-                      STATION_INFO_RX_BITRATE |
+-                      STATION_INFO_RX_DROP_MISC |
+-                      STATION_INFO_BSS_PARAM |
+-                      STATION_INFO_CONNECTED_TIME |
+-                      STATION_INFO_STA_FLAGS |
+-                      STATION_INFO_BEACON_LOSS_COUNT;
+-
+-      do_posix_clock_monotonic_gettime(&uptime);
+-      sinfo->connected_time = uptime.tv_sec - sta->last_connected;
+-
+-      sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+-      sinfo->tx_bytes = 0;
+-      for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+-              sinfo->tx_bytes += sta->tx_bytes[ac];
+-              packets += sta->tx_packets[ac];
+-      }
+-      sinfo->tx_packets = packets;
+-      sinfo->rx_bytes = sta->rx_bytes;
+-      sinfo->rx_packets = sta->rx_packets;
+-      sinfo->tx_retries = sta->tx_retry_count;
+-      sinfo->tx_failed = sta->tx_retry_failed;
+-      sinfo->rx_dropped_misc = sta->rx_dropped;
+-      sinfo->beacon_loss_count = sta->beacon_loss_count;
+-
+-      if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
+-          (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
+-              sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
+-              if (!local->ops->get_rssi ||
+-                  drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
+-                      sinfo->signal = (s8)sta->last_signal;
+-              sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+-      }
+-      if (sta->chains) {
+-              sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
+-                               STATION_INFO_CHAIN_SIGNAL_AVG;
+-
+-              sinfo->chains = sta->chains;
+-              for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
+-                      sinfo->chain_signal[i] = sta->chain_signal_last[i];
+-                      sinfo->chain_signal_avg[i] =
+-                              (s8) -ewma_read(&sta->chain_signal_avg[i]);
+-              }
+-      }
+-
+-      sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
+-      sta_set_rate_info_rx(sta, &sinfo->rxrate);
+-
+-      if (ieee80211_vif_is_mesh(&sdata->vif)) {
+-#ifdef CPTCFG_MAC80211_MESH
+-              sinfo->filled |= STATION_INFO_LLID |
+-                               STATION_INFO_PLID |
+-                               STATION_INFO_PLINK_STATE |
+-                               STATION_INFO_LOCAL_PM |
+-                               STATION_INFO_PEER_PM |
+-                               STATION_INFO_NONPEER_PM;
+-
+-              sinfo->llid = sta->llid;
+-              sinfo->plid = sta->plid;
+-              sinfo->plink_state = sta->plink_state;
+-              if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
+-                      sinfo->filled |= STATION_INFO_T_OFFSET;
+-                      sinfo->t_offset = sta->t_offset;
+-              }
+-              sinfo->local_pm = sta->local_pm;
+-              sinfo->peer_pm = sta->peer_pm;
+-              sinfo->nonpeer_pm = sta->nonpeer_pm;
+-#endif
+-      }
+-
+-      sinfo->bss_param.flags = 0;
+-      if (sdata->vif.bss_conf.use_cts_prot)
+-              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT;
+-      if (sdata->vif.bss_conf.use_short_preamble)
+-              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
+-      if (sdata->vif.bss_conf.use_short_slot)
+-              sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
+-      sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period;
+-      sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int;
+-
+-      sinfo->sta_flags.set = 0;
+-      sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+-                              BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+-                              BIT(NL80211_STA_FLAG_WME) |
+-                              BIT(NL80211_STA_FLAG_MFP) |
+-                              BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+-                              BIT(NL80211_STA_FLAG_ASSOCIATED) |
+-                              BIT(NL80211_STA_FLAG_TDLS_PEER);
+-      if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+-      if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+-      if (test_sta_flag(sta, WLAN_STA_WME))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
+-      if (test_sta_flag(sta, WLAN_STA_MFP))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
+-      if (test_sta_flag(sta, WLAN_STA_AUTH))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+-      if (test_sta_flag(sta, WLAN_STA_ASSOC))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+-      if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+-              sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+-
+-      /* check if the driver has a SW RC implementation */
+-      if (ref && ref->ops->get_expected_throughput)
+-              thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
+-      else
+-              thr = drv_get_expected_throughput(local, &sta->sta);
+-
+-      if (thr != 0) {
+-              sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+-              sinfo->expected_throughput = thr;
+-      }
+-}
+-
+-static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
+-      "rx_packets", "rx_bytes", "wep_weak_iv_count",
+-      "rx_duplicates", "rx_fragments", "rx_dropped",
+-      "tx_packets", "tx_bytes", "tx_fragments",
+-      "tx_filtered", "tx_retry_failed", "tx_retries",
+-      "beacon_loss", "sta_state", "txrate", "rxrate", "signal",
+-      "channel", "noise", "ch_time", "ch_time_busy",
+-      "ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
+-};
+-#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats)
+-
+-static int ieee80211_get_et_sset_count(struct wiphy *wiphy,
+-                                     struct net_device *dev,
+-                                     int sset)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      int rv = 0;
+-
+-      if (sset == ETH_SS_STATS)
+-              rv += STA_STATS_LEN;
+-
+-      rv += drv_get_et_sset_count(sdata, sset);
+-
+-      if (rv == 0)
+-              return -EOPNOTSUPP;
+-      return rv;
+-}
+-
+-static void ieee80211_get_et_stats(struct wiphy *wiphy,
+-                                 struct net_device *dev,
+-                                 struct ethtool_stats *stats,
+-                                 u64 *data)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      struct ieee80211_chanctx_conf *chanctx_conf;
+-      struct ieee80211_channel *channel;
+-      struct sta_info *sta;
+-      struct ieee80211_local *local = sdata->local;
+-      struct station_info sinfo;
+-      struct survey_info survey;
+-      int i, q;
+-#define STA_STATS_SURVEY_LEN 7
+-
+-      memset(data, 0, sizeof(u64) * STA_STATS_LEN);
+-
+-#define ADD_STA_STATS(sta)                            \
+-      do {                                            \
+-              data[i++] += sta->rx_packets;           \
+-              data[i++] += sta->rx_bytes;             \
+-              data[i++] += sta->wep_weak_iv_count;    \
+-              data[i++] += sta->num_duplicates;       \
+-              data[i++] += sta->rx_fragments;         \
+-              data[i++] += sta->rx_dropped;           \
+-                                                      \
+-              data[i++] += sinfo.tx_packets;          \
+-              data[i++] += sinfo.tx_bytes;            \
+-              data[i++] += sta->tx_fragments;         \
+-              data[i++] += sta->tx_filtered_count;    \
+-              data[i++] += sta->tx_retry_failed;      \
+-              data[i++] += sta->tx_retry_count;       \
+-              data[i++] += sta->beacon_loss_count;    \
+-      } while (0)
+-
+-      /* For Managed stations, find the single station based on BSSID
+-       * and use that.  For interface types, iterate through all available
+-       * stations and add stats for any station that is assigned to this
+-       * network device.
+-       */
+-
+-      mutex_lock(&local->sta_mtx);
+-
+-      if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+-              sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
+-
+-              if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
+-                      goto do_survey;
+-
+-              sinfo.filled = 0;
+-              sta_set_sinfo(sta, &sinfo);
+-
+-              i = 0;
+-              ADD_STA_STATS(sta);
+-
+-              data[i++] = sta->sta_state;
+-
+-
+-              if (sinfo.filled & STATION_INFO_TX_BITRATE)
+-                      data[i] = 100000 *
+-                              cfg80211_calculate_bitrate(&sinfo.txrate);
+-              i++;
+-              if (sinfo.filled & STATION_INFO_RX_BITRATE)
+-                      data[i] = 100000 *
+-                              cfg80211_calculate_bitrate(&sinfo.rxrate);
+-              i++;
+-
+-              if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
+-                      data[i] = (u8)sinfo.signal_avg;
+-              i++;
+-      } else {
+-              list_for_each_entry(sta, &local->sta_list, list) {
+-                      /* Make sure this station belongs to the proper dev */
+-                      if (sta->sdata->dev != dev)
+-                              continue;
+-
+-                      sinfo.filled = 0;
+-                      sta_set_sinfo(sta, &sinfo);
+-                      i = 0;
+-                      ADD_STA_STATS(sta);
+-              }
+-      }
+-
+-do_survey:
+-      i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
+-      /* Get survey stats for current channel */
+-      survey.filled = 0;
+-
+-      rcu_read_lock();
+-      chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+-      if (chanctx_conf)
+-              channel = chanctx_conf->def.chan;
+-      else
+-              channel = NULL;
+-      rcu_read_unlock();
+-
+-      if (channel) {
+-              q = 0;
+-              do {
+-                      survey.filled = 0;
+-                      if (drv_get_survey(local, q, &survey) != 0) {
+-                              survey.filled = 0;
+-                              break;
+-                      }
+-                      q++;
+-              } while (channel != survey.channel);
+-      }
+-
+-      if (survey.filled)
+-              data[i++] = survey.channel->center_freq;
+-      else
+-              data[i++] = 0;
+-      if (survey.filled & SURVEY_INFO_NOISE_DBM)
+-              data[i++] = (u8)survey.noise;
+-      else
+-              data[i++] = -1LL;
+-      if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
+-              data[i++] = survey.channel_time;
+-      else
+-              data[i++] = -1LL;
+-      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
+-              data[i++] = survey.channel_time_busy;
+-      else
+-              data[i++] = -1LL;
+-      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
+-              data[i++] = survey.channel_time_ext_busy;
+-      else
+-              data[i++] = -1LL;
+-      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
+-              data[i++] = survey.channel_time_rx;
+-      else
+-              data[i++] = -1LL;
+-      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
+-              data[i++] = survey.channel_time_tx;
+-      else
+-              data[i++] = -1LL;
+-
+-      mutex_unlock(&local->sta_mtx);
+-
+-      if (WARN_ON(i != STA_STATS_LEN))
+-              return;
+-
+-      drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+-}
+-
+-static void ieee80211_get_et_strings(struct wiphy *wiphy,
+-                                   struct net_device *dev,
+-                                   u32 sset, u8 *data)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      int sz_sta_stats = 0;
+-
+-      if (sset == ETH_SS_STATS) {
+-              sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
+-              memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
+-      }
+-      drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
+-}
+-
+ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+                                 int idx, u8 *mac, struct station_info *sinfo)
+ {
+@@ -875,7 +554,8 @@ static int ieee80211_set_monitor_channel
  }
  
-@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_dev
-       if (IS_ERR(rdev))
-               return PTR_ERR(rdev);
+ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
+-                                  const u8 *resp, size_t resp_len)
++                                  const u8 *resp, size_t resp_len,
++                                  const struct ieee80211_csa_settings *csa)
+ {
+       struct probe_resp *new, *old;
  
--      if (rdev->scan_req) {
-+      if (rdev->scan_req || rdev->scan_msg) {
-               err = -EBUSY;
-               goto out;
-       }
-@@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_dev
-       if (IS_ERR(rdev))
-               return PTR_ERR(rdev);
--      if (rdev->scan_req)
-+      if (rdev->scan_req || rdev->scan_msg)
-               return -EAGAIN;
-       res = ieee80211_scan_results(rdev, info, extra, data->length);
---- a/net/wireless/sme.c
-+++ b/net/wireless/sme.c
-@@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wir
-       ASSERT_RDEV_LOCK(rdev);
-       ASSERT_WDEV_LOCK(wdev);
--      if (rdev->scan_req)
-+      if (rdev->scan_req || rdev->scan_msg)
-               return -EBUSY;
-       if (wdev->conn->params.channel)
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -1001,7 +1001,6 @@ ieee80211_sta_process_chanswitch(struct 
-       }
+@@ -891,6 +571,11 @@ static int ieee80211_set_probe_resp(stru
+       new->len = resp_len;
+       memcpy(new->data, resp, resp_len);
++      if (csa)
++              memcpy(new->csa_counter_offsets, csa->counter_offsets_presp,
++                     csa->n_counter_offsets_presp *
++                     sizeof(new->csa_counter_offsets[0]));
++
+       rcu_assign_pointer(sdata->u.ap.probe_resp, new);
+       if (old)
+               kfree_rcu(old, rcu_head);
+@@ -899,7 +584,8 @@ static int ieee80211_set_probe_resp(stru
+ }
+ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+-                                 struct cfg80211_beacon_data *params)
++                                 struct cfg80211_beacon_data *params,
++                                 const struct ieee80211_csa_settings *csa)
+ {
+       struct beacon_data *new, *old;
+       int new_head_len, new_tail_len;
+@@ -943,6 +629,13 @@ static int ieee80211_assign_beacon(struc
+       new->head_len = new_head_len;
+       new->tail_len = new_tail_len;
++      if (csa) {
++              new->csa_current_counter = csa->count;
++              memcpy(new->csa_counter_offsets, csa->counter_offsets_beacon,
++                     csa->n_counter_offsets_beacon *
++                     sizeof(new->csa_counter_offsets[0]));
++      }
++
+       /* copy in head */
+       if (params->head)
+               memcpy(new->head, params->head, new_head_len);
+@@ -957,7 +650,7 @@ static int ieee80211_assign_beacon(struc
+                       memcpy(new->tail, old->tail, new_tail_len);
  
-       ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
--      sdata->vif.csa_active = true;
+       err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+-                                     params->probe_resp_len);
++                                     params->probe_resp_len, csa);
+       if (err < 0)
+               return err;
+       if (err == 0)
+@@ -1042,7 +735,7 @@ static int ieee80211_start_ap(struct wip
+               sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
+                                       IEEE80211_P2P_OPPPS_ENABLE_BIT;
  
-       mutex_lock(&local->chanctx_mtx);
-       if (local->use_chanctx) {
-@@ -1039,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct 
-       mutex_unlock(&local->chanctx_mtx);
+-      err = ieee80211_assign_beacon(sdata, &params->beacon);
++      err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
+       if (err < 0) {
+               ieee80211_vif_release_channel(sdata);
+               return err;
+@@ -1090,7 +783,7 @@ static int ieee80211_change_beacon(struc
+       if (!old)
+               return -ENOENT;
  
-       sdata->csa_chandef = csa_ie.chandef;
-+      sdata->vif.csa_active = true;
+-      err = ieee80211_assign_beacon(sdata, params);
++      err = ieee80211_assign_beacon(sdata, params, NULL);
+       if (err < 0)
+               return err;
+       ieee80211_bss_info_change_notify(sdata, err);
+@@ -3073,7 +2766,8 @@ static int ieee80211_set_after_csa_beaco
  
-       if (csa_ie.mode)
-               ieee80211_stop_queues_by_reason(&local->hw,
---- a/net/mac80211/chan.c
-+++ b/net/mac80211/chan.c
-@@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required(
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+-              err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
++              err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
++                                            NULL);
+               kfree(sdata->u.ap.next_beacon);
+               sdata->u.ap.next_beacon = NULL;
+@@ -3176,6 +2870,7 @@ static int ieee80211_set_csa_beacon(stru
+                                   struct cfg80211_csa_settings *params,
+                                   u32 *changed)
  {
-       struct ieee80211_sub_if_data *sdata;
++      struct ieee80211_csa_settings csa = {};
+       int err;
  
-+      lockdep_assert_held(&local->mtx);
-+
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->radar_required) {
---- a/net/mac80211/ibss.c
-+++ b/net/mac80211/ibss.c
-@@ -294,7 +294,6 @@ static void __ieee80211_sta_join_ibss(st
-       }
+       switch (sdata->vif.type) {
+@@ -3210,20 +2905,13 @@ static int ieee80211_set_csa_beacon(stru
+                    IEEE80211_MAX_CSA_COUNTERS_NUM))
+                       return -EINVAL;
  
-       mutex_lock(&local->mtx);
--      ieee80211_vif_release_channel(sdata);
-       if (ieee80211_vif_use_channel(sdata, &chandef,
-                                     ifibss->fixed_channel ?
-                                       IEEE80211_CHANCTX_SHARED :
-@@ -303,6 +302,7 @@ static void __ieee80211_sta_join_ibss(st
-               mutex_unlock(&local->mtx);
-               return;
+-              /* make sure we don't have garbage in other counters */
+-              memset(sdata->csa_counter_offset_beacon, 0,
+-                     sizeof(sdata->csa_counter_offset_beacon));
+-              memset(sdata->csa_counter_offset_presp, 0,
+-                     sizeof(sdata->csa_counter_offset_presp));
+-
+-              memcpy(sdata->csa_counter_offset_beacon,
+-                     params->counter_offsets_beacon,
+-                     params->n_counter_offsets_beacon * sizeof(u16));
+-              memcpy(sdata->csa_counter_offset_presp,
+-                     params->counter_offsets_presp,
+-                     params->n_counter_offsets_presp * sizeof(u16));
++              csa.counter_offsets_beacon = params->counter_offsets_beacon;
++              csa.counter_offsets_presp = params->counter_offsets_presp;
++              csa.n_counter_offsets_beacon = params->n_counter_offsets_beacon;
++              csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
++              csa.count = params->count;
+-              err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
++              err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa);
+               if (err < 0) {
+                       kfree(sdata->u.ap.next_beacon);
+                       return err;
+@@ -3367,7 +3055,6 @@ __ieee80211_channel_switch(struct wiphy 
+       sdata->csa_radar_required = params->radar_required;
+       sdata->csa_chandef = params->chandef;
+       sdata->csa_block_tx = params->block_tx;
+-      sdata->csa_current_counter = params->count;
+       sdata->vif.csa_active = true;
+       if (sdata->csa_block_tx)
+@@ -3515,10 +3202,23 @@ static int ieee80211_mgmt_tx(struct wiph
+            sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
+           params->n_csa_offsets) {
+               int i;
+-              u8 c = sdata->csa_current_counter;
++              struct beacon_data *beacon = NULL;
++
++              rcu_read_lock();
+-              for (i = 0; i < params->n_csa_offsets; i++)
+-                      data[params->csa_offsets[i]] = c;
++              if (sdata->vif.type == NL80211_IFTYPE_AP)
++                      beacon = rcu_dereference(sdata->u.ap.beacon);
++              else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
++                      beacon = rcu_dereference(sdata->u.ibss.presp);
++              else if (ieee80211_vif_is_mesh(&sdata->vif))
++                      beacon = rcu_dereference(sdata->u.mesh.beacon);
++
++              if (beacon)
++                      for (i = 0; i < params->n_csa_offsets; i++)
++                              data[params->csa_offsets[i]] =
++                                      beacon->csa_current_counter;
++
++              rcu_read_unlock();
        }
-+      sdata->radar_required = radar_required;
-       mutex_unlock(&local->mtx);
-       memcpy(ifibss->bssid, bssid, ETH_ALEN);
-@@ -318,7 +318,6 @@ static void __ieee80211_sta_join_ibss(st
-       rcu_assign_pointer(ifibss->presp, presp);
-       mgmt = (void *)presp->head;
--      sdata->radar_required = radar_required;
-       sdata->vif.bss_conf.enable_beacon = true;
-       sdata->vif.bss_conf.beacon_int = beacon_int;
-       sdata->vif.bss_conf.basic_rates = basic_rates;
-@@ -386,7 +385,7 @@ static void __ieee80211_sta_join_ibss(st
-                                             presp->head_len, 0, GFP_KERNEL);
-       cfg80211_put_bss(local->hw.wiphy, bss);
-       netif_carrier_on(sdata->dev);
--      cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
-+      cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL);
+       IEEE80211_SKB_CB(skb)->flags = flags;
+@@ -3598,21 +3298,6 @@ static int ieee80211_get_antenna(struct 
+       return drv_get_antenna(local, tx_ant, rx_ant);
  }
  
- static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
-@@ -802,6 +801,8 @@ ieee80211_ibss_process_chanswitch(struct
-       int err;
-       u32 sta_flags;
+-static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx)
+-{
+-      struct ieee80211_local *local = wiphy_priv(wiphy);
+-
+-      return drv_set_ringparam(local, tx, rx);
+-}
+-
+-static void ieee80211_get_ringparam(struct wiphy *wiphy,
+-                                  u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
+-{
+-      struct ieee80211_local *local = wiphy_priv(wiphy);
+-
+-      drv_get_ringparam(local, tx, tx_max, rx, rx_max);
+-}
+-
+ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
+                                   struct net_device *dev,
+                                   struct cfg80211_gtk_rekey_data *data)
+@@ -3844,8 +3529,6 @@ const struct cfg80211_ops mac80211_confi
+       .mgmt_frame_register = ieee80211_mgmt_frame_register,
+       .set_antenna = ieee80211_set_antenna,
+       .get_antenna = ieee80211_get_antenna,
+-      .set_ringparam = ieee80211_set_ringparam,
+-      .get_ringparam = ieee80211_get_ringparam,
+       .set_rekey_data = ieee80211_set_rekey_data,
+       .tdls_oper = ieee80211_tdls_oper,
+       .tdls_mgmt = ieee80211_tdls_mgmt,
+@@ -3854,9 +3537,6 @@ const struct cfg80211_ops mac80211_confi
+ #ifdef CONFIG_PM
+       .set_wakeup = ieee80211_set_wakeup,
+ #endif
+-      .get_et_sset_count = ieee80211_get_et_sset_count,
+-      .get_et_stats = ieee80211_get_et_stats,
+-      .get_et_strings = ieee80211_get_et_strings,
+       .get_channel = ieee80211_cfg_get_channel,
+       .start_radar_detection = ieee80211_start_radar_detection,
+       .channel_switch = ieee80211_channel_switch,
+--- a/net/mac80211/debugfs_sta.c
++++ b/net/mac80211/debugfs_sta.c
+@@ -587,7 +587,6 @@ void ieee80211_sta_debugfs_add(struct st
+       DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
+       DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
+       DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
+-      DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
+       if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
+               debugfs_create_x32("driver_buffered_tids", 0400,
+--- a/net/mac80211/wep.c
++++ b/net/mac80211/wep.c
+@@ -271,22 +271,6 @@ static int ieee80211_wep_decrypt(struct 
+       return ret;
+ }
+-
+-static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb,
+-                                   struct ieee80211_key *key)
+-{
+-      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+-      unsigned int hdrlen;
+-      u8 *ivpos;
+-      u32 iv;
+-
+-      hdrlen = ieee80211_hdrlen(hdr->frame_control);
+-      ivpos = skb->data + hdrlen;
+-      iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
+-
+-      return ieee80211_wep_weak_iv(iv, key->conf.keylen);
+-}
+-
+ ieee80211_rx_result
+ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
+ {
+@@ -301,16 +285,12 @@ ieee80211_crypto_wep_decrypt(struct ieee
+       if (!(status->flag & RX_FLAG_DECRYPTED)) {
+               if (skb_linearize(rx->skb))
+                       return RX_DROP_UNUSABLE;
+-              if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+-                      rx->sta->wep_weak_iv_count++;
+               if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
+                       return RX_DROP_UNUSABLE;
+       } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+               if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) +
+                                           IEEE80211_WEP_IV_LEN))
+                       return RX_DROP_UNUSABLE;
+-              if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+-                      rx->sta->wep_weak_iv_count++;
+               ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
+               /* remove ICV */
+               if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -2278,16 +2278,6 @@ struct cfg80211_qos_map {
+  *
+  * @set_noack_map: Set the NoAck Map for the TIDs.
+  *
+- * @get_et_sset_count:  Ethtool API to get string-set count.
+- *    See @ethtool_ops.get_sset_count
+- *
+- * @get_et_stats:  Ethtool API to get a set of u64 stats.
+- *    See @ethtool_ops.get_ethtool_stats
+- *
+- * @get_et_strings:  Ethtool API to get a set of strings to describe stats
+- *    and perhaps other supported types of ethtool data-sets.
+- *    See @ethtool_ops.get_strings
+- *
+  * @get_channel: Get the current operating channel for the virtual interface.
+  *    For monitor interfaces, it should return %NULL unless there's a single
+  *    current monitoring channel.
+@@ -2529,13 +2519,6 @@ struct cfg80211_ops {
+                                 struct net_device *dev,
+                                 u16 noack_map);
+-      int     (*get_et_sset_count)(struct wiphy *wiphy,
+-                                   struct net_device *dev, int sset);
+-      void    (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
+-                              struct ethtool_stats *stats, u64 *data);
+-      void    (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
+-                                u32 sset, u8 *data);
+-
+       int     (*get_channel)(struct wiphy *wiphy,
+                              struct wireless_dev *wdev,
+                              struct cfg80211_chan_def *chandef);
+@@ -4846,6 +4829,10 @@ void cfg80211_stop_iface(struct wiphy *w
+  */
+ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy);
  
-+      sdata_assert_lock(sdata);
-+
-       sta_flags = IEEE80211_STA_DISABLE_VHT;
-       switch (ifibss->chandef.width) {
-       case NL80211_CHAN_WIDTH_5:
-@@ -1471,6 +1472,11 @@ static void ieee80211_rx_mgmt_probe_req(
-       memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN);
-       ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa);
-       IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
 +
-+      /* avoid excessive retries for probe request to wildcard SSIDs */
-+      if (pos[1] == 0)
-+              IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK;
++/* ethtool helper */
++void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
 +
-       ieee80211_tx_skb(sdata, skb);
- }
+ /* Logging, debugging and troubleshooting/diagnostic helpers. */
  
---- a/net/mac80211/mesh.c
-+++ b/net/mac80211/mesh.c
-@@ -872,6 +872,8 @@ ieee80211_mesh_process_chnswitch(struct 
-       if (!ifmsh->mesh_id)
-               return false;
-+      sdata_assert_lock(sdata);
-+
-       sta_flags = IEEE80211_STA_DISABLE_VHT;
-       switch (sdata->vif.bss_conf.chandef.width) {
-       case NL80211_CHAN_WIDTH_20_NOHT:
---- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
-@@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf
-       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
-       struct net_device *ndev = ifp->ndev;
-       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
-+      struct ieee80211_channel *chan;
-       s32 err = 0;
-       if (ifp->vif->mode == WL_MODE_AP) {
-@@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf
-       } else if (brcmf_is_linkup(e)) {
-               brcmf_dbg(CONN, "Linkup\n");
-               if (brcmf_is_ibssmode(ifp->vif)) {
-+                      chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
-                       memcpy(profile->bssid, e->addr, ETH_ALEN);
-                       wl_inform_ibss(cfg, ndev, e->addr);
--                      cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
-+                      cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
-                       clear_bit(BRCMF_VIF_STATUS_CONNECTING,
-                                 &ifp->vif->sme_state);
-                       set_bit(BRCMF_VIF_STATUS_CONNECTED,
---- a/drivers/net/wireless/libertas/cfg.c
-+++ b/drivers/net/wireless/libertas/cfg.c
-@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_pri
-       memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
-       priv->wdev->ssid_len = params->ssid_len;
--      cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
-+      cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
-+                           GFP_KERNEL);
-       /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
-       priv->connect_status = LBS_CONNECTED;
---- a/drivers/net/wireless/mwifiex/cfg80211.c
-+++ b/drivers/net/wireless/mwifiex/cfg80211.c
-@@ -1881,7 +1881,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy 
-                                    params->privacy);
- done:
-       if (!ret) {
--              cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
-+              cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
-+                                   params->chandef.chan, GFP_KERNEL);
-               dev_dbg(priv->adapter->dev,
-                       "info: joined/created adhoc network with bssid"
-                       " %pM successfully\n", priv->cfg_bssid);
---- a/drivers/net/wireless/rndis_wlan.c
-+++ b/drivers/net/wireless/rndis_wlan.c
-@@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(s
-                                       bssid, req_ie, req_ie_len,
-                                       resp_ie, resp_ie_len, GFP_KERNEL);
-       } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
--              cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
-+              cfg80211_ibss_joined(usbdev->net, bssid,
-+                                   get_current_channel(usbdev, NULL),
-+                                   GFP_KERNEL);
-       kfree(info);
---- a/net/wireless/ibss.c
-+++ b/net/wireless/ibss.c
-@@ -14,7 +14,8 @@
- #include "rdev-ops.h"
+ /* wiphy_printk helpers, similar to dev_printk */
+--- a/net/mac80211/Makefile
++++ b/net/mac80211/Makefile
+@@ -17,6 +17,7 @@ mac80211-y := \
+       aes_ccm.o \
+       aes_cmac.o \
+       cfg.o \
++      ethtool.o \
+       rx.o \
+       spectmgmt.o \
+       tx.o \
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -229,16 +229,29 @@ struct ieee80211_rx_data {
+       u16 tkip_iv16;
+ };
  
++struct ieee80211_csa_settings {
++      const u16 *counter_offsets_beacon;
++      const u16 *counter_offsets_presp;
++
++      int n_counter_offsets_beacon;
++      int n_counter_offsets_presp;
++
++      u8 count;
++};
++
+ struct beacon_data {
+       u8 *head, *tail;
+       int head_len, tail_len;
+       struct ieee80211_meshconf_ie *meshconf;
++      u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
++      u8 csa_current_counter;
+       struct rcu_head rcu_head;
+ };
  
--void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
-+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
-+                          struct ieee80211_channel *channel)
- {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_bss *bss;
-@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_d
-       if (!wdev->ssid_len)
-               return;
+ struct probe_resp {
+       struct rcu_head rcu_head;
+       int len;
++      u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
+       u8 data[0];
+ };
  
--      bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
--                             wdev->ssid, wdev->ssid_len,
-+      bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
-                              WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+@@ -754,8 +767,6 @@ struct ieee80211_sub_if_data {
+       struct mac80211_qos_map __rcu *qos_map;
  
-       if (WARN_ON(!bss))
-@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_d
- #endif
- }
+       struct work_struct csa_finalize_work;
+-      u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM];
+-      u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM];
+       bool csa_radar_required;
+       bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
+       struct cfg80211_chan_def csa_chandef;
+@@ -767,7 +778,6 @@ struct ieee80211_sub_if_data {
+       struct ieee80211_chanctx *reserved_chanctx;
+       struct cfg80211_chan_def reserved_chandef;
+       bool reserved_radar_required;
+-      u8 csa_current_counter;
+       /* used to reconfigure hardware SM PS */
+       struct work_struct recalc_smps;
+@@ -1850,6 +1860,8 @@ int ieee80211_tdls_oper(struct wiphy *wi
+                       const u8 *peer, enum nl80211_tdls_operation oper);
  
--void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
-+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
-+                        struct ieee80211_channel *channel, gfp_t gfp)
- {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       struct cfg80211_event *ev;
-       unsigned long flags;
  
--      trace_cfg80211_ibss_joined(dev, bssid);
-+      trace_cfg80211_ibss_joined(dev, bssid, channel);
++extern const struct ethtool_ops ieee80211_ethtool_ops;
 +
-+      if (WARN_ON(!channel))
-+              return;
+ #ifdef CPTCFG_MAC80211_NOINLINE
+ #define debug_noinline noinline
+ #else
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -399,6 +399,7 @@ int ieee80211_add_virtual_monitor(struct
+       sdata->vif.type = NL80211_IFTYPE_MONITOR;
+       snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
+                wiphy_name(local->hw.wiphy));
++      sdata->wdev.iftype = NL80211_IFTYPE_MONITOR;
  
-       ev = kzalloc(sizeof(*ev), gfp);
-       if (!ev)
-               return;
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
  
-       ev->type = EVENT_IBSS_JOINED;
--      memcpy(ev->cr.bssid, bssid, ETH_ALEN);
-+      memcpy(ev->ij.bssid, bssid, ETH_ALEN);
-+      ev->ij.channel = channel;
+@@ -1303,6 +1304,7 @@ static void ieee80211_setup_sdata(struct
+       sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
+       sdata->control_port_no_encrypt = false;
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
++      sdata->vif.bss_conf.idle = true;
  
-       spin_lock_irqsave(&wdev->event_lock, flags);
-       list_add_tail(&ev->list, &wdev->event_list);
-@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211
+       sdata->noack_map = 0;
  
-       wdev->ibss_fixed = params->channel_fixed;
-       wdev->ibss_dfs_possible = params->userspace_handles_dfs;
-+      wdev->chandef = params->chandef;
- #ifdef CPTCFG_CFG80211_WEXT
-       wdev->wext.ibss.chandef = params->chandef;
- #endif
-@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct
-       wdev->current_bss = NULL;
-       wdev->ssid_len = 0;
-+      memset(&wdev->chandef, 0, sizeof(wdev->chandef));
- #ifdef CPTCFG_CFG80211_WEXT
-       if (!nowext)
-               wdev->wext.ibss.ssid_len = 0;
---- a/net/wireless/trace.h
-+++ b/net/wireless/trace.h
-@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt,
-       TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
- );
+@@ -1721,6 +1723,8 @@ int ieee80211_if_add(struct ieee80211_lo
  
--DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
--      TP_PROTO(struct net_device *netdev, const u8 *addr),
--      TP_ARGS(netdev, addr)
--);
--
- DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame,
-       TP_PROTO(struct net_device *netdev, const u8 *addr),
-       TP_ARGS(netdev, addr)
-@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_r
-       TP_ARGS(netdev, addr)
- );
-+TRACE_EVENT(cfg80211_ibss_joined,
-+      TP_PROTO(struct net_device *netdev, const u8 *bssid,
-+               struct ieee80211_channel *channel),
-+      TP_ARGS(netdev, bssid, channel),
-+      TP_STRUCT__entry(
-+              NETDEV_ENTRY
-+              MAC_ENTRY(bssid)
-+              CHAN_ENTRY
-+      ),
-+      TP_fast_assign(
-+              NETDEV_ASSIGN;
-+              MAC_ASSIGN(bssid, bssid);
-+              CHAN_ASSIGN(channel);
-+      ),
-+      TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT,
-+                NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
-+);
-+
- TRACE_EVENT(cfg80211_probe_status,
-       TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
-                bool acked),
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct
-                                               ev->dc.reason, true);
-                       break;
-               case EVENT_IBSS_JOINED:
--                      __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
-+                      __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
-+                                             ev->ij.channel);
-                       break;
-               }
-               wdev_unlock(wdev);
-@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct 
-                */
-               mutex_lock_nested(&wdev_iter->mtx, 1);
-               __acquire(wdev_iter->mtx);
--              cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
-+              cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
-               wdev_unlock(wdev_iter);
-               switch (chmode) {
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct 
- void
- cfg80211_get_chan_state(struct wireless_dev *wdev,
-                       struct ieee80211_channel **chan,
--                      enum cfg80211_chan_mode *chanmode)
-+                      enum cfg80211_chan_mode *chanmode,
-+                      u8 *radar_detect)
- {
-       *chan = NULL;
-       *chanmode = CHAN_MODE_UNDEFINED;
-@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_
-                                    !wdev->ibss_dfs_possible)
-                                 ? CHAN_MODE_SHARED
-                                 : CHAN_MODE_EXCLUSIVE;
-+
-+                      /* consider worst-case - IBSS can try to return to the
-+                       * original user-specified channel as creator */
-+                      if (wdev->ibss_dfs_possible)
-+                              *radar_detect |= BIT(wdev->chandef.width);
-                       return;
-               }
-               break;
-@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_P2P_GO:
-               if (wdev->cac_started) {
--                      *chan = wdev->channel;
-+                      *chan = wdev->chandef.chan;
-                       *chanmode = CHAN_MODE_SHARED;
-+                      *radar_detect |= BIT(wdev->chandef.width);
-               } else if (wdev->beacon_interval) {
--                      *chan = wdev->channel;
-+                      *chan = wdev->chandef.chan;
-                       *chanmode = CHAN_MODE_SHARED;
-+
-+                      if (cfg80211_chandef_dfs_required(wdev->wiphy,
-+                                                        &wdev->chandef))
-+                              *radar_detect |= BIT(wdev->chandef.width);
-               }
-               return;
-       case NL80211_IFTYPE_MESH_POINT:
-               if (wdev->mesh_id_len) {
--                      *chan = wdev->channel;
-+                      *chan = wdev->chandef.chan;
-                       *chanmode = CHAN_MODE_SHARED;
-+
-+                      if (cfg80211_chandef_dfs_required(wdev->wiphy,
-+                                                        &wdev->chandef))
-+                              *radar_detect |= BIT(wdev->chandef.width);
-               }
-               return;
-       case NL80211_IFTYPE_MONITOR:
---- a/net/wireless/mesh.c
-+++ b/net/wireless/mesh.c
-@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211
-       if (!err) {
-               memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
-               wdev->mesh_id_len = setup->mesh_id_len;
--              wdev->channel = setup->chandef.chan;
-+              wdev->chandef = setup->chandef;
-       }
-       return err;
-@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg
-               err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
-                                                    chandef->chan);
-               if (!err)
--                      wdev->channel = chandef->chan;
-+                      wdev->chandef = *chandef;
-               return err;
-       }
-@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct 
-       err = rdev_leave_mesh(rdev, dev);
-       if (!err) {
-               wdev->mesh_id_len = 0;
--              wdev->channel = NULL;
-+              memset(&wdev->chandef, 0, sizeof(wdev->chandef));
-               rdev_set_qos_map(rdev, dev, NULL);
-       }
---- a/net/wireless/mlme.c
-+++ b/net/wireless/mlme.c
-@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_devic
-       if (WARN_ON(!wdev->cac_started))
-               return;
--      if (WARN_ON(!wdev->channel))
-+      if (WARN_ON(!wdev->chandef.chan))
-               return;
+               ndev->features |= local->hw.netdev_features;
  
-       switch (event) {
---- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
-@@ -5065,6 +5065,10 @@ static u16 ar9003_hw_get_max_edge_power(
-                       break;
-               }
-       }
++              netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
 +
-+      if (is2GHz && !twiceMaxEdgePower)
-+              twiceMaxEdgePower = 60;
-+
-       return twiceMaxEdgePower;
- }
---- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
-@@ -23,10 +23,11 @@
- #define MAX_MEASUREMENT       MAX_IQCAL_MEASUREMENT
- #define MAX_MAG_DELTA 11
- #define MAX_PHS_DELTA 10
-+#define MAXIQCAL        3
- struct coeff {
--      int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
--      int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
-+      int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
-+      int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
-       int iqc_coeff[2];
- };
-@@ -800,7 +801,7 @@ static bool ar9003_hw_calc_iq_corr(struc
-       if (q_q_coff > 63)
-               q_q_coff = 63;
--      iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
-+      iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
-       ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
-               chain_idx, iqc_coeff[0]);
-@@ -831,7 +832,7 @@ static bool ar9003_hw_calc_iq_corr(struc
-       if (q_q_coff > 63)
-               q_q_coff = 63;
+               ret = register_netdevice(ndev);
+               if (ret) {
+                       free_netdev(ndev);
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -25,7 +25,6 @@
+ #include "sysfs.h"
+ #include "debugfs.h"
+ #include "wext-compat.h"
+-#include "ethtool.h"
+ #include "rdev-ops.h"
  
--      iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
-+      iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
+ /* name for sysfs, %d is appended */
+@@ -940,8 +939,6 @@ static int cfg80211_netdev_notifier_call
+               /* allow mac80211 to determine the timeout */
+               wdev->ps_timeout = -1;
  
-       ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
-               chain_idx, iqc_coeff[1]);
-@@ -839,7 +840,8 @@ static bool ar9003_hw_calc_iq_corr(struc
-       return true;
- }
+-              netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops);
+-
+               if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+                    wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
+                    wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
+--- a/net/wireless/ethtool.c
++++ b/net/wireless/ethtool.c
+@@ -1,11 +1,9 @@
+ #include <linux/utsname.h>
+ #include <net/cfg80211.h>
+ #include "core.h"
+-#include "ethtool.h"
+ #include "rdev-ops.h"
  
--static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
-+static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
-+                                   int nmeasurement,
-                                    int max_delta)
+-static void cfg80211_get_drvinfo(struct net_device *dev,
+-                                      struct ethtool_drvinfo *info)
++void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
  {
-       int mp_max = -64, max_idx = 0;
-@@ -848,20 +850,20 @@ static void ar9003_hw_detect_outlier(int
-       /* find min/max mismatch across all calibrated gains */
-       for (i = 0; i < nmeasurement; i++) {
--              if (mp_coeff[i] > mp_max) {
--                      mp_max = mp_coeff[i];
-+              if (mp_coeff[i][0] > mp_max) {
-+                      mp_max = mp_coeff[i][0];
-                       max_idx = i;
--              } else if (mp_coeff[i] < mp_min) {
--                      mp_min = mp_coeff[i];
-+              } else if (mp_coeff[i][0] < mp_min) {
-+                      mp_min = mp_coeff[i][0];
-                       min_idx = i;
-               }
-       }
-       /* find average (exclude max abs value) */
-       for (i = 0; i < nmeasurement; i++) {
--              if ((abs(mp_coeff[i]) < abs(mp_max)) ||
--                  (abs(mp_coeff[i]) < abs(mp_min))) {
--                      mp_avg += mp_coeff[i];
-+              if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
-+                  (abs(mp_coeff[i][0]) < abs(mp_min))) {
-+                      mp_avg += mp_coeff[i][0];
-                       mp_count++;
-               }
-       }
-@@ -873,7 +875,7 @@ static void ar9003_hw_detect_outlier(int
-       if (mp_count)
-               mp_avg /= mp_count;
-       else
--              mp_avg = mp_coeff[nmeasurement - 1];
-+              mp_avg = mp_coeff[nmeasurement - 1][0];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
  
-       /* detect outlier */
-       if (abs(mp_max - mp_min) > max_delta) {
-@@ -882,15 +884,16 @@ static void ar9003_hw_detect_outlier(int
-               else
-                       outlier_idx = min_idx;
+@@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct 
+       strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
+               sizeof(info->bus_info));
+ }
+-
+-static int cfg80211_get_regs_len(struct net_device *dev)
+-{
+-      /* For now, return 0... */
+-      return 0;
+-}
+-
+-static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+-                      void *data)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-
+-      regs->version = wdev->wiphy->hw_version;
+-      regs->len = 0;
+-}
+-
+-static void cfg80211_get_ringparam(struct net_device *dev,
+-                                 struct ethtool_ringparam *rp)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+-
+-      memset(rp, 0, sizeof(*rp));
+-
+-      if (rdev->ops->get_ringparam)
+-              rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending,
+-                                 &rp->rx_pending, &rp->rx_max_pending);
+-}
+-
+-static int cfg80211_set_ringparam(struct net_device *dev,
+-                                struct ethtool_ringparam *rp)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+-
+-      if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
+-              return -EINVAL;
+-
+-      if (rdev->ops->set_ringparam)
+-              return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending);
+-
+-      return -ENOTSUPP;
+-}
+-
+-static int cfg80211_get_sset_count(struct net_device *dev, int sset)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+-      if (rdev->ops->get_et_sset_count)
+-              return rdev_get_et_sset_count(rdev, dev, sset);
+-      return -EOPNOTSUPP;
+-}
+-
+-static void cfg80211_get_stats(struct net_device *dev,
+-                             struct ethtool_stats *stats, u64 *data)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+-      if (rdev->ops->get_et_stats)
+-              rdev_get_et_stats(rdev, dev, stats, data);
+-}
+-
+-static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
+-{
+-      struct wireless_dev *wdev = dev->ieee80211_ptr;
+-      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+-      if (rdev->ops->get_et_strings)
+-              rdev_get_et_strings(rdev, dev, sset, data);
+-}
+-
+-const struct ethtool_ops cfg80211_ethtool_ops = {
+-      .get_drvinfo = cfg80211_get_drvinfo,
+-      .get_regs_len = cfg80211_get_regs_len,
+-      .get_regs = cfg80211_get_regs,
+-      .get_link = ethtool_op_get_link,
+-      .get_ringparam = cfg80211_get_ringparam,
+-      .set_ringparam = cfg80211_set_ringparam,
+-      .get_strings = cfg80211_get_strings,
+-      .get_ethtool_stats = cfg80211_get_stats,
+-      .get_sset_count = cfg80211_get_sset_count,
+-};
++EXPORT_SYMBOL(cfg80211_get_drvinfo);
+--- a/net/wireless/ethtool.h
++++ /dev/null
+@@ -1,6 +0,0 @@
+-#ifndef __CFG80211_ETHTOOL__
+-#define __CFG80211_ETHTOOL__
+-
+-extern const struct ethtool_ops cfg80211_ethtool_ops;
+-
+-#endif /* __CFG80211_ETHTOOL__ */
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -714,25 +714,6 @@ static inline int rdev_get_antenna(struc
+       return ret;
+ }
  
--              mp_coeff[outlier_idx] = mp_avg;
-+              mp_coeff[outlier_idx][0] = mp_avg;
-       }
+-static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev,
+-                                   u32 tx, u32 rx)
+-{
+-      int ret;
+-      trace_rdev_set_ringparam(&rdev->wiphy, tx, rx);
+-      ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx);
+-      trace_rdev_return_int(&rdev->wiphy, ret);
+-      return ret;
+-}
+-
+-static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev,
+-                                    u32 *tx, u32 *tx_max, u32 *rx,
+-                                    u32 *rx_max)
+-{
+-      trace_rdev_get_ringparam(&rdev->wiphy);
+-      rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max);
+-      trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max);
+-}
+-
+ static inline int
+ rdev_sched_scan_start(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+@@ -816,35 +797,6 @@ static inline int rdev_set_noack_map(str
  }
  
--static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
--                                               struct coeff *coeff,
--                                               bool is_reusable)
-+static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
-+                                                struct coeff *coeff,
-+                                                bool is_reusable)
- {
-       int i, im, nmeasurement;
-+      int magnitude, phase;
-       u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
-       struct ath9k_hw_cal_data *caldata = ah->caldata;
-@@ -920,21 +923,30 @@ static void ar9003_hw_tx_iqcal_load_avg_
-               if (nmeasurement > MAX_MEASUREMENT)
-                       nmeasurement = MAX_MEASUREMENT;
--              /* detect outlier only if nmeasurement > 1 */
--              if (nmeasurement > 1) {
--                      /* Detect magnitude outlier */
--                      ar9003_hw_detect_outlier(coeff->mag_coeff[i],
--                                      nmeasurement, MAX_MAG_DELTA);
--
--                      /* Detect phase outlier */
--                      ar9003_hw_detect_outlier(coeff->phs_coeff[i],
--                                      nmeasurement, MAX_PHS_DELTA);
-+              /*
-+               * Skip normal outlier detection for AR9550.
-+               */
-+              if (!AR_SREV_9550(ah)) {
-+                      /* detect outlier only if nmeasurement > 1 */
-+                      if (nmeasurement > 1) {
-+                              /* Detect magnitude outlier */
-+                              ar9003_hw_detect_outlier(coeff->mag_coeff[i],
-+                                                       nmeasurement,
-+                                                       MAX_MAG_DELTA);
-+
-+                              /* Detect phase outlier */
-+                              ar9003_hw_detect_outlier(coeff->phs_coeff[i],
-+                                                       nmeasurement,
-+                                                       MAX_PHS_DELTA);
-+                      }
-               }
+ static inline int
+-rdev_get_et_sset_count(struct cfg80211_registered_device *rdev,
+-                     struct net_device *dev, int sset)
+-{
+-      int ret;
+-      trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset);
+-      ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset);
+-      trace_rdev_return_int(&rdev->wiphy, ret);
+-      return ret;
+-}
+-
+-static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev,
+-                                   struct net_device *dev,
+-                                   struct ethtool_stats *stats, u64 *data)
+-{
+-      trace_rdev_get_et_stats(&rdev->wiphy, dev);
+-      rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data);
+-      trace_rdev_return_void(&rdev->wiphy);
+-}
+-
+-static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev,
+-                                     struct net_device *dev, u32 sset,
+-                                     u8 *data)
+-{
+-      trace_rdev_get_et_strings(&rdev->wiphy, dev, sset);
+-      rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data);
+-      trace_rdev_return_void(&rdev->wiphy);
+-}
+-
+-static inline int
+ rdev_get_channel(struct cfg80211_registered_device *rdev,
+                struct wireless_dev *wdev,
+                struct cfg80211_chan_def *chandef)
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -298,11 +298,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_return
+       TP_ARGS(wiphy)
+ );
  
-               for (im = 0; im < nmeasurement; im++) {
-+                      magnitude = coeff->mag_coeff[i][im][0];
-+                      phase = coeff->phs_coeff[i][im][0];
+-DEFINE_EVENT(wiphy_only_evt, rdev_get_ringparam,
+-      TP_PROTO(struct wiphy *wiphy),
+-      TP_ARGS(wiphy)
+-);
+-
+ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna,
+       TP_PROTO(struct wiphy *wiphy),
+       TP_ARGS(wiphy)
+@@ -580,11 +575,6 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_stop
+       TP_ARGS(wiphy, netdev)
+ );
  
--                      coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
--                              ((coeff->phs_coeff[i][im] & 0x7f) << 7);
-+                      coeff->iqc_coeff[0] =
-+                              (phase & 0x7f) | ((magnitude & 0x7f) << 7);
+-DEFINE_EVENT(wiphy_netdev_evt, rdev_get_et_stats,
+-      TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+-      TP_ARGS(wiphy, netdev)
+-);
+-
+ DEFINE_EVENT(wiphy_netdev_evt, rdev_sched_scan_stop,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+@@ -1439,11 +1429,6 @@ DECLARE_EVENT_CLASS(tx_rx_evt,
+                 WIPHY_PR_ARG, __entry->tx, __entry->rx)
+ );
  
-                       if ((im % 2) == 0)
-                               REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
-@@ -991,7 +1003,63 @@ static bool ar9003_hw_tx_iq_cal_run(stru
-       return true;
- }
+-DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam,
+-      TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx),
+-      TP_ARGS(wiphy, rx, tx)
+-);
+-
+ DEFINE_EVENT(tx_rx_evt, rdev_set_antenna,
+       TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx),
+       TP_ARGS(wiphy, rx, tx)
+@@ -1725,40 +1710,6 @@ TRACE_EVENT(rdev_set_noack_map,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
+ );
  
--static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
-+static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
-+                                  struct coeff *coeff,
-+                                  int i, int nmeasurement)
+-TRACE_EVENT(rdev_get_et_sset_count,
+-      TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int sset),
+-      TP_ARGS(wiphy, netdev, sset),
+-      TP_STRUCT__entry(
+-              WIPHY_ENTRY
+-              NETDEV_ENTRY
+-              __field(int, sset)
+-      ),
+-      TP_fast_assign(
+-              WIPHY_ASSIGN;
+-              NETDEV_ASSIGN;
+-              __entry->sset = sset;
+-      ),
+-      TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d",
+-                WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
+-);
+-
+-TRACE_EVENT(rdev_get_et_strings,
+-      TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 sset),
+-      TP_ARGS(wiphy, netdev, sset),
+-      TP_STRUCT__entry(
+-              WIPHY_ENTRY
+-              NETDEV_ENTRY
+-              __field(u32, sset)
+-      ),
+-      TP_fast_assign(
+-              WIPHY_ASSIGN;
+-              NETDEV_ASSIGN;
+-              __entry->sset = sset;
+-      ),
+-      TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u",
+-                WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
+-);
+-
+ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+--- /dev/null
++++ b/net/mac80211/ethtool.c
+@@ -0,0 +1,244 @@
++/*
++ * mac80211 ethtool hooks for cfg80211
++ *
++ * Copied from cfg.c - originally
++ * Copyright 2006-2010        Johannes Berg <johannes@sipsolutions.net>
++ * Copyright 2014     Intel Corporation (Author: Johannes Berg)
++ *
++ * This file is GPLv2 as found in COPYING.
++ */
++#include <linux/types.h>
++#include <net/cfg80211.h>
++#include "ieee80211_i.h"
++#include "sta_info.h"
++#include "driver-ops.h"
++
++static int ieee80211_set_ringparam(struct net_device *dev,
++                                 struct ethtool_ringparam *rp)
 +{
-+      struct ath_common *common = ath9k_hw_common(ah);
-+      int im, ix, iy, temp;
-+
-+      for (im = 0; im < nmeasurement; im++) {
-+              for (ix = 0; ix < MAXIQCAL - 1; ix++) {
-+                      for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
-+                              if (coeff->mag_coeff[i][im][iy] <
-+                                  coeff->mag_coeff[i][im][ix]) {
-+                                      temp = coeff->mag_coeff[i][im][ix];
-+                                      coeff->mag_coeff[i][im][ix] =
-+                                              coeff->mag_coeff[i][im][iy];
-+                                      coeff->mag_coeff[i][im][iy] = temp;
-+                              }
-+                              if (coeff->phs_coeff[i][im][iy] <
-+                                  coeff->phs_coeff[i][im][ix]) {
-+                                      temp = coeff->phs_coeff[i][im][ix];
-+                                      coeff->phs_coeff[i][im][ix] =
-+                                              coeff->phs_coeff[i][im][iy];
-+                                      coeff->phs_coeff[i][im][iy] = temp;
-+                              }
-+                      }
-+              }
-+              coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
-+              coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
-+
-+              ath_dbg(common, CALIBRATE,
-+                      "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
-+                      i, im,
-+                      coeff->mag_coeff[i][im][0],
-+                      coeff->phs_coeff[i][im][0]);
-+      }
++      struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
++
++      if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
++              return -EINVAL;
++
++      return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending);
 +}
 +
-+static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
-+                                  struct coeff *coeff,
-+                                  int iqcal_idx,
-+                                  int nmeasurement)
++static void ieee80211_get_ringparam(struct net_device *dev,
++                                  struct ethtool_ringparam *rp)
 +{
-+      int i;
++      struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
 +
-+      if ((iqcal_idx + 1) != MAXIQCAL)
-+              return false;
++      memset(rp, 0, sizeof(*rp));
 +
-+      for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-+              __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
-+      }
-+
-+      return true;
++      drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending,
++                        &rp->rx_pending, &rp->rx_max_pending);
 +}
 +
-+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
-+                                        int iqcal_idx,
-+                                        bool is_reusable)
- {
-       struct ath_common *common = ath9k_hw_common(ah);
-       const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
-@@ -1004,10 +1072,11 @@ static void ar9003_hw_tx_iq_cal_post_pro
-               AR_PHY_CHAN_INFO_TAB_1,
-               AR_PHY_CHAN_INFO_TAB_2,
-       };
--      struct coeff coeff;
-+      static struct coeff coeff;
-       s32 iq_res[6];
-       int i, im, j;
--      int nmeasurement;
-+      int nmeasurement = 0;
-+      bool outlier_detect = true;
-       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-               if (!(ah->txchainmask & (1 << i)))
-@@ -1065,17 +1134,23 @@ static void ar9003_hw_tx_iq_cal_post_pro
-                               goto tx_iqcal_fail;
-                       }
--                      coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
--                      coeff.phs_coeff[i][im] =
-+                      coeff.phs_coeff[i][im][iqcal_idx] =
-+                              coeff.iqc_coeff[0] & 0x7f;
-+                      coeff.mag_coeff[i][im][iqcal_idx] =
-                               (coeff.iqc_coeff[0] >> 7) & 0x7f;
--                      if (coeff.mag_coeff[i][im] > 63)
--                              coeff.mag_coeff[i][im] -= 128;
--                      if (coeff.phs_coeff[i][im] > 63)
--                              coeff.phs_coeff[i][im] -= 128;
-+                      if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
-+                              coeff.mag_coeff[i][im][iqcal_idx] -= 128;
-+                      if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
-+                              coeff.phs_coeff[i][im][iqcal_idx] -= 128;
-               }
-       }
--      ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
-+
-+      if (AR_SREV_9550(ah))
-+              outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
-+                                                       iqcal_idx, nmeasurement);
-+      if (outlier_detect)
-+              ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
-       return;
-@@ -1409,7 +1484,7 @@ skip_tx_iqcal:
-       }
-       if (txiqcal_done)
--              ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
-+              ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
-       else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
-               ar9003_hw_tx_iq_cal_reload(ah);
-@@ -1455,14 +1530,38 @@ skip_tx_iqcal:
-       return true;
- }
-+static bool do_ar9003_agc_cal(struct ath_hw *ah)
++static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
++      "rx_packets", "rx_bytes",
++      "rx_duplicates", "rx_fragments", "rx_dropped",
++      "tx_packets", "tx_bytes", "tx_fragments",
++      "tx_filtered", "tx_retry_failed", "tx_retries",
++      "beacon_loss", "sta_state", "txrate", "rxrate", "signal",
++      "channel", "noise", "ch_time", "ch_time_busy",
++      "ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
++};
++#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats)
++
++static int ieee80211_get_sset_count(struct net_device *dev, int sset)
 +{
-+      struct ath_common *common = ath9k_hw_common(ah);
-+      bool status;
-+
-+      REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-+                REG_READ(ah, AR_PHY_AGC_CONTROL) |
-+                AR_PHY_AGC_CONTROL_CAL);
-+
-+      status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
-+                             AR_PHY_AGC_CONTROL_CAL,
-+                             0, AH_WAIT_TIMEOUT);
-+      if (!status) {
-+              ath_dbg(common, CALIBRATE,
-+                      "offset calibration failed to complete in %d ms,"
-+                      "noisy environment?\n",
-+                      AH_WAIT_TIMEOUT / 1000);
-+              return false;
-+      }
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      int rv = 0;
++
++      if (sset == ETH_SS_STATS)
++              rv += STA_STATS_LEN;
 +
-+      return true;
++      rv += drv_get_et_sset_count(sdata, sset);
++
++      if (rv == 0)
++              return -EOPNOTSUPP;
++      return rv;
 +}
 +
- static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
-                                  struct ath9k_channel *chan)
- {
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_cal_data *caldata = ah->caldata;
-       bool txiqcal_done = false;
--      bool is_reusable = true, status = true;
-+      bool status = true;
-       bool run_agc_cal = false, sep_iq_cal = false;
-+      int i = 0;
-       /* Use chip chainmask only for calibration */
-       ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
-@@ -1485,7 +1584,12 @@ static bool ar9003_hw_init_cal_soc(struc
-        * AGC calibration. Specifically, AR9550 in SoC chips.
-        */
-       if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
--              txiqcal_done = true;
-+              if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
-+                                 AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
-+                              txiqcal_done = true;
-+              } else {
-+                      txiqcal_done = false;
++static void ieee80211_get_stats(struct net_device *dev,
++                              struct ethtool_stats *stats,
++                              u64 *data)
++{
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      struct ieee80211_chanctx_conf *chanctx_conf;
++      struct ieee80211_channel *channel;
++      struct sta_info *sta;
++      struct ieee80211_local *local = sdata->local;
++      struct station_info sinfo;
++      struct survey_info survey;
++      int i, q;
++#define STA_STATS_SURVEY_LEN 7
++
++      memset(data, 0, sizeof(u64) * STA_STATS_LEN);
++
++#define ADD_STA_STATS(sta)                            \
++      do {                                            \
++              data[i++] += sta->rx_packets;           \
++              data[i++] += sta->rx_bytes;             \
++              data[i++] += sta->num_duplicates;       \
++              data[i++] += sta->rx_fragments;         \
++              data[i++] += sta->rx_dropped;           \
++                                                      \
++              data[i++] += sinfo.tx_packets;          \
++              data[i++] += sinfo.tx_bytes;            \
++              data[i++] += sta->tx_fragments;         \
++              data[i++] += sta->tx_filtered_count;    \
++              data[i++] += sta->tx_retry_failed;      \
++              data[i++] += sta->tx_retry_count;       \
++              data[i++] += sta->beacon_loss_count;    \
++      } while (0)
++
++      /* For Managed stations, find the single station based on BSSID
++       * and use that.  For interface types, iterate through all available
++       * stations and add stats for any station that is assigned to this
++       * network device.
++       */
++
++      mutex_lock(&local->sta_mtx);
++
++      if (sdata->vif.type == NL80211_IFTYPE_STATION) {
++              sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
++
++              if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
++                      goto do_survey;
++
++              sinfo.filled = 0;
++              sta_set_sinfo(sta, &sinfo);
++
++              i = 0;
++              ADD_STA_STATS(sta);
++
++              data[i++] = sta->sta_state;
++
++
++              if (sinfo.filled & STATION_INFO_TX_BITRATE)
++                      data[i] = 100000 *
++                              cfg80211_calculate_bitrate(&sinfo.txrate);
++              i++;
++              if (sinfo.filled & STATION_INFO_RX_BITRATE)
++                      data[i] = 100000 *
++                              cfg80211_calculate_bitrate(&sinfo.rxrate);
++              i++;
++
++              if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
++                      data[i] = (u8)sinfo.signal_avg;
++              i++;
++      } else {
++              list_for_each_entry(sta, &local->sta_list, list) {
++                      /* Make sure this station belongs to the proper dev */
++                      if (sta->sdata->dev != dev)
++                              continue;
++
++                      sinfo.filled = 0;
++                      sta_set_sinfo(sta, &sinfo);
++                      i = 0;
++                      ADD_STA_STATS(sta);
 +              }
-               run_agc_cal = true;
-       } else {
-               sep_iq_cal = true;
-@@ -1512,27 +1616,37 @@ skip_tx_iqcal:
-               if (AR_SREV_9330_11(ah))
-                       ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
--              /* Calibrate the AGC */
--              REG_WRITE(ah, AR_PHY_AGC_CONTROL,
--                        REG_READ(ah, AR_PHY_AGC_CONTROL) |
--                        AR_PHY_AGC_CONTROL_CAL);
--
--              /* Poll for offset calibration complete */
--              status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
--                                     AR_PHY_AGC_CONTROL_CAL,
--                                     0, AH_WAIT_TIMEOUT);
--      }
-+              /*
-+               * For non-AR9550 chips, we just trigger AGC calibration
-+               * in the HW, poll for completion and then process
-+               * the results.
-+               *
-+               * For AR955x, we run it multiple times and use
-+               * median IQ correction.
-+               */
-+              if (!AR_SREV_9550(ah)) {
-+                      status = do_ar9003_agc_cal(ah);
-+                      if (!status)
-+                              return false;
--      if (!status) {
--              ath_dbg(common, CALIBRATE,
--                      "offset calibration failed to complete in %d ms; noisy environment?\n",
--                      AH_WAIT_TIMEOUT / 1000);
--              return false;
-+                      if (txiqcal_done)
-+                              ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
-+              } else {
-+                      if (!txiqcal_done) {
-+                              status = do_ar9003_agc_cal(ah);
-+                              if (!status)
-+                                      return false;
-+                      } else {
-+                              for (i = 0; i < MAXIQCAL; i++) {
-+                                      status = do_ar9003_agc_cal(ah);
-+                                      if (!status)
-+                                              return false;
-+                                      ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
-+                              }
++      }
++
++do_survey:
++      i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
++      /* Get survey stats for current channel */
++      survey.filled = 0;
++
++      rcu_read_lock();
++      chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
++      if (chanctx_conf)
++              channel = chanctx_conf->def.chan;
++      else
++              channel = NULL;
++      rcu_read_unlock();
++
++      if (channel) {
++              q = 0;
++              do {
++                      survey.filled = 0;
++                      if (drv_get_survey(local, q, &survey) != 0) {
++                              survey.filled = 0;
++                              break;
 +                      }
-+              }
-       }
--      if (txiqcal_done)
--              ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
--
-       /* Revert chainmask to runtime parameters */
-       ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
---- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
-+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
-@@ -15,6 +15,8 @@
- #ifndef RTL8187_H
- #define RTL8187_H
-+#include <linux/cache.h>
-+
- #include "rtl818x.h"
- #include "leds.h"
-@@ -139,7 +141,10 @@ struct rtl8187_priv {
-       u8 aifsn[4];
-       u8 rfkill_mask;
-       struct {
--              __le64 buf;
-+              union {
-+                      __le64 buf;
-+                      u8 dummy1[L1_CACHE_BYTES];
-+              } ____cacheline_aligned;
-               struct sk_buff_head queue;
-       } b_tx_status; /* This queue is used by both -b and non-b devices */
-       struct mutex io_mutex;
-@@ -147,7 +152,8 @@ struct rtl8187_priv {
-               u8 bits8;
-               __le16 bits16;
-               __le32 bits32;
--      } *io_dmabuf;
-+              u8 dummy2[L1_CACHE_BYTES];
-+      } *io_dmabuf ____cacheline_aligned;
-       bool rfkill_off;
-       u16 seqno;
- };
---- a/net/mac80211/wme.c
-+++ b/net/mac80211/wme.c
-@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80
-               return IEEE80211_AC_BE;
-       }
-+      if (skb->protocol == sdata->control_port_protocol) {
-+              skb->priority = 7;
-+              return ieee80211_downgrade_queue(sdata, skb);
++                      q++;
++              } while (channel != survey.channel);
 +      }
 +
-       /* use the data classifier to determine what 802.1d tag the
-        * data frame has */
-       rcu_read_lock();
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_
-       for (tidno = 0, tid = &an->tid[tidno];
-            tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
--              if (!tid->sched)
--                      continue;
--
-               ac = tid->ac;
-               txq = ac->txq;
-               ath_txq_lock(sc, txq);
-+              if (!tid->sched) {
-+                      ath_txq_unlock(sc, txq);
-+                      continue;
-+              }
++      if (survey.filled)
++              data[i++] = survey.channel->center_freq;
++      else
++              data[i++] = 0;
++      if (survey.filled & SURVEY_INFO_NOISE_DBM)
++              data[i++] = (u8)survey.noise;
++      else
++              data[i++] = -1LL;
++      if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
++              data[i++] = survey.channel_time;
++      else
++              data[i++] = -1LL;
++      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
++              data[i++] = survey.channel_time_busy;
++      else
++              data[i++] = -1LL;
++      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
++              data[i++] = survey.channel_time_ext_busy;
++      else
++              data[i++] = -1LL;
++      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
++              data[i++] = survey.channel_time_rx;
++      else
++              data[i++] = -1LL;
++      if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
++              data[i++] = survey.channel_time_tx;
++      else
++              data[i++] = -1LL;
 +
-               buffered = ath_tid_has_buffered(tid);
-               tid->sched = false;
-@@ -1696,7 +1698,7 @@ int ath_cabq_update(struct ath_softc *sc
-       ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
--      qi.tqi_readyTime = (cur_conf->beacon_interval *
-+      qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) *
-                           ATH_CABQ_READY_TIME) / 100;
-       ath_txq_update(sc, qnum, &qi);
-@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw
-               txq->stopped = true;
-       }
-+      if (txctl->an)
-+              tid = ath_get_skb_tid(sc, txctl->an, skb);
-+
-       if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
-               ath_txq_unlock(sc, txq);
-               txq = sc->tx.uapsdq;
-               ath_txq_lock(sc, txq);
-       } else if (txctl->an &&
-                  ieee80211_is_data_present(hdr->frame_control)) {
--              tid = ath_get_skb_tid(sc, txctl->an, skb);
--
-               WARN_ON(tid->ac->txq != txctl->txq);
-               if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
---- a/drivers/net/wireless/ath/ath9k/init.c
-+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -943,6 +943,7 @@ static void ath9k_set_hw_capab(struct at
-       hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
-       hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-+      hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
-       hw->queues = 4;
-       hw->max_rates = 4;
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1700,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(stru
- void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
- void ieee80211_add_pending_skb(struct ieee80211_local *local,
-                              struct sk_buff *skb);
--void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
--                                 struct sk_buff_head *skbs,
--                                 void (*fn)(void *data), void *data);
--static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
--                                            struct sk_buff_head *skbs)
--{
--      ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
--}
-+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
-+                              struct sk_buff_head *skbs);
- void ieee80211_flush_queues(struct ieee80211_local *local,
-                           struct ieee80211_sub_if_data *sdata);
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee
-       return -ENOENT;
- }
--static void cleanup_single_sta(struct sta_info *sta)
-+static void __cleanup_single_sta(struct sta_info *sta)
- {
-       int ac, i;
-       struct tid_ampdu_tx *tid_tx;
-@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct st
-       struct ieee80211_local *local = sdata->local;
-       struct ps_data *ps;
--      if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
-+      if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
-+          test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
-               if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
-                   sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-                       ps = &sdata->bss->ps;
-@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct st
-                       return;
-               clear_sta_flag(sta, WLAN_STA_PS_STA);
-+              clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-               atomic_dec(&ps->num_sta_ps);
-               sta_info_recalc_tim(sta);
-@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct st
-               ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
-               kfree(tid_tx);
-       }
++      mutex_unlock(&local->sta_mtx);
++
++      if (WARN_ON(i != STA_STATS_LEN))
++              return;
++
++      drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
 +}
-+static void cleanup_single_sta(struct sta_info *sta)
++
++static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
 +{
-+      struct ieee80211_sub_if_data *sdata = sta->sdata;
-+      struct ieee80211_local *local = sdata->local;
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      int sz_sta_stats = 0;
 +
-+      __cleanup_single_sta(sta);
-       sta_info_free(local, sta);
- }
-@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct i
-       rcu_read_unlock();
-       spin_lock_init(&sta->lock);
-+      spin_lock_init(&sta->ps_lock);
-       INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
-       INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
-       mutex_init(&sta->ampdu_mlme.mtx);
-@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct
-               goto out_err;
-       }
--      /* notify driver */
--      err = sta_info_insert_drv_state(local, sdata, sta);
--      if (err)
--              goto out_err;
--
-       local->num_sta++;
-       local->sta_generation++;
-       smp_mb();
-+      /* simplify things and don't accept BA sessions yet */
-+      set_sta_flag(sta, WLAN_STA_BLOCK_BA);
++      if (sset == ETH_SS_STATS) {
++              sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
++              memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
++      }
++      drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
++}
 +
-       /* make the station visible */
-       sta_info_hash_add(local, sta);
-       list_add_rcu(&sta->list, &local->sta_list);
-+      /* notify driver */
-+      err = sta_info_insert_drv_state(local, sdata, sta);
-+      if (err)
-+              goto out_remove;
++static int ieee80211_get_regs_len(struct net_device *dev)
++{
++      return 0;
++}
 +
-       set_sta_flag(sta, WLAN_STA_INSERTED);
-+      /* accept BA sessions now */
-+      clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
-       ieee80211_recalc_min_chandef(sdata);
-       ieee80211_sta_debugfs_add(sta);
-@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct
-               mesh_accept_plinks_update(sdata);
-       return 0;
-+ out_remove:
-+      sta_info_hash_del(local, sta);
-+      list_del_rcu(&sta->list);
-+      local->num_sta--;
-+      synchronize_net();
-+      __cleanup_single_sta(sta);
-  out_err:
-       mutex_unlock(&local->sta_mtx);
-       rcu_read_lock();
-@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta
- }
- EXPORT_SYMBOL(ieee80211_find_sta);
--static void clear_sta_ps_flags(void *_sta)
-+/* powersave support code */
-+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
- {
--      struct sta_info *sta = _sta;
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
-+      struct ieee80211_local *local = sdata->local;
-+      struct sk_buff_head pending;
-+      int filtered = 0, buffered = 0, ac;
-+      unsigned long flags;
-       struct ps_data *ps;
-       if (sdata->vif.type == NL80211_IFTYPE_AP ||
-@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_st
-       else
-               return;
--      clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
--      if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
--              atomic_dec(&ps->num_sta_ps);
--}
--
--/* powersave support code */
--void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
--{
--      struct ieee80211_sub_if_data *sdata = sta->sdata;
--      struct ieee80211_local *local = sdata->local;
--      struct sk_buff_head pending;
--      int filtered = 0, buffered = 0, ac;
--      unsigned long flags;
--
-       clear_sta_flag(sta, WLAN_STA_SP);
-       BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
-@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(str
-       skb_queue_head_init(&pending);
-+      /* sync with ieee80211_tx_h_unicast_ps_buf */
-+      spin_lock(&sta->ps_lock);
-       /* Send all buffered frames to the station */
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-               int count = skb_queue_len(&pending), tmp;
-@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(str
-               buffered += tmp - count;
-       }
--      ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
-+      ieee80211_add_pending_skbs(local, &pending);
-+      clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
-+      clear_sta_flag(sta, WLAN_STA_PS_STA);
-+      spin_unlock(&sta->ps_lock);
++static void ieee80211_get_regs(struct net_device *dev,
++                             struct ethtool_regs *regs,
++                             void *data)
++{
++      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +
-+      atomic_dec(&ps->num_sta_ps);
-       /* This station just woke up and isn't aware of our SMPS state */
-       if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
-  * @drv_unblock_wk: used for driver PS unblocking
-  * @listen_interval: listen interval of this station, when we're acting as AP
-  * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
-+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
-  * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
-  *    when it leaves power saving state or polls
-  * @tx_filtered: buffers (per AC) of frames we already tried to
-@@ -356,10 +357,8 @@ struct sta_info {
-       /* use the accessors defined below */
-       unsigned long _flags;
--      /*
--       * STA powersave frame queues, no more than the internal
--       * locking required.
--       */
-+      /* STA powersave lock and frame queues */
-+      spinlock_t ps_lock;
-       struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
-       struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
-       unsigned long driver_buffered_tids;
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ie
-       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- }
--void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
--                                 struct sk_buff_head *skbs,
--                                 void (*fn)(void *data), void *data)
-+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
-+                              struct sk_buff_head *skbs)
- {
-       struct ieee80211_hw *hw = &local->hw;
-       struct sk_buff *skb;
-@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struc
-               __skb_queue_tail(&local->pending[queue], skb);
-       }
--      if (fn)
--              fn(data);
--
-       for (i = 0; i < hw->queues; i++)
-               __ieee80211_wake_queue(hw, i,
-                       IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regu
-               return;
-       case NL80211_REGDOM_SET_BY_USER:
-               treatment = reg_process_hint_user(reg_request);
--              if (treatment == REG_REQ_OK ||
-+              if (treatment == REG_REQ_IGNORE ||
-                   treatment == REG_REQ_ALREADY_SET)
-                       return;
-               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -138,43 +138,41 @@ static ssize_t read_file_ani(struct file
-       unsigned int len = 0, size = 1024;
-       ssize_t retval = 0;
-       char *buf;
-+      int i;
-+      struct {
-+              const char *name;
-+              unsigned int val;
-+      } ani_info[] = {
-+              { "ANI RESET", ah->stats.ast_ani_reset },
-+              { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel },
-+              { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel },
-+              { "SPUR UP", ah->stats.ast_ani_spurup },
-+              { "SPUR DOWN", ah->stats.ast_ani_spurup },
-+              { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon },
-+              { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff },
-+              { "MRC-CCK ON", ah->stats.ast_ani_ccklow },
-+              { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh },
-+              { "FIR-STEP UP", ah->stats.ast_ani_stepup },
-+              { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown },
-+              { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero },
-+              { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs },
-+              { "CCK ERRORS", ah->stats.ast_ani_cckerrs },
-+      };
-       buf = kzalloc(size, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
--      if (common->disable_ani) {
--              len += scnprintf(buf + len, size - len, "%s: %s\n",
--                               "ANI", "DISABLED");
-+      len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI",
-+                       common->disable_ani ? "DISABLED" : "ENABLED");
-+
-+      if (common->disable_ani)
-               goto exit;
--      }
--      len += scnprintf(buf + len, size - len, "%15s: %s\n",
--                       "ANI", "ENABLED");
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "ANI RESET", ah->stats.ast_ani_reset);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "SPUR UP", ah->stats.ast_ani_spurup);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "SPUR DOWN", ah->stats.ast_ani_spurup);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "MRC-CCK ON", ah->stats.ast_ani_ccklow);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "FIR-STEP UP", ah->stats.ast_ani_stepup);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
--      len += scnprintf(buf + len, size - len, "%15s: %u\n",
--                       "CCK ERRORS", ah->stats.ast_ani_cckerrs);
-+      for (i = 0; i < ARRAY_SIZE(ani_info); i++)
-+              len += scnprintf(buf + len, size - len, "%15s: %u\n",
-+                               ani_info[i].name, ani_info[i].val);
-+
- exit:
-       if (len > size)
-               len = size;
-@@ -866,6 +864,12 @@ static ssize_t read_file_reset(struct fi
-                        "%17s: %2d\n", "PLL RX Hang",
-                        sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-+                       "%17s: %2d\n", "MAC Hang",
-+                       sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
-+      len += scnprintf(buf + len, sizeof(buf) - len,
-+                       "%17s: %2d\n", "Stuck Beacon",
-+                       sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
-+      len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "MCI Reset",
-                        sc->debug.stats.reset[RESET_TYPE_MCI]);
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct 
-       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
-               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
--      if (IS_CHAN_QUARTER_RATE(chan))
--              rfMode |= AR_PHY_MODE_QUARTER;
--      if (IS_CHAN_HALF_RATE(chan))
--              rfMode |= AR_PHY_MODE_HALF;
-       if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
-               REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
---- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-@@ -706,6 +706,7 @@ ath5k_get_survey(struct ieee80211_hw *hw
-       survey->channel = conf->chandef.chan;
-       survey->noise = ah->ah_noise_floor;
-       survey->filled = SURVEY_INFO_NOISE_DBM |
-+                      SURVEY_INFO_IN_USE |
-                       SURVEY_INFO_CHANNEL_TIME |
-                       SURVEY_INFO_CHANNEL_TIME_BUSY |
-                       SURVEY_INFO_CHANNEL_TIME_RX |
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx
-                       return NULL;
-               /*
--               * mark descriptor as zero-length and set the 'more'
--               * flag to ensure that both buffers get discarded
-+               * Re-check previous descriptor, in case it has been filled
-+               * in the mean time.
-                */
--              rs->rs_datalen = 0;
--              rs->rs_more = true;
-+              ret = ath9k_hw_rxprocdesc(ah, ds, rs);
-+              if (ret == -EINPROGRESS) {
-+                      /*
-+                       * mark descriptor as zero-length and set the 'more'
-+                       * flag to ensure that both buffers get discarded
-+                       */
-+                      rs->rs_datalen = 0;
-+                      rs->rs_more = true;
-+              }
++      regs->version = wdev->wiphy->hw_version;
++      regs->len = 0;
++}
++
++const struct ethtool_ops ieee80211_ethtool_ops = {
++      .get_drvinfo = cfg80211_get_drvinfo,
++      .get_regs_len = ieee80211_get_regs_len,
++      .get_regs = ieee80211_get_regs,
++      .get_link = ethtool_op_get_link,
++      .get_ringparam = ieee80211_get_ringparam,
++      .set_ringparam = ieee80211_set_ringparam,
++      .get_strings = ieee80211_get_strings,
++      .get_ethtool_stats = ieee80211_get_stats,
++      .get_sset_count = ieee80211_get_sset_count,
++};
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -143,7 +143,7 @@ ieee80211_ibss_build_presp(struct ieee80
+               *pos++ = csa_settings->block_tx ? 1 : 0;
+               *pos++ = ieee80211_frequency_to_channel(
+                               csa_settings->chandef.chan->center_freq);
+-              sdata->csa_counter_offset_beacon[0] = (pos - presp->head);
++              presp->csa_counter_offsets[0] = (pos - presp->head);
+               *pos++ = csa_settings->count;
        }
  
-       list_del(&bf->list);
-@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struc
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_hdr *hdr;
-       bool discard_current = sc->rx.discard_next;
--      int ret = 0;
-       /*
-        * Discard corrupt descriptors which are marked in
-        * ath_get_next_rx_buf().
-        */
--      sc->rx.discard_next = rx_stats->rs_more;
-       if (discard_current)
--              return -EINVAL;
-+              goto corrupt;
-+
-+      sc->rx.discard_next = false;
+@@ -1677,6 +1677,7 @@ int ieee80211_ibss_join(struct ieee80211
+       sdata->u.ibss.control_port = params->control_port;
+       sdata->u.ibss.userspace_handles_dfs = params->userspace_handles_dfs;
+       sdata->u.ibss.basic_rates = params->basic_rates;
++      sdata->u.ibss.last_scan_completed = jiffies;
  
-       /*
-        * Discard zero-length packets.
-        */
-       if (!rx_stats->rs_datalen) {
-               RX_STAT_INC(rx_len_err);
--              return -EINVAL;
-+              goto corrupt;
+       /* fix basic_rates if channel does not support these rates */
+       rate_flags = ieee80211_chandef_rate_flags(&params->chandef);
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -679,7 +679,7 @@ ieee80211_mesh_build_beacon(struct ieee8
+               *pos++ = 0x0;
+               *pos++ = ieee80211_frequency_to_channel(
+                               csa->settings.chandef.chan->center_freq);
+-              sdata->csa_counter_offset_beacon[0] = hdr_len + 6;
++              bcn->csa_counter_offsets[0] = hdr_len + 6;
+               *pos++ = csa->settings.count;
+               *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
+               *pos++ = 6;
+--- a/net/wireless/genregdb.awk
++++ b/net/wireless/genregdb.awk
+@@ -65,17 +65,7 @@ function parse_reg_rule()
+       sub(/,/, "", units)
+       dfs_cac = $9
+       if (units == "mW") {
+-              if (power == 100) {
+-                      power = 20
+-              } else if (power == 200) {
+-                      power = 23
+-              } else if (power == 500) {
+-                      power = 27
+-              } else if (power == 1000) {
+-                      power = 30
+-              } else {
+-                      print "Unknown power value in database!"
+-              }
++              power = 10 * log(power)/log(10)
+       } else {
+               dfs_cac = $8
        }
+@@ -114,7 +104,7 @@ function parse_reg_rule()
  
--        /*
--         * rs_status follows rs_datalen so if rs_datalen is too large
--         * we can take a hint that hardware corrupted it, so ignore
--         * those frames.
--         */
-+      /*
-+       * rs_status follows rs_datalen so if rs_datalen is too large
-+       * we can take a hint that hardware corrupted it, so ignore
-+       * those frames.
-+       */
-       if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) {
-               RX_STAT_INC(rx_len_err);
--              return -EINVAL;
-+              goto corrupt;
        }
+       flags = flags "0"
+-      printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
++      printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %.0f, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
+       rules++
+ }
  
-       /* Only use status info from the last fragment */
-@@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struc
-        * This is different from the other corrupt descriptor
-        * condition handled above.
-        */
--      if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) {
--              ret = -EINVAL;
--              goto exit;
--      }
-+      if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC)
-+              goto corrupt;
-       hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len);
-@@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struc
-               if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime))
-                       RX_STAT_INC(rx_spectral);
+--- a/net/mac80211/debugfs_netdev.c
++++ b/net/mac80211/debugfs_netdev.c
+@@ -34,8 +34,7 @@ static ssize_t ieee80211_if_read(
+       ssize_t ret = -EINVAL;
  
--              ret = -EINVAL;
--              goto exit;
-+              return -EINVAL;
-       }
+       read_lock(&dev_base_lock);
+-      if (sdata->dev->reg_state == NETREG_REGISTERED)
+-              ret = (*format)(sdata, buf, sizeof(buf));
++      ret = (*format)(sdata, buf, sizeof(buf));
+       read_unlock(&dev_base_lock);
  
-       /*
-        * everything but the rate is checked here, the rate check is done
-        * separately to avoid doing two lookups for a rate for each frame.
-        */
--      if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) {
--              ret = -EINVAL;
--              goto exit;
--      }
-+      if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
-+              return -EINVAL;
+       if (ret >= 0)
+@@ -62,8 +61,7 @@ static ssize_t ieee80211_if_write(
  
-       if (ath_is_mybeacon(common, hdr)) {
-               RX_STAT_INC(rx_beacons);
-@@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struc
-       /*
-        * This shouldn't happen, but have a safety check anyway.
-        */
--      if (WARN_ON(!ah->curchan)) {
--              ret = -EINVAL;
--              goto exit;
--      }
-+      if (WARN_ON(!ah->curchan))
-+              return -EINVAL;
--      if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
--              ret =-EINVAL;
--              goto exit;
--      }
-+      if (ath9k_process_rate(common, hw, rx_stats, rx_status))
-+              return -EINVAL;
+       ret = -ENODEV;
+       rtnl_lock();
+-      if (sdata->dev->reg_state == NETREG_REGISTERED)
+-              ret = (*write)(sdata, buf, count);
++      ret = (*write)(sdata, buf, count);
+       rtnl_unlock();
  
-       ath9k_process_rssi(common, hw, rx_stats, rx_status);
+       return ret;
+--- a/drivers/net/wireless/b43/xmit.c
++++ b/drivers/net/wireless/b43/xmit.c
+@@ -811,9 +811,13 @@ void b43_rx(struct b43_wldev *dev, struc
+               break;
+       case B43_PHYTYPE_G:
+               status.band = IEEE80211_BAND_2GHZ;
+-              /* chanid is the radio channel cookie value as used
+-               * to tune the radio. */
+-              status.freq = chanid + 2400;
++              /* Somewhere between 478.104 and 508.1084 firmware for G-PHY
++               * has been modified to be compatible with N-PHY and others.
++               */
++              if (dev->fw.rev >= 508)
++                      status.freq = ieee80211_channel_to_frequency(chanid, status.band);
++              else
++                      status.freq = chanid + 2400;
+               break;
+       case B43_PHYTYPE_N:
+       case B43_PHYTYPE_LP:
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -5216,6 +5216,7 @@ static int b43_wireless_core_attach(stru
+       /* We don't support 5 GHz on some PHYs yet */
+       switch (dev->phy.type) {
+       case B43_PHYTYPE_A:
++      case B43_PHYTYPE_G:
+       case B43_PHYTYPE_N:
+       case B43_PHYTYPE_LP:
+       case B43_PHYTYPE_HT:
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -935,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, 
+               if (!band_rule_found)
+                       band_rule_found = freq_in_rule_band(fr, center_freq);
  
-@@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struc
-               sc->rx.num_pkts++;
- #endif
+-              bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5));
++              bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
  
--exit:
--      sc->rx.discard_next = false;
--      return ret;
-+      return 0;
-+
-+corrupt:
-+      sc->rx.discard_next = rx_stats->rs_more;
-+      return -EINVAL;
+               if (band_rule_found && bw_fits)
+                       return rr;
+@@ -1019,10 +1019,10 @@ static void chan_reg_rule_print_dbg(cons
  }
+ #endif
  
- static void ath9k_rx_skb_postprocess(struct ath_common *common,
---- a/drivers/net/wireless/ath/ath9k/ani.c
-+++ b/drivers/net/wireless/ath/ath9k/ani.c
-@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct
-       if (ah->opmode == NL80211_IFTYPE_STATION &&
-           BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
-               weak_sig = true;
+-/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency
+- * chan->center_freq fits there.
+- * If there is no such reg_rule, disable the channel, otherwise set the
+- * flags corresponding to the bandwidths allowed in the particular reg_rule
++/*
++ * Note that right now we assume the desired channel bandwidth
++ * is always 20 MHz for each individual channel (HT40 uses 20 MHz
++ * per channel, the primary and the extension channel).
+  */
+ static void handle_channel(struct wiphy *wiphy,
+                          enum nl80211_reg_initiator initiator,
+@@ -1083,12 +1083,8 @@ static void handle_channel(struct wiphy 
+       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
+               max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+-      if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+-              bw_flags = IEEE80211_CHAN_NO_10MHZ;
+-      if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+-              bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(40))
+-              bw_flags |= IEEE80211_CHAN_NO_HT40;
++              bw_flags = IEEE80211_CHAN_NO_HT40;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(80))
+               bw_flags |= IEEE80211_CHAN_NO_80MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(160))
+@@ -1522,12 +1518,8 @@ static void handle_channel_custom(struct
+       if (reg_rule->flags & NL80211_RRF_AUTO_BW)
+               max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+-      if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+-              bw_flags = IEEE80211_CHAN_NO_10MHZ;
+-      if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+-              bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(40))
+-              bw_flags |= IEEE80211_CHAN_NO_HT40;
++              bw_flags = IEEE80211_CHAN_NO_HT40;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(80))
+               bw_flags |= IEEE80211_CHAN_NO_80MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(160))
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -185,7 +185,8 @@ struct ath_atx_ac {
+ struct ath_frame_info {
+       struct ath_buf *bf;
+-      int framelen;
++      u16 framelen;
++      s8 txq;
+       enum ath9k_key_type keytype;
+       u8 keyix;
+       u8 rtscts_rate;
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -147,15 +147,13 @@ static void ath_set_rates(struct ieee802
+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+                            struct sk_buff *skb)
+ {
+-      int q;
 -
-       /*
--       * OFDM Weak signal detection is always enabled for AP mode.
-+       * Newer chipsets are better at dealing with high PHY error counts -
-+       * keep weak signal detection enabled when no RSSI threshold is
-+       * available to determine if it is needed (mode != STA)
-        */
--      if (ah->opmode != NL80211_IFTYPE_AP &&
--          aniState->ofdmWeakSigDetect != weak_sig) {
--              ath9k_hw_ani_control(ah,
--                                   ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
--                                   entry_ofdm->ofdm_weak_signal_on);
--      }
-+      else if (AR_SREV_9300_20_OR_LATER(ah) &&
-+               ah->opmode != NL80211_IFTYPE_STATION)
-+              weak_sig = true;
-+
-+      /* Older chipsets are more sensitive to high PHY error counts */
-+      else if (!AR_SREV_9300_20_OR_LATER(ah) &&
-+               aniState->ofdmNoiseImmunityLevel >= 8)
-+              weak_sig = false;
-+
-+      if (aniState->ofdmWeakSigDetect != weak_sig)
-+              ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-+                                   weak_sig);
-+
-+      if (!AR_SREV_9300_20_OR_LATER(ah))
-+              return;
+-      q = skb_get_queue_mapping(skb);
+-      if (txq == sc->tx.uapsdq)
+-              txq = sc->tx.txq_map[q];
++      struct ath_frame_info *fi = get_frame_info(skb);
++      int q = fi->txq;
+-      if (txq != sc->tx.txq_map[q])
++      if (q < 0)
+               return;
  
-       if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
-               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
-@@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah, 
-       BUG_ON(aniState == NULL);
-       ah->stats.ast_ani_reset++;
--      /* only allow a subset of functions in AP mode */
--      if (ah->opmode == NL80211_IFTYPE_AP) {
--              if (IS_CHAN_2GHZ(chan)) {
--                      ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
--                                          ATH9K_ANI_FIRSTEP_LEVEL);
--                      if (AR_SREV_9300_20_OR_LATER(ah))
--                              ah->ani_function |= ATH9K_ANI_MRC_CCK;
--              } else
--                      ah->ani_function = 0;
--      }
--
-       ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
-                        aniState->ofdmNoiseImmunityLevel);
-       cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
-@@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah
-       ath_dbg(common, ANI, "Initialize ANI\n");
--      ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
--      ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
--      ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
--      ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
-+      if (AR_SREV_9300_20_OR_LATER(ah)) {
-+              ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
-+              ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
-+              ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
-+              ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
-+      } else {
-+              ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
-+              ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
-+              ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
-+              ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
-+      }
++      txq = sc->tx.txq_map[q];
+       if (WARN_ON(--txq->pending_frames < 0))
+               txq->pending_frames = 0;
+@@ -1999,6 +1997,7 @@ static void setup_frame_info(struct ieee
+               an = (struct ath_node *) sta->drv_priv;
+       memset(fi, 0, sizeof(*fi));
++      fi->txq = -1;
+       if (hw_key)
+               fi->keyix = hw_key->hw_key_idx;
+       else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+@@ -2150,6 +2149,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = txctl->sta;
+       struct ieee80211_vif *vif = info->control.vif;
++      struct ath_frame_info *fi = get_frame_info(skb);
+       struct ath_softc *sc = hw->priv;
+       struct ath_txq *txq = txctl->txq;
+       struct ath_atx_tid *tid = NULL;
+@@ -2170,11 +2170,13 @@ int ath_tx_start(struct ieee80211_hw *hw
+       q = skb_get_queue_mapping(skb);
+       ath_txq_lock(sc, txq);
+-      if (txq == sc->tx.txq_map[q] &&
+-          ++txq->pending_frames > sc->tx.txq_max_pending[q] &&
+-          !txq->stopped) {
+-              ieee80211_stop_queue(sc->hw, q);
+-              txq->stopped = true;
++      if (txq == sc->tx.txq_map[q]) {
++              fi->txq = q;
++              if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
++                  !txq->stopped) {
++                      ieee80211_stop_queue(sc->hw, q);
++                      txq->stopped = true;
++              }
+       }
  
-       ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
---- a/drivers/net/wireless/ath/ath9k/ani.h
-+++ b/drivers/net/wireless/ath/ath9k/ani.h
-@@ -22,12 +22,16 @@
- /* units are errors per second */
- #define ATH9K_ANI_OFDM_TRIG_HIGH           3500
- #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
-+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD       500
- #define ATH9K_ANI_OFDM_TRIG_LOW           400
- #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
-+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
- #define ATH9K_ANI_CCK_TRIG_HIGH           600
-+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
- #define ATH9K_ANI_CCK_TRIG_LOW            300
-+#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100
- #define ATH9K_ANI_SPUR_IMMUNE_LVL         3
- #define ATH9K_ANI_FIRSTEP_LVL             2
+       if (txctl->an && ieee80211_is_data_present(hdr->frame_control))