mac80211: merge a series of cleanups/fixes
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index 702b17b33326848f7a7d08e85b0f0c037806d257..33053884eccea12b2eb265cff27b8c3e832707f9 100644 (file)
-commit 230ab8c1880266c9cfceac962e2d48309dea79a7
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon May 19 21:48:56 2014 +0200
-
-    ath9k: re-schedule rx processing after budget exceeded
-    
-    Should improve rx stability under load
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
-commit ff9655bebd25d35ab13c2515a029723b69949720
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon May 19 21:20:49 2014 +0200
-
-    ath9k: avoid passing buffers to the hardware during flush
-    
-    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: Felix Fietkau <nbd@openwrt.org>
-
-commit 46c5d7d207a2a0725066c0928fd19b8c578b7d4f
-Author: Oleksij Rempel <linux@rempel-privat.de>
-Date:   Tue May 20 00:02:03 2014 +0200
-
-    ath9k_htc: fix build with disabled debug
-    
-      CC [M]  drivers/net/wireless/ath/ath9k/htc_drv_txrx.o
-    drivers/net/wireless/ath/ath9k/htc_drv_txrx.c: In function ‘ath9k_rx_prepare’:
-    drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:1006:2: warning: passing argument 2 of ‘ath9k_htc_err_stat_rx’ from incompatible pointer type [enabled by default]
-      ath9k_htc_err_stat_rx(priv, &rx_stats);
-      ^
-    In file included from drivers/net/wireless/ath/ath9k/htc_drv_txrx.c:17:0:
-    drivers/net/wireless/ath/ath9k/htc.h:380:20: note: expected ‘struct ath_htc_rx_status *’ but argument is of type ‘struct ath_rx_status *’
-     static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
-    
-    Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
-
-commit 2d331334e9dc5659fdf9a89326c34c3db5a15279
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon May 19 17:59:50 2014 +0200
-
-    cfg80211: constify wowlan/coalesce mask/pattern pointers
-    
-    This requires changing the nl80211 parsing code a bit to use
-    intermediate pointers for the allocation, but clarifies the
-    API towards the drivers.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 6788105c46babaa6938cbacb72fdf20bec4bb2e3
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon May 19 17:53:16 2014 +0200
-
-    cfg80211: constify more pointers in the cfg80211 API
-    
-    This also propagates through the drivers.
-    
-    The orinoco driver uses the cfg80211 API structs for internal
-    bookkeeping, and so needs a (void *) cast that removes the
-    const - but that's OK because it allocates those pointers.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit c3d95010fd881da0fa0a4e88532412f5d0c092f6
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon May 19 17:19:31 2014 +0200
-
-    cfg80211: constify MAC addresses in cfg80211 ops
-    
-    This propagates through all the drivers and mac80211.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit ddf1e6f0f0354c601af7d42e5ace4b51f8b0bffc
-Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Thu May 15 20:32:08 2014 +0300
-
-    mac80211: fix csa_counter_offs argument name in docbook
-    
-    The csa_counter_offs was erroneously described as csa_offs in
-    the docbook section.
-    
-    This fixes two warnings when making htmldocs (at least):
-    
-    Warning(include/net/mac80211.h:3428): No description found for parameter 'csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM]'
-    Warning(include/net/mac80211.h:3428): Excess struct/union/enum/typedef member 'csa_offs' description in 'ieee80211_mutable_offsets'
-    
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 202322d1c04b8e498bd5bb78606fcf3941512b35
-Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Thu May 15 20:18:09 2014 +0300
-
-    cfg80211: add documentation for max_num_csa_counters
-    
-    Move the comment in the structure to a description of the
-    max_num_csa_counters field in the docbook area.
-    
-    This fixes a warning when building htmldocs (at least):
-    
-     Warning(include/net/cfg80211.h:3064): No description found for parameter 'max_num_csa_counters'
-    
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 457a33192f64b7637e8fd0ae0e9f32701c908603
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Mon May 19 11:24:19 2014 +0200
-
-    mac80211: minstrel-ht: small clarifications
-    
-    Antonio and I were looking over this code and some things
-    didn't immediately make sense, so we came up with two small
-    clarifications.
-    
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+commit d3a58df87a2e4c2301ac843604202d290a48440b
+Author: Avraham Stern <avraham.stern@intel.com>
+Date:   Thu May 22 12:17:47 2014 +0300
 
-commit 1e35dce952a64a957de97ae1f2bb19301756b936
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:50 2014 +0300
-
-    mac80211: Handle the CSA counters correctly
+    mac80211: set new interfaces as idle upon init
     
-    Make the beacon CSA counters part of ieee80211_mutable_offsets and don't
-    decrement CSA counters when generating a beacon template. This permits the
-    driver to offload the CSA counters handling. Since mac80211 updates the probe
-    responses with the correct counter, the driver should sync the counter's value
-    with mac80211 using ieee80211_csa_update_counter function.
+    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: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    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 e7b5c449815d28a2105fde5b42e112f78cc711ac
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:49 2014 +0300
+commit 923eaf367206e01f22c97aee22300e332d071916
+Author: Arik Nemtsov <arik@wizery.com>
+Date:   Mon May 26 14:40:51 2014 +0300
 
-    mac80211: Provide ieee80211_beacon_get_template API
+    mac80211: don't check netdev state for debugfs read/write
     
-    Add a new API ieee80211_beacon_get_template, which doesn't
-    affect DTIM counter and should be used if the device generates beacon
-    frames, and new beacon template is needed. In addition set the offsets
-    to TIM IE for MESH interface.
+    Doing so will lead to an oops for a p2p-dev interface, since it has
+    no netdev.
     
-    Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    Cc: stable@vger.kernel.org
+    Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
+    Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit e54eda80273ce8aded058c3c9365dca2342e2e75
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:47 2014 +0300
-
-    mac80211: Support multiple CSA counters
-    
-    Support up to IEEE80211_MAX_CSA_COUNTERS_NUM csa counters.
-    This is defined to be 2 now, to support both CSA and eCSA
-    counters.
-    
-    Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@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 678e87c3b929dd60d59470e8981eb551cee10319
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:46 2014 +0300
+commit c7d37a66e345df2fdf1aa7b2c9a6d3d53846ca5b
+Author: Krzysztof Hałasa <khalasa@piap.pl>
+Date:   Mon May 26 14:14:46 2014 +0200
 
-    cfg80211: Support multiple CSA counters
+    mac80211: fix IBSS join by initializing last_scan_completed
     
-    Change the type of NL80211_ATTR_CSA_C_OFF_BEACON and
-    NL80211_ATTR_CSA_C_OFF_PRESP to be NLA_BINARY which allows
-    userspace to use beacons and probe responses with
-    multiple CSA counters.
-    This isn't breaking the API since userspace can
-    continue to use nla_put_u16 for this attributes, which
-    is equivalent to a single element u16 array.
-    In addition advertise max number of supported CSA counters.
-    This is needed when using CSA and eCSA IEs together.
+    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: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    Signed-off-by: Krzysztof Hałasa <khalasa@piap.pl>
+    [edit commit message slightly]
+    Cc: stable@vger.kernel.org
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 93f4867a966cc8645659031bbd44a9bb4b78485f
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:45 2014 +0300
+commit 34171dc0d623be2c1032416bf7d3819f388ed70d
+Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Date:   Sun May 25 15:35:41 2014 +0300
 
-    mac80211: Update CSA counters in mgmt frames
+    mac80211: fix virtual monitor interface addition
     
-    Track current csa counter value and use it
-    to update mgmt frames at the provided offsets.
+    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:
     
-    Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    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 6c8461fcc03ff4d250027e47f53315b5e0ec43aa
-Author: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-Date:   Fri May 9 14:11:44 2014 +0300
+commit d93cc72b37b4e2c314e1c499e80e8801907c2fea
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date:   Thu Jun 5 14:21:37 2014 +0200
 
-    cfg80211: Add API to update CSA counters in mgmt frames
+    mac80211: use csa counter offsets instead of csa_active
     
-    Add NL80211_ATTR_CSA_C_OFFSETS_TX which holds an array
-    of offsets to the CSA counters which should be updated
-    when sending a management frames with NL80211_CMD_FRAME.
+    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.
     
-    This API should be used by the drivers that wish to keep the
-    CSA counter updated in probe responses, but do not implement
-    probe response offloading and so, do not use
-    ieee80211_proberesp_get function.
+    Using csa counter offsets which are embedded in
+    beacon struct (and thus are protected with single
+    RCU assignment) is much safer.
     
-    Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 7d09fc9f1903b3d5e7d046bdf10467f37a97c4f9
-Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Thu May 15 13:05:39 2014 +0300
+commit d2746694fcdef24e0a7a1947d8c70082cde81a26
+Author: Michal Kazior <michal.kazior@tieto.com>
+Date:   Thu Jun 5 14:21:36 2014 +0200
 
-    cfg80211: pass the actual iftype when calling cfg80211_chandef_dfs_required()
+    mac80211: move csa counters from sdata to beacon/presp
     
-    There is no need to pass NL80211_IFTYPE_UNSPECIFIED when calling
-    cfg80211_chandef_dfs_required() since we always already have the
-    interface type.  So, pass the actual interface type instead.
+    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.
     
-    Additionally, have cfg80211_chandef_dfs_required() WARN if the passed
-    interface type is NL80211_IFTYPE_UNSPECIFIED, so we can detect
-    problems more easily.
+    While at it relax WARN_ON into WARN_ON_ONCE to
+    prevent spamming logs and racing.
     
-    Tested-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
-    Reported-by: Eliad Peller <eliad@wizery.com>
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
+    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 2b7443b15f26ecb98281474666383cf2a882fbad
+commit 5dcb54f3a1a8cd7e0331e773487574f9743615db
 Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
-Date:   Wed May 14 13:25:04 2014 +0200
+Date:   Thu Jun 5 08:12:57 2014 +0200
 
-    cfg80211: fix start_radar_detection issue
+    mac80211: allow tx via monitor iface when DFS
     
-    After patch:
-    cfg80211/mac80211: refactor cfg80211_chandef_dfs_required()
+    Allow send frames using monitor interface
+    when DFS chandef and we pass CAC (beaconing
+    allowed).
     
-    start_radar_detection always fail with -EINVAL.
+    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.
     
-    Acked-by: Luciano Coelho <luciano.coelho@intel.com>
     Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 4f46eb8b28f96aca212a364e0fa847eb5333df67
-Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon May 5 11:48:40 2014 +0200
-
-    cfg80211: allow restricting supported dfs regions
-    
-    At the moment, the ath9k/ath10k DFS module only supports detecting ETSI
-    radar patterns.
-    Add a bitmap in the interface combinations, indicating which DFS regions
-    are supported by the detector. If unset, support for all regions is
-    assumed.
-    
-    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit 0277b034768d1800a00829a755fc56b925aa6b95
+commit 6f09a1beb0d2007572248c986780562219bd206f
 Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Wed Apr 30 14:19:04 2014 +0200
+Date:   Wed Jun 4 17:31:56 2014 +0200
 
-    mac80211: handle failed restart/resume better
+    cfg80211: make ethtool the driver's responsibility
     
-    When the driver fails during HW restart or resume, the whole
-    stack goes into a very confused state with interfaces being
-    up while the hardware is down etc.
+    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.
     
-    Address this by shutting down everything; we'll run into a
-    lot of warnings in the process but that's better than having
-    the whole stack get messed up.
+    To cleanly implement this in mac80211, introduce a new file and
+    move some code to appropriate places.
     
-    Reviewed-by: Arik Nemtsov <arik@wizery.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit 43fd71bc4b83d24981e90ca178f505cf6a6b16dc
-Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Wed May 7 20:05:12 2014 +0300
+commit 6b0c6f133de8f90caeb1c4a902e6140567c5bf96
+Author: Johannes Berg <johannes.berg@intel.com>
+Date:   Wed Jun 4 17:06:23 2014 +0200
 
-    mac80211: fix sparse warning caused by __ieee80211_channel_switch()
-    
-    Commit 59af6928 (mac80211: fix CSA tx queue stopping) introduced a
-    sparse warning:
-    
-    net/mac80211/cfg.c:3274:5: warning: symbol '__ieee80211_channel_switch' was not declared. Should it be static?
+    mac80211: remove weak WEP IV accounting
     
-    Fix it by declaring the function static.
+    Since WEP is practically dead, there seems very little
+    point in keeping WEP weak IV accounting.
     
-    Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
     Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 
-commit dd4371e2957db19870bb22ab84e841e1ac6e8997
+commit aecdc89fb4664c76baa4bbd46008f220532309ff
 Author: Luciano Coelho <luciano.coelho@intel.com>
-Date:   Wed May 7 19:07:05 2014 +0300
+Date:   Fri May 23 11:04:50 2014 +0300
 
-    cfg80211: fix docbook warning
-    
-    When trying to generate documentation, at least xmldocs, we get the
-    following warning:
-    
-    Warning(include/net/cfg80211.h:461): No description found for parameter 'nl80211_iftype'
+    ath9k/ath10k: remove unnecessary channel_switch_beacon callbacks
     
-    Fix it by adding the iftype argument name to the
-    cfg80211_chandef_dfs_required() function declaration.
+    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.
     
-    Reported-and-tested-by: Masanari Iida <standby24x7@gmail.com>
+    Cc: Michal Kazior <michal.kazior@tieto.com>
     Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
 
-commit 56de850ae960f096c784ec07864ca5b71abd16e6
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Thu May 8 09:10:02 2014 +0200
+commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798
+Author: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
+Date:   Tue May 27 16:58:02 2014 +0530
 
-    mac80211: disconnect iface if CSA unexpectedly fails
-    
-    It doesn't make much sense to leave a crippled
-    interface running.
-    
-    As a side effect this will unblock tx queues with
-    CSA reason immediately after failure instead of
-    until after userspace requests interface to stop.
+    ath9k: Fix deadlock while updating p2p beacon timer
     
-    This also gives userspace an opportunity to
-    indirectly see CSA failure.
+    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>
-    [small code cleanup]
-    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 f5894c4f19e55bb1ea6376031fe9d47d7528be9e
-Author: Loic Poulain <loic.poulain@intel.com>
-Date:   Wed May 7 11:38:11 2014 +0200
+commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:27 2014 +0200
 
-    rfkill-gpio: Use gpio cansleep version
+    rt2x00: do not initialize BCN_OFFSET registers
     
-    If gpio controller requires waiting for read and write
-    GPIO values, then we have to use the gpio cansleep api.
-    Fix the rfkill_gpio_set_power which calls only the
-    nonsleep version (causing kernel warning).
-    There is no problem to use the cansleep version here
-    because we are not in IRQ handler or similar context
-    (cf rfkill_set_block).
+    We setup BCN_OFFSET{0,1} registers dynamically, don't have to
+    initialize them.
     
-    Signed-off-by: Loic Poulain <loic.poulain@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 47fdf5d4f3704d2db9d1c0f647f788edef104fc8
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Apr 9 15:45:36 2014 +0200
+commit e5c58ca7a48d4c82f282749a978052c47fd95998
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:26 2014 +0200
 
-    mac80211: ignore cqm during csa
+    rt2x00: change order when stop beaconing
     
-    It is not guaranteed that multi-vif channel
-    switching is tightly synchronized. It makes sense
-    to ignore cqm (missing beacons, et al) while csa
-    is progressing and re-check it after it completes.
+    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.
     
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 1a8ed386e1684b266a15dacf675102ae53361ee5
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Apr 9 15:11:01 2014 +0200
+commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:25 2014 +0200
 
-    cfg80211: export interface stopping function
-    
-    This exports a new cfg80211_stop_iface() function.
+    rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM
     
-    This is intended for driver internal interface
-    combination management and channel switching.
+    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.
     
-    Due to locking issues (it re-enters driver) the
-    call is asynchronous and uses cfg80211 event
-    list/worker.
-    
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 573f31d6d0e572ff8186c45a1ecd9273242233e6
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Apr 9 15:11:00 2014 +0200
+commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:24 2014 +0200
 
-    mac80211: split CSA finalize function
+    rt2x00: change beaconing setup on RT2800
     
-    Improves readability and modularity.
+    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.
     
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    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.
+    
+    Reported-by: Matthias Fend <Matthias.Fend@wolfvision.net>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 2d104d52e7c7640d68f29f2136dbe3938b7bc9ba
-Author: Michal Kazior <michal.kazior@tieto.com>
-Date:   Wed Apr 9 15:10:59 2014 +0200
+commit 916e591b2cc41f7e572992175ca56d866d7bc958
+Author: Stanislaw Gruszka <sgruszka@redhat.com>
+Date:   Thu Jun 5 13:52:23 2014 +0200
 
-    mac80211: fix CSA tx queue stopping
+    rt2x00: change beaconing locking
     
-    It was possible for tx queues to be stuck stopped
-    if AP CSA finalization failed. In that case
-    neither stop_ap nor do_stop woke the queues up.
-    This means it was impossible to perform tx at all
-    until driver was reloaded or a successful CSA was
-    performed later.
+    This patch is needed for further changes to keep global variables
+    consistent when changing beaconing on diffrent vif's.
     
-    It was possible to solve this in a simpler manner
-    however this is more robust and future proof
-    (having multi-vif CSA in mind).
-    
-    New sdata->csa_block_tx is introduced to keep
-    track of which interfaces requested tx to be
-    blocked for CSA. This is required because mac80211
-    stops all tx queues for that purpose. This means
-    queues must be awoken only when last tx-blocking
-    CSA interface is finished.
-    
-    It is still possible to have tx queues stopped
-    after CSA failure but as soon as offending
-    interfaces are stopped from userspace (stop_ap or
-    ifdown) tx queues are woken up properly.
-    
-    Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 
-commit 6be615d6d42aa7fdab6c4278031d8fa0953e594f
+commit 930b0dffd1731f3f418f9132faea720a23b7af61
 Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Wed Apr 9 21:31:13 2014 +0200
-
-    mac80211: mark local variable __maybe_unused
-    
-    The 'local' variable in __ieee80211_vif_copy_chanctx_to_vlans()
-    is only used/needed when lockdep is compiled in, mark it as such
-    to avoid compile warnings in the other case.
-    
-    While at it, fix some indentation where it's used.
-    
-    Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
-    Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+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 43279e584aeb78aa0c853728db047b58156c0753
-Author: Arik Nemtsov <arik@wizery.com>
-Date:   Thu May 1 10:17:28 2014 +0300
+commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Fri May 23 19:58:14 2014 +0200
 
-    mac80211: move TDLS code to another file
-    
-    With new additions planned, this code is getting too big for cfg.c.
+    mac80211: reduce packet loss notifications under load
     
-    Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-
-commit bf9c234b83c77f1ebbcbab73de2a9e4a5d4aafc6
-Author: Arik Nemtsov <arik@wizery.com>
-Date:   Thu May 1 10:17:27 2014 +0300
-
-    mac80211: set an external flag for TDLS stations
+    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.
     
-    Expose a new tdls flag for the public ieee80211_sta struct.
-    This can be used in some rate control decisions.
+    Reduce the number of false positives by checking the A-MPDU status flag
+    and treating a failed A-MPDU as a single packet.
     
-    Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 910e65141a17f645ab85dae1a497e64ebe63df70
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Tue Apr 29 17:55:26 2014 +0200
+commit 7b7843a36fbcc568834404c7430ff895d8502131
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Fri May 23 19:26:32 2014 +0200
 
-    mac80211: remove BUG_ON usage
-    
-    These BUG_ON statements should never trigger, but in the unlikely
-    event that somebody does manage don't stop everything but simply
-    exit the code path with an error.
-    
-    Leave the one BUG_ON where changing it would result in a NULL
-    pointer dereference.
+    mac80211: fix a memory leak on sta rate selection table
     
-    Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+    Cc: stable@vger.kernel.org
+    Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit ff36b582a10285530351aab036087b57ddb4ae2b
-Author: Johannes Berg <johannes.berg@intel.com>
-Date:   Tue Apr 29 17:52:36 2014 +0200
+commit 96892d6aa0a153423070addf3070bc79578b3897
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon May 19 21:20:49 2014 +0200
 
-    cfg80211: remove BUG_ON usage
+    ath9k: avoid passing buffers to the hardware during flush
     
-    These really can't trigger unless somebody messes up the code,
-    but don't make debugging it needlessly complicated, WARN and
-    return instead of BUG_ON().
+    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>
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
---- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
-+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
-@@ -1759,7 +1759,7 @@ static bool is_rate_ht40(s32 rate, u8 *m
- }
- static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
--                            u8 *mac, struct station_info *sinfo)
-+                            const u8 *mac, struct station_info *sinfo)
- {
-       struct ath6kl *ar = ath6kl_priv(dev);
-       struct ath6kl_vif *vif = netdev_priv(dev);
-@@ -2974,7 +2974,7 @@ static int ath6kl_stop_ap(struct wiphy *
- static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
--                            u8 *mac)
-+                            const u8 *mac)
+--- 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 ath6kl *ar = ath6kl_priv(dev);
-       struct ath6kl_vif *vif = netdev_priv(dev);
-@@ -2985,7 +2985,8 @@ static int ath6kl_del_station(struct wip
- }
+       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);
  
- static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
--                               u8 *mac, struct station_parameters *params)
-+                               const u8 *mac,
-+                               struct station_parameters *params)
- {
-       struct ath6kl *ar = ath6kl_priv(dev);
-       struct ath6kl_vif *vif = netdev_priv(dev);
---- a/drivers/net/wireless/ath/ath6kl/wmi.c
-+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
-@@ -2320,7 +2320,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wm
-       return ret;
- }
+-      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);
  
--int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk)
-+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk)
- {
-       struct sk_buff *skb;
-       struct wmi_add_krk_cmd *cmd;
---- a/drivers/net/wireless/ath/ath6kl/wmi.h
-+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
-@@ -2616,7 +2616,7 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wm
-                         u8 *key_material,
-                         u8 key_op_ctrl, u8 *mac_addr,
-                         enum wmi_sync_flag sync_flag);
--int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, u8 *krk);
-+int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk);
- int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index);
- int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,
-                           const u8 *pmkid, bool set);
---- a/drivers/net/wireless/ath/ath9k/htc.h
-+++ b/drivers/net/wireless/ath/ath9k/htc.h
-@@ -378,7 +378,7 @@ void ath9k_htc_get_et_stats(struct ieee8
- #define TX_QSTAT_INC(c) do { } while (0)
- static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
--                                       struct ath_htc_rx_status *rxs)
-+                                       struct ath_rx_status *rs);
- {
+       sc->rx.rxlink = &ds->ds_link;
  }
  
---- a/drivers/net/wireless/ath/wil6210/cfg80211.c
-+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
-@@ -172,7 +172,7 @@ static int wil_cid_fill_sinfo(struct wil
- static int wil_cfg80211_get_station(struct wiphy *wiphy,
-                                   struct net_device *ndev,
--                                  u8 *mac, struct station_info *sinfo)
-+                                  const u8 *mac, struct station_info *sinfo)
+-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)
  {
-       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-       int rc;
-@@ -671,7 +671,7 @@ static int wil_cfg80211_stop_ap(struct w
+       if (sc->rx.buf_hold)
+-              ath_rx_buf_link(sc, sc->rx.buf_hold);
++              ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
+       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);
+       }
  
- static int wil_cfg80211_del_station(struct wiphy *wiphy,
--                                  struct net_device *dev, u8 *mac)
-+                                  struct net_device *dev, const u8 *mac)
- {
-       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       /* 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);
  
---- a/drivers/net/wireless/ath/wil6210/main.c
-+++ b/drivers/net/wireless/ath/wil6210/main.c
-@@ -81,7 +81,7 @@ static void wil_disconnect_cid(struct wi
-       memset(&sta->stats, 0, sizeof(sta->stats));
- }
+-              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);
+               }
  
--static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
-+static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
- {
-       int cid = -ENOENT;
-       struct net_device *ndev = wil_to_ndev(wil);
-@@ -252,7 +252,7 @@ int wil_priv_init(struct wil6210_priv *w
-       return 0;
- }
+               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;
+       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 
+               clear_sta_flag(sta, WLAN_STA_PS_STA);
+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
++              clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
+               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);
+-      cancel_work_sync(&sta->drv_unblock_wk);
++      cancel_work_sync(&sta->drv_deliver_wk);
  
--void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
-+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
- {
-       del_timer_sync(&wil->connect_timer);
-       _wil6210_disconnect(wil, bssid);
---- a/drivers/net/wireless/ath/wil6210/wil6210.h
-+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
-@@ -508,7 +508,7 @@ void wil_wdev_free(struct wil6210_priv *
- int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
- int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
- int wmi_pcp_stop(struct wil6210_priv *wil);
--void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
-+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);
- int wil_rx_init(struct wil6210_priv *wil);
- void wil_rx_fini(struct wil6210_priv *wil);
---- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
-@@ -2236,7 +2236,7 @@ brcmf_cfg80211_config_default_mgmt_key(s
- static s32
- brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
--                         u8 *mac, struct station_info *sinfo)
-+                         const u8 *mac, struct station_info *sinfo)
- {
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
-@@ -4014,7 +4014,7 @@ brcmf_cfg80211_change_beacon(struct wiph
- static int
- brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
--                         u8 *mac)
-+                         const u8 *mac)
+       /*
+        * 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 sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
  {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_scb_val_le scbval;
-@@ -4242,7 +4242,7 @@ static int brcmf_convert_nl80211_tdls_op
- }
++      struct ieee80211_sta_rates *rates;
+       int i;
  
- static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
--                                  struct net_device *ndev, u8 *peer,
-+                                  struct net_device *ndev, const u8 *peer,
-                                   enum nl80211_tdls_operation oper)
- {
-       struct brcmf_if *ifp;
---- a/drivers/net/wireless/libertas/cfg.c
-+++ b/drivers/net/wireless/libertas/cfg.c
-@@ -1006,9 +1006,8 @@ struct cmd_key_material {
- } __packed;
- static int lbs_set_key_material(struct lbs_private *priv,
--                              int key_type,
--                              int key_info,
--                              u8 *key, u16 key_len)
-+                              int key_type, int key_info,
-+                              const u8 *key, u16 key_len)
- {
-       struct cmd_key_material cmd;
-       int ret;
-@@ -1610,7 +1609,7 @@ static int lbs_cfg_del_key(struct wiphy 
-  */
+       if (sta->rate_ctrl)
+@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca
+               kfree(sta->tx_lat);
+       }
  
- static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
--                            u8 *mac, struct station_info *sinfo)
-+                             const u8 *mac, struct station_info *sinfo)
- {
-       struct lbs_private *priv = wiphy_priv(wiphy);
-       s8 signal, noise;
---- a/drivers/net/wireless/libertas/defs.h
-+++ b/drivers/net/wireless/libertas/defs.h
-@@ -90,7 +90,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \
- #define lbs_deb_cfg80211(fmt, args...)  LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
- #ifdef DEBUG
--static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
-+static inline void lbs_deb_hex(unsigned int grp, const char *prompt,
-+                             const u8 *buf, int len)
- {
-       int i = 0;
++      rates = rcu_dereference_protected(sta->sta.rates, true);
++      if (rates)
++              kfree(rates);
++
+       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
  
---- a/drivers/net/wireless/mwifiex/11n.h
-+++ b/drivers/net/wireless/mwifiex/11n.h
-@@ -200,7 +200,7 @@ static inline int mwifiex_is_sta_11n_ena
+       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);
  }
  
- static inline u8
--mwifiex_tdls_peer_11n_enabled(struct mwifiex_private *priv, u8 *ra)
-+mwifiex_tdls_peer_11n_enabled(struct mwifiex_private *priv, const u8 *ra)
- {
-       struct mwifiex_sta_node *node = mwifiex_get_sta_entry(priv, ra);
-       if (node)
---- a/drivers/net/wireless/mwifiex/cfg80211.c
-+++ b/drivers/net/wireless/mwifiex/cfg80211.c
-@@ -994,7 +994,7 @@ mwifiex_dump_station_info(struct mwifiex
-  */
- static int
- mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
--                           u8 *mac, struct station_info *sinfo)
-+                           const u8 *mac, struct station_info *sinfo)
+-static void sta_unblock(struct work_struct *wk)
++static void sta_deliver_ps_frames(struct work_struct *wk)
  {
-       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       struct sta_info *sta;
  
-@@ -1270,7 +1270,7 @@ static int mwifiex_cfg80211_change_beaco
-  */
- static int
- mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
--                           u8 *mac)
-+                           const u8 *mac)
- {
-       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
-       struct mwifiex_sta_node *sta_node;
-@@ -2629,7 +2629,7 @@ static int mwifiex_cfg80211_set_coalesce
-  */
- static int
- mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
--                         u8 *peer, u8 action_code, u8 dialog_token,
-+                         const u8 *peer, u8 action_code, u8 dialog_token,
-                          u16 status_code, u32 peer_capability,
-                          const u8 *extra_ies, size_t extra_ies_len)
- {
-@@ -2701,7 +2701,7 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy 
+-      sta = container_of(wk, struct sta_info, drv_unblock_wk);
++      sta = container_of(wk, struct sta_info, drv_deliver_wk);
  
- static int
- mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
--                         u8 *peer, enum nl80211_tdls_operation action)
-+                         const u8 *peer, enum nl80211_tdls_operation action)
- {
-       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       if (sta->dead)
+               return;
  
-@@ -2748,9 +2748,8 @@ mwifiex_cfg80211_tdls_oper(struct wiphy 
+-      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);
+-
+-              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();
  }
  
- static int
--mwifiex_cfg80211_add_station(struct wiphy *wiphy,
--                           struct net_device *dev,
--                           u8 *mac, struct station_parameters *params)
-+mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
-+                           const u8 *mac, struct station_parameters *params)
- {
-       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ static int sta_prepare_rate_control(struct ieee80211_local *local,
+@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i
  
-@@ -2765,9 +2764,9 @@ mwifiex_cfg80211_add_station(struct wiph
- }
+       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
+       }
  
- static int
--mwifiex_cfg80211_change_station(struct wiphy *wiphy,
--                              struct net_device *dev,
--                              u8 *mac, struct station_parameters *params)
-+mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
-+                              const u8 *mac,
-+                              struct station_parameters *params)
- {
-       int ret;
-       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
---- a/drivers/net/wireless/mwifiex/main.h
-+++ b/drivers/net/wireless/mwifiex/main.h
-@@ -910,8 +910,6 @@ int mwifiex_handle_uap_rx_forward(struct
-                                 struct sk_buff *skb);
- int mwifiex_process_sta_event(struct mwifiex_private *);
- int mwifiex_process_uap_event(struct mwifiex_private *);
--struct mwifiex_sta_node *
--mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
- void mwifiex_delete_all_station_list(struct mwifiex_private *priv);
- void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
- void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb);
-@@ -1220,26 +1218,26 @@ void mwifiex_dnld_txpwr_table(struct mwi
- extern const struct ethtool_ops mwifiex_ethtool_ops;
- void mwifiex_del_all_sta_list(struct mwifiex_private *priv);
--void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac);
-+void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac);
- void
- mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
-                      int ies_len, struct mwifiex_sta_node *node);
- struct mwifiex_sta_node *
--mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac);
-+mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac);
- struct mwifiex_sta_node *
--mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
--int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, u8 *peer,
-+mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac);
-+int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
-                                u8 action_code, u8 dialog_token,
-                                u16 status_code, const u8 *extra_ies,
-                                size_t extra_ies_len);
--int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
--                               u8 *peer, u8 action_code, u8 dialog_token,
--                               u16 status_code, const u8 *extra_ies,
--                               size_t extra_ies_len);
-+int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
-+                                 u8 action_code, u8 dialog_token,
-+                                 u16 status_code, const u8 *extra_ies,
-+                                 size_t extra_ies_len);
- void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
-                                      u8 *buf, int len);
--int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action);
--int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, u8 *mac);
-+int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action);
-+int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac);
- void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv);
- bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv);
- u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
---- a/drivers/net/wireless/mwifiex/tdls.c
-+++ b/drivers/net/wireless/mwifiex/tdls.c
-@@ -25,8 +25,8 @@
- #define TDLS_RESP_FIX_LEN     8
- #define TDLS_CONFIRM_FIX_LEN  6
--static void
--mwifiex_restore_tdls_packets(struct mwifiex_private *priv, u8 *mac, u8 status)
-+static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv,
-+                                       const u8 *mac, u8 status)
- {
-       struct mwifiex_ra_list_tbl *ra_list;
-       struct list_head *tid_list;
-@@ -84,7 +84,8 @@ mwifiex_restore_tdls_packets(struct mwif
-       return;
- }
--static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv, u8 *mac)
-+static void mwifiex_hold_tdls_packets(struct mwifiex_private *priv,
-+                                    const u8 *mac)
- {
-       struct mwifiex_ra_list_tbl *ra_list;
-       struct list_head *ra_list_head;
-@@ -228,7 +229,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_
- }
- static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
--                                   u8 *mac, struct sk_buff *skb)
-+                                   const u8 *mac, struct sk_buff *skb)
- {
-       struct mwifiex_bssdescriptor *bss_desc;
-       struct ieee80211_vht_operation *vht_oper;
-@@ -367,8 +368,9 @@ static void mwifiex_tdls_add_qos_capab(s
- }
+       ieee80211_add_pending_skbs(local, &pending);
+-      clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
+-      clear_sta_flag(sta, WLAN_STA_PS_STA);
++
++      /* now we're no longer in the deliver code */
++      clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
++
++      /* 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);
  
- static int mwifiex_prep_tdls_encap_data(struct mwifiex_private *priv,
--                           u8 *peer, u8 action_code, u8 dialog_token,
--                           u16 status_code, struct sk_buff *skb)
-+                                      const u8 *peer, u8 action_code,
-+                                      u8 dialog_token,
-+                                      u16 status_code, struct sk_buff *skb)
- {
-       struct ieee80211_tdls_data *tf;
-       int ret;
-@@ -506,7 +508,8 @@ static int mwifiex_prep_tdls_encap_data(
- }
+       atomic_dec(&ps->num_sta_ps);
+@@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie
  
- static void
--mwifiex_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, u8 *peer, u8 *bssid)
-+mwifiex_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
-+                       const u8 *peer, const u8 *bssid)
- {
-       struct ieee80211_tdls_lnkie *lnkid;
+       trace_api_sta_block_awake(sta->local, pubsta, block);
  
-@@ -520,8 +523,8 @@ mwifiex_tdls_add_link_ie(struct sk_buff 
-       memcpy(lnkid->resp_sta, peer, ETH_ALEN);
+-      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;
++      }
++
++      if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
++              return;
++
++      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);
  
--int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv,
--                               u8 *peer, u8 action_code, u8 dialog_token,
-+int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
-+                               u8 action_code, u8 dialog_token,
-                                u16 status_code, const u8 *extra_ies,
-                                size_t extra_ies_len)
- {
-@@ -613,7 +616,8 @@ int mwifiex_send_tdls_data_frame(struct 
+@@ -1703,3 +1723,137 @@ 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;
  }
++
++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;
++      }
++}
+--- 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
  
- static int
--mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv, u8 *peer,
-+mwifiex_construct_tdls_action_frame(struct mwifiex_private *priv,
-+                                  const u8 *peer,
-                                   u8 action_code, u8 dialog_token,
-                                   u16 status_code, struct sk_buff *skb)
- {
-@@ -691,10 +695,10 @@ mwifiex_construct_tdls_action_frame(stru
-       return 0;
- }
++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);
+                       }
+               }
  
--int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv,
--                               u8 *peer, u8 action_code, u8 dialog_token,
--                               u16 status_code, const u8 *extra_ies,
--                               size_t extra_ies_len)
-+int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
-+                                 u8 action_code, u8 dialog_token,
-+                                 u16 status_code, const u8 *extra_ies,
-+                                 size_t extra_ies_len)
- {
-       struct sk_buff *skb;
-       struct mwifiex_txinfo *tx_info;
-@@ -901,7 +905,7 @@ void mwifiex_process_tdls_action_frame(s
- }
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *
+               return;
+       }
  
- static int
--mwifiex_tdls_process_config_link(struct mwifiex_private *priv, u8 *peer)
-+mwifiex_tdls_process_config_link(struct mwifiex_private *priv, const u8 *peer)
- {
-       struct mwifiex_sta_node *sta_ptr;
-       struct mwifiex_ds_tdls_oper tdls_oper;
-@@ -922,7 +926,7 @@ mwifiex_tdls_process_config_link(struct 
++      set_sta_flag(sta, WLAN_STA_PS_DELIVER);
++      clear_sta_flag(sta, WLAN_STA_PS_STA);
+       ieee80211_sta_ps_deliver_wakeup(sta);
  }
  
- static int
--mwifiex_tdls_process_create_link(struct mwifiex_private *priv, u8 *peer)
-+mwifiex_tdls_process_create_link(struct mwifiex_private *priv, const u8 *peer)
- {
-       struct mwifiex_sta_node *sta_ptr;
-       struct mwifiex_ds_tdls_oper tdls_oper;
-@@ -949,7 +953,7 @@ mwifiex_tdls_process_create_link(struct 
- }
+--- 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,
+ };
  
- static int
--mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, u8 *peer)
-+mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
+ #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;
+       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);
+@@ -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 mwifiex_sta_node *sta_ptr;
-       struct mwifiex_ds_tdls_oper tdls_oper;
-@@ -978,7 +982,7 @@ mwifiex_tdls_process_disable_link(struct
- }
+       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;
+@@ -1721,9 +1723,9 @@ netdev_tx_t ieee80211_monitor_start_xmit
+       }
  
- static int
--mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, u8 *peer)
-+mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
- {
-       struct mwifiex_sta_node *sta_ptr;
-       struct ieee80211_mcs_info mcs;
-@@ -1035,7 +1039,7 @@ mwifiex_tdls_process_enable_link(struct 
-       return 0;
- }
+       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;
+@@ -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;
  
--int mwifiex_tdls_oper(struct mwifiex_private *priv, u8 *peer, u8 action)
-+int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action)
- {
-       switch (action) {
-       case MWIFIEX_TDLS_ENABLE_LINK:
-@@ -1050,7 +1054,7 @@ int mwifiex_tdls_oper(struct mwifiex_pri
-       return 0;
- }
+-      ieee80211_xmit(sdata, skb, chan->band);
++      ieee80211_xmit(sdata, skb, chandef->chan->band);
+       rcu_read_unlock();
  
--int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, u8 *mac)
-+int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)
- {
-       struct mwifiex_sta_node *sta_ptr;
+       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;
  
---- a/drivers/net/wireless/mwifiex/util.c
-+++ b/drivers/net/wireless/mwifiex/util.c
-@@ -259,7 +259,7 @@ int mwifiex_complete_cmd(struct mwifiex_
-  * NULL is returned if station entry is not found in associated STA list.
-  */
- struct mwifiex_sta_node *
--mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
-+mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)
- {
-       struct mwifiex_sta_node *node;
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+@@ -2444,46 +2447,54 @@ static void ieee80211_set_csa(struct iee
+               return;
+       }
  
-@@ -280,7 +280,7 @@ mwifiex_get_sta_entry(struct mwifiex_pri
-  * If received mac address is NULL, NULL is returned.
-  */
- struct mwifiex_sta_node *
--mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
-+mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
- {
-       struct mwifiex_sta_node *node;
-       unsigned long flags;
-@@ -332,7 +332,7 @@ mwifiex_set_sta_ht_cap(struct mwifiex_pr
++      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();
++
++                      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();
  }
  
- /* This function will delete a station entry from station list */
--void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
-+void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
- {
-       struct mwifiex_sta_node *node;
-       unsigned long flags;
---- a/drivers/net/wireless/mwifiex/wmm.c
-+++ b/drivers/net/wireless/mwifiex/wmm.c
-@@ -92,7 +92,7 @@ mwifiex_wmm_ac_debug_print(const struct 
-  * The function also initializes the list with the provided RA.
-  */
- static struct mwifiex_ra_list_tbl *
--mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
-+mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, const u8 *ra)
- {
-       struct mwifiex_ra_list_tbl *ra_list;
-@@ -139,8 +139,7 @@ static u8 mwifiex_get_random_ba_threshol
-  * This function allocates and adds a RA list for all TIDs
-  * with the given RA.
-  */
--void
--mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
-+void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra)
- {
-       int i;
-       struct mwifiex_ra_list_tbl *ra_list;
-@@ -566,7 +565,7 @@ mwifiex_clean_txrx(struct mwifiex_privat
-  */
- static struct mwifiex_ra_list_tbl *
- mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
--                          u8 *ra_addr)
-+                          const u8 *ra_addr)
- {
-       struct mwifiex_ra_list_tbl *ra_list;
-@@ -587,7 +586,8 @@ mwifiex_wmm_get_ralist_node(struct mwifi
-  * retrieved.
-  */
- struct mwifiex_ra_list_tbl *
--mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
-+mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid,
-+                          const u8 *ra_addr)
- {
-       struct mwifiex_ra_list_tbl *ra_list;
---- a/drivers/net/wireless/mwifiex/wmm.h
-+++ b/drivers/net/wireless/mwifiex/wmm.h
-@@ -99,7 +99,7 @@ mwifiex_wmm_is_ra_list_empty(struct list
- void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
-                                struct sk_buff *skb);
--void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
-+void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra);
- void mwifiex_rotate_priolists(struct mwifiex_private *priv,
-                             struct mwifiex_ra_list_tbl *ra, int tid);
-@@ -123,7 +123,8 @@ void mwifiex_wmm_setup_ac_downgrade(stru
- int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
-                              const struct host_cmd_ds_command *resp);
- struct mwifiex_ra_list_tbl *
--mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr);
-+mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid,
-+                          const u8 *ra_addr);
- u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid);
- #endif /* !_MWIFIEX_WMM_H_ */
---- a/drivers/net/wireless/orinoco/hw.c
-+++ b/drivers/net/wireless/orinoco/hw.c
-@@ -988,8 +988,8 @@ int __orinoco_hw_setup_enc(struct orinoc
-  * tsc must be NULL or up to 8 bytes
-  */
- int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
--                            int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
--                            u8 *tsc, size_t tsc_len)
-+                            int set_tx, const u8 *key, const u8 *rsc,
-+                            size_t rsc_len, const u8 *tsc, size_t tsc_len)
+ u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif)
  {
-       struct {
-               __le16 idx;
---- a/drivers/net/wireless/orinoco/hw.h
-+++ b/drivers/net/wireless/orinoco/hw.h
-@@ -38,8 +38,8 @@ int __orinoco_hw_set_wap(struct orinoco_
- int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
- int __orinoco_hw_setup_enc(struct orinoco_private *priv);
- int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
--                            int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
--                            u8 *tsc, size_t tsc_len);
-+                            int set_tx, const u8 *key, const u8 *rsc,
-+                            size_t rsc_len, const u8 *tsc, size_t tsc_len);
- int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
- int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
-                                   struct net_device *dev,
---- a/drivers/net/wireless/orinoco/wext.c
-+++ b/drivers/net/wireless/orinoco/wext.c
-@@ -52,9 +52,9 @@ static int orinoco_set_key(struct orinoc
-       priv->keys[index].seq_len = seq_len;
-       if (key_len)
--              memcpy(priv->keys[index].key, key, key_len);
-+              memcpy((void *)priv->keys[index].key, key, key_len);
-       if (seq_len)
--              memcpy(priv->keys[index].seq, seq, seq_len);
-+              memcpy((void *)priv->keys[index].seq, seq, seq_len);
-       switch (alg) {
-       case ORINOCO_ALG_TKIP:
---- a/drivers/net/wireless/rndis_wlan.c
-+++ b/drivers/net/wireless/rndis_wlan.c
-@@ -517,7 +517,7 @@ static int rndis_set_default_key(struct 
-                                u8 key_index, bool unicast, bool multicast);
- static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
--                                      u8 *mac, struct station_info *sinfo);
-+                           const u8 *mac, struct station_info *sinfo);
- static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
-                              int idx, u8 *mac, struct station_info *sinfo);
-@@ -2490,7 +2490,7 @@ static void rndis_fill_station_info(stru
- }
+       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;
  
- static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
--                                      u8 *mac, struct station_info *sinfo)
-+                           const u8 *mac, struct station_info *sinfo)
- {
-       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
-       struct usbnet *usbdev = priv->usbdev;
---- a/drivers/net/wireless/ti/wlcore/main.c
-+++ b/drivers/net/wireless/ti/wlcore/main.c
-@@ -1416,7 +1416,7 @@ void wl1271_rx_filter_free(struct wl12xx
- int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
-                                u16 offset, u8 flags,
--                               u8 *pattern, u8 len)
-+                               const u8 *pattern, u8 len)
- {
-       struct wl12xx_rx_filter_field *field;
---- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
-+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
-@@ -512,8 +512,8 @@ int wl1271_recalc_rx_streaming(struct wl
- void wl12xx_queue_recovery_work(struct wl1271 *wl);
- size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
- int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
--                                      u16 offset, u8 flags,
--                                      u8 *pattern, u8 len);
-+                               u16 offset, u8 flags,
-+                               const u8 *pattern, u8 len);
- void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
- struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
- int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -341,8 +341,8 @@ struct vif_params {
-  * @seq_len: length of @seq.
-  */
- struct key_params {
--      u8 *key;
--      u8 *seq;
-+      const u8 *key;
-+      const u8 *seq;
-       int key_len;
-       int seq_len;
-       u32 cipher;
-@@ -458,7 +458,7 @@ bool cfg80211_chandef_usable(struct wiph
-  */
- int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-                                 const struct cfg80211_chan_def *chandef,
--                                enum nl80211_iftype);
-+                                enum nl80211_iftype iftype);
- /**
-  * ieee80211_chandef_rate_flags - returns rate flags for a channel
-@@ -694,8 +694,10 @@ struct cfg80211_ap_settings {
-  *
-  * @chandef: defines the channel to use after the switch
-  * @beacon_csa: beacon data while performing the switch
-- * @counter_offset_beacon: offset for the counter within the beacon (tail)
-- * @counter_offset_presp: offset for the counter within the probe response
-+ * @counter_offsets_beacon: offsets of the counters within the beacon (tail)
-+ * @counter_offsets_presp: offsets of the counters within the probe response
-+ * @n_counter_offsets_beacon: number of csa counters the beacon (tail)
-+ * @n_counter_offsets_presp: number of csa counters in the probe response
-  * @beacon_after: beacon data to be used on the new channel
-  * @radar_required: whether radar detection is required on the new channel
-  * @block_tx: whether transmissions should be blocked while changing
-@@ -704,7 +706,10 @@ struct cfg80211_ap_settings {
- struct cfg80211_csa_settings {
-       struct cfg80211_chan_def chandef;
-       struct cfg80211_beacon_data beacon_csa;
--      u16 counter_offset_beacon, counter_offset_presp;
-+      const u16 *counter_offsets_beacon;
-+      const u16 *counter_offsets_presp;
-+      unsigned int n_counter_offsets_beacon;
-+      unsigned int n_counter_offsets_presp;
-       struct cfg80211_beacon_data beacon_after;
-       bool radar_required;
-       bool block_tx;
-@@ -1164,7 +1169,7 @@ struct bss_parameters {
-       int use_cts_prot;
-       int use_short_preamble;
-       int use_short_slot_time;
--      u8 *basic_rates;
-+      const u8 *basic_rates;
-       u8 basic_rates_len;
-       int ap_isolate;
-       int ht_opmode;
-@@ -1694,10 +1699,10 @@ struct cfg80211_disassoc_request {
-  * @ht_capa_mask:  The bits of ht_capa which are to be used.
-  */
- struct cfg80211_ibss_params {
--      u8 *ssid;
--      u8 *bssid;
-+      const u8 *ssid;
-+      const u8 *bssid;
-       struct cfg80211_chan_def chandef;
--      u8 *ie;
-+      const u8 *ie;
-       u8 ssid_len, ie_len;
-       u16 beacon_interval;
-       u32 basic_rates;
-@@ -1806,8 +1811,8 @@ struct cfg80211_bitrate_mask {
-  * @pmkid: The PMK material itself.
-  */
- struct cfg80211_pmksa {
--      u8 *bssid;
--      u8 *pmkid;
-+      const u8 *bssid;
-+      const u8 *pmkid;
- };
+-      sdata->csa_current_counter--;
++      beacon->csa_current_counter--;
  
- /**
-@@ -1822,7 +1827,7 @@ struct cfg80211_pmksa {
-  * memory, free @mask only!
-  */
- struct cfg80211_pkt_pattern {
--      u8 *mask, *pattern;
-+      const u8 *mask, *pattern;
-       int pattern_len;
-       int pkt_offset;
- };
-@@ -1986,6 +1991,8 @@ struct cfg80211_update_ft_ies_params {
-  * @len: buffer length
-  * @no_cck: don't use cck rates for this frame
-  * @dont_wait_for_ack: tells the low level not to wait for an ack
-+ * @n_csa_offsets: length of csa_offsets array
-+ * @csa_offsets: array of all the csa offsets in the frame
-  */
- struct cfg80211_mgmt_tx_params {
-       struct ieee80211_channel *chan;
-@@ -1995,6 +2002,8 @@ struct cfg80211_mgmt_tx_params {
-       size_t len;
-       bool no_cck;
-       bool dont_wait_for_ack;
-+      int n_csa_offsets;
-+      const u16 *csa_offsets;
- };
+       /* the counter should never reach 0 */
+-      WARN_ON(!sdata->csa_current_counter);
++      WARN_ON_ONCE(!beacon->csa_current_counter);
++      count = beacon->csa_current_counter;
  
- /**
-@@ -2336,28 +2345,29 @@ struct cfg80211_ops {
-       int     (*add_station)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *mac, struct station_parameters *params);
-+                             const u8 *mac,
-+                             struct station_parameters *params);
-       int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *mac);
-+                             const u8 *mac);
-       int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
--                                u8 *mac, struct station_parameters *params);
-+                                const u8 *mac,
-+                                struct station_parameters *params);
-       int     (*get_station)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *mac, struct station_info *sinfo);
-+                             const u8 *mac, struct station_info *sinfo);
-       int     (*dump_station)(struct wiphy *wiphy, struct net_device *dev,
--                             int idx, u8 *mac, struct station_info *sinfo);
-+                              int idx, u8 *mac, struct station_info *sinfo);
-       int     (*add_mpath)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *dst, u8 *next_hop);
-+                             const u8 *dst, const u8 *next_hop);
-       int     (*del_mpath)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *dst);
-+                             const u8 *dst);
-       int     (*change_mpath)(struct wiphy *wiphy, struct net_device *dev,
--                                u8 *dst, u8 *next_hop);
-+                                const u8 *dst, const u8 *next_hop);
-       int     (*get_mpath)(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *dst, u8 *next_hop,
--                             struct mpath_info *pinfo);
-+                           u8 *dst, u8 *next_hop, struct mpath_info *pinfo);
-       int     (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
--                             int idx, u8 *dst, u8 *next_hop,
--                             struct mpath_info *pinfo);
-+                            int idx, u8 *dst, u8 *next_hop,
-+                            struct mpath_info *pinfo);
-       int     (*get_mesh_config)(struct wiphy *wiphy,
-                               struct net_device *dev,
-                               struct mesh_config *conf);
-@@ -2487,11 +2497,11 @@ struct cfg80211_ops {
-                                 struct cfg80211_gtk_rekey_data *data);
-       int     (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
--                           u8 *peer, u8 action_code,  u8 dialog_token,
-+                           const u8 *peer, u8 action_code,  u8 dialog_token,
-                            u16 status_code, u32 peer_capability,
-                            const u8 *buf, size_t len);
-       int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
--                           u8 *peer, enum nl80211_tdls_operation oper);
-+                           const u8 *peer, enum nl80211_tdls_operation oper);
-       int     (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
-                               const u8 *peer, u64 *cookie);
-@@ -2638,6 +2648,7 @@ struct ieee80211_iface_limit {
-  *    between infrastructure and AP types must match. This is required
-  *    only in special cases.
-  * @radar_detect_widths: bitmap of channel widths supported for radar detection
-+ * @radar_detect_regions: bitmap of regions supported for radar detection
-  *
-  * With this structure the driver can describe which interface
-  * combinations it supports concurrently.
-@@ -2695,6 +2706,7 @@ struct ieee80211_iface_combination {
-       u8 n_limits;
-       bool beacon_int_infra_match;
-       u8 radar_detect_widths;
-+      u8 radar_detect_regions;
- };
+-      return sdata->csa_current_counter;
++unlock:
++      rcu_read_unlock();
++      return count;
+ }
+ EXPORT_SYMBOL(ieee80211_csa_update_counter);
  
- struct ieee80211_txrx_stypes {
-@@ -2925,6 +2937,11 @@ struct wiphy_vendor_command {
-  *    (including P2P GO) or 0 to indicate no such limit is advertised. The
-  *    driver is allowed to advertise a theoretical limit that it can reach in
-  *    some cases, but may not always reach.
-+ *
-+ * @max_num_csa_counters: Number of supported csa_counters in beacons
-+ *    and probe responses.  This value should be set if the driver
-+ *    wishes to limit the number of csa counters. Default (0) means
-+ *    infinite.
-  */
- struct wiphy {
-       /* assign these fields before you register the wiphy */
-@@ -3045,6 +3062,8 @@ struct wiphy {
+@@ -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;
  
-       u16 max_ap_assoc_sta;
+       if (!ieee80211_sdata_running(sdata))
+@@ -2531,10 +2541,13 @@ bool ieee80211_csa_is_complete(struct ie
+               goto out;
+       }
  
-+      u8 max_num_csa_counters;
+-      if (WARN_ON(counter_beacon > beacon_data_len))
++      if (!beacon->csa_counter_offsets[0])
++              goto out;
 +
-       char priv[0] __aligned(NETDEV_ALIGN);
};
++      if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len))
              goto out;
  
-@@ -3273,7 +3292,7 @@ struct wireless_dev {
-               struct cfg80211_ibss_params ibss;
-               struct cfg80211_connect_params connect;
-               struct cfg80211_cached_keys *keys;
--              u8 *ie;
-+              const u8 *ie;
-               size_t ie_len;
-               u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
-               u8 ssid[IEEE80211_MAX_SSID_LEN];
-@@ -3514,7 +3533,8 @@ int ieee80211_data_to_8023(struct sk_buf
-  * Return: 0 on success, or a negative error code.
-  */
- int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
--                           enum nl80211_iftype iftype, u8 *bssid, bool qos);
-+                           enum nl80211_iftype iftype, const u8 *bssid,
-+                           bool qos);
- /**
-  * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
-@@ -4315,7 +4335,7 @@ void cfg80211_roamed_bss(struct net_devi
-  * and not try to connect to any AP any more.
-  */
- void cfg80211_disconnected(struct net_device *dev, u16 reason,
--                         u8 *ie, size_t ie_len, gfp_t gfp);
-+                         const u8 *ie, size_t ie_len, gfp_t gfp);
+-      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_
  
- /**
-  * cfg80211_ready_on_channel - notification of remain_on_channel start
-@@ -4771,6 +4791,35 @@ int cfg80211_iter_combinations(struct wi
-                                           void *data),
-                              void *data);
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct ieee80211_if_ap *ap = &sdata->u.ap;
+-              struct beacon_data *beacon = rcu_dereference(ap->beacon);
  
-+/*
-+ * cfg80211_stop_iface - trigger interface disconnection
-+ *
-+ * @wiphy: the wiphy
-+ * @wdev: wireless device
-+ * @gfp: context flags
-+ *
-+ * Trigger interface to be stopped as if AP was stopped, IBSS/mesh left, STA
-+ * disconnected.
-+ *
-+ * Note: This doesn't need any locks and is asynchronous.
-+ */
-+void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
-+                       gfp_t gfp);
-+
-+/**
-+ * cfg80211_shutdown_all_interfaces - shut down all interfaces for a wiphy
-+ * @wiphy: the wiphy to shut down
-+ *
-+ * This function shuts down all interfaces belonging to this wiphy by
-+ * calling dev_close() (and treating non-netdev interfaces as needed).
-+ * It shouldn't really be used unless there are some fatal device errors
-+ * that really can't be recovered in any other way.
-+ *
-+ * Callers must hold the RTNL and be able to deal with callbacks into
-+ * the driver while the function is running.
-+ */
-+void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy);
-+
- /* Logging, debugging and troubleshooting/diagnostic helpers. */
++              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;
  
- /* wiphy_printk helpers, similar to dev_printk */
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1113,7 +1113,9 @@ enum ieee80211_vif_flags {
-  * @addr: address of this interface
-  * @p2p: indicates whether this AP or STA interface is a p2p
-  *    interface, i.e. a GO or p2p-sta respectively
-- * @csa_active: marks whether a channel switch is going on
-+ * @csa_active: marks whether a channel switch is going on. Internally it is
-+ *    write-protected by sdata_lock and local->mtx so holding either is fine
-+ *    for read access.
-  * @driver_flags: flags/capabilities the driver has for this interface,
-  *    these need to be set (or cleared) when the interface is added
-  *    or, if supported by the driver, the interface type is changed
-@@ -1374,6 +1376,7 @@ struct ieee80211_sta_rates {
-  *    the station moves to associated state.
-  * @smps_mode: current SMPS mode (off, static or dynamic)
-  * @rates: rate control selection table
-+ * @tdls: indicates whether the STA is a TDLS peer
-  */
- struct ieee80211_sta {
-       u32 supp_rates[IEEE80211_NUM_BANDS];
-@@ -1388,6 +1391,7 @@ struct ieee80211_sta {
-       enum ieee80211_sta_rx_bandwidth bandwidth;
-       enum ieee80211_smps_mode smps_mode;
-       struct ieee80211_sta_rates __rcu *rates;
-+      bool tdls;
-       /* must be last */
-       u8 drv_priv[0] __aligned(sizeof(void *));
-@@ -3407,6 +3411,47 @@ void ieee80211_tx_status_irqsafe(struct 
-  */
- void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
+-              if (sdata->vif.csa_active) {
++              if (beacon->csa_counter_offsets[0]) {
+                       if (!is_template)
+                               ieee80211_csa_update_counter(vif);
  
-+#define IEEE80211_MAX_CSA_COUNTERS_NUM 2
-+
-+/**
-+ * struct ieee80211_mutable_offsets - mutable beacon offsets
-+ * @tim_offset: position of TIM element
-+ * @tim_length: size of TIM element
-+ * @csa_counter_offs: array of IEEE80211_MAX_CSA_COUNTERS_NUM offsets
-+ *    to CSA counters.  This array can contain zero values which
-+ *    should be ignored.
-+ */
-+struct ieee80211_mutable_offsets {
-+      u16 tim_offset;
-+      u16 tim_length;
-+
-+      u16 csa_counter_offs[IEEE80211_MAX_CSA_COUNTERS_NUM];
-+};
-+
-+/**
-+ * ieee80211_beacon_get_template - beacon template generation function
-+ * @hw: pointer obtained from ieee80211_alloc_hw().
-+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
-+ * @offs: &struct ieee80211_mutable_offsets pointer to struct that will
-+ *    receive the offsets that may be updated by the driver.
-+ *
-+ * If the driver implements beaconing modes, it must use this function to
-+ * obtain the beacon template.
-+ *
-+ * This function should be used if the beacon frames are generated by the
-+ * device, and then the driver must use the returned beacon as the template
-+ * The driver or the device are responsible to update the DTIM and, when
-+ * applicable, the CSA count.
-+ *
-+ * The driver is responsible for freeing the returned skb.
-+ *
-+ * Return: The beacon template. %NULL on error.
-+ */
-+struct sk_buff *
-+ieee80211_beacon_get_template(struct ieee80211_hw *hw,
-+                            struct ieee80211_vif *vif,
-+                            struct ieee80211_mutable_offsets *offs);
-+
- /**
-  * ieee80211_beacon_get_tim - beacon generation function
-  * @hw: pointer obtained from ieee80211_alloc_hw().
-@@ -3418,16 +3463,12 @@ void ieee80211_report_low_ack(struct iee
-  *    Set to 0 if invalid (in non-AP modes).
-  *
-  * If the driver implements beaconing modes, it must use this function to
-- * obtain the beacon frame/template.
-+ * obtain the beacon frame.
-  *
-  * If the beacon frames are generated by the host system (i.e., not in
-  * hardware/firmware), the driver uses this function to get each beacon
-- * frame from mac80211 -- it is responsible for calling this function
-- * before the beacon is needed (e.g. based on hardware interrupt).
-- *
-- * If the beacon frames are generated by the device, then the driver
-- * must use the returned beacon as the template and change the TIM IE
-- * according to the current DTIM parameters/TIM bitmap.
-+ * frame from mac80211 -- it is responsible for calling this function exactly
-+ * once before the beacon is needed (e.g. based on hardware interrupt).
-  *
-  * The driver is responsible for freeing the returned skb.
-  *
-@@ -3453,6 +3494,20 @@ static inline struct sk_buff *ieee80211_
- }
+-                      ieee80211_set_csa(sdata, presp);
++                      ieee80211_set_csa(sdata, beacon);
+               }
  
- /**
-+ * ieee80211_csa_update_counter - request mac80211 to decrement the csa counter
-+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
-+ *
-+ * The csa counter should be updated after each beacon transmission.
-+ * This function is called implicitly when
-+ * ieee80211_beacon_get/ieee80211_beacon_get_tim are called, however if the
-+ * beacon frames are generated by the device, the driver should call this
-+ * function after each beacon transmission to sync mac80211's csa counters.
-+ *
-+ * Return: new csa counter value
-+ */
-+u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif);
-+
-+/**
-  * ieee80211_csa_finish - notify mac80211 about channel switch
-  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
-  *
---- a/include/uapi/linux/nl80211.h
-+++ b/include/uapi/linux/nl80211.h
-@@ -503,6 +503,9 @@
-  *    TX status event pertaining to the TX request.
-  *    %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
-  *    management frames at CCK rate or not in 2GHz band.
-+ *    %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA
-+ *    counters which will be updated to the current value. This attribute
-+ *    is used during CSA period.
-  * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
-  *    command may be used with the corresponding cookie to cancel the wait
-  *    time if it is known that it is no longer necessary.
-@@ -1525,10 +1528,10 @@ enum nl80211_commands {
-  *    operation).
-  * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
-  *    for the time while performing a channel switch.
-- * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter
-- *    field in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
-- * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter
-- *    field in the probe response (%NL80211_ATTR_PROBE_RESP).
-+ * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel
-+ *    switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
-+ * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel
-+ *    switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).
-  *
-  * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32.
-  *    As specified in the &enum nl80211_rxmgmt_flags.
-@@ -1576,6 +1579,11 @@ enum nl80211_commands {
-  *    advertise values that cannot always be met. In such cases, an attempt
-  *    to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
-  *
-+ * @NL80211_ATTR_CSA_C_OFFSETS_TX: An array of csa counter offsets (u16) which
-+ *    should be updated when the frame is transmitted.
-+ * @NL80211_ATTR_MAX_CSA_COUNTERS: U8 attribute used to advertise the maximum
-+ *    supported number of csa counters.
-+ *
-  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
-  *    As specified in the &enum nl80211_tdls_peer_capability.
-  *
-@@ -1920,6 +1928,9 @@ enum nl80211_attrs {
+-              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;
  
-       NL80211_ATTR_IFACE_SOCKET_OWNER,
+-              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_
+                                */
+                               ieee80211_csa_update_counter(vif);
+-                      ieee80211_set_csa(sdata, bcn);
++                      ieee80211_set_csa(sdata, beacon);
+               }
  
-+      NL80211_ATTR_CSA_C_OFFSETS_TX,
-+      NL80211_ATTR_MAX_CSA_COUNTERS,
-+
-       /* add attributes here, update the policy in nl80211.c */
-       __NL80211_ATTR_AFTER_LAST,
-@@ -3688,6 +3699,8 @@ enum nl80211_iface_limit_attrs {
-  *    different channels may be used within this group.
-  * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
-  *    of supported channel widths for radar detection.
-+ * @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
-+ *    of supported regulatory regions for radar detection.
-  * @NUM_NL80211_IFACE_COMB: number of attributes
-  * @MAX_NL80211_IFACE_COMB: highest attribute number
-  *
-@@ -3721,6 +3734,7 @@ enum nl80211_if_combination_attrs {
-       NL80211_IFACE_COMB_STA_AP_BI_MATCH,
-       NL80211_IFACE_COMB_NUM_CHANNELS,
-       NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
-+      NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
-       /* keep last */
-       NUM_NL80211_IFACE_COMB,
---- a/net/mac80211/Makefile
-+++ b/net/mac80211/Makefile
-@@ -25,7 +25,8 @@ mac80211-y := \
-       wme.o \
-       event.o \
-       chan.o \
--      trace.o mlme.o
-+      trace.o mlme.o \
-+      tdls.o
- mac80211-$(CPTCFG_MAC80211_LEDS) += led.o
- mac80211-$(CPTCFG_MAC80211_DEBUGFS) += \
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -777,7 +777,7 @@ static void ieee80211_get_et_strings(str
- }
+               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;
+               }
  
- static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
--                               int idx, u8 *mac, struct station_info *sinfo)
-+                                int idx, u8 *mac, struct station_info *sinfo)
- {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
-@@ -807,7 +807,7 @@ static int ieee80211_dump_survey(struct 
- }
+-              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;
+       }
  
- static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
--                               u8 *mac, struct station_info *sinfo)
-+                               const u8 *mac, struct station_info *sinfo)
- {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
-@@ -1084,6 +1084,31 @@ static int ieee80211_change_beacon(struc
-       return 0;
+       /* 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));
  }
  
-+bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local)
++static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev)
 +{
-+      struct ieee80211_sub_if_data *sdata;
-+
-+      lockdep_assert_held(&local->mtx);
++      struct data_queue *queue = rt2x00dev->bcn;
++      struct queue_entry *entry;
++      int i, bcn_num = 0;
++      u64 off, reg = 0;
++      u32 bssid_dw1;
 +
-+      rcu_read_lock();
-+      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-+              if (!ieee80211_sdata_running(sdata))
-+                      continue;
-+
-+              if (!sdata->vif.csa_active)
++      /*
++       * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers.
++       */
++      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++;
++      }
 +
-+              if (!sdata->csa_block_tx)
-+                      continue;
++      WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing);
 +
-+              rcu_read_unlock();
-+              return true;
-+      }
-+      rcu_read_unlock();
++      rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg);
++      rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32));
 +
-+      return false;
++      /*
++       * 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);
 +}
 +
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
  {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -1101,7 +1126,14 @@ static int ieee80211_stop_ap(struct wiph
-       old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
-       /* abort any running channel switch */
-+      mutex_lock(&local->mtx);
-       sdata->vif.csa_active = false;
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-+                                      IEEE80211_MAX_QUEUE_MAP,
-+                                      IEEE80211_QUEUE_STOP_REASON_CSA);
-+      mutex_unlock(&local->mtx);
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_en
+       rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+                                  entry->skb->len + padding_len);
++      __set_bit(ENTRY_BCN_ENABLED, &entry->flags);
 +
-       kfree(sdata->u.ap.next_beacon);
-       sdata->u.ap.next_beacon = NULL;
++      /*
++       * Change global beacons settings.
++       */
++      rt2800_update_beacons_setup(rt2x00dev);
  
-@@ -1425,7 +1457,8 @@ static int sta_apply_parameters(struct i
- }
+       /*
+        * Restore beaconing state.
+@@ -1053,8 +1093,13 @@ void rt2800_clear_beacon(struct queue_en
+        * Clear beacon.
+        */
+       rt2800_clear_beacon_register(rt2x00dev, entry->entry_idx);
++      __clear_bit(ENTRY_BCN_ENABLED, &entry->flags);
  
- static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
--                               u8 *mac, struct station_parameters *params)
-+                               const u8 *mac,
-+                               struct station_parameters *params)
- {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct sta_info *sta;
-@@ -1459,6 +1492,8 @@ static int ieee80211_add_station(struct 
-       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
-               sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
-               sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
-+      } else {
-+              sta->sta.tdls = true;
-       }
+       /*
++       * 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);
+               }
  
-       err = sta_apply_parameters(local, sta, params);
-@@ -1492,7 +1527,7 @@ static int ieee80211_add_station(struct 
- }
+@@ -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);
  
- static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
--                               u8 *mac)
-+                               const u8 *mac)
- {
-       struct ieee80211_sub_if_data *sdata;
+--- 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;
  
-@@ -1506,7 +1541,7 @@ static int ieee80211_del_station(struct 
+-      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);
++      }
  }
  
- static int ieee80211_change_station(struct wiphy *wiphy,
--                                  struct net_device *dev, u8 *mac,
-+                                  struct net_device *dev, const u8 *mac,
-                                   struct station_parameters *params)
- {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -1631,7 +1666,7 @@ out_err:
- #ifdef CPTCFG_MAC80211_MESH
- static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
--                               u8 *dst, u8 *next_hop)
-+                             const u8 *dst, const u8 *next_hop)
- {
-       struct ieee80211_sub_if_data *sdata;
-       struct mesh_path *mpath;
-@@ -1659,7 +1694,7 @@ static int ieee80211_add_mpath(struct wi
+ 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);
  }
  
- static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *dst)
-+                             const u8 *dst)
- {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
+--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
+@@ -624,25 +624,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 +657,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);
+       }
+       /*
+--- 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;
+-      mutex_lock(&intf->beacon_skb_mutex);
+-
+       /*
+        * 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);
  
-@@ -1670,9 +1705,8 @@ static int ieee80211_del_mpath(struct wi
+-      mutex_unlock(&intf->beacon_skb_mutex);
+-
        return 0;
  }
  
--static int ieee80211_change_mpath(struct wiphy *wiphy,
--                                  struct net_device *dev,
--                                  u8 *dst, u8 *next_hop)
-+static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev,
-+                                const u8 *dst, const u8 *next_hop)
+-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 ieee80211_sub_if_data *sdata;
-       struct mesh_path *mpath;
-@@ -1764,8 +1798,8 @@ static int ieee80211_get_mpath(struct wi
- }
+       struct rt2x00_intf *intf = vif_to_intf(vif);
+       struct skb_frame_desc *skbdesc;
+@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str
  
- static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
--                               int idx, u8 *dst, u8 *next_hop,
--                               struct mpath_info *pinfo)
-+                              int idx, u8 *dst, u8 *next_hop,
-+                              struct mpath_info *pinfo)
- {
-       struct ieee80211_sub_if_data *sdata;
-       struct mesh_path *mpath;
-@@ -3019,26 +3053,11 @@ void ieee80211_csa_finish(struct ieee802
  }
- EXPORT_SYMBOL(ieee80211_csa_finish);
  
--static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
-+static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
-+                                        u32 *changed)
- {
--      struct ieee80211_local *local = sdata->local;
--      int err, changed = 0;
+-int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+-                            struct ieee80211_vif *vif)
+-{
+-      struct rt2x00_intf *intf = vif_to_intf(vif);
+-      int ret;
 -
--      sdata_assert_lock(sdata);
+-      mutex_lock(&intf->beacon_skb_mutex);
+-      ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif);
+-      mutex_unlock(&intf->beacon_skb_mutex);
 -
--      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))
--              return;
+-      return ret;
+-}
 -
--      if (!local->use_chanctx) {
--              local->_oper_chandef = sdata->csa_chandef;
--              ieee80211_hw_config(local, 0);
--      }
-+      int err;
--      sdata->vif.csa_active = false;
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-               err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
-@@ -3046,35 +3065,75 @@ static void ieee80211_csa_finalize(struc
-               sdata->u.ap.next_beacon = NULL;
-               if (err < 0)
--                      return;
--              changed |= err;
-+                      return err;
-+              *changed |= err;
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               err = ieee80211_ibss_finish_csa(sdata);
-               if (err < 0)
--                      return;
--              changed |= err;
-+                      return err;
-+              *changed |= err;
-               break;
- #ifdef CPTCFG_MAC80211_MESH
-       case NL80211_IFTYPE_MESH_POINT:
-               err = ieee80211_mesh_finish_csa(sdata);
-               if (err < 0)
--                      return;
--              changed |= err;
-+                      return err;
-+              *changed |= err;
-               break;
- #endif
-       default:
-               WARN_ON(1);
--              return;
-+              return -EINVAL;
-       }
-+
-+      return 0;
-+}
-+
-+static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      u32 changed = 0;
-+      int err;
-+
-+      sdata_assert_lock(sdata);
-+      lockdep_assert_held(&local->mtx);
-+
-+      sdata->radar_required = sdata->csa_radar_required;
-+      err = ieee80211_vif_change_channel(sdata, &changed);
-+      if (err < 0)
-+              return err;
-+
-+      if (!local->use_chanctx) {
-+              local->_oper_chandef = sdata->csa_chandef;
-+              ieee80211_hw_config(local, 0);
-+      }
-+
-+      sdata->vif.csa_active = false;
-+
-+      err = ieee80211_set_after_csa_beacon(sdata, &changed);
-+      if (err)
-+              return err;
-+
-       ieee80211_bss_info_change_notify(sdata, changed);
-+      cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
--      ieee80211_wake_queues_by_reason(&sdata->local->hw,
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-                                       IEEE80211_MAX_QUEUE_MAP,
-                                       IEEE80211_QUEUE_STOP_REASON_CSA);
--      cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
-+      return 0;
-+}
-+
-+static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
-+{
-+      if (__ieee80211_csa_finalize(sdata)) {
-+              sdata_info(sdata, "failed to finalize CSA, disconnecting\n");
-+              cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
-+                                  GFP_KERNEL);
-+      }
- }
- void ieee80211_csa_finalize_work(struct work_struct *work)
-@@ -3082,8 +3141,11 @@ void ieee80211_csa_finalize_work(struct 
-       struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data,
-                            csa_finalize_work);
-+      struct ieee80211_local *local = sdata->local;
-       sdata_lock(sdata);
-+      mutex_lock(&local->mtx);
-+
-       /* AP might have been stopped while waiting for the lock. */
-       if (!sdata->vif.csa_active)
-               goto unlock;
-@@ -3094,6 +3156,7 @@ void ieee80211_csa_finalize_work(struct 
-       ieee80211_csa_finalize(sdata);
- unlock:
-+      mutex_unlock(&local->mtx);
-       sdata_unlock(sdata);
- }
-@@ -3129,9 +3192,25 @@ static int ieee80211_set_csa_beacon(stru
-               if (params->count <= 1)
-                       break;
--              sdata->csa_counter_offset_beacon =
--                      params->counter_offset_beacon;
--              sdata->csa_counter_offset_presp = params->counter_offset_presp;
-+              if ((params->n_counter_offsets_beacon >
-+                   IEEE80211_MAX_CSA_COUNTERS_NUM) ||
-+                  (params->n_counter_offsets_presp >
-+                   IEEE80211_MAX_CSA_COUNTERS_NUM))
-+                      return -EINVAL;
-+
-+              /* 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));
-+
-               err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
-               if (err < 0) {
-                       kfree(sdata->u.ap.next_beacon);
-@@ -3220,8 +3299,9 @@ static int ieee80211_set_csa_beacon(stru
-       return 0;
- }
--int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
--                           struct cfg80211_csa_settings *params)
-+static int
-+__ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-+                         struct cfg80211_csa_settings *params)
+ 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 ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
-@@ -3230,6 +3310,7 @@ int ieee80211_channel_switch(struct wiph
-       int err, num_chanctx, changed = 0;
+       struct ath_vif *avp = (void *)vif->drv_priv;
+-      unsigned long flags;
+       u32 tsf;
  
-       sdata_assert_lock(sdata);
-+      lockdep_assert_held(&local->mtx);
-       if (!list_empty(&local->roc_list) || local->scanning)
-               return -EBUSY;
-@@ -3272,15 +3353,16 @@ int ieee80211_channel_switch(struct wiph
-               return err;
+       if (!sc->p2p_ps_timer)
+@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft
+               return;
  
-       sdata->csa_radar_required = params->radar_required;
+       sc->p2p_ps_vif = avp;
 -
--      if (params->block_tx)
--              ieee80211_stop_queues_by_reason(&local->hw,
--                              IEEE80211_MAX_QUEUE_MAP,
--                              IEEE80211_QUEUE_STOP_REASON_CSA);
--
-       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)
-+              ieee80211_stop_queues_by_reason(&local->hw,
-+                                      IEEE80211_MAX_QUEUE_MAP,
-+                                      IEEE80211_QUEUE_STOP_REASON_CSA);
-+
-       if (changed) {
-               ieee80211_bss_info_change_notify(sdata, changed);
-               drv_channel_switch_beacon(sdata, &params->chandef);
-@@ -3292,6 +3374,20 @@ int ieee80211_channel_switch(struct wiph
-       return 0;
+-      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);
  }
  
-+int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-+                           struct cfg80211_csa_settings *params)
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct ieee80211_local *local = sdata->local;
-+      int err;
-+
-+      mutex_lock(&local->mtx);
-+      err = __ieee80211_channel_switch(wiphy, dev, params);
-+      mutex_unlock(&local->mtx);
-+
-+      return err;
-+}
-+
- static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
-                            struct cfg80211_mgmt_tx_params *params,
-                            u64 *cookie)
-@@ -3304,6 +3400,7 @@ static int ieee80211_mgmt_tx(struct wiph
-       bool need_offchan = false;
-       u32 flags;
-       int ret;
-+      u8 *data;
-       if (params->dont_wait_for_ack)
-               flags = IEEE80211_TX_CTL_NO_ACK;
-@@ -3397,7 +3494,20 @@ static int ieee80211_mgmt_tx(struct wiph
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
--      memcpy(skb_put(skb, params->len), params->buf, params->len);
-+      data = skb_put(skb, params->len);
-+      memcpy(data, params->buf, params->len);
-+
-+      /* Update CSA counters */
-+      if (sdata->vif.csa_active &&
-+          (sdata->vif.type == NL80211_IFTYPE_AP ||
-+           sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
-+          params->n_csa_offsets) {
-+              int i;
-+              u8 c = sdata->csa_current_counter;
-+
-+              for (i = 0; i < params->n_csa_offsets; i++)
-+                      data[params->csa_offsets[i]] = c;
-+      }
+ 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;
  
-       IEEE80211_SKB_CB(skb)->flags = flags;
+       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);
+       }
  
-@@ -3506,320 +3616,6 @@ static int ieee80211_set_rekey_data(stru
-       return 0;
+@@ -2232,14 +2230,6 @@ static void ath9k_sw_scan_complete(struc
+       clear_bit(ATH_OP_SCANNING, &common->op_flags);
  }
  
--static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
+-static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw,
+-                                      struct ieee80211_vif *vif,
+-                                      struct cfg80211_chan_def *chandef)
 -{
--      u8 *pos = (void *)skb_put(skb, 7);
--
--      *pos++ = WLAN_EID_EXT_CAPABILITY;
--      *pos++ = 5; /* len */
--      *pos++ = 0x0;
--      *pos++ = 0x0;
--      *pos++ = 0x0;
--      *pos++ = 0x0;
--      *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
+-      /* depend on vif->csa_active only */
+-      return;
 -}
 -
--static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
+ 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);
+ }
+-static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw,
+-                                       struct ieee80211_vif *vif,
+-                                       struct cfg80211_chan_def *chandef)
 -{
--      struct ieee80211_local *local = sdata->local;
--      u16 capab;
--
--      capab = 0;
--      if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
--              return capab;
--
--      if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
--              capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
--      if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
--              capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
--
--      return capab;
+-      /* there's no need to do anything here. vif->csa_active is enough */
+-      return;
 -}
 -
--static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
--                                     u8 *peer, u8 *bssid)
+ 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;
+ }
+-static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 -{
--      struct ieee80211_tdls_lnkie *lnkid;
--
--      lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
+-      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;
 -
--      lnkid->ie_type = WLAN_EID_LINK_ID;
--      lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
+-      sinfo->generation = sdata->local->sta_generation;
 -
--      memcpy(lnkid->bssid, bssid, ETH_ALEN);
--      memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
--      memcpy(lnkid->resp_sta, peer, ETH_ALEN);
--}
+-      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;
 -
--static int
--ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *peer, u8 action_code, u8 dialog_token,
--                             u16 status_code, struct sk_buff *skb)
--{
--      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
--      enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
--      struct ieee80211_tdls_data *tf;
+-      do_posix_clock_monotonic_gettime(&uptime);
+-      sinfo->connected_time = uptime.tv_sec - sta->last_connected;
 -
--      tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
+-      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;
 -
--      memcpy(tf->da, peer, ETH_ALEN);
--      memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
--      tf->ether_type = cpu_to_be16(ETH_P_TDLS);
--      tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
+-      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;
 -
--      switch (action_code) {
--      case WLAN_TDLS_SETUP_REQUEST:
--              tf->category = WLAN_CATEGORY_TDLS;
--              tf->action_code = WLAN_TDLS_SETUP_REQUEST;
+-              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]);
+-              }
+-      }
 -
--              skb_put(skb, sizeof(tf->u.setup_req));
--              tf->u.setup_req.dialog_token = dialog_token;
--              tf->u.setup_req.capability =
--                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+-      sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
+-      sta_set_rate_info_rx(sta, &sinfo->rxrate);
 -
--              ieee80211_add_srates_ie(sdata, skb, false, band);
--              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
--              ieee80211_tdls_add_ext_capab(skb);
--              break;
--      case WLAN_TDLS_SETUP_RESPONSE:
--              tf->category = WLAN_CATEGORY_TDLS;
--              tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
+-      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;
 -
--              skb_put(skb, sizeof(tf->u.setup_resp));
--              tf->u.setup_resp.status_code = cpu_to_le16(status_code);
--              tf->u.setup_resp.dialog_token = dialog_token;
--              tf->u.setup_resp.capability =
--                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
+-              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
+-      }
 -
--              ieee80211_add_srates_ie(sdata, skb, false, band);
--              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
--              ieee80211_tdls_add_ext_capab(skb);
--              break;
--      case WLAN_TDLS_SETUP_CONFIRM:
--              tf->category = WLAN_CATEGORY_TDLS;
--              tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
+-      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;
 -
--              skb_put(skb, sizeof(tf->u.setup_cfm));
--              tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
--              tf->u.setup_cfm.dialog_token = dialog_token;
--              break;
--      case WLAN_TDLS_TEARDOWN:
--              tf->category = WLAN_CATEGORY_TDLS;
--              tf->action_code = WLAN_TDLS_TEARDOWN;
+-      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);
 -
--              skb_put(skb, sizeof(tf->u.teardown));
--              tf->u.teardown.reason_code = cpu_to_le16(status_code);
--              break;
--      case WLAN_TDLS_DISCOVERY_REQUEST:
--              tf->category = WLAN_CATEGORY_TDLS;
--              tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
+-      /* 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);
 -
--              skb_put(skb, sizeof(tf->u.discover_req));
--              tf->u.discover_req.dialog_token = dialog_token;
--              break;
--      default:
--              return -EINVAL;
+-      if (thr != 0) {
+-              sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+-              sinfo->expected_throughput = thr;
 -      }
--
--      return 0;
 -}
 -
--static int
--ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
--                         u8 *peer, u8 action_code, u8 dialog_token,
--                         u16 status_code, struct sk_buff *skb)
+-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);
--      enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
--      struct ieee80211_mgmt *mgmt;
+-      int rv = 0;
 -
--      mgmt = (void *)skb_put(skb, 24);
--      memset(mgmt, 0, 24);
--      memcpy(mgmt->da, peer, ETH_ALEN);
--      memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
--      memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+-      if (sset == ETH_SS_STATS)
+-              rv += STA_STATS_LEN;
 -
--      mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
--                                        IEEE80211_STYPE_ACTION);
--
--      switch (action_code) {
--      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
--              skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
--              mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
--              mgmt->u.action.u.tdls_discover_resp.action_code =
--                      WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
--              mgmt->u.action.u.tdls_discover_resp.dialog_token =
--                      dialog_token;
--              mgmt->u.action.u.tdls_discover_resp.capability =
--                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
--
--              ieee80211_add_srates_ie(sdata, skb, false, band);
--              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
--              ieee80211_tdls_add_ext_capab(skb);
--              break;
--      default:
--              return -EINVAL;
--      }
+-      rv += drv_get_et_sset_count(sdata, sset);
 -
--      return 0;
+-      if (rv == 0)
+-              return -EOPNOTSUPP;
+-      return rv;
 -}
 -
--static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *peer, u8 action_code, u8 dialog_token,
--                             u16 status_code, u32 peer_capability,
--                             const u8 *extra_ies, size_t extra_ies_len)
+-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 sk_buff *skb = NULL;
--      bool send_direct;
--      int ret;
+-      struct station_info sinfo;
+-      struct survey_info survey;
+-      int i, q;
+-#define STA_STATS_SURVEY_LEN 7
 -
--      if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
--              return -ENOTSUPP;
+-      memset(data, 0, sizeof(u64) * STA_STATS_LEN);
 -
--      /* make sure we are in managed mode, and associated */
--      if (sdata->vif.type != NL80211_IFTYPE_STATION ||
--          !sdata->u.mgd.associated)
--              return -EINVAL;
+-#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)
 -
--      tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
--               action_code, peer);
+-      /* 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.
+-       */
 -
--      skb = dev_alloc_skb(local->hw.extra_tx_headroom +
--                          max(sizeof(struct ieee80211_mgmt),
--                              sizeof(struct ieee80211_tdls_data)) +
--                          50 + /* supported rates */
--                          7 + /* ext capab */
--                          extra_ies_len +
--                          sizeof(struct ieee80211_tdls_lnkie));
--      if (!skb)
--              return -ENOMEM;
+-      mutex_lock(&local->sta_mtx);
 -
--      skb_reserve(skb, local->hw.extra_tx_headroom);
+-      if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+-              sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
 -
--      switch (action_code) {
--      case WLAN_TDLS_SETUP_REQUEST:
--      case WLAN_TDLS_SETUP_RESPONSE:
--      case WLAN_TDLS_SETUP_CONFIRM:
--      case WLAN_TDLS_TEARDOWN:
--      case WLAN_TDLS_DISCOVERY_REQUEST:
--              ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
--                                                   action_code, dialog_token,
--                                                   status_code, skb);
--              send_direct = false;
--              break;
--      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
--              ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
--                                               dialog_token, status_code,
--                                               skb);
--              send_direct = true;
--              break;
--      default:
--              ret = -ENOTSUPP;
--              break;
--      }
+-              if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
+-                      goto do_survey;
 -
--      if (ret < 0)
--              goto fail;
+-              sinfo.filled = 0;
+-              sta_set_sinfo(sta, &sinfo);
 -
--      if (extra_ies_len)
--              memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
+-              i = 0;
+-              ADD_STA_STATS(sta);
 -
--      /* the TDLS link IE is always added last */
--      switch (action_code) {
--      case WLAN_TDLS_SETUP_REQUEST:
--      case WLAN_TDLS_SETUP_CONFIRM:
--      case WLAN_TDLS_TEARDOWN:
--      case WLAN_TDLS_DISCOVERY_REQUEST:
--              /* we are the initiator */
--              ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
--                                         sdata->u.mgd.bssid);
--              break;
--      case WLAN_TDLS_SETUP_RESPONSE:
--      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
--              /* we are the responder */
--              ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
--                                         sdata->u.mgd.bssid);
--              break;
--      default:
--              ret = -ENOTSUPP;
--              goto fail;
--      }
+-              data[i++] = sta->sta_state;
 -
--      if (send_direct) {
--              ieee80211_tx_skb(sdata, skb);
--              return 0;
--      }
 -
--      /*
--       * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
--       * we should default to AC_VI.
--       */
--      switch (action_code) {
--      case WLAN_TDLS_SETUP_REQUEST:
--      case WLAN_TDLS_SETUP_RESPONSE:
--              skb_set_queue_mapping(skb, IEEE80211_AC_BK);
--              skb->priority = 2;
--              break;
--      default:
--              skb_set_queue_mapping(skb, IEEE80211_AC_VI);
--              skb->priority = 5;
--              break;
+-              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);
+-              }
 -      }
 -
--      /* disable bottom halves when entering the Tx path */
--      local_bh_disable();
--      ret = ieee80211_subif_start_xmit(skb, dev);
--      local_bh_enable();
+-do_survey:
+-      i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
+-      /* Get survey stats for current channel */
+-      survey.filled = 0;
 -
--      return ret;
+-      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();
 -
--fail:
--      dev_kfree_skb(skb);
--      return ret;
--}
+-      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);
+-      }
 -
--static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
--                             u8 *peer, enum nl80211_tdls_operation oper)
--{
--      struct sta_info *sta;
--      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      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;
 -
--      if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
--              return -ENOTSUPP;
+-      mutex_unlock(&local->sta_mtx);
 -
--      if (sdata->vif.type != NL80211_IFTYPE_STATION)
--              return -EINVAL;
+-      if (WARN_ON(i != STA_STATS_LEN))
+-              return;
 -
--      tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
+-      drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+-}
 -
--      switch (oper) {
--      case NL80211_TDLS_ENABLE_LINK:
--              rcu_read_lock();
--              sta = sta_info_get(sdata, peer);
--              if (!sta) {
--                      rcu_read_unlock();
--                      return -ENOLINK;
--              }
+-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;
 -
--              set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
--              rcu_read_unlock();
--              break;
--      case NL80211_TDLS_DISABLE_LINK:
--              return sta_info_destroy_addr(sdata, peer);
--      case NL80211_TDLS_TEARDOWN:
--      case NL80211_TDLS_SETUP:
--      case NL80211_TDLS_DISCOVERY_REQ:
--              /* We don't support in-driver setup/teardown/discovery */
--              return -ENOTSUPP;
--      default:
--              return -ENOTSUPP;
+-      if (sset == ETH_SS_STATS) {
+-              sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
+-              memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
 -      }
--
--      return 0;
+-      drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
 -}
 -
- static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
-                                 const u8 *peer, u64 *cookie)
- {
---- a/net/mac80211/chan.c
-+++ b/net/mac80211/chan.c
-@@ -855,7 +855,7 @@ static void
- __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
-                                     bool clear)
- {
--      struct ieee80211_local *local = sdata->local;
-+      struct ieee80211_local *local __maybe_unused = sdata->local;
-       struct ieee80211_sub_if_data *vlan;
-       struct ieee80211_chanctx_conf *conf;
-@@ -871,7 +871,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(st
-        * to a channel context that has already been freed.
-        */
-       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
--                              lockdep_is_held(&local->chanctx_mtx));
-+                                       lockdep_is_held(&local->chanctx_mtx));
-       WARN_ON(!conf);
-       if (clear)
---- a/net/mac80211/driver-ops.h
-+++ b/net/mac80211/driver-ops.h
-@@ -5,11 +5,11 @@
- #include "ieee80211_i.h"
- #include "trace.h"
--static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
-+static inline bool check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
+ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+                                 int idx, u8 *mac, struct station_info *sinfo)
  {
--      WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER),
--           "%s:  Failed check-sdata-in-driver check, flags: 0x%x\n",
--           sdata->dev ? sdata->dev->name : sdata->name, sdata->flags);
-+      return !WARN(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER),
-+                   "%s:  Failed check-sdata-in-driver check, flags: 0x%x\n",
-+                   sdata->dev ? sdata->dev->name : sdata->name, sdata->flags);
+@@ -875,7 +554,8 @@ static int ieee80211_set_monitor_channel
  }
  
- static inline struct ieee80211_sub_if_data *
-@@ -168,7 +168,8 @@ static inline int drv_change_interface(s
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_change_interface(local, sdata, type, p2p);
-       ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
-@@ -181,7 +182,8 @@ static inline void drv_remove_interface(
+ 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)
  {
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_remove_interface(local, sdata);
-       local->ops->remove_interface(&local->hw, &sdata->vif);
-@@ -219,7 +221,8 @@ static inline void drv_bss_info_changed(
-                        sdata->vif.type == NL80211_IFTYPE_MONITOR))
-               return;
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_bss_info_changed(local, sdata, info, changed);
-       if (local->ops->bss_info_changed)
-@@ -278,7 +281,8 @@ static inline int drv_set_key(struct iee
-       might_sleep();
+       struct probe_resp *new, *old;
  
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
+@@ -891,6 +571,11 @@ static int ieee80211_set_probe_resp(stru
+       new->len = resp_len;
+       memcpy(new->data, resp, resp_len);
  
-       trace_drv_set_key(local, cmd, sdata, sta, key);
-       ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
-@@ -298,7 +302,8 @@ static inline void drv_update_tkip_key(s
-               ista = &sta->sta;
++      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
+ }
  
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
+ 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);
  
-       trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
-       if (local->ops->update_tkip_key)
-@@ -315,7 +320,8 @@ static inline int drv_hw_scan(struct iee
+       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;
+-      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;
  
-       might_sleep();
+-      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
  
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
+       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;
  
-       trace_drv_hw_scan(local, sdata);
-       ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
-@@ -328,7 +334,8 @@ static inline void drv_cancel_hw_scan(st
+@@ -3176,6 +2870,7 @@ static int ieee80211_set_csa_beacon(stru
+                                   struct cfg80211_csa_settings *params,
+                                   u32 *changed)
  {
-       might_sleep();
++      struct ieee80211_csa_settings csa = {};
+       int err;
  
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
+       switch (sdata->vif.type) {
+@@ -3210,20 +2905,13 @@ static int ieee80211_set_csa_beacon(stru
+                    IEEE80211_MAX_CSA_COUNTERS_NUM))
+                       return -EINVAL;
  
-       trace_drv_cancel_hw_scan(local, sdata);
-       local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
-@@ -345,7 +352,8 @@ drv_sched_scan_start(struct ieee80211_lo
+-              /* 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;
  
-       might_sleep();
+       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();
  
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
+-              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();
+       }
  
-       trace_drv_sched_scan_start(local, sdata);
-       ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
-@@ -361,7 +369,8 @@ static inline int drv_sched_scan_stop(st
+       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);
+ }
  
-       might_sleep();
+-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;
+ }
  
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
+-
+-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);
  
-       trace_drv_sched_scan_stop(local, sdata);
-       ret = local->ops->sched_scan_stop(&local->hw, &sdata->vif);
-@@ -462,7 +471,8 @@ static inline void drv_sta_notify(struct
-                                 struct ieee80211_sta *sta)
- {
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_sta_notify(local, sdata, cmd, sta);
-       if (local->ops->sta_notify)
-@@ -479,7 +489,8 @@ static inline int drv_sta_add(struct iee
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_sta_add(local, sdata, sta);
-       if (local->ops->sta_add)
-@@ -497,7 +508,8 @@ static inline void drv_sta_remove(struct
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_sta_remove(local, sdata, sta);
-       if (local->ops->sta_remove)
-@@ -515,7 +527,8 @@ static inline void drv_sta_add_debugfs(s
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       if (local->ops->sta_add_debugfs)
-               local->ops->sta_add_debugfs(&local->hw, &sdata->vif,
-@@ -545,7 +558,8 @@ static inline void drv_sta_pre_rcu_remov
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_sta_pre_rcu_remove(local, sdata, &sta->sta);
-       if (local->ops->sta_pre_rcu_remove)
-@@ -566,7 +580,8 @@ int drv_sta_state(struct ieee80211_local
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
-       if (local->ops->sta_state) {
-@@ -590,7 +605,8 @@ static inline void drv_sta_rc_update(str
-                                    struct ieee80211_sta *sta, u32 changed)
- {
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
-               (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-@@ -612,7 +628,8 @@ static inline int drv_conf_tx(struct iee
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_conf_tx(local, sdata, ac, params);
-       if (local->ops->conf_tx)
-@@ -629,7 +646,8 @@ static inline u64 drv_get_tsf(struct iee
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return ret;
-       trace_drv_get_tsf(local, sdata);
-       if (local->ops->get_tsf)
-@@ -644,7 +662,8 @@ static inline void drv_set_tsf(struct ie
- {
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_set_tsf(local, sdata, tsf);
-       if (local->ops->set_tsf)
-@@ -657,7 +676,8 @@ static inline void drv_reset_tsf(struct 
- {
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_reset_tsf(local, sdata);
-       if (local->ops->reset_tsf)
-@@ -689,7 +709,8 @@ static inline int drv_ampdu_action(struc
-       might_sleep();
-       sdata = get_bss_sdata(sdata);
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
-@@ -733,8 +754,8 @@ static inline void drv_flush(struct ieee
-       might_sleep();
--      if (sdata)
--              check_sdata_in_driver(sdata);
-+      if (sdata && !check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_flush(local, queues, drop);
-       if (local->ops->flush)
-@@ -854,7 +875,8 @@ static inline int drv_set_bitrate_mask(s
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_set_bitrate_mask(local, sdata, mask);
-       if (local->ops->set_bitrate_mask)
-@@ -869,7 +891,8 @@ static inline void drv_set_rekey_data(st
-                                     struct ieee80211_sub_if_data *sdata,
-                                     struct cfg80211_gtk_rekey_data *data)
- {
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_set_rekey_data(local, sdata, data);
-       if (local->ops->set_rekey_data)
-@@ -937,7 +960,8 @@ static inline void drv_mgd_prepare_tx(st
- {
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION);
-       trace_drv_mgd_prepare_tx(local, sdata);
-@@ -964,6 +988,9 @@ static inline int drv_add_chanctx(struct
- static inline void drv_remove_chanctx(struct ieee80211_local *local,
-                                     struct ieee80211_chanctx *ctx)
- {
-+      if (WARN_ON(!ctx->driver_present))
-+              return;
 +
-       trace_drv_remove_chanctx(local, ctx);
-       if (local->ops->remove_chanctx)
-               local->ops->remove_chanctx(&local->hw, &ctx->conf);
-@@ -989,7 +1016,8 @@ static inline int drv_assign_vif_chanctx
- {
-       int ret = 0;
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_assign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->assign_vif_chanctx) {
-@@ -1007,7 +1035,8 @@ static inline void drv_unassign_vif_chan
-                                           struct ieee80211_sub_if_data *sdata,
-                                           struct ieee80211_chanctx *ctx)
- {
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_unassign_vif_chanctx(local, sdata, ctx);
-       if (local->ops->unassign_vif_chanctx) {
-@@ -1024,7 +1053,8 @@ static inline int drv_start_ap(struct ie
- {
-       int ret = 0;
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
-       trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf);
-       if (local->ops->start_ap)
-@@ -1036,7 +1066,8 @@ static inline int drv_start_ap(struct ie
- static inline void drv_stop_ap(struct ieee80211_local *local,
-                              struct ieee80211_sub_if_data *sdata)
- {
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       trace_drv_stop_ap(local, sdata);
-       if (local->ops->stop_ap)
-@@ -1059,7 +1090,8 @@ drv_set_default_unicast_key(struct ieee8
-                           struct ieee80211_sub_if_data *sdata,
-                           int key_idx)
- {
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
-       WARN_ON_ONCE(key_idx < -1 || key_idx > 3);
-@@ -1101,7 +1133,8 @@ static inline int drv_join_ibss(struct i
-       int ret = 0;
++/* ethtool helper */
++void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
++
+ /* Logging, debugging and troubleshooting/diagnostic helpers. */
  
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return -EIO;
+ /* 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;
+ };
  
-       trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);
-       if (local->ops->join_ibss)
-@@ -1114,7 +1147,8 @@ static inline void drv_leave_ibss(struct
-                                 struct ieee80211_sub_if_data *sdata)
- {
-       might_sleep();
--      check_sdata_in_driver(sdata);
-+      if (!check_sdata_in_driver(sdata))
-+              return;
++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;
+ };
  
-       trace_drv_leave_ibss(local, sdata);
-       if (local->ops->leave_ibss)
---- 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 = (pos - presp->head);
-+              sdata->csa_counter_offset_beacon[0] = (pos - presp->head);
-               *pos++ = csa_settings->count;
-       }
+ struct probe_resp {
+       struct rcu_head rcu_head;
+       int len;
++      u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM];
+       u8 data[0];
+ };
  
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -754,9 +754,10 @@ struct ieee80211_sub_if_data {
+@@ -754,8 +767,6 @@ struct ieee80211_sub_if_data {
        struct mac80211_qos_map __rcu *qos_map;
  
        struct work_struct csa_finalize_work;
--      int csa_counter_offset_beacon;
--      int csa_counter_offset_presp;
-+      u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM];
-+      u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM];
+-      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 */
+       bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
        struct cfg80211_chan_def csa_chandef;
-       struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
-@@ -766,6 +767,7 @@ struct ieee80211_sub_if_data {
+@@ -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;
+-      u8 csa_current_counter;
  
        /* used to reconfigure hardware SM PS */
        struct work_struct recalc_smps;
-@@ -1462,6 +1464,7 @@ __ieee80211_request_sched_scan_start(str
- int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
-                                      struct cfg80211_sched_scan_request *req);
- int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
-+void ieee80211_sched_scan_end(struct ieee80211_local *local);
- void ieee80211_sched_scan_stopped_work(struct work_struct *work);
- /* off-channel helpers */
-@@ -1476,6 +1479,7 @@ void ieee80211_sw_roc_work(struct work_s
- void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
- /* channel switch handling */
-+bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local);
- void ieee80211_csa_finalize_work(struct work_struct *work);
- int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-                            struct cfg80211_csa_settings *params);
-@@ -1837,6 +1841,15 @@ int ieee80211_check_combinations(struct 
-                                u8 radar_detect);
- int ieee80211_max_num_channels(struct ieee80211_local *local);
-+/* TDLS */
-+int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
-+                      const u8 *peer, u8 action_code, u8 dialog_token,
-+                      u16 status_code, u32 peer_capability,
-+                      const u8 *extra_ies, size_t extra_ies_len);
-+int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
-+                      const u8 *peer, enum nl80211_tdls_operation oper);
-+
+@@ -1850,6 +1860,8 @@ int ieee80211_tdls_oper(struct wiphy *wi
+                       const u8 *peer, enum nl80211_tdls_operation oper);
++extern const struct ethtool_ops ieee80211_ethtool_ops;
 +
  #ifdef CPTCFG_MAC80211_NOINLINE
  #define debug_noinline noinline
  #else
 --- a/net/mac80211/iface.c
 +++ b/net/mac80211/iface.c
-@@ -838,8 +838,15 @@ static void ieee80211_do_stop(struct iee
-       cancel_work_sync(&sdata->recalc_smps);
-       sdata_lock(sdata);
-+      mutex_lock(&local->mtx);
-       sdata->vif.csa_active = false;
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-+                                      IEEE80211_MAX_QUEUE_MAP,
-+                                      IEEE80211_QUEUE_STOP_REASON_CSA);
-+      mutex_unlock(&local->mtx);
-       sdata_unlock(sdata);
-+
-       cancel_work_sync(&sdata->csa_finalize_work);
-       cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
---- a/net/mac80211/key.c
-+++ b/net/mac80211/key.c
-@@ -325,7 +325,8 @@ ieee80211_key_alloc(u32 cipher, int idx,
-       struct ieee80211_key *key;
-       int i, j, err;
--      BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
-+      if (WARN_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS))
-+              return ERR_PTR(-EINVAL);
-       key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
-       if (!key)
-@@ -481,8 +482,8 @@ int ieee80211_key_link(struct ieee80211_
-       int idx, ret;
-       bool pairwise;
--      BUG_ON(!sdata);
--      BUG_ON(!key);
-+      if (WARN_ON(!sdata || !key))
-+              return -EINVAL;
+@@ -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;
  
-       pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
-       idx = key->conf.keyidx;
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -956,6 +956,8 @@ int ieee80211_register_hw(struct ieee802
-       if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
-               local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
-+      local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
-+
-       result = wiphy_register(local->hw.wiphy);
-       if (result < 0)
-               goto fail_wiphy_register;
---- 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 = hdr_len + 6;
-+              sdata->csa_counter_offset_beacon[0] = hdr_len + 6;
-               *pos++ = csa->settings.count;
-               *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
-               *pos++ = 6;
---- a/net/mac80211/mesh_pathtbl.c
-+++ b/net/mac80211/mesh_pathtbl.c
-@@ -287,8 +287,10 @@ static void mesh_path_move_to_queue(stru
-       struct sk_buff_head failq;
-       unsigned long flags;
--      BUG_ON(gate_mpath == from_mpath);
--      BUG_ON(!gate_mpath->next_hop);
-+      if (WARN_ON(gate_mpath == from_mpath))
-+              return;
-+      if (WARN_ON(!gate_mpath->next_hop))
-+              return;
+       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
  
-       __skb_queue_head_init(&failq);
+@@ -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;
  
---- a/net/mac80211/mesh_sync.c
-+++ b/net/mac80211/mesh_sync.c
-@@ -171,7 +171,7 @@ static void mesh_sync_offset_adjust_tbtt
-       u8 cap;
+       sdata->noack_map = 0;
  
-       WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
--      BUG_ON(!rcu_read_lock_held());
-+      WARN_ON(!rcu_read_lock_held());
-       cap = beacon->meshconf->meshconf_cap;
+@@ -1721,6 +1723,8 @@ int ieee80211_if_add(struct ieee80211_lo
  
-       spin_lock_bh(&ifmsh->sync_offset_lock);
---- a/net/mac80211/mlme.c
-+++ b/net/mac80211/mlme.c
-@@ -975,16 +975,23 @@ static void ieee80211_chswitch_work(stru
-       /* XXX: shouldn't really modify cfg80211-owned data! */
-       ifmgd->associated->channel = sdata->csa_chandef.chan;
+               ndev->features |= local->hw.netdev_features;
  
-+      ieee80211_bss_info_change_notify(sdata, changed);
-+
-+      mutex_lock(&local->mtx);
-+      sdata->vif.csa_active = false;
-       /* XXX: wait for a beacon first? */
--      ieee80211_wake_queues_by_reason(&local->hw,
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-                                       IEEE80211_MAX_QUEUE_MAP,
-                                       IEEE80211_QUEUE_STOP_REASON_CSA);
-+      mutex_unlock(&local->mtx);
--      ieee80211_bss_info_change_notify(sdata, changed);
--
-- out:
--      sdata->vif.csa_active = false;
-       ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
-+
-+      ieee80211_sta_reset_beacon_monitor(sdata);
-+      ieee80211_sta_reset_conn_monitor(sdata);
++              netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
 +
-+out:
-       sdata_unlock(sdata);
- }
-@@ -1100,12 +1107,16 @@ ieee80211_sta_process_chanswitch(struct 
-       mutex_unlock(&local->chanctx_mtx);
+               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"
  
-       sdata->csa_chandef = csa_ie.chandef;
-+
-+      mutex_lock(&local->mtx);
-       sdata->vif.csa_active = true;
-+      sdata->csa_block_tx = csa_ie.mode;
--      if (csa_ie.mode)
-+      if (sdata->csa_block_tx)
-               ieee80211_stop_queues_by_reason(&local->hw,
--                              IEEE80211_MAX_QUEUE_MAP,
--                              IEEE80211_QUEUE_STOP_REASON_CSA);
-+                                      IEEE80211_MAX_QUEUE_MAP,
-+                                      IEEE80211_QUEUE_STOP_REASON_CSA);
-+      mutex_unlock(&local->mtx);
-       if (local->ops->channel_switch) {
-               /* use driver's channel switch callback */
-@@ -1817,6 +1828,12 @@ static void ieee80211_set_disassoc(struc
-       ifmgd->flags = 0;
-       mutex_lock(&local->mtx);
-       ieee80211_vif_release_channel(sdata);
-+
-+      sdata->vif.csa_active = false;
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-+                                      IEEE80211_MAX_QUEUE_MAP,
-+                                      IEEE80211_QUEUE_STOP_REASON_CSA);
-       mutex_unlock(&local->mtx);
+ /* 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;
  
-       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
-@@ -2045,6 +2062,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get)
+-              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 __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
+-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)
  {
-+      struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
-@@ -2058,10 +2076,14 @@ static void __ieee80211_disconnect(struc
-                              WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                              true, frame_buf);
-       ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
-+
-+      mutex_lock(&local->mtx);
-       sdata->vif.csa_active = false;
--      ieee80211_wake_queues_by_reason(&sdata->local->hw,
-+      if (!ieee80211_csa_needs_block_tx(local))
-+              ieee80211_wake_queues_by_reason(&local->hw,
-                                       IEEE80211_MAX_QUEUE_MAP,
-                                       IEEE80211_QUEUE_STOP_REASON_CSA);
-+      mutex_unlock(&local->mtx);
-       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                             IEEE80211_DEAUTH_FRAME_LEN);
-@@ -3546,6 +3568,9 @@ static void ieee80211_sta_bcn_mon_timer(
-       if (local->quiescing)
-               return;
-+      if (sdata->vif.csa_active)
-+              return;
-+
-       sdata->u.mgd.connection_loss = false;
-       ieee80211_queue_work(&sdata->local->hw,
-                            &sdata->u.mgd.beacon_connection_loss_work);
-@@ -3561,6 +3586,9 @@ static void ieee80211_sta_conn_mon_timer
-       if (local->quiescing)
-               return;
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
  
-+      if (sdata->vif.csa_active)
-+              return;
-+
-       ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
+@@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct 
+       strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
+               sizeof(info->bus_info));
  }
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -22,7 +22,7 @@
- #define MCS_NBITS (AVG_PKT_SIZE << 3)
- /* Number of symbols for a packet with (bps) bits per symbol */
--#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
-+#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps))
- /* Transmission time (nanoseconds) for a packet containing (syms) symbols */
- #define MCS_SYMBOL_TIME(sgi, syms)                                    \
-@@ -226,8 +226,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_s
-               nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
-       nsecs += minstrel_mcs_groups[group].duration[rate];
--      tp = 1000000 * ((prob * 1000) / nsecs);
-+      /* prob is scaled - see MINSTREL_FRAC above */
-+      tp = 1000000 * ((prob * 1000) / nsecs);
-       mr->cur_tp = MINSTREL_TRUNC(tp);
+-
+-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;
  }
  
---- a/net/mac80211/scan.c
-+++ b/net/mac80211/scan.c
-@@ -1076,12 +1076,8 @@ void ieee80211_sched_scan_results(struct
+-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
  }
- EXPORT_SYMBOL(ieee80211_sched_scan_results);
  
--void ieee80211_sched_scan_stopped_work(struct work_struct *work)
-+void ieee80211_sched_scan_end(struct ieee80211_local *local)
- {
--      struct ieee80211_local *local =
--              container_of(work, struct ieee80211_local,
--                           sched_scan_stopped_work);
+ 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);
+-}
 -
-       mutex_lock(&local->mtx);
+-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)
+ );
  
-       if (!rcu_access_pointer(local->sched_scan_sdata)) {
-@@ -1099,6 +1095,15 @@ void ieee80211_sched_scan_stopped_work(s
-       cfg80211_sched_scan_stopped(local->hw.wiphy);
- }
+-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)
+ );
  
-+void ieee80211_sched_scan_stopped_work(struct work_struct *work)
-+{
-+      struct ieee80211_local *local =
-+              container_of(work, struct ieee80211_local,
-+                           sched_scan_stopped_work);
-+
-+      ieee80211_sched_scan_end(local);
-+}
-+
- void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
- {
-       struct ieee80211_local *local = hw_to_local(hw);
+-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)
+ );
+-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)
+ );
+-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/tdls.c
-@@ -0,0 +1,325 @@
++++ b/net/mac80211/ethtool.c
+@@ -0,0 +1,244 @@
 +/*
-+ * mac80211 TDLS handling code
++ * mac80211 ethtool hooks for cfg80211
 + *
++ * Copied from cfg.c - originally
 + * Copyright 2006-2010        Johannes Berg <johannes@sipsolutions.net>
-+ * Copyright 2014, Intel Corporation
++ * Copyright 2014     Intel Corporation (Author: Johannes Berg)
 + *
 + * This file is GPLv2 as found in COPYING.
 + */
-+
-+#include <linux/ieee80211.h>
++#include <linux/types.h>
++#include <net/cfg80211.h>
 +#include "ieee80211_i.h"
++#include "sta_info.h"
++#include "driver-ops.h"
 +
-+static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
++static int ieee80211_set_ringparam(struct net_device *dev,
++                                 struct ethtool_ringparam *rp)
 +{
-+      u8 *pos = (void *)skb_put(skb, 7);
++      struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
 +
-+      *pos++ = WLAN_EID_EXT_CAPABILITY;
-+      *pos++ = 5; /* len */
-+      *pos++ = 0x0;
-+      *pos++ = 0x0;
-+      *pos++ = 0x0;
-+      *pos++ = 0x0;
-+      *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
++      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 u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
++static void ieee80211_get_ringparam(struct net_device *dev,
++                                  struct ethtool_ringparam *rp)
 +{
-+      struct ieee80211_local *local = sdata->local;
-+      u16 capab;
-+
-+      capab = 0;
-+      if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
-+              return capab;
++      struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
 +
-+      if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
-+              capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
-+      if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
-+              capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
++      memset(rp, 0, sizeof(*rp));
 +
-+      return capab;
++      drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending,
++                        &rp->rx_pending, &rp->rx_max_pending);
 +}
 +
-+static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, const u8 *src_addr,
-+                                     const u8 *peer, const u8 *bssid)
++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 ieee80211_tdls_lnkie *lnkid;
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      int rv = 0;
 +
-+      lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
++      if (sset == ETH_SS_STATS)
++              rv += STA_STATS_LEN;
 +
-+      lnkid->ie_type = WLAN_EID_LINK_ID;
-+      lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
++      rv += drv_get_et_sset_count(sdata, sset);
 +
-+      memcpy(lnkid->bssid, bssid, ETH_ALEN);
-+      memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
-+      memcpy(lnkid->resp_sta, peer, ETH_ALEN);
++      if (rv == 0)
++              return -EOPNOTSUPP;
++      return rv;
 +}
 +
-+static int
-+ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
-+                             const u8 *peer, u8 action_code, u8 dialog_token,
-+                             u16 status_code, struct sk_buff *skb)
++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);
-+      enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-+      struct ieee80211_tdls_data *tf;
++      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.
++       */
 +
-+      tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
++      mutex_lock(&local->sta_mtx);
 +
-+      memcpy(tf->da, peer, ETH_ALEN);
-+      memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
-+      tf->ether_type = cpu_to_be16(ETH_P_TDLS);
-+      tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
++      if (sdata->vif.type == NL80211_IFTYPE_STATION) {
++              sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
 +
-+      switch (action_code) {
-+      case WLAN_TDLS_SETUP_REQUEST:
-+              tf->category = WLAN_CATEGORY_TDLS;
-+              tf->action_code = WLAN_TDLS_SETUP_REQUEST;
++              if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
++                      goto do_survey;
 +
-+              skb_put(skb, sizeof(tf->u.setup_req));
-+              tf->u.setup_req.dialog_token = dialog_token;
-+              tf->u.setup_req.capability =
-+                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
++              sinfo.filled = 0;
++              sta_set_sinfo(sta, &sinfo);
 +
-+              ieee80211_add_srates_ie(sdata, skb, false, band);
-+              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-+              ieee80211_tdls_add_ext_capab(skb);
-+              break;
-+      case WLAN_TDLS_SETUP_RESPONSE:
-+              tf->category = WLAN_CATEGORY_TDLS;
-+              tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
++              i = 0;
++              ADD_STA_STATS(sta);
 +
-+              skb_put(skb, sizeof(tf->u.setup_resp));
-+              tf->u.setup_resp.status_code = cpu_to_le16(status_code);
-+              tf->u.setup_resp.dialog_token = dialog_token;
-+              tf->u.setup_resp.capability =
-+                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
++              data[i++] = sta->sta_state;
 +
-+              ieee80211_add_srates_ie(sdata, skb, false, band);
-+              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-+              ieee80211_tdls_add_ext_capab(skb);
-+              break;
-+      case WLAN_TDLS_SETUP_CONFIRM:
-+              tf->category = WLAN_CATEGORY_TDLS;
-+              tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
 +
-+              skb_put(skb, sizeof(tf->u.setup_cfm));
-+              tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
-+              tf->u.setup_cfm.dialog_token = dialog_token;
-+              break;
-+      case WLAN_TDLS_TEARDOWN:
-+              tf->category = WLAN_CATEGORY_TDLS;
-+              tf->action_code = WLAN_TDLS_TEARDOWN;
++              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++;
 +
-+              skb_put(skb, sizeof(tf->u.teardown));
-+              tf->u.teardown.reason_code = cpu_to_le16(status_code);
-+              break;
-+      case WLAN_TDLS_DISCOVERY_REQUEST:
-+              tf->category = WLAN_CATEGORY_TDLS;
-+              tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
++              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;
 +
-+              skb_put(skb, sizeof(tf->u.discover_req));
-+              tf->u.discover_req.dialog_token = dialog_token;
-+              break;
-+      default:
-+              return -EINVAL;
++                      sinfo.filled = 0;
++                      sta_set_sinfo(sta, &sinfo);
++                      i = 0;
++                      ADD_STA_STATS(sta);
++              }
 +      }
 +
-+      return 0;
-+}
++do_survey:
++      i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
++      /* Get survey stats for current channel */
++      survey.filled = 0;
 +
-+static int
-+ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
-+                         const u8 *peer, u8 action_code, u8 dialog_token,
-+                         u16 status_code, struct sk_buff *skb)
-+{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-+      struct ieee80211_mgmt *mgmt;
++      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();
 +
-+      mgmt = (void *)skb_put(skb, 24);
-+      memset(mgmt, 0, 24);
-+      memcpy(mgmt->da, peer, ETH_ALEN);
-+      memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
-+      memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
++      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;
 +
-+      mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-+                                        IEEE80211_STYPE_ACTION);
++      drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
++}
 +
-+      switch (action_code) {
-+      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-+              skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
-+              mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
-+              mgmt->u.action.u.tdls_discover_resp.action_code =
-+                      WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
-+              mgmt->u.action.u.tdls_discover_resp.dialog_token =
-+                      dialog_token;
-+              mgmt->u.action.u.tdls_discover_resp.capability =
-+                      cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
++static void ieee80211_get_strings(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;
 +
-+              ieee80211_add_srates_ie(sdata, skb, false, band);
-+              ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-+              ieee80211_tdls_add_ext_capab(skb);
-+              break;
-+      default:
-+              return -EINVAL;
++      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_get_regs_len(struct net_device *dev)
++{
 +      return 0;
 +}
 +
-+int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
-+                      const u8 *peer, u8 action_code, u8 dialog_token,
-+                      u16 status_code, u32 peer_capability,
-+                      const u8 *extra_ies, size_t extra_ies_len)
++static void ieee80211_get_regs(struct net_device *dev,
++                             struct ethtool_regs *regs,
++                             void *data)
 +{
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+      struct ieee80211_local *local = sdata->local;
-+      struct sk_buff *skb = NULL;
-+      bool send_direct;
-+      int ret;
++      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +
-+      if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
-+              return -ENOTSUPP;
-+
-+      /* make sure we are in managed mode, and associated */
-+      if (sdata->vif.type != NL80211_IFTYPE_STATION ||
-+          !sdata->u.mgd.associated)
-+              return -EINVAL;
-+
-+      tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
-+               action_code, peer);
++      regs->version = wdev->wiphy->hw_version;
++      regs->len = 0;
++}
 +
-+      skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-+                          max(sizeof(struct ieee80211_mgmt),
-+                              sizeof(struct ieee80211_tdls_data)) +
-+                          50 + /* supported rates */
-+                          7 + /* ext capab */
-+                          extra_ies_len +
-+                          sizeof(struct ieee80211_tdls_lnkie));
-+      if (!skb)
-+              return -ENOMEM;
-+
-+      skb_reserve(skb, local->hw.extra_tx_headroom);
-+
-+      switch (action_code) {
-+      case WLAN_TDLS_SETUP_REQUEST:
-+      case WLAN_TDLS_SETUP_RESPONSE:
-+      case WLAN_TDLS_SETUP_CONFIRM:
-+      case WLAN_TDLS_TEARDOWN:
-+      case WLAN_TDLS_DISCOVERY_REQUEST:
-+              ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
-+                                                   action_code, dialog_token,
-+                                                   status_code, skb);
-+              send_direct = false;
-+              break;
-+      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-+              ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
-+                                               dialog_token, status_code,
-+                                               skb);
-+              send_direct = true;
-+              break;
-+      default:
-+              ret = -ENOTSUPP;
-+              break;
-+      }
-+
-+      if (ret < 0)
-+              goto fail;
-+
-+      if (extra_ies_len)
-+              memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
-+
-+      /* the TDLS link IE is always added last */
-+      switch (action_code) {
-+      case WLAN_TDLS_SETUP_REQUEST:
-+      case WLAN_TDLS_SETUP_CONFIRM:
-+      case WLAN_TDLS_TEARDOWN:
-+      case WLAN_TDLS_DISCOVERY_REQUEST:
-+              /* we are the initiator */
-+              ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
-+                                         sdata->u.mgd.bssid);
-+              break;
-+      case WLAN_TDLS_SETUP_RESPONSE:
-+      case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-+              /* we are the responder */
-+              ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
-+                                         sdata->u.mgd.bssid);
-+              break;
-+      default:
-+              ret = -ENOTSUPP;
-+              goto fail;
-+      }
-+
-+      if (send_direct) {
-+              ieee80211_tx_skb(sdata, skb);
-+              return 0;
-+      }
-+
-+      /*
-+       * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
-+       * we should default to AC_VI.
-+       */
-+      switch (action_code) {
-+      case WLAN_TDLS_SETUP_REQUEST:
-+      case WLAN_TDLS_SETUP_RESPONSE:
-+              skb_set_queue_mapping(skb, IEEE80211_AC_BK);
-+              skb->priority = 2;
-+              break;
-+      default:
-+              skb_set_queue_mapping(skb, IEEE80211_AC_VI);
-+              skb->priority = 5;
-+              break;
-+      }
-+
-+      /* disable bottom halves when entering the Tx path */
-+      local_bh_disable();
-+      ret = ieee80211_subif_start_xmit(skb, dev);
-+      local_bh_enable();
-+
-+      return ret;
-+
-+fail:
-+      dev_kfree_skb(skb);
-+      return ret;
-+}
-+
-+int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
-+                      const u8 *peer, enum nl80211_tdls_operation oper)
-+{
-+      struct sta_info *sta;
-+      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+
-+      if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
-+              return -ENOTSUPP;
-+
-+      if (sdata->vif.type != NL80211_IFTYPE_STATION)
-+              return -EINVAL;
-+
-+      tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
-+
-+      switch (oper) {
-+      case NL80211_TDLS_ENABLE_LINK:
-+              rcu_read_lock();
-+              sta = sta_info_get(sdata, peer);
-+              if (!sta) {
-+                      rcu_read_unlock();
-+                      return -ENOLINK;
-+              }
-+
-+              set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
-+              rcu_read_unlock();
-+              break;
-+      case NL80211_TDLS_DISABLE_LINK:
-+              return sta_info_destroy_addr(sdata, peer);
-+      case NL80211_TDLS_TEARDOWN:
-+      case NL80211_TDLS_SETUP:
-+      case NL80211_TDLS_DISCOVERY_REQ:
-+              /* We don't support in-driver setup/teardown/discovery */
-+              return -ENOTSUPP;
-+      default:
-+              return -ENOTSUPP;
-+      }
-+
-+      return 0;
-+}
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -2330,7 +2330,8 @@ void ieee80211_tx_pending(unsigned long 
- /* functions for drivers to get certain frames */
- static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
--                                     struct ps_data *ps, struct sk_buff *skb)
-+                                     struct ps_data *ps, struct sk_buff *skb,
-+                                     bool is_template)
- {
-       u8 *pos, *tim;
-       int aid0 = 0;
-@@ -2343,11 +2344,12 @@ static void __ieee80211_beacon_add_tim(s
-                * checking byte-for-byte */
-               have_bits = !bitmap_empty((unsigned long *)ps->tim,
-                                         IEEE80211_MAX_AID+1);
--
--      if (ps->dtim_count == 0)
--              ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
--      else
--              ps->dtim_count--;
-+      if (!is_template) {
-+              if (ps->dtim_count == 0)
-+                      ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
-+              else
-+                      ps->dtim_count--;
-+      }
-       tim = pos = (u8 *) skb_put(skb, 6);
-       *pos++ = WLAN_EID_TIM;
-@@ -2393,7 +2395,8 @@ static void __ieee80211_beacon_add_tim(s
- }
- static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
--                                  struct ps_data *ps, struct sk_buff *skb)
-+                                  struct ps_data *ps, struct sk_buff *skb,
-+                                  bool is_template)
- {
-       struct ieee80211_local *local = sdata->local;
-@@ -2405,24 +2408,24 @@ static int ieee80211_beacon_add_tim(stru
-        * of the tim bitmap in mac80211 and the driver.
-        */
-       if (local->tim_in_locked_section) {
--              __ieee80211_beacon_add_tim(sdata, ps, skb);
-+              __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
-       } else {
-               spin_lock_bh(&local->tim_lock);
--              __ieee80211_beacon_add_tim(sdata, ps, skb);
-+              __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
-               spin_unlock_bh(&local->tim_lock);
-       }
-       return 0;
- }
--static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
--                               struct beacon_data *beacon)
-+static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata,
-+                            struct beacon_data *beacon)
- {
-       struct probe_resp *resp;
--      int counter_offset_beacon = sdata->csa_counter_offset_beacon;
--      int counter_offset_presp = sdata->csa_counter_offset_presp;
-       u8 *beacon_data;
-       size_t beacon_data_len;
-+      int i;
-+      u8 count = sdata->csa_current_counter;
-       switch (sdata->vif.type) {
-       case NL80211_IFTYPE_AP:
-@@ -2440,40 +2443,57 @@ static void ieee80211_update_csa(struct 
-       default:
-               return;
-       }
--      if (WARN_ON(counter_offset_beacon >= beacon_data_len))
--              return;
--      /* Warn if the driver did not check for/react to csa
--       * completeness.  A beacon with CSA counter set to 0 should
--       * never occur, because a counter of 1 means switch just
--       * before the next beacon.
--       */
--      if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
--              return;
-+      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]--;
-+                      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);
-+              if (sdata->vif.type == NL80211_IFTYPE_AP &&
-+                  counter_offset_presp) {
-+                      rcu_read_lock();
-+                      resp = rcu_dereference(sdata->u.ap.probe_resp);
--              /* if nl80211 accepted the offset, this should not happen. */
--              if (WARN_ON(!resp)) {
-+                      /* If nl80211 accepted the offset, this should
-+                       * not happen.
-+                       */
-+                      if (WARN_ON(!resp)) {
-+                              rcu_read_unlock();
-+                              return;
-+                      }
-+                      resp->data[counter_offset_presp] = count;
-                       rcu_read_unlock();
--                      return;
-               }
--              resp->data[counter_offset_presp]--;
--              rcu_read_unlock();
++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;
        }
- }
-+u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif)
-+{
-+      struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-+
-+      sdata->csa_current_counter--;
-+
-+      /* the counter should never reach 0 */
-+      WARN_ON(!sdata->csa_current_counter);
-+
-+      return sdata->csa_current_counter;
-+}
-+EXPORT_SYMBOL(ieee80211_csa_update_counter);
-+
- bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
- {
-       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-       struct beacon_data *beacon = NULL;
-       u8 *beacon_data;
-       size_t beacon_data_len;
--      int counter_beacon = sdata->csa_counter_offset_beacon;
-+      int counter_beacon = sdata->csa_counter_offset_beacon[0];
-       int ret = false;
-       if (!ieee80211_sdata_running(sdata))
-@@ -2523,9 +2543,11 @@ bool ieee80211_csa_is_complete(struct ie
- }
- EXPORT_SYMBOL(ieee80211_csa_is_complete);
--struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
--                                       struct ieee80211_vif *vif,
--                                       u16 *tim_offset, u16 *tim_length)
-+static struct sk_buff *
-+__ieee80211_beacon_get(struct ieee80211_hw *hw,
-+                     struct ieee80211_vif *vif,
-+                     struct ieee80211_mutable_offsets *offs,
-+                     bool is_template)
- {
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct sk_buff *skb = NULL;
-@@ -2534,6 +2556,7 @@ struct sk_buff *ieee80211_beacon_get_tim
-       enum ieee80211_band band;
-       struct ieee80211_tx_rate_control txrc;
-       struct ieee80211_chanctx_conf *chanctx_conf;
-+      int csa_off_base = 0;
-       rcu_read_lock();
-@@ -2543,18 +2566,20 @@ struct sk_buff *ieee80211_beacon_get_tim
-       if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
-               goto out;
--      if (tim_offset)
--              *tim_offset = 0;
--      if (tim_length)
--              *tim_length = 0;
-+      if (offs)
-+              memset(offs, 0, sizeof(*offs));
-       if (sdata->vif.type == NL80211_IFTYPE_AP) {
-               struct ieee80211_if_ap *ap = &sdata->u.ap;
-               struct beacon_data *beacon = rcu_dereference(ap->beacon);
-               if (beacon) {
--                      if (sdata->vif.csa_active)
--                              ieee80211_update_csa(sdata, beacon);
-+                      if (sdata->vif.csa_active) {
-+                              if (!is_template)
-+                                      ieee80211_csa_update_counter(vif);
-+
-+                              ieee80211_set_csa(sdata, beacon);
-+                      }
-                       /*
-                        * headroom, head length,
-@@ -2571,12 +2596,16 @@ struct sk_buff *ieee80211_beacon_get_tim
-                       memcpy(skb_put(skb, beacon->head_len), beacon->head,
-                              beacon->head_len);
--                      ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
-+                      ieee80211_beacon_add_tim(sdata, &ap->ps, skb,
-+                                               is_template);
-+
-+                      if (offs) {
-+                              offs->tim_offset = beacon->head_len;
-+                              offs->tim_length = skb->len - beacon->head_len;
--                      if (tim_offset)
--                              *tim_offset = beacon->head_len;
--                      if (tim_length)
--                              *tim_length = skb->len - beacon->head_len;
-+                              /* for AP the csa offsets are from tail */
-+                              csa_off_base = skb->len;
-+                      }
-                       if (beacon->tail)
-                               memcpy(skb_put(skb, beacon->tail_len),
-@@ -2591,9 +2620,12 @@ struct sk_buff *ieee80211_beacon_get_tim
-               if (!presp)
-                       goto out;
  
--              if (sdata->vif.csa_active)
--                      ieee80211_update_csa(sdata, presp);
-+              if (sdata->vif.csa_active) {
-+                      if (!is_template)
-+                              ieee80211_csa_update_counter(vif);
+@@ -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;
  
-+                      ieee80211_set_csa(sdata, presp);
-+              }
-               skb = dev_alloc_skb(local->tx_headroom + presp->head_len +
-                                   local->hw.extra_beacon_tailroom);
-@@ -2613,8 +2645,17 @@ struct sk_buff *ieee80211_beacon_get_tim
-               if (!bcn)
-                       goto out;
--              if (sdata->vif.csa_active)
--                      ieee80211_update_csa(sdata, bcn);
-+              if (sdata->vif.csa_active) {
-+                      if (!is_template)
-+                              /* TODO: For mesh csa_counter is in TU, so
-+                               * decrementing it by one isn't correct, but
-+                               * for now we leave it consistent with overall
-+                               * mac80211's behavior.
-+                               */
-+                              ieee80211_csa_update_counter(vif);
-+
-+                      ieee80211_set_csa(sdata, bcn);
-+              }
-               if (ifmsh->sync_ops)
-                       ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
-@@ -2628,13 +2669,33 @@ struct sk_buff *ieee80211_beacon_get_tim
-                       goto out;
-               skb_reserve(skb, local->tx_headroom);
-               memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len);
--              ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb);
-+              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;
-+              }
-+
-               memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len);
+       /* 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 {
-               WARN_ON(1);
-               goto out;
-       }
-+      /* CSA offsets */
-+      if (offs) {
-+              int i;
-+
-+              for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) {
-+                      u16 csa_off = sdata->csa_counter_offset_beacon[i];
-+
-+                      if (!csa_off)
-+                              continue;
-+
-+                      offs->csa_counter_offs[i] = csa_off_base + csa_off;
-+              }
-+      }
-+
-       band = chanctx_conf->def.chan->band;
-       info = IEEE80211_SKB_CB(skb);
-@@ -2665,6 +2726,32 @@ struct sk_buff *ieee80211_beacon_get_tim
-  out:
-       rcu_read_unlock();
-       return skb;
-+
-+}
-+
-+struct sk_buff *
-+ieee80211_beacon_get_template(struct ieee80211_hw *hw,
-+                            struct ieee80211_vif *vif,
-+                            struct ieee80211_mutable_offsets *offs)
-+{
-+      return __ieee80211_beacon_get(hw, vif, offs, true);
-+}
-+EXPORT_SYMBOL(ieee80211_beacon_get_template);
-+
-+struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
-+                                       struct ieee80211_vif *vif,
-+                                       u16 *tim_offset, u16 *tim_length)
-+{
-+      struct ieee80211_mutable_offsets offs = {};
-+      struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
-+
-+      if (tim_offset)
-+              *tim_offset = offs.tim_offset;
-+
-+      if (tim_length)
-+              *tim_length = offs.tim_length;
-+
-+      return bcn;
- }
- EXPORT_SYMBOL(ieee80211_beacon_get_tim);
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -1457,6 +1457,44 @@ void ieee80211_stop_device(struct ieee80
-       drv_stop(local);
- }
-+static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+      struct ieee80211_chanctx *ctx;
-+
-+      /*
-+       * We get here if during resume the device can't be restarted properly.
-+       * We might also get here if this happens during HW reset, which is a
-+       * slightly different situation and we need to drop all connections in
-+       * the latter case.
-+       *
-+       * Ask cfg80211 to turn off all interfaces, this will result in more
-+       * warnings but at least we'll then get into a clean stopped state.
-+       */
-+
-+      local->resuming = false;
-+      local->suspended = false;
-+      local->started = false;
-+
-+      /* scheduled scan clearly can't be running any more, but tell
-+       * cfg80211 and clear local state
-+       */
-+      ieee80211_sched_scan_end(local);
-+
-+      list_for_each_entry(sdata, &local->interfaces, list)
-+              sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
-+
-+      /* Mark channel contexts as not being in the driver any more to avoid
-+       * removing them from the driver during the shutdown process...
-+       */
-+      mutex_lock(&local->chanctx_mtx);
-+      list_for_each_entry(ctx, &local->chanctx_list, list)
-+              ctx->driver_present = false;
-+      mutex_unlock(&local->chanctx_mtx);
-+
-+      cfg80211_shutdown_all_interfaces(local->hw.wiphy);
-+}
-+
- static void ieee80211_assign_chanctx(struct ieee80211_local *local,
-                                    struct ieee80211_sub_if_data *sdata)
- {
-@@ -1520,9 +1558,11 @@ int ieee80211_reconfig(struct ieee80211_
-        */
-       res = drv_start(local);
-       if (res) {
--              WARN(local->suspended, "Hardware became unavailable "
--                   "upon resume. This could be a software issue "
--                   "prior to suspend or a hardware issue.\n");
-+              if (local->suspended)
-+                      WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
-+              else
-+                      WARN(1, "Hardware became unavailable during restart.\n");
-+              ieee80211_handle_reconfig_failure(local);
-               return res;
+               dfs_cac = $8
        }
+@@ -114,7 +104,7 @@ function parse_reg_rule()
  
---- a/net/wireless/ap.c
-+++ b/net/wireless/ap.c
-@@ -6,8 +6,8 @@
- #include "rdev-ops.h"
--static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
--                            struct net_device *dev, bool notify)
-+int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
-+                     struct net_device *dev, bool notify)
- {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       int err;
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -370,8 +370,8 @@ int cfg80211_chandef_dfs_required(struct
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_WDS:
-       case NL80211_IFTYPE_P2P_DEVICE:
--      case NL80211_IFTYPE_UNSPECIFIED:
-               break;
-+      case NL80211_IFTYPE_UNSPECIFIED:
-       case NUM_NL80211_IFTYPES:
-               WARN_ON(1);
-       }
-@@ -796,8 +796,7 @@ bool cfg80211_reg_can_beacon(struct wiph
-           !cfg80211_go_permissive_chan(rdev, chandef->chan))
-               prohibited_flags |= IEEE80211_CHAN_NO_IR;
--      if (cfg80211_chandef_dfs_required(wiphy, chandef,
--                                        NL80211_IFTYPE_UNSPECIFIED) > 0 &&
-+      if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
-           cfg80211_chandef_dfs_available(wiphy, chandef)) {
-               /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
-               prohibited_flags = IEEE80211_CHAN_DISABLED;
---- a/net/wireless/core.c
-+++ b/net/wireless/core.c
-@@ -210,15 +210,12 @@ void cfg80211_stop_p2p_device(struct cfg
        }
+       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++
  }
  
--static int cfg80211_rfkill_set_block(void *data, bool blocked)
-+void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
- {
--      struct cfg80211_registered_device *rdev = data;
-+      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-       struct wireless_dev *wdev;
+--- 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;
  
--      if (!blocked)
--              return 0;
--
--      rtnl_lock();
-+      ASSERT_RTNL();
+       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);
  
-       list_for_each_entry(wdev, &rdev->wdev_list, list) {
-               if (wdev->netdev) {
-@@ -234,7 +231,18 @@ static int cfg80211_rfkill_set_block(voi
-                       break;
-               }
-       }
-+}
-+EXPORT_SYMBOL_GPL(cfg80211_shutdown_all_interfaces);
+       if (ret >= 0)
+@@ -62,8 +61,7 @@ static ssize_t ieee80211_if_write(
  
-+static int cfg80211_rfkill_set_block(void *data, bool blocked)
-+{
-+      struct cfg80211_registered_device *rdev = data;
-+
-+      if (!blocked)
-+              return 0;
-+
-+      rtnl_lock();
-+      cfg80211_shutdown_all_interfaces(&rdev->wiphy);
-       rtnl_unlock();
-       return 0;
-@@ -401,6 +409,8 @@ struct wiphy *wiphy_new(const struct cfg
-       rdev->wiphy.rts_threshold = (u32) -1;
-       rdev->wiphy.coverage_class = 0;
-+      rdev->wiphy.max_num_csa_counters = 1;
-+
-       return &rdev->wiphy;
- }
- EXPORT_SYMBOL(wiphy_new);
-@@ -697,7 +707,7 @@ void wiphy_unregister(struct wiphy *wiph
+       ret = -ENODEV;
        rtnl_lock();
-       rdev->wiphy.registered = false;
--      BUG_ON(!list_empty(&rdev->wdev_list));
-+      WARN_ON(!list_empty(&rdev->wdev_list));
-       /*
-        * First remove the hardware from everywhere, this makes
-@@ -799,23 +809,23 @@ void cfg80211_update_iface_num(struct cf
-               rdev->num_running_monitor_ifaces += num;
- }
--void cfg80211_leave(struct cfg80211_registered_device *rdev,
--                  struct wireless_dev *wdev)
-+void __cfg80211_leave(struct cfg80211_registered_device *rdev,
-+                    struct wireless_dev *wdev)
- {
-       struct net_device *dev = wdev->netdev;
-       ASSERT_RTNL();
-+      ASSERT_WDEV_LOCK(wdev);
-       switch (wdev->iftype) {
-       case NL80211_IFTYPE_ADHOC:
--              cfg80211_leave_ibss(rdev, dev, true);
-+              __cfg80211_leave_ibss(rdev, dev, true);
-               break;
-       case NL80211_IFTYPE_P2P_CLIENT:
-       case NL80211_IFTYPE_STATION:
-               if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
-                       __cfg80211_stop_sched_scan(rdev, false);
--              wdev_lock(wdev);
- #ifdef CPTCFG_CFG80211_WEXT
-               kfree(wdev->wext.ie);
-               wdev->wext.ie = NULL;
-@@ -824,20 +834,49 @@ void cfg80211_leave(struct cfg80211_regi
- #endif
-               cfg80211_disconnect(rdev, dev,
-                                   WLAN_REASON_DEAUTH_LEAVING, true);
--              wdev_unlock(wdev);
-               break;
-       case NL80211_IFTYPE_MESH_POINT:
--              cfg80211_leave_mesh(rdev, dev);
-+              __cfg80211_leave_mesh(rdev, dev);
-               break;
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_P2P_GO:
--              cfg80211_stop_ap(rdev, dev, true);
-+              __cfg80211_stop_ap(rdev, dev, true);
-               break;
-       default:
-               break;
-       }
- }
-+void cfg80211_leave(struct cfg80211_registered_device *rdev,
-+                  struct wireless_dev *wdev)
-+{
-+      wdev_lock(wdev);
-+      __cfg80211_leave(rdev, wdev);
-+      wdev_unlock(wdev);
-+}
-+
-+void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
-+                       gfp_t gfp)
-+{
-+      struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-+      struct cfg80211_event *ev;
-+      unsigned long flags;
-+
-+      trace_cfg80211_stop_iface(wiphy, wdev);
-+
-+      ev = kzalloc(sizeof(*ev), gfp);
-+      if (!ev)
-+              return;
-+
-+      ev->type = EVENT_STOPPED;
-+
-+      spin_lock_irqsave(&wdev->event_lock, flags);
-+      list_add_tail(&ev->list, &wdev->event_list);
-+      spin_unlock_irqrestore(&wdev->event_lock, flags);
-+      queue_work(cfg80211_wq, &rdev->event_work);
-+}
-+EXPORT_SYMBOL(cfg80211_stop_iface);
-+
- static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
-                                        unsigned long state, void *ptr)
- {
---- a/net/wireless/core.h
-+++ b/net/wireless/core.h
-@@ -185,6 +185,7 @@ enum cfg80211_event_type {
-       EVENT_ROAMED,
-       EVENT_DISCONNECTED,
-       EVENT_IBSS_JOINED,
-+      EVENT_STOPPED,
- };
- struct cfg80211_event {
-@@ -281,6 +282,8 @@ int cfg80211_join_mesh(struct cfg80211_r
-                      struct net_device *dev,
-                      struct mesh_setup *setup,
-                      const struct mesh_config *conf);
-+int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
-+                        struct net_device *dev);
- int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
-                       struct net_device *dev);
- int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
-@@ -288,6 +291,8 @@ int cfg80211_set_mesh_channel(struct cfg
-                             struct cfg80211_chan_def *chandef);
- /* AP */
-+int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
-+                     struct net_device *dev, bool notify);
- int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
-                    struct net_device *dev, bool notify);
-@@ -441,6 +446,8 @@ int cfg80211_validate_beacon_int(struct 
- void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
-                              enum nl80211_iftype iftype, int num);
-+void __cfg80211_leave(struct cfg80211_registered_device *rdev,
-+                    struct wireless_dev *wdev);
- void cfg80211_leave(struct cfg80211_registered_device *rdev,
-                   struct wireless_dev *wdev);
---- a/net/wireless/ibss.c
-+++ b/net/wireless/ibss.c
-@@ -420,8 +420,8 @@ int cfg80211_ibss_wext_siwessid(struct n
-       if (len > 0 && ssid[len - 1] == '\0')
-               len--;
-+      memcpy(wdev->ssid, ssid, len);
-       wdev->wext.ibss.ssid = wdev->ssid;
--      memcpy(wdev->wext.ibss.ssid, ssid, len);
-       wdev->wext.ibss.ssid_len = len;
-       wdev_lock(wdev);
---- a/net/wireless/mesh.c
-+++ b/net/wireless/mesh.c
-@@ -238,8 +238,8 @@ int cfg80211_set_mesh_channel(struct cfg
-       return 0;
- }
--static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
--                               struct net_device *dev)
-+int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
-+                        struct net_device *dev)
- {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       int err;
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -371,8 +371,8 @@ static const struct nla_policy nl80211_p
-       [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
-       [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
-       [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
--      [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
--      [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
-+      [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY },
-+      [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY },
-       [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
-       [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
-       [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
-@@ -386,6 +386,7 @@ static const struct nla_policy nl80211_p
-       [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
-       [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
-       [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
-+      [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
- };
- /* policy for the key attributes */
-@@ -970,8 +971,10 @@ static int nl80211_put_iface_combination
-                               c->max_interfaces))
-                       goto nla_put_failure;
-               if (large &&
--                  nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
--                              c->radar_detect_widths))
-+                  (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
-+                              c->radar_detect_widths) ||
-+                   nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
-+                              c->radar_detect_regions)))
-                       goto nla_put_failure;
-               nla_nest_end(msg, nl_combi);
-@@ -1667,6 +1670,13 @@ static int nl80211_send_wiphy(struct cfg
-                       }
-                       nla_nest_end(msg, nested);
-               }
-+              state->split_start++;
-+              break;
-+      case 12:
-+              if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH &&
-+                  nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS,
-+                             rdev->wiphy.max_num_csa_counters))
-+                      goto nla_put_failure;
-               /* done */
-               state->split_start = 0;
-@@ -5825,7 +5835,7 @@ static int nl80211_start_radar_detection
-               return -EBUSY;
-       err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
--                                          NL80211_IFTYPE_UNSPECIFIED);
-+                                          wdev->iftype);
-       if (err < 0)
-               return err;
-@@ -5866,6 +5876,7 @@ static int nl80211_channel_switch(struct
-       u8 radar_detect_width = 0;
-       int err;
-       bool need_new_beacon = false;
-+      int len, i;
-       if (!rdev->ops->channel_switch ||
-           !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
-@@ -5924,26 +5935,55 @@ static int nl80211_channel_switch(struct
-       if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON])
-               return -EINVAL;
--      params.counter_offset_beacon =
--              nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
--      if (params.counter_offset_beacon >= params.beacon_csa.tail_len)
-+      len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
-+      if (!len || (len % sizeof(u16)))
-               return -EINVAL;
--      /* sanity check - counters should be the same */
--      if (params.beacon_csa.tail[params.counter_offset_beacon] !=
--          params.count)
-+      params.n_counter_offsets_beacon = len / sizeof(u16);
-+      if (rdev->wiphy.max_num_csa_counters &&
-+          (params.n_counter_offsets_beacon >
-+           rdev->wiphy.max_num_csa_counters))
-               return -EINVAL;
-+      params.counter_offsets_beacon =
-+              nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]);
-+
-+      /* sanity checks - counters should fit and be the same */
-+      for (i = 0; i < params.n_counter_offsets_beacon; i++) {
-+              u16 offset = params.counter_offsets_beacon[i];
-+
-+              if (offset >= params.beacon_csa.tail_len)
-+                      return -EINVAL;
-+
-+              if (params.beacon_csa.tail[offset] != params.count)
-+                      return -EINVAL;
-+      }
-+
-       if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) {
--              params.counter_offset_presp =
--                      nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
--              if (params.counter_offset_presp >=
--                  params.beacon_csa.probe_resp_len)
-+              len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
-+              if (!len || (len % sizeof(u16)))
-                       return -EINVAL;
--              if (params.beacon_csa.probe_resp[params.counter_offset_presp] !=
--                  params.count)
-+              params.n_counter_offsets_presp = len / sizeof(u16);
-+              if (rdev->wiphy.max_num_csa_counters &&
-+                  (params.n_counter_offsets_beacon >
-+                   rdev->wiphy.max_num_csa_counters))
-                       return -EINVAL;
-+
-+              params.counter_offsets_presp =
-+                      nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]);
-+
-+              /* sanity checks - counters should fit and be the same */
-+              for (i = 0; i < params.n_counter_offsets_presp; i++) {
-+                      u16 offset = params.counter_offsets_presp[i];
-+
-+                      if (offset >= params.beacon_csa.probe_resp_len)
-+                              return -EINVAL;
-+
-+                      if (params.beacon_csa.probe_resp[offset] !=
-+                          params.count)
-+                              return -EINVAL;
-+              }
-       }
- skip_beacons:
-@@ -7793,6 +7833,27 @@ static int nl80211_tx_mgmt(struct sk_buf
-       if (!chandef.chan && params.offchan)
-               return -EINVAL;
-+      params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
-+      params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
-+
-+      if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
-+              int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
-+              int i;
-+
-+              if (len % sizeof(u16))
-+                      return -EINVAL;
-+
-+              params.n_csa_offsets = len / sizeof(u16);
-+              params.csa_offsets =
-+                      nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
-+
-+              /* check that all the offsets fit the frame */
-+              for (i = 0; i < params.n_csa_offsets; i++) {
-+                      if (params.csa_offsets[i] >= params.len)
-+                              return -EINVAL;
-+              }
-+      }
-+
-       if (!params.dont_wait_for_ack) {
-               msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-               if (!msg)
-@@ -7807,8 +7868,6 @@ static int nl80211_tx_mgmt(struct sk_buf
-               }
-       }
--      params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
--      params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
-       params.chan = chandef.chan;
-       err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
-       if (err)
-@@ -8507,6 +8566,8 @@ static int nl80211_set_wowlan(struct sk_
-               nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
-                                   rem) {
-+                      u8 *mask_pat;
-+
-                       nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
-                                 nla_len(pat), NULL);
-                       err = -EINVAL;
-@@ -8530,19 +8591,18 @@ static int nl80211_set_wowlan(struct sk_
-                               goto error;
-                       new_triggers.patterns[i].pkt_offset = pkt_offset;
--                      new_triggers.patterns[i].mask =
--                              kmalloc(mask_len + pat_len, GFP_KERNEL);
--                      if (!new_triggers.patterns[i].mask) {
-+                      mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
-+                      if (!mask_pat) {
-                               err = -ENOMEM;
-                               goto error;
-                       }
--                      new_triggers.patterns[i].pattern =
--                              new_triggers.patterns[i].mask + mask_len;
--                      memcpy(new_triggers.patterns[i].mask,
--                             nla_data(pat_tb[NL80211_PKTPAT_MASK]),
-+                      new_triggers.patterns[i].mask = mask_pat;
-+                      memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
-                              mask_len);
-+                      mask_pat += mask_len;
-+                      new_triggers.patterns[i].pattern = mask_pat;
-                       new_triggers.patterns[i].pattern_len = pat_len;
--                      memcpy(new_triggers.patterns[i].pattern,
-+                      memcpy(mask_pat,
-                              nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
-                              pat_len);
-                       i++;
-@@ -8735,6 +8795,8 @@ static int nl80211_parse_coalesce_rule(s
-       nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
-                           rem) {
-+              u8 *mask_pat;
-+
-               nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
-                         nla_len(pat), NULL);
-               if (!pat_tb[NL80211_PKTPAT_MASK] ||
-@@ -8756,17 +8818,19 @@ static int nl80211_parse_coalesce_rule(s
-                       return -EINVAL;
-               new_rule->patterns[i].pkt_offset = pkt_offset;
--              new_rule->patterns[i].mask =
--                      kmalloc(mask_len + pat_len, GFP_KERNEL);
--              if (!new_rule->patterns[i].mask)
-+              mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL);
-+              if (!mask_pat)
-                       return -ENOMEM;
--              new_rule->patterns[i].pattern =
--                      new_rule->patterns[i].mask + mask_len;
--              memcpy(new_rule->patterns[i].mask,
--                     nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len);
-+
-+              new_rule->patterns[i].mask = mask_pat;
-+              memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]),
-+                     mask_len);
-+
-+              mask_pat += mask_len;
-+              new_rule->patterns[i].pattern = mask_pat;
-               new_rule->patterns[i].pattern_len = pat_len;
--              memcpy(new_rule->patterns[i].pattern,
--                     nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len);
-+              memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]),
-+                     pat_len);
-               i++;
-       }
---- a/net/wireless/sme.c
-+++ b/net/wireless/sme.c
-@@ -149,7 +149,8 @@ static int cfg80211_conn_do_work(struct 
-       case CFG80211_CONN_SCAN_AGAIN:
-               return cfg80211_conn_scan(wdev);
-       case CFG80211_CONN_AUTHENTICATE_NEXT:
--              BUG_ON(!rdev->ops->auth);
-+              if (WARN_ON(!rdev->ops->auth))
-+                      return -EOPNOTSUPP;
-               wdev->conn->state = CFG80211_CONN_AUTHENTICATING;
-               return cfg80211_mlme_auth(rdev, wdev->netdev,
-                                         params->channel, params->auth_type,
-@@ -161,7 +162,8 @@ static int cfg80211_conn_do_work(struct 
-       case CFG80211_CONN_AUTH_FAILED:
-               return -ENOTCONN;
-       case CFG80211_CONN_ASSOCIATE_NEXT:
--              BUG_ON(!rdev->ops->assoc);
-+              if (WARN_ON(!rdev->ops->assoc))
-+                      return -EOPNOTSUPP;
-               wdev->conn->state = CFG80211_CONN_ASSOCIATING;
-               if (wdev->conn->prev_bssid_valid)
-                       req.prev_bssid = wdev->conn->prev_bssid;
-@@ -877,7 +879,7 @@ void __cfg80211_disconnected(struct net_
- }
- void cfg80211_disconnected(struct net_device *dev, u16 reason,
--                         u8 *ie, size_t ie_len, gfp_t gfp)
-+                         const u8 *ie, size_t ie_len, gfp_t gfp)
- {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
---- a/net/wireless/trace.h
-+++ b/net/wireless/trace.h
-@@ -1876,29 +1876,33 @@ TRACE_EVENT(rdev_channel_switch,
-               WIPHY_ENTRY
-               NETDEV_ENTRY
-               CHAN_DEF_ENTRY
--              __field(u16, counter_offset_beacon)
--              __field(u16, counter_offset_presp)
-               __field(bool, radar_required)
-               __field(bool, block_tx)
-               __field(u8, count)
-+              __dynamic_array(u16, bcn_ofs, params->n_counter_offsets_beacon)
-+              __dynamic_array(u16, pres_ofs, params->n_counter_offsets_presp)
-       ),
-       TP_fast_assign(
-               WIPHY_ASSIGN;
-               NETDEV_ASSIGN;
-               CHAN_DEF_ASSIGN(&params->chandef);
--              __entry->counter_offset_beacon = params->counter_offset_beacon;
--              __entry->counter_offset_presp = params->counter_offset_presp;
-               __entry->radar_required = params->radar_required;
-               __entry->block_tx = params->block_tx;
-               __entry->count = params->count;
-+              memcpy(__get_dynamic_array(bcn_ofs),
-+                     params->counter_offsets_beacon,
-+                     params->n_counter_offsets_beacon * sizeof(u16));
-+
-+              /* probe response offsets are optional */
-+              if (params->n_counter_offsets_presp)
-+                      memcpy(__get_dynamic_array(pres_ofs),
-+                             params->counter_offsets_presp,
-+                             params->n_counter_offsets_presp * sizeof(u16));
-       ),
-       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
--                ", block_tx: %d, count: %u, radar_required: %d"
--                ", counter offsets (beacon/presp): %u/%u",
-+                ", block_tx: %d, count: %u, radar_required: %d",
-                 WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
--                __entry->block_tx, __entry->count, __entry->radar_required,
--                __entry->counter_offset_beacon,
--                __entry->counter_offset_presp)
-+                __entry->block_tx, __entry->count, __entry->radar_required)
- );
- TRACE_EVENT(rdev_set_qos_map,
-@@ -2636,6 +2640,21 @@ TRACE_EVENT(cfg80211_ft_event,
-                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
- );
-+TRACE_EVENT(cfg80211_stop_iface,
-+      TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
-+      TP_ARGS(wiphy, wdev),
-+      TP_STRUCT__entry(
-+              WIPHY_ENTRY
-+              WDEV_ENTRY
-+      ),
-+      TP_fast_assign(
-+              WIPHY_ASSIGN;
-+              WDEV_ASSIGN;
-+      ),
-+      TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
-+                WIPHY_PR_ARG, WDEV_PR_ARG)
-+);
-+
- #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
- #undef TRACE_INCLUDE_PATH
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -476,7 +476,8 @@ int ieee80211_data_to_8023(struct sk_buf
- EXPORT_SYMBOL(ieee80211_data_to_8023);
- int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
--                           enum nl80211_iftype iftype, u8 *bssid, bool qos)
-+                           enum nl80211_iftype iftype,
-+                           const u8 *bssid, bool qos)
- {
-       struct ieee80211_hdr hdr;
-       u16 hdrlen, ethertype;
-@@ -839,6 +840,9 @@ void cfg80211_process_wdev_events(struct
-                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
-                                              ev->ij.channel);
-                       break;
-+              case EVENT_STOPPED:
-+                      __cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
-+                      break;
-               }
-               wdev_unlock(wdev);
-@@ -1271,10 +1275,20 @@ int cfg80211_iter_combinations(struct wi
-                                           void *data),
-                              void *data)
- {
-+      const struct ieee80211_regdomain *regdom;
-+      enum nl80211_dfs_regions region = 0;
-       int i, j, iftype;
-       int num_interfaces = 0;
-       u32 used_iftypes = 0;
-+      if (radar_detect) {
-+              rcu_read_lock();
-+              regdom = rcu_dereference(cfg80211_regdomain);
-+              if (regdom)
-+                      region = regdom->dfs_region;
-+              rcu_read_unlock();
-+      }
-+
-       for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
-               num_interfaces += iftype_num[iftype];
-               if (iftype_num[iftype] > 0 &&
-@@ -1315,6 +1329,10 @@ int cfg80211_iter_combinations(struct wi
-               if (radar_detect != (c->radar_detect_widths & radar_detect))
-                       goto cont;
-+              if (radar_detect && c->radar_detect_regions &&
-+                  !(c->radar_detect_regions & BIT(region)))
-+                      goto cont;
-+
-               /* Finally check that all iftypes that we're currently
-                * using are actually part of this combination. If they
-                * aren't then we can't use this combination and have
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -444,6 +444,8 @@ void ath9k_tasklet(unsigned long data)
-       ath9k_ps_wakeup(sc);
-       spin_lock(&sc->sc_pcu_lock);
-+      sc->intrstatus = 0;
-+
-       if (status & ATH9K_INT_FATAL) {
-               type = RESET_TYPE_FATAL_INT;
-               ath9k_queue_reset(sc, type);
-@@ -512,10 +514,12 @@ void ath9k_tasklet(unsigned long data)
-       if (status & rxmask) {
-               /* Check for high priority Rx first */
-               if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
--                  (status & ATH9K_INT_RXHP))
--                      ath_rx_tasklet(sc, 0, true);
-+                  (status & ATH9K_INT_RXHP) &&
-+                  ath_rx_tasklet(sc, 0, true))
-+                      sc->intrstatus |= ATH9K_INT_RXHP;
--              ath_rx_tasklet(sc, 0, false);
-+              if (ath_rx_tasklet(sc, 0, false))
-+                      sc->intrstatus |= ATH9K_INT_RXLP;
-       }
-       if (status & ATH9K_INT_TX) {
-@@ -543,6 +547,9 @@ void ath9k_tasklet(unsigned long data)
-       /* re-enable hardware interrupt */
-       ath9k_hw_enable_interrupts(ah);
-+      if (sc->intrstatus)
-+              tasklet_schedule(&sc->intr_tq);
-+
- out:
-       spin_unlock(&sc->sc_pcu_lock);
-       ath9k_ps_restore(sc);
-@@ -609,7 +616,7 @@ irqreturn_t ath_isr(int irq, void *dev)
-               return IRQ_NONE;
-       /* Cache the status */
--      sc->intrstatus = status;
-+      sc->intrstatus |= status;
-       if (status & SCHED_INTR)
-               sched = true;
---- 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;
- }
--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)
- {
-       if (sc->rx.buf_hold)
--              ath_rx_buf_link(sc, sc->rx.buf_hold);
-+              ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
-       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);
-       }
-       /* 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);
-               }
-               if (!budget--)
-@@ -1135,5 +1137,5 @@ requeue:
-               ath9k_hw_set_interrupts(ah);
-       }
+-      if (sdata->dev->reg_state == NETREG_REGISTERED)
+-              ret = (*write)(sdata, buf, count);
++      ret = (*write)(sdata, buf, count);
+       rtnl_unlock();
  
--      return 0;
-+      return !budget;
- }
+       return ret;