mirror of https://github.com/hak5/openwrt-owl.git
4143 lines
142 KiB
Diff
4143 lines
142 KiB
Diff
commit 584d297fd29fb39c76af25ae74ff9d5fe74c8a14
|
||
Author: Helmut Schaa <helmut.schaa@googlemail.com>
|
||
Date: Wed Mar 12 10:37:55 2014 +0100
|
||
|
||
ath9k: Fix sequence number assignment for non-data frames
|
||
|
||
Since commit 558ff225de80ac95b132d3a115ddadcd64498b4f (ath9k: fix
|
||
ps-poll responses under a-mpdu sessions) non-data frames would have
|
||
gotten a sequence number from a TIDs sequence counter instead of
|
||
using the global sequence counter.
|
||
|
||
This can lead to instable connections.
|
||
|
||
To fix this only select the correct TID if we are processing a
|
||
data frame. Furthermore, prevent non-data frames to get a sequence
|
||
number from a TID sequence counter by adding a check to
|
||
ath_tx_setup_buffer.
|
||
|
||
Cc: Felix Fietkau <nbd@openwrt.org>
|
||
Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
|
||
|
||
commit 3a0f984b1cdcd6a9f8c441635ef3b05d58547f4e
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Tue Mar 11 14:03:32 2014 +0100
|
||
|
||
ath9k_hw: set ANI firstep as absolute values instead of relative
|
||
|
||
On older chips, the INI value differ in similar ways as cycpwr_thr1, so
|
||
convert it to absolute values as well.
|
||
|
||
Since the ANI algorithm is different here compared to the old
|
||
implementation (fewer steps, controlled at a different point in time),
|
||
it makes sense to use values similar to what would be applied for newer
|
||
chips, just without relying on INI defaults.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 91d70d40400c569b49605b78fd7c43e9405694f4
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Tue Mar 11 14:00:37 2014 +0100
|
||
|
||
ath9k_hw: set ANI cycpwr_thr1 as absolute values instead of relative
|
||
|
||
The table was copied from the ANI implementation of AR9300. It assumes
|
||
that the INI values contain a baseline value that is usable as reference
|
||
from which to increase/decrease based on the noise immunity value.
|
||
|
||
On older chips, the differences are bigger and especially AR5008/AR9001
|
||
are configured to much more sensitive values than what is useful.
|
||
|
||
Improve ANI behavior by reverting to the absolute values used in the
|
||
previous implementation (expressed as a simple formula instead of the
|
||
old table).
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit c977493766310a825f406836636ffd66e1447783
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Mon Mar 10 19:52:56 2014 +0100
|
||
|
||
ath9k_hw: remove ANI function restrictions for AP mode
|
||
|
||
The primary purpose of this piece of code was to selectively disable
|
||
OFDM weak signal detection. The checks for this are elsewhere, and an
|
||
earlier commit relaxed the restrictions for older chips, which are more
|
||
sensitive to interference.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 8d804f1af11e4e058b1e8453327777d73a585cb8
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sun Mar 9 11:25:43 2014 +0100
|
||
|
||
ath9k: clean up and enhance ANI debugfs file
|
||
|
||
Unify scnprintf calls and include the current OFDM/CCK immunity level.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 22e298b5a3a8a49e33805d4e351965123dede35b
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sun Mar 9 10:58:47 2014 +0100
|
||
|
||
ath9k: fix ready time of the multicast buffer queue
|
||
|
||
qi->tqi_readyTime is written directly to registers that expect
|
||
microseconds as unit instead of TU.
|
||
When setting the CABQ ready time, cur_conf->beacon_interval is in TU, so
|
||
convert it to microseconds before passing it to ath9k_hw.
|
||
|
||
This should hopefully fix some Tx DMA issues with buffered multicast
|
||
frames in AP mode.
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit fcb064fdd5a27bec8d24099bc0172468f34c97cb
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sun Mar 9 09:43:09 2014 +0100
|
||
|
||
ath9k_hw: fix unreachable code in baseband hang detection code
|
||
|
||
The commit "ath9k: reduce baseband hang detection false positive rate"
|
||
added a delay in the loop checking the baseband state, however it was
|
||
unreachable due to previous 'continue' statements.
|
||
|
||
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 31959d8df39319e32c6d5ba9c135727be90cfad7
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Fri Mar 7 08:09:38 2014 +0100
|
||
|
||
mac80211: fix possible NULL dereference
|
||
|
||
If chanctx is missing on a given vif then the band
|
||
is assumed to be 2GHz. However if hw doesn't
|
||
support 2GHz band then mac80211 ended up with a
|
||
NULL dereference.
|
||
|
||
This fixes a splat:
|
||
|
||
[ 4605.207223] BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
|
||
[ 4605.210789] IP: [<ffffffffa07b5635>] ieee80211_parse_bitrates+0x65/0x110 [mac80211]
|
||
|
||
The splat was preceeded by WARN_ON(!chanctx_conf)
|
||
in ieee80211_get_sdata_band().
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
|
||
commit 6c5a3ffa0a2d22c091a2717f427259bacf77ac5e
|
||
Author: Michael Braun <michael-dev@fami-braun.de>
|
||
Date: Thu Mar 6 15:08:43 2014 +0100
|
||
|
||
mac80211: fix WPA with VLAN on AP side with ps-sta again
|
||
|
||
commit de74a1d9032f4d37ea453ad2a647e1aff4cd2591
|
||
"mac80211: fix WPA with VLAN on AP side with ps-sta"
|
||
fixed an issue where queued multicast packets would
|
||
be sent out encrypted with the key of an other bss.
|
||
|
||
commit "7cbf9d017dbb5e3276de7d527925d42d4c11e732"
|
||
"mac80211: fix oops on mesh PS broadcast forwarding"
|
||
essentially reverted it, because vif.type cannot be AP_VLAN
|
||
due to the check to vif.type in ieee80211_get_buffered_bc before.
|
||
|
||
As the later commit intended to fix the MESH case, fix it
|
||
by checking for IFTYPE_AP instead of IFTYPE_AP_VLAN.
|
||
|
||
Fixes: 7cbf9d017dbb
|
||
Cc: <stable@vger.kernel.org> # 3.10.x
|
||
Cc: <stable@vger.kernel.org> # 3.11.x
|
||
Cc: <stable@vger.kernel.org> # 3.12.x
|
||
Cc: <stable@vger.kernel.org> # 3.13.x
|
||
Cc: <linux-wireless@vger.kernel.org>
|
||
Cc: <projekt-wlan@fem.tu-ilmenau.de>
|
||
Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
|
||
|
||
commit 9d6ab9bdb9b368a6cf9519f0f92509b5b2c297ec
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Mon Mar 3 14:19:08 2014 +0100
|
||
|
||
cfg80211: remove racy beacon_interval assignment
|
||
|
||
In case of AP mode, the beacon interval is already reset to
|
||
zero inside cfg80211_stop_ap(), and in the other modes it
|
||
isn't relevant. Remove the assignment to remove a potential
|
||
race since the assignment isn't properly locked.
|
||
|
||
Reported-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 1abdeca3c6fb9cf1f84f85e78ed8d1c33bd69db0
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Fri Feb 28 18:52:56 2014 +0100
|
||
|
||
ath9k_hw: tweak noise immunity thresholds for older chipsets
|
||
|
||
Older chipsets are more sensitive to high PHY error counts, and the
|
||
current noise immunity thresholds were based on tests run at QCA with
|
||
newer chipsets.
|
||
|
||
This patch brings back the values from the old ANI implementation for
|
||
old chipsets, and it also disables weak signal detection on an earlier
|
||
noise immunity level, to improve overall radio stability on affected
|
||
devices.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 431e506da5953adc3b65af25f4b90873d528c115
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Fri Feb 28 18:44:13 2014 +0100
|
||
|
||
ath9k_hw: toggle weak signal detection in AP mode on older chipsets
|
||
|
||
The commit 80b4205b "ath9k: Fix OFDM weak signal detection for AP mode"
|
||
prevented weak signal detection changes from taking effect in AP mode on
|
||
all chipsets, claiming it is "not allowed".
|
||
|
||
The main reason for not disabling weak signal detection in AP mode is
|
||
that typically beacon RSSI is used to track whether it is needed to
|
||
boost range, and this is unavailable in AP mode for obvious reasons.
|
||
|
||
The problem with not disabling weak signal detection is that older
|
||
chipsets are very sensitive to high PHY error counts. When faced with
|
||
heavy noise, this can lead to an excessive amount of "Failed to stop
|
||
TX DMA" errors in the field.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 98d1a6c5b14688ed030e81b889f607be308e0df9
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Mon Feb 24 22:20:32 2014 +0100
|
||
|
||
ath9k: fix invalid descriptor discarding
|
||
|
||
Only set sc->rx.discard_next to rx_stats->rs_more when actually
|
||
discarding the current descriptor.
|
||
|
||
Also, fix a detection of broken descriptors:
|
||
First the code checks if the current descriptor is not done.
|
||
Then it checks if the next descriptor is done.
|
||
Add a check that afterwards checks the first descriptor again, because
|
||
it might have been completed in the mean time.
|
||
|
||
This fixes a regression introduced in
|
||
commit 723e711356b5a8a95728a890e254e8b0d47b55cf
|
||
"ath9k: fix handling of broken descriptors"
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Reported-by: Marco André Dinis <marcoandredinis@gmail.com>
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 52a46300e782fe6994466523eb2b0b59091ea59f
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Mon Feb 24 11:43:50 2014 +0100
|
||
|
||
ath9k: reduce baseband hang detection false positive rate
|
||
|
||
Check if the baseband state remains stable, and add a small delay
|
||
between register reads.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 118945bb12082e9d4edddc868d88143164e0f440
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sat Feb 22 14:55:23 2014 +0100
|
||
|
||
ath5k: set SURVEY_INFO_IN_USE on get_survey
|
||
|
||
Only one channel is returned - the one currently being used.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit ee41f72476e1ea44283dfe1cbf75b9543a1e15c8
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sat Feb 22 14:44:52 2014 +0100
|
||
|
||
ath9k: make some hardware reset log messages debug-only
|
||
|
||
On some chips, baseband watchdog hangs are more common than others, and
|
||
the driver has support for handling them.
|
||
Interrupts even after a watchdog hang are also quite common, so there's
|
||
not much point in spamming the user's logfiles.
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit b14fbb554fc65a2e0b5c41a319269b0350f187e7
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sat Feb 22 14:35:25 2014 +0100
|
||
|
||
ath9k: do not set half/quarter channel flags in AR_PHY_MODE
|
||
|
||
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.
|
||
|
||
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
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit 0f1cb7be2551b30b02cd54c897e0e29e483cfda5
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Sat Feb 22 13:43:29 2014 +0100
|
||
|
||
ath9k: fix ps-poll responses under a-mpdu sessions
|
||
|
||
When passing tx frames to the U-APSD queue for powersave poll responses,
|
||
the ath_atx_tid pointer needs to be passed to ath_tx_setup_buffer for
|
||
proper sequence number accounting.
|
||
|
||
This fixes high latency and connection stability issues with ath9k
|
||
running as AP and a few kinds of mobile phones as client, when PS-Poll
|
||
is heavily used
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit d5d87a37bbd6066b2c3c5d0bd0fe2a6e2ea45cc5
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Fri Feb 21 11:39:59 2014 +0100
|
||
|
||
ath9k: list more reset causes in debugfs
|
||
|
||
Number of MAC hangs and stuck beacons were missing
|
||
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit d84856012e0f10fe598a5ad3b7b869397a089e07
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
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 <johannes.berg@intel.com>
|
||
|
||
commit 798f2786602cbe93e6b928299614aa36ebf50692
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
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 <johannes.berg@intel.com>
|
||
|
||
commit b9ba6a520cb07ab3aa7aaaf9ce4a0bc7a6bc06fe
|
||
Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Date: Thu Feb 20 09:22:11 2014 +0200
|
||
|
||
mac80211: fix AP powersave TX vs. wakeup race
|
||
|
||
There is a race between the TX path and the STA wakeup: while
|
||
a station is sleeping, mac80211 buffers frames until it wakes
|
||
up, then the frames are transmitted. However, the RX and TX
|
||
path are concurrent, so the packet indicating wakeup can be
|
||
processed while a packet is being transmitted.
|
||
|
||
This can lead to a situation where the buffered frames list
|
||
is emptied on the one side, while a frame is being added on
|
||
the other side, as the station is still seen as sleeping in
|
||
the TX path.
|
||
|
||
As a result, the newly added frame will not be send anytime
|
||
soon. It might be sent much later (and out of order) when the
|
||
station goes to sleep and wakes up the next time.
|
||
|
||
Additionally, it can lead to the crash below.
|
||
|
||
Fix all this by synchronising both paths with a new lock.
|
||
Both path are not fastpath since they handle PS situations.
|
||
|
||
In a later patch we'll remove the extra skb queue locks to
|
||
reduce locking overhead.
|
||
|
||
BUG: unable to handle kernel
|
||
NULL pointer dereference at 000000b0
|
||
IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
|
||
*pde = 00000000
|
||
Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
|
||
EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1
|
||
EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
|
||
EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000
|
||
ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0
|
||
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
|
||
CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0
|
||
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
|
||
DR6: ffff0ff0 DR7: 00000400
|
||
Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000)
|
||
iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9
|
||
Stack:
|
||
e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0
|
||
ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210
|
||
ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002
|
||
Call Trace:
|
||
[<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211]
|
||
[<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211]
|
||
[<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211]
|
||
[<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211]
|
||
[<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211]
|
||
[<c149ef70>] dev_hard_start_xmit+0x450/0x950
|
||
[<c14b9aa9>] sch_direct_xmit+0xa9/0x250
|
||
[<c14b9c9b>] __qdisc_run+0x4b/0x150
|
||
[<c149f732>] dev_queue_xmit+0x2c2/0xca0
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com>
|
||
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||
[reword commit log, use a separate lock]
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 80e419de0dff38436b30d363311c625766193f86
|
||
Author: Inbal Hacohen <Inbal.Hacohen@intel.com>
|
||
Date: Wed Feb 12 09:32:27 2014 +0200
|
||
|
||
cfg80211: bugfix in regulatory user hint process
|
||
|
||
After processing hint_user, we would want to schedule the
|
||
timeout work only if we are actually waiting to CRDA. This happens
|
||
when the status is not "IGNORE" nor "ALREADY_SET".
|
||
|
||
Signed-off-by: Inbal Hacohen <Inbal.Hacohen@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 6514c93afede55284e2cb63359aadedb85884c80
|
||
Author: Jouni Malinen <jouni@qca.qualcomm.com>
|
||
Date: Tue Feb 18 20:41:08 2014 +0200
|
||
|
||
ath9k: Enable U-APSD AP mode support
|
||
|
||
mac80211 handles the actual operations, so ath9k can just indicate
|
||
support for this. Based on initial tests, this combination seems to
|
||
work fine.
|
||
|
||
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
|
||
|
||
commit a63caf0a357ad5c1f08d6b7827dc76c451445017
|
||
Author: Stanislaw Gruszka <sgruszka@redhat.com>
|
||
Date: Wed Feb 19 13:15:17 2014 +0100
|
||
|
||
ath9k: protect tid->sched check
|
||
|
||
We check tid->sched without a lock taken on ath_tx_aggr_sleep(). That
|
||
is race condition which can result of doing list_del(&tid->list) twice
|
||
(second time with poisoned list node) and cause crash like shown below:
|
||
|
||
[424271.637220] BUG: unable to handle kernel paging request at 00100104
|
||
[424271.637328] IP: [<f90fc072>] ath_tx_aggr_sleep+0x62/0xe0 [ath9k]
|
||
...
|
||
[424271.639953] Call Trace:
|
||
[424271.639998] [<f90f6900>] ? ath9k_get_survey+0x110/0x110 [ath9k]
|
||
[424271.640083] [<f90f6942>] ath9k_sta_notify+0x42/0x50 [ath9k]
|
||
[424271.640177] [<f809cfef>] sta_ps_start+0x8f/0x1c0 [mac80211]
|
||
[424271.640258] [<c10f730e>] ? free_compound_page+0x2e/0x40
|
||
[424271.640346] [<f809e915>] ieee80211_rx_handlers+0x9d5/0x2340 [mac80211]
|
||
[424271.640437] [<c112f048>] ? kmem_cache_free+0x1d8/0x1f0
|
||
[424271.640510] [<c1345a84>] ? kfree_skbmem+0x34/0x90
|
||
[424271.640578] [<c10fc23c>] ? put_page+0x2c/0x40
|
||
[424271.640640] [<c1345a84>] ? kfree_skbmem+0x34/0x90
|
||
[424271.640706] [<c1345a84>] ? kfree_skbmem+0x34/0x90
|
||
[424271.640787] [<f809dde3>] ? ieee80211_rx_handlers_result+0x73/0x1d0 [mac80211]
|
||
[424271.640897] [<f80a07a0>] ieee80211_prepare_and_rx_handle+0x520/0xad0 [mac80211]
|
||
[424271.641009] [<f809e22d>] ? ieee80211_rx_handlers+0x2ed/0x2340 [mac80211]
|
||
[424271.641104] [<c13846ce>] ? ip_output+0x7e/0xd0
|
||
[424271.641182] [<f80a1057>] ieee80211_rx+0x307/0x7c0 [mac80211]
|
||
[424271.641266] [<f90fa6ee>] ath_rx_tasklet+0x88e/0xf70 [ath9k]
|
||
[424271.641358] [<f80a0f2c>] ? ieee80211_rx+0x1dc/0x7c0 [mac80211]
|
||
[424271.641445] [<f90f82db>] ath9k_tasklet+0xcb/0x130 [ath9k]
|
||
|
||
Bug report:
|
||
https://bugzilla.kernel.org/show_bug.cgi?id=70551
|
||
|
||
Reported-and-tested-by: Max Sydorenko <maxim.stargazer@gmail.com>
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
|
||
|
||
commit 82ed9e3ccc02797df2ffe4b78127c4cd5f799a41
|
||
Author: Felix Fietkau <nbd@openwrt.org>
|
||
Date: Tue Feb 11 15:54:13 2014 +0100
|
||
|
||
mac80211: send control port protocol frames to the VO queue
|
||
|
||
Improves reliability of wifi connections with WPA, since authentication
|
||
frames are prioritized over normal traffic and also typically exempt
|
||
from aggregation.
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||
|
||
commit d4426800f71e972feaa33e04c5801fc730627bdd
|
||
Author: Stanislaw Gruszka <stf_xl@wp.pl>
|
||
Date: Mon Feb 10 22:38:28 2014 +0100
|
||
|
||
rtl8187: fix regression on MIPS without coherent DMA
|
||
|
||
This patch fixes regression caused by commit a16dad77634 "MIPS: Fix
|
||
potencial corruption". That commit fixes one corruption scenario in
|
||
cost of adding another one, which actually start to cause crashes
|
||
on Yeeloong laptop when rtl8187 driver is used.
|
||
|
||
For correct DMA read operation on machines without DMA coherence, kernel
|
||
have to invalidate cache, such it will refill later with new data that
|
||
device wrote to memory, when that data is needed to process. We can only
|
||
invalidate full cache line. Hence when cache line includes both dma
|
||
buffer and some other data (written in cache, but not yet in main
|
||
memory), the other data can not hit memory due to invalidation. That
|
||
happen on rtl8187 where struct rtl8187_priv fields are located just
|
||
before and after small buffers that are passed to USB layer and DMA
|
||
is performed on them.
|
||
|
||
To fix the problem we align buffers and reserve space after them to make
|
||
them match cache line.
|
||
|
||
This patch does not resolve all possible MIPS problems entirely, for
|
||
that we have to assure that we always map cache aligned buffers for DMA,
|
||
what can be complex or even not possible. But patch fixes visible and
|
||
reproducible regression and seems other possible corruptions do not
|
||
happen in practice, since Yeeloong laptop works stable without rtl8187
|
||
driver.
|
||
|
||
Bug report:
|
||
https://bugzilla.kernel.org/show_bug.cgi?id=54391
|
||
|
||
Reported-by: Petr Pisar <petr.pisar@atlas.cz>
|
||
Bisected-by: Tom Li <biergaizi2009@gmail.com>
|
||
Reported-and-tested-by: Tom Li <biergaizi2009@gmail.com>
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
|
||
|
||
commit e2f141d67ad1e7fe10aaab61811e8a409dfb2442
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:55 2014 +0530
|
||
|
||
ath9k: Calculate IQ-CAL median
|
||
|
||
This patch adds a routine to calculate the median IQ correction
|
||
values for AR955x, which is used for outlier detection.
|
||
The normal method which is used for all other chips is
|
||
bypassed for AR955x.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit c52a6fce0820c8d0687443ab86058ae03b478c8f
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:54 2014 +0530
|
||
|
||
ath9k: Expand the IQ coefficient array
|
||
|
||
This will be used for storing data for mutiple
|
||
IQ calibration runs, for AR955x.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit 034969ff5c2b6431d10e07c1938f0b916da85cc3
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:53 2014 +0530
|
||
|
||
ath9k: Modify IQ calibration for AR955x
|
||
|
||
IQ calibration post-processing for AR955x is different
|
||
from other chips - instead of just doing it as part
|
||
of AGC calibration once, it is triggered 3 times and
|
||
a median is determined. This patch adds initial support
|
||
for changing the calibration behavior for AR955x.
|
||
|
||
Also, to simplify things, a helper routine to issue/poll
|
||
AGC calibration is used.
|
||
|
||
For non-AR955x chips, the iqcal_idx (which will be used
|
||
in subsequent patches) is set to zero.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit 9b1ed6454e6f3511f24266be99b4e403f243f6a8
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:52 2014 +0530
|
||
|
||
ath9k: Fix magnitude/phase calculation
|
||
|
||
Incorrect values are programmed in the registers
|
||
containing the IQ correction coefficients by the IQ-CAL
|
||
post-processing code. Fix this.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit 36f93484f96f79171dcecb67c5ef0c3de22531a6
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:51 2014 +0530
|
||
|
||
ath9k: Rename ar9003_hw_tx_iqcal_load_avg_2_passes
|
||
|
||
Use ar9003_hw_tx_iq_cal_outlier_detection instead.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit 3af09a7f5d21dd5fd15b973ce6a91a575da30417
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:50 2014 +0530
|
||
|
||
ath9k: Check explicitly for IQ calibration
|
||
|
||
In chips like AR955x, the initvals contain the information
|
||
whether IQ calibration is to be done in the HW when an
|
||
AGC calibration is triggered. Check if IQ-CAL is enabled
|
||
in the initvals before flagging 'txiqcal_done' as true.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit cb4969634b93c4643a32cc3fbd27d2b288b25771
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Fri Feb 7 10:29:49 2014 +0530
|
||
|
||
ath9k: Fix IQ cal post processing for SoC
|
||
|
||
Calibration data is not reused for SoC chips, so
|
||
call ar9003_hw_tx_iq_cal_post_proc() with the correct
|
||
argument. The 'is_reusable' flag is currently used
|
||
only for PC-OEM chips, but it makes things clearer to
|
||
specify it explicity.
|
||
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit e138e0ef9560c46ce93dbb22a728a57888e94d1c
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Mon Feb 3 13:31:37 2014 +0530
|
||
|
||
ath9k: Fix TX power calculation
|
||
|
||
The commit, "ath9k_hw: Fix incorrect Tx control power in AR9003 template"
|
||
fixed the incorrect values in the eeprom templates, but if
|
||
boards have already been calibrated with incorrect values,
|
||
they would still be using the wrong TX power. Fix this by assigning
|
||
a default value in such cases.
|
||
|
||
Cc: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit b9f268b5b01331c3c82179abca551429450e9417
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Wed Jan 29 14:22:27 2014 +0100
|
||
|
||
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:
|
||
|
||
step 1. start AP on DFS channel by matching combo 2
|
||
step 2. start AP on non-DFS channel by matching combo 1
|
||
|
||
This was possible beacuse (step 2) did not consider
|
||
if other interfaces require radar detection.
|
||
|
||
The patch changes how cfg80211 tracks channels -
|
||
instead of channel itself now a complete chandef
|
||
is stored.
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit bc9c62f5f511cc395c62dbf4cdd437f23db53b28
|
||
Author: Antonio Quartulli <antonio@open-mesh.com>
|
||
Date: Wed Jan 29 17:53:43 2014 +0100
|
||
|
||
cfg80211: fix channel configuration in IBSS join
|
||
|
||
When receiving an IBSS_JOINED event select the BSS object
|
||
based on the {bssid, channel} couple rather than the bssid
|
||
only.
|
||
With the current approach if another cell having the same
|
||
BSSID (but using a different channel) exists then cfg80211
|
||
picks up the wrong BSS object.
|
||
The result is a mismatching channel configuration between
|
||
cfg80211 and the driver, that can lead to any sort of
|
||
problem.
|
||
|
||
The issue can be triggered by having an IBSS sitting on
|
||
given channel and then asking the driver to create a new
|
||
cell using the same BSSID but with a different frequency.
|
||
By passing the channel to cfg80211_get_bss() we can solve
|
||
this ambiguity and retrieve/create the correct BSS object.
|
||
All the users of cfg80211_ibss_joined() have been changed
|
||
accordingly.
|
||
|
||
Moreover WARN when cfg80211_ibss_joined() gets a NULL
|
||
channel as argument and remove a bogus call of the same
|
||
function in ath6kl (it does not make sense to call
|
||
cfg80211_ibss_joined() with a zero BSSID on ibss-leave).
|
||
|
||
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
|
||
Cc: Arend van Spriel <arend@broadcom.com>
|
||
Cc: Bing Zhao <bzhao@marvell.com>
|
||
Cc: Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||
Cc: libertas-dev@lists.infradead.org
|
||
Acked-by: Kalle Valo <kvalo@qca.qualcomm.com>
|
||
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
|
||
[minor code cleanup in ath6kl]
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 7e0c41cb41f215aba2c39b1c237bb4d42ec49a85
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Fri Jan 24 14:41:44 2014 +0100
|
||
|
||
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.
|
||
|
||
Also use the new helper in the TX path to clean up the code.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit fc0df6d2343636e3f48a069330d5b972e3d8659d
|
||
Author: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||
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 <janusz.dziedzic@tieto.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit cdec895e2344987ff171cece96e25d7407a3ebf6
|
||
Author: Simon Wunderlich <simon@open-mesh.com>
|
||
Date: Fri Jan 24 23:48:29 2014 +0100
|
||
|
||
mac80211: send ibss probe responses with noack flag
|
||
|
||
Responding to probe requests for scanning clients will often create
|
||
excessive retries, as it happens quite often that the scanning client
|
||
already left the channel. Therefore do it like hostapd and send probe
|
||
responses for wildcard SSID only once by using the noack flag.
|
||
|
||
Signed-off-by: Simon Wunderlich <simon@open-mesh.com>
|
||
[fix typo & 'wildcard SSID' in commit log]
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 0b865d1e6b9c05052adae9315df7cb195dc60c3b
|
||
Author: Luciano Coelho <luciano.coelho@intel.com>
|
||
Date: Tue Jan 28 17:09:08 2014 +0200
|
||
|
||
mac80211: ibss: remove unnecessary call to release channel
|
||
|
||
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 <luciano.coelho@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit e1b6c17e971f0a51ff86c2dac2584c63cd999cd7
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Wed Jan 29 07:56:21 2014 +0100
|
||
|
||
mac80211: add missing CSA locking
|
||
|
||
The patch adds a missing sdata lock and adds a few
|
||
lockdeps for easier maintenance.
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit ad17ba7d14d225b109b73c177cd446afb8050598
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Wed Jan 29 07:56:20 2014 +0100
|
||
|
||
mac80211: fix sdata->radar_required locking
|
||
|
||
radar_required setting wasn't protected by
|
||
local->mtx in some places. This should prevent
|
||
from scanning/radar detection/roc colliding.
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 5fcd5f1808813a3d9e502fd756e01bee8a79c85d
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Wed Jan 29 07:56:19 2014 +0100
|
||
|
||
mac80211: move csa_active setting in STA CSA
|
||
|
||
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.
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit e486da4b7eed71821c6b4c1bb9ac62ffd3ab13e9
|
||
Author: Michal Kazior <michal.kazior@tieto.com>
|
||
Date: Wed Jan 29 07:56:18 2014 +0100
|
||
|
||
mac80211: fix possible memory leak on AP CSA failure
|
||
|
||
If CSA for AP interface failed and the interface
|
||
was not stopped afterwards another CSA request
|
||
would leak sdata->u.ap.next_beacon.
|
||
|
||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
||
Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 3a77ba08940682bf3d52cf14f980337324af9d4a
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Sat Feb 1 00:33:29 2014 +0100
|
||
|
||
mac80211: fix fragmentation code, particularly for encryption
|
||
|
||
The "new" fragmentation code (since my rewrite almost 5 years ago)
|
||
erroneously sets skb->len rather than using skb_trim() to adjust
|
||
the length of the first fragment after copying out all the others.
|
||
This leaves the skb tail pointer pointing to after where the data
|
||
originally ended, and thus causes the encryption MIC to be written
|
||
at that point, rather than where it belongs: immediately after the
|
||
data.
|
||
|
||
The impact of this is that if software encryption is done, then
|
||
a) encryption doesn't work for the first fragment, the connection
|
||
becomes unusable as the first fragment will never be properly
|
||
verified at the receiver, the MIC is practically guaranteed to
|
||
be wrong
|
||
b) we leak up to 8 bytes of plaintext (!) of the packet out into
|
||
the air
|
||
|
||
This is only mitigated by the fact that many devices are capable
|
||
of doing encryption in hardware, in which case this can't happen
|
||
as the tail pointer is irrelevant in that case. Additionally,
|
||
fragmentation is not used very frequently and would normally have
|
||
to be configured manually.
|
||
|
||
Fix this by using skb_trim() properly.
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation")
|
||
Reported-by: Jouni Malinen <j@w1.fi>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit de5f242e0c10e841017e37eb8c38974a642dbca8
|
||
Author: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
Date: Tue Jan 28 06:21:59 2014 +0530
|
||
|
||
ath9k: Fix build error on ARM
|
||
|
||
Use mdelay instead of udelay to fix this error:
|
||
|
||
ERROR: "__bad_udelay" [drivers/net/wireless/ath/ath9k/ath9k_hw.ko] undefined!
|
||
make[1]: *** [__modpost] Error 1
|
||
make: *** [modules] Error 2
|
||
|
||
Reported-by: Josh Boyer <jwboyer@fedoraproject.org>
|
||
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
||
|
||
commit 8e3ea7a51dfc61810fcefd947f6edcf61125252a
|
||
Author: Geert Uytterhoeven <geert@linux-m68k.org>
|
||
Date: Sun Jan 26 11:53:21 2014 +0100
|
||
|
||
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
|
||
|
||
Introduced by commit 10e2318103f5941aa70c318afe34bc41f1b98529 ("ath9k:
|
||
optimize ath9k_flush").
|
||
|
||
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
|
||
|
||
commit a4a634a6937ebdd827fa58e8fcdb8ca49a3769f6
|
||
Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Date: Mon Jan 27 11:07:42 2014 +0200
|
||
|
||
mac80211: release the channel in error path in start_ap
|
||
|
||
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 <emmanuel.grumbach@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit dfb6889a75c601aedb7450b7e606668e77da6679
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Wed Jan 22 11:14:19 2014 +0200
|
||
|
||
cfg80211: send scan results from work queue
|
||
|
||
Due to the previous commit, when a scan finishes, it is in theory
|
||
possible to hit the following sequence:
|
||
1. interface starts being removed
|
||
2. scan is cancelled by driver and cfg80211 is notified
|
||
3. scan done work is scheduled
|
||
4. interface is removed completely, rdev->scan_req is freed,
|
||
event sent to userspace but scan done work remains pending
|
||
5. new scan is requested on another virtual interface
|
||
6. scan done work runs, freeing the still-running scan
|
||
|
||
To fix this situation, hang on to the scan done message and block
|
||
new scans while that is the case, and only send the message from
|
||
the work function, regardless of whether the scan_req is already
|
||
freed from interface removal. This makes step 5 above impossible
|
||
and changes step 6 to be
|
||
5. scan done work runs, sending the scan done message
|
||
|
||
As this can't work for wext, so we send the message immediately,
|
||
but this shouldn't be an issue since we still return -EBUSY.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 45b7ab41fc08627d9a8428cb413d5d84662a9707
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Wed Jan 22 11:14:18 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.
|
||
|
||
Fix this by making sure the scan request is not pending after
|
||
the interface is destroyed. We can't flush or cancel the work
|
||
item due to locking concerns, but when it'll run it shouldn't
|
||
find anything to do. This leaves a potential issue, if a new
|
||
scan gets requested before the work runs, it prematurely stops
|
||
the running scan, potentially causing another crash. I'll fix
|
||
that in the next patch.
|
||
|
||
This was particularly observed with P2P_DEVICE wdevs, likely
|
||
because freeing them is quicker than freeing netdevs.
|
||
|
||
Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
|
||
Fixes: 4a58e7c38443 ("cfg80211: don't "leak" uncompleted scans")
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit ae04fa489ab31b5a10d3cc8399f52761175d4321
|
||
Author: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Date: Thu Jan 23 14:28:16 2014 +0200
|
||
|
||
mac80211: avoid deadlock revealed by lockdep
|
||
|
||
sdata->u.ap.request_smps_work can’t be flushed synchronously
|
||
under wdev_lock(wdev) since ieee80211_request_smps_ap_work
|
||
itself locks the same lock.
|
||
While at it, reset the driver_smps_mode when the ap is
|
||
stopped to its default: OFF.
|
||
|
||
This solves:
|
||
|
||
======================================================
|
||
[ INFO: possible circular locking dependency detected ]
|
||
3.12.0-ipeer+ #2 Tainted: G O
|
||
-------------------------------------------------------
|
||
rmmod/2867 is trying to acquire lock:
|
||
((&sdata->u.ap.request_smps_work)){+.+...}, at: [<c105b8d0>] flush_work+0x0/0x90
|
||
|
||
but task is already holding lock:
|
||
(&wdev->mtx){+.+.+.}, at: [<f9b32626>] cfg80211_stop_ap+0x26/0x230 [cfg80211]
|
||
|
||
which lock already depends on the new lock.
|
||
|
||
the existing dependency chain (in reverse order) is:
|
||
|
||
-> #1 (&wdev->mtx){+.+.+.}:
|
||
[<c10aefa9>] lock_acquire+0x79/0xe0
|
||
[<c1607a1a>] mutex_lock_nested+0x4a/0x360
|
||
[<fb06288b>] ieee80211_request_smps_ap_work+0x2b/0x50 [mac80211]
|
||
[<c105cdd8>] process_one_work+0x198/0x450
|
||
[<c105d469>] worker_thread+0xf9/0x320
|
||
[<c10669ff>] kthread+0x9f/0xb0
|
||
[<c1613397>] ret_from_kernel_thread+0x1b/0x28
|
||
|
||
-> #0 ((&sdata->u.ap.request_smps_work)){+.+...}:
|
||
[<c10ae9df>] __lock_acquire+0x183f/0x1910
|
||
[<c10aefa9>] lock_acquire+0x79/0xe0
|
||
[<c105b917>] flush_work+0x47/0x90
|
||
[<c105d867>] __cancel_work_timer+0x67/0xe0
|
||
[<c105d90f>] cancel_work_sync+0xf/0x20
|
||
[<fb0765cc>] ieee80211_stop_ap+0x8c/0x340 [mac80211]
|
||
[<f9b3268c>] cfg80211_stop_ap+0x8c/0x230 [cfg80211]
|
||
[<f9b0d8f9>] cfg80211_leave+0x79/0x100 [cfg80211]
|
||
[<f9b0da72>] cfg80211_netdev_notifier_call+0xf2/0x4f0 [cfg80211]
|
||
[<c160f2c9>] notifier_call_chain+0x59/0x130
|
||
[<c106c6de>] __raw_notifier_call_chain+0x1e/0x30
|
||
[<c106c70f>] raw_notifier_call_chain+0x1f/0x30
|
||
[<c14f8213>] call_netdevice_notifiers_info+0x33/0x70
|
||
[<c14f8263>] call_netdevice_notifiers+0x13/0x20
|
||
[<c14f82a4>] __dev_close_many+0x34/0xb0
|
||
[<c14f83fe>] dev_close_many+0x6e/0xc0
|
||
[<c14f9c77>] rollback_registered_many+0xa7/0x1f0
|
||
[<c14f9dd4>] unregister_netdevice_many+0x14/0x60
|
||
[<fb06f4d9>] ieee80211_remove_interfaces+0xe9/0x170 [mac80211]
|
||
[<fb055116>] ieee80211_unregister_hw+0x56/0x110 [mac80211]
|
||
[<fa3e9396>] iwl_op_mode_mvm_stop+0x26/0xe0 [iwlmvm]
|
||
[<f9b9d8ca>] _iwl_op_mode_stop+0x3a/0x70 [iwlwifi]
|
||
[<f9b9d96f>] iwl_opmode_deregister+0x6f/0x90 [iwlwifi]
|
||
[<fa405179>] __exit_compat+0xd/0x19 [iwlmvm]
|
||
[<c10b8bf9>] SyS_delete_module+0x179/0x2b0
|
||
[<c1613421>] sysenter_do_call+0x12/0x32
|
||
|
||
Fixes: 687da132234f ("mac80211: implement SMPS for AP")
|
||
Cc: <stable@vger.kernel.org> [3.13]
|
||
Reported-by: Ilan Peer <ilan.peer@intel.com>
|
||
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 178b205e96217164fd7c30113464250d0b6f5eca
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Thu Jan 23 16:32:29 2014 +0100
|
||
|
||
cfg80211: re-enable 5/10 MHz support
|
||
|
||
Unfortunately I forgot this during the merge window, but the
|
||
patch seems small enough to go in as a fix. The userspace API
|
||
bug that was the reason for disabling it has long been fixed.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 110a1c79acda14edc83b7c8dc5af9c7ddd23eb61
|
||
Author: Pontus Fuchs <pontus.fuchs@gmail.com>
|
||
Date: Thu Jan 16 15:00:40 2014 +0100
|
||
|
||
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.
|
||
|
||
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.
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Fixes: 3713b4e364ef ("nl80211: allow splitting wiphy information in dumps")
|
||
Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
|
||
[avoid the entire workaround when state->split is set]
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit b4c31b45ffc7ef110fa9ecc34d7878fe7c5b9da4
|
||
Author: Eliad Peller <eliad@wizery.com>
|
||
Date: Sun Jan 12 11:06:37 2014 +0200
|
||
|
||
mac80211: move roc cookie assignment earlier
|
||
|
||
ieee80211_start_roc_work() might add a new roc
|
||
to existing roc, and tell cfg80211 it has already
|
||
started.
|
||
|
||
However, this might happen before the roc cookie
|
||
was set, resulting in REMAIN_ON_CHANNEL (started)
|
||
event with null cookie. Consequently, it can make
|
||
wpa_supplicant go out of sync.
|
||
|
||
Fix it by setting the roc cookie earlier.
|
||
|
||
Cc: stable@vger.kernel.org
|
||
Signed-off-by: Eliad Peller <eliad@wizery.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit cfdc9157bfd7bcf88ab4dae08873a9907eba984c
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Fri Jan 24 14:06:29 2014 +0100
|
||
|
||
nl80211: send event when AP operation is stopped
|
||
|
||
There are a few cases, e.g. suspend, where an AP interface is
|
||
stopped by the kernel rather than by userspace request, most
|
||
commonly when suspending. To let userspace know about this,
|
||
send the NL80211_CMD_STOP_AP command as an event every time
|
||
an AP interface is stopped. This also happens when userspace
|
||
did in fact request the AP stop, but that's not a problem.
|
||
|
||
For full-MAC drivers this may need to be extended to also
|
||
cover cases where the device stopped the AP operation for
|
||
some reason, this a bit more complicated because then all
|
||
cfg80211 state also needs to be reset; such API is not part
|
||
of this patch.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit d5d567eda7704f190379ca852a8f9a4112e3eee3
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Thu Jan 23 16:20:29 2014 +0100
|
||
|
||
mac80211: add length check in ieee80211_is_robust_mgmt_frame()
|
||
|
||
A few places weren't checking that the frame passed to the
|
||
function actually has enough data even though the function
|
||
clearly documents it must have a payload byte. Make this
|
||
safer by changing the function to take an skb and checking
|
||
the length inside. The old version is preserved for now as
|
||
the rtl* drivers use it and don't have a correct skb.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit f8f6d212a047fc65c7d3442dfc038f65517236fc
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Fri Jan 24 10:53:53 2014 +0100
|
||
|
||
nl80211: fix scheduled scan RSSI matchset attribute confusion
|
||
|
||
The scheduled scan matchsets were intended to be a list of filters,
|
||
with the found BSS having to pass at least one of them to be passed
|
||
to the host. When the RSSI attribute was added, however, this was
|
||
broken and currently wpa_supplicant adds that attribute in its own
|
||
matchset; however, it doesn't intend that to mean that anything
|
||
that passes the RSSI filter should be passed to the host, instead
|
||
it wants it to mean that everything needs to also have higher RSSI.
|
||
|
||
This is semantically problematic because we have a list of filters
|
||
like [ SSID1, SSID2, SSID3, RSSI ] with no real indication which
|
||
one should be OR'ed and which one AND'ed.
|
||
|
||
To fix this, move the RSSI filter attribute into each matchset. As
|
||
we need to stay backward compatible, treat a matchset with only the
|
||
RSSI attribute as a "default RSSI filter" for all other matchsets,
|
||
but only if there are other matchsets (an RSSI-only matchset by
|
||
itself is still desirable.)
|
||
|
||
To make driver implementation easier, keep a global min_rssi_thold
|
||
for the entire request as well. The only affected driver is ath6kl.
|
||
|
||
I found this when I looked into the code after Raja Mani submitted
|
||
a patch fixing the n_match_sets calculation to disregard the RSSI,
|
||
but that patch didn't address the semantic issue.
|
||
|
||
Reported-by: Raja Mani <rmani@qti.qualcomm.com>
|
||
Acked-by: Luciano Coelho <luciano.coelho@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit de553e8545e65a6dc4e45f43df7e1443d4291922
|
||
Author: Johannes Berg <johannes.berg@intel.com>
|
||
Date: Fri Jan 24 10:17:47 2014 +0100
|
||
|
||
nl80211: check nla_parse() return values
|
||
|
||
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.
|
||
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
||
commit 652204a0733e9e1c54661d6f9d36e2e1e3b22bb1
|
||
Author: Karl Beldan <karl.beldan@rivierawaves.com>
|
||
Date: Thu Jan 23 20:06:34 2014 +0100
|
||
|
||
mac80211: send {ADD,DEL}BA on AC_VO like other mgmt frames, as per spec
|
||
|
||
ATM, {ADD,DEL}BA and BAR frames are sent on the AC matching the TID of
|
||
the BA parameters. In the discussion [1] about this patch, Johannes
|
||
recalled that it fixed some races with the DELBA and indeed this
|
||
behavior was introduced in [2].
|
||
While [2] is right for the BARs, the part queueing the {ADD,DEL}BAs on
|
||
their BA params TID AC violates the spec and is more a workaround for
|
||
some drivers. Helmut expressed some concerns wrt such drivers, in
|
||
particular DELBAs in rt2x00.
|
||
|
||
ATM, DELBAs are sent after a driver has called (hence "purposely")
|
||
ieee80211_start_tx_ba_cb_irqsafe and Johannes and Emmanuel gave some
|
||
details wrt intentions behind the split of the IEEE80211_AMPDU_TX_STOP_*
|
||
given to the driver ampdu_action supposed to call this function, which
|
||
could prove handy to people trying to do the right thing in faulty
|
||
drivers (if their fw/hw don't get in their way).
|
||
|
||
[1] http://mid.gmane.org/1390391564-18481-1-git-send-email-karl.beldan@gmail.com
|
||
[2] Commit: cf6bb79ad828 ("mac80211: Use appropriate TID for sending BAR, ADDBA and DELBA frames")
|
||
|
||
Signed-off-by: Karl Beldan <karl.beldan@rivierawaves.com>
|
||
Cc: Helmut Schaa <helmut.schaa@googlemail.com>
|
||
Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
|
||
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
|
||
@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struc
|
||
if (nw_type & ADHOC_NETWORK) {
|
||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
|
||
nw_type & ADHOC_CREATOR ? "creator" : "joiner");
|
||
- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
|
||
+ cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
|
||
cfg80211_put_bss(ar->wiphy, bss);
|
||
return;
|
||
}
|
||
@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(st
|
||
}
|
||
|
||
if (vif->nw_type & ADHOC_NETWORK) {
|
||
- if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
|
||
+ if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
|
||
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
|
||
"%s: ath6k not in ibss mode\n", __func__);
|
||
- return;
|
||
- }
|
||
- memset(bssid, 0, ETH_ALEN);
|
||
- cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
|
||
return;
|
||
}
|
||
|
||
@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(s
|
||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||
u16 interval;
|
||
int ret, rssi_thold;
|
||
+ int n_match_sets = request->n_match_sets;
|
||
+
|
||
+ /*
|
||
+ * If there's a matchset w/o an SSID, then assume it's just for
|
||
+ * the RSSI (nothing else is currently supported) and ignore it.
|
||
+ * The device only supports a global RSSI filter that we set below.
|
||
+ */
|
||
+ if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
|
||
+ n_match_sets = 0;
|
||
|
||
if (ar->state != ATH6KL_STATE_ON)
|
||
return -EIO;
|
||
@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(s
|
||
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
|
||
request->n_ssids,
|
||
request->match_sets,
|
||
- request->n_match_sets);
|
||
+ n_match_sets);
|
||
if (ret < 0)
|
||
return ret;
|
||
|
||
- if (!request->n_match_sets) {
|
||
+ if (!n_match_sets) {
|
||
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
|
||
ALL_BSS_FILTER, 0);
|
||
if (ret < 0)
|
||
@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(s
|
||
|
||
if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
|
||
ar->fw_capabilities)) {
|
||
- if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
|
||
+ if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
|
||
rssi_thold = 0;
|
||
- else if (request->rssi_thold < -127)
|
||
+ else if (request->min_rssi_thold < -127)
|
||
rssi_thold = -127;
|
||
else
|
||
- rssi_thold = request->rssi_thold;
|
||
+ rssi_thold = request->min_rssi_thold;
|
||
|
||
ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
|
||
rssi_thold);
|
||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||
@@ -1316,7 +1316,7 @@ static bool ath9k_hw_set_reset(struct at
|
||
if (AR_SREV_9300_20_OR_LATER(ah))
|
||
udelay(50);
|
||
else if (AR_SREV_9100(ah))
|
||
- udelay(10000);
|
||
+ mdelay(10);
|
||
else
|
||
udelay(100);
|
||
|
||
@@ -1534,7 +1534,7 @@ EXPORT_SYMBOL(ath9k_hw_check_nav);
|
||
bool ath9k_hw_check_alive(struct ath_hw *ah)
|
||
{
|
||
int count = 50;
|
||
- u32 reg;
|
||
+ u32 reg, last_val;
|
||
|
||
if (AR_SREV_9300(ah))
|
||
return !ath9k_hw_detect_mac_hang(ah);
|
||
@@ -1542,9 +1542,14 @@ bool ath9k_hw_check_alive(struct ath_hw
|
||
if (AR_SREV_9285_12_OR_LATER(ah))
|
||
return true;
|
||
|
||
+ last_val = REG_READ(ah, AR_OBS_BUS_1);
|
||
do {
|
||
reg = REG_READ(ah, AR_OBS_BUS_1);
|
||
+ if (reg != last_val)
|
||
+ return true;
|
||
|
||
+ udelay(1);
|
||
+ last_val = reg;
|
||
if ((reg & 0x7E7FFFEF) == 0x00702400)
|
||
continue;
|
||
|
||
@@ -2051,9 +2056,8 @@ static bool ath9k_hw_set_power_awake(str
|
||
|
||
REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
|
||
AR_RTC_FORCE_WAKE_EN);
|
||
-
|
||
if (AR_SREV_9100(ah))
|
||
- udelay(10000);
|
||
+ mdelay(10);
|
||
else
|
||
udelay(50);
|
||
|
||
--- 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;
|
||
}
|
||
|
||
@@ -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
|
||
|
||
static bool ath9k_has_tx_pending(struct ath_softc *sc)
|
||
{
|
||
- int i, npend;
|
||
+ int i, npend = 0;
|
||
|
||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
|
||
if (!ATH_TXQ_SETUP(sc, i))
|
||
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
|
||
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
|
||
@@ -595,6 +595,9 @@ static void iwl_scan_offload_build_ssid(
|
||
* config match list.
|
||
*/
|
||
for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
|
||
+ /* skip empty SSID matchsets */
|
||
+ if (!req->match_sets[i].ssid.ssid_len)
|
||
+ continue;
|
||
scan->direct_scan[i].id = WLAN_EID_SSID;
|
||
scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
|
||
memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
|
||
@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80
|
||
/* During testing, hdr was NULL */
|
||
return false;
|
||
}
|
||
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
(ieee80211_has_protected(hdr->frame_control)))
|
||
rx_status->flag &= ~RX_FLAG_DECRYPTED;
|
||
else
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
|
||
@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80
|
||
/* In testing, hdr was NULL here */
|
||
return false;
|
||
}
|
||
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
(ieee80211_has_protected(hdr->frame_control)))
|
||
rx_status->flag &= ~RX_FLAG_DECRYPTED;
|
||
else
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
|
||
@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80
|
||
/* during testing, hdr was NULL here */
|
||
return false;
|
||
}
|
||
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
(ieee80211_has_protected(hdr->frame_control)))
|
||
rx_status->flag &= ~RX_FLAG_DECRYPTED;
|
||
else
|
||
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
|
||
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
|
||
@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee
|
||
/* during testing, hdr could be NULL here */
|
||
return false;
|
||
}
|
||
- if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
+ if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
|
||
(ieee80211_has_protected(hdr->frame_control)))
|
||
rx_status->flag &= ~RX_FLAG_DECRYPTED;
|
||
else
|
||
--- a/include/linux/ieee80211.h
|
||
+++ b/include/linux/ieee80211.h
|
||
@@ -597,6 +597,20 @@ static inline int ieee80211_is_qos_nullf
|
||
}
|
||
|
||
/**
|
||
+ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
|
||
+ * @fc: frame control field in little-endian byteorder
|
||
+ */
|
||
+static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
|
||
+{
|
||
+ /* IEEE 802.11-2012, definition of "bufferable management frame";
|
||
+ * note that this ignores the IBSS special case. */
|
||
+ return ieee80211_is_mgmt(fc) &&
|
||
+ (ieee80211_is_action(fc) ||
|
||
+ ieee80211_is_disassoc(fc) ||
|
||
+ ieee80211_is_deauth(fc));
|
||
+}
|
||
+
|
||
+/**
|
||
* ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
|
||
* @seq_ctrl: frame sequence control bytes in little-endian byteorder
|
||
*/
|
||
@@ -2192,10 +2206,10 @@ static inline u8 *ieee80211_get_DA(struc
|
||
}
|
||
|
||
/**
|
||
- * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
|
||
+ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
|
||
* @hdr: the frame (buffer must include at least the first octet of payload)
|
||
*/
|
||
-static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
|
||
+static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
|
||
{
|
||
if (ieee80211_is_disassoc(hdr->frame_control) ||
|
||
ieee80211_is_deauth(hdr->frame_control))
|
||
@@ -2224,6 +2238,17 @@ static inline bool ieee80211_is_robust_m
|
||
}
|
||
|
||
/**
|
||
+ * 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;
|
||
};
|
||
|
||
/**
|
||
@@ -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;
|
||
|
||
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);
|
||
}
|
||
|
||
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);
|
||
|
||
/* 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;
|
||
|
||
+ sdata_assert_lock(sdata);
|
||
+
|
||
old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
|
||
if (!old_beacon)
|
||
return -ENOENT;
|
||
@@ -1090,8 +1096,6 @@ static int ieee80211_stop_ap(struct wiph
|
||
kfree(sdata->u.ap.next_beacon);
|
||
sdata->u.ap.next_beacon = NULL;
|
||
|
||
- 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);
|
||
@@ -1988,6 +1993,9 @@ static int ieee80211_change_bss(struct w
|
||
|
||
band = ieee80211_get_sdata_band(sdata);
|
||
|
||
+ if (WARN_ON(!wiphy->bands[band]))
|
||
+ return -EINVAL;
|
||
+
|
||
if (params->use_cts_prot >= 0) {
|
||
sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
|
||
changed |= BSS_CHANGED_ERP_CTS_PROT;
|
||
@@ -2638,6 +2646,24 @@ static int ieee80211_start_roc_work(stru
|
||
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
|
||
INIT_LIST_HEAD(&roc->dependents);
|
||
|
||
+ /*
|
||
+ * cookie is either the roc cookie (for normal roc)
|
||
+ * or the SKB (for mgmt TX)
|
||
+ */
|
||
+ if (!txskb) {
|
||
+ /* local->mtx protects this */
|
||
+ local->roc_cookie_counter++;
|
||
+ roc->cookie = local->roc_cookie_counter;
|
||
+ /* wow, you wrapped 64 bits ... more likely a bug */
|
||
+ if (WARN_ON(roc->cookie == 0)) {
|
||
+ roc->cookie = 1;
|
||
+ local->roc_cookie_counter++;
|
||
+ }
|
||
+ *cookie = roc->cookie;
|
||
+ } else {
|
||
+ *cookie = (unsigned long)txskb;
|
||
+ }
|
||
+
|
||
/* if there's one pending or we're scanning, queue this one */
|
||
if (!list_empty(&local->roc_list) ||
|
||
local->scanning || local->radar_detect_enabled)
|
||
@@ -2772,24 +2798,6 @@ static int ieee80211_start_roc_work(stru
|
||
if (!queued)
|
||
list_add_tail(&roc->list, &local->roc_list);
|
||
|
||
- /*
|
||
- * 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;
|
||
}
|
||
|
||
@@ -3004,8 +3012,10 @@ void ieee80211_csa_finalize_work(struct
|
||
if (!ieee80211_sdata_running(sdata))
|
||
goto unlock;
|
||
|
||
- sdata->radar_required = sdata->csa_radar_required;
|
||
+ sdata_assert_lock(sdata);
|
||
+
|
||
mutex_lock(&local->mtx);
|
||
+ sdata->radar_required = sdata->csa_radar_required;
|
||
err = ieee80211_vif_change_channel(sdata, &changed);
|
||
mutex_unlock(&local->mtx);
|
||
if (WARN_ON(err < 0))
|
||
@@ -3022,13 +3032,13 @@ void ieee80211_csa_finalize_work(struct
|
||
switch (sdata->vif.type) {
|
||
case NL80211_IFTYPE_AP:
|
||
err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
|
||
+ kfree(sdata->u.ap.next_beacon);
|
||
+ sdata->u.ap.next_beacon = NULL;
|
||
+
|
||
if (err < 0)
|
||
goto unlock;
|
||
|
||
changed |= err;
|
||
- kfree(sdata->u.ap.next_beacon);
|
||
- sdata->u.ap.next_beacon = NULL;
|
||
-
|
||
ieee80211_bss_info_change_notify(sdata, err);
|
||
break;
|
||
case NL80211_IFTYPE_ADHOC:
|
||
@@ -3066,7 +3076,7 @@ int ieee80211_channel_switch(struct wiph
|
||
struct ieee80211_if_mesh __maybe_unused *ifmsh;
|
||
int err, num_chanctx;
|
||
|
||
- lockdep_assert_held(&sdata->wdev.mtx);
|
||
+ sdata_assert_lock(sdata);
|
||
|
||
if (!list_empty(&local->roc_list) || local->scanning)
|
||
return -EBUSY;
|
||
--- a/net/mac80211/ht.c
|
||
+++ b/net/mac80211/ht.c
|
||
@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee802
|
||
mgmt->u.action.u.delba.params = cpu_to_le16(params);
|
||
mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
|
||
|
||
- ieee80211_tx_skb_tid(sdata, skb, tid);
|
||
+ ieee80211_tx_skb(sdata, skb);
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
--- 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;
|
||
+ }
|
||
|
||
/*
|
||
* 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);
|
||
|
||
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;
|
||
|
||
- return ieee80211_is_robust_mgmt_frame(hdr);
|
||
+ return ieee80211_is_robust_mgmt_frame(skb);
|
||
}
|
||
|
||
|
||
@@ -610,10 +610,10 @@ static int ieee80211_is_multicast_robust
|
||
{
|
||
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;
|
||
|
||
- return ieee80211_is_robust_mgmt_frame(hdr);
|
||
+ return ieee80211_is_robust_mgmt_frame(skb);
|
||
}
|
||
|
||
|
||
@@ -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;
|
||
|
||
- if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
|
||
+ if (!ieee80211_is_robust_mgmt_frame(skb))
|
||
return -1; /* not a robust management frame */
|
||
|
||
mmie = (struct ieee80211_mmie *)
|
||
@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *
|
||
sta->sta.addr, sta->sta.aid);
|
||
|
||
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);
|
||
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;
|
||
+ }
|
||
+
|
||
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
|
||
}
|
||
|
||
/* adjust first fragment's length */
|
||
- skb->len = hdrlen + per_fragm;
|
||
+ skb_trim(skb, hdrlen + per_fragm);
|
||
return 0;
|
||
}
|
||
|
||
@@ -2900,7 +2912,7 @@ ieee80211_get_buffered_bc(struct ieee802
|
||
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
|
||
}
|
||
|
||
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
||
if (!ieee80211_tx_prepare(sdata, &tx, skb))
|
||
break;
|
||
--- a/net/mac80211/wpa.c
|
||
+++ b/net/mac80211/wpa.c
|
||
@@ -499,7 +499,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
|
||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||
|
||
if (!ieee80211_is_data(hdr->frame_control) &&
|
||
- !ieee80211_is_robust_mgmt_frame(hdr))
|
||
+ !ieee80211_is_robust_mgmt_frame(skb))
|
||
return RX_CONTINUE;
|
||
|
||
data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN -
|
||
--- a/net/wireless/ap.c
|
||
+++ b/net/wireless/ap.c
|
||
@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg
|
||
err = rdev_stop_ap(rdev, dev);
|
||
if (!err) {
|
||
wdev->beacon_interval = 0;
|
||
- wdev->channel = NULL;
|
||
+ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||
wdev->ssid_len = 0;
|
||
rdev_set_qos_map(rdev, dev, NULL);
|
||
+ nl80211_send_ap_stopped(wdev);
|
||
}
|
||
|
||
return err;
|
||
--- a/net/wireless/core.c
|
||
+++ b/net/wireless/core.c
|
||
@@ -203,8 +203,11 @@ void cfg80211_stop_p2p_device(struct cfg
|
||
|
||
rdev->opencount--;
|
||
|
||
- 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);
|
||
+ }
|
||
}
|
||
|
||
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.
|
||
@@ -795,8 +795,6 @@ void cfg80211_leave(struct cfg80211_regi
|
||
default:
|
||
break;
|
||
}
|
||
-
|
||
- wdev->beacon_interval = 0;
|
||
}
|
||
|
||
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||
@@ -875,8 +873,11 @@ static int cfg80211_netdev_notifier_call
|
||
break;
|
||
case NETDEV_DOWN:
|
||
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
|
||
- WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev &&
|
||
- !rdev->scan_req->notified);
|
||
+ if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
|
||
+ if (WARN_ON(!rdev->scan_req->notified))
|
||
+ rdev->scan_req->aborted = true;
|
||
+ ___cfg80211_scan_done(rdev, false);
|
||
+ }
|
||
|
||
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);
|
||
}
|
||
@@ -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;
|
||
+
|
||
+ request->min_rssi_thold = INT_MAX;
|
||
+ for (i = 0; i < n_match_sets; i++)
|
||
+ request->min_rssi_thold =
|
||
+ min(request->match_sets[i].rssi_thold,
|
||
+ request->min_rssi_thold);
|
||
+ } else {
|
||
+ request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
|
||
}
|
||
|
||
if (info->attrs[NL80211_ATTR_IE]) {
|
||
@@ -5751,7 +5810,7 @@ static int nl80211_start_radar_detection
|
||
|
||
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);
|
||
}
|
||
|
||
-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;
|
||
|
||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||
if (!msg)
|
||
- return;
|
||
+ return NULL;
|
||
|
||
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;
|
||
}
|
||
|
||
- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||
- NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||
+ return msg;
|
||
}
|
||
|
||
-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 (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;
|
||
|
||
- wdev->channel = chandef->chan;
|
||
+ wdev->chandef = *chandef;
|
||
+ wdev->preset_chandef = *chandef;
|
||
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
|
||
}
|
||
EXPORT_SYMBOL(cfg80211_ch_switch_notify);
|
||
@@ -11673,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct
|
||
}
|
||
EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
|
||
|
||
+void nl80211_send_ap_stopped(struct wireless_dev *wdev)
|
||
+{
|
||
+ struct wiphy *wiphy = wdev->wiphy;
|
||
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||
+ struct sk_buff *msg;
|
||
+ void *hdr;
|
||
+
|
||
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||
+ if (!msg)
|
||
+ return;
|
||
+
|
||
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
|
||
+ if (!hdr)
|
||
+ goto out;
|
||
+
|
||
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
|
||
+ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
|
||
+ goto out;
|
||
+
|
||
+ genlmsg_end(msg, hdr);
|
||
+
|
||
+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
|
||
+ NL80211_MCGRP_MLME, GFP_KERNEL);
|
||
+ return;
|
||
+ out:
|
||
+ nlmsg_free(msg);
|
||
+}
|
||
+
|
||
/* initialisation/exit functions */
|
||
|
||
int nl80211_init(void)
|
||
--- a/net/wireless/nl80211.h
|
||
+++ b/net/wireless/nl80211.h
|
||
@@ -8,10 +8,10 @@ void nl80211_exit(void);
|
||
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
|
||
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
|
||
struct wireless_dev *wdev);
|
||
-void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
|
||
- struct wireless_dev *wdev);
|
||
-void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
|
||
- struct wireless_dev *wdev);
|
||
+struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
|
||
+ struct wireless_dev *wdev, bool aborted);
|
||
+void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
|
||
+ struct sk_buff *msg);
|
||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||
struct net_device *netdev, u32 cmd);
|
||
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
|
||
@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_reg
|
||
enum nl80211_radar_event event,
|
||
struct net_device *netdev, gfp_t gfp);
|
||
|
||
+void nl80211_send_ap_stopped(struct wireless_dev *wdev);
|
||
+
|
||
void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
|
||
|
||
#endif /* __NET_WIRELESS_NL80211_H */
|
||
--- a/net/wireless/scan.c
|
||
+++ b/net/wireless/scan.c
|
||
@@ -161,18 +161,25 @@ static void __cfg80211_bss_expire(struct
|
||
dev->bss_generation++;
|
||
}
|
||
|
||
-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
|
||
+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
|
||
+ bool send_message)
|
||
{
|
||
struct cfg80211_scan_request *request;
|
||
struct wireless_dev *wdev;
|
||
+ struct sk_buff *msg;
|
||
#ifdef CPTCFG_CFG80211_WEXT
|
||
union iwreq_data wrqu;
|
||
#endif
|
||
|
||
ASSERT_RTNL();
|
||
|
||
- request = rdev->scan_req;
|
||
+ if (rdev->scan_msg) {
|
||
+ nl80211_send_scan_result(rdev, rdev->scan_msg);
|
||
+ rdev->scan_msg = NULL;
|
||
+ return;
|
||
+ }
|
||
|
||
+ request = rdev->scan_req;
|
||
if (!request)
|
||
return;
|
||
|
||
@@ -186,18 +193,16 @@ void ___cfg80211_scan_done(struct cfg802
|
||
if (wdev->netdev)
|
||
cfg80211_sme_scan_done(wdev->netdev);
|
||
|
||
- 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);
|
||
}
|
||
|
||
+ 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
|
||
|
||
rdev->scan_req = NULL;
|
||
kfree(request);
|
||
+
|
||
+ if (!send_message)
|
||
+ rdev->scan_msg = msg;
|
||
+ else
|
||
+ nl80211_send_scan_result(rdev, msg);
|
||
}
|
||
|
||
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();
|
||
}
|
||
|
||
@@ -1079,7 +1089,7 @@ int cfg80211_wext_siwscan(struct net_dev
|
||
if (IS_ERR(rdev))
|
||
return PTR_ERR(rdev);
|
||
|
||
- 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
|
||
}
|
||
|
||
ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
|
||
- sdata->vif.csa_active = true;
|
||
|
||
mutex_lock(&local->chanctx_mtx);
|
||
if (local->use_chanctx) {
|
||
@@ -1039,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct
|
||
mutex_unlock(&local->chanctx_mtx);
|
||
|
||
sdata->csa_chandef = csa_ie.chandef;
|
||
+ sdata->vif.csa_active = true;
|
||
|
||
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(
|
||
{
|
||
struct ieee80211_sub_if_data *sdata;
|
||
|
||
+ 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
|
||
}
|
||
|
||
mutex_lock(&local->mtx);
|
||
- ieee80211_vif_release_channel(sdata);
|
||
if (ieee80211_vif_use_channel(sdata, &chandef,
|
||
ifibss->fixed_channel ?
|
||
IEEE80211_CHANCTX_SHARED :
|
||
@@ -303,6 +302,7 @@ static void __ieee80211_sta_join_ibss(st
|
||
mutex_unlock(&local->mtx);
|
||
return;
|
||
}
|
||
+ 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);
|
||
}
|
||
|
||
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;
|
||
|
||
+ 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);
|
||
}
|
||
|
||
--- 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"
|
||
|
||
|
||
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
|
||
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
||
+ struct ieee80211_channel *channel)
|
||
{
|
||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
struct cfg80211_bss *bss;
|
||
@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_d
|
||
if (!wdev->ssid_len)
|
||
return;
|
||
|
||
- 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);
|
||
|
||
if (WARN_ON(!bss))
|
||
@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_d
|
||
#endif
|
||
}
|
||
|
||
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
|
||
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
||
+ struct ieee80211_channel *channel, gfp_t gfp)
|
||
{
|
||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||
struct cfg80211_event *ev;
|
||
unsigned long flags;
|
||
|
||
- trace_cfg80211_ibss_joined(dev, bssid);
|
||
+ trace_cfg80211_ibss_joined(dev, bssid, channel);
|
||
+
|
||
+ if (WARN_ON(!channel))
|
||
+ return;
|
||
|
||
ev = kzalloc(sizeof(*ev), gfp);
|
||
if (!ev)
|
||
return;
|
||
|
||
ev->type = EVENT_IBSS_JOINED;
|
||
- memcpy(ev->cr.bssid, bssid, ETH_ALEN);
|
||
+ memcpy(ev->ij.bssid, bssid, ETH_ALEN);
|
||
+ ev->ij.channel = channel;
|
||
|
||
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
|
||
|
||
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))
|
||
);
|
||
|
||
-DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
|
||
- TP_PROTO(struct net_device *netdev, const u8 *addr),
|
||
- TP_ARGS(netdev, addr)
|
||
-);
|
||
-
|
||
DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame,
|
||
TP_PROTO(struct net_device *netdev, const u8 *addr),
|
||
TP_ARGS(netdev, addr)
|
||
@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_r
|
||
TP_ARGS(netdev, addr)
|
||
);
|
||
|
||
+TRACE_EVENT(cfg80211_ibss_joined,
|
||
+ TP_PROTO(struct net_device *netdev, const u8 *bssid,
|
||
+ struct ieee80211_channel *channel),
|
||
+ TP_ARGS(netdev, bssid, channel),
|
||
+ TP_STRUCT__entry(
|
||
+ NETDEV_ENTRY
|
||
+ MAC_ENTRY(bssid)
|
||
+ CHAN_ENTRY
|
||
+ ),
|
||
+ TP_fast_assign(
|
||
+ NETDEV_ASSIGN;
|
||
+ MAC_ASSIGN(bssid, bssid);
|
||
+ CHAN_ASSIGN(channel);
|
||
+ ),
|
||
+ TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT,
|
||
+ NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
|
||
+);
|
||
+
|
||
TRACE_EVENT(cfg80211_probe_status,
|
||
TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
|
||
bool acked),
|
||
--- a/net/wireless/util.c
|
||
+++ b/net/wireless/util.c
|
||
@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct
|
||
ev->dc.reason, true);
|
||
break;
|
||
case EVENT_IBSS_JOINED:
|
||
- __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
|
||
+ __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
|
||
+ ev->ij.channel);
|
||
break;
|
||
}
|
||
wdev_unlock(wdev);
|
||
@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct
|
||
*/
|
||
mutex_lock_nested(&wdev_iter->mtx, 1);
|
||
__acquire(wdev_iter->mtx);
|
||
- cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
|
||
+ cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
|
||
wdev_unlock(wdev_iter);
|
||
|
||
switch (chmode) {
|
||
--- a/net/wireless/chan.c
|
||
+++ b/net/wireless/chan.c
|
||
@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct
|
||
void
|
||
cfg80211_get_chan_state(struct wireless_dev *wdev,
|
||
struct ieee80211_channel **chan,
|
||
- enum cfg80211_chan_mode *chanmode)
|
||
+ enum cfg80211_chan_mode *chanmode,
|
||
+ u8 *radar_detect)
|
||
{
|
||
*chan = NULL;
|
||
*chanmode = CHAN_MODE_UNDEFINED;
|
||
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_
|
||
!wdev->ibss_dfs_possible)
|
||
? CHAN_MODE_SHARED
|
||
: CHAN_MODE_EXCLUSIVE;
|
||
+
|
||
+ /* consider worst-case - IBSS can try to return to the
|
||
+ * original user-specified channel as creator */
|
||
+ if (wdev->ibss_dfs_possible)
|
||
+ *radar_detect |= BIT(wdev->chandef.width);
|
||
return;
|
||
}
|
||
break;
|
||
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_
|
||
case NL80211_IFTYPE_AP:
|
||
case NL80211_IFTYPE_P2P_GO:
|
||
if (wdev->cac_started) {
|
||
- *chan = wdev->channel;
|
||
+ *chan = wdev->chandef.chan;
|
||
*chanmode = CHAN_MODE_SHARED;
|
||
+ *radar_detect |= BIT(wdev->chandef.width);
|
||
} else if (wdev->beacon_interval) {
|
||
- *chan = wdev->channel;
|
||
+ *chan = wdev->chandef.chan;
|
||
*chanmode = CHAN_MODE_SHARED;
|
||
+
|
||
+ if (cfg80211_chandef_dfs_required(wdev->wiphy,
|
||
+ &wdev->chandef))
|
||
+ *radar_detect |= BIT(wdev->chandef.width);
|
||
}
|
||
return;
|
||
case NL80211_IFTYPE_MESH_POINT:
|
||
if (wdev->mesh_id_len) {
|
||
- *chan = wdev->channel;
|
||
+ *chan = wdev->chandef.chan;
|
||
*chanmode = CHAN_MODE_SHARED;
|
||
+
|
||
+ if (cfg80211_chandef_dfs_required(wdev->wiphy,
|
||
+ &wdev->chandef))
|
||
+ *radar_detect |= BIT(wdev->chandef.width);
|
||
}
|
||
return;
|
||
case NL80211_IFTYPE_MONITOR:
|
||
--- a/net/wireless/mesh.c
|
||
+++ b/net/wireless/mesh.c
|
||
@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211
|
||
if (!err) {
|
||
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
|
||
wdev->mesh_id_len = setup->mesh_id_len;
|
||
- wdev->channel = setup->chandef.chan;
|
||
+ wdev->chandef = setup->chandef;
|
||
}
|
||
|
||
return err;
|
||
@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg
|
||
err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
|
||
chandef->chan);
|
||
if (!err)
|
||
- wdev->channel = chandef->chan;
|
||
+ wdev->chandef = *chandef;
|
||
|
||
return err;
|
||
}
|
||
@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct
|
||
err = rdev_leave_mesh(rdev, dev);
|
||
if (!err) {
|
||
wdev->mesh_id_len = 0;
|
||
- wdev->channel = NULL;
|
||
+ memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||
rdev_set_qos_map(rdev, dev, NULL);
|
||
}
|
||
|
||
--- a/net/wireless/mlme.c
|
||
+++ b/net/wireless/mlme.c
|
||
@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_devic
|
||
if (WARN_ON(!wdev->cac_started))
|
||
return;
|
||
|
||
- if (WARN_ON(!wdev->channel))
|
||
+ if (WARN_ON(!wdev->chandef.chan))
|
||
return;
|
||
|
||
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;
|
||
}
|
||
}
|
||
+
|
||
+ if (is2GHz && !twiceMaxEdgePower)
|
||
+ twiceMaxEdgePower = 60;
|
||
+
|
||
return twiceMaxEdgePower;
|
||
}
|
||
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
||
@@ -23,10 +23,11 @@
|
||
#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
|
||
#define MAX_MAG_DELTA 11
|
||
#define MAX_PHS_DELTA 10
|
||
+#define MAXIQCAL 3
|
||
|
||
struct coeff {
|
||
- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
|
||
- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
|
||
+ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
|
||
+ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
|
||
int iqc_coeff[2];
|
||
};
|
||
|
||
@@ -800,7 +801,7 @@ static bool ar9003_hw_calc_iq_corr(struc
|
||
if (q_q_coff > 63)
|
||
q_q_coff = 63;
|
||
|
||
- iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
|
||
+ iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
|
||
|
||
ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
|
||
chain_idx, iqc_coeff[0]);
|
||
@@ -831,7 +832,7 @@ static bool ar9003_hw_calc_iq_corr(struc
|
||
if (q_q_coff > 63)
|
||
q_q_coff = 63;
|
||
|
||
- 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;
|
||
}
|
||
|
||
-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;
|
||
}
|
||
}
|
||
|
||
/* 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];
|
||
|
||
/* 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;
|
||
|
||
- mp_coeff[outlier_idx] = mp_avg;
|
||
+ mp_coeff[outlier_idx][0] = mp_avg;
|
||
}
|
||
}
|
||
|
||
-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);
|
||
+ }
|
||
}
|
||
|
||
for (im = 0; im < nmeasurement; im++) {
|
||
+ magnitude = coeff->mag_coeff[i][im][0];
|
||
+ phase = coeff->phs_coeff[i][im][0];
|
||
|
||
- 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);
|
||
|
||
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;
|
||
}
|
||
|
||
-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)
|
||
{
|
||
struct ath_common *common = ath9k_hw_common(ah);
|
||
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
|
||
@@ -1004,10 +1072,11 @@ static void ar9003_hw_tx_iq_cal_post_pro
|
||
AR_PHY_CHAN_INFO_TAB_1,
|
||
AR_PHY_CHAN_INFO_TAB_2,
|
||
};
|
||
- struct coeff coeff;
|
||
+ static struct coeff coeff;
|
||
s32 iq_res[6];
|
||
int i, im, j;
|
||
- int nmeasurement;
|
||
+ int nmeasurement = 0;
|
||
+ bool outlier_detect = true;
|
||
|
||
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
||
if (!(ah->txchainmask & (1 << i)))
|
||
@@ -1065,17 +1134,23 @@ static void ar9003_hw_tx_iq_cal_post_pro
|
||
goto tx_iqcal_fail;
|
||
}
|
||
|
||
- coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
|
||
- coeff.phs_coeff[i][im] =
|
||
+ coeff.phs_coeff[i][im][iqcal_idx] =
|
||
+ coeff.iqc_coeff[0] & 0x7f;
|
||
+ coeff.mag_coeff[i][im][iqcal_idx] =
|
||
(coeff.iqc_coeff[0] >> 7) & 0x7f;
|
||
|
||
- if (coeff.mag_coeff[i][im] > 63)
|
||
- coeff.mag_coeff[i][im] -= 128;
|
||
- if (coeff.phs_coeff[i][im] > 63)
|
||
- coeff.phs_coeff[i][im] -= 128;
|
||
+ if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
|
||
+ coeff.mag_coeff[i][im][iqcal_idx] -= 128;
|
||
+ if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
|
||
+ coeff.phs_coeff[i][im][iqcal_idx] -= 128;
|
||
}
|
||
}
|
||
- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
|
||
+
|
||
+ if (AR_SREV_9550(ah))
|
||
+ outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
|
||
+ iqcal_idx, nmeasurement);
|
||
+ if (outlier_detect)
|
||
+ ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
|
||
|
||
return;
|
||
|
||
@@ -1409,7 +1484,7 @@ skip_tx_iqcal:
|
||
}
|
||
|
||
if (txiqcal_done)
|
||
- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
|
||
+ ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
|
||
else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
|
||
ar9003_hw_tx_iq_cal_reload(ah);
|
||
|
||
@@ -1455,14 +1530,38 @@ skip_tx_iqcal:
|
||
return true;
|
||
}
|
||
|
||
+static bool do_ar9003_agc_cal(struct ath_hw *ah)
|
||
+{
|
||
+ 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;
|
||
+ }
|
||
+
|
||
+ return true;
|
||
+}
|
||
+
|
||
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;
|
||
+ }
|
||
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);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
}
|
||
|
||
- if (txiqcal_done)
|
||
- ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
|
||
-
|
||
/* Revert chainmask to runtime parameters */
|
||
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
|
||
|
||
--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
|
||
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h
|
||
@@ -15,6 +15,8 @@
|
||
#ifndef RTL8187_H
|
||
#define RTL8187_H
|
||
|
||
+#include <linux/cache.h>
|
||
+
|
||
#include "rtl818x.h"
|
||
#include "leds.h"
|
||
|
||
@@ -139,7 +141,10 @@ struct rtl8187_priv {
|
||
u8 aifsn[4];
|
||
u8 rfkill_mask;
|
||
struct {
|
||
- __le64 buf;
|
||
+ union {
|
||
+ __le64 buf;
|
||
+ u8 dummy1[L1_CACHE_BYTES];
|
||
+ } ____cacheline_aligned;
|
||
struct sk_buff_head queue;
|
||
} b_tx_status; /* This queue is used by both -b and non-b devices */
|
||
struct mutex io_mutex;
|
||
@@ -147,7 +152,8 @@ struct rtl8187_priv {
|
||
u8 bits8;
|
||
__le16 bits16;
|
||
__le32 bits32;
|
||
- } *io_dmabuf;
|
||
+ u8 dummy2[L1_CACHE_BYTES];
|
||
+ } *io_dmabuf ____cacheline_aligned;
|
||
bool rfkill_off;
|
||
u16 seqno;
|
||
};
|
||
--- a/net/mac80211/wme.c
|
||
+++ b/net/mac80211/wme.c
|
||
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80
|
||
return IEEE80211_AC_BE;
|
||
}
|
||
|
||
+ if (skb->protocol == sdata->control_port_protocol) {
|
||
+ skb->priority = 7;
|
||
+ return ieee80211_downgrade_queue(sdata, skb);
|
||
+ }
|
||
+
|
||
/* 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;
|
||
+ }
|
||
+
|
||
buffered = ath_tid_has_buffered(tid);
|
||
|
||
tid->sched = false;
|
||
@@ -1696,7 +1698,7 @@ int ath_cabq_update(struct ath_softc *sc
|
||
|
||
ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
|
||
|
||
- qi.tqi_readyTime = (cur_conf->beacon_interval *
|
||
+ qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) *
|
||
ATH_CABQ_READY_TIME) / 100;
|
||
ath_txq_update(sc, qnum, &qi);
|
||
|
||
@@ -2061,7 +2063,7 @@ static struct ath_buf *ath_tx_setup_buff
|
||
|
||
ATH_TXBUF_RESET(bf);
|
||
|
||
- if (tid) {
|
||
+ if (tid && ieee80211_is_data_present(hdr->frame_control)) {
|
||
fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
|
||
seqno = tid->seq_next;
|
||
hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
|
||
@@ -2184,14 +2186,15 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||
txq->stopped = true;
|
||
}
|
||
|
||
+ if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
|
||
+ 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);
|
||
}
|
||
+}
|
||
|
||
+static void cleanup_single_sta(struct sta_info *sta)
|
||
+{
|
||
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||
+ struct ieee80211_local *local = sdata->local;
|
||
+
|
||
+ __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);
|
||
+
|
||
/* 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;
|
||
+
|
||
set_sta_flag(sta, WLAN_STA_INSERTED);
|
||
+ /* accept BA sessions now */
|
||
+ clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||
|
||
ieee80211_recalc_min_chandef(sdata);
|
||
ieee80211_sta_debugfs_add(sta);
|
||
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct
|
||
mesh_accept_plinks_update(sdata);
|
||
|
||
return 0;
|
||
+ out_remove:
|
||
+ sta_info_hash_del(local, sta);
|
||
+ list_del_rcu(&sta->list);
|
||
+ local->num_sta--;
|
||
+ synchronize_net();
|
||
+ __cleanup_single_sta(sta);
|
||
out_err:
|
||
mutex_unlock(&local->sta_mtx);
|
||
rcu_read_lock();
|
||
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta
|
||
}
|
||
EXPORT_SYMBOL(ieee80211_find_sta);
|
||
|
||
-static void clear_sta_ps_flags(void *_sta)
|
||
+/* powersave support code */
|
||
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||
{
|
||
- struct sta_info *sta = _sta;
|
||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||
+ struct ieee80211_local *local = sdata->local;
|
||
+ struct sk_buff_head pending;
|
||
+ int filtered = 0, buffered = 0, ac;
|
||
+ unsigned long flags;
|
||
struct ps_data *ps;
|
||
|
||
if (sdata->vif.type == NL80211_IFTYPE_AP ||
|
||
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_st
|
||
else
|
||
return;
|
||
|
||
- clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
|
||
- if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
|
||
- atomic_dec(&ps->num_sta_ps);
|
||
-}
|
||
-
|
||
-/* powersave support code */
|
||
-void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
|
||
-{
|
||
- struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||
- struct ieee80211_local *local = sdata->local;
|
||
- struct sk_buff_head pending;
|
||
- int filtered = 0, buffered = 0, ac;
|
||
- unsigned long flags;
|
||
-
|
||
clear_sta_flag(sta, WLAN_STA_SP);
|
||
|
||
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
|
||
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||
|
||
skb_queue_head_init(&pending);
|
||
|
||
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
|
||
+ spin_lock(&sta->ps_lock);
|
||
/* Send all buffered frames to the station */
|
||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||
int count = skb_queue_len(&pending), tmp;
|
||
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||
buffered += tmp - count;
|
||
}
|
||
|
||
- ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
|
||
+ ieee80211_add_pending_skbs(local, &pending);
|
||
+ clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
|
||
+ clear_sta_flag(sta, WLAN_STA_PS_STA);
|
||
+ spin_unlock(&sta->ps_lock);
|
||
+
|
||
+ atomic_dec(&ps->num_sta_ps);
|
||
|
||
/* This station just woke up and isn't aware of our SMPS state */
|
||
if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
|
||
--- a/net/mac80211/sta_info.h
|
||
+++ b/net/mac80211/sta_info.h
|
||
@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
|
||
* @drv_unblock_wk: used for driver PS unblocking
|
||
* @listen_interval: listen interval of this station, when we're acting as AP
|
||
* @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
|
||
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
|
||
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station
|
||
* when it leaves power saving state or polls
|
||
* @tx_filtered: buffers (per AC) of frames we already tried to
|
||
@@ -356,10 +357,8 @@ struct sta_info {
|
||
/* use the accessors defined below */
|
||
unsigned long _flags;
|
||
|
||
- /*
|
||
- * STA powersave frame queues, no more than the internal
|
||
- * locking required.
|
||
- */
|
||
+ /* STA powersave lock and frame queues */
|
||
+ spinlock_t ps_lock;
|
||
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
|
||
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
|
||
unsigned long driver_buffered_tids;
|
||
--- a/net/mac80211/util.c
|
||
+++ b/net/mac80211/util.c
|
||
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ie
|
||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||
}
|
||
|
||
-void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
|
||
- struct sk_buff_head *skbs,
|
||
- void (*fn)(void *data), void *data)
|
||
+void ieee80211_add_pending_skbs(struct ieee80211_local *local,
|
||
+ struct sk_buff_head *skbs)
|
||
{
|
||
struct ieee80211_hw *hw = &local->hw;
|
||
struct sk_buff *skb;
|
||
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struc
|
||
__skb_queue_tail(&local->pending[queue], skb);
|
||
}
|
||
|
||
- if (fn)
|
||
- fn(data);
|
||
-
|
||
for (i = 0; i < hw->queues; i++)
|
||
__ieee80211_wake_queue(hw, i,
|
||
IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
|
||
--- a/net/wireless/reg.c
|
||
+++ b/net/wireless/reg.c
|
||
@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regu
|
||
return;
|
||
case NL80211_REGDOM_SET_BY_USER:
|
||
treatment = reg_process_hint_user(reg_request);
|
||
- if (treatment == REG_REQ_OK ||
|
||
+ if (treatment == REG_REQ_IGNORE ||
|
||
treatment == REG_REQ_ALREADY_SET)
|
||
return;
|
||
schedule_delayed_work(®_timeout, msecs_to_jiffies(3142));
|
||
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||
@@ -138,43 +138,41 @@ static ssize_t read_file_ani(struct file
|
||
unsigned int len = 0, size = 1024;
|
||
ssize_t retval = 0;
|
||
char *buf;
|
||
+ int i;
|
||
+ struct {
|
||
+ const char *name;
|
||
+ unsigned int val;
|
||
+ } ani_info[] = {
|
||
+ { "ANI RESET", ah->stats.ast_ani_reset },
|
||
+ { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel },
|
||
+ { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel },
|
||
+ { "SPUR UP", ah->stats.ast_ani_spurup },
|
||
+ { "SPUR DOWN", ah->stats.ast_ani_spurup },
|
||
+ { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon },
|
||
+ { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff },
|
||
+ { "MRC-CCK ON", ah->stats.ast_ani_ccklow },
|
||
+ { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh },
|
||
+ { "FIR-STEP UP", ah->stats.ast_ani_stepup },
|
||
+ { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown },
|
||
+ { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero },
|
||
+ { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs },
|
||
+ { "CCK ERRORS", ah->stats.ast_ani_cckerrs },
|
||
+ };
|
||
|
||
buf = kzalloc(size, GFP_KERNEL);
|
||
if (buf == NULL)
|
||
return -ENOMEM;
|
||
|
||
- if (common->disable_ani) {
|
||
- len += scnprintf(buf + len, size - len, "%s: %s\n",
|
||
- "ANI", "DISABLED");
|
||
+ len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI",
|
||
+ common->disable_ani ? "DISABLED" : "ENABLED");
|
||
+
|
||
+ if (common->disable_ani)
|
||
goto exit;
|
||
- }
|
||
|
||
- len += scnprintf(buf + len, size - len, "%15s: %s\n",
|
||
- "ANI", "ENABLED");
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "ANI RESET", ah->stats.ast_ani_reset);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "SPUR UP", ah->stats.ast_ani_spurup);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "SPUR DOWN", ah->stats.ast_ani_spurup);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "MRC-CCK ON", ah->stats.ast_ani_ccklow);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "FIR-STEP UP", ah->stats.ast_ani_stepup);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
|
||
- len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
- "CCK ERRORS", ah->stats.ast_ani_cckerrs);
|
||
+ for (i = 0; i < ARRAY_SIZE(ani_info); i++)
|
||
+ len += scnprintf(buf + len, size - len, "%15s: %u\n",
|
||
+ ani_info[i].name, ani_info[i].val);
|
||
+
|
||
exit:
|
||
if (len > size)
|
||
len = size;
|
||
@@ -866,6 +864,12 @@ static ssize_t read_file_reset(struct fi
|
||
"%17s: %2d\n", "PLL RX Hang",
|
||
sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
|
||
len += scnprintf(buf + len, sizeof(buf) - len,
|
||
+ "%17s: %2d\n", "MAC Hang",
|
||
+ sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
|
||
+ len += scnprintf(buf + len, sizeof(buf) - len,
|
||
+ "%17s: %2d\n", "Stuck Beacon",
|
||
+ sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
|
||
+ len += scnprintf(buf + len, sizeof(buf) - len,
|
||
"%17s: %2d\n", "MCI Reset",
|
||
sc->debug.stats.reset[RESET_TYPE_MCI]);
|
||
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||
@@ -868,10 +868,6 @@ static void ar9003_hw_set_rfmode(struct
|
||
|
||
if (IS_CHAN_A_FAST_CLOCK(ah, chan))
|
||
rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
|
||
- if (IS_CHAN_QUARTER_RATE(chan))
|
||
- rfMode |= AR_PHY_MODE_QUARTER;
|
||
- if (IS_CHAN_HALF_RATE(chan))
|
||
- rfMode |= AR_PHY_MODE_HALF;
|
||
|
||
if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF))
|
||
REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL,
|
||
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
|
||
@@ -706,6 +706,7 @@ ath5k_get_survey(struct ieee80211_hw *hw
|
||
survey->channel = conf->chandef.chan;
|
||
survey->noise = ah->ah_noise_floor;
|
||
survey->filled = SURVEY_INFO_NOISE_DBM |
|
||
+ SURVEY_INFO_IN_USE |
|
||
SURVEY_INFO_CHANNEL_TIME |
|
||
SURVEY_INFO_CHANNEL_TIME_BUSY |
|
||
SURVEY_INFO_CHANNEL_TIME_RX |
|
||
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
||
@@ -732,11 +732,18 @@ static struct ath_rxbuf *ath_get_next_rx
|
||
return NULL;
|
||
|
||
/*
|
||
- * mark descriptor as zero-length and set the 'more'
|
||
- * flag to ensure that both buffers get discarded
|
||
+ * Re-check previous descriptor, in case it has been filled
|
||
+ * in the mean time.
|
||
*/
|
||
- rs->rs_datalen = 0;
|
||
- rs->rs_more = true;
|
||
+ ret = ath9k_hw_rxprocdesc(ah, ds, rs);
|
||
+ if (ret == -EINPROGRESS) {
|
||
+ /*
|
||
+ * mark descriptor as zero-length and set the 'more'
|
||
+ * flag to ensure that both buffers get discarded
|
||
+ */
|
||
+ rs->rs_datalen = 0;
|
||
+ rs->rs_more = true;
|
||
+ }
|
||
}
|
||
|
||
list_del(&bf->list);
|
||
@@ -985,32 +992,32 @@ static int ath9k_rx_skb_preprocess(struc
|
||
struct ath_common *common = ath9k_hw_common(ah);
|
||
struct ieee80211_hdr *hdr;
|
||
bool discard_current = sc->rx.discard_next;
|
||
- int ret = 0;
|
||
|
||
/*
|
||
* Discard corrupt descriptors which are marked in
|
||
* ath_get_next_rx_buf().
|
||
*/
|
||
- sc->rx.discard_next = rx_stats->rs_more;
|
||
if (discard_current)
|
||
- return -EINVAL;
|
||
+ goto corrupt;
|
||
+
|
||
+ sc->rx.discard_next = false;
|
||
|
||
/*
|
||
* 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;
|
||
}
|
||
|
||
/*
|
||
* 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
|
||
|
||
-exit:
|
||
- sc->rx.discard_next = false;
|
||
- return ret;
|
||
+ return 0;
|
||
+
|
||
+corrupt:
|
||
+ sc->rx.discard_next = rx_stats->rs_more;
|
||
+ return -EINVAL;
|
||
}
|
||
|
||
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;
|
||
+
|
||
+ /* Older chipsets are more sensitive to high PHY error counts */
|
||
+ else if (!AR_SREV_9300_20_OR_LATER(ah) &&
|
||
+ aniState->ofdmNoiseImmunityLevel >= 8)
|
||
+ weak_sig = false;
|
||
+
|
||
+ if (aniState->ofdmWeakSigDetect != weak_sig)
|
||
+ ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
|
||
+ weak_sig);
|
||
+
|
||
+ if (!AR_SREV_9300_20_OR_LATER(ah))
|
||
+ return;
|
||
|
||
if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
|
||
ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||
@@ -308,17 +318,6 @@ void ath9k_ani_reset(struct ath_hw *ah,
|
||
BUG_ON(aniState == NULL);
|
||
ah->stats.ast_ani_reset++;
|
||
|
||
- /* only allow a subset of functions in AP mode */
|
||
- if (ah->opmode == NL80211_IFTYPE_AP) {
|
||
- if (IS_CHAN_2GHZ(chan)) {
|
||
- ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
|
||
- ATH9K_ANI_FIRSTEP_LEVEL);
|
||
- if (AR_SREV_9300_20_OR_LATER(ah))
|
||
- ah->ani_function |= ATH9K_ANI_MRC_CCK;
|
||
- } else
|
||
- ah->ani_function = 0;
|
||
- }
|
||
-
|
||
ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL,
|
||
aniState->ofdmNoiseImmunityLevel);
|
||
cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL,
|
||
@@ -483,10 +482,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah
|
||
|
||
ath_dbg(common, ANI, "Initialize ANI\n");
|
||
|
||
- ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||
- ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
|
||
- ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
|
||
- ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
|
||
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
|
||
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
|
||
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
|
||
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
|
||
+ } else {
|
||
+ ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
|
||
+ ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
|
||
+ ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
|
||
+ ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
|
||
+ }
|
||
|
||
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
|
||
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
||
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
|
||
@@ -26,10 +26,6 @@ static const int firstep_table[] =
|
||
/* level: 0 1 2 3 4 5 6 7 8 */
|
||
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
|
||
|
||
-static const int cycpwrThr1_table[] =
|
||
-/* level: 0 1 2 3 4 5 6 7 8 */
|
||
- { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */
|
||
-
|
||
/*
|
||
* register values to turn OFDM weak signal detection OFF
|
||
*/
|
||
@@ -921,7 +917,7 @@ static bool ar5008_hw_ani_control_new(st
|
||
struct ath_common *common = ath9k_hw_common(ah);
|
||
struct ath9k_channel *chan = ah->curchan;
|
||
struct ar5416AniState *aniState = &ah->ani;
|
||
- s32 value, value2;
|
||
+ s32 value;
|
||
|
||
switch (cmd & ah->ani_function) {
|
||
case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
|
||
@@ -1008,42 +1004,11 @@ static bool ar5008_hw_ani_control_new(st
|
||
case ATH9K_ANI_FIRSTEP_LEVEL:{
|
||
u32 level = param;
|
||
|
||
- if (level >= ARRAY_SIZE(firstep_table)) {
|
||
- ath_dbg(common, ANI,
|
||
- "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n",
|
||
- level, ARRAY_SIZE(firstep_table));
|
||
- return false;
|
||
- }
|
||
-
|
||
- /*
|
||
- * make register setting relative to default
|
||
- * from INI file & cap value
|
||
- */
|
||
- value = firstep_table[level] -
|
||
- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
|
||
- aniState->iniDef.firstep;
|
||
- if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
|
||
- value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
|
||
- if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
|
||
- value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
|
||
+ value = level * 2;
|
||
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
|
||
- AR_PHY_FIND_SIG_FIRSTEP,
|
||
- value);
|
||
- /*
|
||
- * we need to set first step low register too
|
||
- * make register setting relative to default
|
||
- * from INI file & cap value
|
||
- */
|
||
- value2 = firstep_table[level] -
|
||
- firstep_table[ATH9K_ANI_FIRSTEP_LVL] +
|
||
- aniState->iniDef.firstepLow;
|
||
- if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
|
||
- value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
|
||
- if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
|
||
- value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
|
||
-
|
||
+ AR_PHY_FIND_SIG_FIRSTEP, value);
|
||
REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
|
||
- AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
|
||
+ AR_PHY_FIND_SIG_FIRSTEP_LOW, value);
|
||
|
||
if (level != aniState->firstepLevel) {
|
||
ath_dbg(common, ANI,
|
||
@@ -1060,7 +1025,7 @@ static bool ar5008_hw_ani_control_new(st
|
||
aniState->firstepLevel,
|
||
level,
|
||
ATH9K_ANI_FIRSTEP_LVL,
|
||
- value2,
|
||
+ value,
|
||
aniState->iniDef.firstepLow);
|
||
if (level > aniState->firstepLevel)
|
||
ah->stats.ast_ani_stepup++;
|
||
@@ -1073,41 +1038,13 @@ static bool ar5008_hw_ani_control_new(st
|
||
case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
|
||
u32 level = param;
|
||
|
||
- if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
|
||
- ath_dbg(common, ANI,
|
||
- "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n",
|
||
- level, ARRAY_SIZE(cycpwrThr1_table));
|
||
- return false;
|
||
- }
|
||
- /*
|
||
- * make register setting relative to default
|
||
- * from INI file & cap value
|
||
- */
|
||
- value = cycpwrThr1_table[level] -
|
||
- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
|
||
- aniState->iniDef.cycpwrThr1;
|
||
- if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
|
||
- value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
|
||
- if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
|
||
- value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
|
||
+ value = (level + 1) * 2;
|
||
REG_RMW_FIELD(ah, AR_PHY_TIMING5,
|
||
- AR_PHY_TIMING5_CYCPWR_THR1,
|
||
- value);
|
||
+ AR_PHY_TIMING5_CYCPWR_THR1, value);
|
||
|
||
- /*
|
||
- * set AR_PHY_EXT_CCA for extension channel
|
||
- * make register setting relative to default
|
||
- * from INI file & cap value
|
||
- */
|
||
- value2 = cycpwrThr1_table[level] -
|
||
- cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] +
|
||
- aniState->iniDef.cycpwrThr1Ext;
|
||
- if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
|
||
- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
|
||
- if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
|
||
- value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
|
||
- REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
|
||
- AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
|
||
+ if (IS_CHAN_HT40(ah->curchan))
|
||
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
|
||
+ AR_PHY_EXT_TIMING5_CYCPWR_THR1, value);
|
||
|
||
if (level != aniState->spurImmunityLevel) {
|
||
ath_dbg(common, ANI,
|
||
@@ -1124,7 +1061,7 @@ static bool ar5008_hw_ani_control_new(st
|
||
aniState->spurImmunityLevel,
|
||
level,
|
||
ATH9K_ANI_SPUR_IMMUNE_LVL,
|
||
- value2,
|
||
+ value,
|
||
aniState->iniDef.cycpwrThr1Ext);
|
||
if (level > aniState->spurImmunityLevel)
|
||
ah->stats.ast_ani_spurup++;
|