X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=blobdiff_plain;f=package%2Fmac80211%2Fpatches%2F300-pending_work.patch;h=fc1ff107445c7eff4fc6e73ec9074b28c5356249;hp=127e77795008b9925c7f3b4e9db7a655eb50a2de;hb=refs%2Fheads%2Fattitude_adjustment;hpb=a18219918adda578ffcfe23c7929575525a1dbb5 diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index 127e777950..fc1ff10744 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/package/mac80211/patches/300-pending_work.patch @@ -1,1189 +1,3293 @@ ---- a/net/mac80211/agg-rx.c -+++ b/net/mac80211/agg-rx.c -@@ -204,6 +204,8 @@ static void ieee80211_send_addba_resp(st - memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); - else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); -+ else if (sdata->vif.type == NL80211_IFTYPE_WDS) -+ memcpy(mgmt->bssid, da, ETH_ALEN); - - mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_ACTION); ---- a/net/mac80211/agg-tx.c -+++ b/net/mac80211/agg-tx.c -@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request - memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - if (sdata->vif.type == NL80211_IFTYPE_AP || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN || -- sdata->vif.type == NL80211_IFTYPE_MESH_POINT) -+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT || -+ sdata->vif.type == NL80211_IFTYPE_WDS) - memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); -@@ -527,6 +528,7 @@ int ieee80211_start_tx_ba_session(struct - sdata->vif.type != NL80211_IFTYPE_MESH_POINT && - sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_AP && -+ sdata->vif.type != NL80211_IFTYPE_WDS && - sdata->vif.type != NL80211_IFTYPE_ADHOC) - return -EINVAL; +commit 11f17631d9bf2a9e910dac7d09ba4581f5693831 +Author: Felix Fietkau +Date: Tue Sep 9 09:48:30 2014 +0200 + + ath9k_hw: fix PLL clock initialization for newer SoC + + On AR934x and newer SoC devices, the layout of the AR_RTC_PLL_CONTROL + register changed. This currently breaks at least 5/10 MHz operation. + AR933x uses the old layout. + + It might also have been causing other stability issues because of the + different location of the PLL_BYPASS bit which needs to be set during + PLL clock initialization. + + This patch also removes more instances of hardcoded register values in + favor of properly computed ones with the PLL_BYPASS bit added. + + Reported-by: Lorenzo Bianconi + Signed-off-by: Felix Fietkau + +commit 0fecedddd4a0945873db1bd230ec6a168b3cc4fe +Author: Felix Fietkau +Date: Mon Sep 8 18:35:08 2014 +0200 + + ath9k_hw: reduce ANI spur immunity setting on HT40 extension channel + + The cycpwr_thr1 value needs to be lower on the extension channel than on + the control channel, similar to how the register settings are programmed + in the initvals. + + Also drop the unnecessary check for HT40 - this register can always be + written. This patch has been reported to improve HT40 stability and + throughput in some environments. + + Signed-off-by: Felix Fietkau + +commit 30d7434ccb853b96de698a040888fa4dacd0cc19 +Author: Felix Fietkau +Date: Mon Sep 8 18:31:26 2014 +0200 + + Revert "ath9k_hw: reduce ANI firstep range for older chips" + + This reverts commit 09efc56345be4146ab9fc87a55c837ed5d6ea1ab + + I've received reports that this change is decreasing throughput in some + rare conditions on an AR9280 based device + + Cc: stable@vger.kernel.org + Signed-off-by: Felix Fietkau + +commit 15ed54948f508ad1baad79c30050e2d29a21696d +Author: Felix Fietkau +Date: Fri Jul 25 16:18:03 2014 +0200 + + mac80211: fix smps mode check for AP_VLAN + + In ieee80211_sta_ps_deliver_wakeup, sdata->smps_mode is checked. This is + initialized only for the base AP interface, not the individual VLANs. + + Signed-off-by: Felix Fietkau + +commit bc74ad816bba291359ae46301173ea744bdda9d2 +Author: Felix Fietkau +Date: Fri Jul 25 16:15:44 2014 +0200 + + mac80211: ignore AP_VLAN in ieee80211_recalc_chanctx_chantype + + When bringing down the AP, a WARN_ON is hit because the bss config chandef + is empty here. + Since AP_VLAN channel settings do not matter for anything chanctx related + (always inherits the settings from the AP interface), let's just ignore + it here. + + Signed-off-by: Felix Fietkau + +commit ff354dbdd743e5fe186df8cd17982db19f78231a +Author: Felix Fietkau +Date: Wed Jul 23 15:33:26 2014 +0200 + + ath9k: fix aggregation session lockup + + If an aggregation session fails, frames still end up in the driver queue + with IEEE80211_TX_CTL_AMPDU set. + This causes tx for the affected station/tid to stall, since + ath_tx_get_tid_subframe returning packets to send. + + Fix this by clearing IEEE80211_TX_CTL_AMPDU as long as no aggregation + session is running. + + Cc: stable@vger.kernel.org + Reported-by: Antonio Quartulli + Signed-off-by: Felix Fietkau + +commit 38695a6e5a940e6a524523b88a33916b016fb2a1 +Author: Felix Fietkau +Date: Fri Jul 11 12:06:18 2014 +0200 + + mac80211: fix crash on getting sta info with uninitialized rate control + + If the expected throughput is queried before rate control has been + initialized, the minstrel op for it will crash while trying to access + the rate table. + Check for WLAN_STA_RATE_CONTROL before attempting to use the rate + control op. + + Reported-by: Jean-Pierre Tosoni + Signed-off-by: Felix Fietkau + +commit c0ee7fa4c0da824ccccc172bf175fb1f86540921 +Author: Felix Fietkau +Date: Wed Jul 16 18:00:31 2014 +0200 + + ath9k: fix pending tx frames accounting + + Packets originally buffered for the regular hardware tx queues can end + up being transmitted through the U-APSD queue (via PS-Poll or U-APSD). + When packets are dropped due to retransmit failures, the pending frames + counter is not always updated properly. + Fix this by keeping track of the queue that a frame was accounted for in + the ath_frame_info struct, and using that on completion to decide + whether the counter should be updated. + This fixes some spurious transmit queue hangs. + + Cc: stable@vger.kernel.org + Signed-off-by: Felix Fietkau + +commit edcdf0989410a05a6a4b8438df4010447eaa7d9a +Author: Felix Fietkau +Date: Sun Jun 22 13:36:20 2014 +0200 + + Revert "cfg80211: Use 5MHz bandwidth by default when checking usable channels" + + It enables channels that are not supposed to be enabled according to the + regulatory rules. + + This reverts commit 8eca1fb692cc9557f386eddce75c300a3855d11a. + +commit 6e7341074823d2a45b81f2742cbf75f1da790031 +Author: Rafał Miłecki +Date: Sat May 31 19:40:45 2014 +0200 + + b43: disable 5 GHz on G-PHY + + This fixes regression introduced by adding some G-PHY devices to the + list of dual band devices. There is simply no support for 5 GHz on + G-PHY devices in b43. It results in: + WARNING: CPU: 0 PID: 79 at drivers/net/wireless/b43/phy_g.c:75 b43_gphy_channel_switch+0x125/0x130 [b43]() + b43-phy1 ERROR: PHY init: Channel switch to default failed + + Regression was introduced by the following commit: + + commit 773cfc508f4d64c14547ff8751b5cbd473124364 + Author: Rafał Miłecki + Date: Mon May 19 23:18:55 2014 +0200 + + b43: add more devices to the bands database + + Signed-off-by: Rafał Miłecki + Signed-off-by: John W. Linville + +commit 1186edbef91f15722e5bdf56326ce0abc2935ce7 +Author: Stanislaw Gruszka +Date: Tue Jun 10 12:51:06 2014 +0200 + + rt2x00: disable TKIP on USB + + On USB we can not get atomically TKIP key. We have to disable support + for TKIP acceleration on USB hardware to avoid bug as showed bellow. + + [ 860.827243] BUG: scheduling while atomic: hostapd/3397/0x00000002 + + [ 860.827280] Call Trace: + [ 860.827282] [] dump_stack+0x4d/0x66 + [ 860.827284] [] __schedule_bug+0x47/0x55 + [ 860.827285] [] __schedule+0x733/0x7b0 + [ 860.827287] [] schedule+0x29/0x70 + [ 860.827289] [] schedule_timeout+0x15a/0x2b0 + [ 860.827291] [] ? ftrace_raw_event_tick_stop+0xc0/0xc0 + [ 860.827294] [] ? __module_text_address+0x12/0x70 + [ 860.827296] [] wait_for_completion_timeout+0xb3/0x140 + [ 860.827298] [] ? wake_up_state+0x20/0x20 + [ 860.827301] [] usb_start_wait_urb+0x7d/0x150 + [ 860.827303] [] usb_control_msg+0xc5/0x110 + [ 860.827305] [] rt2x00usb_vendor_request+0xc6/0x160 [rt2x00usb] + [ 860.827307] [] rt2x00usb_vendor_req_buff_lock+0x75/0x150 [rt2x00usb] + [ 860.827309] [] rt2x00usb_vendor_request_buff+0xa3/0xe0 [rt2x00usb] + [ 860.827311] [] rt2x00usb_register_multiread+0x33/0x40 [rt2800usb] + [ 860.827314] [] rt2800_get_tkip_seq+0x39/0x50 [rt2800lib] + [ 860.827321] [] ieee80211_get_key+0x218/0x2a0 [mac80211] + [ 860.827322] [] ? __nlmsg_put+0x6c/0x80 + [ 860.827329] [] nl80211_get_key+0x22e/0x360 [cfg80211] + + Cc: stable@vger.kernel.org + Reported-and-tested-by: Peter Wu + Reported-and-tested-by: Pontus Fuchs + Signed-off-by: Stanislaw Gruszka + Signed-off-by: John W. Linville + +commit 5f313a15da92dda80ac4c9a137bc42d7d0b49adf +Author: Rafał Miłecki +Date: Thu Jun 12 09:28:38 2014 +0200 + + b43: fix frequency reported on G-PHY with /new/ firmware + +commit d3a58df87a2e4c2301ac843604202d290a48440b +Author: Avraham Stern +Date: Thu May 22 12:17:47 2014 +0300 + + mac80211: set new interfaces as idle upon init + + Mark new interfaces as idle to allow operations that require that + interfaces are idle to take place. Interface types that are always + not idle (like AP interfaces) will be set as not idle when they are + assigned a channel context. + + Signed-off-by: Avraham Stern + Signed-off-by: Emmanuel Grumbach + Signed-off-by: Johannes Berg + +commit 923eaf367206e01f22c97aee22300e332d071916 +Author: Arik Nemtsov +Date: Mon May 26 14:40:51 2014 +0300 + + mac80211: don't check netdev state for debugfs read/write + + Doing so will lead to an oops for a p2p-dev interface, since it has + no netdev. + + Cc: stable@vger.kernel.org + Signed-off-by: Arik Nemtsov + Signed-off-by: Emmanuel Grumbach + Signed-off-by: Johannes Berg + +commit a9fb54169b197f31aff24c8d6270dd1e56cde395 +Author: 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 + Signed-off-by: Chaitanya T K + Acked-by: John W. Linville + [remove unneeded parentheses, fix rounding by using %.0f] + Signed-off-by: Johannes Berg + +commit c7d37a66e345df2fdf1aa7b2c9a6d3d53846ca5b +Author: Krzysztof Hałasa +Date: Mon May 26 14:14:46 2014 +0200 + + mac80211: fix IBSS join by initializing last_scan_completed + + Without this fix, freshly rebooted Linux creates a new IBSS + instead of joining an existing one. Only when jiffies counter + overflows after 5 minutes the IBSS can be successfully joined. + + Signed-off-by: Krzysztof Hałasa + [edit commit message slightly] + Cc: stable@vger.kernel.org + Signed-off-by: Johannes Berg + +commit 34171dc0d623be2c1032416bf7d3819f388ed70d +Author: Emmanuel Grumbach +Date: Sun May 25 15:35:41 2014 +0300 + + mac80211: fix virtual monitor interface addition + + Since the commit below, cfg80211_chandef_dfs_required() + will warn if it gets a an NL80211_IFTYPE_UNSPECIFIED iftype + as explicitely written in the commit log. + When an virtual monitor interface is added, its type is set + in ieee80211_sub_if_data.vif.type, but not in + ieee80211_sub_if_data.wdev.iftype which is passed to + cfg80211_chandef_dfs_required() hence resulting in the + following warning: + + WARNING: CPU: 1 PID: 21265 at net/wireless/chan.c:376 cfg80211_chandef_dfs_required+0xbc/0x130 [cfg80211]() + Modules linked in: [...] + CPU: 1 PID: 21265 Comm: ifconfig Tainted: G W O 3.13.11+ #12 + Hardware name: Dell Inc. Latitude E6410/0667CC, BIOS A01 03/05/2010 + 0000000000000009 ffff88008f5fdb08 ffffffff817d4219 ffff88008f5fdb50 + ffff88008f5fdb40 ffffffff8106f57d 0000000000000000 0000000000000000 + ffff880081062fb8 ffff8800810604e0 0000000000000001 ffff88008f5fdba0 + Call Trace: + [] dump_stack+0x4d/0x66 + [] warn_slowpath_common+0x7d/0xa0 + [] warn_slowpath_fmt+0x4c/0x50 + [] cfg80211_chandef_dfs_required+0xbc/0x130 [cfg80211] + [] ieee80211_vif_use_channel+0x94/0x500 [mac80211] + [] ieee80211_add_virtual_monitor+0x1ab/0x5c0 [mac80211] + [] ieee80211_do_open+0xe75/0x1580 [mac80211] + [] ieee80211_open+0x69/0x70 [mac80211] + [snip] + + Fixes: 00ec75fc5a64 ("cfg80211: pass the actual iftype when calling cfg80211_chandef_dfs_required()") + Signed-off-by: Emmanuel Grumbach + Acked-by: Luciano Coelho + Signed-off-by: Johannes Berg + +commit d93cc72b37b4e2c314e1c499e80e8801907c2fea +Author: Michal Kazior +Date: Thu Jun 5 14:21:37 2014 +0200 + + mac80211: use csa counter offsets instead of csa_active + + 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. + + Using csa counter offsets which are embedded in + beacon struct (and thus are protected with single + RCU assignment) is much safer. + + Signed-off-by: Michal Kazior + Signed-off-by: Johannes Berg + +commit d2746694fcdef24e0a7a1947d8c70082cde81a26 +Author: Michal Kazior +Date: Thu Jun 5 14:21:36 2014 +0200 + + mac80211: move csa counters from sdata to beacon/presp + + 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. + + While at it relax WARN_ON into WARN_ON_ONCE to + prevent spamming logs and racing. + + Signed-off-by: Michal Kazior + Signed-off-by: Johannes Berg + +commit 5dcb54f3a1a8cd7e0331e773487574f9743615db +Author: Janusz Dziedzic +Date: Thu Jun 5 08:12:57 2014 +0200 + + mac80211: allow tx via monitor iface when DFS + + Allow send frames using monitor interface + when DFS chandef and we pass CAC (beaconing + allowed). + + This fix problem when old kernel and new backports used, + in such case hostapd create/use also monitor interface. + Before this patch all frames hostapd send using monitor + iface were dropped when AP was configured on DFS channel. + + Signed-off-by: Janusz Dziedzic + Signed-off-by: Johannes Berg + +commit 6f09a1beb0d2007572248c986780562219bd206f +Author: Johannes Berg +Date: Wed Jun 4 17:31:56 2014 +0200 + + cfg80211: make ethtool the driver's responsibility + + 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. + + To cleanly implement this in mac80211, introduce a new file and + move some code to appropriate places. + + Signed-off-by: Johannes Berg + +commit 6b0c6f133de8f90caeb1c4a902e6140567c5bf96 +Author: Johannes Berg +Date: Wed Jun 4 17:06:23 2014 +0200 + + mac80211: remove weak WEP IV accounting + + Since WEP is practically dead, there seems very little + point in keeping WEP weak IV accounting. + + Signed-off-by: Johannes Berg + +commit aecdc89fb4664c76baa4bbd46008f220532309ff +Author: Luciano Coelho +Date: Fri May 23 11:04:50 2014 +0300 + + ath9k/ath10k: remove unnecessary channel_switch_beacon callbacks + + 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. + + Cc: Michal Kazior + Signed-off-by: Luciano Coelho + Signed-off-by: Kalle Valo + +commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798 +Author: Rajkumar Manoharan +Date: Tue May 27 16:58:02 2014 +0530 + + ath9k: Fix deadlock while updating p2p beacon timer + + pm_lock is taken twice while syncing HW TSF of p2p vif. + Fix this by taking the lock at caller side. + + Cc: Felix Fietkau + Signed-off-by: Rajkumar Manoharan + Signed-off-by: John W. Linville + +commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:27 2014 +0200 + + rt2x00: do not initialize BCN_OFFSET registers + + We setup BCN_OFFSET{0,1} registers dynamically, don't have to + initialize them. + + Signed-off-by: Stanislaw Gruszka + +commit e5c58ca7a48d4c82f282749a978052c47fd95998 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:26 2014 +0200 + + rt2x00: change order when stop beaconing + + 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: Stanislaw Gruszka + +commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:25 2014 +0200 + + rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM + + We setup MAC_BSSID_DW1_BSS_BCN_NUM dynamically when numbers of active + beacons increase. Change default to 0 to tell hardware that we want to + send only one beacon as default. + + Signed-off-by: Stanislaw Gruszka + +commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:24 2014 +0200 + + rt2x00: change beaconing setup on RT2800 + + 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. + + 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 + Signed-off-by: Stanislaw Gruszka + +commit 916e591b2cc41f7e572992175ca56d866d7bc958 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:23 2014 +0200 + + rt2x00: change beaconing locking + + This patch is needed for further changes to keep global variables + consistent when changing beaconing on diffrent vif's. + + Signed-off-by: Stanislaw Gruszka + +commit 930b0dffd1731f3f418f9132faea720a23b7af61 +Author: Johannes Berg +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 + Signed-off-by: Johannes Berg + +commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873 +Author: Felix Fietkau +Date: Fri May 23 19:58:14 2014 +0200 + + mac80211: reduce packet loss notifications under load + + 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. + + 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: Felix Fietkau + +commit 7b7843a36fbcc568834404c7430ff895d8502131 +Author: Felix Fietkau +Date: Fri May 23 19:26:32 2014 +0200 + + mac80211: fix a memory leak on sta rate selection table + + Cc: stable@vger.kernel.org + Reported-by: Christophe Prévotaux + Signed-off-by: Felix Fietkau + +commit 96892d6aa0a153423070addf3070bc79578b3897 +Author: Felix Fietkau +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 + +--- 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; + } ---- a/net/mac80211/debugfs_sta.c -+++ b/net/mac80211/debugfs_sta.c -@@ -66,11 +66,11 @@ static ssize_t sta_flags_read(struct fil - test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" - - int res = scnprintf(buf, sizeof(buf), -- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", -+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - TEST(AUTH), TEST(ASSOC), TEST(PS_STA), - TEST(PS_DRIVER), TEST(AUTHORIZED), - TEST(SHORT_PREAMBLE), -- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT), -+ TEST(WME), TEST(CLEAR_PS_FILT), - TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), - TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), - TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -463,7 +463,6 @@ int ieee80211_do_open(struct wireless_de - struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); - struct net_device *dev = wdev->netdev; - struct ieee80211_local *local = sdata->local; -- struct sta_info *sta; - u32 changed = 0; - int res; - u32 hw_reconf_flags = 0; -@@ -629,30 +628,8 @@ int ieee80211_do_open(struct wireless_de - - set_bit(SDATA_STATE_RUNNING, &sdata->state); - -- if (sdata->vif.type == NL80211_IFTYPE_WDS) { -- /* Create STA entry for the WDS peer */ -- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, -- GFP_KERNEL); -- if (!sta) { -- res = -ENOMEM; -- goto err_del_interface; -- } -- -- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); -- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); -- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); -- -- res = sta_info_insert(sta); -- if (res) { -- /* STA has been freed */ -- goto err_del_interface; -- } -- -- rate_control_rate_init(sta); -- netif_carrier_on(dev); -- } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { -+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) - rcu_assign_pointer(local->p2p_sdata, sdata); -- } +-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--) +--- 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); /* - * set_multicast_list will be invoked by the networking core -@@ -1116,6 +1093,74 @@ static void ieee80211_if_setup(struct ne - dev->destructor = free_netdev; + * 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 ieee80211_sta_rates *rates; + int i; + + if (sta->rate_ctrl) +@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca + kfree(sta->tx_lat); + } + ++ rates = rcu_dereference_protected(sta->sta.rates, true); ++ if (rates) ++ kfree(rates); ++ + sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); + + 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 void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb) -+{ -+ struct ieee80211_local *local = sdata->local; -+ struct ieee80211_rx_status *rx_status; -+ struct ieee802_11_elems elems; -+ struct ieee80211_mgmt *mgmt; -+ struct sta_info *sta; -+ size_t baselen; -+ u32 rates = 0; -+ u16 stype; -+ bool new = false; -+ enum ieee80211_band band; -+ struct ieee80211_supported_band *sband; -+ -+ rx_status = IEEE80211_SKB_RXCB(skb); -+ band = rx_status->band; -+ sband = local->hw.wiphy->bands[band]; -+ mgmt = (struct ieee80211_mgmt *) skb->data; -+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; -+ -+ if (stype != IEEE80211_STYPE_BEACON) +-static void sta_unblock(struct work_struct *wk) ++static void sta_deliver_ps_frames(struct work_struct *wk) + { + struct sta_info *sta; + +- sta = container_of(wk, struct sta_info, drv_unblock_wk); ++ sta = container_of(wk, struct sta_info, drv_deliver_wk); + + if (sta->dead) + return; + +- 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 sta_prepare_rate_control(struct ieee80211_local *local, +@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i + + 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 +@@ -1101,8 +1098,11 @@ void ieee80211_sta_ps_deliver_wakeup(str + unsigned long flags; + struct ps_data *ps; + +- if (sdata->vif.type == NL80211_IFTYPE_AP || +- sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, ++ u.ap); ++ ++ if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->bss->ps; + else if (ieee80211_vif_is_mesh(&sdata->vif)) + ps = &sdata->u.mesh.ps; +@@ -1140,8 +1140,15 @@ void ieee80211_sta_ps_deliver_wakeup(str + } + + 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); + + atomic_dec(&ps->num_sta_ps); +@@ -1542,10 +1549,26 @@ void ieee80211_sta_block_awake(struct ie + + trace_api_sta_block_awake(sta->local, pubsta, block); + +- 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; ++ } + -+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; -+ if (baselen > skb->len) ++ if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) + return; + -+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable, -+ skb->len - baselen, false, &elems); ++ 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); + +@@ -1703,3 +1726,140 @@ u8 sta_info_tx_streams(struct sta_info * + return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; + } ++ ++void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) ++{ ++ struct ieee80211_sub_if_data *sdata = sta->sdata; ++ struct ieee80211_local *local = sdata->local; ++ struct rate_control_ref *ref = NULL; ++ struct timespec uptime; ++ u64 packets = 0; ++ u32 thr = 0; ++ int i, ac; ++ ++ if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) ++ ref = local->rate_ctrl; + -+ rates = ieee80211_sta_get_rates(local, &elems, band, NULL); ++ sinfo->generation = sdata->local->sta_generation; + -+ rcu_read_lock(); ++ 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; + -+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr); ++ do_posix_clock_monotonic_gettime(&uptime); ++ sinfo->connected_time = uptime.tv_sec - sta->last_connected; + -+ if (!sta) { -+ rcu_read_unlock(); -+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, -+ GFP_KERNEL); -+ if (!sta) -+ return; ++ 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; + -+ new = true; ++ 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; + -+ sta->last_rx = jiffies; -+ sta->sta.supp_rates[band] = rates; ++ 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]); ++ } ++ } + -+ if (elems.ht_cap_elem) -+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, -+ elems.ht_cap_elem, sta); ++ sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); ++ sta_set_rate_info_rx(sta, &sinfo->rxrate); + -+ if (elems.wmm_param) -+ set_sta_flag(sta, WLAN_STA_WME); ++ 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; + -+ if (new) { -+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); -+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); -+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); -+ rate_control_rate_init(sta); -+ sta_info_insert_rcu(sta); ++ 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 + } + -+ rcu_read_unlock(); -+} ++ 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; + - static void ieee80211_iface_work(struct work_struct *work) - { - struct ieee80211_sub_if_data *sdata = -@@ -1220,6 +1265,9 @@ static void ieee80211_iface_work(struct - break; - ieee80211_mesh_rx_queued_mgmt(sdata, skb); - break; -+ case NL80211_IFTYPE_WDS: -+ ieee80211_wds_rx_queued_mgmt(sdata, skb); -+ break; - default: - WARN(1, "frame for unexpected interface type"); - break; ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct - - sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; -+ rate->count = 1; -+ -+ if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { -+ int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); -+ rate->idx = mp->cck_rates[idx]; -+ rate->flags = 0; -+ return; -+ } ++ 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); + - rate->idx = sample_idx % MCS_GROUP_RATES + - (sample_group->streams - 1) * MCS_GROUP_RATES; - rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; -- rate->count = 1; - } - - static void ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - -- /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ -- if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { -+ /* -+ * Drop duplicate 802.11 retransmissions -+ * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") -+ */ -+ if (rx->skb->len >= 24 && rx->sta && -+ !ieee80211_is_ctl(hdr->frame_control) && -+ !ieee80211_is_qos_nullfunc(hdr->frame_control) && -+ !is_multicast_ether_addr(hdr->addr1)) { - if (unlikely(ieee80211_has_retry(hdr->frame_control) && - rx->sta->last_seq_ctrl[rx->seqno_idx] == - hdr->seq_ctrl)) { -@@ -2369,6 +2375,7 @@ ieee80211_rx_h_action(struct ieee80211_r - sdata->vif.type != NL80211_IFTYPE_MESH_POINT && - sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sdata->vif.type != NL80211_IFTYPE_AP && -+ sdata->vif.type != NL80211_IFTYPE_WDS && - sdata->vif.type != NL80211_IFTYPE_ADHOC) - break; - -@@ -2720,14 +2727,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_ - - if (!ieee80211_vif_is_mesh(&sdata->vif) && - sdata->vif.type != NL80211_IFTYPE_ADHOC && -- sdata->vif.type != NL80211_IFTYPE_STATION) -+ sdata->vif.type != NL80211_IFTYPE_STATION && -+ sdata->vif.type != NL80211_IFTYPE_WDS) - return RX_DROP_MONITOR; - - switch (stype) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_BEACON): - case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): -- /* process for all: mesh, mlme, ibss */ -+ /* process for all: mesh, mlme, ibss, wds */ - break; - case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): -@@ -3008,6 +3016,9 @@ static int prepare_for_handlers(struct i - case NL80211_IFTYPE_ADHOC: - if (!bssid) - return 0; -+ if (ether_addr_equal(sdata->vif.addr, hdr->addr2) || -+ ether_addr_equal(sdata->u.ibss.bssid, hdr->addr2)) -+ return 0; - if (ieee80211_is_beacon(hdr->frame_control)) { - return 1; - } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { -@@ -3059,10 +3070,16 @@ static int prepare_for_handlers(struct i - } - break; - case NL80211_IFTYPE_WDS: -- if (bssid || !ieee80211_is_data(hdr->frame_control)) -- return 0; - if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2)) - return 0; -+ -+ if (ieee80211_is_data(hdr->frame_control) || -+ ieee80211_is_action(hdr->frame_control)) { -+ if (compare_ether_addr(sdata->vif.addr, hdr->addr1)) -+ return 0; -+ } else if (!ieee80211_is_beacon(hdr->frame_control)) -+ return 0; ++ /* 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); + - break; - case NL80211_IFTYPE_P2P_DEVICE: - if (!ieee80211_is_public_action(hdr, skb->len) && ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -32,7 +32,6 @@ - * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble - * frames. - * @WLAN_STA_WME: Station is a QoS-STA. -- * @WLAN_STA_WDS: Station is one of our WDS peers. - * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the - * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next - * frame to this station is transmitted. -@@ -66,7 +65,6 @@ enum ieee80211_sta_info_flags { - WLAN_STA_AUTHORIZED, - WLAN_STA_SHORT_PREAMBLE, - WLAN_STA_WME, -- WLAN_STA_WDS, - WLAN_STA_CLEAR_PS_FILT, - WLAN_STA_MFP, - WLAN_STA_BLOCK_BA, ---- a/drivers/net/wireless/ath/ath9k/xmit.c -+++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee802 - ARRAY_SIZE(bf->rates)); - } ++ 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 void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, -+ struct sk_buff *skb) ++static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) +{ -+ int q; ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + -+ q = skb_get_queue_mapping(skb); -+ if (txq == sc->tx.uapsdq) -+ txq = sc->tx.txq_map[q]; -+ -+ if (txq != sc->tx.txq_map[q]) ++ /* 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 (WARN_ON(--txq->pending_frames < 0)) -+ txq->pending_frames = 0; ++ if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD) ++ return; + -+ if (txq->stopped && -+ txq->pending_frames < sc->tx.txq_max_pending[q]) { -+ ieee80211_wake_queue(sc->hw, q); -+ txq->stopped = false; -+ } ++ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, ++ sta->lost_packets, GFP_ATOMIC); ++ sta->lost_packets = 0; +} + - static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ath_txq *txq = tid->ac->txq; -@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_ - if (!bf) { - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { -+ ath_txq_skb_done(sc, txq, skb); - ieee80211_free_txskb(sc->hw, skb); - continue; + 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); } -@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc - - if (!bf) { - __skb_unlink(skb, &tid->buf_q); -+ ath_txq_skb_done(sc, txq, skb); - ieee80211_free_txskb(sc->hw, skb); - continue; } -@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { -+ ath_txq_skb_done(sc, txq, skb); - ieee80211_free_txskb(sc->hw, skb); +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info * return; } -@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw - - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { -+ ath_txq_skb_done(sc, txq, skb); - if (txctl->paprd) - dev_kfree_skb_any(skb); - else -@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_s - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; -- int q, padpos, padsize; -+ int padpos, padsize; - unsigned long flags; - - ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); -@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_s - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - __skb_queue_tail(&txq->complete_q, skb); -- -- q = skb_get_queue_mapping(skb); -- if (txq == sc->tx.uapsdq) -- txq = sc->tx.txq_map[q]; -- -- if (txq == sc->tx.txq_map[q]) { -- if (WARN_ON(--txq->pending_frames < 0)) -- txq->pending_frames = 0; -- -- if (txq->stopped && -- txq->pending_frames < sc->tx.txq_max_pending[q]) { -- ieee80211_wake_queue(sc->hw, q); -- txq->stopped = false; -- } -- } -+ ath_txq_skb_done(sc, txq, skb); ++ set_sta_flag(sta, WLAN_STA_PS_DELIVER); ++ clear_sta_flag(sta, WLAN_STA_PS_STA); + ieee80211_sta_ps_deliver_wakeup(sta); } - static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, ---- a/drivers/net/wireless/ath/ath9k/main.c -+++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -209,6 +209,7 @@ static bool ath_complete_reset(struct at - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - unsigned long flags; -+ int i; +--- 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, + }; - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to restart recv logic\n"); -@@ -236,6 +237,15 @@ static bool ath_complete_reset(struct at - } - work: - ath_restart_work(sc); -+ -+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -+ if (!ATH_TXQ_SETUP(sc, i)) -+ continue; + #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); + -+ spin_lock_bh(&sc->tx.txq[i].axq_lock); -+ ath_txq_schedule(sc, &sc->tx.txq[i]); -+ spin_unlock_bh(&sc->tx.txq[i].axq_lock); -+ } + 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 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 } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) -@@ -543,21 +553,10 @@ chip_reset: + 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; - static int ath_reset(struct ath_softc *sc) - { -- int i, r; -+ int r; +- ieee80211_xmit(sdata, skb, chan->band); ++ ieee80211_xmit(sdata, skb, chandef->chan->band); + rcu_read_unlock(); - ath9k_ps_wakeup(sc); -- - r = ath_reset_internal(sc, NULL); + 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; + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: +@@ -2444,46 +2447,54 @@ static void ieee80211_set_csa(struct iee + return; + } + ++ 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]; - -- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -- if (!ATH_TXQ_SETUP(sc, i)) -- continue; +- if (counter_offset_beacon) { +- if (WARN_ON(counter_offset_beacon >= beacon_data_len)) +- return; - -- spin_lock_bh(&sc->tx.txq[i].axq_lock); -- ath_txq_schedule(sc, &sc->tx.txq[i]); -- spin_unlock_bh(&sc->tx.txq[i].axq_lock); -- } +- beacon_data[counter_offset_beacon] = count; +- } - - ath9k_ps_restore(sc); - - return r; -@@ -2094,7 +2093,7 @@ static void ath9k_wow_add_pattern(struct - { - struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; -- struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; -+ struct cfg80211_pkt_pattern *patterns = wowlan->patterns; - int mask_len; - s8 i = 0; - ---- a/drivers/net/wireless/mwifiex/cfg80211.c -+++ b/drivers/net/wireless/mwifiex/cfg80211.c -@@ -2298,8 +2298,7 @@ EXPORT_SYMBOL_GPL(mwifiex_del_virtual_in +- 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(); + } - #ifdef CONFIG_PM - static bool --mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat, -- s8 *byte_seq) -+mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq) + u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) { - int j, k, valid_byte_cnt = 0; - bool dont_care_byte = false; ---- a/drivers/net/wireless/ti/wlcore/main.c -+++ b/drivers/net/wireless/ti/wlcore/main.c -@@ -1315,7 +1315,7 @@ static struct sk_buff *wl12xx_alloc_dumm + 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; - #ifdef CONFIG_PM - static int --wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p) -+wl1271_validate_wowlan_pattern(struct cfg80211_pkt_pattern *p) - { - int num_fields = 0, in_field = 0, fields_size = 0; - int i, pattern_len = 0; -@@ -1458,9 +1458,9 @@ void wl1271_rx_filter_flatten_fields(str - * Allocates an RX filter returned through f - * which needs to be freed using rx_filter_free() - */ --static int wl1271_convert_wowlan_pattern_to_rx_filter( -- struct cfg80211_wowlan_trig_pkt_pattern *p, -- struct wl12xx_rx_filter **f) -+static int -+wl1271_convert_wowlan_pattern_to_rx_filter(struct cfg80211_pkt_pattern *p, -+ struct wl12xx_rx_filter **f) - { - int i, j, ret = 0; - struct wl12xx_rx_filter *filter; -@@ -1562,7 +1562,7 @@ static int wl1271_configure_wowlan(struc +- sdata->csa_current_counter--; ++ beacon->csa_current_counter--; - /* Translate WoWLAN patterns into filters */ - for (i = 0; i < wow->n_patterns; i++) { -- struct cfg80211_wowlan_trig_pkt_pattern *p; -+ struct cfg80211_pkt_pattern *p; - struct wl12xx_rx_filter *filter = NULL; + /* the counter should never reach 0 */ +- WARN_ON(!sdata->csa_current_counter); ++ WARN_ON_ONCE(!beacon->csa_current_counter); ++ count = beacon->csa_current_counter; - p = &wow->patterns[i]; ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -1698,7 +1698,7 @@ struct cfg80211_pmksa { - }; +- return sdata->csa_current_counter; ++unlock: ++ rcu_read_unlock(); ++ return count; + } + EXPORT_SYMBOL(ieee80211_csa_update_counter); - /** -- * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern -+ * struct cfg80211_pkt_pattern - packet pattern - * @mask: bitmask where to match pattern and where to ignore bytes, - * one bit per byte, in same format as nl80211 - * @pattern: bytes to match where bitmask is 1 -@@ -1708,7 +1708,7 @@ struct cfg80211_pmksa { - * Internal note: @mask and @pattern are allocated in one chunk of - * memory, free @mask only! - */ --struct cfg80211_wowlan_trig_pkt_pattern { -+struct cfg80211_pkt_pattern { - u8 *mask, *pattern; - int pattern_len; - int pkt_offset; -@@ -1770,7 +1770,7 @@ struct cfg80211_wowlan { - bool any, disconnect, magic_pkt, gtk_rekey_failure, - eap_identity_req, four_way_handshake, - rfkill_release; -- struct cfg80211_wowlan_trig_pkt_pattern *patterns; -+ struct cfg80211_pkt_pattern *patterns; - struct cfg80211_wowlan_tcp *tcp; - int n_patterns; - }; ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -3060,11 +3060,11 @@ enum nl80211_tx_power_setting { - }; +@@ -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; - /** -- * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute -- * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute -- * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has -+ * enum nl80211_packet_pattern_attr - packet pattern attribute -+ * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute -+ * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has - * a zero bit are ignored -- * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have -+ * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have - * a bit for each byte in the pattern. The lowest-order bit corresponds - * to the first byte of the pattern, but the bytes of the pattern are - * in a little-endian-like format, i.e. the 9th byte of the pattern -@@ -3075,23 +3075,23 @@ enum nl80211_tx_power_setting { - * Note that the pattern matching is done as though frames were not - * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked - * first (including SNAP header unpacking) and then matched. -- * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after -+ * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after - * these fixed number of bytes of received packet -- * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes -- * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number -+ * @NUM_NL80211_PKTPAT: number of attributes -+ * @MAX_NL80211_PKTPAT: max attribute number - */ --enum nl80211_wowlan_packet_pattern_attr { -- __NL80211_WOWLAN_PKTPAT_INVALID, -- NL80211_WOWLAN_PKTPAT_MASK, -- NL80211_WOWLAN_PKTPAT_PATTERN, -- NL80211_WOWLAN_PKTPAT_OFFSET, -+enum nl80211_packet_pattern_attr { -+ __NL80211_PKTPAT_INVALID, -+ NL80211_PKTPAT_MASK, -+ NL80211_PKTPAT_PATTERN, -+ NL80211_PKTPAT_OFFSET, - -- NUM_NL80211_WOWLAN_PKTPAT, -- MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, -+ NUM_NL80211_PKTPAT, -+ MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1, - }; + if (!ieee80211_sdata_running(sdata)) +@@ -2531,10 +2541,13 @@ bool ieee80211_csa_is_complete(struct ie + goto out; + } - /** -- * struct nl80211_wowlan_pattern_support - pattern support information -+ * struct nl80211_pattern_support - packet pattern support information - * @max_patterns: maximum number of patterns supported - * @min_pattern_len: minimum length of each pattern - * @max_pattern_len: maximum length of each pattern -@@ -3101,13 +3101,22 @@ enum nl80211_wowlan_packet_pattern_attr - * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the - * capability information given by the kernel to userspace. - */ --struct nl80211_wowlan_pattern_support { -+struct nl80211_pattern_support { - __u32 max_patterns; - __u32 min_pattern_len; - __u32 max_pattern_len; - __u32 max_pkt_offset; - } __attribute__((packed)); - -+/* only for backward compatibility */ -+#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID -+#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK -+#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN -+#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET -+#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT -+#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT -+#define nl80211_wowlan_pattern_support nl80211_pattern_support -+ - /** - * enum nl80211_wowlan_triggers - WoWLAN trigger definitions - * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes -@@ -3127,7 +3136,7 @@ struct nl80211_wowlan_pattern_support { - * pattern matching is done after the packet is converted to the MSDU. - * - * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute -- * carrying a &struct nl80211_wowlan_pattern_support. -+ * carrying a &struct nl80211_pattern_support. - * - * When reporting wakeup. it is a u32 attribute containing the 0-based - * index of the pattern that caused the wakeup, in the patterns passed -@@ -3284,7 +3293,7 @@ struct nl80211_wowlan_tcp_data_token_fea - * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a - * u32 attribute holding the maximum length - * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for -- * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK -+ * feature advertising. The mask works like @NL80211_PKTPAT_MASK - * but on the TCP payload only. - * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes - * @MAX_NL80211_WOWLAN_TCP: highest attribute number ---- a/net/mac80211/mesh_ps.c -+++ b/net/mac80211/mesh_ps.c -@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(str - enum nl80211_mesh_power_mode pm; - bool do_buffer; - -+ /* For non-assoc STA, prevent buffering or frame transmission */ -+ if (sta->sta_state < IEEE80211_STA_ASSOC) -+ return; +- if (WARN_ON(counter_beacon > beacon_data_len)) ++ if (!beacon->csa_counter_offsets[0]) ++ goto out; + - /* - * use peer-specific power mode if peering is established and the - * peer's power mode is known ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -441,10 +441,12 @@ static int nl80211_prepare_wdev_dump(str - goto out_unlock; - } - *rdev = wiphy_to_dev((*wdev)->wiphy); -- cb->args[0] = (*rdev)->wiphy_idx; -+ /* 0 is the first index - add 1 to parse only once */ -+ cb->args[0] = (*rdev)->wiphy_idx + 1; - cb->args[1] = (*wdev)->identifier; - } else { -- struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]); -+ /* subtract the 1 again here */ -+ struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); - struct wireless_dev *tmp; ++ if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) + goto out; - if (!wiphy) { -@@ -974,7 +976,7 @@ static int nl80211_send_wowlan(struct sk - return -ENOBUFS; +- if (beacon_data[counter_beacon] == 1) ++ if (beacon_data[beacon->csa_counter_offsets[0]] == 1) + ret = true; + out: + rcu_read_unlock(); +@@ -2550,6 +2563,7 @@ __ieee80211_beacon_get(struct ieee80211_ + bool is_template) + { + struct ieee80211_local *local = hw_to_local(hw); ++ struct beacon_data *beacon = NULL; + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata = NULL; +@@ -2571,10 +2585,10 @@ __ieee80211_beacon_get(struct ieee80211_ + + if (sdata->vif.type == NL80211_IFTYPE_AP) { + struct ieee80211_if_ap *ap = &sdata->u.ap; +- struct beacon_data *beacon = rcu_dereference(ap->beacon); + ++ beacon = rcu_dereference(ap->beacon); + if (beacon) { +- if (sdata->vif.csa_active) { ++ if (beacon->csa_counter_offsets[0]) { + if (!is_template) + ieee80211_csa_update_counter(vif); + +@@ -2615,37 +2629,37 @@ __ieee80211_beacon_get(struct ieee80211_ + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + struct ieee80211_hdr *hdr; +- struct beacon_data *presp = rcu_dereference(ifibss->presp); + +- if (!presp) ++ beacon = rcu_dereference(ifibss->presp); ++ if (!beacon) + goto out; + +- if (sdata->vif.csa_active) { ++ if (beacon->csa_counter_offsets[0]) { + if (!is_template) + ieee80211_csa_update_counter(vif); + +- ieee80211_set_csa(sdata, presp); ++ ieee80211_set_csa(sdata, beacon); + } - if (dev->wiphy.wowlan->n_patterns) { -- struct nl80211_wowlan_pattern_support pat = { -+ struct nl80211_pattern_support pat = { - .max_patterns = dev->wiphy.wowlan->n_patterns, - .min_pattern_len = dev->wiphy.wowlan->pattern_min_len, - .max_pattern_len = dev->wiphy.wowlan->pattern_max_len, -@@ -1568,8 +1570,10 @@ static int nl80211_dump_wiphy(struct sk_ - rtnl_lock(); - if (!state) { - state = kzalloc(sizeof(*state), GFP_KERNEL); -- if (!state) -+ if (!state) { -+ rtnl_unlock(); - return -ENOMEM; -+ } - state->filter_wiphy = -1; - ret = nl80211_dump_wiphy_parse(skb, cb, state); - if (ret) { -@@ -6615,12 +6619,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_ev +- skb = dev_alloc_skb(local->tx_headroom + presp->head_len + ++ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + + local->hw.extra_beacon_tailroom); + if (!skb) + goto out; + skb_reserve(skb, local->tx_headroom); +- memcpy(skb_put(skb, presp->head_len), presp->head, +- presp->head_len); ++ memcpy(skb_put(skb, beacon->head_len), beacon->head, ++ beacon->head_len); + + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; +- struct beacon_data *bcn = rcu_dereference(ifmsh->beacon); + +- if (!bcn) ++ beacon = rcu_dereference(ifmsh->beacon); ++ if (!beacon) + goto out; + +- if (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); + } - void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) - { -+ struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; - void *hdr = ((void **)skb->cb)[1]; - struct nlattr *data = ((void **)skb->cb)[2]; - - nla_nest_end(skb, data); - genlmsg_end(skb, hdr); -- genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); -+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0, -+ nl80211_testmode_mcgrp.id, gfp); - } - EXPORT_SYMBOL(cfg80211_testmode_event); - #endif -@@ -7593,12 +7599,11 @@ static int nl80211_send_wowlan_patterns( - if (!nl_pat) - return -ENOBUFS; - pat_len = wowlan->patterns[i].pattern_len; -- if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, -- DIV_ROUND_UP(pat_len, 8), -+ if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8), - wowlan->patterns[i].mask) || -- nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, -- pat_len, wowlan->patterns[i].pattern) || -- nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, -+ nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len, -+ wowlan->patterns[i].pattern) || -+ nla_put_u32(msg, NL80211_PKTPAT_OFFSET, - wowlan->patterns[i].pkt_offset)) - return -ENOBUFS; - nla_nest_end(msg, nl_pat); -@@ -7939,7 +7944,7 @@ static int nl80211_set_wowlan(struct sk_ - struct nlattr *pat; - int n_patterns = 0; - int rem, pat_len, mask_len, pkt_offset; -- struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; -+ struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; - - nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], - rem) -@@ -7958,26 +7963,25 @@ static int nl80211_set_wowlan(struct sk_ - - nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], - rem) { -- nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, -- nla_data(pat), nla_len(pat), NULL); -+ nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), -+ nla_len(pat), NULL); - err = -EINVAL; -- if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || -- !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) -+ if (!pat_tb[NL80211_PKTPAT_MASK] || -+ !pat_tb[NL80211_PKTPAT_PATTERN]) - goto error; -- pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); -+ pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]); - mask_len = DIV_ROUND_UP(pat_len, 8); -- if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != -- mask_len) -+ if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len) - goto error; - if (pat_len > wowlan->pattern_max_len || - pat_len < wowlan->pattern_min_len) - goto error; - -- if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]) -+ if (!pat_tb[NL80211_PKTPAT_OFFSET]) - pkt_offset = 0; - else - pkt_offset = nla_get_u32( -- pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]); -+ pat_tb[NL80211_PKTPAT_OFFSET]); - if (pkt_offset > wowlan->max_pkt_offset) - goto error; - new_triggers.patterns[i].pkt_offset = pkt_offset; -@@ -7991,11 +7995,11 @@ static int nl80211_set_wowlan(struct sk_ - new_triggers.patterns[i].pattern = - new_triggers.patterns[i].mask + mask_len; - memcpy(new_triggers.patterns[i].mask, -- nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), -+ nla_data(pat_tb[NL80211_PKTPAT_MASK]), - mask_len); - new_triggers.patterns[i].pattern_len = pat_len; - memcpy(new_triggers.patterns[i].pattern, -- nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), -+ nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), - pat_len); - i++; + 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; } -@@ -10066,7 +10070,8 @@ void cfg80211_mgmt_tx_status(struct wire - genlmsg_end(msg, hdr); +- 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; + } + + /* CSA offsets */ +- if (offs) { ++ if (offs && beacon) { + int i; -- genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); -+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, -+ nl80211_mlme_mcgrp.id, gfp); - return; + 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]; - nla_put_failure: ---- a/net/wireless/reg.c -+++ b/net/wireless/reg.c -@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev + 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)); + } - void wiphy_regulatory_register(struct wiphy *wiphy) ++static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) ++{ ++ struct data_queue *queue = rt2x00dev->bcn; ++ struct queue_entry *entry; ++ int i, bcn_num = 0; ++ u64 off, reg = 0; ++ u32 bssid_dw1; ++ ++ /* ++ * 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++; ++ } ++ ++ WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing); ++ ++ rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg); ++ rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32)); ++ ++ /* ++ * H/W sends up to MAC_BSSID_DW1_BSS_BCN_NUM + 1 consecutive beacons. ++ */ ++ rt2800_register_read(rt2x00dev, MAC_BSSID_DW1, &bssid_dw1); ++ rt2x00_set_field32(&bssid_dw1, MAC_BSSID_DW1_BSS_BCN_NUM, ++ bcn_num > 0 ? bcn_num - 1 : 0); ++ rt2800_register_write(rt2x00dev, MAC_BSSID_DW1, bssid_dw1); ++} ++ + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { -+ struct regulatory_request *lr; + 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); + - if (!reg_dev_ignore_cell_hint(wiphy)) - reg_num_devs_support_basehint++; ++ /* ++ * Change global beacons settings. ++ */ ++ rt2800_update_beacons_setup(rt2x00dev); -- wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); -+ lr = get_last_request(); -+ wiphy_update_regulatory(wiphy, lr->initiator); - } + /* + * 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); - void wiphy_regulatory_deregister(struct wiphy *wiphy) -@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct - static void reg_timeout_work(struct work_struct *work) - { - REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); -+ rtnl_lock(); - restore_regulatory_settings(true); -+ rtnl_unlock(); - } + /* ++ * 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(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); +- rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); ++ rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); + conf->bssid[1] = cpu_to_le32(reg); + } - int __init regulatory_init(void) ---- a/net/wireless/sme.c -+++ b/net/wireless/sme.c -@@ -34,8 +34,10 @@ struct cfg80211_conn { - CFG80211_CONN_SCAN_AGAIN, - CFG80211_CONN_AUTHENTICATE_NEXT, - CFG80211_CONN_AUTHENTICATING, -+ CFG80211_CONN_AUTH_FAILED, - CFG80211_CONN_ASSOCIATE_NEXT, - CFG80211_CONN_ASSOCIATING, -+ CFG80211_CONN_ASSOC_FAILED, - CFG80211_CONN_DEAUTH, - CFG80211_CONN_CONNECTED, - } state; -@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct - NULL, 0, - params->key, params->key_len, - params->key_idx, NULL, 0); -+ case CFG80211_CONN_AUTH_FAILED: -+ return -ENOTCONN; - case CFG80211_CONN_ASSOCIATE_NEXT: - BUG_ON(!rdev->ops->assoc); - wdev->conn->state = CFG80211_CONN_ASSOCIATING; -@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct - WLAN_REASON_DEAUTH_LEAVING, - false); - return err; -+ case CFG80211_CONN_ASSOC_FAILED: -+ cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, -+ NULL, 0, -+ WLAN_REASON_DEAUTH_LEAVING, false); -+ return -ENOTCONN; - case CFG80211_CONN_DEAUTH: - cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, - NULL, 0, - WLAN_REASON_DEAUTH_LEAVING, false); -+ /* free directly, disconnected event already sent */ -+ cfg80211_sme_free(wdev); - return 0; - default: - return 0; -@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct w - return true; - } +@@ -4517,28 +4562,6 @@ static int rt2800_init_registers(struct + if (ret) + return ret; + +- rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); +- rt2x00_set_field32(®, BCN_OFFSET0_BCN0, +- rt2800_get_beacon_offset(rt2x00dev, 0)); +- rt2x00_set_field32(®, BCN_OFFSET0_BCN1, +- rt2800_get_beacon_offset(rt2x00dev, 1)); +- rt2x00_set_field32(®, BCN_OFFSET0_BCN2, +- rt2800_get_beacon_offset(rt2x00dev, 2)); +- rt2x00_set_field32(®, BCN_OFFSET0_BCN3, +- rt2800_get_beacon_offset(rt2x00dev, 3)); +- rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); +- +- rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); +- rt2x00_set_field32(®, BCN_OFFSET1_BCN4, +- rt2800_get_beacon_offset(rt2x00dev, 4)); +- rt2x00_set_field32(®, BCN_OFFSET1_BCN5, +- rt2800_get_beacon_offset(rt2x00dev, 5)); +- rt2x00_set_field32(®, BCN_OFFSET1_BCN6, +- rt2800_get_beacon_offset(rt2x00dev, 6)); +- rt2x00_set_field32(®, 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); -- wdev->conn->state = CFG80211_CONN_DEAUTH; -+ wdev->conn->state = CFG80211_CONN_ASSOC_FAILED; - schedule_work(&rdev->conn_work); - return false; +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -141,8 +141,11 @@ static void rt2x00lib_intf_scheduled_ite + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + +- if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) ++ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) { ++ mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_update_beacon(rt2x00dev, vif); ++ mutex_unlock(&intf->beacon_skb_mutex); ++ } } -@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless - void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) - { -- cfg80211_sme_free(wdev); -+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); -+ -+ if (!wdev->conn) -+ return; -+ -+ wdev->conn->state = CFG80211_CONN_AUTH_FAILED; -+ schedule_work(&rdev->conn_work); + 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); } - void cfg80211_sme_disassoc(struct wireless_dev *wdev) -@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wirele + void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) +--- a/drivers/net/wireless/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c +@@ -487,6 +487,8 @@ int rt2x00mac_set_key(struct ieee80211_h + crypto.cipher = rt2x00crypto_key_to_cipher(key); + if (crypto.cipher == CIPHER_NONE) + return -EOPNOTSUPP; ++ if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev)) ++ return -EOPNOTSUPP; - void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) - { -- cfg80211_sme_disassoc(wdev); -+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); -+ -+ if (!wdev->conn) -+ return; -+ -+ wdev->conn->state = CFG80211_CONN_ASSOC_FAILED; -+ schedule_work(&rdev->conn_work); - } + crypto.cmd = cmd; - static int cfg80211_sme_connect(struct wireless_dev *wdev, ---- a/net/mac80211/rc80211_minstrel.c -+++ b/net/mac80211/rc80211_minstrel.c -@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct iee - struct minstrel_rate *msr, *mr; - unsigned int ndx; - bool mrr_capable; -- bool prev_sample = mi->prev_sample; -+ bool prev_sample; - int delta; - int sampling_ratio; - -@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct iee - (mi->sample_count + mi->sample_deferred / 2); - - /* delta < 0: no sampling required */ -+ prev_sample = mi->prev_sample; - mi->prev_sample = false; - if (delta < 0 || (!mrr_capable && prev_sample)) - return; +@@ -624,25 +626,24 @@ void rt2x00mac_bss_info_changed(struct i + * Start/stop beaconing. + */ + if (changes & BSS_CHANGED_BEACON_ENABLED) { ++ mutex_lock(&intf->beacon_skb_mutex); + if (!bss_conf->enable_beacon && intf->enable_beacon) { + rt2x00dev->intf_beaconing--; + intf->enable_beacon = false; +- /* +- * Clear beacon in the H/W for this vif. This is needed +- * to disable beaconing on this particular interface +- * and keep it running on other interfaces. +- */ +- rt2x00queue_clear_beacon(rt2x00dev, vif); + + if (rt2x00dev->intf_beaconing == 0) { + /* + * Last beaconing interface disabled + * -> stop beacon queue. + */ +- mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_stop_queue(rt2x00dev->bcn); +- mutex_unlock(&intf->beacon_skb_mutex); + } ++ /* ++ * Clear beacon in the H/W for this vif. This is needed ++ * to disable beaconing on this particular interface ++ * and keep it running on other interfaces. ++ */ ++ rt2x00queue_clear_beacon(rt2x00dev, vif); + } else if (bss_conf->enable_beacon && !intf->enable_beacon) { + rt2x00dev->intf_beaconing++; + intf->enable_beacon = true; +@@ -658,11 +659,10 @@ void rt2x00mac_bss_info_changed(struct i + * First beaconing interface enabled + * -> start beacon queue. + */ +- mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_start_queue(rt2x00dev->bcn); +- mutex_unlock(&intf->beacon_skb_mutex); + } + } ++ mutex_unlock(&intf->beacon_skb_mutex); + } + + /* --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c -@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_ - spin_unlock_irqrestore(&queue->index_lock, irqflags); - } +@@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x + if (unlikely(!intf->beacon)) + return -ENOBUFS; --void rt2x00queue_pause_queue(struct data_queue *queue) -+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) - { -- if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || -- !test_bit(QUEUE_STARTED, &queue->flags) || -- test_and_set_bit(QUEUE_PAUSED, &queue->flags)) -- return; +- mutex_lock(&intf->beacon_skb_mutex); - - switch (queue->qid) { - case QID_AC_VO: - case QID_AC_VI: -@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data - break; - } + /* + * 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); + +- mutex_unlock(&intf->beacon_skb_mutex); +- + return 0; } -+void rt2x00queue_pause_queue(struct data_queue *queue) -+{ -+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || -+ !test_bit(QUEUE_STARTED, &queue->flags) || -+ test_and_set_bit(QUEUE_PAUSED, &queue->flags)) -+ return; -+ -+ rt2x00queue_pause_queue_nocheck(queue); -+} - EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); - void rt2x00queue_unpause_queue(struct data_queue *queue) -@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_ +-int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_vif *vif) ++int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_vif *vif) + { + struct rt2x00_intf *intf = vif_to_intf(vif); + struct skb_frame_desc *skbdesc; +@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str + + } + +-int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_vif *vif) +-{ +- struct rt2x00_intf *intf = vif_to_intf(vif); +- int ret; +- +- mutex_lock(&intf->beacon_skb_mutex); +- ret = rt2x00queue_update_beacon_locked(rt2x00dev, vif); +- mutex_unlock(&intf->beacon_skb_mutex); +- +- return ret; +-} +- + bool rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, +--- a/drivers/net/wireless/rt2x00/rt2x00queue.h ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.h +@@ -353,6 +353,7 @@ struct txentry_desc { + */ + enum queue_entry_flags { + ENTRY_BCN_ASSIGNED, ++ ENTRY_BCN_ENABLED, + ENTRY_OWNER_DEVICE_DATA, + ENTRY_DATA_PENDING, + ENTRY_DATA_IO_FAILED, +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1757,7 +1757,6 @@ out: + void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) + { + struct ath_vif *avp = (void *)vif->drv_priv; +- unsigned long flags; + u32 tsf; + + if (!sc->p2p_ps_timer) +@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft return; + + sc->p2p_ps_vif = avp; +- +- spin_lock_irqsave(&sc->sc_pm_lock, flags); +- if (!(sc->ps_flags & PS_BEACON_SYNC)) { +- tsf = ath9k_hw_gettsf32(sc->sc_ah); +- ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); +- ath9k_update_p2p_ps_timer(sc, avp); +- } +- spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ++ tsf = ath9k_hw_gettsf32(sc->sc_ah); ++ ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); ++ ath9k_update_p2p_ps_timer(sc, avp); + } + + static void ath9k_bss_info_changed(struct ieee80211_hw *hw, +@@ -1791,6 +1785,7 @@ static void ath9k_bss_info_changed(struc + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; ++ unsigned long flags; + int slottime; + + ath9k_ps_wakeup(sc); +@@ -1853,7 +1848,10 @@ static void ath9k_bss_info_changed(struc + + if (changed & BSS_CHANGED_P2P_PS) { + spin_lock_bh(&sc->sc_pcu_lock); +- ath9k_update_p2p_ps(sc, vif); ++ spin_lock_irqsave(&sc->sc_pm_lock, flags); ++ if (!(sc->ps_flags & PS_BEACON_SYNC)) ++ ath9k_update_p2p_ps(sc, vif); ++ spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + spin_unlock_bh(&sc->sc_pcu_lock); } -- rt2x00queue_pause_queue(queue); -+ rt2x00queue_pause_queue_nocheck(queue); - - queue->rt2x00dev->ops->lib->stop_queue(queue); - ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -31,10 +31,12 @@ - #include "led.h" - - #define IEEE80211_AUTH_TIMEOUT (HZ / 5) -+#define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2) - #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10) - #define IEEE80211_AUTH_MAX_TRIES 3 - #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) - #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) -+#define IEEE80211_ASSOC_TIMEOUT_LONG (HZ / 2) - #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10) - #define IEEE80211_ASSOC_MAX_TRIES 3 - -@@ -209,8 +211,9 @@ ieee80211_determine_chantype(struct ieee - struct ieee80211_channel *channel, - const struct ieee80211_ht_operation *ht_oper, - const struct ieee80211_vht_operation *vht_oper, -- struct cfg80211_chan_def *chandef, bool verbose) -+ struct cfg80211_chan_def *chandef, bool tracking) +@@ -2232,14 +2230,6 @@ static void ath9k_sw_scan_complete(struc + clear_bit(ATH_OP_SCANNING, &common->op_flags); + } + +-static void ath9k_channel_switch_beacon(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct cfg80211_chan_def *chandef) +-{ +- /* depend on vif->csa_active only */ +- return; +-} +- + struct ieee80211_ops ath9k_ops = { + .tx = ath9k_tx, + .start = ath9k_start, +@@ -2287,5 +2277,4 @@ struct ieee80211_ops ath9k_ops = { + #endif + .sw_scan_start = ath9k_sw_scan_start, + .sw_scan_complete = ath9k_sw_scan_complete, +- .channel_switch_beacon = ath9k_channel_switch_beacon, + }; +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -4142,14 +4142,6 @@ static int ath10k_set_bitrate_mask(struc + fixed_nss, force_sgi); + } + +-static void ath10k_channel_switch_beacon(struct ieee80211_hw *hw, +- struct ieee80211_vif *vif, +- struct cfg80211_chan_def *chandef) +-{ +- /* there's no need to do anything here. vif->csa_active is enough */ +- return; +-} +- + static void ath10k_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, +@@ -4256,7 +4248,6 @@ static const struct ieee80211_ops ath10k + .restart_complete = ath10k_restart_complete, + .get_survey = ath10k_get_survey, + .set_bitrate_mask = ath10k_set_bitrate_mask, +- .channel_switch_beacon = ath10k_channel_switch_beacon, + .sta_rc_update = ath10k_sta_rc_update, + .get_tsf = ath10k_get_tsf, + #ifdef CONFIG_PM +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -468,327 +468,6 @@ void sta_set_rate_info_rx(struct sta_inf + rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; + } + +-static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) +-{ +- struct ieee80211_sub_if_data *sdata = sta->sdata; +- struct ieee80211_local *local = sdata->local; +- struct rate_control_ref *ref = local->rate_ctrl; +- struct timespec uptime; +- u64 packets = 0; +- u32 thr = 0; +- int i, ac; +- +- sinfo->generation = sdata->local->sta_generation; +- +- sinfo->filled = STATION_INFO_INACTIVE_TIME | +- STATION_INFO_RX_BYTES64 | +- STATION_INFO_TX_BYTES64 | +- STATION_INFO_RX_PACKETS | +- STATION_INFO_TX_PACKETS | +- STATION_INFO_TX_RETRIES | +- STATION_INFO_TX_FAILED | +- STATION_INFO_TX_BITRATE | +- STATION_INFO_RX_BITRATE | +- STATION_INFO_RX_DROP_MISC | +- STATION_INFO_BSS_PARAM | +- STATION_INFO_CONNECTED_TIME | +- STATION_INFO_STA_FLAGS | +- STATION_INFO_BEACON_LOSS_COUNT; +- +- do_posix_clock_monotonic_gettime(&uptime); +- sinfo->connected_time = uptime.tv_sec - sta->last_connected; +- +- sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); +- sinfo->tx_bytes = 0; +- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- sinfo->tx_bytes += sta->tx_bytes[ac]; +- packets += sta->tx_packets[ac]; +- } +- sinfo->tx_packets = packets; +- sinfo->rx_bytes = sta->rx_bytes; +- sinfo->rx_packets = sta->rx_packets; +- sinfo->tx_retries = sta->tx_retry_count; +- sinfo->tx_failed = sta->tx_retry_failed; +- sinfo->rx_dropped_misc = sta->rx_dropped; +- sinfo->beacon_loss_count = sta->beacon_loss_count; +- +- if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || +- (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { +- sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; +- if (!local->ops->get_rssi || +- drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) +- sinfo->signal = (s8)sta->last_signal; +- sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); +- } +- if (sta->chains) { +- sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | +- STATION_INFO_CHAIN_SIGNAL_AVG; +- +- sinfo->chains = sta->chains; +- for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { +- sinfo->chain_signal[i] = sta->chain_signal_last[i]; +- sinfo->chain_signal_avg[i] = +- (s8) -ewma_read(&sta->chain_signal_avg[i]); +- } +- } +- +- sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); +- sta_set_rate_info_rx(sta, &sinfo->rxrate); +- +- if (ieee80211_vif_is_mesh(&sdata->vif)) { +-#ifdef CPTCFG_MAC80211_MESH +- sinfo->filled |= STATION_INFO_LLID | +- STATION_INFO_PLID | +- STATION_INFO_PLINK_STATE | +- STATION_INFO_LOCAL_PM | +- STATION_INFO_PEER_PM | +- STATION_INFO_NONPEER_PM; +- +- sinfo->llid = sta->llid; +- sinfo->plid = sta->plid; +- sinfo->plink_state = sta->plink_state; +- if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { +- sinfo->filled |= STATION_INFO_T_OFFSET; +- sinfo->t_offset = sta->t_offset; +- } +- sinfo->local_pm = sta->local_pm; +- sinfo->peer_pm = sta->peer_pm; +- sinfo->nonpeer_pm = sta->nonpeer_pm; +-#endif +- } +- +- sinfo->bss_param.flags = 0; +- if (sdata->vif.bss_conf.use_cts_prot) +- sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; +- if (sdata->vif.bss_conf.use_short_preamble) +- sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; +- if (sdata->vif.bss_conf.use_short_slot) +- sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; +- sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; +- sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; +- +- sinfo->sta_flags.set = 0; +- sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | +- BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | +- BIT(NL80211_STA_FLAG_WME) | +- BIT(NL80211_STA_FLAG_MFP) | +- BIT(NL80211_STA_FLAG_AUTHENTICATED) | +- BIT(NL80211_STA_FLAG_ASSOCIATED) | +- BIT(NL80211_STA_FLAG_TDLS_PEER); +- if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); +- if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); +- if (test_sta_flag(sta, WLAN_STA_WME)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); +- if (test_sta_flag(sta, WLAN_STA_MFP)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); +- if (test_sta_flag(sta, WLAN_STA_AUTH)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); +- if (test_sta_flag(sta, WLAN_STA_ASSOC)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); +- if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) +- sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); +- +- /* check if the driver has a SW RC implementation */ +- if (ref && ref->ops->get_expected_throughput) +- thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); +- else +- thr = drv_get_expected_throughput(local, &sta->sta); +- +- if (thr != 0) { +- sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; +- sinfo->expected_throughput = thr; +- } +-} +- +-static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = { +- "rx_packets", "rx_bytes", "wep_weak_iv_count", +- "rx_duplicates", "rx_fragments", "rx_dropped", +- "tx_packets", "tx_bytes", "tx_fragments", +- "tx_filtered", "tx_retry_failed", "tx_retries", +- "beacon_loss", "sta_state", "txrate", "rxrate", "signal", +- "channel", "noise", "ch_time", "ch_time_busy", +- "ch_time_ext_busy", "ch_time_rx", "ch_time_tx" +-}; +-#define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats) +- +-static int ieee80211_get_et_sset_count(struct wiphy *wiphy, +- struct net_device *dev, +- int sset) +-{ +- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +- int rv = 0; +- +- if (sset == ETH_SS_STATS) +- rv += STA_STATS_LEN; +- +- rv += drv_get_et_sset_count(sdata, sset); +- +- if (rv == 0) +- return -EOPNOTSUPP; +- return rv; +-} +- +-static void ieee80211_get_et_stats(struct wiphy *wiphy, +- struct net_device *dev, +- struct ethtool_stats *stats, +- u64 *data) +-{ +- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +- struct ieee80211_chanctx_conf *chanctx_conf; +- struct ieee80211_channel *channel; +- struct sta_info *sta; +- struct ieee80211_local *local = sdata->local; +- struct station_info sinfo; +- struct survey_info survey; +- int i, q; +-#define STA_STATS_SURVEY_LEN 7 +- +- memset(data, 0, sizeof(u64) * STA_STATS_LEN); +- +-#define ADD_STA_STATS(sta) \ +- do { \ +- data[i++] += sta->rx_packets; \ +- data[i++] += sta->rx_bytes; \ +- data[i++] += sta->wep_weak_iv_count; \ +- data[i++] += sta->num_duplicates; \ +- data[i++] += sta->rx_fragments; \ +- data[i++] += sta->rx_dropped; \ +- \ +- data[i++] += sinfo.tx_packets; \ +- data[i++] += sinfo.tx_bytes; \ +- data[i++] += sta->tx_fragments; \ +- data[i++] += sta->tx_filtered_count; \ +- data[i++] += sta->tx_retry_failed; \ +- data[i++] += sta->tx_retry_count; \ +- data[i++] += sta->beacon_loss_count; \ +- } while (0) +- +- /* For Managed stations, find the single station based on BSSID +- * and use that. For interface types, iterate through all available +- * stations and add stats for any station that is assigned to this +- * network device. +- */ +- +- mutex_lock(&local->sta_mtx); +- +- if (sdata->vif.type == NL80211_IFTYPE_STATION) { +- sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); +- +- if (!(sta && !WARN_ON(sta->sdata->dev != dev))) +- goto do_survey; +- +- sinfo.filled = 0; +- sta_set_sinfo(sta, &sinfo); +- +- i = 0; +- ADD_STA_STATS(sta); +- +- data[i++] = sta->sta_state; +- +- +- if (sinfo.filled & STATION_INFO_TX_BITRATE) +- data[i] = 100000 * +- cfg80211_calculate_bitrate(&sinfo.txrate); +- i++; +- if (sinfo.filled & STATION_INFO_RX_BITRATE) +- data[i] = 100000 * +- cfg80211_calculate_bitrate(&sinfo.rxrate); +- i++; +- +- if (sinfo.filled & STATION_INFO_SIGNAL_AVG) +- data[i] = (u8)sinfo.signal_avg; +- i++; +- } else { +- list_for_each_entry(sta, &local->sta_list, list) { +- /* Make sure this station belongs to the proper dev */ +- if (sta->sdata->dev != dev) +- continue; +- +- sinfo.filled = 0; +- sta_set_sinfo(sta, &sinfo); +- i = 0; +- ADD_STA_STATS(sta); +- } +- } +- +-do_survey: +- i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; +- /* Get survey stats for current channel */ +- survey.filled = 0; +- +- rcu_read_lock(); +- chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); +- if (chanctx_conf) +- channel = chanctx_conf->def.chan; +- else +- channel = NULL; +- rcu_read_unlock(); +- +- if (channel) { +- q = 0; +- do { +- survey.filled = 0; +- if (drv_get_survey(local, q, &survey) != 0) { +- survey.filled = 0; +- break; +- } +- q++; +- } while (channel != survey.channel); +- } +- +- if (survey.filled) +- data[i++] = survey.channel->center_freq; +- else +- data[i++] = 0; +- if (survey.filled & SURVEY_INFO_NOISE_DBM) +- data[i++] = (u8)survey.noise; +- else +- data[i++] = -1LL; +- if (survey.filled & SURVEY_INFO_CHANNEL_TIME) +- data[i++] = survey.channel_time; +- else +- data[i++] = -1LL; +- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) +- data[i++] = survey.channel_time_busy; +- else +- data[i++] = -1LL; +- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) +- data[i++] = survey.channel_time_ext_busy; +- else +- data[i++] = -1LL; +- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) +- data[i++] = survey.channel_time_rx; +- else +- data[i++] = -1LL; +- if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) +- data[i++] = survey.channel_time_tx; +- else +- data[i++] = -1LL; +- +- mutex_unlock(&local->sta_mtx); +- +- if (WARN_ON(i != STA_STATS_LEN)) +- return; +- +- drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); +-} +- +-static void ieee80211_get_et_strings(struct wiphy *wiphy, +- struct net_device *dev, +- u32 sset, u8 *data) +-{ +- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +- int sz_sta_stats = 0; +- +- if (sset == ETH_SS_STATS) { +- sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); +- memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); +- } +- drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); +-} +- + static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) { -+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct cfg80211_chan_def vht_chandef; - u32 ht_cfreq, ret; - -@@ -229,7 +232,7 @@ ieee80211_determine_chantype(struct ieee - ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, - channel->band); - /* check that channel matches the right operating channel */ -- if (channel->center_freq != ht_cfreq) { -+ if (!tracking && channel->center_freq != ht_cfreq) { - /* - * It's possible that some APs are confused here; - * Netgear WNDR3700 sometimes reports 4 higher than -@@ -237,11 +240,10 @@ ieee80211_determine_chantype(struct ieee - * since we look at probe response/beacon data here - * it should be OK. - */ -- if (verbose) -- sdata_info(sdata, -- "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", -- channel->center_freq, ht_cfreq, -- ht_oper->primary_chan, channel->band); -+ sdata_info(sdata, -+ "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", -+ channel->center_freq, ht_cfreq, -+ ht_oper->primary_chan, channel->band); - ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; - goto out; - } -@@ -295,7 +297,7 @@ ieee80211_determine_chantype(struct ieee - channel->band); - break; - default: -- if (verbose) -+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT operation IE has invalid channel width (%d), disable VHT\n", - vht_oper->chan_width); -@@ -304,7 +306,7 @@ ieee80211_determine_chantype(struct ieee - } +@@ -875,7 +554,8 @@ static int ieee80211_set_monitor_channel + } - if (!cfg80211_chandef_valid(&vht_chandef)) { -- if (verbose) -+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT information is invalid, disable VHT\n"); - ret = IEEE80211_STA_DISABLE_VHT; -@@ -317,7 +319,7 @@ ieee80211_determine_chantype(struct ieee - } + static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, +- const u8 *resp, size_t resp_len) ++ const u8 *resp, size_t resp_len, ++ const struct ieee80211_csa_settings *csa) + { + struct probe_resp *new, *old; - if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { -- if (verbose) -+ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) - sdata_info(sdata, - "AP VHT information doesn't match HT, disable VHT\n"); - ret = IEEE80211_STA_DISABLE_VHT; -@@ -333,18 +335,27 @@ out: - if (ret & IEEE80211_STA_DISABLE_VHT) - vht_chandef = *chandef; +@@ -891,6 +571,11 @@ static int ieee80211_set_probe_resp(stru + new->len = resp_len; + memcpy(new->data, resp, resp_len); -+ /* -+ * Ignore the DISABLED flag when we're already connected and only -+ * tracking the APs beacon for bandwidth changes - otherwise we -+ * might get disconnected here if we connect to an AP, update our -+ * regulatory information based on the AP's country IE and the -+ * information we have is wrong/outdated and disables the channel -+ * that we're actually using for the connection to the AP. -+ */ - while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, -- IEEE80211_CHAN_DISABLED)) { -+ tracking ? 0 : -+ IEEE80211_CHAN_DISABLED)) { - if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { - ret = IEEE80211_STA_DISABLE_HT | - IEEE80211_STA_DISABLE_VHT; -- goto out; -+ break; - } ++ 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 + } - ret |= chandef_downgrade(chandef); + 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); + + 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, ¶ms->beacon); ++ err = ieee80211_assign_beacon(sdata, ¶ms->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; + +- 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 + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: +- err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); ++ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, ++ NULL); + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + +@@ -3176,6 +2870,7 @@ static int ieee80211_set_csa_beacon(stru + struct cfg80211_csa_settings *params, + u32 *changed) + { ++ struct ieee80211_csa_settings csa = {}; + int err; + + switch (sdata->vif.type) { +@@ -3210,20 +2905,13 @@ static int ieee80211_set_csa_beacon(stru + 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)); ++ 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, ¶ms->beacon_csa); ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); + if (err < 0) { + kfree(sdata->u.ap.next_beacon); + return err; +@@ -3367,7 +3055,6 @@ __ieee80211_channel_switch(struct wiphy + sdata->csa_radar_required = params->radar_required; + sdata->csa_chandef = params->chandef; + sdata->csa_block_tx = params->block_tx; +- sdata->csa_current_counter = params->count; + sdata->vif.csa_active = true; + + if (sdata->csa_block_tx) +@@ -3515,10 +3202,23 @@ static int ieee80211_mgmt_tx(struct wiph + sdata->vif.type == NL80211_IFTYPE_ADHOC) && + params->n_csa_offsets) { + int i; +- u8 c = sdata->csa_current_counter; ++ struct beacon_data *beacon = NULL; ++ ++ rcu_read_lock(); + +- for (i = 0; i < params->n_csa_offsets; i++) +- data[params->csa_offsets[i]] = c; ++ if (sdata->vif.type == NL80211_IFTYPE_AP) ++ beacon = rcu_dereference(sdata->u.ap.beacon); ++ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) ++ beacon = rcu_dereference(sdata->u.ibss.presp); ++ else if (ieee80211_vif_is_mesh(&sdata->vif)) ++ beacon = rcu_dereference(sdata->u.mesh.beacon); ++ ++ if (beacon) ++ for (i = 0; i < params->n_csa_offsets; i++) ++ data[params->csa_offsets[i]] = ++ beacon->csa_current_counter; ++ ++ rcu_read_unlock(); } -- if (chandef->width != vht_chandef.width && verbose) -+ if (chandef->width != vht_chandef.width && !tracking) - sdata_info(sdata, - "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); + IEEE80211_SKB_CB(skb)->flags = flags; +@@ -3598,21 +3298,6 @@ static int ieee80211_get_antenna(struct + return drv_get_antenna(local, tx_ant, rx_ant); + } + +-static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) +-{ +- struct ieee80211_local *local = wiphy_priv(wiphy); +- +- return drv_set_ringparam(local, tx, rx); +-} +- +-static void ieee80211_get_ringparam(struct wiphy *wiphy, +- u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) +-{ +- struct ieee80211_local *local = wiphy_priv(wiphy); +- +- drv_get_ringparam(local, tx, tx_max, rx, rx_max); +-} +- + static int ieee80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +@@ -3844,8 +3529,6 @@ const struct cfg80211_ops mac80211_confi + .mgmt_frame_register = ieee80211_mgmt_frame_register, + .set_antenna = ieee80211_set_antenna, + .get_antenna = ieee80211_get_antenna, +- .set_ringparam = ieee80211_set_ringparam, +- .get_ringparam = ieee80211_get_ringparam, + .set_rekey_data = ieee80211_set_rekey_data, + .tdls_oper = ieee80211_tdls_oper, + .tdls_mgmt = ieee80211_tdls_mgmt, +@@ -3854,9 +3537,6 @@ const struct cfg80211_ops mac80211_confi + #ifdef CONFIG_PM + .set_wakeup = ieee80211_set_wakeup, + #endif +- .get_et_sset_count = ieee80211_get_et_sset_count, +- .get_et_stats = ieee80211_get_et_stats, +- .get_et_strings = ieee80211_get_et_strings, + .get_channel = ieee80211_cfg_get_channel, + .start_radar_detection = ieee80211_start_radar_detection, + .channel_switch = ieee80211_channel_switch, +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -587,7 +587,6 @@ void ieee80211_sta_debugfs_add(struct st + DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count); + DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); + DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); +- DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); + + if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) + debugfs_create_x32("driver_buffered_tids", 0400, +--- a/net/mac80211/wep.c ++++ b/net/mac80211/wep.c +@@ -271,22 +271,6 @@ static int ieee80211_wep_decrypt(struct + return ret; + } + +- +-static bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, +- struct ieee80211_key *key) +-{ +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +- unsigned int hdrlen; +- u8 *ivpos; +- u32 iv; +- +- hdrlen = ieee80211_hdrlen(hdr->frame_control); +- ivpos = skb->data + hdrlen; +- iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; +- +- return ieee80211_wep_weak_iv(iv, key->conf.keylen); +-} +- + ieee80211_rx_result + ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) + { +@@ -301,16 +285,12 @@ ieee80211_crypto_wep_decrypt(struct ieee + if (!(status->flag & RX_FLAG_DECRYPTED)) { + if (skb_linearize(rx->skb)) + return RX_DROP_UNUSABLE; +- if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) +- rx->sta->wep_weak_iv_count++; + if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) + return RX_DROP_UNUSABLE; + } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + + IEEE80211_WEP_IV_LEN)) + return RX_DROP_UNUSABLE; +- if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) +- rx->sta->wep_weak_iv_count++; + ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); + /* remove ICV */ + if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -2278,16 +2278,6 @@ struct cfg80211_qos_map { + * + * @set_noack_map: Set the NoAck Map for the TIDs. + * +- * @get_et_sset_count: Ethtool API to get string-set count. +- * See @ethtool_ops.get_sset_count +- * +- * @get_et_stats: Ethtool API to get a set of u64 stats. +- * See @ethtool_ops.get_ethtool_stats +- * +- * @get_et_strings: Ethtool API to get a set of strings to describe stats +- * and perhaps other supported types of ethtool data-sets. +- * See @ethtool_ops.get_strings +- * + * @get_channel: Get the current operating channel for the virtual interface. + * For monitor interfaces, it should return %NULL unless there's a single + * current monitoring channel. +@@ -2529,13 +2519,6 @@ struct cfg80211_ops { + struct net_device *dev, + u16 noack_map); + +- int (*get_et_sset_count)(struct wiphy *wiphy, +- struct net_device *dev, int sset); +- void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, +- struct ethtool_stats *stats, u64 *data); +- void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, +- u32 sset, u8 *data); +- + int (*get_channel)(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef); +@@ -4846,6 +4829,10 @@ void cfg80211_stop_iface(struct wiphy *w + */ + void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy); -@@ -384,7 +395,7 @@ static int ieee80211_config_bw(struct ie ++ ++/* ethtool helper */ ++void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); ++ + /* Logging, debugging and troubleshooting/diagnostic helpers. */ + + /* 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; + }; - /* calculate new channel (type) based on HT/VHT operation IEs */ - flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, -- vht_oper, &chandef, false); -+ vht_oper, &chandef, true); ++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; + }; - /* - * Downgrade the new channel if we associated with restricted -@@ -3394,10 +3405,13 @@ static int ieee80211_probe_auth(struct i - - if (tx_flags == 0) { - auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; -- ifmgd->auth_data->timeout_started = true; -+ auth_data->timeout_started = true; - run_again(sdata, auth_data->timeout); - } else { -- auth_data->timeout_started = false; -+ auth_data->timeout = -+ round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG); -+ auth_data->timeout_started = true; -+ run_again(sdata, auth_data->timeout); + struct probe_resp { + struct rcu_head rcu_head; + int len; ++ u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; + u8 data[0]; + }; + +@@ -754,8 +767,6 @@ struct ieee80211_sub_if_data { + struct mac80211_qos_map __rcu *qos_map; + + struct work_struct csa_finalize_work; +- u16 csa_counter_offset_beacon[IEEE80211_MAX_CSA_COUNTERS_NUM]; +- u16 csa_counter_offset_presp[IEEE80211_MAX_CSA_COUNTERS_NUM]; + bool csa_radar_required; + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; +@@ -767,7 +778,6 @@ struct ieee80211_sub_if_data { + struct ieee80211_chanctx *reserved_chanctx; + struct cfg80211_chan_def reserved_chandef; + bool reserved_radar_required; +- u8 csa_current_counter; + + /* used to reconfigure hardware SM PS */ + struct work_struct recalc_smps; +@@ -1850,6 +1860,8 @@ int ieee80211_tdls_oper(struct wiphy *wi + const u8 *peer, enum nl80211_tdls_operation oper); + + ++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 +@@ -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; + + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; + +@@ -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; + + sdata->noack_map = 0; + +@@ -1721,6 +1723,8 @@ int ieee80211_if_add(struct ieee80211_lo + + ndev->features |= local->hw.netdev_features; + ++ netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops); ++ + 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" + + /* 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; + +- 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 + #include + #include "core.h" +-#include "ethtool.h" + #include "rdev-ops.h" + +-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 wireless_dev *wdev = dev->ieee80211_ptr; + +@@ -23,84 +21,4 @@ static void cfg80211_get_drvinfo(struct + strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)), + sizeof(info->bus_info)); + } +- +-static int cfg80211_get_regs_len(struct net_device *dev) +-{ +- /* For now, return 0... */ +- return 0; +-} +- +-static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, +- void *data) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- +- regs->version = wdev->wiphy->hw_version; +- regs->len = 0; +-} +- +-static void cfg80211_get_ringparam(struct net_device *dev, +- struct ethtool_ringparam *rp) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); +- +- memset(rp, 0, sizeof(*rp)); +- +- if (rdev->ops->get_ringparam) +- rdev_get_ringparam(rdev, &rp->tx_pending, &rp->tx_max_pending, +- &rp->rx_pending, &rp->rx_max_pending); +-} +- +-static int cfg80211_set_ringparam(struct net_device *dev, +- struct ethtool_ringparam *rp) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); +- +- if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) +- return -EINVAL; +- +- if (rdev->ops->set_ringparam) +- return rdev_set_ringparam(rdev, rp->tx_pending, rp->rx_pending); +- +- return -ENOTSUPP; +-} +- +-static int cfg80211_get_sset_count(struct net_device *dev, int sset) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); +- if (rdev->ops->get_et_sset_count) +- return rdev_get_et_sset_count(rdev, dev, sset); +- return -EOPNOTSUPP; +-} +- +-static void cfg80211_get_stats(struct net_device *dev, +- struct ethtool_stats *stats, u64 *data) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); +- if (rdev->ops->get_et_stats) +- rdev_get_et_stats(rdev, dev, stats, data); +-} +- +-static void cfg80211_get_strings(struct net_device *dev, u32 sset, u8 *data) +-{ +- struct wireless_dev *wdev = dev->ieee80211_ptr; +- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); +- if (rdev->ops->get_et_strings) +- rdev_get_et_strings(rdev, dev, sset, data); +-} +- +-const struct ethtool_ops cfg80211_ethtool_ops = { +- .get_drvinfo = cfg80211_get_drvinfo, +- .get_regs_len = cfg80211_get_regs_len, +- .get_regs = cfg80211_get_regs, +- .get_link = ethtool_op_get_link, +- .get_ringparam = cfg80211_get_ringparam, +- .set_ringparam = cfg80211_set_ringparam, +- .get_strings = cfg80211_get_strings, +- .get_ethtool_stats = cfg80211_get_stats, +- .get_sset_count = cfg80211_get_sset_count, +-}; ++EXPORT_SYMBOL(cfg80211_get_drvinfo); +--- a/net/wireless/ethtool.h ++++ /dev/null +@@ -1,6 +0,0 @@ +-#ifndef __CFG80211_ETHTOOL__ +-#define __CFG80211_ETHTOOL__ +- +-extern const struct ethtool_ops cfg80211_ethtool_ops; +- +-#endif /* __CFG80211_ETHTOOL__ */ +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -714,25 +714,6 @@ static inline int rdev_get_antenna(struc + return ret; + } + +-static inline int rdev_set_ringparam(struct cfg80211_registered_device *rdev, +- u32 tx, u32 rx) +-{ +- int ret; +- trace_rdev_set_ringparam(&rdev->wiphy, tx, rx); +- ret = rdev->ops->set_ringparam(&rdev->wiphy, tx, rx); +- trace_rdev_return_int(&rdev->wiphy, ret); +- return ret; +-} +- +-static inline void rdev_get_ringparam(struct cfg80211_registered_device *rdev, +- u32 *tx, u32 *tx_max, u32 *rx, +- u32 *rx_max) +-{ +- trace_rdev_get_ringparam(&rdev->wiphy); +- rdev->ops->get_ringparam(&rdev->wiphy, tx, tx_max, rx, rx_max); +- trace_rdev_return_void_tx_rx(&rdev->wiphy, *tx, *tx_max, *rx, *rx_max); +-} +- + static inline int + rdev_sched_scan_start(struct cfg80211_registered_device *rdev, + struct net_device *dev, +@@ -816,35 +797,6 @@ static inline int rdev_set_noack_map(str + } + + static inline int +-rdev_get_et_sset_count(struct cfg80211_registered_device *rdev, +- struct net_device *dev, int sset) +-{ +- int ret; +- trace_rdev_get_et_sset_count(&rdev->wiphy, dev, sset); +- ret = rdev->ops->get_et_sset_count(&rdev->wiphy, dev, sset); +- trace_rdev_return_int(&rdev->wiphy, ret); +- return ret; +-} +- +-static inline void rdev_get_et_stats(struct cfg80211_registered_device *rdev, +- struct net_device *dev, +- struct ethtool_stats *stats, u64 *data) +-{ +- trace_rdev_get_et_stats(&rdev->wiphy, dev); +- rdev->ops->get_et_stats(&rdev->wiphy, dev, stats, data); +- trace_rdev_return_void(&rdev->wiphy); +-} +- +-static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, +- struct net_device *dev, u32 sset, +- u8 *data) +-{ +- trace_rdev_get_et_strings(&rdev->wiphy, dev, sset); +- rdev->ops->get_et_strings(&rdev->wiphy, dev, sset, data); +- trace_rdev_return_void(&rdev->wiphy); +-} +- +-static inline int + rdev_get_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -298,11 +298,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_return + TP_ARGS(wiphy) + ); + +-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) + ); + +-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/ethtool.c +@@ -0,0 +1,244 @@ ++/* ++ * mac80211 ethtool hooks for cfg80211 ++ * ++ * Copied from cfg.c - originally ++ * Copyright 2006-2010 Johannes Berg ++ * Copyright 2014 Intel Corporation (Author: Johannes Berg) ++ * ++ * This file is GPLv2 as found in COPYING. ++ */ ++#include ++#include ++#include "ieee80211_i.h" ++#include "sta_info.h" ++#include "driver-ops.h" ++ ++static int ieee80211_set_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *rp) ++{ ++ struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); ++ ++ if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) ++ return -EINVAL; ++ ++ return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending); ++} ++ ++static void ieee80211_get_ringparam(struct net_device *dev, ++ struct ethtool_ringparam *rp) ++{ ++ struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); ++ ++ memset(rp, 0, sizeof(*rp)); ++ ++ drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending, ++ &rp->rx_pending, &rp->rx_max_pending); ++} ++ ++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_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ int rv = 0; ++ ++ if (sset == ETH_SS_STATS) ++ rv += STA_STATS_LEN; ++ ++ rv += drv_get_et_sset_count(sdata, sset); ++ ++ if (rv == 0) ++ return -EOPNOTSUPP; ++ return rv; ++} ++ ++static void ieee80211_get_stats(struct net_device *dev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ieee80211_chanctx_conf *chanctx_conf; ++ struct ieee80211_channel *channel; ++ struct sta_info *sta; ++ struct ieee80211_local *local = sdata->local; ++ struct station_info sinfo; ++ struct survey_info survey; ++ int i, q; ++#define STA_STATS_SURVEY_LEN 7 ++ ++ memset(data, 0, sizeof(u64) * STA_STATS_LEN); ++ ++#define ADD_STA_STATS(sta) \ ++ do { \ ++ data[i++] += sta->rx_packets; \ ++ data[i++] += sta->rx_bytes; \ ++ data[i++] += sta->num_duplicates; \ ++ data[i++] += sta->rx_fragments; \ ++ data[i++] += sta->rx_dropped; \ ++ \ ++ data[i++] += sinfo.tx_packets; \ ++ data[i++] += sinfo.tx_bytes; \ ++ data[i++] += sta->tx_fragments; \ ++ data[i++] += sta->tx_filtered_count; \ ++ data[i++] += sta->tx_retry_failed; \ ++ data[i++] += sta->tx_retry_count; \ ++ data[i++] += sta->beacon_loss_count; \ ++ } while (0) ++ ++ /* For Managed stations, find the single station based on BSSID ++ * and use that. For interface types, iterate through all available ++ * stations and add stats for any station that is assigned to this ++ * network device. ++ */ ++ ++ mutex_lock(&local->sta_mtx); ++ ++ if (sdata->vif.type == NL80211_IFTYPE_STATION) { ++ sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); ++ ++ if (!(sta && !WARN_ON(sta->sdata->dev != dev))) ++ goto do_survey; ++ ++ sinfo.filled = 0; ++ sta_set_sinfo(sta, &sinfo); ++ ++ i = 0; ++ ADD_STA_STATS(sta); ++ ++ data[i++] = sta->sta_state; ++ ++ ++ if (sinfo.filled & STATION_INFO_TX_BITRATE) ++ data[i] = 100000 * ++ cfg80211_calculate_bitrate(&sinfo.txrate); ++ i++; ++ if (sinfo.filled & STATION_INFO_RX_BITRATE) ++ data[i] = 100000 * ++ cfg80211_calculate_bitrate(&sinfo.rxrate); ++ i++; ++ ++ if (sinfo.filled & STATION_INFO_SIGNAL_AVG) ++ data[i] = (u8)sinfo.signal_avg; ++ i++; ++ } else { ++ list_for_each_entry(sta, &local->sta_list, list) { ++ /* Make sure this station belongs to the proper dev */ ++ if (sta->sdata->dev != dev) ++ continue; ++ ++ sinfo.filled = 0; ++ sta_set_sinfo(sta, &sinfo); ++ i = 0; ++ ADD_STA_STATS(sta); ++ } ++ } ++ ++do_survey: ++ i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; ++ /* Get survey stats for current channel */ ++ survey.filled = 0; ++ ++ rcu_read_lock(); ++ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); ++ if (chanctx_conf) ++ channel = chanctx_conf->def.chan; ++ else ++ channel = NULL; ++ rcu_read_unlock(); ++ ++ if (channel) { ++ q = 0; ++ do { ++ survey.filled = 0; ++ if (drv_get_survey(local, q, &survey) != 0) { ++ survey.filled = 0; ++ break; ++ } ++ q++; ++ } while (channel != survey.channel); ++ } ++ ++ if (survey.filled) ++ data[i++] = survey.channel->center_freq; ++ else ++ data[i++] = 0; ++ if (survey.filled & SURVEY_INFO_NOISE_DBM) ++ data[i++] = (u8)survey.noise; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME) ++ data[i++] = survey.channel_time; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) ++ data[i++] = survey.channel_time_busy; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) ++ data[i++] = survey.channel_time_ext_busy; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) ++ data[i++] = survey.channel_time_rx; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) ++ data[i++] = survey.channel_time_tx; ++ else ++ data[i++] = -1LL; ++ ++ mutex_unlock(&local->sta_mtx); ++ ++ if (WARN_ON(i != STA_STATS_LEN)) ++ return; ++ ++ drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); ++} ++ ++static void ieee80211_get_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; ++ ++ 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; ++} ++ ++static void ieee80211_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; ++} ++ ++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; } - return 0; -@@ -3434,7 +3448,11 @@ static int ieee80211_do_assoc(struct iee - assoc_data->timeout_started = true; - run_again(sdata, assoc_data->timeout); +@@ -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; + + /* fix basic_rates if channel does not support these rates */ + rate_flags = ieee80211_chandef_rate_flags(¶ms->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 { -- assoc_data->timeout_started = false; -+ assoc_data->timeout = -+ round_jiffies_up(jiffies + -+ IEEE80211_ASSOC_TIMEOUT_LONG); -+ assoc_data->timeout_started = true; -+ run_again(sdata, assoc_data->timeout); + dfs_cac = $8 } +@@ -114,7 +104,7 @@ function parse_reg_rule() - return 0; -@@ -3829,7 +3847,7 @@ static int ieee80211_prep_channel(struct - ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, - cbss->channel, - ht_oper, vht_oper, -- &chandef, true); -+ &chandef, false); - - sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), - local->rx_chains); ---- a/net/wireless/core.c -+++ b/net/wireless/core.c -@@ -772,6 +772,7 @@ void cfg80211_leave(struct cfg80211_regi - cfg80211_leave_mesh(rdev, dev); + } + 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++ + } + +--- 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; + + 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); + + if (ret >= 0) +@@ -62,8 +61,7 @@ static ssize_t ieee80211_if_write( + + ret = -ENODEV; + rtnl_lock(); +- if (sdata->dev->reg_state == NETREG_REGISTERED) +- ret = (*write)(sdata, buf, count); ++ ret = (*write)(sdata, buf, count); + rtnl_unlock(); + + return ret; +--- a/drivers/net/wireless/b43/xmit.c ++++ b/drivers/net/wireless/b43/xmit.c +@@ -811,9 +811,13 @@ void b43_rx(struct b43_wldev *dev, struc break; - case NL80211_IFTYPE_AP: -+ case NL80211_IFTYPE_P2P_GO: - cfg80211_stop_ap(rdev, dev); + case B43_PHYTYPE_G: + status.band = IEEE80211_BAND_2GHZ; +- /* chanid is the radio channel cookie value as used +- * to tune the radio. */ +- status.freq = chanid + 2400; ++ /* Somewhere between 478.104 and 508.1084 firmware for G-PHY ++ * has been modified to be compatible with N-PHY and others. ++ */ ++ if (dev->fw.rev >= 508) ++ status.freq = ieee80211_channel_to_frequency(chanid, status.band); ++ else ++ status.freq = chanid + 2400; break; - default: ---- a/drivers/net/wireless/rt2x00/rt2800lib.c -+++ b/drivers/net/wireless/rt2x00/rt2800lib.c -@@ -5404,19 +5404,20 @@ int rt2800_enable_radio(struct rt2x00_de - rt2800_init_registers(rt2x00dev))) - return -EIO; + case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -5216,6 +5216,7 @@ static int b43_wireless_core_attach(stru + /* We don't support 5 GHz on some PHYs yet */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: ++ case B43_PHYTYPE_G: + case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: + case B43_PHYTYPE_HT: +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -935,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, + if (!band_rule_found) + band_rule_found = freq_in_rule_band(fr, center_freq); + +- bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5)); ++ bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20)); -+ if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev))) -+ return -EIO; + if (band_rule_found && bw_fits) + return rr; +@@ -1019,10 +1019,10 @@ static void chan_reg_rule_print_dbg(cons + } + #endif + +-/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency +- * chan->center_freq fits there. +- * If there is no such reg_rule, disable the channel, otherwise set the +- * flags corresponding to the bandwidths allowed in the particular reg_rule ++/* ++ * Note that right now we assume the desired channel bandwidth ++ * is always 20 MHz for each individual channel (HT40 uses 20 MHz ++ * per channel, the primary and the extension channel). + */ + static void handle_channel(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator, +@@ -1083,12 +1083,8 @@ static void handle_channel(struct wiphy + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + +- if (max_bandwidth_khz < MHZ_TO_KHZ(10)) +- bw_flags = IEEE80211_CHAN_NO_10MHZ; +- if (max_bandwidth_khz < MHZ_TO_KHZ(20)) +- bw_flags |= IEEE80211_CHAN_NO_20MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(40)) +- bw_flags |= IEEE80211_CHAN_NO_HT40; ++ bw_flags = IEEE80211_CHAN_NO_HT40; + if (max_bandwidth_khz < MHZ_TO_KHZ(80)) + bw_flags |= IEEE80211_CHAN_NO_80MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(160)) +@@ -1522,12 +1518,8 @@ static void handle_channel_custom(struct + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); + +- if (max_bandwidth_khz < MHZ_TO_KHZ(10)) +- bw_flags = IEEE80211_CHAN_NO_10MHZ; +- if (max_bandwidth_khz < MHZ_TO_KHZ(20)) +- bw_flags |= IEEE80211_CHAN_NO_20MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(40)) +- bw_flags |= IEEE80211_CHAN_NO_HT40; ++ bw_flags = IEEE80211_CHAN_NO_HT40; + if (max_bandwidth_khz < MHZ_TO_KHZ(80)) + bw_flags |= IEEE80211_CHAN_NO_80MHZ; + if (max_bandwidth_khz < MHZ_TO_KHZ(160)) +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -185,7 +185,8 @@ struct ath_atx_ac { + + struct ath_frame_info { + struct ath_buf *bf; +- int framelen; ++ u16 framelen; ++ s8 txq; + enum ath9k_key_type keytype; + u8 keyix; + u8 rtscts_rate; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -147,15 +147,13 @@ static void ath_set_rates(struct ieee802 + static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, + struct sk_buff *skb) + { +- int q; +- +- q = skb_get_queue_mapping(skb); +- if (txq == sc->tx.uapsdq) +- txq = sc->tx.txq_map[q]; ++ struct ath_frame_info *fi = get_frame_info(skb); ++ int q = fi->txq; + +- if (txq != sc->tx.txq_map[q]) ++ if (q < 0) + return; + ++ txq = sc->tx.txq_map[q]; + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; + +@@ -887,6 +885,15 @@ ath_tx_get_tid_subframe(struct ath_softc + + tx_info = IEEE80211_SKB_CB(skb); + tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + - /* - * Send signal to firmware during boot time. - */ - rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); -- if (rt2x00_is_usb(rt2x00dev)) { -+ if (rt2x00_is_usb(rt2x00dev)) - rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0); -- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); -- } -+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); - msleep(1); - -- if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) || -- rt2800_wait_bbp_ready(rt2x00dev))) -+ if (unlikely(rt2800_wait_bbp_ready(rt2x00dev))) - return -EIO; - - rt2800_init_bbp(rt2x00dev); ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -101,7 +101,7 @@ static u32 ieee80211_hw_conf_chan(struct - struct ieee80211_sub_if_data *sdata; - struct cfg80211_chan_def chandef = {}; - u32 changed = 0; -- int power; -+ int power = 0; - u32 offchannel_flag; - - offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; -@@ -155,16 +155,16 @@ static u32 ieee80211_hw_conf_chan(struct - changed |= IEEE80211_CONF_CHANGE_SMPS; ++ /* ++ * No aggregation session is running, but there may be frames ++ * from a previous session or a failed attempt in the queue. ++ * Send them out as normal data frames ++ */ ++ if (!tid->active) ++ tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; ++ + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { + bf->bf_state.bf_type = 0; + return bf; +@@ -1999,6 +2006,7 @@ static void setup_frame_info(struct ieee + an = (struct ath_node *) sta->drv_priv; + + memset(fi, 0, sizeof(*fi)); ++ fi->txq = -1; + if (hw_key) + fi->keyix = hw_key->hw_key_idx; + else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) +@@ -2150,6 +2158,7 @@ int ath_tx_start(struct ieee80211_hw *hw + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = txctl->sta; + struct ieee80211_vif *vif = info->control.vif; ++ struct ath_frame_info *fi = get_frame_info(skb); + struct ath_softc *sc = hw->priv; + struct ath_txq *txq = txctl->txq; + struct ath_atx_tid *tid = NULL; +@@ -2170,11 +2179,13 @@ int ath_tx_start(struct ieee80211_hw *hw + q = skb_get_queue_mapping(skb); + + ath_txq_lock(sc, txq); +- if (txq == sc->tx.txq_map[q] && +- ++txq->pending_frames > sc->tx.txq_max_pending[q] && +- !txq->stopped) { +- ieee80211_stop_queue(sc->hw, q); +- txq->stopped = true; ++ if (txq == sc->tx.txq_map[q]) { ++ fi->txq = q; ++ if (++txq->pending_frames > sc->tx.txq_max_pending[q] && ++ !txq->stopped) { ++ ieee80211_stop_queue(sc->hw, q); ++ txq->stopped = true; ++ } } -- power = chandef.chan->max_power; -- - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!rcu_access_pointer(sdata->vif.chanctx_conf)) + if (txctl->an && ieee80211_is_data_present(hdr->frame_control)) +--- a/net/mac80211/chan.c ++++ b/net/mac80211/chan.c +@@ -521,6 +521,8 @@ static void ieee80211_recalc_chanctx_cha continue; -- power = min(power, sdata->vif.bss_conf.txpower); -+ power = max(power, sdata->vif.bss_conf.txpower); - } - rcu_read_unlock(); + if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + continue; ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ continue; + + if (!compat) + compat = &sdata->vif.bss_conf.chandef; +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -1004,9 +1004,11 @@ static bool ar5008_hw_ani_control_new(st + case ATH9K_ANI_FIRSTEP_LEVEL:{ + u32 level = param; + +- value = level; ++ value = level * 2; + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, value); ++ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, ++ AR_PHY_FIND_SIG_FIRSTEP_LOW, value); + + if (level != aniState->firstepLevel) { + ath_dbg(common, ANI, +@@ -1040,9 +1042,8 @@ static bool ar5008_hw_ani_control_new(st + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, value); + +- if (IS_CHAN_HT40(ah->curchan)) +- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, +- AR_PHY_EXT_TIMING5_CYCPWR_THR1, value); ++ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, ++ AR_PHY_EXT_TIMING5_CYCPWR_THR1, value - 1); + + if (level != aniState->spurImmunityLevel) { + ath_dbg(common, ANI, +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -517,6 +517,23 @@ static void ar9003_hw_spur_mitigate(stru + ar9003_hw_spur_mitigate_ofdm(ah, chan); + } -+ power = min(power, chandef.chan->max_power); ++static u32 ar9003_hw_compute_pll_control_soc(struct ath_hw *ah, ++ struct ath9k_channel *chan) ++{ ++ u32 pll; + - if (local->hw.conf.power_level != power) { - changed |= IEEE80211_CONF_CHANGE_POWER; - local->hw.conf.power_level = power; ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -3332,7 +3332,7 @@ static int ieee80211_probe_client(struct - return -EINVAL; - } - band = chanctx_conf->def.chan->band; -- sta = sta_info_get(sdata, peer); -+ sta = sta_info_get_bss(sdata, peer); - if (sta) { - qos = test_sta_flag(sta, WLAN_STA_WME); - } else { ---- a/net/mac80211/status.c -+++ b/net/mac80211/status.c -@@ -180,6 +180,9 @@ static void ieee80211_frame_acked(struct - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata = sta->sdata; ++ pll = SM(0x5, AR_RTC_9300_SOC_PLL_REFDIV); ++ ++ if (chan && IS_CHAN_HALF_RATE(chan)) ++ pll |= SM(0x1, AR_RTC_9300_SOC_PLL_CLKSEL); ++ else if (chan && IS_CHAN_QUARTER_RATE(chan)) ++ pll |= SM(0x2, AR_RTC_9300_SOC_PLL_CLKSEL); ++ ++ pll |= SM(0x2c, AR_RTC_9300_SOC_PLL_DIV_INT); ++ ++ return pll; ++} ++ + static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) + { +@@ -1779,7 +1796,12 @@ void ar9003_hw_attach_phy_ops(struct ath -+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) -+ sta->last_rx = jiffies; + priv_ops->rf_set_freq = ar9003_hw_set_channel; + priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate; +- priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; + - if (ieee80211_is_data_qos(mgmt->frame_control)) { - struct ieee80211_hdr *hdr = (void *) skb->data; - u8 *qc = ieee80211_get_qos_ctl(hdr); ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1101,7 +1101,8 @@ ieee80211_tx_prepare(struct ieee80211_su - tx->sta = rcu_dereference(sdata->u.vlan.sta); - if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) - return TX_DROP; -- } else if (info->flags & IEEE80211_TX_CTL_INJECTED || -+ } else if (info->flags & (IEEE80211_TX_CTL_INJECTED | -+ IEEE80211_TX_INTFL_NL80211_FRAME_TX) || - tx->sdata->control_port_protocol == tx->skb->protocol) { - tx->sta = sta_info_get_bss(sdata, hdr->addr1); ++ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) ++ priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc; ++ else ++ priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; ++ + priv_ops->set_channel_regs = ar9003_hw_set_channel_regs; + priv_ops->init_bb = ar9003_hw_init_bb; + priv_ops->process_ini = ar9003_hw_process_ini; +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -702,6 +702,8 @@ static void ath9k_hw_init_pll(struct ath + { + u32 pll; + ++ pll = ath9k_hw_compute_pll_control(ah, chan); ++ + if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) { + /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ + REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, +@@ -752,7 +754,8 @@ static void ath9k_hw_init_pll(struct ath + REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, + AR_CH0_DPLL3_PHASE_SHIFT, 0x1); + +- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); ++ REG_WRITE(ah, AR_RTC_PLL_CONTROL, ++ pll | AR_RTC_9300_PLL_BYPASS); + udelay(1000); + + /* program refdiv, nint, frac to RTC register */ +@@ -768,7 +771,8 @@ static void ath9k_hw_init_pll(struct ath + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + u32 regval, pll2_divint, pll2_divfrac, refdiv; + +- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); ++ REG_WRITE(ah, AR_RTC_PLL_CONTROL, ++ pll | AR_RTC_9300_SOC_PLL_BYPASS); + udelay(1000); + + REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); +@@ -840,7 +844,6 @@ static void ath9k_hw_init_pll(struct ath + udelay(1000); } + +- pll = ath9k_hw_compute_pll_control(ah, chan); + if (AR_SREV_9565(ah)) + pll |= 0x40000; + REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); +--- a/drivers/net/wireless/ath/ath9k/reg.h ++++ b/drivers/net/wireless/ath/ath9k/reg.h +@@ -1236,12 +1236,23 @@ enum { + #define AR_CH0_DPLL3_PHASE_SHIFT_S 23 + #define AR_PHY_CCA_NOM_VAL_2GHZ -118 + ++#define AR_RTC_9300_SOC_PLL_DIV_INT 0x0000003f ++#define AR_RTC_9300_SOC_PLL_DIV_INT_S 0 ++#define AR_RTC_9300_SOC_PLL_DIV_FRAC 0x000fffc0 ++#define AR_RTC_9300_SOC_PLL_DIV_FRAC_S 6 ++#define AR_RTC_9300_SOC_PLL_REFDIV 0x01f00000 ++#define AR_RTC_9300_SOC_PLL_REFDIV_S 20 ++#define AR_RTC_9300_SOC_PLL_CLKSEL 0x06000000 ++#define AR_RTC_9300_SOC_PLL_CLKSEL_S 25 ++#define AR_RTC_9300_SOC_PLL_BYPASS 0x08000000 ++ + #define AR_RTC_9300_PLL_DIV 0x000003ff + #define AR_RTC_9300_PLL_DIV_S 0 + #define AR_RTC_9300_PLL_REFDIV 0x00003C00 + #define AR_RTC_9300_PLL_REFDIV_S 10 + #define AR_RTC_9300_PLL_CLKSEL 0x0000C000 + #define AR_RTC_9300_PLL_CLKSEL_S 14 ++#define AR_RTC_9300_PLL_BYPASS 0x00010000 + + #define AR_RTC_9160_PLL_DIV 0x000003ff + #define AR_RTC_9160_PLL_DIV_S 0