X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=package%2Fkernel%2Fmac80211%2Fpatches%2F300-pending_work.patch;h=78e3d7cb22e985975970774e1a27d883f8940662;hb=6ea49c5e135e8700ac342c4b5fb1fa5cc460f74c;hp=1a68845aae36657400e4b08dbf077dd023219cb1;hpb=a2068afd77dcde2c3cf274dc73b71b689c5fedc7;p=openwrt%2Fstaging%2Fchunkeey.git diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch index 1a68845aae..78e3d7cb22 100644 --- a/package/kernel/mac80211/patches/300-pending_work.patch +++ b/package/kernel/mac80211/patches/300-pending_work.patch @@ -1,3709 +1,3322 @@ -commit 1abdeca3c6fb9cf1f84f85e78ed8d1c33bd69db0 -Author: Felix Fietkau -Date: Fri Feb 28 18:52:56 2014 +0100 +commit fb77a822cc68745186b38db7d105ad97e0622152 +Author: Johannes Stezenbach +Date: Fri Sep 12 22:36:51 2014 +0200 - ath9k_hw: tweak noise immunity thresholds for older chipsets - - Older chipsets are more sensitive to high PHY error counts, and the - current noise immunity thresholds were based on tests run at QCA with - newer chipsets. + ath9k_htc: fix random decryption failure - This patch brings back the values from the old ANI implementation for - old chipsets, and it also disables weak signal detection on an earlier - noise immunity level, to improve overall radio stability on affected - devices. + In v3.15 the driver stopped to accept network packets after successful + authentification, which could be worked around by passing the + nohwcrypt=1 module parameter. This was not reproducible by + everyone, and showed random behaviour in some tests. + It was caused by an uninitialized variable introduced + in 4ed1a8d4a257 ("ath9k_htc: use ath9k_cmn_rx_accept") and + used in 341b29b9cd2f ("ath9k_htc: use ath9k_cmn_rx_skb_postprocess"). - Signed-off-by: Felix Fietkau + Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=78581 + Fixes: 341b29b9cd2f ("ath9k_htc: use ath9k_cmn_rx_skb_postprocess") + Signed-off-by: Johannes Stezenbach -commit 431e506da5953adc3b65af25f4b90873d528c115 +commit 11f17631d9bf2a9e910dac7d09ba4581f5693831 Author: Felix Fietkau -Date: Fri Feb 28 18:44:13 2014 +0100 +Date: Tue Sep 9 09:48:30 2014 +0200 - ath9k_hw: toggle weak signal detection in AP mode on older chipsets + ath9k_hw: fix PLL clock initialization for newer SoC - The commit 80b4205b "ath9k: Fix OFDM weak signal detection for AP mode" - prevented weak signal detection changes from taking effect in AP mode on - all chipsets, claiming it is "not allowed". + 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. - The main reason for not disabling weak signal detection in AP mode is - that typically beacon RSSI is used to track whether it is needed to - boost range, and this is unavailable in AP mode for obvious reasons. + 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. - The problem with not disabling weak signal detection is that older - chipsets are very sensitive to high PHY error counts. When faced with - heavy noise, this can lead to an excessive amount of "Failed to stop - TX DMA" errors in the field. + 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 98d1a6c5b14688ed030e81b889f607be308e0df9 +commit 0fecedddd4a0945873db1bd230ec6a168b3cc4fe Author: Felix Fietkau -Date: Mon Feb 24 22:20:32 2014 +0100 +Date: Mon Sep 8 18:35:08 2014 +0200 - ath9k: fix invalid descriptor discarding - - Only set sc->rx.discard_next to rx_stats->rs_more when actually - discarding the current descriptor. + ath9k_hw: reduce ANI spur immunity setting on HT40 extension channel - Also, fix a detection of broken descriptors: - First the code checks if the current descriptor is not done. - Then it checks if the next descriptor is done. - Add a check that afterwards checks the first descriptor again, because - it might have been completed in the mean time. + 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. - This fixes a regression introduced in - commit 723e711356b5a8a95728a890e254e8b0d47b55cf - "ath9k: fix handling of broken descriptors" + 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. - Cc: stable@vger.kernel.org - Reported-by: Marco André Dinis Signed-off-by: Felix Fietkau -commit 52a46300e782fe6994466523eb2b0b59091ea59f +commit 30d7434ccb853b96de698a040888fa4dacd0cc19 Author: Felix Fietkau -Date: Mon Feb 24 11:43:50 2014 +0100 +Date: Mon Sep 8 18:31:26 2014 +0200 - ath9k: reduce baseband hang detection false positive rate - - Check if the baseband state remains stable, and add a small delay - between register reads. + Revert "ath9k_hw: reduce ANI firstep range for older chips" - Signed-off-by: Felix Fietkau - -commit 118945bb12082e9d4edddc868d88143164e0f440 -Author: Felix Fietkau -Date: Sat Feb 22 14:55:23 2014 +0100 - - ath5k: set SURVEY_INFO_IN_USE on get_survey + This reverts commit 09efc56345be4146ab9fc87a55c837ed5d6ea1ab - Only one channel is returned - the one currently being used. + 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 ee41f72476e1ea44283dfe1cbf75b9543a1e15c8 +commit 15ed54948f508ad1baad79c30050e2d29a21696d Author: Felix Fietkau -Date: Sat Feb 22 14:44:52 2014 +0100 +Date: Fri Jul 25 16:18:03 2014 +0200 - ath9k: make some hardware reset log messages debug-only + mac80211: fix smps mode check for AP_VLAN - On some chips, baseband watchdog hangs are more common than others, and - the driver has support for handling them. - Interrupts even after a watchdog hang are also quite common, so there's - not much point in spamming the user's logfiles. + 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 b14fbb554fc65a2e0b5c41a319269b0350f187e7 +commit bc74ad816bba291359ae46301173ea744bdda9d2 Author: Felix Fietkau -Date: Sat Feb 22 14:35:25 2014 +0100 +Date: Fri Jul 25 16:15:44 2014 +0200 - ath9k: do not set half/quarter channel flags in AR_PHY_MODE - - 5/10 MHz channel bandwidth is configured via the PLL clock, instead of - the AR_PHY_MODE register. Using that register is AR93xx specific, and - makes the mode incompatible with earlier chipsets. + mac80211: ignore AP_VLAN in ieee80211_recalc_chanctx_chantype - In some early versions, these flags were apparently applied at the wrong - point in time and thus did not cause connectivity issues, however now - they are causing problems, as pointed out in this OpenWrt ticket: - - https://dev.openwrt.org/ticket/14916 + 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 0f1cb7be2551b30b02cd54c897e0e29e483cfda5 +commit ff354dbdd743e5fe186df8cd17982db19f78231a Author: Felix Fietkau -Date: Sat Feb 22 13:43:29 2014 +0100 +Date: Wed Jul 23 15:33:26 2014 +0200 - ath9k: fix ps-poll responses under a-mpdu sessions + ath9k: fix aggregation session lockup - When passing tx frames to the U-APSD queue for powersave poll responses, - the ath_atx_tid pointer needs to be passed to ath_tx_setup_buffer for - proper sequence number accounting. + 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. - This fixes high latency and connection stability issues with ath9k - running as AP and a few kinds of mobile phones as client, when PS-Poll - is heavily used + 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 d5d87a37bbd6066b2c3c5d0bd0fe2a6e2ea45cc5 +commit 38695a6e5a940e6a524523b88a33916b016fb2a1 Author: Felix Fietkau -Date: Fri Feb 21 11:39:59 2014 +0100 +Date: Fri Jul 11 12:06:18 2014 +0200 - ath9k: list more reset causes in debugfs + mac80211: fix crash on getting sta info with uninitialized rate control - Number of MAC hangs and stuck beacons were missing + 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 d84856012e0f10fe598a5ad3b7b869397a089e07 -Author: Johannes Berg -Date: Thu Feb 20 11:19:58 2014 +0100 - - mac80211: fix station wakeup powersave race - - Consider the following (relatively unlikely) scenario: - 1) station goes to sleep while frames are buffered in driver - 2) driver blocks wakeup (until no more frames are buffered) - 3) station wakes up again - 4) driver unblocks wakeup - - In this case, the current mac80211 code will do the following: - 1) WLAN_STA_PS_STA set - 2) WLAN_STA_PS_DRIVER set - 3) - nothing - - 4) WLAN_STA_PS_DRIVER cleared - - As a result, no frames will be delivered to the client, even - though it is awake, until it sends another frame to us that - triggers ieee80211_sta_ps_deliver_wakeup() in sta_ps_end(). - - Since we now take the PS spinlock, we can fix this while at - the same time removing the complexity with the pending skb - queue function. This was broken since my commit 50a9432daeec - ("mac80211: fix powersaving clients races") due to removing - the clearing of WLAN_STA_PS_STA in the RX path. - - While at it, fix a cleanup path issue when a station is - removed while the driver is still blocking its wakeup. - - Signed-off-by: Johannes Berg - -commit 798f2786602cbe93e6b928299614aa36ebf50692 -Author: Johannes Berg -Date: Mon Feb 17 20:49:03 2014 +0100 - - mac80211: insert stations before adding to driver - - There's a race condition in mac80211 because we add stations - to the internal lists after adding them to the driver, which - means that (for example) the following can happen: - 1. a station connects and is added - 2. first, it is added to the driver - 3. then, it is added to the mac80211 lists - - If the station goes to sleep between steps 2 and 3, and the - firmware/hardware records it as being asleep, mac80211 will - never instruct the driver to wake it up again as it never - realized it went to sleep since the RX path discarded the - frame as a "spurious class 3 frame", no station entry was - present yet. - - Fix this by adding the station in software first, and only - then adding it to the driver. That way, any state that the - driver changes will be reflected properly in mac80211's - station state. The problematic part is the roll-back if the - driver fails to add the station, in that case a bit more is - needed. To not make that overly complex prevent starting BA - sessions in the meantime. - - Signed-off-by: Johannes Berg - -commit b9ba6a520cb07ab3aa7aaaf9ce4a0bc7a6bc06fe -Author: Emmanuel Grumbach -Date: Thu Feb 20 09:22:11 2014 +0200 - - mac80211: fix AP powersave TX vs. wakeup race - - There is a race between the TX path and the STA wakeup: while - a station is sleeping, mac80211 buffers frames until it wakes - up, then the frames are transmitted. However, the RX and TX - path are concurrent, so the packet indicating wakeup can be - processed while a packet is being transmitted. - - This can lead to a situation where the buffered frames list - is emptied on the one side, while a frame is being added on - the other side, as the station is still seen as sleeping in - the TX path. - - As a result, the newly added frame will not be send anytime - soon. It might be sent much later (and out of order) when the - station goes to sleep and wakes up the next time. - - Additionally, it can lead to the crash below. - - Fix all this by synchronising both paths with a new lock. - Both path are not fastpath since they handle PS situations. - - In a later patch we'll remove the extra skb queue locks to - reduce locking overhead. - - BUG: unable to handle kernel - NULL pointer dereference at 000000b0 - IP: [] ieee80211_report_used_skb+0x11/0x3e0 [mac80211] - *pde = 00000000 - Oops: 0000 [#1] SMP DEBUG_PAGEALLOC - EIP: 0060:[] EFLAGS: 00210282 CPU: 1 - EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211] - EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000 - ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0 - DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 - CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0 - DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 - DR6: ffff0ff0 DR7: 00000400 - Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000) - iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9 - Stack: - e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0 - ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210 - ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002 - Call Trace: - [] ieee80211_free_txskb+0x15/0x20 [mac80211] - [] invoke_tx_handlers+0x1661/0x1780 [mac80211] - [] ieee80211_tx+0x75/0x100 [mac80211] - [] ieee80211_xmit+0x8f/0xc0 [mac80211] - [] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211] - [] dev_hard_start_xmit+0x450/0x950 - [] sch_direct_xmit+0xa9/0x250 - [] __qdisc_run+0x4b/0x150 - [] dev_queue_xmit+0x2c2/0xca0 - - Cc: stable@vger.kernel.org - Reported-by: Yaara Rozenblum - Signed-off-by: Emmanuel Grumbach - Reviewed-by: Stanislaw Gruszka - [reword commit log, use a separate lock] - Signed-off-by: Johannes Berg - -commit 80e419de0dff38436b30d363311c625766193f86 -Author: Inbal Hacohen -Date: Wed Feb 12 09:32:27 2014 +0200 - - cfg80211: bugfix in regulatory user hint process - - After processing hint_user, we would want to schedule the - timeout work only if we are actually waiting to CRDA. This happens - when the status is not "IGNORE" nor "ALREADY_SET". - - Signed-off-by: Inbal Hacohen - Signed-off-by: Johannes Berg - -commit 6514c93afede55284e2cb63359aadedb85884c80 -Author: Jouni Malinen -Date: Tue Feb 18 20:41:08 2014 +0200 - - ath9k: Enable U-APSD AP mode support - - mac80211 handles the actual operations, so ath9k can just indicate - support for this. Based on initial tests, this combination seems to - work fine. - - Signed-off-by: Jouni Malinen - -commit a63caf0a357ad5c1f08d6b7827dc76c451445017 -Author: Stanislaw Gruszka -Date: Wed Feb 19 13:15:17 2014 +0100 - - ath9k: protect tid->sched check - - We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That - is race condition which can result of doing list_del(&tid->list) twice - (second time with poisoned list node) and cause crash like shown below: - - [424271.637220] BUG: unable to handle kernel paging request at 00100104 - [424271.637328] IP: [] ath_tx_aggr_sleep+0x62/0xe0 [ath9k] - ... - [424271.639953] Call Trace: - [424271.639998] [] ? ath9k_get_survey+0x110/0x110 [ath9k] - [424271.640083] [] ath9k_sta_notify+0x42/0x50 [ath9k] - [424271.640177] [] sta_ps_start+0x8f/0x1c0 [mac80211] - [424271.640258] [] ? free_compound_page+0x2e/0x40 - [424271.640346] [] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211] - [424271.640437] [] ? kmem_cache_free+0x1d8/0x1f0 - [424271.640510] [] ? kfree_skbmem+0x34/0x90 - [424271.640578] [] ? put_page+0x2c/0x40 - [424271.640640] [] ? kfree_skbmem+0x34/0x90 - [424271.640706] [] ? kfree_skbmem+0x34/0x90 - [424271.640787] [] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211] - [424271.640897] [] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211] - [424271.641009] [] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211] - [424271.641104] [] ? ip_output+0x7e/0xd0 - [424271.641182] [] ieee80211_rx+0x307/0x7c0 [mac80211] - [424271.641266] [] ath_rx_tasklet+0x88e/0xf70 [ath9k] - [424271.641358] [] ? ieee80211_rx+0x1dc/0x7c0 [mac80211] - [424271.641445] [] ath9k_tasklet+0xcb/0x130 [ath9k] - - Bug report: - https://bugzilla.kernel.org/show_bug.cgi?id=70551 - - Reported-and-tested-by: Max Sydorenko - Cc: stable@vger.kernel.org - Signed-off-by: Stanislaw Gruszka - -commit 82ed9e3ccc02797df2ffe4b78127c4cd5f799a41 +commit c0ee7fa4c0da824ccccc172bf175fb1f86540921 Author: Felix Fietkau -Date: Tue Feb 11 15:54:13 2014 +0100 +Date: Wed Jul 16 18:00:31 2014 +0200 - mac80211: send control port protocol frames to the VO queue + ath9k: fix pending tx frames accounting - Improves reliability of wifi connections with WPA, since authentication - frames are prioritized over normal traffic and also typically exempt - from aggregation. + 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 d4426800f71e972feaa33e04c5801fc730627bdd -Author: Stanislaw Gruszka -Date: Mon Feb 10 22:38:28 2014 +0100 - - rtl8187: fix regression on MIPS without coherent DMA - - This patch fixes regression caused by commit a16dad77634 "MIPS: Fix - potencial corruption". That commit fixes one corruption scenario in - cost of adding another one, which actually start to cause crashes - on Yeeloong laptop when rtl8187 driver is used. - - For correct DMA read operation on machines without DMA coherence, kernel - have to invalidate cache, such it will refill later with new data that - device wrote to memory, when that data is needed to process. We can only - invalidate full cache line. Hence when cache line includes both dma - buffer and some other data (written in cache, but not yet in main - memory), the other data can not hit memory due to invalidation. That - happen on rtl8187 where struct rtl8187_priv fields are located just - before and after small buffers that are passed to USB layer and DMA - is performed on them. - - To fix the problem we align buffers and reserve space after them to make - them match cache line. - - This patch does not resolve all possible MIPS problems entirely, for - that we have to assure that we always map cache aligned buffers for DMA, - what can be complex or even not possible. But patch fixes visible and - reproducible regression and seems other possible corruptions do not - happen in practice, since Yeeloong laptop works stable without rtl8187 - driver. - - Bug report: - https://bugzilla.kernel.org/show_bug.cgi?id=54391 - - Reported-by: Petr Pisar - Bisected-by: Tom Li - Reported-and-tested-by: Tom Li - Cc: stable@vger.kernel.org - Signed-off-by: Stanislaw Gruszka - -commit e2f141d67ad1e7fe10aaab61811e8a409dfb2442 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:55 2014 +0530 - - ath9k: Calculate IQ-CAL median - - This patch adds a routine to calculate the median IQ correction - values for AR955x, which is used for outlier detection. - The normal method which is used for all other chips is - bypassed for AR955x. - - Signed-off-by: Sujith Manoharan - -commit c52a6fce0820c8d0687443ab86058ae03b478c8f -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:54 2014 +0530 - - ath9k: Expand the IQ coefficient array - - This will be used for storing data for mutiple - IQ calibration runs, for AR955x. - - Signed-off-by: Sujith Manoharan - -commit 034969ff5c2b6431d10e07c1938f0b916da85cc3 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:53 2014 +0530 +commit edcdf0989410a05a6a4b8438df4010447eaa7d9a +Author: Felix Fietkau +Date: Sun Jun 22 13:36:20 2014 +0200 - ath9k: Modify IQ calibration for AR955x - - IQ calibration post-processing for AR955x is different - from other chips - instead of just doing it as part - of AGC calibration once, it is triggered 3 times and - a median is determined. This patch adds initial support - for changing the calibration behavior for AR955x. - - Also, to simplify things, a helper routine to issue/poll - AGC calibration is used. + Revert "cfg80211: Use 5MHz bandwidth by default when checking usable channels" - For non-AR955x chips, the iqcal_idx (which will be used - in subsequent patches) is set to zero. + It enables channels that are not supposed to be enabled according to the + regulatory rules. - Signed-off-by: Sujith Manoharan + This reverts commit 8eca1fb692cc9557f386eddce75c300a3855d11a. -commit 9b1ed6454e6f3511f24266be99b4e403f243f6a8 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:52 2014 +0530 +commit 6e7341074823d2a45b81f2742cbf75f1da790031 +Author: Rafał Miłecki +Date: Sat May 31 19:40:45 2014 +0200 - ath9k: Fix magnitude/phase calculation + b43: disable 5 GHz on G-PHY - Incorrect values are programmed in the registers - containing the IQ correction coefficients by the IQ-CAL - post-processing code. Fix this. + 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 - Signed-off-by: Sujith Manoharan - -commit 36f93484f96f79171dcecb67c5ef0c3de22531a6 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:51 2014 +0530 - - ath9k: Rename ar9003_hw_tx_iqcal_load_avg_2_passes + Regression was introduced by the following commit: - Use ar9003_hw_tx_iq_cal_outlier_detection instead. - - Signed-off-by: Sujith Manoharan - -commit 3af09a7f5d21dd5fd15b973ce6a91a575da30417 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:50 2014 +0530 - - ath9k: Check explicitly for IQ calibration + commit 773cfc508f4d64c14547ff8751b5cbd473124364 + Author: Rafał Miłecki + Date: Mon May 19 23:18:55 2014 +0200 - In chips like AR955x, the initvals contain the information - whether IQ calibration is to be done in the HW when an - AGC calibration is triggered. Check if IQ-CAL is enabled - in the initvals before flagging 'txiqcal_done' as true. + b43: add more devices to the bands database - Signed-off-by: Sujith Manoharan - -commit cb4969634b93c4643a32cc3fbd27d2b288b25771 -Author: Sujith Manoharan -Date: Fri Feb 7 10:29:49 2014 +0530 + Signed-off-by: Rafał Miłecki + Signed-off-by: John W. Linville - ath9k: Fix IQ cal post processing for SoC - - Calibration data is not reused for SoC chips, so - call ar9003_hw_tx_iq_cal_post_proc() with the correct - argument. The 'is_reusable' flag is currently used - only for PC-OEM chips, but it makes things clearer to - specify it explicity. +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] - Signed-off-by: Sujith Manoharan + 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 e138e0ef9560c46ce93dbb22a728a57888e94d1c -Author: Sujith Manoharan -Date: Mon Feb 3 13:31:37 2014 +0530 +commit 5f313a15da92dda80ac4c9a137bc42d7d0b49adf +Author: Rafał Miłecki +Date: Thu Jun 12 09:28:38 2014 +0200 - ath9k: Fix TX power calculation - - The commit, "ath9k_hw: Fix incorrect Tx control power in AR9003 template" - fixed the incorrect values in the eeprom templates, but if - boards have already been calibrated with incorrect values, - they would still be using the wrong TX power. Fix this by assigning - a default value in such cases. - - Cc: Rajkumar Manoharan - Signed-off-by: Sujith Manoharan + b43: fix frequency reported on G-PHY with /new/ firmware -commit b9f268b5b01331c3c82179abca551429450e9417 -Author: Michal Kazior -Date: Wed Jan 29 14:22:27 2014 +0100 +commit d3a58df87a2e4c2301ac843604202d290a48440b +Author: Avraham Stern +Date: Thu May 22 12:17:47 2014 +0300 - cfg80211: consider existing DFS interfaces - - It was possible to break interface combinations in - the following way: - - combo 1: iftype = AP, num_ifaces = 2, num_chans = 2, - combo 2: iftype = AP, num_ifaces = 1, num_chans = 1, radar = HT20 - - With the above interface combinations it was - possible to: + mac80211: set new interfaces as idle upon init - step 1. start AP on DFS channel by matching combo 2 - step 2. start AP on non-DFS channel by matching combo 1 + 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. - This was possible beacuse (step 2) did not consider - if other interfaces require radar detection. - - The patch changes how cfg80211 tracks channels - - instead of channel itself now a complete chandef - is stored. - - Signed-off-by: Michal Kazior - Signed-off-by: Johannes Berg - -commit bc9c62f5f511cc395c62dbf4cdd437f23db53b28 -Author: Antonio Quartulli -Date: Wed Jan 29 17:53:43 2014 +0100 - - cfg80211: fix channel configuration in IBSS join - - When receiving an IBSS_JOINED event select the BSS object - based on the {bssid, channel} couple rather than the bssid - only. - With the current approach if another cell having the same - BSSID (but using a different channel) exists then cfg80211 - picks up the wrong BSS object. - The result is a mismatching channel configuration between - cfg80211 and the driver, that can lead to any sort of - problem. - - The issue can be triggered by having an IBSS sitting on - given channel and then asking the driver to create a new - cell using the same BSSID but with a different frequency. - By passing the channel to cfg80211_get_bss() we can solve - this ambiguity and retrieve/create the correct BSS object. - All the users of cfg80211_ibss_joined() have been changed - accordingly. - - Moreover WARN when cfg80211_ibss_joined() gets a NULL - channel as argument and remove a bogus call of the same - function in ath6kl (it does not make sense to call - cfg80211_ibss_joined() with a zero BSSID on ibss-leave). - - Cc: Kalle Valo - Cc: Arend van Spriel - Cc: Bing Zhao - Cc: Jussi Kivilinna - Cc: libertas-dev@lists.infradead.org - Acked-by: Kalle Valo - Signed-off-by: Antonio Quartulli - [minor code cleanup in ath6kl] + Signed-off-by: Avraham Stern + Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg -commit 7e0c41cb41f215aba2c39b1c237bb4d42ec49a85 -Author: Johannes Berg -Date: Fri Jan 24 14:41:44 2014 +0100 +commit 923eaf367206e01f22c97aee22300e332d071916 +Author: Arik Nemtsov +Date: Mon May 26 14:40:51 2014 +0300 - mac80211: fix bufferable MMPDU RX handling - - Action, disassoc and deauth frames are bufferable, and as such don't - have the PM bit in the frame control field reserved which means we - need to react to the bit when receiving in such a frame. - - Fix this by introducing a new helper ieee80211_is_bufferable_mmpdu() - and using it for the RX path that currently ignores the PM bit in - any non-data frames for doze->wake transitions, but listens to it in - all frames for wake->doze transitions, both of which are wrong. + mac80211: don't check netdev state for debugfs read/write - Also use the new helper in the TX path to clean up the code. + 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 fc0df6d2343636e3f48a069330d5b972e3d8659d -Author: Janusz Dziedzic -Date: Fri Jan 24 14:29:21 2014 +0100 - - cfg80211: set preset_chandef after channel switch - - Set preset_chandef in channel switch notification. - In other case we will have old preset_chandef. - - Signed-off-by: Janusz Dziedzic +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 cdec895e2344987ff171cece96e25d7407a3ebf6 -Author: Simon Wunderlich -Date: Fri Jan 24 23:48:29 2014 +0100 +commit c7d37a66e345df2fdf1aa7b2c9a6d3d53846ca5b +Author: Krzysztof Hałasa +Date: Mon May 26 14:14:46 2014 +0200 - mac80211: send ibss probe responses with noack flag + mac80211: fix IBSS join by initializing last_scan_completed - Responding to probe requests for scanning clients will often create - excessive retries, as it happens quite often that the scanning client - already left the channel. Therefore do it like hostapd and send probe - responses for wildcard SSID only once by using the noack flag. + 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: Simon Wunderlich - [fix typo & 'wildcard SSID' in commit log] + Signed-off-by: Krzysztof Hałasa + [edit commit message slightly] + Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg -commit 0b865d1e6b9c05052adae9315df7cb195dc60c3b -Author: Luciano Coelho -Date: Tue Jan 28 17:09:08 2014 +0200 - - mac80211: ibss: remove unnecessary call to release channel - - The ieee80211_vif_use_channel() function calls - ieee80211_vif_release_channel(), so there's no need to call it - explicitly in __ieee80211_sta_join_ibss(). - - Signed-off-by: Luciano Coelho +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 e1b6c17e971f0a51ff86c2dac2584c63cd999cd7 +commit d93cc72b37b4e2c314e1c499e80e8801907c2fea Author: Michal Kazior -Date: Wed Jan 29 07:56:21 2014 +0100 +Date: Thu Jun 5 14:21:37 2014 +0200 - mac80211: add missing CSA locking + 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. - The patch adds a missing sdata lock and adds a few - lockdeps for easier maintenance. + 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 ad17ba7d14d225b109b73c177cd446afb8050598 +commit d2746694fcdef24e0a7a1947d8c70082cde81a26 Author: Michal Kazior -Date: Wed Jan 29 07:56:20 2014 +0100 +Date: Thu Jun 5 14:21:36 2014 +0200 - mac80211: fix sdata->radar_required locking + mac80211: move csa counters from sdata to beacon/presp - radar_required setting wasn't protected by - local->mtx in some places. This should prevent - from scanning/radar detection/roc colliding. + 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 5fcd5f1808813a3d9e502fd756e01bee8a79c85d -Author: Michal Kazior -Date: Wed Jan 29 07:56:19 2014 +0100 +commit 5dcb54f3a1a8cd7e0331e773487574f9743615db +Author: Janusz Dziedzic +Date: Thu Jun 5 08:12:57 2014 +0200 - mac80211: move csa_active setting in STA CSA + mac80211: allow tx via monitor iface when DFS - The sdata->vif.csa_active could be left set after, - e.g. channel context constraints check fail in STA - mode leaving the interface in a strange state for - a brief period of time until it is disconnected. - This was harmless but ugly. + Allow send frames using monitor interface + when DFS chandef and we pass CAC (beaconing + allowed). - Signed-off-by: Michal Kazior - Reviewed-by: Luciano Coelho + 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 e486da4b7eed71821c6b4c1bb9ac62ffd3ab13e9 -Author: Michal Kazior -Date: Wed Jan 29 07:56:18 2014 +0100 +commit 6f09a1beb0d2007572248c986780562219bd206f +Author: Johannes Berg +Date: Wed Jun 4 17:31:56 2014 +0200 - mac80211: fix possible memory leak on AP CSA failure + cfg80211: make ethtool the driver's responsibility - If CSA for AP interface failed and the interface - was not stopped afterwards another CSA request - would leak sdata->u.ap.next_beacon. + 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. - Signed-off-by: Michal Kazior - Reviewed-by: Luciano Coelho - Signed-off-by: Johannes Berg - -commit 3a77ba08940682bf3d52cf14f980337324af9d4a -Author: Johannes Berg -Date: Sat Feb 1 00:33:29 2014 +0100 - - mac80211: fix fragmentation code, particularly for encryption - - The "new" fragmentation code (since my rewrite almost 5 years ago) - erroneously sets skb->len rather than using skb_trim() to adjust - the length of the first fragment after copying out all the others. - This leaves the skb tail pointer pointing to after where the data - originally ended, and thus causes the encryption MIC to be written - at that point, rather than where it belongs: immediately after the - data. - - The impact of this is that if software encryption is done, then - a) encryption doesn't work for the first fragment, the connection - becomes unusable as the first fragment will never be properly - verified at the receiver, the MIC is practically guaranteed to - be wrong - b) we leak up to 8 bytes of plaintext (!) of the packet out into - the air - - This is only mitigated by the fact that many devices are capable - of doing encryption in hardware, in which case this can't happen - as the tail pointer is irrelevant in that case. Additionally, - fragmentation is not used very frequently and would normally have - to be configured manually. - - Fix this by using skb_trim() properly. + To cleanly implement this in mac80211, introduce a new file and + move some code to appropriate places. - Cc: stable@vger.kernel.org - Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation") - Reported-by: Jouni Malinen Signed-off-by: Johannes Berg -commit de5f242e0c10e841017e37eb8c38974a642dbca8 -Author: Sujith Manoharan -Date: Tue Jan 28 06:21:59 2014 +0530 +commit 6b0c6f133de8f90caeb1c4a902e6140567c5bf96 +Author: Johannes Berg +Date: Wed Jun 4 17:06:23 2014 +0200 - ath9k: Fix build error on ARM + mac80211: remove weak WEP IV accounting - Use mdelay instead of udelay to fix this error: + Since WEP is practically dead, there seems very little + point in keeping WEP weak IV accounting. - ERROR: "__bad_udelay" [drivers/net/wireless/ath/ath9k/ath9k_hw.ko] undefined! - make[1]: *** [__modpost] Error 1 - make: *** [modules] Error 2 - - Reported-by: Josh Boyer - Signed-off-by: Sujith Manoharan + Signed-off-by: Johannes Berg -commit 8e3ea7a51dfc61810fcefd947f6edcf61125252a -Author: Geert Uytterhoeven -Date: Sun Jan 26 11:53:21 2014 +0100 +commit aecdc89fb4664c76baa4bbd46008f220532309ff +Author: Luciano Coelho +Date: Fri May 23 11:04:50 2014 +0300 - ath9k: Fix uninitialized variable in ath9k_has_tx_pending() - - drivers/net/wireless/ath/ath9k/main.c: In function ‘ath9k_has_tx_pending’: - drivers/net/wireless/ath/ath9k/main.c:1869: warning: ‘npend’ may be used uninitialized in this function + ath9k/ath10k: remove unnecessary channel_switch_beacon callbacks - Introduced by commit 10e2318103f5941aa70c318afe34bc41f1b98529 ("ath9k: - optimize ath9k_flush"). + The channel_switch_beacon callback is optional, so it doesn't have to + be defined if it's not going to do anything useful with it. Both + ath9k and ath10k define the callback and just returns. This commit + removes them. - Signed-off-by: Geert Uytterhoeven + Cc: Michal Kazior + Signed-off-by: Luciano Coelho + Signed-off-by: Kalle Valo -commit a4a634a6937ebdd827fa58e8fcdb8ca49a3769f6 -Author: Emmanuel Grumbach -Date: Mon Jan 27 11:07:42 2014 +0200 +commit 60ccc107c9b9fb732fdee1f76bb2dad44f0e1798 +Author: Rajkumar Manoharan +Date: Tue May 27 16:58:02 2014 +0530 - mac80211: release the channel in error path in start_ap + ath9k: Fix deadlock while updating p2p beacon timer - When the driver cannot start the AP or when the assignement - of the beacon goes wrong, we need to unassign the vif. - - Cc: stable@vger.kernel.org - Signed-off-by: Emmanuel Grumbach - Signed-off-by: Johannes Berg - -commit dfb6889a75c601aedb7450b7e606668e77da6679 -Author: Johannes Berg -Date: Wed Jan 22 11:14:19 2014 +0200 - - cfg80211: send scan results from work queue - - Due to the previous commit, when a scan finishes, it is in theory - possible to hit the following sequence: - 1. interface starts being removed - 2. scan is cancelled by driver and cfg80211 is notified - 3. scan done work is scheduled - 4. interface is removed completely, rdev->scan_req is freed, - event sent to userspace but scan done work remains pending - 5. new scan is requested on another virtual interface - 6. scan done work runs, freeing the still-running scan - - To fix this situation, hang on to the scan done message and block - new scans while that is the case, and only send the message from - the work function, regardless of whether the scan_req is already - freed from interface removal. This makes step 5 above impossible - and changes step 6 to be - 5. scan done work runs, sending the scan done message - - As this can't work for wext, so we send the message immediately, - but this shouldn't be an issue since we still return -EBUSY. + pm_lock is taken twice while syncing HW TSF of p2p vif. + Fix this by taking the lock at caller side. - Signed-off-by: Johannes Berg + Cc: Felix Fietkau + Signed-off-by: Rajkumar Manoharan + Signed-off-by: John W. Linville -commit 45b7ab41fc08627d9a8428cb413d5d84662a9707 -Author: Johannes Berg -Date: Wed Jan 22 11:14:18 2014 +0200 +commit f3831a4e3903dbc1a57d5df56deb6a143fd001bc +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:27 2014 +0200 - cfg80211: fix scan done race - - When an interface/wdev is removed, any ongoing scan should be - cancelled by the driver. This will make it call cfg80211, which - only queues a work struct. If interface/wdev removal is quick - enough, this can leave the scan request pending and processed - only after the interface is gone, causing a use-after-free. + rt2x00: do not initialize BCN_OFFSET registers - Fix this by making sure the scan request is not pending after - the interface is destroyed. We can't flush or cancel the work - item due to locking concerns, but when it'll run it shouldn't - find anything to do. This leaves a potential issue, if a new - scan gets requested before the work runs, it prematurely stops - the running scan, potentially causing another crash. I'll fix - that in the next patch. + We setup BCN_OFFSET{0,1} registers dynamically, don't have to + initialize them. - This was particularly observed with P2P_DEVICE wdevs, likely - because freeing them is quicker than freeing netdevs. - - Reported-by: Andrei Otcheretianski - Fixes: 4a58e7c38443 ("cfg80211: don't "leak" uncompleted scans") - Signed-off-by: Johannes Berg - -commit ae04fa489ab31b5a10d3cc8399f52761175d4321 -Author: Emmanuel Grumbach -Date: Thu Jan 23 14:28:16 2014 +0200 - - mac80211: avoid deadlock revealed by lockdep - - sdata->u.ap.request_smps_work can’t be flushed synchronously - under wdev_lock(wdev) since ieee80211_request_smps_ap_work - itself locks the same lock. - While at it, reset the driver_smps_mode when the ap is - stopped to its default: OFF. - - This solves: - - ====================================================== - [ INFO: possible circular locking dependency detected ] - 3.12.0-ipeer+ #2 Tainted: G O - ------------------------------------------------------- - rmmod/2867 is trying to acquire lock: - ((&sdata->u.ap.request_smps_work)){+.+...}, at: [] flush_work+0x0/0x90 - - but task is already holding lock: - (&wdev->mtx){+.+.+.}, at: [] cfg80211_stop_ap+0x26/0x230 [cfg80211] - - which lock already depends on the new lock. - - the existing dependency chain (in reverse order) is: - - -> #1 (&wdev->mtx){+.+.+.}: - [] lock_acquire+0x79/0xe0 - [] mutex_lock_nested+0x4a/0x360 - [] ieee80211_request_smps_ap_work+0x2b/0x50 [mac80211] - [] process_one_work+0x198/0x450 - [] worker_thread+0xf9/0x320 - [] kthread+0x9f/0xb0 - [] ret_from_kernel_thread+0x1b/0x28 - - -> #0 ((&sdata->u.ap.request_smps_work)){+.+...}: - [] __lock_acquire+0x183f/0x1910 - [] lock_acquire+0x79/0xe0 - [] flush_work+0x47/0x90 - [] __cancel_work_timer+0x67/0xe0 - [] cancel_work_sync+0xf/0x20 - [] ieee80211_stop_ap+0x8c/0x340 [mac80211] - [] cfg80211_stop_ap+0x8c/0x230 [cfg80211] - [] cfg80211_leave+0x79/0x100 [cfg80211] - [] cfg80211_netdev_notifier_call+0xf2/0x4f0 [cfg80211] - [] notifier_call_chain+0x59/0x130 - [] __raw_notifier_call_chain+0x1e/0x30 - [] raw_notifier_call_chain+0x1f/0x30 - [] call_netdevice_notifiers_info+0x33/0x70 - [] call_netdevice_notifiers+0x13/0x20 - [] __dev_close_many+0x34/0xb0 - [] dev_close_many+0x6e/0xc0 - [] rollback_registered_many+0xa7/0x1f0 - [] unregister_netdevice_many+0x14/0x60 - [] ieee80211_remove_interfaces+0xe9/0x170 [mac80211] - [] ieee80211_unregister_hw+0x56/0x110 [mac80211] - [] iwl_op_mode_mvm_stop+0x26/0xe0 [iwlmvm] - [] _iwl_op_mode_stop+0x3a/0x70 [iwlwifi] - [] iwl_opmode_deregister+0x6f/0x90 [iwlwifi] - [] __exit_compat+0xd/0x19 [iwlmvm] - [] SyS_delete_module+0x179/0x2b0 - [] sysenter_do_call+0x12/0x32 - - Fixes: 687da132234f ("mac80211: implement SMPS for AP") - Cc: [3.13] - Reported-by: Ilan Peer - Signed-off-by: Emmanuel Grumbach - Signed-off-by: Johannes Berg + Signed-off-by: Stanislaw Gruszka -commit 178b205e96217164fd7c30113464250d0b6f5eca -Author: Johannes Berg -Date: Thu Jan 23 16:32:29 2014 +0100 +commit e5c58ca7a48d4c82f282749a978052c47fd95998 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:26 2014 +0200 - cfg80211: re-enable 5/10 MHz support + rt2x00: change order when stop beaconing - Unfortunately I forgot this during the merge window, but the - patch seems small enough to go in as a fix. The userspace API - bug that was the reason for disabling it has long been fixed. + 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: Johannes Berg + Signed-off-by: Stanislaw Gruszka -commit 110a1c79acda14edc83b7c8dc5af9c7ddd23eb61 -Author: Pontus Fuchs -Date: Thu Jan 16 15:00:40 2014 +0100 +commit 382c1b9e03f52d0cd741ef1d942cad0f649f0744 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:25 2014 +0200 - nl80211: Reset split_start when netlink skb is exhausted - - When the netlink skb is exhausted split_start is left set. In the - subsequent retry, with a larger buffer, the dump is continued from the - failing point instead of from the beginning. + rt2x00: change default MAC_BSSID_DW1_BSS_BCN_NUM - This was causing my rt28xx based USB dongle to now show up when - running "iw list" with an old iw version without split dump support. + 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. - Cc: stable@vger.kernel.org - Fixes: 3713b4e364ef ("nl80211: allow splitting wiphy information in dumps") - Signed-off-by: Pontus Fuchs - [avoid the entire workaround when state->split is set] - Signed-off-by: Johannes Berg + Signed-off-by: Stanislaw Gruszka -commit b4c31b45ffc7ef110fa9ecc34d7878fe7c5b9da4 -Author: Eliad Peller -Date: Sun Jan 12 11:06:37 2014 +0200 +commit 3b400571dd033e46fa7e76c5bb92a3ce8198afa9 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:24 2014 +0200 - mac80211: move roc cookie assignment earlier + rt2x00: change beaconing setup on RT2800 - ieee80211_start_roc_work() might add a new roc - to existing roc, and tell cfg80211 it has already - started. + 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. - However, this might happen before the roc cookie - was set, resulting in REMAIN_ON_CHANNEL (started) - event with null cookie. Consequently, it can make - wpa_supplicant go out of sync. + 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. - Fix it by setting the roc cookie earlier. - - Cc: stable@vger.kernel.org - Signed-off-by: Eliad Peller - Signed-off-by: Johannes Berg + Reported-by: Matthias Fend + Signed-off-by: Stanislaw Gruszka -commit cfdc9157bfd7bcf88ab4dae08873a9907eba984c -Author: Johannes Berg -Date: Fri Jan 24 14:06:29 2014 +0100 +commit 916e591b2cc41f7e572992175ca56d866d7bc958 +Author: Stanislaw Gruszka +Date: Thu Jun 5 13:52:23 2014 +0200 - nl80211: send event when AP operation is stopped + rt2x00: change beaconing locking - There are a few cases, e.g. suspend, where an AP interface is - stopped by the kernel rather than by userspace request, most - commonly when suspending. To let userspace know about this, - send the NL80211_CMD_STOP_AP command as an event every time - an AP interface is stopped. This also happens when userspace - did in fact request the AP stop, but that's not a problem. + This patch is needed for further changes to keep global variables + consistent when changing beaconing on diffrent vif's. - For full-MAC drivers this may need to be extended to also - cover cases where the device stopped the AP operation for - some reason, this a bit more complicated because then all - cfg80211 state also needs to be reset; such API is not part - of this patch. - - Signed-off-by: Johannes Berg + Signed-off-by: Stanislaw Gruszka -commit d5d567eda7704f190379ca852a8f9a4112e3eee3 +commit 930b0dffd1731f3f418f9132faea720a23b7af61 Author: Johannes Berg -Date: Thu Jan 23 16:20:29 2014 +0100 - - mac80211: add length check in ieee80211_is_robust_mgmt_frame() - - A few places weren't checking that the frame passed to the - function actually has enough data even though the function - clearly documents it must have a payload byte. Make this - safer by changing the function to take an skb and checking - the length inside. The old version is preserved for now as - the rtl* drivers use it and don't have a correct skb. +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 f8f6d212a047fc65c7d3442dfc038f65517236fc -Author: Johannes Berg -Date: Fri Jan 24 10:53:53 2014 +0100 +commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873 +Author: Felix Fietkau +Date: Fri May 23 19:58:14 2014 +0200 - nl80211: fix scheduled scan RSSI matchset attribute confusion + mac80211: reduce packet loss notifications under load - The scheduled scan matchsets were intended to be a list of filters, - with the found BSS having to pass at least one of them to be passed - to the host. When the RSSI attribute was added, however, this was - broken and currently wpa_supplicant adds that attribute in its own - matchset; however, it doesn't intend that to mean that anything - that passes the RSSI filter should be passed to the host, instead - it wants it to mean that everything needs to also have higher RSSI. + During strong signal fluctuations under high throughput, few consecutive + failed A-MPDU transmissions can easily trigger packet loss notification, + and thus (in AP mode) client disconnection. - This is semantically problematic because we have a list of filters - like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which - one should be OR'ed and which one AND'ed. + Reduce the number of false positives by checking the A-MPDU status flag + and treating a failed A-MPDU as a single packet. - To fix this, move the RSSI filter attribute into each matchset. As - we need to stay backward compatible, treat a matchset with only the - RSSI attribute as a "default RSSI filter" for all other matchsets, - but only if there are other matchsets (an RSSI-only matchset by - itself is still desirable.) - - To make driver implementation easier, keep a global min_rssi_thold - for the entire request as well. The only affected driver is ath6kl. - - I found this when I looked into the code after Raja Mani submitted - a patch fixing the n_match_sets calculation to disregard the RSSI, - but that patch didn't address the semantic issue. + 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 - Reported-by: Raja Mani - Acked-by: Luciano Coelho - Signed-off-by: Johannes Berg + Cc: stable@vger.kernel.org + Reported-by: Christophe Prévotaux + Signed-off-by: Felix Fietkau -commit de553e8545e65a6dc4e45f43df7e1443d4291922 -Author: Johannes Berg -Date: Fri Jan 24 10:17:47 2014 +0100 +commit 96892d6aa0a153423070addf3070bc79578b3897 +Author: Felix Fietkau +Date: Mon May 19 21:20:49 2014 +0200 - nl80211: check nla_parse() return values + ath9k: avoid passing buffers to the hardware during flush - If there's a policy, then nla_parse() return values must be - checked, otherwise the policy is useless and there's nothing - that ensures the attributes are actually what we expect them - to be. + The commit "ath9k: fix possible hang on flush" changed the receive code + to always link rx descriptors of processed frames, even when flushing. + In some cases, this leads to flushed rx buffers being passed to the + hardware while rx is already stopped. - Signed-off-by: Johannes Berg + Signed-off-by: Felix Fietkau -commit 652204a0733e9e1c54661d6f9d36e2e1e3b22bb1 -Author: Karl Beldan -Date: Thu Jan 23 20:06:34 2014 +0100 - - mac80211: send {ADD,DEL}BA on AC_VO like other mgmt frames, as per spec - - ATM, {ADD,DEL}BA and BAR frames are sent on the AC matching the TID of - the BA parameters. In the discussion [1] about this patch, Johannes - recalled that it fixed some races with the DELBA and indeed this - behavior was introduced in [2]. - While [2] is right for the BARs, the part queueing the {ADD,DEL}BAs on - their BA params TID AC violates the spec and is more a workaround for - some drivers. Helmut expressed some concerns wrt such drivers, in - particular DELBAs in rt2x00. - - ATM, DELBAs are sent after a driver has called (hence "purposely") - ieee80211_start_tx_ba_cb_irqsafe and Johannes and Emmanuel gave some - details wrt intentions behind the split of the IEEE80211_AMPDU_TX_STOP_* - given to the driver ampdu_action supposed to call this function, which - could prove handy to people trying to do the right thing in faulty - drivers (if their fw/hw don't get in their way). - - [1] http://mid.gmane.org/1390391564-18481-1-git-send-email-karl.beldan@gmail.com - [2] Commit: cf6bb79ad828 ("mac80211: Use appropriate TID for sending BAR, ADDBA and DELBA frames") - - Signed-off-by: Karl Beldan - Cc: Helmut Schaa - Cc: Emmanuel Grumbach - Signed-off-by: Johannes Berg ---- a/drivers/net/wireless/ath/ath6kl/cfg80211.c -+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c -@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struc - if (nw_type & ADHOC_NETWORK) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n", - nw_type & ADHOC_CREATOR ? "creator" : "joiner"); -- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); -+ cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL); - cfg80211_put_bss(ar->wiphy, bss); - return; - } -@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(st - } - - if (vif->nw_type & ADHOC_NETWORK) { -- if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) { -+ if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, - "%s: ath6k not in ibss mode\n", __func__); -- return; -- } -- memset(bssid, 0, ETH_ALEN); -- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL); - return; - } - -@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(s - struct ath6kl_vif *vif = netdev_priv(dev); - u16 interval; - int ret, rssi_thold; -+ int n_match_sets = request->n_match_sets; -+ -+ /* -+ * If there's a matchset w/o an SSID, then assume it's just for -+ * the RSSI (nothing else is currently supported) and ignore it. -+ * The device only supports a global RSSI filter that we set below. -+ */ -+ if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len) -+ n_match_sets = 0; - - if (ar->state != ATH6KL_STATE_ON) - return -EIO; -@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(s - ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, - request->n_ssids, - request->match_sets, -- request->n_match_sets); -+ n_match_sets); - if (ret < 0) - return ret; - -- if (!request->n_match_sets) { -+ if (!n_match_sets) { - ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, - ALL_BSS_FILTER, 0); - if (ret < 0) -@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(s - - if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, - ar->fw_capabilities)) { -- if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) -+ if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF) - rssi_thold = 0; -- else if (request->rssi_thold < -127) -+ else if (request->min_rssi_thold < -127) - rssi_thold = -127; - else -- rssi_thold = request->rssi_thold; -+ rssi_thold = request->min_rssi_thold; - - ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx, - rssi_thold); ---- a/drivers/net/wireless/ath/ath9k/hw.c -+++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -1316,7 +1316,7 @@ static bool ath9k_hw_set_reset(struct at - if (AR_SREV_9300_20_OR_LATER(ah)) - udelay(50); - else if (AR_SREV_9100(ah)) -- udelay(10000); -+ mdelay(10); - else - udelay(100); +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee + * buffer (or rx fifo). This can incorrectly acknowledge packets + * to a sender if last desc is self-linked. + */ +-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf) ++static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, ++ bool flush) + { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); +@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s + common->rx_bufsize, + 0); + +- if (sc->rx.rxlink == NULL) +- ath9k_hw_putrxbuf(ah, bf->bf_daddr); +- else ++ if (sc->rx.rxlink) + *sc->rx.rxlink = bf->bf_daddr; ++ else if (!flush) ++ ath9k_hw_putrxbuf(ah, bf->bf_daddr); + + sc->rx.rxlink = &ds->ds_link; + } -@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav); - bool ath9k_hw_check_alive(struct ath_hw *ah) +-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf) ++static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, ++ bool flush) { - int count = 50; -- u32 reg; -+ u32 reg, last_val; - - if (AR_SREV_9300(ah)) - return !ath9k_hw_detect_mac_hang(ah); -@@ -1542,9 +1542,13 @@ bool ath9k_hw_check_alive(struct ath_hw - if (AR_SREV_9285_12_OR_LATER(ah)) - return true; - -+ last_val = REG_READ(ah, AR_OBS_BUS_1); - do { - reg = REG_READ(ah, AR_OBS_BUS_1); -+ if (reg != last_val) -+ return true; - -+ last_val = reg; - if ((reg & 0x7E7FFFEF) == 0x00702400) - continue; + 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); + } -@@ -1556,6 +1560,8 @@ bool ath9k_hw_check_alive(struct ath_hw - default: - return true; + /* 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); } -+ -+ udelay(1); - } while (count-- > 0); - return false; -@@ -2051,9 +2057,8 @@ static bool ath9k_hw_set_power_awake(str + 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; - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); -- - if (AR_SREV_9100(ah)) -- udelay(10000); -+ mdelay(10); - else - udelay(50); + if (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 ---- a/drivers/net/wireless/ath/ath9k/main.c -+++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -451,7 +451,7 @@ void ath9k_tasklet(unsigned long data) - * interrupts are enabled in the reset routine. - */ - atomic_inc(&ah->intr_ref_cnt); -- ath_dbg(common, ANY, "FATAL: Skipping interrupts\n"); -+ ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); - goto out; - } + clear_sta_flag(sta, WLAN_STA_PS_STA); + clear_sta_flag(sta, WLAN_STA_PS_DRIVER); ++ clear_sta_flag(sta, WLAN_STA_PS_DELIVER); -@@ -471,7 +471,7 @@ void ath9k_tasklet(unsigned long data) - * interrupts are enabled in the reset routine. - */ - atomic_inc(&ah->intr_ref_cnt); -- ath_dbg(common, ANY, -+ ath_dbg(common, RESET, - "BB_WATCHDOG: Skipping interrupts\n"); - goto out; - } -@@ -484,7 +484,7 @@ void ath9k_tasklet(unsigned long data) - type = RESET_TYPE_TX_GTT; - ath9k_queue_reset(sc, type); - atomic_inc(&ah->intr_ref_cnt); -- ath_dbg(common, ANY, -+ ath_dbg(common, RESET, - "GTT: Skipping interrupts\n"); - goto out; - } -@@ -1866,7 +1866,7 @@ static void ath9k_set_coverage_class(str + 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); - static bool ath9k_has_tx_pending(struct ath_softc *sc) +- cancel_work_sync(&sta->drv_unblock_wk); ++ cancel_work_sync(&sta->drv_deliver_wk); + + /* + * 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) { -- int i, npend; -+ int i, npend = 0; - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) ---- a/drivers/net/wireless/iwlwifi/mvm/scan.c -+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c -@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid( - * config match list. - */ - for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) { -+ /* skip empty SSID matchsets */ -+ if (!req->match_sets[i].ssid.ssid_len) -+ continue; - scan->direct_scan[i].id = WLAN_EID_SSID; - scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; - memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, ---- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c -+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c -@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80 - /* During testing, hdr was NULL */ - return false; - } -- if ((ieee80211_is_robust_mgmt_frame(hdr)) && -+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) && - (ieee80211_has_protected(hdr->frame_control))) - rx_status->flag &= ~RX_FLAG_DECRYPTED; - else ---- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c -+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c -@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80 - /* In testing, hdr was NULL here */ - return false; - } -- if ((ieee80211_is_robust_mgmt_frame(hdr)) && -+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) && - (ieee80211_has_protected(hdr->frame_control))) - rx_status->flag &= ~RX_FLAG_DECRYPTED; - else ---- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c -+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c -@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80 - /* during testing, hdr was NULL here */ - return false; - } -- if ((ieee80211_is_robust_mgmt_frame(hdr)) && -+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) && - (ieee80211_has_protected(hdr->frame_control))) - rx_status->flag &= ~RX_FLAG_DECRYPTED; - else ---- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c -+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c -@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee - /* during testing, hdr could be NULL here */ - return false; - } -- if ((ieee80211_is_robust_mgmt_frame(hdr)) && -+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) && - (ieee80211_has_protected(hdr->frame_control))) - rx_status->flag &= ~RX_FLAG_DECRYPTED; - else ---- a/include/linux/ieee80211.h -+++ b/include/linux/ieee80211.h -@@ -597,6 +597,20 @@ static inline int ieee80211_is_qos_nullf - } ++ struct ieee80211_sta_rates *rates; + int i; - /** -+ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU -+ * @fc: frame control field in little-endian byteorder -+ */ -+static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc) -+{ -+ /* IEEE 802.11-2012, definition of "bufferable management frame"; -+ * note that this ignores the IBSS special case. */ -+ return ieee80211_is_mgmt(fc) && -+ (ieee80211_is_action(fc) || -+ ieee80211_is_disassoc(fc) || -+ ieee80211_is_deauth(fc)); -+} + 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); + -+/** - * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set - * @seq_ctrl: frame sequence control bytes in little-endian byteorder - */ -@@ -2192,10 +2206,10 @@ static inline u8 *ieee80211_get_DA(struc + 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); } - /** -- * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame -+ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame - * @hdr: the frame (buffer must include at least the first octet of payload) - */ --static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) -+static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) +-static void sta_unblock(struct work_struct *wk) ++static void sta_deliver_ps_frames(struct work_struct *wk) { - if (ieee80211_is_disassoc(hdr->frame_control) || - ieee80211_is_deauth(hdr->frame_control)) -@@ -2224,6 +2238,17 @@ static inline bool ieee80211_is_robust_m - } + struct sta_info *sta; - /** -+ * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame -+ * @skb: the skb containing the frame, length will be checked -+ */ -+static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb) -+{ -+ if (skb->len < 25) -+ return false; -+ return _ieee80211_is_robust_mgmt_frame((void *)skb->data); -+} -+ -+/** - * ieee80211_is_public_action - check if frame is a public action frame - * @hdr: the frame - * @len: length of the frame ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -1395,9 +1395,11 @@ struct cfg80211_scan_request { - * struct cfg80211_match_set - sets of attributes to match - * - * @ssid: SSID to be matched -+ * @rssi_thold: don't report scan results below this threshold (in s32 dBm) - */ - struct cfg80211_match_set { - struct cfg80211_ssid ssid; -+ s32 rssi_thold; - }; +- sta = container_of(wk, struct sta_info, drv_unblock_wk); ++ sta = container_of(wk, struct sta_info, drv_deliver_wk); - /** -@@ -1420,7 +1422,8 @@ struct cfg80211_match_set { - * @dev: the interface - * @scan_start: start time of the scheduled scan - * @channels: channels to scan -- * @rssi_thold: don't report scan results below this threshold (in s32 dBm) -+ * @min_rssi_thold: for drivers only supporting a single threshold, this -+ * contains the minimum over all matchsets - */ - struct cfg80211_sched_scan_request { - struct cfg80211_ssid *ssids; -@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request { - u32 flags; - struct cfg80211_match_set *match_sets; - int n_match_sets; -- s32 rssi_thold; -+ s32 min_rssi_thold; - - /* internal */ - struct wiphy *wiphy; -@@ -3130,8 +3133,8 @@ struct cfg80211_cached_keys; - * @identifier: (private) Identifier used in nl80211 to identify this - * wireless device if it has no netdev - * @current_bss: (private) Used by the internal configuration code -- * @channel: (private) Used by the internal configuration code to track -- * the user-set AP, monitor and WDS channel -+ * @chandef: (private) Used by the internal configuration code to track -+ * the user-set channel definition. - * @preset_chandef: (private) Used by the internal configuration code to - * track the channel to be used for AP later - * @bssid: (private) Used by the internal configuration code -@@ -3195,9 +3198,7 @@ struct wireless_dev { - - struct cfg80211_internal_bss *current_bss; /* associated / joined */ - struct cfg80211_chan_def preset_chandef; -- -- /* for AP and mesh channel tracking */ -- struct ieee80211_channel *channel; -+ struct cfg80211_chan_def chandef; + if (sta->dead) + return; - bool ibss_fixed; - bool ibss_dfs_possible; -@@ -3879,6 +3880,7 @@ void cfg80211_michael_mic_failure(struct - * - * @dev: network device - * @bssid: the BSSID of the IBSS joined -+ * @channel: the channel of the IBSS joined - * @gfp: allocation flags - * - * This function notifies cfg80211 that the device joined an IBSS or -@@ -3888,7 +3890,8 @@ void cfg80211_michael_mic_failure(struct - * with the locally generated beacon -- this guarantees that there is - * always a scan result for this IBSS. cfg80211 will handle the rest. - */ --void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp); -+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, -+ struct ieee80211_channel *channel, gfp_t gfp); - - /** - * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -2442,9 +2442,15 @@ enum nl80211_reg_rule_attr { - * enum nl80211_sched_scan_match_attr - scheduled scan match attributes - * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved - * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, -- * only report BSS with matching SSID. -+ * only report BSS with matching SSID. - * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a -- * BSS in scan results. Filtering is turned off if not specified. -+ * BSS in scan results. Filtering is turned off if not specified. Note that -+ * if this attribute is in a match set of its own, then it is treated as -+ * the default value for all matchsets with an SSID, rather than being a -+ * matchset of its own without an RSSI filter. This is due to problems with -+ * how this API was implemented in the past. Also, due to the same problem, -+ * the only way to create a matchset with only an RSSI filter (with this -+ * attribute) is if there's only a single matchset with the RSSI attribute. - * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter - * attribute number currently defined - * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use ---- a/net/mac80211/agg-tx.c -+++ b/net/mac80211/agg-tx.c -@@ -107,7 +107,7 @@ static void ieee80211_send_addba_request - mgmt->u.action.u.addba_req.start_seq_num = - cpu_to_le16(start_seq_num << 4); - -- ieee80211_tx_skb_tid(sdata, skb, tid); -+ ieee80211_tx_skb(sdata, skb); +- 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(); } - void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wip - /* TODO: make hostapd tell us what it wants */ - sdata->smps_mode = IEEE80211_SMPS_OFF; - sdata->needed_rx_chains = sdata->local->rx_chains; -- sdata->radar_required = params->radar_required; - - mutex_lock(&local->mtx); -+ sdata->radar_required = params->radar_required; - err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, - IEEE80211_CHANCTX_SHARED); - mutex_unlock(&local->mtx); -@@ -1021,8 +1021,10 @@ static int ieee80211_start_ap(struct wip - IEEE80211_P2P_OPPPS_ENABLE_BIT; - - err = ieee80211_assign_beacon(sdata, ¶ms->beacon); -- if (err < 0) -+ if (err < 0) { -+ ieee80211_vif_release_channel(sdata); - return err; -+ } - changed |= err; - - err = drv_start_ap(sdata->local, sdata); -@@ -1032,6 +1034,7 @@ static int ieee80211_start_ap(struct wip - if (old) - kfree_rcu(old, rcu_head); - RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); -+ ieee80211_vif_release_channel(sdata); - return err; - } - -@@ -1053,6 +1056,7 @@ static int ieee80211_change_beacon(struc - int err; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ sdata_assert_lock(sdata); + static int sta_prepare_rate_control(struct ieee80211_local *local, +@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i - /* don't allow changing the beacon while CSA is in place - offset - * of channel switch counter may change -@@ -1080,6 +1084,8 @@ static int ieee80211_stop_ap(struct wiph - struct probe_resp *old_probe_resp; - struct cfg80211_chan_def chandef; + 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; -+ sdata_assert_lock(sdata); +- 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); + - old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); - if (!old_beacon) - return -ENOENT; -@@ -1090,8 +1096,6 @@ static int ieee80211_stop_ap(struct wiph - kfree(sdata->u.ap.next_beacon); - sdata->u.ap.next_beacon = NULL; - -- cancel_work_sync(&sdata->u.ap.request_smps_work); -- - /* turn off carrier for this interface and dependent VLANs */ - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - netif_carrier_off(vlan->dev); -@@ -1103,6 +1107,7 @@ static int ieee80211_stop_ap(struct wiph - kfree_rcu(old_beacon, rcu_head); - if (old_probe_resp) - kfree_rcu(old_probe_resp, rcu_head); -+ sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; - - __sta_info_flush(sdata, true); - ieee80211_free_keys(sdata, true); -@@ -2638,6 +2643,24 @@ static int ieee80211_start_roc_work(stru - INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); - INIT_LIST_HEAD(&roc->dependents); ++ 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 + } -+ /* -+ * cookie is either the roc cookie (for normal roc) -+ * or the SKB (for mgmt TX) -+ */ -+ if (!txskb) { -+ /* local->mtx protects this */ -+ local->roc_cookie_counter++; -+ roc->cookie = local->roc_cookie_counter; -+ /* wow, you wrapped 64 bits ... more likely a bug */ -+ if (WARN_ON(roc->cookie == 0)) { -+ roc->cookie = 1; -+ local->roc_cookie_counter++; -+ } -+ *cookie = roc->cookie; -+ } else { -+ *cookie = (unsigned long)txskb; -+ } + 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); + - /* if there's one pending or we're scanning, queue this one */ - if (!list_empty(&local->roc_list) || - local->scanning || local->radar_detect_enabled) -@@ -2772,24 +2795,6 @@ static int ieee80211_start_roc_work(stru - if (!queued) - list_add_tail(&roc->list, &local->roc_list); ++ /* The station might have polled and then woken up before we responded, ++ * so clear these flags now to avoid them sticking around. ++ */ ++ clear_sta_flag(sta, WLAN_STA_PSPOLL); ++ clear_sta_flag(sta, WLAN_STA_UAPSD); + spin_unlock(&sta->ps_lock); -- /* -- * cookie is either the roc cookie (for normal roc) -- * or the SKB (for mgmt TX) -- */ -- if (!txskb) { -- /* local->mtx protects this */ -- local->roc_cookie_counter++; -- roc->cookie = local->roc_cookie_counter; -- /* wow, you wrapped 64 bits ... more likely a bug */ -- if (WARN_ON(roc->cookie == 0)) { -- roc->cookie = 1; -- local->roc_cookie_counter++; -- } -- *cookie = roc->cookie; -- } else { -- *cookie = (unsigned long)txskb; -- } -- - return 0; - } + atomic_dec(&ps->num_sta_ps); +@@ -1542,10 +1549,26 @@ void ieee80211_sta_block_awake(struct ie -@@ -3004,8 +3009,10 @@ void ieee80211_csa_finalize_work(struct - if (!ieee80211_sdata_running(sdata)) - goto unlock; + trace_api_sta_block_awake(sta->local, pubsta, block); -- sdata->radar_required = sdata->csa_radar_required; -+ sdata_assert_lock(sdata); +- if (block) ++ if (block) { + set_sta_flag(sta, WLAN_STA_PS_DRIVER); +- else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) +- ieee80211_queue_work(hw, &sta->drv_unblock_wk); ++ return; ++ } + - mutex_lock(&local->mtx); -+ sdata->radar_required = sdata->csa_radar_required; - err = ieee80211_vif_change_channel(sdata, &changed); - mutex_unlock(&local->mtx); - if (WARN_ON(err < 0)) -@@ -3022,13 +3029,13 @@ void ieee80211_csa_finalize_work(struct - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; ++ if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) ++ return; + - if (err < 0) - goto unlock; - - changed |= err; -- kfree(sdata->u.ap.next_beacon); -- sdata->u.ap.next_beacon = NULL; -- - ieee80211_bss_info_change_notify(sdata, err); - break; - case NL80211_IFTYPE_ADHOC: -@@ -3066,7 +3073,7 @@ int ieee80211_channel_switch(struct wiph - struct ieee80211_if_mesh __maybe_unused *ifmsh; - int err, num_chanctx; - -- lockdep_assert_held(&sdata->wdev.mtx); -+ sdata_assert_lock(sdata); - - if (!list_empty(&local->roc_list) || local->scanning) - return -EBUSY; ---- a/net/mac80211/ht.c -+++ b/net/mac80211/ht.c -@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee802 - mgmt->u.action.u.delba.params = cpu_to_le16(params); - mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); - -- ieee80211_tx_skb_tid(sdata, skb, tid); -+ ieee80211_tx_skb(sdata, skb); ++ if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { ++ set_sta_flag(sta, WLAN_STA_PS_DELIVER); ++ clear_sta_flag(sta, WLAN_STA_PS_DRIVER); ++ ieee80211_queue_work(hw, &sta->drv_deliver_wk); ++ } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || ++ test_sta_flag(sta, WLAN_STA_UAPSD)) { ++ /* must be asleep in this case */ ++ clear_sta_flag(sta, WLAN_STA_PS_DRIVER); ++ ieee80211_queue_work(hw, &sta->drv_deliver_wk); ++ } else { ++ clear_sta_flag(sta, WLAN_STA_PS_DRIVER); ++ } } + EXPORT_SYMBOL(ieee80211_sta_block_awake); - void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, -@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(stru - u.ap.request_smps_work); - - sdata_lock(sdata); -- __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode); -+ if (sdata_dereference(sdata->u.ap.beacon, sdata)) -+ __ieee80211_request_smps_ap(sdata, -+ sdata->u.ap.driver_smps_mode); - sdata_unlock(sdata); +@@ -1703,3 +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; } - ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -770,12 +770,19 @@ static void ieee80211_do_stop(struct iee - - ieee80211_roc_purge(local, sdata); - -- if (sdata->vif.type == NL80211_IFTYPE_STATION) -+ switch (sdata->vif.type) { -+ case NL80211_IFTYPE_STATION: - ieee80211_mgd_stop(sdata); -- -- if (sdata->vif.type == NL80211_IFTYPE_ADHOC) -+ break; -+ case NL80211_IFTYPE_ADHOC: - ieee80211_ibss_stop(sdata); -- -+ break; -+ case NL80211_IFTYPE_AP: -+ cancel_work_sync(&sdata->u.ap.request_smps_work); -+ break; -+ default: -+ break; ++ ++void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) ++{ ++ struct ieee80211_sub_if_data *sdata = sta->sdata; ++ struct ieee80211_local *local = sdata->local; ++ struct rate_control_ref *ref = NULL; ++ struct timespec uptime; ++ u64 packets = 0; ++ u32 thr = 0; ++ int i, ac; ++ ++ if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) ++ ref = local->rate_ctrl; ++ ++ sinfo->generation = sdata->local->sta_generation; ++ ++ sinfo->filled = STATION_INFO_INACTIVE_TIME | ++ STATION_INFO_RX_BYTES64 | ++ STATION_INFO_TX_BYTES64 | ++ STATION_INFO_RX_PACKETS | ++ STATION_INFO_TX_PACKETS | ++ STATION_INFO_TX_RETRIES | ++ STATION_INFO_TX_FAILED | ++ STATION_INFO_TX_BITRATE | ++ STATION_INFO_RX_BITRATE | ++ STATION_INFO_RX_DROP_MISC | ++ STATION_INFO_BSS_PARAM | ++ STATION_INFO_CONNECTED_TIME | ++ STATION_INFO_STA_FLAGS | ++ STATION_INFO_BEACON_LOSS_COUNT; ++ ++ do_posix_clock_monotonic_gettime(&uptime); ++ sinfo->connected_time = uptime.tv_sec - sta->last_connected; ++ ++ sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); ++ sinfo->tx_bytes = 0; ++ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { ++ sinfo->tx_bytes += sta->tx_bytes[ac]; ++ packets += sta->tx_packets[ac]; + } ++ sinfo->tx_packets = packets; ++ sinfo->rx_bytes = sta->rx_bytes; ++ sinfo->rx_packets = sta->rx_packets; ++ sinfo->tx_retries = sta->tx_retry_count; ++ sinfo->tx_failed = sta->tx_retry_failed; ++ sinfo->rx_dropped_misc = sta->rx_dropped; ++ sinfo->beacon_loss_count = sta->beacon_loss_count; ++ ++ if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || ++ (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { ++ sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; ++ if (!local->ops->get_rssi || ++ drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) ++ sinfo->signal = (s8)sta->last_signal; ++ sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); ++ } ++ if (sta->chains) { ++ sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | ++ STATION_INFO_CHAIN_SIGNAL_AVG; ++ ++ sinfo->chains = sta->chains; ++ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { ++ sinfo->chain_signal[i] = sta->chain_signal_last[i]; ++ sinfo->chain_signal_avg[i] = ++ (s8) -ewma_read(&sta->chain_signal_avg[i]); ++ } ++ } ++ ++ sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); ++ sta_set_rate_info_rx(sta, &sinfo->rxrate); ++ ++ if (ieee80211_vif_is_mesh(&sdata->vif)) { ++#ifdef CPTCFG_MAC80211_MESH ++ sinfo->filled |= STATION_INFO_LLID | ++ STATION_INFO_PLID | ++ STATION_INFO_PLINK_STATE | ++ STATION_INFO_LOCAL_PM | ++ STATION_INFO_PEER_PM | ++ STATION_INFO_NONPEER_PM; ++ ++ sinfo->llid = sta->llid; ++ sinfo->plid = sta->plid; ++ sinfo->plink_state = sta->plink_state; ++ if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { ++ sinfo->filled |= STATION_INFO_T_OFFSET; ++ sinfo->t_offset = sta->t_offset; ++ } ++ sinfo->local_pm = sta->local_pm; ++ sinfo->peer_pm = sta->peer_pm; ++ sinfo->nonpeer_pm = sta->nonpeer_pm; ++#endif ++ } ++ ++ sinfo->bss_param.flags = 0; ++ if (sdata->vif.bss_conf.use_cts_prot) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; ++ if (sdata->vif.bss_conf.use_short_preamble) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; ++ if (sdata->vif.bss_conf.use_short_slot) ++ sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; ++ sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; ++ sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; ++ ++ sinfo->sta_flags.set = 0; ++ sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | ++ BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | ++ BIT(NL80211_STA_FLAG_WME) | ++ BIT(NL80211_STA_FLAG_MFP) | ++ BIT(NL80211_STA_FLAG_AUTHENTICATED) | ++ BIT(NL80211_STA_FLAG_ASSOCIATED) | ++ BIT(NL80211_STA_FLAG_TDLS_PEER); ++ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); ++ if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); ++ if (test_sta_flag(sta, WLAN_STA_WME)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); ++ if (test_sta_flag(sta, WLAN_STA_MFP)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); ++ if (test_sta_flag(sta, WLAN_STA_AUTH)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); ++ if (test_sta_flag(sta, WLAN_STA_ASSOC)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); ++ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) ++ sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); ++ ++ /* check if the driver has a SW RC implementation */ ++ if (ref && ref->ops->get_expected_throughput) ++ thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); ++ else ++ thr = drv_get_expected_throughput(local, &sta->sta); ++ ++ if (thr != 0) { ++ sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; ++ sinfo->expected_throughput = thr; ++ } ++} +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr + */ + #define STA_LOST_PKT_THRESHOLD 50 - /* - * Remove all stations associated with this interface. -@@ -827,7 +834,9 @@ static void ieee80211_do_stop(struct iee - cancel_work_sync(&local->dynamic_ps_enable_work); - - cancel_work_sync(&sdata->recalc_smps); -+ sdata_lock(sdata); - sdata->vif.csa_active = false; -+ sdata_unlock(sdata); - cancel_work_sync(&sdata->csa_finalize_work); ++static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb) ++{ ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ ++ /* This packet was aggregated but doesn't carry status info */ ++ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && ++ !(info->flags & IEEE80211_TX_STAT_AMPDU)) ++ return; ++ ++ if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD) ++ return; ++ ++ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, ++ sta->lost_packets, GFP_ATOMIC); ++ sta->lost_packets = 0; ++} ++ + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) + { + struct sk_buff *skb2; +@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021 + if (info->flags & IEEE80211_TX_STAT_ACK) { + if (sta->lost_packets) + sta->lost_packets = 0; +- } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) { +- cfg80211_cqm_pktloss_notify(sta->sdata->dev, +- sta->sta.addr, +- sta->lost_packets, +- GFP_ATOMIC); +- sta->lost_packets = 0; ++ } else { ++ ieee80211_lost_packet(sta, skb); + } + } - cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c -@@ -599,10 +599,10 @@ static int ieee80211_is_unicast_robust_m - { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - -- if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) -+ if (is_multicast_ether_addr(hdr->addr1)) - return 0; +@@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info * + return; + } -- return ieee80211_is_robust_mgmt_frame(hdr); -+ return ieee80211_is_robust_mgmt_frame(skb); ++ set_sta_flag(sta, WLAN_STA_PS_DELIVER); ++ clear_sta_flag(sta, WLAN_STA_PS_STA); + ieee80211_sta_ps_deliver_wakeup(sta); } +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags { + WLAN_STA_TOFFSET_KNOWN, + WLAN_STA_MPSP_OWNER, + WLAN_STA_MPSP_RECIPIENT, ++ WLAN_STA_PS_DELIVER, + }; -@@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust - { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + #define ADDBA_RESP_INTERVAL HZ +@@ -265,7 +266,7 @@ struct ieee80211_tx_latency_stat { + * @last_rx_rate_vht_nss: rx status nss of last data packet + * @lock: used for locking all fields that require locking, see comments + * in the header file. +- * @drv_unblock_wk: used for driver PS unblocking ++ * @drv_deliver_wk: used for delivering frames after driver PS unblocking + * @listen_interval: listen interval of this station, when we're acting as AP + * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly + * @ps_lock: used for powersave (when mac80211 is the AP) related locking +@@ -278,7 +279,6 @@ struct ieee80211_tx_latency_stat { + * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on + * @rx_packets: Number of MSDUs received from this STA + * @rx_bytes: Number of bytes received from this STA +- * @wep_weak_iv_count: number of weak WEP IVs received from this station + * @last_rx: time (in jiffies) when last frame was received from this STA + * @last_connected: time (in seconds) when a station got connected + * @num_duplicates: number of duplicate frames received from this STA +@@ -345,7 +345,7 @@ struct sta_info { + void *rate_ctrl_priv; + spinlock_t lock; + +- struct work_struct drv_unblock_wk; ++ struct work_struct drv_deliver_wk; + + u16 listen_interval; + +@@ -367,7 +367,6 @@ struct sta_info { + /* Updated from RX path only, no locking requirements */ + unsigned long rx_packets; + u64 rx_bytes; +- unsigned long wep_weak_iv_count; + unsigned long last_rx; + long last_connected; + unsigned long num_duplicates; +@@ -628,6 +627,8 @@ void sta_set_rate_info_tx(struct sta_inf + struct rate_info *rinfo); + void sta_set_rate_info_rx(struct sta_info *sta, + struct rate_info *rinfo); ++void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo); ++ + void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, + unsigned long exp_time); + u8 sta_info_tx_streams(struct sta_info *sta); +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee + return TX_CONTINUE; -- if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) -+ if (!is_multicast_ether_addr(hdr->addr1)) - return 0; + 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); -- return ieee80211_is_robust_mgmt_frame(hdr); -+ return ieee80211_is_robust_mgmt_frame(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 (chanctx_conf) +- chan = chanctx_conf->def.chan; ++ chandef = &chanctx_conf->def; + else if (!local->use_chanctx) +- chan = local->_oper_chandef.chan; ++ chandef = &local->_oper_chandef; + else + goto fail_rcu; -@@ -626,7 +626,7 @@ static int ieee80211_get_mmie_keyidx(str - if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) - return -1; +@@ -1743,10 +1745,11 @@ netdev_tx_t ieee80211_monitor_start_xmit + * radar detection by itself. We can do that later by adding a + * monitor flag interfaces used for AP support. + */ +- if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) ++ if (!cfg80211_reg_can_beacon(local->hw.wiphy, chandef, ++ sdata->vif.type)) + goto fail_rcu; -- if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) -+ if (!ieee80211_is_robust_mgmt_frame(skb)) - return -1; /* not a robust management frame */ +- ieee80211_xmit(sdata, skb, chan->band); ++ ieee80211_xmit(sdata, skb, chandef->chan->band); + rcu_read_unlock(); - mmie = (struct ieee80211_mmie *) -@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info * - sta->sta.addr, sta->sta.aid); + return NETDEV_TX_OK; +@@ -2425,7 +2428,7 @@ static void ieee80211_set_csa(struct iee + u8 *beacon_data; + size_t beacon_data_len; + int i; +- u8 count = sdata->csa_current_counter; ++ u8 count = beacon->csa_current_counter; - if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { -+ /* -+ * Clear the flag only if the other one is still set -+ * so that the TX path won't start TX'ing new frames -+ * directly ... In the case that the driver flag isn't -+ * set ieee80211_sta_ps_deliver_wakeup() will clear it. -+ */ -+ clear_sta_flag(sta, WLAN_STA_PS_STA); - ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", - sta->sta.addr, sta->sta.aid); + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: +@@ -2444,46 +2447,54 @@ static void ieee80211_set_csa(struct iee return; -@@ -1311,18 +1318,15 @@ ieee80211_rx_h_sta_process(struct ieee80 - !ieee80211_has_morefrags(hdr->frame_control) && - !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && - (rx->sdata->vif.type == NL80211_IFTYPE_AP || -- rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { -+ rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && -+ /* PM bit is only checked in frames where it isn't reserved, -+ * in AP mode it's reserved in non-bufferable management frames -+ * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field) -+ */ -+ (!ieee80211_is_mgmt(hdr->frame_control) || -+ ieee80211_is_bufferable_mmpdu(hdr->frame_control))) { - if (test_sta_flag(sta, WLAN_STA_PS_STA)) { -- /* -- * Ignore doze->wake transitions that are -- * indicated by non-data frames, the standard -- * is unclear here, but for example going to -- * PS mode and then scanning would cause a -- * doze->wake transition for the probe request, -- * and that is clearly undesirable. -- */ -- if (ieee80211_is_data(hdr->frame_control) && -- !ieee80211_has_pm(hdr->frame_control)) -+ if (!ieee80211_has_pm(hdr->frame_control)) - sta_ps_end(sta); - } else { - if (ieee80211_has_pm(hdr->frame_control)) -@@ -1845,8 +1849,7 @@ static int ieee80211_drop_unencrypted_mg - * having configured keys. - */ - if (unlikely(ieee80211_is_action(fc) && !rx->key && -- ieee80211_is_robust_mgmt_frame( -- (struct ieee80211_hdr *) rx->skb->data))) -+ ieee80211_is_robust_mgmt_frame(rx->skb))) - return -EACCES; } ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, - if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) - return 0; - -- if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) -- skb->data)) -+ if (!ieee80211_is_robust_mgmt_frame(skb)) - return 0; - - return 1; -@@ -478,6 +477,20 @@ ieee80211_tx_h_unicast_ps_buf(struct iee - sta->sta.addr, sta->sta.aid, ac); - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); -+ -+ /* sync with ieee80211_sta_ps_deliver_wakeup */ -+ spin_lock(&sta->ps_lock); -+ /* -+ * STA woke up the meantime and all the frames on ps_tx_buf have -+ * been queued to pending queue. No reordering can happen, go -+ * ahead and Tx the packet. -+ */ -+ if (!test_sta_flag(sta, WLAN_STA_PS_STA) && -+ !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { -+ spin_unlock(&sta->ps_lock); -+ return TX_CONTINUE; -+ } ++ rcu_read_lock(); + for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; ++i) { +- u16 counter_offset_beacon = +- sdata->csa_counter_offset_beacon[i]; +- u16 counter_offset_presp = sdata->csa_counter_offset_presp[i]; +- +- if (counter_offset_beacon) { +- if (WARN_ON(counter_offset_beacon >= beacon_data_len)) +- return; +- +- beacon_data[counter_offset_beacon] = count; +- } +- +- if (sdata->vif.type == NL80211_IFTYPE_AP && +- counter_offset_presp) { +- rcu_read_lock(); +- resp = rcu_dereference(sdata->u.ap.probe_resp); ++ resp = rcu_dereference(sdata->u.ap.probe_resp); + +- /* If nl80211 accepted the offset, this should +- * not happen. +- */ +- if (WARN_ON(!resp)) { ++ if (beacon->csa_counter_offsets[i]) { ++ if (WARN_ON_ONCE(beacon->csa_counter_offsets[i] >= ++ beacon_data_len)) { + rcu_read_unlock(); + return; + } +- resp->data[counter_offset_presp] = count; +- rcu_read_unlock(); + - if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { - struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); - ps_dbg(tx->sdata, -@@ -492,6 +505,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; - skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); -+ spin_unlock(&sta->ps_lock); - - if (!timer_pending(&local->sta_cleanup)) - mod_timer(&local->sta_cleanup, -@@ -525,9 +539,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t - - /* only deauth, disassoc and action are bufferable MMPDUs */ - if (ieee80211_is_mgmt(hdr->frame_control) && -- !ieee80211_is_deauth(hdr->frame_control) && -- !ieee80211_is_disassoc(hdr->frame_control) && -- !ieee80211_is_action(hdr->frame_control)) { -+ !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { - if (tx->flags & IEEE80211_TX_UNICAST) - info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; - return TX_CONTINUE; -@@ -567,7 +579,7 @@ ieee80211_tx_h_select_key(struct ieee802 - tx->key = key; - else if (ieee80211_is_mgmt(hdr->frame_control) && - is_multicast_ether_addr(hdr->addr1) && -- ieee80211_is_robust_mgmt_frame(hdr) && -+ ieee80211_is_robust_mgmt_frame(tx->skb) && - (key = rcu_dereference(tx->sdata->default_mgmt_key))) - tx->key = key; - else if (is_multicast_ether_addr(hdr->addr1) && -@@ -582,12 +594,12 @@ ieee80211_tx_h_select_key(struct ieee802 - tx->key = NULL; - else if (tx->skb->protocol == tx->sdata->control_port_protocol) - tx->key = NULL; -- else if (ieee80211_is_robust_mgmt_frame(hdr) && -+ else if (ieee80211_is_robust_mgmt_frame(tx->skb) && - !(ieee80211_is_action(hdr->frame_control) && - tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) - tx->key = NULL; - else if (ieee80211_is_mgmt(hdr->frame_control) && -- !ieee80211_is_robust_mgmt_frame(hdr)) -+ !ieee80211_is_robust_mgmt_frame(tx->skb)) - tx->key = NULL; - else { - I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); -@@ -878,7 +890,7 @@ static int ieee80211_fragment(struct iee ++ beacon_data[beacon->csa_counter_offsets[i]] = count; + } ++ ++ if (sdata->vif.type == NL80211_IFTYPE_AP && resp && ++ resp->csa_counter_offsets) ++ resp->data[resp->csa_counter_offsets[i]] = count; } - - /* adjust first fragment's length */ -- skb->len = hdrlen + per_fragm; -+ skb_trim(skb, hdrlen + per_fragm); - return 0; ++ rcu_read_unlock(); } ---- a/net/mac80211/wpa.c -+++ b/net/mac80211/wpa.c -@@ -499,7 +499,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - if (!ieee80211_is_data(hdr->frame_control) && -- !ieee80211_is_robust_mgmt_frame(hdr)) -+ !ieee80211_is_robust_mgmt_frame(skb)) - return RX_CONTINUE; - - data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - ---- a/net/wireless/ap.c -+++ b/net/wireless/ap.c -@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg - err = rdev_stop_ap(rdev, dev); - if (!err) { - wdev->beacon_interval = 0; -- wdev->channel = NULL; -+ memset(&wdev->chandef, 0, sizeof(wdev->chandef)); - wdev->ssid_len = 0; - rdev_set_qos_map(rdev, dev, NULL); -+ nl80211_send_ap_stopped(wdev); - } + u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) + { + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct beacon_data *beacon = NULL; ++ u8 count = 0; ++ ++ rcu_read_lock(); ++ ++ if (sdata->vif.type == NL80211_IFTYPE_AP) ++ beacon = rcu_dereference(sdata->u.ap.beacon); ++ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) ++ beacon = rcu_dereference(sdata->u.ibss.presp); ++ else if (ieee80211_vif_is_mesh(&sdata->vif)) ++ beacon = rcu_dereference(sdata->u.mesh.beacon); ++ ++ if (!beacon) ++ goto unlock; - return err; ---- a/net/wireless/core.c -+++ b/net/wireless/core.c -@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg +- sdata->csa_current_counter--; ++ beacon->csa_current_counter--; - rdev->opencount--; + /* the counter should never reach 0 */ +- WARN_ON(!sdata->csa_current_counter); ++ WARN_ON_ONCE(!beacon->csa_current_counter); ++ count = beacon->csa_current_counter; -- WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && -- !rdev->scan_req->notified); -+ if (rdev->scan_req && rdev->scan_req->wdev == wdev) { -+ if (WARN_ON(!rdev->scan_req->notified)) -+ rdev->scan_req->aborted = true; -+ ___cfg80211_scan_done(rdev, false); -+ } +- return sdata->csa_current_counter; ++unlock: ++ rcu_read_unlock(); ++ return count; } + EXPORT_SYMBOL(ieee80211_csa_update_counter); - static int cfg80211_rfkill_set_block(void *data, bool blocked) -@@ -447,9 +450,6 @@ int wiphy_register(struct wiphy *wiphy) - int i; - u16 ifmodes = wiphy->interface_modes; - -- /* support for 5/10 MHz is broken due to nl80211 API mess - disable */ -- wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ; -- - /* - * There are major locking problems in nl80211/mac80211 for CSA, - * disable for all drivers until this has been reworked. -@@ -875,8 +875,11 @@ static int cfg80211_netdev_notifier_call - break; - case NETDEV_DOWN: - cfg80211_update_iface_num(rdev, wdev->iftype, -1); -- WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev && -- !rdev->scan_req->notified); -+ if (rdev->scan_req && rdev->scan_req->wdev == wdev) { -+ if (WARN_ON(!rdev->scan_req->notified)) -+ rdev->scan_req->aborted = true; -+ ___cfg80211_scan_done(rdev, false); -+ } +@@ -2493,7 +2504,6 @@ bool ieee80211_csa_is_complete(struct ie + struct beacon_data *beacon = NULL; + u8 *beacon_data; + size_t beacon_data_len; +- int counter_beacon = sdata->csa_counter_offset_beacon[0]; + int ret = false; - if (WARN_ON(rdev->sched_scan_req && - rdev->sched_scan_req->dev == wdev->netdev)) { ---- a/net/wireless/core.h -+++ b/net/wireless/core.h -@@ -62,6 +62,7 @@ struct cfg80211_registered_device { - struct rb_root bss_tree; - u32 bss_generation; - struct cfg80211_scan_request *scan_req; /* protected by RTNL */ -+ struct sk_buff *scan_msg; - struct cfg80211_sched_scan_request *sched_scan_req; - unsigned long suspend_at; - struct work_struct scan_done_wk; -@@ -210,6 +211,7 @@ struct cfg80211_event { - } dc; - struct { - u8 bssid[ETH_ALEN]; -+ struct ieee80211_channel *channel; - } ij; - }; - }; -@@ -257,7 +259,8 @@ int __cfg80211_leave_ibss(struct cfg8021 - struct net_device *dev, bool nowext); - int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool nowext); --void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); -+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, -+ struct ieee80211_channel *channel); - int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev); - -@@ -361,7 +364,8 @@ int cfg80211_validate_key_settings(struc - struct key_params *params, int key_idx, - bool pairwise, const u8 *mac_addr); - void __cfg80211_scan_done(struct work_struct *wk); --void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); -+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, -+ bool send_message); - void __cfg80211_sched_scan_results(struct work_struct *wk); - int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, - bool driver_initiated); -@@ -441,7 +445,8 @@ static inline unsigned int elapsed_jiffi - void - cfg80211_get_chan_state(struct wireless_dev *wdev, - struct ieee80211_channel **chan, -- enum cfg80211_chan_mode *chanmode); -+ enum cfg80211_chan_mode *chanmode, -+ u8 *radar_detect); - - int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, - struct cfg80211_chan_def *chandef); ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -1723,9 +1723,10 @@ static int nl80211_dump_wiphy(struct sk_ - * We can then retry with the larger buffer. - */ - if ((ret == -ENOBUFS || ret == -EMSGSIZE) && -- !skb->len && -+ !skb->len && !state->split && - cb->min_dump_alloc < 4096) { - cb->min_dump_alloc = 4096; -+ state->split_start = 0; - rtnl_unlock(); - return 1; - } -@@ -2047,10 +2048,12 @@ static int nl80211_set_wiphy(struct sk_b - nla_for_each_nested(nl_txq_params, - info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], - rem_txq_params) { -- nla_parse(tb, NL80211_TXQ_ATTR_MAX, -- nla_data(nl_txq_params), -- nla_len(nl_txq_params), -- txq_params_policy); -+ result = nla_parse(tb, NL80211_TXQ_ATTR_MAX, -+ nla_data(nl_txq_params), -+ nla_len(nl_txq_params), -+ txq_params_policy); -+ if (result) -+ goto bad_res; - result = parse_txq_params(tb, &txq_params); - if (result) - goto bad_res; -@@ -3289,7 +3292,7 @@ static int nl80211_start_ap(struct sk_bu - if (!err) { - wdev->preset_chandef = params.chandef; - wdev->beacon_interval = params.beacon_interval; -- wdev->channel = params.chandef.chan; -+ wdev->chandef = params.chandef; - wdev->ssid_len = params.ssid_len; - memcpy(wdev->ssid, params.ssid, wdev->ssid_len); + if (!ieee80211_sdata_running(sdata)) +@@ -2531,10 +2541,13 @@ bool ieee80211_csa_is_complete(struct ie + goto out; } -@@ -5210,9 +5213,11 @@ static int nl80211_set_reg(struct sk_buf - - nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], - rem_reg_rules) { -- nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, -- nla_data(nl_reg_rule), nla_len(nl_reg_rule), -- reg_rule_policy); -+ r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, -+ nla_data(nl_reg_rule), nla_len(nl_reg_rule), -+ reg_rule_policy); -+ if (r) -+ goto bad_reg; - r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); - if (r) - goto bad_reg; -@@ -5277,7 +5282,7 @@ static int nl80211_trigger_scan(struct s - if (!rdev->ops->scan) - return -EOPNOTSUPP; -- if (rdev->scan_req) { -+ if (rdev->scan_req || rdev->scan_msg) { - err = -EBUSY; - goto unlock; - } -@@ -5475,6 +5480,7 @@ static int nl80211_start_sched_scan(stru - enum ieee80211_band band; - size_t ie_len; - struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; -+ s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; - - if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || - !rdev->ops->sched_scan_start) -@@ -5509,11 +5515,40 @@ static int nl80211_start_sched_scan(stru - if (n_ssids > wiphy->max_sched_scan_ssids) - return -EINVAL; - -- if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) -+ /* -+ * First, count the number of 'real' matchsets. Due to an issue with -+ * the old implementation, matchsets containing only the RSSI attribute -+ * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default' -+ * RSSI for all matchsets, rather than their own matchset for reporting -+ * all APs with a strong RSSI. This is needed to be compatible with -+ * older userspace that treated a matchset with only the RSSI as the -+ * global RSSI for all other matchsets - if there are other matchsets. -+ */ -+ if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { - nla_for_each_nested(attr, - info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], -- tmp) -- n_match_sets++; -+ tmp) { -+ struct nlattr *rssi; -+ -+ err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, -+ nla_data(attr), nla_len(attr), -+ nl80211_match_policy); -+ if (err) -+ return err; -+ /* add other standalone attributes here */ -+ if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { -+ n_match_sets++; -+ continue; -+ } -+ rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; -+ if (rssi) -+ default_match_rssi = nla_get_s32(rssi); -+ } -+ } -+ -+ /* However, if there's no other matchset, add the RSSI one */ -+ if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF) -+ n_match_sets = 1; - - if (n_match_sets > wiphy->max_match_sets) - return -EINVAL; -@@ -5634,11 +5669,22 @@ static int nl80211_start_sched_scan(stru - tmp) { - struct nlattr *ssid, *rssi; - -- nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, -- nla_data(attr), nla_len(attr), -- nl80211_match_policy); -+ err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, -+ nla_data(attr), nla_len(attr), -+ nl80211_match_policy); -+ if (err) -+ goto out_free; - ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; - if (ssid) { -+ if (WARN_ON(i >= n_match_sets)) { -+ /* this indicates a programming error, -+ * the loop above should have verified -+ * things properly -+ */ -+ err = -EINVAL; -+ goto out_free; -+ } -+ - if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { - err = -EINVAL; - goto out_free; -@@ -5647,15 +5693,28 @@ static int nl80211_start_sched_scan(stru - nla_data(ssid), nla_len(ssid)); - request->match_sets[i].ssid.ssid_len = - nla_len(ssid); -+ /* special attribute - old implemenation w/a */ -+ request->match_sets[i].rssi_thold = -+ default_match_rssi; -+ rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; -+ if (rssi) -+ request->match_sets[i].rssi_thold = -+ nla_get_s32(rssi); - } -- rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; -- if (rssi) -- request->rssi_thold = nla_get_u32(rssi); -- else -- request->rssi_thold = -- NL80211_SCAN_RSSI_THOLD_OFF; - i++; - } -+ -+ /* there was no other matchset, so the RSSI one is alone */ -+ if (i == 0) -+ request->match_sets[0].rssi_thold = default_match_rssi; +- if (WARN_ON(counter_beacon > beacon_data_len)) ++ if (!beacon->csa_counter_offsets[0]) ++ goto out; + -+ request->min_rssi_thold = INT_MAX; -+ for (i = 0; i < n_match_sets; i++) -+ request->min_rssi_thold = -+ min(request->match_sets[i].rssi_thold, -+ request->min_rssi_thold); -+ } else { -+ request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; - } ++ if (WARN_ON_ONCE(beacon->csa_counter_offsets[0] > beacon_data_len)) + goto out; - if (info->attrs[NL80211_ATTR_IE]) { -@@ -5751,7 +5810,7 @@ static int nl80211_start_radar_detection +- 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; - err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); - if (!err) { -- wdev->channel = chandef.chan; -+ wdev->chandef = chandef; - wdev->cac_started = true; - wdev->cac_start_time = jiffies; - } -@@ -7502,16 +7561,19 @@ static int nl80211_set_tx_bitrate_mask(s - * directly to the enum ieee80211_band values used in cfg80211. - */ - BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); -- nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) -- { -+ nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { - enum ieee80211_band band = nla_type(tx_rates); -+ int err; -+ - if (band < 0 || band >= IEEE80211_NUM_BANDS) - return -EINVAL; - sband = rdev->wiphy.bands[band]; - if (sband == NULL) - return -EINVAL; -- nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), -- nla_len(tx_rates), nl80211_txattr_policy); -+ err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), -+ nla_len(tx_rates), nl80211_txattr_policy); -+ if (err) -+ return err; - if (tb[NL80211_TXRATE_LEGACY]) { - mask.control[band].legacy = rateset_to_mask( - sband, -@@ -10054,40 +10116,31 @@ void nl80211_send_scan_start(struct cfg8 - NL80211_MCGRP_SCAN, GFP_KERNEL); - } +- if (sdata->vif.csa_active) { ++ if (beacon->csa_counter_offsets[0]) { + if (!is_template) + ieee80211_csa_update_counter(vif); --void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev) -+struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, bool aborted) - { - struct sk_buff *msg; +- ieee80211_set_csa(sdata, presp); ++ ieee80211_set_csa(sdata, beacon); + } - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) -- return; -+ return NULL; +- 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 (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, -- NL80211_CMD_NEW_SCAN_RESULTS) < 0) { -+ aborted ? NL80211_CMD_SCAN_ABORTED : -+ NL80211_CMD_NEW_SCAN_RESULTS) < 0) { - nlmsg_free(msg); -- return; -+ return NULL; - } +- 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); -- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, -- NL80211_MCGRP_SCAN, GFP_KERNEL); -+ return msg; - } +- ieee80211_set_csa(sdata, bcn); ++ ieee80211_set_csa(sdata, beacon); + } --void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev) -+void nl80211_send_scan_result(struct cfg80211_registered_device *rdev, -+ struct sk_buff *msg) - { -- struct sk_buff *msg; -- -- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) - return; + 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; + } -- if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, -- NL80211_CMD_SCAN_ABORTED) < 0) { -- nlmsg_free(msg); -- return; -- } -- - genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - NL80211_MCGRP_SCAN, GFP_KERNEL); - } -@@ -11158,7 +11211,8 @@ void cfg80211_ch_switch_notify(struct ne - wdev->iftype != NL80211_IFTYPE_MESH_POINT)) - return; +- 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; + } -- wdev->channel = chandef->chan; -+ wdev->chandef = *chandef; -+ wdev->preset_chandef = *chandef; - nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); - } - EXPORT_SYMBOL(cfg80211_ch_switch_notify); -@@ -11673,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct + /* CSA offsets */ +- if (offs) { ++ if (offs && beacon) { + int i; + + for (i = 0; i < IEEE80211_MAX_CSA_COUNTERS_NUM; i++) { +- u16 csa_off = sdata->csa_counter_offset_beacon[i]; ++ u16 csa_off = beacon->csa_counter_offsets[i]; + + if (!csa_off) + continue; +--- a/drivers/net/wireless/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/rt2x00/rt2800lib.c +@@ -947,6 +947,40 @@ static inline u8 rt2800_get_beacon_offse + return BEACON_BASE_TO_OFFSET(rt2800_hw_beacon_base(rt2x00dev, index)); } - EXPORT_SYMBOL(cfg80211_crit_proto_stopped); -+void nl80211_send_ap_stopped(struct wireless_dev *wdev) ++static void rt2800_update_beacons_setup(struct rt2x00_dev *rt2x00dev) +{ -+ struct wiphy *wiphy = wdev->wiphy; -+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); -+ struct sk_buff *msg; -+ void *hdr; -+ -+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); -+ if (!msg) -+ return; ++ struct data_queue *queue = rt2x00dev->bcn; ++ struct queue_entry *entry; ++ int i, bcn_num = 0; ++ u64 off, reg = 0; ++ u32 bssid_dw1; + -+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP); -+ if (!hdr) -+ goto out; ++ /* ++ * Setup offsets of all active beacons in BCN_OFFSET{0,1} registers. ++ */ ++ for (i = 0; i < queue->limit; i++) { ++ entry = &queue->entries[i]; ++ if (!test_bit(ENTRY_BCN_ENABLED, &entry->flags)) ++ continue; ++ off = rt2800_get_beacon_offset(rt2x00dev, entry->entry_idx); ++ reg |= off << (8 * bcn_num); ++ bcn_num++; ++ } + -+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || -+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) || -+ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) -+ goto out; ++ WARN_ON_ONCE(bcn_num != rt2x00dev->intf_beaconing); + -+ genlmsg_end(msg, hdr); ++ rt2800_register_write(rt2x00dev, BCN_OFFSET0, (u32) reg); ++ rt2800_register_write(rt2x00dev, BCN_OFFSET1, (u32) (reg >> 32)); + -+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0, -+ NL80211_MCGRP_MLME, GFP_KERNEL); -+ return; -+ out: -+ nlmsg_free(msg); ++ /* ++ * 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); +} + - /* initialisation/exit functions */ - - int nl80211_init(void) ---- a/net/wireless/nl80211.h -+++ b/net/wireless/nl80211.h -@@ -8,10 +8,10 @@ void nl80211_exit(void); - void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); - void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev); --void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev); --void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev); -+struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, bool aborted); -+void nl80211_send_scan_result(struct cfg80211_registered_device *rdev, -+ struct sk_buff *msg); - void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 cmd); - void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, -@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_reg - enum nl80211_radar_event event, - struct net_device *netdev, gfp_t gfp); - -+void nl80211_send_ap_stopped(struct wireless_dev *wdev); -+ - void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); - - #endif /* __NET_WIRELESS_NL80211_H */ ---- a/net/wireless/scan.c -+++ b/net/wireless/scan.c -@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct - dev->bss_generation++; - } - --void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) -+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, -+ bool send_message) + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct cfg80211_scan_request *request; - struct wireless_dev *wdev; -+ struct sk_buff *msg; - #ifdef CPTCFG_CFG80211_WEXT - union iwreq_data wrqu; - #endif + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; +@@ -1003,6 +1037,12 @@ void rt2800_write_beacon(struct queue_en - ASSERT_RTNL(); + rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, + entry->skb->len + padding_len); ++ __set_bit(ENTRY_BCN_ENABLED, &entry->flags); ++ ++ /* ++ * Change global beacons settings. ++ */ ++ rt2800_update_beacons_setup(rt2x00dev); -- request = rdev->scan_req; -+ if (rdev->scan_msg) { -+ nl80211_send_scan_result(rdev, rdev->scan_msg); -+ rdev->scan_msg = NULL; -+ return; -+ } + /* + * 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); -+ request = rdev->scan_req; - if (!request) - return; + /* ++ * 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); + } -@@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg802 - if (wdev->netdev) - cfg80211_sme_scan_done(wdev->netdev); +@@ -4517,28 +4562,6 @@ static int rt2800_init_registers(struct + if (ret) + return ret; -- if (request->aborted) { -- nl80211_send_scan_aborted(rdev, wdev); -- } else { -- if (request->flags & NL80211_SCAN_FLAG_FLUSH) { -- /* flush entries from previous scans */ -- spin_lock_bh(&rdev->bss_lock); -- __cfg80211_bss_expire(rdev, request->scan_start); -- spin_unlock_bh(&rdev->bss_lock); -- } -- nl80211_send_scan_done(rdev, wdev); -+ if (!request->aborted && -+ request->flags & NL80211_SCAN_FLAG_FLUSH) { -+ /* flush entries from previous scans */ -+ spin_lock_bh(&rdev->bss_lock); -+ __cfg80211_bss_expire(rdev, request->scan_start); -+ spin_unlock_bh(&rdev->bss_lock); - } +- 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); -+ msg = nl80211_build_scan_msg(rdev, wdev, request->aborted); -+ - #ifdef CPTCFG_CFG80211_WEXT - if (wdev->netdev && !request->aborted) { - memset(&wrqu, 0, sizeof(wrqu)); -@@ -211,6 +216,11 @@ void ___cfg80211_scan_done(struct cfg802 +--- 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; - rdev->scan_req = NULL; - kfree(request); -+ -+ if (!send_message) -+ rdev->scan_msg = msg; -+ else -+ nl80211_send_scan_result(rdev, msg); +- if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) ++ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) { ++ mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_update_beacon(rt2x00dev, vif); ++ mutex_unlock(&intf->beacon_skb_mutex); ++ } } - void __cfg80211_scan_done(struct work_struct *wk) -@@ -221,7 +231,7 @@ void __cfg80211_scan_done(struct work_st - scan_done_wk); - - rtnl_lock(); -- ___cfg80211_scan_done(rdev); -+ ___cfg80211_scan_done(rdev, true); - rtnl_unlock(); + 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); } -@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_dev - if (IS_ERR(rdev)) - return PTR_ERR(rdev); + void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) +--- a/drivers/net/wireless/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c +@@ -487,6 +487,8 @@ int rt2x00mac_set_key(struct ieee80211_h + crypto.cipher = rt2x00crypto_key_to_cipher(key); + if (crypto.cipher == CIPHER_NONE) + return -EOPNOTSUPP; ++ if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev)) ++ return -EOPNOTSUPP; -- if (rdev->scan_req) { -+ if (rdev->scan_req || rdev->scan_msg) { - err = -EBUSY; - goto out; - } -@@ -1481,7 +1491,7 @@ int cfg80211_wext_giwscan(struct net_dev - if (IS_ERR(rdev)) - return PTR_ERR(rdev); - -- if (rdev->scan_req) -+ if (rdev->scan_req || rdev->scan_msg) - return -EAGAIN; - - res = ieee80211_scan_results(rdev, info, extra, data->length); ---- a/net/wireless/sme.c -+++ b/net/wireless/sme.c -@@ -67,7 +67,7 @@ static int cfg80211_conn_scan(struct wir - ASSERT_RDEV_LOCK(rdev); - ASSERT_WDEV_LOCK(wdev); - -- if (rdev->scan_req) -+ if (rdev->scan_req || rdev->scan_msg) - return -EBUSY; - - if (wdev->conn->params.channel) ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -1001,7 +1001,6 @@ ieee80211_sta_process_chanswitch(struct + crypto.cmd = cmd; + +@@ -624,25 +626,24 @@ void rt2x00mac_bss_info_changed(struct i + * Start/stop beaconing. + */ + if (changes & BSS_CHANGED_BEACON_ENABLED) { ++ mutex_lock(&intf->beacon_skb_mutex); + if (!bss_conf->enable_beacon && intf->enable_beacon) { + rt2x00dev->intf_beaconing--; + intf->enable_beacon = false; +- /* +- * Clear beacon in the H/W for this vif. This is needed +- * to disable beaconing on this particular interface +- * and keep it running on other interfaces. +- */ +- rt2x00queue_clear_beacon(rt2x00dev, vif); + + if (rt2x00dev->intf_beaconing == 0) { + /* + * Last beaconing interface disabled + * -> stop beacon queue. + */ +- mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_stop_queue(rt2x00dev->bcn); +- mutex_unlock(&intf->beacon_skb_mutex); + } ++ /* ++ * Clear beacon in the H/W for this vif. This is needed ++ * to disable beaconing on this particular interface ++ * and keep it running on other interfaces. ++ */ ++ rt2x00queue_clear_beacon(rt2x00dev, vif); + } else if (bss_conf->enable_beacon && !intf->enable_beacon) { + rt2x00dev->intf_beaconing++; + intf->enable_beacon = true; +@@ -658,11 +659,10 @@ void rt2x00mac_bss_info_changed(struct i + * First beaconing interface enabled + * -> start beacon queue. + */ +- mutex_lock(&intf->beacon_skb_mutex); + rt2x00queue_start_queue(rt2x00dev->bcn); +- mutex_unlock(&intf->beacon_skb_mutex); + } + } ++ mutex_unlock(&intf->beacon_skb_mutex); } - ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; -- sdata->vif.csa_active = true; + /* +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -754,8 +754,6 @@ int rt2x00queue_clear_beacon(struct rt2x + if (unlikely(!intf->beacon)) + return -ENOBUFS; - mutex_lock(&local->chanctx_mtx); - if (local->use_chanctx) { -@@ -1039,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct - mutex_unlock(&local->chanctx_mtx); +- mutex_lock(&intf->beacon_skb_mutex); +- + /* + * Clean up the beacon skb. + */ +@@ -768,13 +766,11 @@ int rt2x00queue_clear_beacon(struct rt2x + if (rt2x00dev->ops->lib->clear_beacon) + rt2x00dev->ops->lib->clear_beacon(intf->beacon); - sdata->csa_chandef = csa_ie.chandef; -+ sdata->vif.csa_active = true; +- mutex_unlock(&intf->beacon_skb_mutex); +- + return 0; + } - if (csa_ie.mode) - ieee80211_stop_queues_by_reason(&local->hw, ---- a/net/mac80211/chan.c -+++ b/net/mac80211/chan.c -@@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required( +-int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev, +- struct ieee80211_vif *vif) ++int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_vif *vif) { - struct ieee80211_sub_if_data *sdata; + struct rt2x00_intf *intf = vif_to_intf(vif); + struct skb_frame_desc *skbdesc; +@@ -815,19 +811,6 @@ int rt2x00queue_update_beacon_locked(str -+ lockdep_assert_held(&local->mtx); -+ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->radar_required) { ---- a/net/mac80211/ibss.c -+++ b/net/mac80211/ibss.c -@@ -294,7 +294,6 @@ static void __ieee80211_sta_join_ibss(st - } + } + +-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; - mutex_lock(&local->mtx); -- ieee80211_vif_release_channel(sdata); - if (ieee80211_vif_use_channel(sdata, &chandef, - ifibss->fixed_channel ? - IEEE80211_CHANCTX_SHARED : -@@ -303,6 +302,7 @@ static void __ieee80211_sta_join_ibss(st - mutex_unlock(&local->mtx); + if (!sc->p2p_ps_timer) +@@ -1767,14 +1766,9 @@ void ath9k_update_p2p_ps(struct ath_soft return; - } -+ sdata->radar_required = radar_required; - mutex_unlock(&local->mtx); - - memcpy(ifibss->bssid, bssid, ETH_ALEN); -@@ -318,7 +318,6 @@ static void __ieee80211_sta_join_ibss(st - rcu_assign_pointer(ifibss->presp, presp); - mgmt = (void *)presp->head; - -- sdata->radar_required = radar_required; - sdata->vif.bss_conf.enable_beacon = true; - sdata->vif.bss_conf.beacon_int = beacon_int; - sdata->vif.bss_conf.basic_rates = basic_rates; -@@ -386,7 +385,7 @@ static void __ieee80211_sta_join_ibss(st - presp->head_len, 0, GFP_KERNEL); - cfg80211_put_bss(local->hw.wiphy, bss); - netif_carrier_on(sdata->dev); -- cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); -+ cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL); + + 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 ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, -@@ -802,6 +801,8 @@ ieee80211_ibss_process_chanswitch(struct - int err; - u32 sta_flags; + static 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); + } -+ sdata_assert_lock(sdata); -+ - sta_flags = IEEE80211_STA_DISABLE_VHT; - switch (ifibss->chandef.width) { - case NL80211_CHAN_WIDTH_5: -@@ -1471,6 +1472,11 @@ static void ieee80211_rx_mgmt_probe_req( - memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN); - ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa); - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; -+ -+ /* avoid excessive retries for probe request to wildcard SSIDs */ -+ if (pos[1] == 0) -+ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK; -+ - ieee80211_tx_skb(sdata, skb); +@@ -2232,14 +2230,6 @@ static void ath9k_sw_scan_complete(struc + clear_bit(ATH_OP_SCANNING, &common->op_flags); } ---- a/net/mac80211/mesh.c -+++ b/net/mac80211/mesh.c -@@ -872,6 +872,8 @@ ieee80211_mesh_process_chnswitch(struct - if (!ifmsh->mesh_id) - return false; - -+ sdata_assert_lock(sdata); -+ - sta_flags = IEEE80211_STA_DISABLE_VHT; - switch (sdata->vif.bss_conf.chandef.width) { - case NL80211_CHAN_WIDTH_20_NOHT: ---- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c -+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c -@@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf - struct brcmf_cfg80211_info *cfg = ifp->drvr->config; - struct net_device *ndev = ifp->ndev; - struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; -+ struct ieee80211_channel *chan; - s32 err = 0; - - if (ifp->vif->mode == WL_MODE_AP) { -@@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf - } else if (brcmf_is_linkup(e)) { - brcmf_dbg(CONN, "Linkup\n"); - if (brcmf_is_ibssmode(ifp->vif)) { -+ chan = ieee80211_get_channel(cfg->wiphy, cfg->channel); - memcpy(profile->bssid, e->addr, ETH_ALEN); - wl_inform_ibss(cfg, ndev, e->addr); -- cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); -+ cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL); - clear_bit(BRCMF_VIF_STATUS_CONNECTING, - &ifp->vif->sme_state); - set_bit(BRCMF_VIF_STATUS_CONNECTED, ---- a/drivers/net/wireless/libertas/cfg.c -+++ b/drivers/net/wireless/libertas/cfg.c -@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_pri - memcpy(priv->wdev->ssid, params->ssid, params->ssid_len); - priv->wdev->ssid_len = params->ssid_len; - -- cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL); -+ cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan, -+ GFP_KERNEL); - - /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */ - priv->connect_status = LBS_CONNECTED; ---- a/drivers/net/wireless/mwifiex/cfg80211.c -+++ b/drivers/net/wireless/mwifiex/cfg80211.c -@@ -1881,7 +1881,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy - params->privacy); - done: - if (!ret) { -- cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); -+ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, -+ params->chandef.chan, GFP_KERNEL); - dev_dbg(priv->adapter->dev, - "info: joined/created adhoc network with bssid" - " %pM successfully\n", priv->cfg_bssid); ---- a/drivers/net/wireless/rndis_wlan.c -+++ b/drivers/net/wireless/rndis_wlan.c -@@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(s - bssid, req_ie, req_ie_len, - resp_ie, resp_ie_len, GFP_KERNEL); - } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC) -- cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL); -+ cfg80211_ibss_joined(usbdev->net, bssid, -+ get_current_channel(usbdev, NULL), -+ GFP_KERNEL); - - kfree(info); - ---- a/net/wireless/ibss.c -+++ b/net/wireless/ibss.c -@@ -14,7 +14,8 @@ - #include "rdev-ops.h" +-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) + { +@@ -875,7 +554,8 @@ static int ieee80211_set_monitor_channel + } --void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) -+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, -+ struct ieee80211_channel *channel) + 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 wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_bss *bss; -@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_d - if (!wdev->ssid_len) - return; + struct probe_resp *new, *old; -- bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, -- wdev->ssid, wdev->ssid_len, -+ bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, - WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); +@@ -891,6 +571,11 @@ static int ieee80211_set_probe_resp(stru + new->len = resp_len; + memcpy(new->data, resp, resp_len); - if (WARN_ON(!bss)) -@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_d - #endif ++ 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 } --void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) -+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, -+ struct ieee80211_channel *channel, gfp_t gfp) + 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 wireless_dev *wdev = dev->ieee80211_ptr; - struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct cfg80211_event *ev; - unsigned long flags; - -- trace_cfg80211_ibss_joined(dev, bssid); -+ trace_cfg80211_ibss_joined(dev, bssid, channel); + 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])); ++ } + -+ if (WARN_ON(!channel)) -+ return; + /* 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; - ev = kzalloc(sizeof(*ev), gfp); - if (!ev) - return; +- 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; - ev->type = EVENT_IBSS_JOINED; -- memcpy(ev->cr.bssid, bssid, ETH_ALEN); -+ memcpy(ev->ij.bssid, bssid, ETH_ALEN); -+ ev->ij.channel = channel; +- 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 - spin_lock_irqsave(&wdev->event_lock, flags); - list_add_tail(&ev->list, &wdev->event_list); -@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211 + 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; - wdev->ibss_fixed = params->channel_fixed; - wdev->ibss_dfs_possible = params->userspace_handles_dfs; -+ wdev->chandef = params->chandef; - #ifdef CPTCFG_CFG80211_WEXT - wdev->wext.ibss.chandef = params->chandef; - #endif -@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct - - wdev->current_bss = NULL; - wdev->ssid_len = 0; -+ memset(&wdev->chandef, 0, sizeof(wdev->chandef)); - #ifdef CPTCFG_CFG80211_WEXT - if (!nowext) - wdev->wext.ibss.ssid_len = 0; ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, - TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) - ); + switch (sdata->vif.type) { +@@ -3210,20 +2905,13 @@ static int ieee80211_set_csa_beacon(stru + IEEE80211_MAX_CSA_COUNTERS_NUM)) + return -EINVAL; --DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, -- TP_PROTO(struct net_device *netdev, const u8 *addr), -- TP_ARGS(netdev, addr) --); +- /* 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)); - - DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, - TP_PROTO(struct net_device *netdev, const u8 *addr), - TP_ARGS(netdev, addr) -@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_r - TP_ARGS(netdev, addr) - ); - -+TRACE_EVENT(cfg80211_ibss_joined, -+ TP_PROTO(struct net_device *netdev, const u8 *bssid, -+ struct ieee80211_channel *channel), -+ TP_ARGS(netdev, bssid, channel), -+ TP_STRUCT__entry( -+ NETDEV_ENTRY -+ MAC_ENTRY(bssid) -+ CHAN_ENTRY -+ ), -+ TP_fast_assign( -+ NETDEV_ASSIGN; -+ MAC_ASSIGN(bssid, bssid); -+ CHAN_ASSIGN(channel); -+ ), -+ TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT, -+ NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) -+); -+ - TRACE_EVENT(cfg80211_probe_status, - TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, - bool acked), ---- a/net/wireless/util.c -+++ b/net/wireless/util.c -@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct - ev->dc.reason, true); - break; - case EVENT_IBSS_JOINED: -- __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); -+ __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, -+ ev->ij.channel); - break; - } - wdev_unlock(wdev); -@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct - */ - mutex_lock_nested(&wdev_iter->mtx, 1); - __acquire(wdev_iter->mtx); -- cfg80211_get_chan_state(wdev_iter, &ch, &chmode); -+ cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); - wdev_unlock(wdev_iter); - - switch (chmode) { ---- a/net/wireless/chan.c -+++ b/net/wireless/chan.c -@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct - void - cfg80211_get_chan_state(struct wireless_dev *wdev, - struct ieee80211_channel **chan, -- enum cfg80211_chan_mode *chanmode) -+ enum cfg80211_chan_mode *chanmode, -+ u8 *radar_detect) - { - *chan = NULL; - *chanmode = CHAN_MODE_UNDEFINED; -@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_ - !wdev->ibss_dfs_possible) - ? CHAN_MODE_SHARED - : CHAN_MODE_EXCLUSIVE; -+ -+ /* consider worst-case - IBSS can try to return to the -+ * original user-specified channel as creator */ -+ if (wdev->ibss_dfs_possible) -+ *radar_detect |= BIT(wdev->chandef.width); - return; - } - break; -@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_ - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - if (wdev->cac_started) { -- *chan = wdev->channel; -+ *chan = wdev->chandef.chan; - *chanmode = CHAN_MODE_SHARED; -+ *radar_detect |= BIT(wdev->chandef.width); - } else if (wdev->beacon_interval) { -- *chan = wdev->channel; -+ *chan = wdev->chandef.chan; - *chanmode = CHAN_MODE_SHARED; -+ -+ if (cfg80211_chandef_dfs_required(wdev->wiphy, -+ &wdev->chandef)) -+ *radar_detect |= BIT(wdev->chandef.width); - } - return; - case NL80211_IFTYPE_MESH_POINT: - if (wdev->mesh_id_len) { -- *chan = wdev->channel; -+ *chan = wdev->chandef.chan; - *chanmode = CHAN_MODE_SHARED; -+ -+ if (cfg80211_chandef_dfs_required(wdev->wiphy, -+ &wdev->chandef)) -+ *radar_detect |= BIT(wdev->chandef.width); - } - return; - case NL80211_IFTYPE_MONITOR: ---- a/net/wireless/mesh.c -+++ b/net/wireless/mesh.c -@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211 - if (!err) { - memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); - wdev->mesh_id_len = setup->mesh_id_len; -- wdev->channel = setup->chandef.chan; -+ wdev->chandef = setup->chandef; +- 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(); } - return err; -@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg - err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, - chandef->chan); - if (!err) -- wdev->channel = chandef->chan; -+ wdev->chandef = *chandef; + 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); + } - return err; - } -@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct - err = rdev_leave_mesh(rdev, dev); - if (!err) { - wdev->mesh_id_len = 0; -- wdev->channel = NULL; -+ memset(&wdev->chandef, 0, sizeof(wdev->chandef)); - rdev_set_qos_map(rdev, dev, NULL); - } +-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; + } ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_devic - if (WARN_ON(!wdev->cac_started)) - return; +- +-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); -- if (WARN_ON(!wdev->channel)) -+ if (WARN_ON(!wdev->chandef.chan)) - return; ++ ++/* 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; + }; - switch (event) { ---- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c -+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c -@@ -5065,6 +5065,10 @@ static u16 ar9003_hw_get_max_edge_power( - break; - } - } ++struct ieee80211_csa_settings { ++ const u16 *counter_offsets_beacon; ++ const u16 *counter_offsets_presp; + -+ if (is2GHz && !twiceMaxEdgePower) -+ twiceMaxEdgePower = 60; ++ int n_counter_offsets_beacon; ++ int n_counter_offsets_presp; + - return twiceMaxEdgePower; - } ++ 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; + }; ---- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c -+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c -@@ -23,10 +23,11 @@ - #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT - #define MAX_MAG_DELTA 11 - #define MAX_PHS_DELTA 10 -+#define MAXIQCAL 3 - - struct coeff { -- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; -- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; -+ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; -+ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; - int iqc_coeff[2]; + struct probe_resp { + struct rcu_head rcu_head; + int len; ++ u16 csa_counter_offsets[IEEE80211_MAX_CSA_COUNTERS_NUM]; + u8 data[0]; }; -@@ -800,7 +801,7 @@ static bool ar9003_hw_calc_iq_corr(struc - if (q_q_coff > 63) - q_q_coff = 63; +@@ -754,8 +767,6 @@ struct ieee80211_sub_if_data { + struct mac80211_qos_map __rcu *qos_map; -- iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; -+ iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); + 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; - ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", - chain_idx, iqc_coeff[0]); -@@ -831,7 +832,7 @@ static bool ar9003_hw_calc_iq_corr(struc - if (q_q_coff > 63) - q_q_coff = 63; + /* 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); -- iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; -+ iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); - ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", - chain_idx, iqc_coeff[1]); -@@ -839,7 +840,8 @@ static bool ar9003_hw_calc_iq_corr(struc - return true; - } ++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; --static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, -+static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL], -+ int nmeasurement, - int max_delta) - { - int mp_max = -64, max_idx = 0; -@@ -848,20 +850,20 @@ static void ar9003_hw_detect_outlier(int - - /* find min/max mismatch across all calibrated gains */ - for (i = 0; i < nmeasurement; i++) { -- if (mp_coeff[i] > mp_max) { -- mp_max = mp_coeff[i]; -+ if (mp_coeff[i][0] > mp_max) { -+ mp_max = mp_coeff[i][0]; - max_idx = i; -- } else if (mp_coeff[i] < mp_min) { -- mp_min = mp_coeff[i]; -+ } else if (mp_coeff[i][0] < mp_min) { -+ mp_min = mp_coeff[i][0]; - min_idx = i; - } - } + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - /* find average (exclude max abs value) */ - for (i = 0; i < nmeasurement; i++) { -- if ((abs(mp_coeff[i]) < abs(mp_max)) || -- (abs(mp_coeff[i]) < abs(mp_min))) { -- mp_avg += mp_coeff[i]; -+ if ((abs(mp_coeff[i][0]) < abs(mp_max)) || -+ (abs(mp_coeff[i][0]) < abs(mp_min))) { -+ mp_avg += mp_coeff[i][0]; - mp_count++; - } - } -@@ -873,7 +875,7 @@ static void ar9003_hw_detect_outlier(int - if (mp_count) - mp_avg /= mp_count; - else -- mp_avg = mp_coeff[nmeasurement - 1]; -+ mp_avg = mp_coeff[nmeasurement - 1][0]; +@@ -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; - /* detect outlier */ - if (abs(mp_max - mp_min) > max_delta) { -@@ -882,15 +884,16 @@ static void ar9003_hw_detect_outlier(int - else - outlier_idx = min_idx; + sdata->noack_map = 0; -- mp_coeff[outlier_idx] = mp_avg; -+ mp_coeff[outlier_idx][0] = mp_avg; - } - } +@@ -1721,6 +1723,8 @@ int ieee80211_if_add(struct ieee80211_lo --static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, -- struct coeff *coeff, -- bool is_reusable) -+static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah, -+ struct coeff *coeff, -+ bool is_reusable) - { - int i, im, nmeasurement; -+ int magnitude, phase; - u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; - struct ath9k_hw_cal_data *caldata = ah->caldata; - -@@ -920,21 +923,30 @@ static void ar9003_hw_tx_iqcal_load_avg_ - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; - -- /* detect outlier only if nmeasurement > 1 */ -- if (nmeasurement > 1) { -- /* Detect magnitude outlier */ -- ar9003_hw_detect_outlier(coeff->mag_coeff[i], -- nmeasurement, MAX_MAG_DELTA); -- -- /* Detect phase outlier */ -- ar9003_hw_detect_outlier(coeff->phs_coeff[i], -- nmeasurement, MAX_PHS_DELTA); -+ /* -+ * Skip normal outlier detection for AR9550. -+ */ -+ if (!AR_SREV_9550(ah)) { -+ /* detect outlier only if nmeasurement > 1 */ -+ if (nmeasurement > 1) { -+ /* Detect magnitude outlier */ -+ ar9003_hw_detect_outlier(coeff->mag_coeff[i], -+ nmeasurement, -+ MAX_MAG_DELTA); -+ -+ /* Detect phase outlier */ -+ ar9003_hw_detect_outlier(coeff->phs_coeff[i], -+ nmeasurement, -+ MAX_PHS_DELTA); -+ } - } + ndev->features |= local->hw.netdev_features; - for (im = 0; im < nmeasurement; im++) { -+ magnitude = coeff->mag_coeff[i][im][0]; -+ phase = coeff->phs_coeff[i][im][0]; ++ 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" -- coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | -- ((coeff->phs_coeff[i][im] & 0x7f) << 7); -+ coeff->iqc_coeff[0] = -+ (phase & 0x7f) | ((magnitude & 0x7f) << 7); + /* 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; - if ((im % 2) == 0) - REG_RMW_FIELD(ah, tx_corr_coeff[im][i], -@@ -991,7 +1003,63 @@ static bool ar9003_hw_tx_iq_cal_run(stru - return true; - } +- 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 ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) -+static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, -+ struct coeff *coeff, -+ int i, int nmeasurement) -+{ -+ struct ath_common *common = ath9k_hw_common(ah); -+ int im, ix, iy, temp; -+ -+ for (im = 0; im < nmeasurement; im++) { -+ for (ix = 0; ix < MAXIQCAL - 1; ix++) { -+ for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { -+ if (coeff->mag_coeff[i][im][iy] < -+ coeff->mag_coeff[i][im][ix]) { -+ temp = coeff->mag_coeff[i][im][ix]; -+ coeff->mag_coeff[i][im][ix] = -+ coeff->mag_coeff[i][im][iy]; -+ coeff->mag_coeff[i][im][iy] = temp; -+ } -+ if (coeff->phs_coeff[i][im][iy] < -+ coeff->phs_coeff[i][im][ix]) { -+ temp = coeff->phs_coeff[i][im][ix]; -+ coeff->phs_coeff[i][im][ix] = -+ coeff->phs_coeff[i][im][iy]; -+ coeff->phs_coeff[i][im][iy] = temp; -+ } -+ } -+ } -+ coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2]; -+ coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2]; -+ -+ ath_dbg(common, CALIBRATE, -+ "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n", -+ i, im, -+ coeff->mag_coeff[i][im][0], -+ coeff->phs_coeff[i][im][0]); -+ } -+} -+ -+static bool ar955x_tx_iq_cal_median(struct ath_hw *ah, -+ struct coeff *coeff, -+ int iqcal_idx, -+ int nmeasurement) -+{ -+ int i; -+ -+ if ((iqcal_idx + 1) != MAXIQCAL) -+ return false; -+ -+ for (i = 0; i < AR9300_MAX_CHAINS; i++) { -+ __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement); -+ } -+ -+ return true; -+} -+ -+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, -+ int iqcal_idx, -+ bool is_reusable) +-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 ath_common *common = ath9k_hw_common(ah); - const u32 txiqcal_status[AR9300_MAX_CHAINS] = { -@@ -1004,10 +1072,11 @@ static void ar9003_hw_tx_iq_cal_post_pro - AR_PHY_CHAN_INFO_TAB_1, - AR_PHY_CHAN_INFO_TAB_2, - }; -- struct coeff coeff; -+ static struct coeff coeff; - s32 iq_res[6]; - int i, im, j; -- int nmeasurement; -+ int nmeasurement = 0; -+ bool outlier_detect = true; - - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->txchainmask & (1 << i))) -@@ -1065,17 +1134,23 @@ static void ar9003_hw_tx_iq_cal_post_pro - goto tx_iqcal_fail; - } + struct wireless_dev *wdev = dev->ieee80211_ptr; -- coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; -- coeff.phs_coeff[i][im] = -+ coeff.phs_coeff[i][im][iqcal_idx] = -+ coeff.iqc_coeff[0] & 0x7f; -+ coeff.mag_coeff[i][im][iqcal_idx] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; - -- if (coeff.mag_coeff[i][im] > 63) -- coeff.mag_coeff[i][im] -= 128; -- if (coeff.phs_coeff[i][im] > 63) -- coeff.phs_coeff[i][im] -= 128; -+ if (coeff.mag_coeff[i][im][iqcal_idx] > 63) -+ coeff.mag_coeff[i][im][iqcal_idx] -= 128; -+ if (coeff.phs_coeff[i][im][iqcal_idx] > 63) -+ coeff.phs_coeff[i][im][iqcal_idx] -= 128; - } - } -- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable); -+ -+ if (AR_SREV_9550(ah)) -+ outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff, -+ iqcal_idx, nmeasurement); -+ if (outlier_detect) -+ ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable); +@@ -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 + } - return; + 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) + ); -@@ -1409,7 +1484,7 @@ skip_tx_iqcal: - } +-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) + ); - if (txiqcal_done) -- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); -+ ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); - else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) - ar9003_hw_tx_iq_cal_reload(ah); +-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) + ); -@@ -1455,14 +1530,38 @@ skip_tx_iqcal: - return true; - } +-DEFINE_EVENT(tx_rx_evt, rdev_set_ringparam, +- TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), +- TP_ARGS(wiphy, rx, tx) +-); +- + DEFINE_EVENT(tx_rx_evt, rdev_set_antenna, + TP_PROTO(struct wiphy *wiphy, u32 tx, u32 rx), + TP_ARGS(wiphy, rx, tx) +@@ -1725,40 +1710,6 @@ TRACE_EVENT(rdev_set_noack_map, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) + ); -+static bool do_ar9003_agc_cal(struct ath_hw *ah) +-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 ath_common *common = ath9k_hw_common(ah); -+ bool status; -+ -+ REG_WRITE(ah, AR_PHY_AGC_CONTROL, -+ REG_READ(ah, AR_PHY_AGC_CONTROL) | -+ AR_PHY_AGC_CONTROL_CAL); -+ -+ status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, -+ AR_PHY_AGC_CONTROL_CAL, -+ 0, AH_WAIT_TIMEOUT); -+ if (!status) { -+ ath_dbg(common, CALIBRATE, -+ "offset calibration failed to complete in %d ms," -+ "noisy environment?\n", -+ AH_WAIT_TIMEOUT / 1000); -+ return false; -+ } ++ struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy); + -+ return true; ++ if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) ++ return -EINVAL; ++ ++ return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending); +} + - static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, - struct ath9k_channel *chan) - { - struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_cal_data *caldata = ah->caldata; - bool txiqcal_done = false; -- bool is_reusable = true, status = true; -+ bool status = true; - bool run_agc_cal = false, sep_iq_cal = false; -+ int i = 0; - - /* Use chip chainmask only for calibration */ - ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); -@@ -1485,7 +1584,12 @@ static bool ar9003_hw_init_cal_soc(struc - * AGC calibration. Specifically, AR9550 in SoC chips. - */ - if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { -- txiqcal_done = true; -+ if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, -+ AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) { -+ txiqcal_done = true; -+ } else { -+ txiqcal_done = false; ++static void ieee80211_get_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); + } - run_agc_cal = true; - } else { - sep_iq_cal = true; -@@ -1512,27 +1616,37 @@ skip_tx_iqcal: - if (AR_SREV_9330_11(ah)) - ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); - -- /* Calibrate the AGC */ -- REG_WRITE(ah, AR_PHY_AGC_CONTROL, -- REG_READ(ah, AR_PHY_AGC_CONTROL) | -- AR_PHY_AGC_CONTROL_CAL); -- -- /* Poll for offset calibration complete */ -- status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, -- AR_PHY_AGC_CONTROL_CAL, -- 0, AH_WAIT_TIMEOUT); -- } -+ /* -+ * For non-AR9550 chips, we just trigger AGC calibration -+ * in the HW, poll for completion and then process -+ * the results. -+ * -+ * For AR955x, we run it multiple times and use -+ * median IQ correction. -+ */ -+ if (!AR_SREV_9550(ah)) { -+ status = do_ar9003_agc_cal(ah); -+ if (!status) -+ return false; - -- if (!status) { -- ath_dbg(common, CALIBRATE, -- "offset calibration failed to complete in %d ms; noisy environment?\n", -- AH_WAIT_TIMEOUT / 1000); -- return false; -+ if (txiqcal_done) -+ ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); -+ } else { -+ if (!txiqcal_done) { -+ status = do_ar9003_agc_cal(ah); -+ if (!status) -+ return false; -+ } else { -+ for (i = 0; i < MAXIQCAL; i++) { -+ status = do_ar9003_agc_cal(ah); -+ if (!status) -+ return false; -+ ar9003_hw_tx_iq_cal_post_proc(ah, i, false); -+ } ++ } ++ ++do_survey: ++ i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; ++ /* Get survey stats for current channel */ ++ survey.filled = 0; ++ ++ rcu_read_lock(); ++ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); ++ if (chanctx_conf) ++ channel = chanctx_conf->def.chan; ++ else ++ channel = NULL; ++ rcu_read_unlock(); ++ ++ if (channel) { ++ q = 0; ++ do { ++ survey.filled = 0; ++ if (drv_get_survey(local, q, &survey) != 0) { ++ survey.filled = 0; ++ break; + } -+ } - } - -- if (txiqcal_done) -- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); -- - /* Revert chainmask to runtime parameters */ - ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - ---- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h -+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h -@@ -15,6 +15,8 @@ - #ifndef RTL8187_H - #define RTL8187_H - -+#include -+ - #include "rtl818x.h" - #include "leds.h" - -@@ -139,7 +141,10 @@ struct rtl8187_priv { - u8 aifsn[4]; - u8 rfkill_mask; - struct { -- __le64 buf; -+ union { -+ __le64 buf; -+ u8 dummy1[L1_CACHE_BYTES]; -+ } ____cacheline_aligned; - struct sk_buff_head queue; - } b_tx_status; /* This queue is used by both -b and non-b devices */ - struct mutex io_mutex; -@@ -147,7 +152,8 @@ struct rtl8187_priv { - u8 bits8; - __le16 bits16; - __le32 bits32; -- } *io_dmabuf; -+ u8 dummy2[L1_CACHE_BYTES]; -+ } *io_dmabuf ____cacheline_aligned; - bool rfkill_off; - u16 seqno; - }; ---- a/net/mac80211/wme.c -+++ b/net/mac80211/wme.c -@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80 - return IEEE80211_AC_BE; - } - -+ if (skb->protocol == sdata->control_port_protocol) { -+ skb->priority = 7; -+ return ieee80211_downgrade_queue(sdata, skb); ++ q++; ++ } while (channel != survey.channel); + } + - /* use the data classifier to determine what 802.1d tag the - * data frame has */ - rcu_read_lock(); ---- a/drivers/net/wireless/ath/ath9k/xmit.c -+++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -1444,14 +1444,16 @@ void ath_tx_aggr_sleep(struct ieee80211_ - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - -- if (!tid->sched) -- continue; -- - ac = tid->ac; - txq = ac->txq; - - ath_txq_lock(sc, txq); - -+ if (!tid->sched) { -+ ath_txq_unlock(sc, txq); -+ continue; -+ } ++ if (survey.filled) ++ data[i++] = survey.channel->center_freq; ++ else ++ data[i++] = 0; ++ if (survey.filled & SURVEY_INFO_NOISE_DBM) ++ data[i++] = (u8)survey.noise; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME) ++ data[i++] = survey.channel_time; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) ++ data[i++] = survey.channel_time_busy; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) ++ data[i++] = survey.channel_time_ext_busy; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) ++ data[i++] = survey.channel_time_rx; ++ else ++ data[i++] = -1LL; ++ if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) ++ data[i++] = survey.channel_time_tx; ++ else ++ data[i++] = -1LL; + - buffered = ath_tid_has_buffered(tid); - - tid->sched = false; -@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw - txq->stopped = true; - } - -+ if (txctl->an) -+ tid = ath_get_skb_tid(sc, txctl->an, skb); -+ - if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { - ath_txq_unlock(sc, txq); - txq = sc->tx.uapsdq; - ath_txq_lock(sc, txq); - } else if (txctl->an && - ieee80211_is_data_present(hdr->frame_control)) { -- tid = ath_get_skb_tid(sc, txctl->an, skb); -- - WARN_ON(tid->ac->txq != txctl->txq); - - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ---- a/drivers/net/wireless/ath/ath9k/init.c -+++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -943,6 +943,7 @@ static void ath9k_set_hw_capab(struct at - hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; - hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; -+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - - hw->queues = 4; - hw->max_rates = 4; ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1700,14 +1700,8 @@ void ieee80211_stop_queue_by_reason(stru - void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); - void ieee80211_add_pending_skb(struct ieee80211_local *local, - struct sk_buff *skb); --void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, -- struct sk_buff_head *skbs, -- void (*fn)(void *data), void *data); --static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, -- struct sk_buff_head *skbs) --{ -- ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); --} -+void ieee80211_add_pending_skbs(struct ieee80211_local *local, -+ struct sk_buff_head *skbs); - void ieee80211_flush_queues(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); - ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee - return -ENOENT; - } - --static void cleanup_single_sta(struct sta_info *sta) -+static void __cleanup_single_sta(struct sta_info *sta) - { - int ac, i; - struct tid_ampdu_tx *tid_tx; -@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct st - struct ieee80211_local *local = sdata->local; - struct ps_data *ps; - -- if (test_sta_flag(sta, WLAN_STA_PS_STA)) { -+ if (test_sta_flag(sta, WLAN_STA_PS_STA) || -+ test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { - if (sta->sdata->vif.type == NL80211_IFTYPE_AP || - sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - ps = &sdata->bss->ps; -@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct st - return; - - clear_sta_flag(sta, WLAN_STA_PS_STA); -+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER); - - atomic_dec(&ps->num_sta_ps); - sta_info_recalc_tim(sta); -@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct st - ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); - kfree(tid_tx); - } ++ mutex_unlock(&local->sta_mtx); ++ ++ if (WARN_ON(i != STA_STATS_LEN)) ++ return; ++ ++ drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN])); +} - -+static void cleanup_single_sta(struct sta_info *sta) ++ ++static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data) +{ -+ struct ieee80211_sub_if_data *sdata = sta->sdata; -+ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ int sz_sta_stats = 0; + -+ __cleanup_single_sta(sta); - sta_info_free(local, sta); - } - -@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct i - rcu_read_unlock(); - - spin_lock_init(&sta->lock); -+ spin_lock_init(&sta->ps_lock); - INIT_WORK(&sta->drv_unblock_wk, sta_unblock); - INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); - mutex_init(&sta->ampdu_mlme.mtx); -@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct - goto out_err; - } - -- /* notify driver */ -- err = sta_info_insert_drv_state(local, sdata, sta); -- if (err) -- goto out_err; -- - local->num_sta++; - local->sta_generation++; - smp_mb(); - -+ /* simplify things and don't accept BA sessions yet */ -+ set_sta_flag(sta, WLAN_STA_BLOCK_BA); ++ if (sset == ETH_SS_STATS) { ++ sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); ++ memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); ++ } ++ drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); ++} + - /* make the station visible */ - sta_info_hash_add(local, sta); - - list_add_rcu(&sta->list, &local->sta_list); - -+ /* notify driver */ -+ err = sta_info_insert_drv_state(local, sdata, sta); -+ if (err) -+ goto out_remove; ++static int ieee80211_get_regs_len(struct net_device *dev) ++{ ++ return 0; ++} ++ ++static void ieee80211_get_regs(struct net_device *dev, ++ struct ethtool_regs *regs, ++ void *data) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; + - set_sta_flag(sta, WLAN_STA_INSERTED); -+ /* accept BA sessions now */ -+ clear_sta_flag(sta, WLAN_STA_BLOCK_BA); ++ 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; + } - ieee80211_recalc_min_chandef(sdata); - ieee80211_sta_debugfs_add(sta); -@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct - mesh_accept_plinks_update(sdata); +@@ -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; - return 0; -+ out_remove: -+ sta_info_hash_del(local, sta); -+ list_del_rcu(&sta->list); -+ local->num_sta--; -+ synchronize_net(); -+ __cleanup_single_sta(sta); - out_err: - mutex_unlock(&local->sta_mtx); - rcu_read_lock(); -@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta - } - EXPORT_SYMBOL(ieee80211_find_sta); + /* 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 { + dfs_cac = $8 + } +@@ -114,7 +104,7 @@ function parse_reg_rule() --static void clear_sta_ps_flags(void *_sta) -+/* powersave support code */ -+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) - { -- struct sta_info *sta = _sta; - struct ieee80211_sub_if_data *sdata = sta->sdata; -+ struct ieee80211_local *local = sdata->local; -+ struct sk_buff_head pending; -+ int filtered = 0, buffered = 0, ac; -+ unsigned long flags; - struct ps_data *ps; + } + 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++ + } - if (sdata->vif.type == NL80211_IFTYPE_AP || -@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_st - else - return; +--- 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; -- clear_sta_flag(sta, WLAN_STA_PS_DRIVER); -- if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) -- atomic_dec(&ps->num_sta_ps); --} -- --/* powersave support code */ --void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) --{ -- struct ieee80211_sub_if_data *sdata = sta->sdata; -- struct ieee80211_local *local = sdata->local; -- struct sk_buff_head pending; -- int filtered = 0, buffered = 0, ac; -- unsigned long flags; -- - clear_sta_flag(sta, WLAN_STA_SP); + 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); - BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); -@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(str + if (ret >= 0) +@@ -62,8 +61,7 @@ static ssize_t ieee80211_if_write( - skb_queue_head_init(&pending); + ret = -ENODEV; + rtnl_lock(); +- if (sdata->dev->reg_state == NETREG_REGISTERED) +- ret = (*write)(sdata, buf, count); ++ ret = (*write)(sdata, buf, count); + rtnl_unlock(); -+ /* sync with ieee80211_tx_h_unicast_ps_buf */ -+ spin_lock(&sta->ps_lock); - /* Send all buffered frames to the station */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - int count = skb_queue_len(&pending), tmp; -@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(str - buffered += tmp - count; - } + return ret; +--- a/drivers/net/wireless/b43/xmit.c ++++ b/drivers/net/wireless/b43/xmit.c +@@ -811,9 +811,13 @@ void b43_rx(struct b43_wldev *dev, struc + break; + case B43_PHYTYPE_G: + status.band = IEEE80211_BAND_2GHZ; +- /* chanid is the radio channel cookie value as used +- * to tune the radio. */ +- status.freq = chanid + 2400; ++ /* Somewhere between 478.104 and 508.1084 firmware for G-PHY ++ * has been modified to be compatible with N-PHY and others. ++ */ ++ if (dev->fw.rev >= 508) ++ status.freq = ieee80211_channel_to_frequency(chanid, status.band); ++ else ++ status.freq = chanid + 2400; + break; + case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -5216,6 +5216,7 @@ static int b43_wireless_core_attach(stru + /* We don't support 5 GHz on some PHYs yet */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: ++ case B43_PHYTYPE_G: + case B43_PHYTYPE_N: + case B43_PHYTYPE_LP: + case B43_PHYTYPE_HT: +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -935,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, + if (!band_rule_found) + band_rule_found = freq_in_rule_band(fr, center_freq); -- ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); -+ ieee80211_add_pending_skbs(local, &pending); -+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER); -+ clear_sta_flag(sta, WLAN_STA_PS_STA); -+ spin_unlock(&sta->ps_lock); -+ -+ atomic_dec(&ps->num_sta_ps); +- 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)); - /* This station just woke up and isn't aware of our SMPS state */ - if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat { - * @drv_unblock_wk: used for driver PS unblocking - * @listen_interval: listen interval of this station, when we're acting as AP - * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly -+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking - * @ps_tx_buf: buffers (per AC) of frames to transmit to this station - * when it leaves power saving state or polls - * @tx_filtered: buffers (per AC) of frames we already tried to -@@ -356,10 +357,8 @@ struct sta_info { - /* use the accessors defined below */ - unsigned long _flags; - -- /* -- * STA powersave frame queues, no more than the internal -- * locking required. -- */ -+ /* STA powersave lock and frame queues */ -+ spinlock_t ps_lock; - struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; - struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; - unsigned long driver_buffered_tids; ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ie - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + if (band_rule_found && bw_fits) + return rr; +@@ -1019,10 +1019,10 @@ static void chan_reg_rule_print_dbg(cons } + #endif --void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, -- struct sk_buff_head *skbs, -- void (*fn)(void *data), void *data) -+void ieee80211_add_pending_skbs(struct ieee80211_local *local, -+ struct sk_buff_head *skbs) +-/* 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) { - struct ieee80211_hw *hw = &local->hw; - struct sk_buff *skb; -@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struc - __skb_queue_tail(&local->pending[queue], skb); - } - -- if (fn) -- fn(data); +- int q; - - for (i = 0; i < hw->queues; i++) - __ieee80211_wake_queue(hw, i, - IEEE80211_QUEUE_STOP_REASON_SKB_ADD); ---- a/net/wireless/reg.c -+++ b/net/wireless/reg.c -@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regu +- 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; - case NL80211_REGDOM_SET_BY_USER: - treatment = reg_process_hint_user(reg_request); -- if (treatment == REG_REQ_OK || -+ if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET) - return; - schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); ---- a/drivers/net/wireless/ath/ath9k/debug.c -+++ b/drivers/net/wireless/ath/ath9k/debug.c -@@ -866,6 +866,12 @@ static ssize_t read_file_reset(struct fi - "%17s: %2d\n", "PLL RX Hang", - sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); - len += scnprintf(buf + len, sizeof(buf) - len, -+ "%17s: %2d\n", "MAC Hang", -+ sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); -+ len += scnprintf(buf + len, sizeof(buf) - len, -+ "%17s: %2d\n", "Stuck Beacon", -+ sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); -+ len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "MCI Reset", - sc->debug.stats.reset[RESET_TYPE_MCI]); ---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c -+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c -@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct - - if (IS_CHAN_A_FAST_CLOCK(ah, chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); -- if (IS_CHAN_QUARTER_RATE(chan)) -- rfMode |= AR_PHY_MODE_QUARTER; -- if (IS_CHAN_HALF_RATE(chan)) -- rfMode |= AR_PHY_MODE_HALF; - - if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) - REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, ---- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c -+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c -@@ -706,6 +706,7 @@ ath5k_get_survey(struct ieee80211_hw *hw - survey->channel = conf->chandef.chan; - survey->noise = ah->ah_noise_floor; - survey->filled = SURVEY_INFO_NOISE_DBM | -+ SURVEY_INFO_IN_USE | - SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | ---- a/drivers/net/wireless/ath/ath9k/recv.c -+++ b/drivers/net/wireless/ath/ath9k/recv.c -@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx - return NULL; - - /* -- * mark descriptor as zero-length and set the 'more' -- * flag to ensure that both buffers get discarded -+ * Re-check previous descriptor, in case it has been filled -+ * in the mean time. - */ -- rs->rs_datalen = 0; -- rs->rs_more = true; -+ ret = ath9k_hw_rxprocdesc(ah, ds, rs); -+ if (ret == -EINPROGRESS) { -+ /* -+ * mark descriptor as zero-length and set the 'more' -+ * flag to ensure that both buffers get discarded -+ */ -+ rs->rs_datalen = 0; -+ rs->rs_more = true; -+ } - } ++ txq = sc->tx.txq_map[q]; + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; - list_del(&bf->list); -@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struc - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_hdr *hdr; - bool discard_current = sc->rx.discard_next; -- int ret = 0; +@@ -887,6 +885,15 @@ ath_tx_get_tid_subframe(struct ath_softc - /* - * Discard corrupt descriptors which are marked in - * ath_get_next_rx_buf(). - */ -- sc->rx.discard_next = rx_stats->rs_more; - if (discard_current) -- return -EINVAL; -+ goto corrupt; + tx_info = IEEE80211_SKB_CB(skb); + tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + -+ sc->rx.discard_next = false; - - /* - * Discard zero-length packets. - */ - if (!rx_stats->rs_datalen) { - RX_STAT_INC(rx_len_err); -- return -EINVAL; -+ goto corrupt; - } - -- /* -- * rs_status follows rs_datalen so if rs_datalen is too large -- * we can take a hint that hardware corrupted it, so ignore -- * those frames. -- */ -+ /* -+ * rs_status follows rs_datalen so if rs_datalen is too large -+ * we can take a hint that hardware corrupted it, so ignore -+ * those frames. -+ */ - if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { - RX_STAT_INC(rx_len_err); -- return -EINVAL; -+ goto corrupt; - } - - /* Only use status info from the last fragment */ -@@ -1024,10 +1031,8 @@ static int ath9k_rx_skb_preprocess(struc - * This is different from the other corrupt descriptor - * condition handled above. - */ -- if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) { -- ret = -EINVAL; -- goto exit; -- } -+ if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) -+ goto corrupt; - - hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); - -@@ -1043,18 +1048,15 @@ static int ath9k_rx_skb_preprocess(struc - if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) - RX_STAT_INC(rx_spectral); - -- ret = -EINVAL; -- goto exit; -+ return -EINVAL; ++ /* ++ * 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; ++ } } - /* - * everything but the rate is checked here, the rate check is done - * separately to avoid doing two lookups for a rate for each frame. - */ -- if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) { -- ret = -EINVAL; -- goto exit; -- } -+ if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) -+ return -EINVAL; - - if (ath_is_mybeacon(common, hdr)) { - RX_STAT_INC(rx_beacons); -@@ -1064,15 +1066,11 @@ static int ath9k_rx_skb_preprocess(struc - /* - * This shouldn't happen, but have a safety check anyway. - */ -- if (WARN_ON(!ah->curchan)) { -- ret = -EINVAL; -- goto exit; -- } -+ if (WARN_ON(!ah->curchan)) -+ return -EINVAL; - -- if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { -- ret =-EINVAL; -- goto exit; -- } -+ if (ath9k_process_rate(common, hw, rx_stats, rx_status)) -+ return -EINVAL; - - ath9k_process_rssi(common, hw, rx_stats, rx_status); - -@@ -1087,9 +1085,11 @@ static int ath9k_rx_skb_preprocess(struc - sc->rx.num_pkts++; - #endif + 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; + if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + continue; ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ++ continue; --exit: -- sc->rx.discard_next = false; -- return ret; -+ return 0; -+ -+corrupt: -+ sc->rx.discard_next = rx_stats->rs_more; -+ return -EINVAL; + 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); } - static void ath9k_rx_skb_postprocess(struct ath_common *common, ---- a/drivers/net/wireless/ath/ath9k/ani.c -+++ b/drivers/net/wireless/ath/ath9k/ani.c -@@ -176,16 +176,26 @@ static void ath9k_hw_set_ofdm_nil(struct - if (ah->opmode == NL80211_IFTYPE_STATION && - BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) - weak_sig = true; -- - /* -- * OFDM Weak signal detection is always enabled for AP mode. -+ * Newer chipsets are better at dealing with high PHY error counts - -+ * keep weak signal detection enabled when no RSSI threshold is -+ * available to determine if it is needed (mode != STA) - */ -- if (ah->opmode != NL80211_IFTYPE_AP && -- aniState->ofdmWeakSigDetect != weak_sig) { -- ath9k_hw_ani_control(ah, -- ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, -- entry_ofdm->ofdm_weak_signal_on); -- } -+ else if (AR_SREV_9300_20_OR_LATER(ah) && -+ ah->opmode != NL80211_IFTYPE_STATION) -+ weak_sig = true; ++static u32 ar9003_hw_compute_pll_control_soc(struct ath_hw *ah, ++ struct ath9k_channel *chan) ++{ ++ u32 pll; + -+ /* Older chipsets are more sensitive to high PHY error counts */ -+ else if (!AR_SREV_9300_20_OR_LATER(ah) && -+ aniState->ofdmNoiseImmunityLevel >= 8) -+ weak_sig = false; ++ pll = SM(0x5, AR_RTC_9300_SOC_PLL_REFDIV); + -+ if (aniState->ofdmWeakSigDetect != weak_sig) -+ ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, -+ weak_sig); ++ 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); + -+ if (!AR_SREV_9300_20_OR_LATER(ah)) -+ return; ++ 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 (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; -@@ -483,10 +493,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah - - ath_dbg(common, ANI, "Initialize ANI\n"); - -- ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; -- ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; -- ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; -- ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; -+ if (AR_SREV_9300_20_OR_LATER(ah)) { -+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; -+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; -+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; -+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; -+ } else { -+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; -+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; -+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; -+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; -+ } + 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 (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; - ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; ---- a/drivers/net/wireless/ath/ath9k/ani.h -+++ b/drivers/net/wireless/ath/ath9k/ani.h -@@ -22,12 +22,16 @@ - /* units are errors per second */ - #define ATH9K_ANI_OFDM_TRIG_HIGH 3500 - #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 -+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 - - #define ATH9K_ANI_OFDM_TRIG_LOW 400 - #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 -+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 - - #define ATH9K_ANI_CCK_TRIG_HIGH 600 -+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 - #define ATH9K_ANI_CCK_TRIG_LOW 300 -+#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 - - #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 - #define ATH9K_ANI_FIRSTEP_LVL 2 ++ 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 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +@@ -978,7 +978,7 @@ static bool ath9k_rx_prepare(struct ath9 + struct ath_hw *ah = common->ah; + struct ath_htc_rx_status *rxstatus; + struct ath_rx_status rx_stats; +- bool decrypt_error; ++ bool decrypt_error = false; + + if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { + ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",