mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
More changes, including drivers:
- brcmfmac: FT/OKC roaming offload
- ath12k: IPQ5332 platform infrastructure
- cfg80211/mac80211: non-STA TX/RX infrastructure
for MLO to fix address translation bugs
- the rest is mostly minor cleanups etc.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmqxHzUACgkQ10qiO8sP
aACS2g/9HLt0g35/O74zeEyD1+J37Xu7oXNdbG7CWGPnTqxupvSeNxrLJN8ToSRj
Gm80BGEuFxF+OhR4ZuvwGd2sUjmprZ6l27CIrqiEIHWrI3+kFyqkOBHKu2DuQ6/m
QyvXn6tAKwQ9YPOyfpmyVYszujT/TyEmYkPvgX8xeNeTStwUhDCT/G3/NIN2/eyn
jR5po2eeg3M12V93mTb9usHRkaWN5NIfsUTAuN5noHv4o8v8kbwbTuQiVMjlMIxJ
5rEen2BidPJuxfSXeYK1JVgEzs1j+JKvHF+Wd1VCE011iZaF3lp8d9CF+Wn15v0Z
UfvXzrmU3zoQb2bKyCSQPBskHI8r3zDpkxzZoifGBucKsf0lm3pqH2EVGiBpTPga
OvUp2/4Z75RGKtC9Hao7a6rofPDyZTyiaG+hHtsOs8qTDBSQZGt6sAbv1b4iVziw
VpZoyocBUyIKqX8SST14kLbqG8crEso08Zy4xE4JbSV7VBl96Qwck4hqmiDL0cAC
Vuq5Pg/OCN6A2TWvJElnWJiWE96sZ0wF9T00WmMEGPBuyZWVk4RkfCGzQJ1SK/1K
s8NrFdqqcIsICLNQTO7ofBeaky7/55m0It7OfcvHIQwo1DWUZ//WeMptSKWP2BBb
rVBgUtPlQhxvuNVNysvkgUnjS7Fh8/18JvE81yX8sIN6DGgduxE=
=Nzgx
-----END PGP SIGNATURE-----
Merge tag 'wireless-next-2026-09-21' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
More changes, including drivers:
- brcmfmac: FT/OKC roaming offload
- ath12k: IPQ5332 platform infrastructure
- cfg80211/mac80211: non-STA TX/RX infrastructure
for MLO to fix address translation bugs
- the rest is mostly minor cleanups etc.
* tag 'wireless-next-2026-09-21' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (101 commits)
dt-bindings: net: wireless: Convert WL1251 to DT schema
libertas: mesh: remove unused and undocumented sysfs attribute groups
wifi: mac80211: fix multi-link UHR association
wifi: nl80211: rename no-ACK bitmap to TID bitmap
wifi: radiotap: correct EHT TB U-SIG 1 B20:25
wifi: ieee80211: fix FTM bufferable check
wifi: mac80211: allow advertising 20 MHz-only non-AP STA
wifi: mac80211: WARN on 40 MHz HT/HE mismatch
wifi: mac80211: tests: fix memory leak
wifi: mac80211: use assign_bit() where applicable
wifi: mac80211: pass error station if non-STA transmit was requested
wifi: mac80211: pass station to ieee80211_tx_skb_tid
wifi: mac80211: report to cfg80211 when no STA is known for a frame
wifi: cfg80211: add attribute for TX/RX denoting there is no station
wifi: mac80211: rework RX packet handling
wifi: mac80211: refactor RX link_id and station handling
wifi: mac80211: change public RX API to use link stations
wifi: iwlwifi: use link_sta internally to the driver
MAINTAINERS: Replace wireless.wiki.kernel.org links
wifi: brcmfmac: log the firmware status when a connect fails
...
====================
Link: https://patch.msgid.link/20260921121635.195723-3-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
10cfa109c8
13
.mailmap
13
.mailmap
|
|
@ -10,6 +10,7 @@
|
|||
#
|
||||
# Please keep this list dictionary sorted.
|
||||
#
|
||||
Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com> <quic_aarasahu@quicinc.com>
|
||||
Aaron Durbin <adurbin@google.com>
|
||||
Abel Vesa <abelvesa@kernel.org> <abel.vesa@nxp.com>
|
||||
Abel Vesa <abelvesa@kernel.org> <abel.vesa@linaro.org>
|
||||
|
|
@ -130,7 +131,8 @@ Axel Dyks <xl@xlsigned.net>
|
|||
Axel Lin <axel.lin@gmail.com>
|
||||
Balakrishna Godavarthi <quic_bgodavar@quicinc.com> <bgodavar@codeaurora.org>
|
||||
Banajit Goswami <quic_bgoswami@quicinc.com> <bgoswami@codeaurora.org>
|
||||
Baochen Qiang <quic_bqiang@quicinc.com> <bqiang@codeaurora.org>
|
||||
Baochen Qiang <baochen.qiang@oss.qualcomm.com> <bqiang@codeaurora.org>
|
||||
Baochen Qiang <baochen.qiang@oss.qualcomm.com> <quic_bqiang@quicinc.com>
|
||||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@linaro.org>
|
||||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@spreadtrum.com>
|
||||
Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@unisoc.com>
|
||||
|
|
@ -575,6 +577,7 @@ Maheshwar Ajja <quic_majja@quicinc.com> <majja@codeaurora.org>
|
|||
Maíra Canal <mairacanal@riseup.net> <maira.canal@usp.br>
|
||||
Malathi Gottam <quic_mgottam@quicinc.com> <mgottam@codeaurora.org>
|
||||
Manikanta Pubbisetty <quic_mpubbise@quicinc.com> <mpubbise@codeaurora.org>
|
||||
Manish Dharanenthiran <manish.dharanenthiran@oss.qualcomm.com> <quic_mdharane@quicinc.com>
|
||||
Manivannan Sadhasivam <mani@kernel.org> <manivannanece23@gmail.com>
|
||||
Manivannan Sadhasivam <mani@kernel.org> <manivannan.sadhasivam@linaro.org>
|
||||
Manoj Basapathi <quic_manojbm@quicinc.com> <manojbm@codeaurora.org>
|
||||
|
|
@ -764,6 +767,8 @@ Rakesh Pillai <quic_pillair@quicinc.com> <pillair@codeaurora.org>
|
|||
Ralf Baechle <ralf@linux-mips.org>
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Ram Chandra Jangir <quic_rjangir@quicinc.com> <rjangir@codeaurora.org>
|
||||
Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com> <quic_ramess@quicinc.com>
|
||||
Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com> <ramess@codeaurora.org>
|
||||
Randy Dunlap <rdunlap@infradead.org> <rdunlap@xenotime.net>
|
||||
Randy Dunlap <rdunlap@infradead.org> <randy.dunlap@oracle.com>
|
||||
Randy Dunlap <rdunlap@infradead.org> <rddunlap@osdl.org>
|
||||
|
|
@ -862,7 +867,8 @@ Sricharan Ramabadhran <quic_srichara@quicinc.com> <sricharan@codeaurora.org>
|
|||
Srinivas Kandagatla <srini@kernel.org> <srinivas.kandagatla@st.com>
|
||||
Srinivas Kandagatla <srini@kernel.org> <srinivas.kandagatla@linaro.org>
|
||||
Srinivas Ramana <quic_sramana@quicinc.com> <sramana@codeaurora.org>
|
||||
Sriram R <quic_srirrama@quicinc.com> <srirrama@codeaurora.org>
|
||||
Sriram R <sriram.ramachandran@oss.qualcomm.com> <quic_srirrama@quicinc.com>
|
||||
Sriram R <sriram.ramachandran@oss.qualcomm.com> <srirrama@codeaurora.org>
|
||||
Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> <sriram.yagnaraman@est.tech>
|
||||
Stanislav Fomichev <sdf@fomichev.me> <sdf@google.com>
|
||||
Stanislav Fomichev <sdf@fomichev.me> <stfomichev@gmail.com>
|
||||
|
|
@ -946,7 +952,8 @@ Vadim Fedorenko <vadim.fedorenko@linux.dev> <vfedorenko@novek.ru>
|
|||
Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
|
||||
Vara Reddy <quic_varar@quicinc.com> <varar@codeaurora.org>
|
||||
Varadarajan Narayanan <quic_varada@quicinc.com> <varada@codeaurora.org>
|
||||
Vasanthakumar Thiagarajan <quic_vthiagar@quicinc.com> <vthiagar@codeaurora.org>
|
||||
Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> <quic_vthiagar@quicinc.com>
|
||||
Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> <vthiagar@codeaurora.org>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@virtuozzo.com>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@openvz.org>
|
||||
Vasily Averin <vasily.averin@linux.dev> <vvs@parallels.com>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ properties:
|
|||
description: Calibration data for sub-band 3 in the 5GHz band.
|
||||
maxItems: 502
|
||||
|
||||
marvell,invalid-reg-hint-in-rom:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
The regulatory hint in ROM conflicts with platform configuration.
|
||||
It should be ignored, so the platform regulatory domain can be used.
|
||||
|
||||
marvell,wakeup-pin:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -58,13 +58,6 @@ properties:
|
|||
String to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
|
||||
qcom,ath12k-calibration-variant:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
description:
|
||||
String to uniquely identify variant of the calibration data for designs
|
||||
with colliding bus and device ids
|
||||
|
||||
qcom,wsi-controller:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ properties:
|
|||
used, this property is required. When SDIO is used, the "in-band"
|
||||
interrupt provided by the SDIO bus is used unless an interrupt is defined
|
||||
in the Device Tree.
|
||||
|
||||
The hardware suffers from a limitation when this property is used with
|
||||
SDIO. OOB IRQ with SDIO should only be used for debug.
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
* Texas Instruments wl1251 wireless lan controller
|
||||
|
||||
The wl1251 chip can be connected via SPI or via SDIO. This
|
||||
document describes the binding for the SPI connected chip.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "ti,wl1251"
|
||||
- reg : Chip select address of device
|
||||
- spi-max-frequency : Maximum SPI clocking speed of device in Hz
|
||||
- interrupts : Should contain interrupt line
|
||||
- vio-supply : phandle to regulator providing VIO
|
||||
|
||||
Optional properties:
|
||||
- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which
|
||||
provides configuration data (calibration, MAC, ...)
|
||||
- ti,power-gpio : GPIO connected to chip's PMEN pin if operated in
|
||||
SPI mode
|
||||
- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
for optional SPI connection related properties,
|
||||
|
||||
Examples:
|
||||
|
||||
&spi1 {
|
||||
wl1251@0 {
|
||||
compatible = "ti,wl1251";
|
||||
|
||||
reg = <0>;
|
||||
spi-max-frequency = <48000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */
|
||||
|
||||
vio-supply = <&vio>;
|
||||
ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */
|
||||
};
|
||||
};
|
||||
|
||||
&mmc3 {
|
||||
vmmc-supply = <&wlan_en>;
|
||||
|
||||
bus-width = <4>;
|
||||
non-removable;
|
||||
ti,non-removable;
|
||||
cap-power-off-card;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mmc3_pins>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
wlan: wifi@1 {
|
||||
compatible = "ti,wl1251";
|
||||
|
||||
reg = <1>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; /* GPIO_21 */
|
||||
|
||||
ti,wl1251-has-eeprom;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/wireless/ti,wl1251.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments WL1251 Wireless LAN Controller
|
||||
|
||||
maintainers:
|
||||
- Eduard Bostina <egbostina@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,wl1251
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vio-supply:
|
||||
description:
|
||||
Phandle to the regulator providing VIO. Required when connected via SPI.
|
||||
|
||||
ti,power-gpio:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO connected to chip's PMEN pin if operated in SPI mode.
|
||||
|
||||
ti,wl1251-has-eeprom:
|
||||
type: boolean
|
||||
description:
|
||||
The wl1251 has an EEPROM connected, which provides configuration
|
||||
data (calibration, MAC, ...).
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
spi-cpol: true
|
||||
spi-cpha: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
wifi@0 {
|
||||
compatible = "ti,wl1251";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <48000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <10 IRQ_TYPE_NONE>;
|
||||
vio-supply = <&vio>;
|
||||
ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
mmc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
wifi@1 {
|
||||
compatible = "ti,wl1251";
|
||||
reg = <1>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
|
||||
ti,wl1251-has-eeprom;
|
||||
};
|
||||
};
|
||||
40
MAINTAINERS
40
MAINTAINERS
|
|
@ -113,7 +113,7 @@ F: net/6lowpan/
|
|||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/
|
||||
W: https://wireless.docs.kernel.org/en/latest/
|
||||
Q: https://patchwork.kernel.org/project/linux-wireless/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
|
||||
|
|
@ -4260,13 +4260,13 @@ M: Nick Kossifidis <mickflemm@gmail.com>
|
|||
M: Luis Chamberlain <mcgrof@kernel.org>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath5k
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath5k.html
|
||||
F: drivers/net/wireless/ath/ath5k/
|
||||
|
||||
ATHEROS ATH6KL WIRELESS DRIVER
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Orphan
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath6kl
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath6kl.html
|
||||
F: drivers/net/wireless/ath/ath6kl/
|
||||
|
||||
ATI_REMOTE2 DRIVER
|
||||
|
|
@ -4535,14 +4535,14 @@ B43 WIRELESS DRIVER
|
|||
L: linux-wireless@vger.kernel.org
|
||||
L: b43-dev@lists.infradead.org
|
||||
S: Orphan
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/b43
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/b43.html
|
||||
F: drivers/net/wireless/broadcom/b43/
|
||||
|
||||
B43LEGACY WIRELESS DRIVER
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: b43-dev@lists.infradead.org
|
||||
S: Orphan
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/b43
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/b43.html
|
||||
F: drivers/net/wireless/broadcom/b43legacy/
|
||||
|
||||
BACKLIGHT CLASS/SUBSYSTEM
|
||||
|
|
@ -5919,7 +5919,7 @@ CARL9170 LINUX COMMUNITY WIRELESS DRIVER
|
|||
M: Christian Lamparter <chunkeey@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/carl9170
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/carl9170.html
|
||||
F: drivers/net/wireless/ath/carl9170/
|
||||
|
||||
CAVIUM I2C DRIVER
|
||||
|
|
@ -13560,7 +13560,7 @@ INTEL WIRELESS WIFI LINK (iwlwifi)
|
|||
M: Miri Korenblit <miriam.rachel.korenblit@intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/iwlwifi.html
|
||||
T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/
|
||||
F: drivers/net/wireless/intel/iwlwifi/
|
||||
|
||||
|
|
@ -15663,7 +15663,7 @@ MAC80211
|
|||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/
|
||||
W: https://wireless.docs.kernel.org/en/latest/
|
||||
Q: https://patchwork.kernel.org/project/linux-wireless/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
|
||||
|
|
@ -18933,7 +18933,7 @@ NETWORKING DRIVERS (WIRELESS)
|
|||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/
|
||||
W: https://wireless.docs.kernel.org/en/latest/
|
||||
Q: https://patchwork.kernel.org/project/linux-wireless/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
|
||||
|
|
@ -20606,7 +20606,7 @@ P54 WIRELESS DRIVER
|
|||
M: Christian Lamparter <chunkeey@googlemail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/p54
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/p54.html
|
||||
F: Documentation/devicetree/bindings/net/wireless/st,stlc4560.yaml
|
||||
F: drivers/net/wireless/intersil/
|
||||
|
||||
|
|
@ -22296,7 +22296,7 @@ M: Jeff Johnson <jjohnson@kernel.org>
|
|||
L: linux-wireless@vger.kernel.org
|
||||
L: ath12k@lists.infradead.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath12k
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath12k.html
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
|
||||
F: drivers/net/wireless/ath/ath12k/
|
||||
N: ath12k
|
||||
|
|
@ -22306,7 +22306,7 @@ M: Jeff Johnson <jjohnson@kernel.org>
|
|||
L: linux-wireless@vger.kernel.org
|
||||
L: ath10k@lists.infradead.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath10k.html
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
|
||||
F: drivers/net/wireless/ath/ath10k/
|
||||
N: ath10k
|
||||
|
|
@ -22316,8 +22316,8 @@ M: Jeff Johnson <jjohnson@kernel.org>
|
|||
L: linux-wireless@vger.kernel.org
|
||||
L: ath11k@lists.infradead.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath11k
|
||||
B: https://wireless.wiki.kernel.org/en/users/Drivers/ath11k/bugreport
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath11k.html
|
||||
B: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath11k/bugreport.html
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
|
||||
F: drivers/net/wireless/ath/ath11k/
|
||||
N: ath11k
|
||||
|
|
@ -22326,7 +22326,7 @@ QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
|
|||
M: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/ath9k
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/ath9k.html
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
|
||||
F: Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
|
||||
F: drivers/net/wireless/ath/ath9k/
|
||||
|
|
@ -22668,7 +22668,7 @@ M: Loic Poulain <loic.poulain@oss.qualcomm.com>
|
|||
L: wcn36xx@lists.infradead.org
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/wcn36xx
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/wcn36xx.html
|
||||
F: drivers/net/wireless/ath/wcn36xx/
|
||||
|
||||
QUANTENNA QTNFMAC WIRELESS DRIVER
|
||||
|
|
@ -23427,7 +23427,7 @@ RFKILL
|
|||
M: Johannes Berg <johannes@sipsolutions.net>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
W: https://wireless.wiki.kernel.org/
|
||||
W: https://wireless.docs.kernel.org/en/latest/
|
||||
Q: https://patchwork.kernel.org/project/linux-wireless/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
|
||||
|
|
@ -27522,8 +27522,8 @@ F: drivers/media/platform/ti/vpe/
|
|||
TI WILINK WIRELESS DRIVERS
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Orphan
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/wl1251
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/wl12xx.html
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/wl1251.html
|
||||
F: drivers/net/wireless/ti/
|
||||
|
||||
TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
|
||||
|
|
@ -29412,7 +29412,7 @@ F: drivers/hid/hid-wiimote*
|
|||
WILOCITY WIL6210 WIRELESS DRIVER
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Orphan
|
||||
W: https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
|
||||
W: https://wireless.docs.kernel.org/en/latest/en/users/drivers/wil6210.html
|
||||
F: drivers/net/wireless/ath/wil6210/
|
||||
|
||||
WINBOND CIR DRIVER
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ config ATH11K_AHB
|
|||
tristate "Atheros ath11k AHB support"
|
||||
depends on ATH11K
|
||||
depends on REMOTEPROC
|
||||
select RPMSG
|
||||
select QRTR
|
||||
select QRTR_SMD
|
||||
help
|
||||
This module adds support for AHB bus
|
||||
|
||||
|
|
|
|||
|
|
@ -391,12 +391,17 @@ static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
|
|||
ath11k_ahb_sync_ext_irqs(ab);
|
||||
}
|
||||
|
||||
static void ath11k_ahb_stop(struct ath11k_base *ab)
|
||||
static void ath11k_ahb_ce_irq_disable_sync(struct ath11k_base *ab)
|
||||
{
|
||||
if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
|
||||
ath11k_ahb_ce_irqs_disable(ab);
|
||||
ath11k_ahb_sync_ce_irqs(ab);
|
||||
ath11k_ahb_kill_tasklets(ab);
|
||||
}
|
||||
|
||||
static void ath11k_ahb_stop(struct ath11k_base *ab)
|
||||
{
|
||||
ath11k_ahb_ce_irq_disable_sync(ab);
|
||||
timer_delete_sync(&ab->rx_replenish_retry);
|
||||
ath11k_ce_cleanup_pipes(ab);
|
||||
}
|
||||
|
|
@ -804,6 +809,8 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
|
|||
.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
|
||||
.power_down = ath11k_ahb_power_down,
|
||||
.power_up = ath11k_ahb_power_up,
|
||||
.ce_irq_enable = ath11k_ahb_ce_irqs_enable,
|
||||
.ce_irq_disable = ath11k_ahb_ce_irq_disable_sync,
|
||||
};
|
||||
|
||||
static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
|
||||
|
|
@ -1296,14 +1303,16 @@ static void ath11k_ahb_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ath11k_base *ab = platform_get_drvdata(pdev);
|
||||
|
||||
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
|
||||
ath11k_ahb_remove_prepare(ab);
|
||||
|
||||
if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
|
||||
ath11k_ahb_power_down(ab, false);
|
||||
ath11k_debugfs_soc_destroy(ab);
|
||||
ath11k_qmi_deinit_service(ab);
|
||||
ath11k_core_pm_notifier_unregister(ab);
|
||||
goto qmi_fail;
|
||||
}
|
||||
|
||||
ath11k_ahb_remove_prepare(ab);
|
||||
ath11k_core_deinit(ab);
|
||||
|
||||
qmi_fail:
|
||||
|
|
@ -1343,5 +1352,6 @@ static struct platform_driver ath11k_ahb_driver = {
|
|||
|
||||
module_platform_driver(ath11k_ahb_driver);
|
||||
|
||||
MODULE_SOFTDEP("pre: qrtr_smd");
|
||||
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe)
|
|||
dma_addr_t paddr;
|
||||
int ret = 0;
|
||||
|
||||
if (!(pipe->dest_ring || pipe->status_ring))
|
||||
if (!pipe->dest_ring || !pipe->status_ring)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&ab->ce.ce_lock);
|
||||
|
|
|
|||
|
|
@ -2334,6 +2334,16 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
|
|||
|
||||
mutex_lock(&ab->core_lock);
|
||||
ath11k_thermal_unregister(ab);
|
||||
|
||||
/*
|
||||
* ath11k_core_reset() already disabled the interrupts on the reset
|
||||
* path; only the firmware crash path reaches here with them live.
|
||||
*/
|
||||
if (!ab->is_reset) {
|
||||
ath11k_hif_irq_disable(ab);
|
||||
ath11k_hif_ce_irq_disable(ab);
|
||||
}
|
||||
|
||||
ath11k_dp_pdev_free(ab);
|
||||
ath11k_cfr_deinit(ab);
|
||||
ath11k_spectral_deinit(ab);
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
|
|||
case HAL_RXDMA_DIR_BUF:
|
||||
break;
|
||||
default:
|
||||
ath11k_dp_srng_cleanup(ab, ring);
|
||||
ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -324,6 +325,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
|
|||
|
||||
ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms);
|
||||
if (ret < 0) {
|
||||
ath11k_dp_srng_cleanup(ab, ring);
|
||||
ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n",
|
||||
ret, ring_num);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -762,6 +762,9 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
|
|||
struct ath11k_base *ab = dp->ab;
|
||||
struct dp_rx_tid *rx_tid = ctx;
|
||||
struct dp_reo_cache_flush_elem *elem, *tmp;
|
||||
struct list_head flush_list;
|
||||
|
||||
INIT_LIST_HEAD(&flush_list);
|
||||
|
||||
if (status == HAL_REO_CMD_DRAIN) {
|
||||
goto free_desc;
|
||||
|
|
@ -783,23 +786,25 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
|
|||
list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
|
||||
dp->reo_cmd_cache_flush_count++;
|
||||
|
||||
/* Flush and invalidate aged REO desc from HW cache */
|
||||
/* identify aged REO desc that needs removal */
|
||||
list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list,
|
||||
list) {
|
||||
if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
|
||||
time_after(jiffies, elem->ts +
|
||||
msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) {
|
||||
list_del(&elem->list);
|
||||
list_move_tail(&elem->list, &flush_list);
|
||||
dp->reo_cmd_cache_flush_count--;
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
|
||||
ath11k_dp_reo_cache_flush(ab, &elem->data);
|
||||
kfree(elem);
|
||||
spin_lock_bh(&dp->reo_cmd_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&dp->reo_cmd_lock);
|
||||
|
||||
/* remove aged REO desc from HW */
|
||||
list_for_each_entry_safe(elem, tmp, &flush_list, list) {
|
||||
ath11k_dp_reo_cache_flush(ab, &elem->data);
|
||||
list_del(&elem->list);
|
||||
kfree(elem);
|
||||
}
|
||||
|
||||
return;
|
||||
free_desc:
|
||||
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||
|
|
@ -2500,7 +2505,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
|
|||
!(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
|
||||
rx_status->flag |= RX_FLAG_8023;
|
||||
|
||||
ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
|
||||
ieee80211_rx_napi(ar->hw, pubsta ? &pubsta->deflink : NULL, msdu, napi);
|
||||
}
|
||||
|
||||
static bool ath11k_dp_rx_check_nwifi_hdr_len_valid(struct ath11k_base *ab,
|
||||
|
|
|
|||
|
|
@ -347,35 +347,60 @@ static void ath12k_ahb_stop(struct ath12k_base *ab)
|
|||
ath12k_ce_cleanup_pipes(ab);
|
||||
}
|
||||
|
||||
static int ath12k_ahb_get_fw_load_region(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
|
||||
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
|
||||
struct device *dev = ab->dev;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
if (rproc_info->mem_region)
|
||||
return 0;
|
||||
|
||||
ret = of_reserved_mem_region_to_resource_byname(dev->of_node, "q6-region", &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rproc_info->mem_phys = res.start;
|
||||
rproc_info->mem_size = resource_size(&res);
|
||||
rproc_info->mem_region = memremap(rproc_info->mem_phys, rproc_info->mem_size,
|
||||
MEMREMAP_WC);
|
||||
if (!rproc_info->mem_region) {
|
||||
ath12k_err(ab, "unable to map memory region: %pa+%zx\n",
|
||||
&res.start, rproc_info->mem_size);
|
||||
rproc_info->mem_phys = 0;
|
||||
rproc_info->mem_size = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_ahb_put_fw_load_region(struct ath12k_ahb_rproc_info *rproc_info)
|
||||
{
|
||||
memunmap(rproc_info->mem_region);
|
||||
rproc_info->mem_region = NULL;
|
||||
rproc_info->mem_phys = 0;
|
||||
rproc_info->mem_size = 0;
|
||||
}
|
||||
|
||||
static int ath12k_ahb_power_up(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
|
||||
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
|
||||
char fw_name[ATH12K_USERPD_FW_NAME_LEN];
|
||||
char fw2_name[ATH12K_USERPD_FW_NAME_LEN];
|
||||
struct device *dev = ab->dev;
|
||||
const struct firmware *fw, *fw2;
|
||||
unsigned long time_left;
|
||||
phys_addr_t mem_phys;
|
||||
struct resource res;
|
||||
void *mem_region;
|
||||
size_t mem_size;
|
||||
u32 pasid;
|
||||
int ret;
|
||||
|
||||
ret = of_reserved_mem_region_to_resource_byname(dev->of_node, "q6-region",
|
||||
&res);
|
||||
ret = ath12k_ahb_get_fw_load_region(ab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem_phys = res.start;
|
||||
mem_size = resource_size(&res);
|
||||
mem_region = devm_memremap(dev, mem_phys, mem_size, MEMREMAP_WC);
|
||||
if (IS_ERR(mem_region)) {
|
||||
ath12k_err(ab, "unable to map memory region: %pa+%zx\n",
|
||||
&res.start, mem_size);
|
||||
return PTR_ERR(mem_region);
|
||||
}
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "%s/%s/%s%d%s", ATH12K_FW_DIR,
|
||||
ab->hw_params->fw.dir, ATH12K_AHB_FW_PREFIX, ab_ahb->userpd_id,
|
||||
ATH12K_AHB_FW_SUFFIX);
|
||||
|
|
@ -400,11 +425,13 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
|
|||
|
||||
/* Load FW image to a reserved memory location */
|
||||
if (ab_ahb->scm_auth_enabled)
|
||||
ret = qcom_mdt_load(dev, fw, fw_name, pasid, mem_region,
|
||||
mem_phys, mem_size, &mem_phys);
|
||||
ret = qcom_mdt_load(dev, fw, fw_name, pasid, rproc_info->mem_region,
|
||||
rproc_info->mem_phys, rproc_info->mem_size,
|
||||
NULL);
|
||||
else
|
||||
ret = qcom_mdt_load_no_init(dev, fw, fw_name, mem_region,
|
||||
mem_phys, mem_size, &mem_phys);
|
||||
ret = qcom_mdt_load_no_init(dev, fw, fw_name, rproc_info->mem_region,
|
||||
rproc_info->mem_phys, rproc_info->mem_size,
|
||||
NULL);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "Failed to load MDT segments: %d\n", ret);
|
||||
goto err_fw;
|
||||
|
|
@ -428,8 +455,9 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
|
|||
goto err_fw2;
|
||||
}
|
||||
|
||||
ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, mem_region, mem_phys,
|
||||
mem_size, &mem_phys);
|
||||
ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, rproc_info->mem_region,
|
||||
rproc_info->mem_phys, rproc_info->mem_size,
|
||||
NULL);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "Failed to load MDT segments: %d\n", ret);
|
||||
goto err_fw2;
|
||||
|
|
@ -877,6 +905,7 @@ static struct ath12k_ahb_rproc_info *ath12k_ahb_rproc_info_alloc(struct ath12k_b
|
|||
rproc_info->rootpd_booted_by_driver = false;
|
||||
rproc_info->userpd[ab_ahb->userpd_id - 1] = ab_ahb;
|
||||
rproc_info->num_userpd = 1;
|
||||
rproc_info->shared_fw_loaded = false;
|
||||
init_completion(&rproc_info->rootpd_ready);
|
||||
ab_ahb->rproc_info = rproc_info;
|
||||
|
||||
|
|
@ -961,6 +990,76 @@ static int ath12k_ahb_boot_root_pd(struct ath12k_base *ab)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_ahb_load_auth_shared_fw(struct ath12k_base *ab,
|
||||
struct ath12k_ahb_rproc_info *rproc_info,
|
||||
const char *fw_name, u32 pasid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const struct firmware *fw __free(firmware) = NULL;
|
||||
ret = request_firmware(&fw, fw_name, ab->dev);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to request shared firmware %s: %d\n",
|
||||
fw_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!fw->size) {
|
||||
ath12k_err(ab, "Invalid firmware size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_AHB, "loading firmware %s, size %zd\n", fw_name,
|
||||
fw->size);
|
||||
|
||||
ret = qcom_mdt_load(ab->dev, fw, fw_name, pasid, rproc_info->mem_region,
|
||||
rproc_info->mem_phys, rproc_info->mem_size, NULL);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to load RO firmware %s: %d\n", fw_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcom_pas_auth_and_reset(pasid);
|
||||
if (ret)
|
||||
ath12k_err(ab, "failed to authenticate and boot shared firmware: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath12k_ahb_load_shared_firmware(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
|
||||
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
|
||||
char fw_name[ATH12K_USERPD_FW_NAME_LEN];
|
||||
u32 pasid;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ath12k_rproc_info_lock);
|
||||
|
||||
if (!ab_ahb->supports_multipd)
|
||||
return 0;
|
||||
|
||||
ret = ath12k_ahb_get_fw_load_region(ab);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "%s/%s/%s%d%s", ATH12K_FW_DIR,
|
||||
ab->hw_params->fw.dir, ATH12K_AHB_FW_PREFIX, ATH12K_AHB_RO_ID,
|
||||
ATH12K_AHB_FW_SUFFIX);
|
||||
|
||||
pasid = u32_encode_bits(ATH12K_AHB_RO_ID, ATH12K_USERPD_ID_MASK) |
|
||||
ATH12K_AHB_UPD_SWID;
|
||||
|
||||
ret = ath12k_ahb_load_auth_shared_fw(ab, rproc_info, fw_name, pasid);
|
||||
if (ret) {
|
||||
ath12k_ahb_put_fw_load_region(rproc_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rproc_info->shared_fw_loaded = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_ahb_configure_rproc(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -989,6 +1088,15 @@ static int ath12k_ahb_configure_rproc(struct ath12k_base *ab)
|
|||
g_rproc_info->rootpd_booted_by_driver = true;
|
||||
}
|
||||
|
||||
if (!g_rproc_info->shared_fw_loaded) {
|
||||
ret = ath12k_ahb_load_shared_firmware(ab);
|
||||
if (ret) {
|
||||
if (g_rproc_info->rootpd_booted_by_driver)
|
||||
rproc_shutdown(g_rproc_info->tgt_rproc);
|
||||
goto err_unreg_notifier;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ath12k_rproc_info_lock);
|
||||
return 0;
|
||||
|
||||
|
|
@ -1012,6 +1120,8 @@ static void ath12k_ahb_deconfigure_rproc(struct ath12k_base *ab)
|
|||
{
|
||||
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
|
||||
struct ath12k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
|
||||
u32 pasid;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ath12k_rproc_info_lock);
|
||||
|
||||
|
|
@ -1023,6 +1133,20 @@ static void ath12k_ahb_deconfigure_rproc(struct ath12k_base *ab)
|
|||
if (!g_rproc_info->num_userpd) {
|
||||
ath12k_ahb_unregister_rproc_notifier();
|
||||
|
||||
if (g_rproc_info->shared_fw_loaded) {
|
||||
pasid = u32_encode_bits(ATH12K_AHB_RO_ID, ATH12K_USERPD_ID_MASK) |
|
||||
ATH12K_AHB_UPD_SWID;
|
||||
ret = qcom_pas_shutdown(pasid);
|
||||
if (ret)
|
||||
ath12k_err(ab, "pas shutdown failed for shared firmware: %d\n",
|
||||
ret);
|
||||
|
||||
g_rproc_info->shared_fw_loaded = false;
|
||||
}
|
||||
|
||||
if (g_rproc_info->mem_region)
|
||||
ath12k_ahb_put_fw_load_region(g_rproc_info);
|
||||
|
||||
if (g_rproc_info->rootpd_booted_by_driver &&
|
||||
g_rproc_info->tgt_rproc->state == RPROC_RUNNING)
|
||||
rproc_shutdown(g_rproc_info->tgt_rproc);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#define ATH12K_USERPD_ID_MASK GENMASK(10, 8)
|
||||
#define ATH12K_USERPD_FW_NAME_LEN 35
|
||||
|
||||
/* Shared read-only firmware ID, mandated by MultiPD firmware architecture */
|
||||
#define ATH12K_AHB_RO_ID 4
|
||||
|
||||
enum ath12k_ahb_userpd_id {
|
||||
ATH12K_AHB_USERPD_ID_0 = 1,
|
||||
ATH12K_AHB_USERPD_ID_1,
|
||||
|
|
@ -46,6 +49,7 @@ struct ath12k_ahb_desc {
|
|||
enum ath12k_hw_rev hw_rev;
|
||||
bool auth_enabled;
|
||||
const struct ath12k_hif_ops *ops;
|
||||
bool supports_multipd;
|
||||
};
|
||||
|
||||
enum ath12k_ahb_smp2p_msg_id {
|
||||
|
|
@ -77,6 +81,10 @@ struct ath12k_ahb_rproc_info {
|
|||
u8 num_userpd;
|
||||
bool rootpd_booted_by_driver;
|
||||
struct ath12k_ahb *userpd[ATH12K_MAX_DEVICES];
|
||||
bool shared_fw_loaded;
|
||||
phys_addr_t mem_phys;
|
||||
size_t mem_size;
|
||||
void *mem_region;
|
||||
};
|
||||
|
||||
struct ath12k_ahb {
|
||||
|
|
@ -95,6 +103,7 @@ struct ath12k_ahb {
|
|||
const struct ath12k_ahb_device_family_ops *device_family_ops;
|
||||
bool scm_auth_enabled;
|
||||
struct ath12k_ahb_rproc_info *rproc_info;
|
||||
bool supports_multipd;
|
||||
};
|
||||
|
||||
struct ath12k_ahb_driver {
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ static void ath12k_ce_srng_msi_ring_params_setup(struct ath12k_base *ab, u32 ce_
|
|||
ath12k_hif_get_ce_msi_idx(ab, ce_id, &msi_data_idx);
|
||||
|
||||
ring_params->msi_addr = addr_lo;
|
||||
ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
|
||||
ring_params->msi_addr |= (dma_addr_t)(((u64)addr_hi) << 32);
|
||||
ring_params->msi_data = (msi_data_idx % msi_data_count) + msi_data_start;
|
||||
ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -792,6 +792,29 @@ int ath12k_core_check_smbios(struct ath12k_base *ab)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_core_check_dt(struct ath12k_base *ab)
|
||||
{
|
||||
size_t max_len = sizeof(ab->qmi.target.bdf_ext);
|
||||
const char *variant = NULL;
|
||||
struct device_node *node;
|
||||
|
||||
node = ab->dev->of_node;
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
|
||||
of_property_read_string(node, "qcom,calibration-variant",
|
||||
&variant);
|
||||
if (!variant)
|
||||
return -ENODATA;
|
||||
|
||||
if (strscpy(ab->qmi.target.bdf_ext, variant, max_len) < 0)
|
||||
ath12k_dbg(ab, ATH12K_DBG_BOOT,
|
||||
"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
|
||||
variant);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_core_soc_create(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ static void ath12k_dp_srng_msi_setup(struct ath12k_base *ab,
|
|||
ath12k_hif_get_msi_address(ab, &addr_lo, &addr_hi);
|
||||
|
||||
ring_params->msi_addr = addr_lo;
|
||||
ring_params->msi_addr |= (dma_addr_t)(((uint64_t)addr_hi) << 32);
|
||||
ring_params->msi_addr |= (dma_addr_t)(((u64)addr_hi) << 32);
|
||||
ring_params->msi_data = (msi_group_number % msi_data_count)
|
||||
+ msi_data_start;
|
||||
ring_params->flags |= HAL_SRNG_FLAGS_MSI_INTR;
|
||||
|
|
|
|||
|
|
@ -503,8 +503,6 @@ void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
|
|||
struct ieee80211_rx_status *rx_status;
|
||||
struct ieee80211_radiotap_he *he = NULL;
|
||||
|
||||
status->link_valid = 0;
|
||||
|
||||
if ((status->encoding == RX_ENC_HE) && !(status->flag & RX_FLAG_RADIOTAP_HE) &&
|
||||
!(status->flag & RX_FLAG_SKIP_MONITOR)) {
|
||||
he = skb_push(msdu, sizeof(known));
|
||||
|
|
|
|||
|
|
@ -1375,6 +1375,7 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
struct ath12k_dp *dp = dp_pdev->dp;
|
||||
struct ieee80211_rx_status *rx_status;
|
||||
struct ieee80211_sta *pubsta;
|
||||
struct ieee80211_link_sta *link_pubsta = NULL;
|
||||
struct ath12k_dp_peer *peer;
|
||||
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
|
||||
struct ieee80211_rx_status *status = rx_info->rx_status;
|
||||
|
|
@ -1384,9 +1385,19 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
|
||||
pubsta = peer ? peer->sta : NULL;
|
||||
|
||||
status->link_valid = 0;
|
||||
if (pubsta && pubsta->valid_links)
|
||||
ath12k_hw_set_rx_link_id(dp->hw_params, peer, rxcb, status);
|
||||
if (pubsta) {
|
||||
if (pubsta->valid_links) {
|
||||
int link_id =
|
||||
ath12k_hw_get_rx_link_id(dp->hw_params, peer,
|
||||
rxcb, status);
|
||||
|
||||
if (link_id >= 0)
|
||||
link_pubsta =
|
||||
rcu_dereference(pubsta->link[link_id]);
|
||||
} else {
|
||||
link_pubsta = &pubsta->deflink;
|
||||
}
|
||||
}
|
||||
|
||||
ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
|
||||
"rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
|
||||
|
|
@ -1422,7 +1433,8 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
|
||||
/* TODO: trace rx packet */
|
||||
|
||||
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), pubsta, msdu, napi);
|
||||
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), link_pubsta, msdu,
|
||||
napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_dp_rx_deliver_msdu);
|
||||
|
||||
|
|
|
|||
|
|
@ -249,9 +249,9 @@ struct ath12k_hw_ops {
|
|||
bool (*dp_srng_is_tx_comp_ring)(int ring_num);
|
||||
bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
|
||||
struct ieee80211_mgmt *mgmt);
|
||||
void (*set_rx_link_id)(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
int (*get_rx_link_id)(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
};
|
||||
|
||||
static inline
|
||||
|
|
@ -282,13 +282,15 @@ static inline int ath12k_hw_mac_id_to_srng_id(const struct ath12k_hw_params *hw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath12k_hw_set_rx_link_id(const struct ath12k_hw_params *hw,
|
||||
struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
static inline int ath12k_hw_get_rx_link_id(const struct ath12k_hw_params *hw,
|
||||
struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
if (hw->hw_ops->set_rx_link_id)
|
||||
hw->hw_ops->set_rx_link_id(dp_peer, rxcb, status);
|
||||
if (hw->hw_ops->get_rx_link_id)
|
||||
return hw->hw_ops->get_rx_link_id(dp_peer, rxcb, status);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ath12k_fw_ie {
|
||||
|
|
|
|||
|
|
@ -1506,6 +1506,13 @@ static int ath12k_mac_monitor_start(struct ath12k *ar)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* A previous monitor session may have stopped mid-PPDU, leaving
|
||||
* ppdu_continuation set. Clear it so the first status buffer of
|
||||
* this session is not merged with stale state from before.
|
||||
*/
|
||||
ar->dp.mon_data.mon_ppdu_info.ppdu_continuation = false;
|
||||
|
||||
ar->monitor_started = true;
|
||||
ar->num_started_vdevs++;
|
||||
|
||||
|
|
@ -3517,7 +3524,7 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
|
|||
IEEE80211_EHT_MCS_NSS_RX));
|
||||
}
|
||||
|
||||
max_nss = min(max_nss, (uint8_t)eht_nss);
|
||||
max_nss = min(max_nss, (u8)eht_nss);
|
||||
|
||||
arg->peer_nss = min(link_sta->rx_nss, max_nss);
|
||||
|
||||
|
|
@ -14294,6 +14301,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
|
|||
sizeof(ath12k_6ghz_channels), GFP_KERNEL);
|
||||
if (!channels) {
|
||||
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
|
||||
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -14344,7 +14352,9 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
|
|||
GFP_KERNEL);
|
||||
if (!channels) {
|
||||
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
|
||||
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
|
||||
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
|
||||
ar->mac.sbands[NL80211_BAND_6GHZ].channels = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -14384,7 +14394,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
|
|||
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
|
||||
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
|
||||
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
|
||||
ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
|
||||
ar->mac.sbands[NL80211_BAND_6GHZ].channels = NULL;
|
||||
kfree(channels);
|
||||
band->channels = NULL;
|
||||
return ret;
|
||||
|
|
@ -15043,28 +15053,49 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah)
|
|||
wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
|
||||
|
||||
for_each_ar(ah, ar, i) {
|
||||
struct ath12k_base *this_ab = ar->ab;
|
||||
|
||||
/* Apply the regd received during initialization */
|
||||
ret = ath12k_regd_update(ar, true);
|
||||
if (ret) {
|
||||
ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret);
|
||||
ath12k_err(this_ab, "ath12k regd update failed: %d\n", ret);
|
||||
goto err_unregister_hw;
|
||||
}
|
||||
|
||||
if (ar->ab->hw_params->current_cc_support && ab->new_alpha2[0]) {
|
||||
if (this_ab->hw_params->current_cc_support) {
|
||||
struct wmi_set_current_country_arg current_cc = {};
|
||||
struct ieee80211_regdomain *default_regd;
|
||||
bool same_cc = false;
|
||||
|
||||
memcpy(¤t_cc.alpha2, ab->new_alpha2, 2);
|
||||
memcpy(&ar->alpha2, ab->new_alpha2, 2);
|
||||
spin_lock_bh(&this_ab->base_lock);
|
||||
memcpy(¤t_cc.alpha2, this_ab->new_alpha2, 2);
|
||||
spin_unlock_bh(&this_ab->base_lock);
|
||||
|
||||
if (!current_cc.alpha2[0])
|
||||
goto fw_stats_init;
|
||||
|
||||
memcpy(&ar->alpha2, current_cc.alpha2, 2);
|
||||
|
||||
spin_lock_bh(&this_ab->base_lock);
|
||||
default_regd = this_ab->default_regd[ar->pdev_idx];
|
||||
if (default_regd)
|
||||
same_cc = !memcmp(default_regd->alpha2,
|
||||
current_cc.alpha2, 2);
|
||||
spin_unlock_bh(&this_ab->base_lock);
|
||||
|
||||
if (same_cc)
|
||||
goto fw_stats_init;
|
||||
|
||||
reinit_completion(&ar->regd_update_completed);
|
||||
|
||||
ret = ath12k_wmi_send_set_current_country_cmd(ar, ¤t_cc);
|
||||
if (ret)
|
||||
ath12k_warn(ar->ab,
|
||||
ath12k_warn(this_ab,
|
||||
"failed set cc code for mac register: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
fw_stats_init:
|
||||
ath12k_fw_stats_init(ar);
|
||||
ath12k_debugfs_register(ar);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,11 +313,24 @@ static void ath12k_pci_sw_reset(struct ath12k_base *ab, bool power_on)
|
|||
ath12k_mhi_set_mhictrl_reset(ab);
|
||||
}
|
||||
|
||||
static void ath12k_pci_free_ext_irq(struct ath12k_base *ab)
|
||||
static void ath12k_pci_free_ce_irq(struct ath12k_base *ab, int num_ce)
|
||||
{
|
||||
int i, irq_idx;
|
||||
|
||||
for (i = 0; i < num_ce; i++) {
|
||||
if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
||||
continue;
|
||||
|
||||
irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;
|
||||
free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ath12k_pci_free_ext_irq(struct ath12k_base *ab, int num_ext_irq_grp)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
|
||||
for (i = 0; i < num_ext_irq_grp; i++) {
|
||||
struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
|
||||
|
||||
for (j = 0; j < irq_grp->num_irq; j++)
|
||||
|
|
@ -330,16 +343,8 @@ static void ath12k_pci_free_ext_irq(struct ath12k_base *ab)
|
|||
|
||||
static void ath12k_pci_free_irq(struct ath12k_base *ab)
|
||||
{
|
||||
int i, irq_idx;
|
||||
|
||||
for (i = 0; i < ab->hw_params->ce_count; i++) {
|
||||
if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
|
||||
continue;
|
||||
irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;
|
||||
free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
|
||||
}
|
||||
|
||||
ath12k_pci_free_ext_irq(ab);
|
||||
ath12k_pci_free_ce_irq(ab, ab->hw_params->ce_count);
|
||||
ath12k_pci_free_ext_irq(ab, ATH12K_EXT_IRQ_GRP_NUM_MAX);
|
||||
}
|
||||
|
||||
static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id)
|
||||
|
|
@ -595,8 +600,6 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
|
||||
irq = ath12k_pci_get_msi_irq(ab->dev, vector);
|
||||
|
||||
ab->irq_num[irq_idx] = irq;
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_PCI,
|
||||
"irq:%d group:%d\n", irq, i);
|
||||
|
||||
|
|
@ -607,22 +610,24 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
|
|||
if (ret) {
|
||||
ath12k_err(ab, "failed request irq %d: %d\n",
|
||||
vector, ret);
|
||||
goto fail_request;
|
||||
|
||||
for (n = 0; n < j; n++)
|
||||
free_irq(ab->irq_num[irq_grp->irqs[n]], irq_grp);
|
||||
|
||||
netif_napi_del(&ab->ext_irq_grp[i].napi);
|
||||
free_netdev(ab->ext_irq_grp[i].napi_ndev);
|
||||
goto fail_allocate;
|
||||
}
|
||||
|
||||
ab->irq_num[irq_idx] = irq;
|
||||
}
|
||||
ath12k_pci_ext_grp_disable(irq_grp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_request:
|
||||
/* i ->napi_ndev was properly allocated. Free it also */
|
||||
i += 1;
|
||||
fail_allocate:
|
||||
for (n = 0; n < i; n++) {
|
||||
irq_grp = &ab->ext_irq_grp[n];
|
||||
free_netdev(irq_grp->napi_ndev);
|
||||
}
|
||||
ath12k_pci_free_ext_irq(ab, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -671,6 +676,8 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab)
|
|||
if (ret) {
|
||||
ath12k_err(ab, "failed to request irq %d: %d\n",
|
||||
irq_idx, ret);
|
||||
|
||||
ath12k_pci_free_ce_irq(ab, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -681,8 +688,10 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab)
|
|||
}
|
||||
|
||||
ret = ath12k_pci_ext_irq_config(ab);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ath12k_pci_free_ce_irq(ab, ab->hw_params->ce_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2972,6 +2972,10 @@ int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
|
|||
if (r)
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "SMBIOS bdf variant name not set.\n");
|
||||
|
||||
r = ath12k_core_check_dt(ab);
|
||||
if (r)
|
||||
ath12k_dbg(ab, ATH12K_DBG_QMI, "DT bdf variant name not set.\n");
|
||||
|
||||
r = ath12k_acpi_start(ab);
|
||||
if (r)
|
||||
/* ACPI is optional so continue in case of an error */
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@ static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = {
|
|||
.hw_rev = ATH12K_HW_IPQ5332_HW10,
|
||||
.auth_enabled = true,
|
||||
.ops = &ath12k_ahb_hif_ops,
|
||||
.supports_multipd = true,
|
||||
},
|
||||
[ATH12K_HW_IPQ5424_HW10] = {
|
||||
.hw_rev = ATH12K_HW_IPQ5424_HW10,
|
||||
.auth_enabled = false,
|
||||
.ops = &ath12k_ahb_hif_ops,
|
||||
.supports_multipd = false,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3211,18 +3211,23 @@ __ath12k_wifi7_dp_mon_process_ring(struct ath12k *ar, int mac_id,
|
|||
goto exit;
|
||||
|
||||
while ((skb = __skb_dequeue(&skb_list))) {
|
||||
memset(ppdu_info, 0, sizeof(*ppdu_info));
|
||||
ppdu_info->peer_id = HAL_INVALID_PEERID;
|
||||
if (!ppdu_info->ppdu_continuation)
|
||||
ath12k_wifi7_dp_mon_rx_memset_ppdu_info(ppdu_info);
|
||||
|
||||
hal_status = ath12k_wifi7_dp_mon_parse_rx_dest(&ar->dp, pmon, skb);
|
||||
|
||||
if (ar->monitor_started &&
|
||||
pmon->mon_ppdu_status == DP_PPDU_STATUS_START &&
|
||||
hal_status == HAL_TLV_STATUS_PPDU_DONE) {
|
||||
rx_mon_stats->status_ppdu_done++;
|
||||
pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
|
||||
ath12k_wifi7_dp_rx_mon_dest_process(ar, mac_id, *budget, napi);
|
||||
pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
|
||||
if (hal_status == HAL_TLV_STATUS_PPDU_DONE) {
|
||||
ppdu_info->ppdu_continuation = false;
|
||||
if (ar->monitor_started &&
|
||||
pmon->mon_ppdu_status == DP_PPDU_STATUS_START) {
|
||||
rx_mon_stats->status_ppdu_done++;
|
||||
pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
|
||||
ath12k_wifi7_dp_rx_mon_dest_process(ar, mac_id,
|
||||
*budget, napi);
|
||||
pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
|
||||
}
|
||||
} else {
|
||||
ppdu_info->ppdu_continuation = true;
|
||||
}
|
||||
|
||||
dev_kfree_skb_any(skb);
|
||||
|
|
|
|||
|
|
@ -2317,17 +2317,16 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
|
|||
return tlv_tag == HAL_RX_MPDU_START;
|
||||
}
|
||||
|
||||
void
|
||||
ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
int
|
||||
ath12k_wifi7_dp_rx_get_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
status->link_valid = 1;
|
||||
status->link_id = dp_peer->hw_links[rxcb->hw_link_id];
|
||||
return dp_peer->hw_links[rxcb->hw_link_id];
|
||||
}
|
||||
|
||||
void
|
||||
ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
int
|
||||
ath12k_wifi7_dp_rx_get_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status)
|
||||
{
|
||||
|
|
@ -2341,10 +2340,9 @@ ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
|||
links_map = READ_ONCE(dp_peer->link_peers_map);
|
||||
for_each_set_bit(i, &links_map, ATH12K_NUM_MAX_LINKS) {
|
||||
link_peer = rcu_dereference(dp_peer->link_peers[i]);
|
||||
if (link_peer && link_peer->peer_id == rxcb->peer_id) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = link_peer->link_id;
|
||||
return;
|
||||
}
|
||||
if (link_peer && link_peer->peer_id == rxcb->peer_id)
|
||||
return link_peer->link_id;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
|
|||
struct hal_rx_desc *rx_desc);
|
||||
int ath12k_wifi7_dp_rx_tid_delete_handler(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid);
|
||||
void ath12k_wifi7_dp_rx_set_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
void ath12k_wifi7_dp_rx_set_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
int ath12k_wifi7_dp_rx_get_link_id_qcn9274(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
int ath12k_wifi7_dp_rx_get_link_id_wcn7850(struct ath12k_dp_peer *dp_peer,
|
||||
struct ath12k_skb_rxcb *rxcb,
|
||||
struct ieee80211_rx_status *status);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ ath12k_wifi7_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
|
|||
{
|
||||
tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
|
||||
HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
|
||||
tcl_ext_cmd->info1 = le32_encode_bits(0x0,
|
||||
tcl_ext_cmd->info1 = le32_encode_bits((u64)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_PTR_HI) |
|
||||
le32_encode_bits(ti->data_len,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
|
||||
|
|
@ -313,10 +313,15 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
|
|||
goto map;
|
||||
}
|
||||
|
||||
/* hdr is pointing to a wrong place after alignment,
|
||||
* so refresh it for later use.
|
||||
/*
|
||||
* The payload may have been shifted or even the entire buffer may have
|
||||
* been reallocated for alignment. In that case, hdr, eth and skb_cb
|
||||
* are stale pointers. Refresh them now for later dereference.
|
||||
*/
|
||||
hdr = (void *)skb->data;
|
||||
if (eth)
|
||||
eth = (struct ethhdr *)skb->data;
|
||||
skb_cb = ATH12K_SKB_CB(skb);
|
||||
}
|
||||
map:
|
||||
ti.paddr = dma_map_single(dp->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
||||
|
|
@ -449,15 +454,17 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
|
|||
return 0;
|
||||
|
||||
fail_unmap_dma_ext:
|
||||
if (skb_cb->paddr_ext_desc)
|
||||
if (skb_cb->paddr_ext_desc) {
|
||||
dma_unmap_single(dp->dev, skb_cb->paddr_ext_desc,
|
||||
skb_ext_desc->len,
|
||||
DMA_TO_DEVICE);
|
||||
skb_cb->paddr_ext_desc = 0;
|
||||
}
|
||||
fail_free_ext_skb:
|
||||
kfree_skb(skb_ext_desc);
|
||||
|
||||
fail_unmap_dma:
|
||||
dma_unmap_single(dp->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
|
||||
dma_unmap_single(dp->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
|
||||
|
||||
fail_remove_tx_buf:
|
||||
ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
|
|||
tcl_cmd->buf_addr_info.info0 =
|
||||
le32_encode_bits(ti->paddr, BUFFER_ADDR_INFO0_ADDR);
|
||||
tcl_cmd->buf_addr_info.info1 =
|
||||
le32_encode_bits(((uint64_t)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT),
|
||||
le32_encode_bits(((u64)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT),
|
||||
BUFFER_ADDR_INFO1_ADDR);
|
||||
tcl_cmd->buf_addr_info.info1 |=
|
||||
le32_encode_bits((ti->rbm_id), BUFFER_ADDR_INFO1_RET_BUF_MGR) |
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ static const struct ath12k_hw_ops qcn9274_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_qcn9274,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_qcn9274,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_qcn9274,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_qcn9274,
|
||||
.get_rx_link_id = ath12k_wifi7_dp_rx_get_link_id_qcn9274,
|
||||
};
|
||||
|
||||
static const struct ath12k_hw_ops wcn7850_ops = {
|
||||
|
|
@ -169,7 +169,7 @@ static const struct ath12k_hw_ops wcn7850_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
|
||||
.get_rx_link_id = ath12k_wifi7_dp_rx_get_link_id_wcn7850,
|
||||
};
|
||||
|
||||
static const struct ath12k_hw_ops qcc2072_ops = {
|
||||
|
|
@ -180,7 +180,7 @@ static const struct ath12k_hw_ops qcc2072_ops = {
|
|||
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
|
||||
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
|
||||
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
|
||||
.set_rx_link_id = ath12k_wifi7_dp_rx_set_link_id_wcn7850,
|
||||
.get_rx_link_id = ath12k_wifi7_dp_rx_get_link_id_wcn7850,
|
||||
};
|
||||
|
||||
#define ATH12K_TX_RING_MASK_0 0x1
|
||||
|
|
@ -664,7 +664,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
|
|||
|
||||
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT),
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_AP_VLAN),
|
||||
.supports_monitor = true,
|
||||
.supports_cong_ctrl_max_msdus = true,
|
||||
|
||||
|
|
|
|||
|
|
@ -6975,6 +6975,14 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
|
|||
goto mem_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the valid pdev_idx before validating so that, even when the
|
||||
* event is dropped or falls back, the completion the caller in
|
||||
* ath12k_mac_hw_register() may be waiting on is still signalled at
|
||||
* the end and it does not time out.
|
||||
*/
|
||||
pdev_idx = reg_info->phy_id;
|
||||
|
||||
ret = ath12k_reg_validate_reg_info(ab, reg_info);
|
||||
if (ret == ATH12K_REG_STATUS_FALLBACK) {
|
||||
ath12k_warn(ab, "failed to validate reg info %d\n", ret);
|
||||
|
|
@ -6991,7 +6999,6 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
|
|||
}
|
||||
|
||||
/* free old reg_info if it exist */
|
||||
pdev_idx = reg_info->phy_id;
|
||||
if (ab->reg_info[pdev_idx]) {
|
||||
ath12k_reg_reset_reg_info(ab->reg_info[pdev_idx]);
|
||||
kfree(ab->reg_info[pdev_idx]);
|
||||
|
|
@ -7030,7 +7037,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
|
|||
|
||||
out:
|
||||
/* In some error cases, even a valid pdev_idx might not be available */
|
||||
if (pdev_idx != 255)
|
||||
if (pdev_idx < ab->num_radios)
|
||||
ar = ab->pdevs[pdev_idx].ar;
|
||||
|
||||
/* During the boot-time update, 'ar' might not be allocated,
|
||||
|
|
@ -7271,7 +7278,6 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
struct ath12k_wmi_mgmt_rx_arg rx_ev = {};
|
||||
struct ath12k *ar;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_sta *pubsta = NULL;
|
||||
struct ath12k_dp_link_peer *peer;
|
||||
struct ieee80211_hdr *hdr;
|
||||
bool is_4addr_null_pkt;
|
||||
|
|
@ -7373,11 +7379,6 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
dev_kfree_skb(skb);
|
||||
goto exit;
|
||||
}
|
||||
pubsta = peer->sta;
|
||||
if (pubsta && pubsta->valid_links) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = peer->link_id;
|
||||
}
|
||||
spin_unlock_bh(&dp->dp_lock);
|
||||
goto send_rx;
|
||||
}
|
||||
|
|
@ -9992,11 +9993,6 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab,
|
|||
u32 event_count;
|
||||
int ret;
|
||||
|
||||
if (!skb->data) {
|
||||
ath12k_warn(ab, "No data present in tpc stats event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (skb->len < (sizeof(*fixed_param) + TLV_HDR_SIZE)) {
|
||||
ath12k_warn(ab, "TPC stats event size invalid\n");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ static bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf,
|
|||
if (!sta)
|
||||
return false;
|
||||
|
||||
ratetbl = rcu_dereference(sta->rates);
|
||||
ratetbl = rcu_dereference_bh(sta->rates);
|
||||
if (!ratetbl)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -610,25 +610,25 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
int nr_slots;
|
||||
dma_addr_t dma_test;
|
||||
|
||||
ring = kzalloc_obj(*ring);
|
||||
if (for_tx)
|
||||
nr_slots = B43legacy_TXRING_SLOTS;
|
||||
else
|
||||
nr_slots = B43legacy_RXRING_SLOTS;
|
||||
|
||||
ring = kzalloc_flex(*ring, meta, nr_slots);
|
||||
if (!ring)
|
||||
goto out;
|
||||
|
||||
ring->nr_slots = nr_slots;
|
||||
ring->type = type;
|
||||
ring->dev = dev;
|
||||
|
||||
nr_slots = B43legacy_RXRING_SLOTS;
|
||||
if (for_tx)
|
||||
nr_slots = B43legacy_TXRING_SLOTS;
|
||||
|
||||
ring->meta = kzalloc_objs(struct b43legacy_dmadesc_meta, nr_slots);
|
||||
if (!ring->meta)
|
||||
goto err_kfree_ring;
|
||||
if (for_tx) {
|
||||
ring->txhdr_cache = kcalloc(nr_slots,
|
||||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
GFP_KERNEL);
|
||||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
goto err_kfree_ring;
|
||||
|
||||
/* test for ability to dma to txhdr_cache */
|
||||
dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
|
||||
|
|
@ -643,7 +643,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
sizeof(struct b43legacy_txhdr_fw3),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!ring->txhdr_cache)
|
||||
goto err_kfree_meta;
|
||||
goto err_kfree_txhdr_cache;
|
||||
|
||||
dma_test = dma_map_single(dev->dev->dma_dev,
|
||||
ring->txhdr_cache,
|
||||
|
|
@ -660,7 +660,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
ring->nr_slots = nr_slots;
|
||||
ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
|
||||
ring->index = controller_index;
|
||||
if (for_tx) {
|
||||
|
|
@ -694,8 +693,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
|
|||
free_ringmemory(ring);
|
||||
err_kfree_txhdr_cache:
|
||||
kfree(ring->txhdr_cache);
|
||||
err_kfree_meta:
|
||||
kfree(ring->meta);
|
||||
err_kfree_ring:
|
||||
kfree(ring);
|
||||
ring = NULL;
|
||||
|
|
@ -720,7 +717,6 @@ static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
|
|||
free_ringmemory(ring);
|
||||
|
||||
kfree(ring->txhdr_cache);
|
||||
kfree(ring->meta);
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,8 +122,6 @@ enum b43legacy_dmatype {
|
|||
struct b43legacy_dmaring {
|
||||
/* Kernel virtual base address of the ring memory. */
|
||||
void *descbase;
|
||||
/* Meta data about all descriptors. */
|
||||
struct b43legacy_dmadesc_meta *meta;
|
||||
/* Cache of TX headers for each slot.
|
||||
* This is to avoid an allocation on each TX.
|
||||
* This is NULL for an RX ring.
|
||||
|
|
@ -161,6 +159,8 @@ struct b43legacy_dmaring {
|
|||
/* Last time we injected a ring overflow. */
|
||||
unsigned long last_injected_overflow;
|
||||
#endif /* CONFIG_B43LEGACY_DEBUG*/
|
||||
/* Meta data about all descriptors. */
|
||||
struct b43legacy_dmadesc_meta meta[] __counted_by(nr_slots);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2112,9 +2112,11 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
struct brcmf_pub *drvr = ifp->drvr;
|
||||
s32 val;
|
||||
s32 err;
|
||||
s32 okc_enable;
|
||||
const struct brcmf_tlv *rsn_ie;
|
||||
const u8 *ie;
|
||||
u32 ie_len;
|
||||
bool fwsup_roam;
|
||||
u32 offset;
|
||||
u16 rsn_cap;
|
||||
u32 mfp;
|
||||
|
|
@ -2122,6 +2124,9 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
|
||||
profile->is_ft = false;
|
||||
profile->is_okc = false;
|
||||
fwsup_roam = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FBT) ||
|
||||
brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OKC);
|
||||
|
||||
if (!sme->crypto.n_akm_suites)
|
||||
return 0;
|
||||
|
|
@ -2138,6 +2143,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
val = WPA_AUTH_UNSPECIFIED;
|
||||
if (sme->want_1x)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
|
||||
else if (fwsup_roam)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_PSK:
|
||||
val = WPA_AUTH_PSK;
|
||||
|
|
@ -2153,11 +2160,15 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
val = WPA2_AUTH_UNSPECIFIED;
|
||||
if (sme->want_1x)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
|
||||
else if (fwsup_roam)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_8021X_SHA256:
|
||||
val = WPA2_AUTH_1X_SHA256;
|
||||
if (sme->want_1x)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
|
||||
else if (fwsup_roam)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_PSK_SHA256:
|
||||
val = WPA2_AUTH_PSK_SHA256;
|
||||
|
|
@ -2170,10 +2181,16 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
profile->is_ft = true;
|
||||
if (sme->want_1x)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
|
||||
else if (fwsup_roam)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_FT_PSK:
|
||||
val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
|
||||
profile->is_ft = true;
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP))
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
|
||||
else if (fwsup_roam)
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_ROAM;
|
||||
break;
|
||||
case WLAN_AKM_SUITE_WFA_DPP:
|
||||
val = WFA_AUTH_DPP;
|
||||
|
|
@ -2204,8 +2221,22 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
|
|||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
|
||||
brcmf_dbg(INFO, "using 1X offload\n");
|
||||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X ||
|
||||
profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM) {
|
||||
err = brcmf_fil_bsscfg_int_get(ifp, "okc_enable",
|
||||
&okc_enable);
|
||||
if (err) {
|
||||
bphy_err(drvr, "get okc_enable failed (%d)\n", err);
|
||||
} else {
|
||||
brcmf_dbg(INFO, "okc_enable (%d)\n", okc_enable);
|
||||
profile->is_okc = okc_enable;
|
||||
}
|
||||
}
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE)
|
||||
brcmf_dbg(INFO, "using SAE offload\n");
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM)
|
||||
brcmf_dbg(INFO, "using roaming offload\n");
|
||||
|
||||
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
|
||||
goto skip_mfp_config;
|
||||
|
|
@ -2494,13 +2525,14 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
|
|||
|
||||
if (sme->crypto.psk && !is_sae_akm &&
|
||||
profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) {
|
||||
if (WARN_ON(profile->use_fwsup !=
|
||||
BRCMF_PROFILE_FWSUP_NONE)) {
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_NONE) {
|
||||
brcmf_dbg(INFO, "using PSK offload\n");
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
|
||||
} else if (WARN_ON(profile->use_fwsup !=
|
||||
BRCMF_PROFILE_FWSUP_PSK)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
brcmf_dbg(INFO, "using PSK offload\n");
|
||||
profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
|
||||
}
|
||||
if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
|
||||
/* enable firmware supplicant for this interface */
|
||||
|
|
@ -5953,17 +5985,29 @@ static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
|
|||
const struct cfg80211_pmk_conf *conf)
|
||||
{
|
||||
struct brcmf_if *ifp;
|
||||
struct brcmf_pub *drvr;
|
||||
int ret;
|
||||
|
||||
brcmf_dbg(TRACE, "enter\n");
|
||||
|
||||
/* expect using firmware supplicant for 1X */
|
||||
ifp = netdev_priv(dev);
|
||||
if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
|
||||
drvr = ifp->drvr;
|
||||
if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X &&
|
||||
!ifp->vif->profile.is_ft &&
|
||||
!ifp->vif->profile.is_okc))
|
||||
return -EINVAL;
|
||||
|
||||
if (conf->pmk_len > BRCMF_WSEC_MAX_PSK_LEN)
|
||||
return -ERANGE;
|
||||
|
||||
if (ifp->vif->profile.is_okc) {
|
||||
ret = brcmf_fil_iovar_data_set(ifp, "okc_info_pmk",
|
||||
conf->pmk, conf->pmk_len);
|
||||
if (ret < 0)
|
||||
bphy_err(drvr, "okc_info_pmk iovar failed: ret=%d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
|
||||
}
|
||||
|
||||
|
|
@ -6422,6 +6466,47 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool brcmf_has_pmkid(const u8 *parse, u32 len)
|
||||
{
|
||||
const struct brcmf_tlv *rsn_ie;
|
||||
const u8 *ie;
|
||||
u32 ie_len;
|
||||
u32 offset;
|
||||
u16 count;
|
||||
|
||||
if (!parse)
|
||||
return false;
|
||||
|
||||
rsn_ie = brcmf_parse_tlvs(parse, len, WLAN_EID_RSN);
|
||||
if (!rsn_ie)
|
||||
return false;
|
||||
|
||||
ie = (const u8 *)rsn_ie;
|
||||
ie_len = rsn_ie->len + TLV_HDR_LEN;
|
||||
|
||||
offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
|
||||
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
|
||||
return false;
|
||||
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
offset += WPA_IE_SUITE_COUNT_LEN + count * WPA_IE_MIN_OUI_LEN;
|
||||
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
|
||||
return false;
|
||||
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
offset += WPA_IE_SUITE_COUNT_LEN + count * WPA_IE_MIN_OUI_LEN;
|
||||
if (offset + RSN_CAP_LEN >= ie_len)
|
||||
return false;
|
||||
|
||||
offset += RSN_CAP_LEN;
|
||||
if (offset + RSN_PMKID_COUNT_LEN > ie_len)
|
||||
return false;
|
||||
|
||||
count = ie[offset] + (ie[offset + 1] << 8);
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
static s32
|
||||
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
|
||||
struct net_device *ndev,
|
||||
|
|
@ -6436,6 +6521,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
|
|||
struct brcmf_bss_info_le *bi;
|
||||
struct brcmu_chan ch;
|
||||
struct cfg80211_roam_info roam_info = {};
|
||||
bool authorized = false;
|
||||
u32 freq;
|
||||
s32 err = 0;
|
||||
u8 *buf;
|
||||
|
|
@ -6482,13 +6568,17 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
|
|||
roam_info.resp_ie = conn_info->resp_ie;
|
||||
roam_info.resp_ie_len = conn_info->resp_ie_len;
|
||||
|
||||
cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report roaming result\n");
|
||||
if ((profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X ||
|
||||
profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM) &&
|
||||
(brcmf_has_pmkid(roam_info.req_ie, roam_info.req_ie_len) ||
|
||||
profile->is_ft || profile->is_okc))
|
||||
authorized = true;
|
||||
|
||||
if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && profile->is_ft) {
|
||||
cfg80211_port_authorized(ndev, profile->bssid, NULL, 0, GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report port authorized\n");
|
||||
}
|
||||
cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
|
||||
if (authorized)
|
||||
cfg80211_port_authorized(ndev, profile->bssid, NULL, 0,
|
||||
GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report roaming result\n");
|
||||
|
||||
set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
|
||||
brcmf_dbg(TRACE, "Exit\n");
|
||||
|
|
@ -6504,6 +6594,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
|
|||
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
|
||||
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
|
||||
struct cfg80211_connect_resp_params conn_params;
|
||||
bool authorized;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
||||
|
|
@ -6522,13 +6613,23 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
|
|||
clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS,
|
||||
&ifp->vif->sme_state);
|
||||
conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
|
||||
bphy_err(ifp->drvr, "connect failed: event %u status %u reason %u\n",
|
||||
e->event_code, e->status, e->reason);
|
||||
}
|
||||
conn_params.links[0].bssid = profile->bssid;
|
||||
conn_params.req_ie = conn_info->req_ie;
|
||||
conn_params.req_ie_len = conn_info->req_ie_len;
|
||||
conn_params.resp_ie = conn_info->resp_ie;
|
||||
conn_params.resp_ie_len = conn_info->resp_ie_len;
|
||||
authorized = completed &&
|
||||
(profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X ||
|
||||
profile->use_fwsup == BRCMF_PROFILE_FWSUP_ROAM) &&
|
||||
brcmf_has_pmkid(conn_params.req_ie,
|
||||
conn_params.req_ie_len);
|
||||
cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
|
||||
if (authorized)
|
||||
cfg80211_port_authorized(ndev, profile->bssid, NULL, 0,
|
||||
GFP_KERNEL);
|
||||
brcmf_dbg(CONN, "Report connect result - connection %s\n",
|
||||
completed ? "succeeded" : "failed");
|
||||
}
|
||||
|
|
@ -7731,6 +7832,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
}
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE_EXT))
|
||||
wiphy->features |= NL80211_FEATURE_SAE;
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FBT) ||
|
||||
brcmf_feat_is_enabled(ifp, BRCMF_FEAT_OKC))
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_FAST_ROAM_OFFLOAD);
|
||||
wiphy->mgmt_stypes = brcmf_txrx_stypes;
|
||||
wiphy->max_remain_on_channel_duration = 5000;
|
||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
|
||||
|
|
|
|||
|
|
@ -127,7 +127,8 @@ enum brcmf_profile_fwsup {
|
|||
BRCMF_PROFILE_FWSUP_NONE,
|
||||
BRCMF_PROFILE_FWSUP_PSK,
|
||||
BRCMF_PROFILE_FWSUP_1X,
|
||||
BRCMF_PROFILE_FWSUP_SAE
|
||||
BRCMF_PROFILE_FWSUP_SAE,
|
||||
BRCMF_PROFILE_FWSUP_ROAM
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -164,6 +165,7 @@ enum brcmf_mgmt_tx_status {
|
|||
* @bssid: bssid of joined/joining ibss.
|
||||
* @sec: security information.
|
||||
* @key: key information
|
||||
* @is_okc: OKC is used for current connection.
|
||||
*/
|
||||
struct brcmf_cfg80211_profile {
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
|
@ -172,6 +174,7 @@ struct brcmf_cfg80211_profile {
|
|||
enum brcmf_profile_fwsup use_fwsup;
|
||||
u16 use_fwauth;
|
||||
bool is_ft;
|
||||
bool is_okc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
|
|||
{ BRCMF_FEAT_SAE, "sae " },
|
||||
{ BRCMF_FEAT_FWAUTH, "idauth" },
|
||||
{ BRCMF_FEAT_SAE_EXT, "sae_ext" },
|
||||
{ BRCMF_FEAT_FBT, "fbt " },
|
||||
{ BRCMF_FEAT_OKC, "okc" },
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@
|
|||
BRCMF_FEAT_DEF(SCAN_V2) \
|
||||
BRCMF_FEAT_DEF(PMKID_V2) \
|
||||
BRCMF_FEAT_DEF(PMKID_V3) \
|
||||
BRCMF_FEAT_DEF(SAE_EXT)
|
||||
BRCMF_FEAT_DEF(SAE_EXT) \
|
||||
BRCMF_FEAT_DEF(FBT) \
|
||||
BRCMF_FEAT_DEF(OKC)
|
||||
|
||||
/*
|
||||
* Quirks:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
#include "hcmd.h"
|
||||
|
||||
static void
|
||||
iwl_mld_reorder_release_frames(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
||||
iwl_mld_reorder_release_frames(struct iwl_mld *mld,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct napi_struct *napi,
|
||||
struct iwl_mld_baid_data *baid_data,
|
||||
struct iwl_mld_reorder_buffer *reorder_buf,
|
||||
|
|
@ -32,7 +33,7 @@ iwl_mld_reorder_release_frames(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
|||
while ((skb = __skb_dequeue(skb_list))) {
|
||||
iwl_mld_pass_packet_to_mac80211(mld, napi, skb,
|
||||
reorder_buf->queue,
|
||||
sta);
|
||||
link_sta);
|
||||
reorder_buf->num_stored--;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +75,7 @@ static void iwl_mld_release_frames_from_notif(struct iwl_mld *mld,
|
|||
|
||||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
iwl_mld_reorder_release_frames(mld, link_sta->sta, napi, ba_data,
|
||||
iwl_mld_reorder_release_frames(mld, link_sta, napi, ba_data,
|
||||
reorder_buf, nssn);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
|
|
@ -180,7 +181,7 @@ void iwl_mld_del_ba(struct iwl_mld *mld, int queue,
|
|||
reorder_buf = &ba_data->reorder_buf[queue];
|
||||
|
||||
/* release all frames that are in the reorder buffer to the stack */
|
||||
iwl_mld_reorder_release_frames(mld, link_sta->sta, NULL,
|
||||
iwl_mld_reorder_release_frames(mld, link_sta, NULL,
|
||||
ba_data, reorder_buf,
|
||||
ieee80211_sn_add(reorder_buf->head_sn,
|
||||
ba_data->buf_size));
|
||||
|
|
@ -193,7 +194,7 @@ void iwl_mld_del_ba(struct iwl_mld *mld, int queue,
|
|||
*/
|
||||
enum iwl_mld_reorder_result
|
||||
iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
||||
int queue, struct ieee80211_sta *sta,
|
||||
int queue, struct ieee80211_link_sta *link_sta,
|
||||
struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);
|
||||
|
|
@ -228,12 +229,12 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
/* no sta yet */
|
||||
if (IWL_FW_CHECK(mld, !sta,
|
||||
if (IWL_FW_CHECK(mld, !link_sta,
|
||||
"Got valid BAID without a valid station assigned - %d\n",
|
||||
baid))
|
||||
return IWL_MLD_PASS_SKB;
|
||||
|
||||
mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
|
||||
/* not a data packet */
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
|
|
@ -324,7 +325,7 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
* will be released when the frame release notification arrives.
|
||||
*/
|
||||
if (!amsdu || last_subframe)
|
||||
iwl_mld_reorder_release_frames(mld, sta, napi, baid_data,
|
||||
iwl_mld_reorder_release_frames(mld, link_sta, napi, baid_data,
|
||||
buffer, nssn);
|
||||
else if (buffer->num_stored == 1)
|
||||
buffer->head_sn = nssn;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024, 2026 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_agg_h__
|
||||
#define __iwl_agg_h__
|
||||
|
|
@ -106,7 +106,7 @@ int iwl_mld_ampdu_rx_stop(struct iwl_mld *mld, struct ieee80211_sta *sta,
|
|||
|
||||
enum iwl_mld_reorder_result
|
||||
iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
|
||||
int queue, struct ieee80211_sta *sta,
|
||||
int queue, struct ieee80211_link_sta *link_sta,
|
||||
struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc);
|
||||
|
||||
void iwl_mld_handle_frame_release_notif(struct iwl_mld *mld,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ iwl_mld_fill_phy_data_from_mpdu(struct iwl_mld *mld,
|
|||
}
|
||||
|
||||
static inline int iwl_mld_check_pn(struct iwl_mld *mld, struct sk_buff *skb,
|
||||
int queue, struct ieee80211_sta *sta)
|
||||
int queue,
|
||||
struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);
|
||||
struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
|
||||
|
|
@ -71,13 +72,13 @@ static inline int iwl_mld_check_pn(struct iwl_mld *mld, struct sk_buff *skb,
|
|||
return 0;
|
||||
|
||||
/* if we are here - this for sure is either CCMP or GCMP */
|
||||
if (!sta) {
|
||||
if (!link_sta) {
|
||||
IWL_DEBUG_DROP(mld,
|
||||
"expected hw-decrypted unicast frame for station\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
|
||||
extiv = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
|
||||
keyidx = extiv[3] >> 6;
|
||||
|
|
@ -119,17 +120,17 @@ static inline int iwl_mld_check_pn(struct iwl_mld *mld, struct sk_buff *skb,
|
|||
void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *skb, int queue,
|
||||
struct ieee80211_sta *sta)
|
||||
struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
KUNIT_STATIC_STUB_REDIRECT(iwl_mld_pass_packet_to_mac80211,
|
||||
mld, napi, skb, queue, sta);
|
||||
mld, napi, skb, queue, link_sta);
|
||||
|
||||
if (unlikely(iwl_mld_check_pn(mld, skb, queue, sta))) {
|
||||
if (unlikely(iwl_mld_check_pn(mld, skb, queue, link_sta))) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_rx_napi(mld->hw, sta, skb, napi);
|
||||
ieee80211_rx_napi(mld->hw, link_sta, skb, napi);
|
||||
}
|
||||
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_pass_packet_to_mac80211);
|
||||
|
||||
|
|
@ -1728,7 +1729,7 @@ static void iwl_mld_update_last_rx_timestamp(struct iwl_mld *mld, u8 baid)
|
|||
* Sets *drop to true if the packet should be dropped.
|
||||
* Returns the station if found, or NULL otherwise.
|
||||
*/
|
||||
static struct ieee80211_sta *
|
||||
static struct ieee80211_link_sta *
|
||||
iwl_mld_rx_with_sta(struct iwl_mld *mld, struct ieee80211_hdr *hdr,
|
||||
struct sk_buff *skb,
|
||||
const struct iwl_rx_mpdu_desc *mpdu_desc,
|
||||
|
|
@ -1764,11 +1765,6 @@ iwl_mld_rx_with_sta(struct iwl_mld *mld, struct ieee80211_hdr *hdr,
|
|||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
if (link_sta && sta->valid_links) {
|
||||
rx_status->link_valid = true;
|
||||
rx_status->link_id = link_sta->link_id;
|
||||
}
|
||||
|
||||
/* fill checksum */
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
pkt->len_n_flags & cpu_to_le32(FH_RSCSR_RPA_EN)) {
|
||||
|
|
@ -1803,10 +1799,10 @@ iwl_mld_rx_with_sta(struct iwl_mld *mld, struct ieee80211_hdr *hdr,
|
|||
queue);
|
||||
}
|
||||
|
||||
return sta;
|
||||
return link_sta;
|
||||
}
|
||||
|
||||
static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta,
|
||||
static int iwl_mld_rx_mgmt_prot(struct ieee80211_link_sta *link_sta,
|
||||
struct ieee80211_hdr *hdr,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
u32 mpdu_status,
|
||||
|
|
@ -1820,7 +1816,6 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta,
|
|||
struct ieee80211_key_conf *key;
|
||||
const u8 *frame = (void *)hdr;
|
||||
const u8 *mmie;
|
||||
u8 link_id;
|
||||
|
||||
if ((mpdu_status & IWL_RX_MPDU_STATUS_SEC_MASK) ==
|
||||
IWL_RX_MPDU_STATUS_SEC_NONE)
|
||||
|
|
@ -1836,10 +1831,10 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta,
|
|||
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
if (!sta)
|
||||
if (!link_sta)
|
||||
return -1;
|
||||
|
||||
mld_sta = iwl_mld_sta_from_mac80211(sta);
|
||||
mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
mld_vif = iwl_mld_vif_from_mac80211(mld_sta->vif);
|
||||
|
||||
/* key mismatch - will also report !MIC_OK but we shouldn't count it */
|
||||
|
|
@ -1853,8 +1848,7 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta,
|
|||
return 0;
|
||||
}
|
||||
|
||||
link_id = rx_status->link_valid ? rx_status->link_id : 0;
|
||||
link = rcu_dereference(mld_vif->link[link_id]);
|
||||
link = rcu_dereference(mld_vif->link[link_sta->link_id]);
|
||||
if (WARN_ON_ONCE(!link))
|
||||
return -1;
|
||||
|
||||
|
|
@ -1905,7 +1899,7 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta,
|
|||
}
|
||||
|
||||
static int iwl_mld_rx_crypto(struct iwl_mld *mld,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct ieee80211_hdr *hdr,
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
struct iwl_rx_mpdu_desc *desc, int queue,
|
||||
|
|
@ -1915,7 +1909,7 @@ static int iwl_mld_rx_crypto(struct iwl_mld *mld,
|
|||
|
||||
if (unlikely(ieee80211_is_mgmt(hdr->frame_control) &&
|
||||
!ieee80211_has_protected(hdr->frame_control)))
|
||||
return iwl_mld_rx_mgmt_prot(sta, hdr, rx_status, status,
|
||||
return iwl_mld_rx_mgmt_prot(link_sta, hdr, rx_status, status,
|
||||
le16_to_cpu(desc->mpdu_len));
|
||||
|
||||
if (!ieee80211_has_protected(hdr->frame_control) ||
|
||||
|
|
@ -2023,7 +2017,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_mld_rx_phy_data phy_data = {};
|
||||
struct iwl_rx_mpdu_desc *mpdu_desc = (void *)pkt->data;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct sk_buff *skb;
|
||||
size_t mpdu_desc_size = sizeof(*mpdu_desc);
|
||||
|
|
@ -2086,7 +2080,8 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = iwl_mld_rx_with_sta(mld, hdr, skb, mpdu_desc, pkt, queue, &drop);
|
||||
link_sta = iwl_mld_rx_with_sta(mld, hdr, skb, mpdu_desc, pkt, queue,
|
||||
&drop);
|
||||
if (drop)
|
||||
goto drop;
|
||||
|
||||
|
|
@ -2127,7 +2122,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
|
||||
iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data);
|
||||
|
||||
if (iwl_mld_rx_crypto(mld, sta, hdr, rx_status, mpdu_desc, queue,
|
||||
if (iwl_mld_rx_crypto(mld, link_sta, hdr, rx_status, mpdu_desc, queue,
|
||||
le32_to_cpu(pkt->len_n_flags), &crypto_len))
|
||||
goto drop;
|
||||
|
||||
|
|
@ -2140,7 +2135,8 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
if (iwl_mld_time_sync_frame(mld, skb, hdr->addr2))
|
||||
goto out;
|
||||
|
||||
reorder_res = iwl_mld_reorder(mld, napi, queue, sta, skb, mpdu_desc);
|
||||
reorder_res = iwl_mld_reorder(mld, napi, queue, link_sta, skb,
|
||||
mpdu_desc);
|
||||
switch (reorder_res) {
|
||||
case IWL_MLD_PASS_SKB:
|
||||
break;
|
||||
|
|
@ -2153,7 +2149,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi,
|
|||
goto drop;
|
||||
}
|
||||
|
||||
iwl_mld_pass_packet_to_mac80211(mld, napi, skb, queue, sta);
|
||||
iwl_mld_pass_packet_to_mac80211(mld, napi, skb, queue, link_sta);
|
||||
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ void iwl_mld_handle_rsc_notif(struct iwl_mld *mld,
|
|||
void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *skb, int queue,
|
||||
struct ieee80211_sta *sta);
|
||||
struct ieee80211_link_sta *link_sta);
|
||||
|
||||
void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* KUnit tests for channel helper functions
|
||||
*
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
* Copyright (C) 2024-2026 Intel Corporation
|
||||
*/
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/static_stub.h>
|
||||
|
|
@ -441,7 +441,7 @@ static void
|
|||
fake_iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld,
|
||||
struct napi_struct *napi,
|
||||
struct sk_buff *skb, int queue,
|
||||
struct ieee80211_sta *sta)
|
||||
struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
__skb_queue_tail(&g_released_skbs, skb);
|
||||
g_num_released_skbs++;
|
||||
|
|
@ -630,7 +630,8 @@ static void test_reorder_buffer(struct kunit *test)
|
|||
mpdu_desc = setup_mpdu_desc();
|
||||
|
||||
rcu_read_lock();
|
||||
reorder_res = iwl_mld_reorder(mld, NULL, QUEUE, sta, skb, mpdu_desc);
|
||||
reorder_res = iwl_mld_reorder(mld, NULL, QUEUE, &sta->deflink, skb,
|
||||
mpdu_desc);
|
||||
rcu_read_unlock();
|
||||
|
||||
KUNIT_ASSERT_EQ(test, reorder_res, param->expected.reorder_res);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
|||
fraglen, rxb->truesize);
|
||||
}
|
||||
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
ieee80211_rx_napi(mvm->hw, sta ? &sta->deflink : NULL, skb, napi);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2026 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
|
@ -243,7 +243,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
|||
return;
|
||||
}
|
||||
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
ieee80211_rx_napi(mvm->hw, sta ? &sta->deflink : NULL, skb, napi);
|
||||
}
|
||||
|
||||
static bool iwl_mvm_used_average_energy(struct iwl_mvm *mvm,
|
||||
|
|
@ -2528,7 +2528,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
|
||||
ieee80211_rx_napi(mvm->hw, sta ? &sta->deflink : NULL, skb, napi);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -798,10 +798,18 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
|
|||
exit = len = 0;
|
||||
|
||||
do {
|
||||
struct fwheader *fwh = (void *)data;
|
||||
struct fwheader *fwh;
|
||||
|
||||
if (totlen - len < sizeof(*fwh))
|
||||
break;
|
||||
|
||||
fwh = (void *)data;
|
||||
|
||||
bincmd = le32_to_cpu(fwh->dnldcmd);
|
||||
blksize = le32_to_cpu(fwh->datalength);
|
||||
if (blksize > totlen - len - sizeof(*fwh))
|
||||
break;
|
||||
|
||||
switch (bincmd) {
|
||||
case FW_HAS_DATA_TO_RECV:
|
||||
offset = sizeof(struct fwheader) + blksize;
|
||||
|
|
|
|||
|
|
@ -65,19 +65,6 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lbs_mesh_config_send(struct lbs_private *priv,
|
||||
struct cmd_ds_mesh_config *cmd,
|
||||
uint16_t action, uint16_t type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = __lbs_mesh_config_send(priv, cmd, action, type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
|
||||
* START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
|
||||
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
|
||||
|
|
@ -333,497 +320,6 @@ static const struct attribute_group lbs_mesh_attr_group = {
|
|||
.attrs = lbs_mesh_sysfs_entries,
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Persistent configuration support
|
||||
*/
|
||||
|
||||
static int mesh_get_default_parameters(struct device *dev,
|
||||
struct mrvl_mesh_defaults *defs)
|
||||
{
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
int ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
|
||||
CMD_TYPE_MESH_GET_DEFAULTS);
|
||||
|
||||
if (ret)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bootflag_show - Get function for sysfs attribute bootflag
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t bootflag_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", le32_to_cpu(defs.bootflag));
|
||||
}
|
||||
|
||||
/**
|
||||
* bootflag_store - Set function for sysfs attribute bootflag
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &datum);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (datum > 1)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
|
||||
cmd.length = cpu_to_le16(sizeof(uint32_t));
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_BOOTFLAG);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* boottime_show - Get function for sysfs attribute boottime
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t boottime_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", defs.boottime);
|
||||
}
|
||||
|
||||
/**
|
||||
* boottime_store - Set function for sysfs attribute boottime
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t boottime_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &datum);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (datum > 255)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
/* A too small boot time will result in the device booting into
|
||||
* standalone (no-host) mode before the host can take control of it,
|
||||
* so the change will be hard to revert. This may be a desired
|
||||
* feature (e.g to configure a very fast boot time for devices that
|
||||
* will not be attached to a host), but dangerous. So I'm enforcing a
|
||||
* lower limit of 20 seconds: remove and recompile the driver if this
|
||||
* does not work for you.
|
||||
*/
|
||||
datum = (datum < 20) ? 20 : datum;
|
||||
cmd.data[0] = datum;
|
||||
cmd.length = cpu_to_le16(sizeof(uint8_t));
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_BOOTTIME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* channel_show - Get function for sysfs attribute channel
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t channel_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", le16_to_cpu(defs.channel));
|
||||
}
|
||||
|
||||
/**
|
||||
* channel_store - Set function for sysfs attribute channel
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &datum);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (datum < 1 || datum > 11)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
|
||||
cmd.length = cpu_to_le16(sizeof(uint16_t));
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_DEF_CHANNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_id_show - Get function for sysfs attribute mesh_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
|
||||
dev_err(dev, "inconsistent mesh ID length\n");
|
||||
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
|
||||
}
|
||||
|
||||
memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
|
||||
buf[defs.meshie.val.mesh_id_len] = '\n';
|
||||
buf[defs.meshie.val.mesh_id_len + 1] = '\0';
|
||||
|
||||
return defs.meshie.val.mesh_id_len + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_id_store - Set function for sysfs attribute mesh_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
struct mrvl_mesh_defaults defs;
|
||||
struct mrvl_meshie *ie;
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
|
||||
ie = (struct mrvl_meshie *) &cmd.data[0];
|
||||
|
||||
/* fetch all other Information Element parameters */
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
|
||||
|
||||
/* transfer IE elements */
|
||||
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
|
||||
|
||||
len = count - 1;
|
||||
memcpy(ie->val.mesh_id, buf, len);
|
||||
/* SSID len */
|
||||
ie->val.mesh_id_len = len;
|
||||
/* IE len */
|
||||
ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
|
||||
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_MESH_IE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* protocol_id_show - Get function for sysfs attribute protocol_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t protocol_id_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", defs.meshie.val.active_protocol_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* protocol_id_store - Set function for sysfs attribute protocol_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t protocol_id_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
struct mrvl_mesh_defaults defs;
|
||||
struct mrvl_meshie *ie;
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &datum);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (datum > 255)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
/* fetch all other Information Element parameters */
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
|
||||
|
||||
/* transfer IE elements */
|
||||
ie = (struct mrvl_meshie *) &cmd.data[0];
|
||||
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
|
||||
/* update protocol id */
|
||||
ie->val.active_protocol_id = datum;
|
||||
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_MESH_IE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* metric_id_show - Get function for sysfs attribute metric_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t metric_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", defs.meshie.val.active_metric_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* metric_id_store - Set function for sysfs attribute metric_id
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t metric_id_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
struct mrvl_mesh_defaults defs;
|
||||
struct mrvl_meshie *ie;
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
ret = sscanf(buf, "%d", &datum);
|
||||
if ((ret != 1) || (datum > 255))
|
||||
return -EINVAL;
|
||||
|
||||
/* fetch all other Information Element parameters */
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
|
||||
|
||||
/* transfer IE elements */
|
||||
ie = (struct mrvl_meshie *) &cmd.data[0];
|
||||
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
|
||||
/* update metric id */
|
||||
ie->val.active_metric_id = datum;
|
||||
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_MESH_IE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* capability_show - Get function for sysfs attribute capability
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer where data will be returned
|
||||
*/
|
||||
static ssize_t capability_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct mrvl_mesh_defaults defs;
|
||||
int ret;
|
||||
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", defs.meshie.val.mesh_capability);
|
||||
}
|
||||
|
||||
/**
|
||||
* capability_store - Set function for sysfs attribute capability
|
||||
* @dev: the &struct device
|
||||
* @attr: device attributes
|
||||
* @buf: buffer that contains new attribute value
|
||||
* @count: size of buffer
|
||||
*/
|
||||
static ssize_t capability_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct cmd_ds_mesh_config cmd;
|
||||
struct mrvl_mesh_defaults defs;
|
||||
struct mrvl_meshie *ie;
|
||||
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
|
||||
uint32_t datum;
|
||||
int ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
ret = sscanf(buf, "%d", &datum);
|
||||
if ((ret != 1) || (datum > 255))
|
||||
return -EINVAL;
|
||||
|
||||
/* fetch all other Information Element parameters */
|
||||
ret = mesh_get_default_parameters(dev, &defs);
|
||||
|
||||
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
|
||||
|
||||
/* transfer IE elements */
|
||||
ie = (struct mrvl_meshie *) &cmd.data[0];
|
||||
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
|
||||
/* update value */
|
||||
ie->val.mesh_capability = datum;
|
||||
|
||||
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
|
||||
CMD_TYPE_MESH_SET_MESH_IE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_ATTR_RW(bootflag);
|
||||
static DEVICE_ATTR_RW(boottime);
|
||||
static DEVICE_ATTR_RW(channel);
|
||||
static DEVICE_ATTR_RW(mesh_id);
|
||||
static DEVICE_ATTR_RW(protocol_id);
|
||||
static DEVICE_ATTR_RW(metric_id);
|
||||
static DEVICE_ATTR_RW(capability);
|
||||
|
||||
static struct attribute *boot_opts_attrs[] = {
|
||||
&dev_attr_bootflag.attr,
|
||||
&dev_attr_boottime.attr,
|
||||
&dev_attr_channel.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group boot_opts_group = {
|
||||
.name = "boot_options",
|
||||
.attrs = boot_opts_attrs,
|
||||
};
|
||||
|
||||
static struct attribute *mesh_ie_attrs[] = {
|
||||
&dev_attr_mesh_id.attr,
|
||||
&dev_attr_protocol_id.attr,
|
||||
&dev_attr_metric_id.attr,
|
||||
&dev_attr_capability.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group mesh_ie_group = {
|
||||
.name = "mesh_ie",
|
||||
.attrs = mesh_ie_attrs,
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Initializing and starting, stopping mesh
|
||||
*/
|
||||
|
|
@ -1019,8 +515,6 @@ static int lbs_add_mesh(struct lbs_private *priv)
|
|||
|
||||
mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
|
||||
mesh_dev->sysfs_groups[0] = &lbs_mesh_attr_group;
|
||||
mesh_dev->sysfs_groups[1] = &boot_opts_group;
|
||||
mesh_dev->sysfs_groups[2] = &mesh_ie_group;
|
||||
|
||||
/* Register virtual mesh interface */
|
||||
ret = register_netdev(mesh_dev);
|
||||
|
|
|
|||
|
|
@ -769,10 +769,18 @@ static int check_fwfile_format(const u8 *data, u32 totlen)
|
|||
exit = len = 0;
|
||||
|
||||
do {
|
||||
struct fwheader *fwh = (void *) data;
|
||||
struct fwheader *fwh;
|
||||
|
||||
if (totlen - len < sizeof(*fwh))
|
||||
break;
|
||||
|
||||
fwh = (void *)data;
|
||||
|
||||
bincmd = le32_to_cpu(fwh->dnldcmd);
|
||||
blksize = le32_to_cpu(fwh->datalength);
|
||||
if (blksize > totlen - len - sizeof(*fwh))
|
||||
break;
|
||||
|
||||
switch (bincmd) {
|
||||
case FW_HAS_DATA_TO_RECV:
|
||||
offset = sizeof(struct fwheader) + blksize;
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
|
|||
list_del(&tbl->list);
|
||||
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
|
||||
|
||||
kfree(tbl->rx_reorder_ptr);
|
||||
kfree(tbl);
|
||||
|
||||
spin_lock_bh(&priv->adapter->rx_proc_lock);
|
||||
|
|
@ -329,7 +328,6 @@ static void
|
|||
mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
|
||||
int tid, int win_size, int seq_num)
|
||||
{
|
||||
int i;
|
||||
struct mwifiex_rx_reorder_tbl *tbl, *new_node;
|
||||
u16 last_seq = 0;
|
||||
struct mwifiex_sta_node *node;
|
||||
|
|
@ -344,10 +342,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
|
|||
return;
|
||||
}
|
||||
/* if !tbl then create one */
|
||||
new_node = kzalloc_obj(struct mwifiex_rx_reorder_tbl);
|
||||
new_node = kzalloc_flex(*new_node, rx_reorder_ptr, win_size);
|
||||
if (!new_node)
|
||||
return;
|
||||
|
||||
new_node->win_size = win_size;
|
||||
|
||||
INIT_LIST_HEAD(&new_node->list);
|
||||
new_node->tid = tid;
|
||||
memcpy(new_node->ta, ta, ETH_ALEN);
|
||||
|
|
@ -381,26 +381,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
|
|||
new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
|
||||
}
|
||||
|
||||
new_node->win_size = win_size;
|
||||
|
||||
new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (!new_node->rx_reorder_ptr) {
|
||||
kfree(new_node);
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"%s: failed to alloc reorder_ptr\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
new_node->timer_context.ptr = new_node;
|
||||
new_node->timer_context.priv = priv;
|
||||
new_node->timer_context.timer_is_set = false;
|
||||
|
||||
timer_setup(&new_node->timer_context.timer, mwifiex_flush_data, 0);
|
||||
|
||||
for (i = 0; i < win_size; ++i)
|
||||
new_node->rx_reorder_ptr[i] = NULL;
|
||||
|
||||
spin_lock_bh(&priv->rx_reorder_tbl_lock);
|
||||
list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
|
||||
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
|
||||
|
|
|
|||
|
|
@ -4905,7 +4905,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
|||
country_code =
|
||||
mwifiex_11d_code_2_region(
|
||||
adapter->region_code);
|
||||
|
||||
/* If the reg hint in ROM conflicts with platform
|
||||
* configuration, it should be ignored, so the
|
||||
* platform regulatory domain can be used.
|
||||
*/
|
||||
if (country_code &&
|
||||
!device_property_read_bool(adapter->dev,
|
||||
"marvell,invalid-reg-hint-in-rom") &&
|
||||
regulatory_hint(wiphy, country_code))
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"regulatory_hint() failed\n");
|
||||
|
|
|
|||
|
|
@ -708,10 +708,10 @@ struct mwifiex_rx_reorder_tbl {
|
|||
int init_win;
|
||||
int start_win;
|
||||
int win_size;
|
||||
void **rx_reorder_ptr;
|
||||
struct reorder_tmr_cnxt timer_context;
|
||||
u8 amsdu;
|
||||
u8 flags;
|
||||
struct sk_buff *rx_reorder_ptr[] __counted_by(win_size);
|
||||
};
|
||||
|
||||
struct mwifiex_bss_prio_node {
|
||||
|
|
|
|||
|
|
@ -1255,11 +1255,12 @@ EXPORT_SYMBOL(mt76_rx_signal);
|
|||
static void
|
||||
mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
|
||||
struct ieee80211_hw **hw,
|
||||
struct ieee80211_sta **sta)
|
||||
struct ieee80211_link_sta **link_sta)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
||||
struct mt76_rx_status mstat;
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
mstat = *((struct mt76_rx_status *)skb->cb);
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
|
@ -1301,12 +1302,14 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
|
|||
memcpy(status->chain_signal, mstat.chain_signal,
|
||||
sizeof(mstat.chain_signal));
|
||||
|
||||
if (mstat.wcid) {
|
||||
status->link_valid = mstat.wcid->link_valid;
|
||||
status->link_id = mstat.wcid->link_id;
|
||||
}
|
||||
sta = wcid_to_sta(mstat.wcid);
|
||||
if (!sta)
|
||||
*link_sta = NULL;
|
||||
else if (mstat.wcid->link_valid)
|
||||
*link_sta = rcu_dereference(sta->link[mstat.wcid->link_id]);
|
||||
else
|
||||
*link_sta = &sta->deflink;
|
||||
|
||||
*sta = wcid_to_sta(mstat.wcid);
|
||||
*hw = mt76_phy_hw(dev, mstat.phy_idx);
|
||||
}
|
||||
|
||||
|
|
@ -1530,7 +1533,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
|
|||
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
struct napi_struct *napi)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct ieee80211_hw *hw;
|
||||
struct sk_buff *skb, *tmp;
|
||||
LIST_HEAD(list);
|
||||
|
|
@ -1541,8 +1544,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
|||
|
||||
mt76_check_ccmp_pn(skb);
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
mt76_rx_convert(dev, skb, &hw, &sta);
|
||||
ieee80211_rx_list(hw, sta, skb, &list);
|
||||
mt76_rx_convert(dev, skb, &hw, &link_sta);
|
||||
ieee80211_rx_list(hw, link_sta, skb, &list);
|
||||
|
||||
/* subsequent amsdu frames */
|
||||
while (nskb) {
|
||||
|
|
@ -1550,8 +1553,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
|||
nskb = nskb->next;
|
||||
skb->next = NULL;
|
||||
|
||||
mt76_rx_convert(dev, skb, &hw, &sta);
|
||||
ieee80211_rx_list(hw, sta, skb, &list);
|
||||
mt76_rx_convert(dev, skb, &hw, &link_sta);
|
||||
ieee80211_rx_list(hw, link_sta, skb, &list);
|
||||
}
|
||||
}
|
||||
spin_unlock(&dev->rx_lock);
|
||||
|
|
|
|||
|
|
@ -19,84 +19,50 @@
|
|||
#include "rt2x00.h"
|
||||
#include "rt2x00pci.h"
|
||||
|
||||
/*
|
||||
* PCI driver handlers.
|
||||
*/
|
||||
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
kfree(rt2x00dev->rf);
|
||||
rt2x00dev->rf = NULL;
|
||||
|
||||
kfree(rt2x00dev->eeprom);
|
||||
rt2x00dev->eeprom = NULL;
|
||||
|
||||
if (rt2x00dev->csr.base) {
|
||||
iounmap(rt2x00dev->csr.base);
|
||||
rt2x00dev->csr.base = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev);
|
||||
|
||||
rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0);
|
||||
if (!rt2x00dev->csr.base)
|
||||
goto exit;
|
||||
|
||||
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
|
||||
if (!rt2x00dev->eeprom)
|
||||
goto exit;
|
||||
|
||||
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
|
||||
if (!rt2x00dev->rf)
|
||||
goto exit;
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
rt2x00_probe_err("Failed to allocate registers\n");
|
||||
|
||||
rt2x00pci_free_reg(rt2x00dev);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct rt2x00_dev *rt2x00dev;
|
||||
struct ieee80211_hw *hw;
|
||||
void __iomem *base;
|
||||
__le16 *eeprom;
|
||||
int retval;
|
||||
u16 chip;
|
||||
u32 *rf;
|
||||
|
||||
retval = pci_enable_device(pci_dev);
|
||||
retval = pcim_enable_device(pci_dev);
|
||||
if (retval) {
|
||||
rt2x00_probe_err("Enable device failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
|
||||
if (retval) {
|
||||
rt2x00_probe_err("PCI request regions failed\n");
|
||||
goto exit_disable_device;
|
||||
base = pcim_iomap_region(pci_dev, 0, pci_name(pci_dev));
|
||||
if (IS_ERR(base)) {
|
||||
rt2x00_probe_err("PCI iomap region failed\n");
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
pci_set_master(pci_dev);
|
||||
|
||||
if (pci_set_mwi(pci_dev))
|
||||
if (pcim_set_mwi(pci_dev))
|
||||
rt2x00_probe_err("MWI not available\n");
|
||||
|
||||
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
|
||||
rt2x00_probe_err("PCI DMA not supported\n");
|
||||
retval = -EIO;
|
||||
goto exit_release_regions;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
eeprom = devm_kzalloc(&pci_dev->dev, ops->eeprom_size, GFP_KERNEL);
|
||||
if (!eeprom)
|
||||
return -ENOMEM;
|
||||
|
||||
rf = devm_kzalloc(&pci_dev->dev, ops->rf_size, GFP_KERNEL);
|
||||
if (!rf)
|
||||
return -ENOMEM;
|
||||
|
||||
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
|
||||
if (!hw) {
|
||||
rt2x00_probe_err("Failed to allocate hardware\n");
|
||||
retval = -ENOMEM;
|
||||
goto exit_release_regions;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci_dev, hw);
|
||||
|
|
@ -105,18 +71,17 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
|
|||
rt2x00dev->dev = &pci_dev->dev;
|
||||
rt2x00dev->ops = ops;
|
||||
rt2x00dev->hw = hw;
|
||||
rt2x00dev->csr.base = base;
|
||||
rt2x00dev->irq = pci_dev->irq;
|
||||
rt2x00dev->name = ops->name;
|
||||
rt2x00dev->eeprom = eeprom;
|
||||
rt2x00dev->rf = rf;
|
||||
|
||||
if (pci_is_pcie(pci_dev))
|
||||
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
|
||||
else
|
||||
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
|
||||
|
||||
retval = rt2x00pci_alloc_reg(rt2x00dev);
|
||||
if (retval)
|
||||
goto exit_free_device;
|
||||
|
||||
/*
|
||||
* Because rt3290 chip use different efuse offset to read efuse data.
|
||||
* So before read efuse it need to indicate it is the
|
||||
|
|
@ -127,23 +92,13 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
|
|||
|
||||
retval = rt2x00lib_probe_dev(rt2x00dev);
|
||||
if (retval)
|
||||
goto exit_free_reg;
|
||||
goto exit_free_device;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_reg:
|
||||
rt2x00pci_free_reg(rt2x00dev);
|
||||
|
||||
exit_free_device:
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
exit_release_regions:
|
||||
pci_clear_mwi(pci_dev);
|
||||
pci_release_regions(pci_dev);
|
||||
|
||||
exit_disable_device:
|
||||
pci_disable_device(pci_dev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00pci_probe);
|
||||
|
|
@ -153,19 +108,8 @@ void rt2x00pci_remove(struct pci_dev *pci_dev)
|
|||
struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
|
||||
/*
|
||||
* Free all allocated data.
|
||||
*/
|
||||
rt2x00lib_remove_dev(rt2x00dev);
|
||||
rt2x00pci_free_reg(rt2x00dev);
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
/*
|
||||
* Free the PCI device data.
|
||||
*/
|
||||
pci_clear_mwi(pci_dev);
|
||||
pci_disable_device(pci_dev);
|
||||
pci_release_regions(pci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00pci_remove);
|
||||
|
||||
|
|
|
|||
|
|
@ -755,55 +755,31 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
|
||||
|
||||
/*
|
||||
* USB driver handlers.
|
||||
*/
|
||||
static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
kfree(rt2x00dev->rf);
|
||||
rt2x00dev->rf = NULL;
|
||||
|
||||
kfree(rt2x00dev->eeprom);
|
||||
rt2x00dev->eeprom = NULL;
|
||||
|
||||
kfree(rt2x00dev->csr.cache);
|
||||
rt2x00dev->csr.cache = NULL;
|
||||
}
|
||||
|
||||
static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
rt2x00dev->csr.cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
|
||||
if (!rt2x00dev->csr.cache)
|
||||
goto exit;
|
||||
|
||||
rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
|
||||
if (!rt2x00dev->eeprom)
|
||||
goto exit;
|
||||
|
||||
rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
|
||||
if (!rt2x00dev->rf)
|
||||
goto exit;
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
rt2x00_probe_err("Failed to allocate registers\n");
|
||||
|
||||
rt2x00usb_free_reg(rt2x00dev);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int rt2x00usb_probe(struct usb_interface *usb_intf,
|
||||
const struct rt2x00_ops *ops)
|
||||
{
|
||||
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
|
||||
struct ieee80211_hw *hw;
|
||||
struct rt2x00_dev *rt2x00dev;
|
||||
struct ieee80211_hw *hw;
|
||||
__le16 *eeprom;
|
||||
void *cache;
|
||||
int retval;
|
||||
u32 *rf;
|
||||
|
||||
usb_reset_device(usb_dev);
|
||||
|
||||
cache = devm_kzalloc(&usb_intf->dev, CSR_CACHE_SIZE, GFP_KERNEL);
|
||||
if (!cache)
|
||||
return -ENOMEM;
|
||||
|
||||
eeprom = devm_kzalloc(&usb_intf->dev, ops->eeprom_size, GFP_KERNEL);
|
||||
if (!eeprom)
|
||||
return -ENOMEM;
|
||||
|
||||
rf = devm_kzalloc(&usb_intf->dev, ops->rf_size, GFP_KERNEL);
|
||||
if (!rf)
|
||||
return -ENOMEM;
|
||||
|
||||
hw = ieee80211_alloc_hw(struct_size(rt2x00dev, anchor, 1), ops->hw);
|
||||
if (!hw) {
|
||||
rt2x00_probe_err("Failed to allocate hardware\n");
|
||||
|
|
@ -816,16 +792,15 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
|
|||
rt2x00dev->dev = &usb_intf->dev;
|
||||
rt2x00dev->ops = ops;
|
||||
rt2x00dev->hw = hw;
|
||||
rt2x00dev->csr.cache = cache;
|
||||
rt2x00dev->eeprom = eeprom;
|
||||
rt2x00dev->rf = rf;
|
||||
|
||||
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
|
||||
|
||||
INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
|
||||
INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
|
||||
|
||||
retval = rt2x00usb_alloc_reg(rt2x00dev);
|
||||
if (retval)
|
||||
goto exit_free_device;
|
||||
|
||||
init_usb_anchor(rt2x00dev->anchor);
|
||||
|
||||
retval = rt2x00lib_probe_dev(rt2x00dev);
|
||||
|
|
@ -836,9 +811,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
|
|||
|
||||
exit_free_anchor:
|
||||
usb_kill_anchored_urbs(rt2x00dev->anchor);
|
||||
rt2x00usb_free_reg(rt2x00dev);
|
||||
|
||||
exit_free_device:
|
||||
ieee80211_free_hw(hw);
|
||||
usb_set_intfdata(usb_intf, NULL);
|
||||
|
||||
|
|
@ -855,7 +827,6 @@ void rt2x00usb_disconnect(struct usb_interface *usb_intf)
|
|||
* Free all allocated data.
|
||||
*/
|
||||
rt2x00lib_remove_dev(rt2x00dev);
|
||||
rt2x00usb_free_reg(rt2x00dev);
|
||||
ieee80211_free_hw(hw);
|
||||
|
||||
usb_set_intfdata(usb_intf, NULL);
|
||||
|
|
|
|||
|
|
@ -3073,10 +3073,8 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
|||
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
|
||||
struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
|
||||
struct sk_buff *skb = iter_data->skb;
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu;
|
||||
bool is_mld = ieee80211_vif_is_mld(vif);
|
||||
struct ieee80211_bss_conf *bss_conf;
|
||||
struct rtw89_vif_link *rtwvif_link;
|
||||
const u8 *bssid = iter_data->bssid;
|
||||
|
|
@ -3110,11 +3108,6 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
|
|||
if (!ether_addr_equal(target_bssid, bssid))
|
||||
goto out;
|
||||
|
||||
if (is_mld) {
|
||||
rx_status->link_valid = true;
|
||||
rx_status->link_id = rtwvif_link->link_id;
|
||||
}
|
||||
|
||||
bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
|
||||
pkt_stat = &bb->cur_pkt_stat;
|
||||
|
||||
|
|
|
|||
|
|
@ -284,10 +284,10 @@ void wfx_bh_request_tx(struct wfx_dev *wdev)
|
|||
}
|
||||
|
||||
/* If IRQ is not available, this function allow to manually poll the control register and simulate
|
||||
* an IRQ ahen an event happened.
|
||||
* an IRQ when an event happened.
|
||||
*
|
||||
* Note that the device has a bug: If an IRQ raise while host read control register, the IRQ is
|
||||
* lost. So, use this function carefully (only duing device initialisation).
|
||||
* Note that the device has a bug: If an IRQ raise while host read control register, the device is
|
||||
* lost. Unfortunately, this is the only way to initialize the SDIO with out-of-band IRQ.
|
||||
*/
|
||||
void wfx_bh_poll_irq(struct wfx_dev *wdev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *i
|
|||
goto sdio_release;
|
||||
}
|
||||
|
||||
bus->core->poll_irq = !!bus->of_irq;
|
||||
ret = wfx_probe(bus->core);
|
||||
if (ret)
|
||||
goto sdio_release;
|
||||
|
|
|
|||
|
|
@ -362,7 +362,6 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
*/
|
||||
gpio_saved = wdev->pdata.gpio_wakeup;
|
||||
wdev->pdata.gpio_wakeup = NULL;
|
||||
wdev->poll_irq = true;
|
||||
|
||||
wdev->bh_wq = alloc_workqueue("wfx_bh_wq", WQ_HIGHPRI | WQ_PERCPU, 0);
|
||||
if (!wdev->bh_wq)
|
||||
|
|
@ -370,16 +369,24 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
|
||||
wfx_bh_register(wdev);
|
||||
|
||||
if (!wdev->poll_irq) {
|
||||
err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
|
||||
if (err)
|
||||
goto bh_unregister;
|
||||
}
|
||||
|
||||
err = wfx_init_device(wdev);
|
||||
if (err)
|
||||
goto bh_unregister;
|
||||
goto irq_unsubscribe;
|
||||
|
||||
if (wdev->poll_irq)
|
||||
wfx_bh_poll_irq(wdev);
|
||||
|
||||
wfx_bh_poll_irq(wdev);
|
||||
err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ);
|
||||
if (err == 0) {
|
||||
dev_err(wdev->dev, "timeout while waiting for startup indication\n");
|
||||
err = -ETIMEDOUT;
|
||||
goto bh_unregister;
|
||||
goto irq_unsubscribe;
|
||||
}
|
||||
|
||||
/* FIXME: fill wiphy::hw_version */
|
||||
|
|
@ -399,12 +406,13 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
dev_err(wdev->dev, "unsupported firmware API version (expect 1 while firmware returns %d)\n",
|
||||
wdev->hw_caps.api_version_major);
|
||||
err = -EOPNOTSUPP;
|
||||
goto bh_unregister;
|
||||
goto irq_unsubscribe;
|
||||
}
|
||||
|
||||
if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) {
|
||||
dev_err(wdev->dev, "chip require secure_link, but can't negotiate it\n");
|
||||
goto bh_unregister;
|
||||
err = -EOPNOTSUPP;
|
||||
goto irq_unsubscribe;
|
||||
}
|
||||
|
||||
if (wdev->hw_caps.region_sel_mode) {
|
||||
|
|
@ -420,12 +428,14 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds);
|
||||
err = wfx_send_pdata_pds(wdev);
|
||||
if (err < 0 && err != -ENOENT)
|
||||
goto bh_unregister;
|
||||
goto irq_unsubscribe;
|
||||
|
||||
wdev->poll_irq = false;
|
||||
err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
|
||||
if (err)
|
||||
goto bh_unregister;
|
||||
if (wdev->poll_irq) {
|
||||
err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv);
|
||||
if (err)
|
||||
goto bh_unregister;
|
||||
wdev->poll_irq = false;
|
||||
}
|
||||
|
||||
err = wfx_hif_use_multi_tx_conf(wdev, true);
|
||||
if (err)
|
||||
|
|
@ -474,9 +484,11 @@ int wfx_probe(struct wfx_dev *wdev)
|
|||
ieee80211_unregister:
|
||||
ieee80211_unregister_hw(wdev->hw);
|
||||
irq_unsubscribe:
|
||||
wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
|
||||
if (!wdev->poll_irq)
|
||||
wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
|
||||
bh_unregister:
|
||||
wfx_bh_unregister(wdev);
|
||||
cancel_delayed_work_sync(&wdev->cooling_timeout_work);
|
||||
destroy_workqueue(wdev->bh_wq);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -487,6 +499,7 @@ void wfx_release(struct wfx_dev *wdev)
|
|||
wfx_hif_shutdown(wdev);
|
||||
wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv);
|
||||
wfx_bh_unregister(wdev);
|
||||
cancel_delayed_work_sync(&wdev->cooling_timeout_work);
|
||||
destroy_workqueue(wdev->bh_wq);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
|
||||
* Copyright (C) 2020, 2022-2025 Intel Corporation
|
||||
* Copyright (C) 2020, 2022-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __MAC80211_HWSIM_H
|
||||
|
|
@ -162,6 +162,8 @@ enum hwsim_commands {
|
|||
* each radio instead of for the wiphy.
|
||||
* @HWSIM_ATTR_SUPPORT_NAN_DEVICE: support NAN Device virtual interface (flag)
|
||||
* @HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR: background radar/CAC support (flag)
|
||||
* @HWSIM_ATTR_NO_MONITOR: skip monitor report for this TX status, e.g. in case
|
||||
* the frame was never reported to any receiver (flag)
|
||||
* @__HWSIM_ATTR_MAX: enum limit
|
||||
*/
|
||||
enum hwsim_attrs {
|
||||
|
|
@ -197,6 +199,7 @@ enum hwsim_attrs {
|
|||
HWSIM_ATTR_MULTI_RADIO,
|
||||
HWSIM_ATTR_SUPPORT_NAN_DEVICE,
|
||||
HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR,
|
||||
HWSIM_ATTR_NO_MONITOR,
|
||||
__HWSIM_ATTR_MAX,
|
||||
};
|
||||
#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
|
||||
|
|
|
|||
|
|
@ -895,6 +895,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
|
|||
[HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG },
|
||||
[HWSIM_ATTR_SUPPORT_NAN_DEVICE] = { .type = NLA_FLAG },
|
||||
[HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR] = { .type = NLA_FLAG },
|
||||
[HWSIM_ATTR_NO_MONITOR] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_VIRTIO)
|
||||
|
|
@ -1337,7 +1338,7 @@ mac80211_hwsim_get_tx_rate(struct ieee80211_hw *hw,
|
|||
|
||||
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *tx_skb,
|
||||
struct ieee80211_channel *chan)
|
||||
u32 freq)
|
||||
{
|
||||
struct mac80211_hwsim_data *data = hw->priv;
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -1369,7 +1370,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
|||
hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);
|
||||
hdr->rt_flags = 0;
|
||||
hdr->rt_rate = bitrate / 5;
|
||||
hdr->rt_channel = cpu_to_le16(chan->center_freq);
|
||||
hdr->rt_channel = cpu_to_le16(freq);
|
||||
flags = IEEE80211_CHAN_2GHZ;
|
||||
if (txrate && txrate->flags & IEEE80211_RATE_ERP_G)
|
||||
flags |= IEEE80211_CHAN_OFDM;
|
||||
|
|
@ -1387,8 +1388,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
|
||||
static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
|
||||
const u8 *addr)
|
||||
static void mac80211_hwsim_monitor_ack(u32 freq, const u8 *addr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct hwsim_radiotap_ack_hdr *hdr;
|
||||
|
|
@ -1410,7 +1410,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
|
|||
(1 << IEEE80211_RADIOTAP_CHANNEL));
|
||||
hdr->rt_flags = 0;
|
||||
hdr->pad = 0;
|
||||
hdr->rt_channel = cpu_to_le16(chan->center_freq);
|
||||
hdr->rt_channel = cpu_to_le16(freq);
|
||||
flags = IEEE80211_CHAN_2GHZ;
|
||||
hdr->rt_chbitmask = cpu_to_le16(flags);
|
||||
|
||||
|
|
@ -1735,6 +1735,9 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
|
|||
if (nla_put_u64_64bit(skb, HWSIM_ATTR_COOKIE, cookie, HWSIM_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* track the frequency */
|
||||
info->rate_driver_data[1] = (void *)(uintptr_t)channel->center_freq;
|
||||
|
||||
genlmsg_end(skb, msg_head);
|
||||
|
||||
if (hwsim_virtio_enabled) {
|
||||
|
|
@ -1880,9 +1883,6 @@ static void mac80211_hwsim_rx(struct mac80211_hwsim_data *data,
|
|||
sp->active_links_rx &= ~BIT(link_id);
|
||||
else
|
||||
sp->active_links_rx |= BIT(link_id);
|
||||
|
||||
rx_status->link_valid = true;
|
||||
rx_status->link_id = link_id;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
@ -1912,7 +1912,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
|
|||
|
||||
mac80211_hwsim_write_tsf(data, skb, sim_tsf);
|
||||
|
||||
mac80211_hwsim_monitor_rx(hw, skb, chan);
|
||||
mac80211_hwsim_monitor_rx(hw, skb, chan->center_freq);
|
||||
|
||||
memset(&rx_status, 0, sizeof(rx_status));
|
||||
rx_status.flag |= RX_FLAG_MACTIME_START;
|
||||
|
|
@ -2276,7 +2276,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
|||
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
||||
|
||||
if (ack && skb->len >= 16)
|
||||
mac80211_hwsim_monitor_ack(channel, hdr->addr2);
|
||||
mac80211_hwsim_monitor_ack(channel->center_freq, hdr->addr2);
|
||||
|
||||
ieee80211_tx_info_clear_status(txi);
|
||||
|
||||
|
|
@ -4401,15 +4401,15 @@ struct hwsim_new_radio_params {
|
|||
bool background_radar;
|
||||
};
|
||||
|
||||
static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
|
||||
static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, struct net *net,
|
||||
struct genl_info *info)
|
||||
{
|
||||
if (info)
|
||||
genl_notify(&hwsim_genl_family, mcast_skb, info,
|
||||
HWSIM_MCGRP_CONFIG, GFP_KERNEL);
|
||||
else
|
||||
genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
|
||||
HWSIM_MCGRP_CONFIG, GFP_KERNEL);
|
||||
genlmsg_multicast_netns(&hwsim_genl_family, net, mcast_skb, 0,
|
||||
HWSIM_MCGRP_CONFIG, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int append_radio_msg(struct sk_buff *skb, int id,
|
||||
|
|
@ -4493,7 +4493,8 @@ static int append_radio_msg(struct sk_buff *skb, int id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hwsim_mcast_new_radio(int id, struct genl_info *info,
|
||||
static void hwsim_mcast_new_radio(int id, struct net *net,
|
||||
struct genl_info *info,
|
||||
struct hwsim_new_radio_params *param)
|
||||
{
|
||||
struct sk_buff *mcast_skb;
|
||||
|
|
@ -4513,7 +4514,7 @@ static void hwsim_mcast_new_radio(int id, struct genl_info *info,
|
|||
|
||||
genlmsg_end(mcast_skb, data);
|
||||
|
||||
hwsim_mcast_config_msg(mcast_skb, info);
|
||||
hwsim_mcast_config_msg(mcast_skb, net, info);
|
||||
return;
|
||||
|
||||
out_err:
|
||||
|
|
@ -6195,7 +6196,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
hwsim_radios_generation++;
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
|
||||
hwsim_mcast_new_radio(idx, info, param);
|
||||
hwsim_mcast_new_radio(idx, wiphy_net(data->hw->wiphy), info, param);
|
||||
|
||||
return idx;
|
||||
|
||||
|
|
@ -6213,7 +6214,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
}
|
||||
|
||||
static void hwsim_mcast_del_radio(int id, const char *hwname,
|
||||
struct genl_info *info)
|
||||
struct net *net, struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
void *data;
|
||||
|
|
@ -6239,7 +6240,7 @@ static void hwsim_mcast_del_radio(int id, const char *hwname,
|
|||
|
||||
genlmsg_end(skb, data);
|
||||
|
||||
hwsim_mcast_config_msg(skb, info);
|
||||
hwsim_mcast_config_msg(skb, net, info);
|
||||
|
||||
return;
|
||||
|
||||
|
|
@ -6251,7 +6252,7 @@ static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
|
|||
const char *hwname,
|
||||
struct genl_info *info)
|
||||
{
|
||||
hwsim_mcast_del_radio(data->idx, hwname, info);
|
||||
hwsim_mcast_del_radio(data->idx, hwname, wiphy_net(data->hw->wiphy), info);
|
||||
debugfs_remove_recursive(data->debugfs);
|
||||
ieee80211_unregister_hw(data->hw);
|
||||
device_release_driver(data->dev);
|
||||
|
|
@ -6396,6 +6397,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
|||
int i;
|
||||
unsigned long flags;
|
||||
bool found = false;
|
||||
bool no_monitor;
|
||||
u32 freq;
|
||||
|
||||
if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
|
||||
!info->attrs[HWSIM_ATTR_FLAGS] ||
|
||||
|
|
@ -6407,6 +6410,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
|||
src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
|
||||
hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
|
||||
ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
|
||||
no_monitor = nla_get_flag(info->attrs[HWSIM_ATTR_NO_MONITOR]);
|
||||
|
||||
data2 = get_hwsim_data_ref_from_addr(src);
|
||||
if (!data2)
|
||||
|
|
@ -6441,7 +6445,11 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
|||
if (!found)
|
||||
goto out;
|
||||
|
||||
mac80211_hwsim_monitor_rx(data2->hw, skb, data2->channel);
|
||||
txi = IEEE80211_SKB_CB(skb);
|
||||
freq = (uintptr_t)txi->rate_driver_data[1];
|
||||
|
||||
if (!no_monitor)
|
||||
mac80211_hwsim_monitor_rx(data2->hw, skb, freq);
|
||||
|
||||
/* Tx info received because the frame was broadcasted on user space,
|
||||
so we get all the necessary info: tx attempts and skb control buff */
|
||||
|
|
@ -6450,8 +6458,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
|||
info->attrs[HWSIM_ATTR_TX_INFO]);
|
||||
|
||||
/* now send back TX status */
|
||||
txi = IEEE80211_SKB_CB(skb);
|
||||
|
||||
ieee80211_tx_info_clear_status(txi);
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
|
|
@ -6471,8 +6477,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
|||
if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) &&
|
||||
(hwsim_flags & HWSIM_TX_STAT_ACK)) {
|
||||
if (skb->len >= 16)
|
||||
mac80211_hwsim_monitor_ack(data2->channel,
|
||||
hdr->addr2);
|
||||
mac80211_hwsim_monitor_ack(freq, hdr->addr2);
|
||||
txi->flags |= IEEE80211_TX_STAT_ACK;
|
||||
}
|
||||
|
||||
|
|
@ -6547,6 +6552,51 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
*/
|
||||
mutex_lock(&data2->mutex);
|
||||
|
||||
/* look for the skb matching the cookie passed back from user */
|
||||
if (info->attrs[HWSIM_ATTR_COOKIE] &&
|
||||
info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) {
|
||||
u64 cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
|
||||
struct sk_buff *orig_skb, *found = NULL;
|
||||
struct mac80211_hwsim_data *txdata;
|
||||
struct ieee80211_tx_info *txi;
|
||||
const u8 *transmitter;
|
||||
unsigned long flags;
|
||||
|
||||
transmitter = nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
|
||||
txdata = get_hwsim_data_ref_from_addr(transmitter);
|
||||
if (!txdata || txdata->netgroup != data2->netgroup)
|
||||
goto out_unlock;
|
||||
|
||||
spin_lock_irqsave(&txdata->pending.lock, flags);
|
||||
skb_queue_walk(&txdata->pending, orig_skb) {
|
||||
uintptr_t skb_cookie;
|
||||
|
||||
txi = IEEE80211_SKB_CB(orig_skb);
|
||||
skb_cookie = (uintptr_t)txi->rate_driver_data[0];
|
||||
|
||||
if (skb_cookie == cookie) {
|
||||
found = orig_skb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* that's weird */
|
||||
if (!found) {
|
||||
spin_unlock_irqrestore(&txdata->pending.lock, flags);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (frame_data_len > found->len &&
|
||||
pskb_expand_head(found, 0, frame_data_len - found->len,
|
||||
GFP_ATOMIC)) {
|
||||
spin_unlock_irqrestore(&txdata->pending.lock, flags);
|
||||
goto out_unlock;
|
||||
}
|
||||
skb_trim(found, 0);
|
||||
skb_put_data(found, frame_data, frame_data_len);
|
||||
spin_unlock_irqrestore(&txdata->pending.lock, flags);
|
||||
}
|
||||
|
||||
/* check if radio is configured properly */
|
||||
|
||||
if ((data2->idle && !data2->tmp_chan) || !data2->started)
|
||||
|
|
|
|||
|
|
@ -482,6 +482,7 @@ struct ieee80211_multi_link_elem {
|
|||
#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200
|
||||
#define IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP 0x0400
|
||||
#define IEEE80211_MLC_BASIC_PRES_ENH_CRIT_UPD 0x0800
|
||||
#define IEEE80211_MLC_BASIC_PRES_AGE_OF_BSS_LOAD 0x1000
|
||||
|
||||
#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff
|
||||
#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00
|
||||
|
|
@ -550,6 +551,8 @@ struct ieee80211_mle_basic_common_info {
|
|||
} __packed;
|
||||
|
||||
#define IEEE80211_MLC_PREQ_PRES_MLD_ID 0x0010
|
||||
#define IEEE80211_MLC_PREQ_PRES_MLD_MAC_ADDR 0x0020
|
||||
#define IEEE80211_MLC_PREQ_PRES_NEIGH_AP_MLD_MAC_ADDR 0x0040
|
||||
|
||||
struct ieee80211_mle_preq_common_info {
|
||||
u8 len;
|
||||
|
|
@ -560,6 +563,7 @@ struct ieee80211_mle_preq_common_info {
|
|||
#define IEEE80211_MLC_RECONF_PRES_EML_CAPA 0x0020
|
||||
#define IEEE80211_MLC_RECONF_PRES_MLD_CAPA_OP 0x0040
|
||||
#define IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP 0x0080
|
||||
#define IEEE80211_MLC_RECONF_PRES_TARGET_AP_MLD_ADDR 0x0100
|
||||
|
||||
/* no fixed fields in RECONF */
|
||||
|
||||
|
|
@ -766,7 +770,7 @@ static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data)
|
|||
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_NSTR_UPDATE 0x0020
|
||||
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_EMLSR_ENA_ON_ONE_LINK 0x0040
|
||||
#define IEEE80211_EHT_ML_EXT_MLD_CAPA_BTM_MLD_RECO_MULTI_AP 0x0080
|
||||
/* defined by UHR Draft P802.11bn_D1.3 Figure 9-1147 */
|
||||
/* defined by UHR Draft P802.11bn_D1.5 Figure 9-1168 */
|
||||
#define IEEE80211_UHR_ML_EXT_MLD_CAPA_ML_PM 0x0100
|
||||
|
||||
/**
|
||||
|
|
@ -928,11 +932,17 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
common += 2;
|
||||
if (control & IEEE80211_MLC_BASIC_PRES_ENH_CRIT_UPD)
|
||||
common += 1;
|
||||
if (control & IEEE80211_MLC_BASIC_PRES_AGE_OF_BSS_LOAD)
|
||||
common += 1;
|
||||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_PREQ:
|
||||
common += sizeof(struct ieee80211_mle_preq_common_info);
|
||||
if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID)
|
||||
common += 1;
|
||||
if (control & IEEE80211_MLC_PREQ_PRES_MLD_MAC_ADDR)
|
||||
common += ETH_ALEN;
|
||||
if (control & IEEE80211_MLC_PREQ_PRES_NEIGH_AP_MLD_MAC_ADDR)
|
||||
common += ETH_ALEN;
|
||||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_RECONF:
|
||||
common += 1;
|
||||
|
|
@ -944,6 +954,8 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
common += 2;
|
||||
if (control & IEEE80211_MLC_RECONF_PRES_EXT_MLD_CAPA_OP)
|
||||
common += 2;
|
||||
if (control & IEEE80211_MLC_RECONF_PRES_TARGET_AP_MLD_ADDR)
|
||||
common += ETH_ALEN;
|
||||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_TDLS:
|
||||
common += sizeof(struct ieee80211_mle_tdls_common_info);
|
||||
|
|
@ -1003,6 +1015,7 @@ enum ieee80211_mle_subelems {
|
|||
#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800
|
||||
#define IEEE80211_MLE_STA_CONTROL_ENH_CRIT_UPD_PRESENT 0x1000
|
||||
#define IEEE80211_MLE_STA_CONTROL_AP_CONDUCTED_TX_PWR_PRESENT 0x2000
|
||||
#define IEEE80211_MLE_STA_CONTROL_AGE_OF_BSS_LOAD_PRESENT 0x4000
|
||||
|
||||
struct ieee80211_mle_per_sta_profile {
|
||||
__le16 control;
|
||||
|
|
@ -1054,6 +1067,9 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data,
|
|||
if (control & IEEE80211_MLE_STA_CONTROL_AP_CONDUCTED_TX_PWR_PRESENT)
|
||||
info_len += 1;
|
||||
|
||||
if (control & IEEE80211_MLE_STA_CONTROL_AGE_OF_BSS_LOAD_PRESENT)
|
||||
info_len += 1;
|
||||
|
||||
return prof->sta_info_len >= info_len &&
|
||||
fixed + prof->sta_info_len - 1 <= len;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,32 +17,32 @@
|
|||
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_ENA 0x0004
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DBE_ENA 0x0008
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DBE_BW 0x0070
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DUO_PRES 0x0080
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DPS_PRES 0x0100
|
||||
#define IEEE80211_UHR_OPER_PARAMS_NPCA_PRES 0x0200
|
||||
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES 0x0400
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DBE_PRES 0x0800
|
||||
#define IEEE80211_UHR_OPER_PARAMS_ELR_RX 0x0080
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DUO_PRES 0x0100
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DPS_PRES 0x0200
|
||||
#define IEEE80211_UHR_OPER_PARAMS_NPCA_PRES 0x0400
|
||||
#define IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES 0x0800
|
||||
#define IEEE80211_UHR_OPER_PARAMS_DBE_PRES 0x1000
|
||||
|
||||
struct ieee80211_uhr_operation {
|
||||
__le16 params;
|
||||
u8 basic_mcs_nss_set[4];
|
||||
u8 variable[];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_PRIMARY_CHAN_OFFS 0x0000000F
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_MIN_DUR_THRESH 0x000000F0
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_DELAY 0x00003F00
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_BACK_DELAY 0x000FC000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_INIT_QSRC 0x00300000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_MOPLEN 0x00400000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES 0x00800000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_PRIMARY_CHAN 0x000000FF
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_MIN_DUR_THRESH 0x00000F00
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_DELAY 0x0003F000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_SWITCH_BACK_DELAY 0x00FC0000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_INIT_QSRC 0x03000000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_MOPLEN 0x04000000
|
||||
#define IEEE80211_UHR_NPCA_PARAMS_DIS_SUBCH_BMAP_PRES 0x08000000
|
||||
|
||||
/**
|
||||
* struct ieee80211_uhr_npca_info - npca operation information
|
||||
*
|
||||
* This structure is the "NPCA Operation Parameters field format" of "UHR
|
||||
* Operation Element" fields as described in P802.11bn_D1.3
|
||||
* subclause 9.4.2.353. See Figure 9-aa4.
|
||||
* Operation Element" fields as described in P802.11bn_D1.5
|
||||
* subclause 9.4.2.355.2, see Figure 9-aa6.
|
||||
*
|
||||
* Refer to IEEE80211_UHR_NPCA*
|
||||
* @params:
|
||||
|
|
@ -97,7 +97,7 @@ struct ieee80211_uhr_npca_info {
|
|||
* struct ieee80211_uhr_dps_info - DPS operation information
|
||||
*
|
||||
* This structure is the "DPS Operation Parameter field" of "UHR
|
||||
* Operation Element" fields as described in P802.11bn_D1.3
|
||||
* Operation Element" fields as described in P802.11bn_D1.5
|
||||
* subclause 9.4.1.87. See Figure 9-207u.
|
||||
*
|
||||
* Refer to IEEE80211_UHR_DPS*
|
||||
|
|
@ -211,8 +211,8 @@ static inline int ieee80211_uhr_dbe_bw_mhz(enum ieee80211_uhr_dbe_oper_bw bw)
|
|||
* struct ieee80211_uhr_dbe_info - DBE operation information
|
||||
*
|
||||
* This structure is the "DBE Operation Parameters field" of
|
||||
* "UHR Operation Element" fields as described in P802.11bn_D1.3
|
||||
* subclause 9.4.2.353. See Figure 9-aa6.
|
||||
* "UHR Operation Element" fields as described in P802.11bn_D1.5
|
||||
* subclause 9.4.2.355.4, see Figure 9-aa9.
|
||||
*
|
||||
* Refer to IEEE80211_UHR_DBE_OPER*
|
||||
* @params:
|
||||
|
|
@ -234,25 +234,23 @@ struct ieee80211_uhr_dbe_info {
|
|||
__le16 dis_subch_bmap[];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_UHR_P_EDCA_ECWMIN 0x0F
|
||||
#define IEEE80211_UHR_P_EDCA_ECWMAX 0xF0
|
||||
#define IEEE80211_UHR_P_EDCA_AIFSN 0x000F
|
||||
#define IEEE80211_UHR_P_EDCA_CW_DS 0x0030
|
||||
#define IEEE80211_UHR_P_EDCA_PSRC_THRESHOLD 0x01C0
|
||||
#define IEEE80211_UHR_P_EDCA_QSRC_THRESHOLD 0x0600
|
||||
#define IEEE80211_UHR_P_EDCA_ECWMIN 0x0007
|
||||
#define IEEE80211_UHR_P_EDCA_ECWMAX 0x0038
|
||||
#define IEEE80211_UHR_P_EDCA_AIFSN 0x01C0
|
||||
#define IEEE80211_UHR_P_EDCA_CW_DS 0x0600
|
||||
#define IEEE80211_UHR_P_EDCA_PSRC_THRESHOLD 0x3800
|
||||
#define IEEE80211_UHR_P_EDCA_QSRC_THRESHOLD 0xC000
|
||||
|
||||
/**
|
||||
* struct ieee80211_uhr_p_edca_info - P-EDCA operation information
|
||||
*
|
||||
* This structure is the "P-EDCA Operation Parameters field" of
|
||||
* "UHR Operation Element" fields as described in P802.11bn_D1.3
|
||||
* subclause 9.4.2.353. See Figure 9-aa5.
|
||||
* "UHR Operation Element" fields as described in P802.11bn_D1.5
|
||||
* subclause 9.4.2.355.3, see Figure 9-aa8.
|
||||
*
|
||||
* Refer to IEEE80211_UHR_P_EDCA*
|
||||
* @p_edca_ec: P-EDCA ECWmin and ECWmax.
|
||||
* These fields indicate the CWmin and CWmax values used by a
|
||||
* P-EDCA STA during P-EDCA contention.
|
||||
* @params: AIFSN, CW DS, PSRC threshold, and QSRC threshold.
|
||||
* @params: ECWmin, ECWmax, AIFSN, CW DS, PSRC threshold, and QSRC threshold.
|
||||
* - CWmin/CWmax values used by a P-EDCA STA during P-EDCA contention.
|
||||
* - The AIFSN field indicates the AIFSN value used by a P-EDCA STA
|
||||
* during P-EDCA contention.
|
||||
* - The CW DS field indicates the value used for randomization of the
|
||||
|
|
@ -266,7 +264,6 @@ struct ieee80211_uhr_dbe_info {
|
|||
* value 0 is reserved.
|
||||
*/
|
||||
struct ieee80211_uhr_p_edca_info {
|
||||
u8 p_edca_ec;
|
||||
__le16 params;
|
||||
} __packed;
|
||||
|
||||
|
|
@ -302,7 +299,7 @@ static inline bool ieee80211_uhr_oper_size_ok(const u8 *data, u8 len)
|
|||
}
|
||||
}
|
||||
|
||||
/* P-EDCA Operation Parameters (fixed 3 bytes) */
|
||||
/* P-EDCA Operation Parameters */
|
||||
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_PEDCA_PRES)) {
|
||||
needed += sizeof(struct ieee80211_uhr_p_edca_info);
|
||||
if (len < needed)
|
||||
|
|
@ -341,6 +338,9 @@ ieee80211_uhr_npca_info(const struct ieee80211_uhr_operation *oper)
|
|||
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_NPCA_ENA)))
|
||||
return NULL;
|
||||
|
||||
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DUO_PRES))
|
||||
pos += 1;
|
||||
|
||||
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
|
||||
pos += sizeof(struct ieee80211_uhr_dps_info);
|
||||
|
||||
|
|
@ -372,6 +372,9 @@ ieee80211_uhr_oper_dbe_info(const struct ieee80211_uhr_operation *oper)
|
|||
if (!(oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DBE_ENA)))
|
||||
return NULL;
|
||||
|
||||
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DUO_PRES))
|
||||
pos += 1;
|
||||
|
||||
if (oper->params & cpu_to_le16(IEEE80211_UHR_OPER_PARAMS_DPS_PRES))
|
||||
pos += sizeof(struct ieee80211_uhr_dps_info);
|
||||
|
||||
|
|
@ -415,28 +418,42 @@ ieee80211_uhr_oper_dbe_info(const struct ieee80211_uhr_operation *oper)
|
|||
#define IEEE80211_UHR_MAC_CAP2_UHR_OM_PU_TO_LOW 0xC0
|
||||
|
||||
#define IEEE80211_UHR_MAC_CAP3_UHR_OM_PU_TO_HIGH 0x03
|
||||
#define IEEE80211_UHR_MAC_CAP3_PARAM_UPD_ADV_NOTIF_INTV 0x1C
|
||||
#define IEEE80211_UHR_MAC_CAP3_UPD_IND_TIM_INTV_LOW 0xE0
|
||||
#define IEEE80211_UHR_MAC_CAP3_PARAM_UPD_ADV_NOTIF_INTV 0x7C
|
||||
#define IEEE80211_UHR_MAC_CAP3_UPD_IND_TIM_INTV_LOW 0x80
|
||||
|
||||
#define IEEE80211_UHR_MAC_CAP4_UPD_IND_TIM_INTV_HIGH 0x03
|
||||
#define IEEE80211_UHR_MAC_CAP4_BOUNDED_ESS 0x04
|
||||
#define IEEE80211_UHR_MAC_CAP4_BTM_ASSURANCE 0x08
|
||||
#define IEEE80211_UHR_MAC_CAP4_CO_BF_SUPP 0x10
|
||||
#define IEEE80211_UHR_MAC_CAP4_UPD_IND_TIM_INTV_HIGH 0x0F
|
||||
#define IEEE80211_UHR_MAC_CAP4_BOUNDED_ESS 0x10
|
||||
#define IEEE80211_UHR_MAC_CAP4_BTM_ASSURANCE 0x20
|
||||
#define IEEE80211_UHR_MAC_CAP4_CO_BF_SUPP 0x40
|
||||
#define IEEE80211_UHR_MAC_CAP4_CO_SR_SUPP 0x80
|
||||
|
||||
#define IEEE80211_UHR_MAC_CAP5_MAPC_ENH_MSRMT_SUPP 0x01
|
||||
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_MAX_BW 0x07
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_160_PRES 0x08
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_320_PRES 0x10
|
||||
|
||||
/* struct ieee80211_uhr_cap_dbe::bwcap[].cap */
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_CAP_NUM_SND_DIMS 0x07
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_CAP_NON_OFDMA_UL_MUMIMO 0x08
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_CAP_MU_BEAMFORMER 0x10
|
||||
#define IEEE80211_UHR_MAC_CAP_DBE_CAP_BEAMFORMEE_SS 0xe0
|
||||
|
||||
struct ieee80211_uhr_cap_dbe {
|
||||
u8 cap;
|
||||
u8 max_switch_time_period;
|
||||
u8 mode_change_intvl;
|
||||
/* present 0, 1 or 2 times depending on _PRES bits */
|
||||
struct ieee80211_eht_mcs_nss_supp_bw eht_mcs_map[];
|
||||
struct {
|
||||
struct ieee80211_eht_mcs_nss_supp_bw eht_mcs_map;
|
||||
u8 cap;
|
||||
} __packed bwcap[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum ieee80211_uhr_dbe_max_supported_bw - DBE Maximum Supported Bandwidth
|
||||
*
|
||||
* As per spec P802.11bn_D1.3 "Table 9-bb5—Encoding of the DBE Maximum
|
||||
* As per spec P802.11bn_D1.5 Table 9-bb8 "Encoding of the DBE Maximum
|
||||
* Supported Bandwidth field".
|
||||
*
|
||||
* @IEEE80211_UHR_DBE_MAX_BW_40: Indicates 40 MHz DBE max supported bw
|
||||
|
|
@ -520,10 +537,10 @@ static inline bool ieee80211_uhr_capa_size_ok(const u8 *data, u8 len,
|
|||
dbe = (const void *)cap->variable;
|
||||
|
||||
if (dbe->cap & IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_160_PRES)
|
||||
needed += sizeof(dbe->eht_mcs_map[0]);
|
||||
needed += sizeof(dbe->bwcap[0]);
|
||||
|
||||
if (dbe->cap & IEEE80211_UHR_MAC_CAP_DBE_EHT_MCS_MAP_320_PRES)
|
||||
needed += sizeof(dbe->eht_mcs_map[0]);
|
||||
needed += sizeof(dbe->bwcap[0]);
|
||||
}
|
||||
|
||||
return len >= needed;
|
||||
|
|
|
|||
|
|
@ -2421,8 +2421,7 @@ static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb)
|
|||
|
||||
/* action frame - additionally check for non-bufferable FTM */
|
||||
|
||||
if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
|
||||
mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION)
|
||||
if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
|
||||
return true;
|
||||
|
||||
if (mgmt->u.action.action_code == WLAN_PUB_ACTION_FTM_REQUEST ||
|
||||
|
|
|
|||
|
|
@ -576,7 +576,6 @@ struct ieee80211_sta_s1g_cap {
|
|||
* @vht_cap: VHT capabilities in this band
|
||||
* @s1g_cap: S1G capabilities in this band
|
||||
* @edmg_cap: EDMG capabilities in this band
|
||||
* @s1g_cap: S1G capabilities in this band (S1G band only, of course)
|
||||
* @n_iftype_data: number of iftype data entries
|
||||
* @iftype_data: interface type data entries. Note that the bits in
|
||||
* @types_mask inside this structure cannot overlap (i.e. only
|
||||
|
|
@ -901,6 +900,7 @@ struct cfg80211_bitrate_mask {
|
|||
enum nl80211_eht_gi eht_gi;
|
||||
enum nl80211_he_ltf he_ltf;
|
||||
enum nl80211_eht_ltf eht_ltf;
|
||||
bool nonht_dup_6ghz;
|
||||
} control[NUM_NL80211_BANDS];
|
||||
};
|
||||
|
||||
|
|
@ -4009,6 +4009,7 @@ struct cfg80211_update_ft_ies_params {
|
|||
* @link_id: for MLO, the link ID to transmit on, -1 if not given; note
|
||||
* that the link ID isn't validated (much), it's in range but the
|
||||
* link might not exist (or be used by the receiver STA)
|
||||
* @no_sta: set if the frame should not be transmitted using an existing STA
|
||||
*/
|
||||
struct cfg80211_mgmt_tx_params {
|
||||
struct ieee80211_channel *chan;
|
||||
|
|
@ -4021,6 +4022,7 @@ struct cfg80211_mgmt_tx_params {
|
|||
int n_csa_offsets;
|
||||
const u16 *csa_offsets;
|
||||
int link_id;
|
||||
bool no_sta;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -9501,6 +9503,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
|
|||
* @flags: flags, as defined in &enum nl80211_rxmgmt_flags
|
||||
* @rx_tstamp: Hardware timestamp of frame RX in nanoseconds
|
||||
* @ack_tstamp: Hardware timestamp of ack TX in nanoseconds
|
||||
* @no_sta: set if no station is known for the frame (relevant for MLD)
|
||||
*/
|
||||
struct cfg80211_rx_info {
|
||||
int freq;
|
||||
|
|
@ -9512,6 +9515,7 @@ struct cfg80211_rx_info {
|
|||
u32 flags;
|
||||
u64 rx_tstamp;
|
||||
u64 ack_tstamp;
|
||||
bool no_sta;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ enum ieee80211_radiotap_presence {
|
|||
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
|
||||
IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
|
||||
IEEE80211_RADIOTAP_EXT = 31,
|
||||
IEEE80211_RADIOTAP_S1G = 32,
|
||||
IEEE80211_RADIOTAP_EHT_USIG = 33,
|
||||
IEEE80211_RADIOTAP_EHT = 34,
|
||||
IEEE80211_RADIOTAP_UHR_ELR = 37,
|
||||
|
|
@ -112,6 +113,9 @@ enum ieee80211_radiotap_flags {
|
|||
|
||||
/* for IEEE80211_RADIOTAP_CHANNEL */
|
||||
enum ieee80211_radiotap_channel_flags {
|
||||
IEEE80211_CHAN_700MHZ = 0x0001,
|
||||
IEEE80211_CHAN_800MHZ = 0x0002,
|
||||
IEEE80211_CHAN_900MHZ = 0x0004,
|
||||
IEEE80211_CHAN_CCK = 0x0020,
|
||||
IEEE80211_CHAN_OFDM = 0x0040,
|
||||
IEEE80211_CHAN_2GHZ = 0x0080,
|
||||
|
|
@ -592,7 +596,7 @@ enum ieee80211_radiotap_eht_usig_mu {
|
|||
|
||||
enum ieee80211_radiotap_eht_usig_tb {
|
||||
/* TB-USIG-1 */
|
||||
IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD = 0x0000001f,
|
||||
IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD = 0x0000003f,
|
||||
|
||||
/* TB-USIG-2 */
|
||||
IEEE80211_RADIOTAP_EHT_USIG2_TB_B0_B1_PPDU_TYPE = 0x000000c0,
|
||||
|
|
@ -792,6 +796,68 @@ enum ieee80211_radiotap_uhr_user_info {
|
|||
IEEE80211_RADIOTAP_UHR_USER_INFO_2X_LDPC = 0x02000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* ieee80211_radiotap_s1g - content of S1G TLV (type 32)
|
||||
* see www.radiotap.org/fields/S1G.html for details
|
||||
*/
|
||||
struct ieee80211_radiotap_s1g {
|
||||
__le16 known;
|
||||
__le16 data1;
|
||||
__le16 data2;
|
||||
} __packed;
|
||||
|
||||
enum ieee80211_radiotap_s1g_known {
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_PPDU_FORMAT = 0x0001,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_RESPONSE_IND = 0x0002,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_GI = 0x0004,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_NSS = 0x0008,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_BW = 0x0010,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_MCS = 0x0020,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_COLOR = 0x0040,
|
||||
IEEE80211_RADIOTAP_S1G_KNOWN_UPLINK_IND = 0x0080,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_data1 {
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_PPDU_FORMAT = 0x0003,
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_RESPONSE_IND = 0x000c,
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_GI = 0x0020,
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_NSS = 0x00c0,
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_BW = 0x0f00,
|
||||
IEEE80211_RADIOTAP_S1G_DATA1_MCS = 0xf000,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_data2 {
|
||||
IEEE80211_RADIOTAP_S1G_DATA2_COLOR = 0x0007,
|
||||
IEEE80211_RADIOTAP_S1G_DATA2_UPLINK_IND = 0x0008,
|
||||
IEEE80211_RADIOTAP_S1G_DATA2_RSSI = 0xff00,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_ppdu_format {
|
||||
IEEE80211_RADIOTAP_S1G_PPDU_FORMAT_1M = 0,
|
||||
IEEE80211_RADIOTAP_S1G_PPDU_FORMAT_SHORT = 1,
|
||||
IEEE80211_RADIOTAP_S1G_PPDU_FORMAT_LONG = 2,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_response_ind {
|
||||
IEEE80211_RADIOTAP_S1G_RESPONSE_IND_NONE = 0,
|
||||
IEEE80211_RADIOTAP_S1G_RESPONSE_IND_NDP = 1,
|
||||
IEEE80211_RADIOTAP_S1G_RESPONSE_IND_NORMAL = 2,
|
||||
IEEE80211_RADIOTAP_S1G_RESPONSE_IND_LONG = 3,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_gi {
|
||||
IEEE80211_RADIOTAP_S1G_GI_LONG = 0,
|
||||
IEEE80211_RADIOTAP_S1G_GI_SHORT = 1,
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_s1g_bw {
|
||||
IEEE80211_RADIOTAP_S1G_BW_1MHZ = 0,
|
||||
IEEE80211_RADIOTAP_S1G_BW_2MHZ = 1,
|
||||
IEEE80211_RADIOTAP_S1G_BW_4MHZ = 2,
|
||||
IEEE80211_RADIOTAP_S1G_BW_8MHZ = 3,
|
||||
IEEE80211_RADIOTAP_S1G_BW_16MHZ = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_get_radiotap_len - get radiotap header length
|
||||
* @data: pointer to the header
|
||||
|
|
|
|||
|
|
@ -1770,10 +1770,9 @@ enum mac80211_rx_encoding {
|
|||
* @ampdu_reference: A-MPDU reference number, must be a different value for
|
||||
* each A-MPDU but the same for each subframe within one A-MPDU
|
||||
* @zero_length_psdu_type: radiotap type of the 0-length PSDU
|
||||
* @link_valid: if the link which is identified by @link_id is valid. This flag
|
||||
* is set only when connection is MLO.
|
||||
* @link_id: id of the link used to receive the packet. This is used along with
|
||||
* @link_valid.
|
||||
* @link_id: id of the link used to receive the packet. Set and used by
|
||||
* mac80211 internally, it uses @freq set by the driver to identify the
|
||||
* correct link per vif.
|
||||
*/
|
||||
struct ieee80211_rx_status {
|
||||
u64 mactime;
|
||||
|
|
@ -1813,7 +1812,7 @@ struct ieee80211_rx_status {
|
|||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
u8 zero_length_psdu_type;
|
||||
u8 link_valid:1, link_id:4;
|
||||
u8 link_id:4;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct ieee80211_rx_status) <= sizeof_field(struct sk_buff, cb));
|
||||
|
|
@ -2919,8 +2918,8 @@ struct ieee80211_txq {
|
|||
* autonomously manages the PS status of connected stations. When
|
||||
* this flag is set mac80211 will not trigger PS mode for connected
|
||||
* stations based on the PM bit of incoming frames.
|
||||
* Use ieee80211_start_ps()/ieee8021_end_ps() to manually configure
|
||||
* the PS mode of connected stations.
|
||||
* Use ieee80211_sta_ps_transition() to manually toggle the PS mode
|
||||
* of connected stations.
|
||||
*
|
||||
* @IEEE80211_HW_TX_AMPDU_SETUP_IN_HW: The device handles TX A-MPDU session
|
||||
* setup strictly in HW. mac80211 should not attempt to do this in
|
||||
|
|
@ -5389,14 +5388,18 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
|
|||
* mixed for a single hardware. Must not run concurrently with
|
||||
* ieee80211_tx_status_skb() or ieee80211_tx_status_ni().
|
||||
*
|
||||
* For data frames, when hardware has done address translation, a link station
|
||||
* has to be provided and the frequency information may be skipped.
|
||||
*
|
||||
* This function must be called with BHs disabled and RCU read lock
|
||||
*
|
||||
* @hw: the hardware this frame came in on
|
||||
* @sta: the station the frame was received from, or %NULL
|
||||
* @link_sta: the link station the data frame was received from, or %NULL
|
||||
* @skb: the buffer to receive, owned by mac80211 after this call
|
||||
* @list: the destination list
|
||||
*/
|
||||
void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
||||
void ieee80211_rx_list(struct ieee80211_hw *hw,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct sk_buff *skb, struct list_head *list);
|
||||
|
||||
/**
|
||||
|
|
@ -5414,14 +5417,18 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
|||
* mixed for a single hardware. Must not run concurrently with
|
||||
* ieee80211_tx_status_skb() or ieee80211_tx_status_ni().
|
||||
*
|
||||
* For data frames, when hardware has done address translation, a link station
|
||||
* has to be provided and the frequency information may be skipped.
|
||||
*
|
||||
* This function must be called with BHs disabled.
|
||||
*
|
||||
* @hw: the hardware this frame came in on
|
||||
* @sta: the station the frame was received from, or %NULL
|
||||
* @link_sta: the link station the data frame was received from, or %NULL
|
||||
* @skb: the buffer to receive, owned by mac80211 after this call
|
||||
* @napi: the NAPI context
|
||||
*/
|
||||
void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
||||
void ieee80211_rx_napi(struct ieee80211_hw *hw,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
struct sk_buff *skb, struct napi_struct *napi);
|
||||
|
||||
/**
|
||||
|
|
@ -5499,10 +5506,8 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
|
|||
*
|
||||
* @sta: currently connected sta
|
||||
* @start: start or stop PS
|
||||
*
|
||||
* Return: 0 on success. -EINVAL when the requested PS mode is already set.
|
||||
*/
|
||||
int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
|
||||
void ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
|
||||
|
||||
/**
|
||||
* ieee80211_sta_ps_transition_ni - PS transition for connected sta
|
||||
|
|
@ -5514,19 +5519,13 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
|
|||
*
|
||||
* @sta: currently connected sta
|
||||
* @start: start or stop PS
|
||||
*
|
||||
* Return: Like ieee80211_sta_ps_transition().
|
||||
*/
|
||||
static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
|
||||
static inline void ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
|
||||
bool start)
|
||||
{
|
||||
int ret;
|
||||
|
||||
local_bh_disable();
|
||||
ret = ieee80211_sta_ps_transition(sta, start);
|
||||
ieee80211_sta_ps_transition(sta, start);
|
||||
local_bh_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -7640,12 +7639,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|||
* @dev: the &struct device of this 802.11 device
|
||||
* @chandef: the channel definition the frame will be transmitted on, or
|
||||
* %NULL to skip the bandwidth checks
|
||||
* @trim_fcs: trim the FCS trailer when present; validate it otherwise
|
||||
*
|
||||
* Return: %true if the radiotap header was parsed, %false otherwise
|
||||
*/
|
||||
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
bool trim_fcs);
|
||||
|
||||
/**
|
||||
* struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
|
||||
|
|
@ -8061,25 +8062,6 @@ void
|
|||
ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
|
||||
u64 color_bitmap, u8 link_id);
|
||||
|
||||
/**
|
||||
* ieee80211_is_tx_data - check if frame is a data frame
|
||||
*
|
||||
* The function is used to check if a frame is a data frame. Frames with
|
||||
* hardware encapsulation enabled are data frames.
|
||||
*
|
||||
* @skb: the frame to be transmitted.
|
||||
*
|
||||
* Return: %true if @skb is a data frame, %false otherwise
|
||||
*/
|
||||
static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *) skb->data;
|
||||
|
||||
return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP ||
|
||||
ieee80211_is_data(hdr->frame_control);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_set_active_links - set active links in client mode
|
||||
* @vif: interface to set active links on
|
||||
|
|
|
|||
|
|
@ -937,8 +937,8 @@
|
|||
* OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
|
||||
* messages. Note that per PHY only one application may register.
|
||||
*
|
||||
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
|
||||
* No Acknowledgement Policy should be applied.
|
||||
* @NL80211_CMD_SET_NOACK_MAP: sets a bitmap (%NL80211_ATTR_TID_BITMAP)
|
||||
* indicating for which TIDs No Acknowledgment Policy should be applied.
|
||||
*
|
||||
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
|
||||
* independently of the userspace SME, send this event indicating
|
||||
|
|
@ -2288,8 +2288,8 @@ enum nl80211_commands {
|
|||
* abides to when initiating radiation on DFS channels. A country maps
|
||||
* to one DFS region.
|
||||
*
|
||||
* @NL80211_ATTR_NOACK_MAP: This u16 bitmap contains the No Ack Policy of
|
||||
* up to 16 TIDs.
|
||||
* @NL80211_ATTR_TID_BITMAP: A TID bitmap (u16) whose meaning depends
|
||||
* on the command.
|
||||
*
|
||||
* @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
|
||||
* used by the drivers which has MLME in firmware and does not have support
|
||||
|
|
@ -3185,6 +3185,11 @@ enum nl80211_commands {
|
|||
* The aggregated message always precedes the per-link messages for the
|
||||
* same station within a dump sequence.
|
||||
*
|
||||
* @NL80211_ATTR_FRAME_NO_STA: Valid for @NL80211_CMD_FRAME to denote that
|
||||
* the kernel had no station for a received frame or should not use a
|
||||
* known station to transmit a frame. This is relevant to know whether
|
||||
* MLD address translation happened or to disable it when sending a frame.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
|
@ -3429,7 +3434,7 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_DISABLE_HT,
|
||||
NL80211_ATTR_HT_CAPABILITY_MASK,
|
||||
|
||||
NL80211_ATTR_NOACK_MAP,
|
||||
NL80211_ATTR_TID_BITMAP,
|
||||
|
||||
NL80211_ATTR_INACTIVITY_TIMEOUT,
|
||||
|
||||
|
|
@ -3785,6 +3790,8 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_STA_DUMP_LINK_STATS,
|
||||
|
||||
NL80211_ATTR_FRAME_NO_STA,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
|
@ -3800,6 +3807,7 @@ enum nl80211_attrs {
|
|||
#define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON
|
||||
#define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP
|
||||
#define NL80211_ATTR_ASSOC_MLD_EXT_CAPA_OPS NL80211_ATTR_EXT_MLD_CAPA_AND_OPS
|
||||
#define NL80211_ATTR_NOACK_MAP NL80211_ATTR_TID_BITMAP
|
||||
|
||||
/*
|
||||
* Allow user space programs to use #ifdef on new attributes by defining them
|
||||
|
|
@ -5900,6 +5908,9 @@ enum nl80211_key_attributes {
|
|||
* see &struct nl80211_txrate_eht
|
||||
* @NL80211_TXRATE_EHT_GI: configure EHT GI, (u8, see &enum nl80211_eht_gi)
|
||||
* @NL80211_TXRATE_EHT_LTF: configure EHT LTF, (u8, see &enum nl80211_eht_ltf)
|
||||
* @NL80211_TXRATE_6GHZ_NON_HT_DUP: configure 6 GHz non-HT duplicate Beacon
|
||||
* transmission. This flag is applicable only in Beacon TX rate setting
|
||||
* and must be accompanied by a non-HT (legacy) Beacon rate.
|
||||
* @__NL80211_TXRATE_AFTER_LAST: internal
|
||||
* @NL80211_TXRATE_MAX: highest TX rate attribute
|
||||
*/
|
||||
|
|
@ -5915,6 +5926,7 @@ enum nl80211_tx_rate_attributes {
|
|||
NL80211_TXRATE_EHT,
|
||||
NL80211_TXRATE_EHT_GI,
|
||||
NL80211_TXRATE_EHT_LTF,
|
||||
NL80211_TXRATE_6GHZ_NON_HT_DUP,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_TXRATE_AFTER_LAST,
|
||||
|
|
@ -7110,6 +7122,10 @@ enum nl80211_feature_flags {
|
|||
* @NL80211_EXT_FEATURE_PROBE_AP: Driver supports probing the associated AP
|
||||
* in STA mode using @NL80211_CMD_PROBE_PEER.
|
||||
*
|
||||
* @NL80211_EXT_FEATURE_FAST_ROAM_OFFLOAD: Driver supports fast roaming
|
||||
* offload in station mode, including Fast Transition or Opportunistic
|
||||
* Key Caching.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
|
|
@ -7192,6 +7208,7 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_ROC_ADDR_FILTER,
|
||||
NL80211_EXT_FEATURE_SET_KEY_LTF_SEED,
|
||||
NL80211_EXT_FEATURE_PROBE_AP,
|
||||
NL80211_EXT_FEATURE_FAST_ROAM_OFFLOAD,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid,
|
|||
if (sta->sta.deflink.he_cap.has_he)
|
||||
ieee80211_add_addbaext(skb, 0, agg_size);
|
||||
|
||||
ieee80211_tx_skb_tid(sdata, skb, tid, -1);
|
||||
ieee80211_tx_skb_tid(sdata, skb, NULL, tid, -1);
|
||||
}
|
||||
|
||||
void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
|
||||
|
|
@ -127,7 +127,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
|
|||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
ieee80211_tx_skb_tid(sdata, skb, tid, -1);
|
||||
ieee80211_tx_skb_tid(sdata, skb, NULL, tid, -1);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_send_bar);
|
||||
|
||||
|
|
@ -212,10 +212,7 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
|
|||
|
||||
txqi = to_txq_info(txq);
|
||||
|
||||
if (enable)
|
||||
set_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||
else
|
||||
clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
|
||||
assign_bit(IEEE80211_TXQ_AMPDU, &txqi->flags, enable);
|
||||
|
||||
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
local_bh_disable();
|
||||
|
|
|
|||
|
|
@ -82,9 +82,6 @@ ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
|
|||
if (!ift_ext_capa)
|
||||
return;
|
||||
|
||||
if (!status->link_valid)
|
||||
return;
|
||||
|
||||
sta = sta_info_get_bss(sdata, mgmt->sa);
|
||||
if (!sta)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ static ssize_t aqm_read(struct file *file,
|
|||
"RW fq_quantum %u\n",
|
||||
fq->flows_cnt,
|
||||
fq->backlog,
|
||||
fq->overmemory,
|
||||
fq->overlimit,
|
||||
fq->overmemory,
|
||||
fq->collisions,
|
||||
fq->memory_usage,
|
||||
fq->memory_limit,
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,13 @@ void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
debugfs_change_name(sdata->vif.debugfs_dir, "netdev:%s", sdata->name);
|
||||
struct dentry *dir;
|
||||
|
||||
wiphy_lock(sdata->local->hw.wiphy);
|
||||
dir = sdata->vif.debugfs_dir;
|
||||
if (dir)
|
||||
debugfs_change_name(dir, "netdev:%s", sdata->name);
|
||||
wiphy_unlock(sdata->local->hw.wiphy);
|
||||
}
|
||||
|
||||
void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
|||
info->status_data = IEEE80211_STATUS_TYPE_SMPS |
|
||||
u16_encode_bits(status_link_id << 2 | smps,
|
||||
IEEE80211_STATUS_SUBDATA_MASK);
|
||||
ieee80211_tx_skb_tid(sdata, skb, 7, link_id);
|
||||
ieee80211_tx_skb_tid(sdata, skb, NULL, 7, link_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,6 +191,15 @@ struct ieee80211_tx_data {
|
|||
unsigned int flags;
|
||||
};
|
||||
|
||||
static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
|
||||
return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP ||
|
||||
ieee80211_is_data(hdr->frame_control);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum ieee80211_packet_rx_flags - packet RX flags
|
||||
* @IEEE80211_RX_AMSDU: a-MSDU packet
|
||||
|
|
@ -1459,6 +1468,7 @@ struct ieee80211_local {
|
|||
spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
|
||||
struct list_head active_txqs[IEEE80211_NUM_ACS];
|
||||
u16 schedule_round[IEEE80211_NUM_ACS];
|
||||
bool schedule_open[IEEE80211_NUM_ACS];
|
||||
|
||||
/* serializes ieee80211_handle_wake_tx_queue */
|
||||
spinlock_t handle_wake_tx_queue_lock;
|
||||
|
|
@ -2233,8 +2243,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
|
|||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags,
|
||||
u32 ctrl_flags,
|
||||
u64 cookie);
|
||||
u32 ctrl_flags);
|
||||
struct sk_buff *
|
||||
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags);
|
||||
|
|
@ -2388,7 +2397,6 @@ ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
|
|||
const struct ieee80211_he_operation *he_op_ie_elem);
|
||||
|
||||
/* S1G */
|
||||
void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
|
||||
bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb);
|
||||
void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
|
|
@ -2463,7 +2471,8 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
struct sta_info *sta, struct sk_buff *skb);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid, int link_id,
|
||||
struct sk_buff *skb, struct sta_info *sta,
|
||||
int tid, int link_id,
|
||||
enum nl80211_band band);
|
||||
|
||||
static inline bool ieee80211_require_encrypted_assoc(__le16 fc,
|
||||
|
|
@ -2472,29 +2481,26 @@ static inline bool ieee80211_require_encrypted_assoc(__le16 fc,
|
|||
return sta && sta->sta.epp_peer && ieee80211_is_assoc(fc);
|
||||
}
|
||||
|
||||
/* sta_out needs to be checked for ERR_PTR() before using */
|
||||
int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct sta_info **sta_out);
|
||||
|
||||
static inline void
|
||||
ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
rcu_read_lock();
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, tid, -1, band);
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, ERR_PTR(-ENOENT),
|
||||
tid, -1, band);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid, int link_id);
|
||||
struct sk_buff *skb, struct sta_info *sta,
|
||||
int tid, int link_id);
|
||||
|
||||
static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
|
||||
ieee80211_tx_skb_tid(sdata, skb, 7, -1);
|
||||
ieee80211_tx_skb_tid(sdata, skb, NULL, 7, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -632,8 +632,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
}
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
}
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
break;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
/* Check if any open NAN_DATA interfaces */
|
||||
|
|
@ -993,7 +994,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
|
|||
/* reset flags and info before parsing radiotap header */
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, NULL))
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, NULL, false))
|
||||
return 0; /* doesn't matter, frame will be dropped */
|
||||
|
||||
len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
||||
|
|
@ -1706,11 +1707,8 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
|
|||
break;
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
if (!status->link_valid)
|
||||
link_sta = &sta->deflink;
|
||||
else
|
||||
link_sta = rcu_dereference_protected(sta->link[status->link_id],
|
||||
lockdep_is_held(&local->hw.wiphy->mtx));
|
||||
link_sta = wiphy_dereference(local->hw.wiphy,
|
||||
sta->link[status->link_id]);
|
||||
if (link_sta)
|
||||
ieee80211_ht_handle_chanwidth_notif(local, sdata, sta,
|
||||
link_sta, chanwidth,
|
||||
|
|
|
|||
|
|
@ -1322,12 +1322,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
|
||||
|
||||
/* currently no support for HE client where HT has 40 MHz but not HT */
|
||||
if (iftd->he_cap.has_he &&
|
||||
iftd->types_mask & (BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
|
||||
sband->ht_cap.ht_supported &&
|
||||
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
|
||||
!(iftd->he_cap.he_cap_elem.phy_cap_info[0] & he_40_mhz_cap))
|
||||
if (WARN_ON(iftd->he_cap.has_he &&
|
||||
iftd->types_mask & (BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
|
||||
sband->ht_cap.ht_supported &&
|
||||
sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
|
||||
!(iftd->he_cap.he_cap_elem.phy_cap_info[0] &
|
||||
he_40_mhz_cap)))
|
||||
return -EINVAL;
|
||||
|
||||
/* no support for per-band vendor elems with MLO */
|
||||
|
|
|
|||
|
|
@ -673,7 +673,7 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata,
|
|||
* @sdata: local subif
|
||||
* @dst: destination address of the path (ETH_ALEN length)
|
||||
*
|
||||
* Returns: 0 on success
|
||||
* Returns: the new or the existing path on success, an ERR_PTR() on failure
|
||||
*
|
||||
* State: the initial state of the new path is set to 0
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6347,7 +6347,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
|
|||
}
|
||||
|
||||
static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link,
|
||||
struct sta_info *sta,
|
||||
struct link_sta_info *link_sta,
|
||||
struct cfg80211_bss *cbss)
|
||||
{
|
||||
|
|
@ -6362,11 +6361,9 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link,
|
|||
memcpy(link_sta->addr, cbss->bssid, ETH_ALEN);
|
||||
memcpy(link_sta->pub->addr, cbss->bssid, ETH_ALEN);
|
||||
|
||||
/* TODO: S1G Basic Rate Set is expressed elsewhere */
|
||||
if (cbss->channel->band == NL80211_BAND_S1GHZ) {
|
||||
ieee80211_s1g_sta_rate_init(sta);
|
||||
/* S1G does not use basic rates */
|
||||
if (cbss->channel->band == NL80211_BAND_S1GHZ)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sband = local->hw.wiphy->bands[cbss->channel->band];
|
||||
|
||||
|
|
@ -6516,7 +6513,7 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_sta_ht_cap sta_ht_cap = sband->ht_cap;
|
||||
bool is_5ghz = sband->band == NL80211_BAND_5GHZ;
|
||||
bool is_6ghz = sband->band == NL80211_BAND_6GHZ;
|
||||
const struct ieee80211_sta_he_cap *he_cap;
|
||||
const struct ieee80211_sta_he_cap *he_cap = NULL;
|
||||
const struct ieee80211_sta_eht_cap *eht_cap;
|
||||
const struct ieee80211_sta_uhr_cap *uhr_cap;
|
||||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
|
|
@ -6580,7 +6577,15 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (vht_cap.vht_supported && is_5ghz) {
|
||||
if (req && req->flags & ASSOC_REQ_DISABLE_HE && !is_6ghz)
|
||||
mlme_link_id_dbg(sdata, link_id,
|
||||
"HE disabled by flag, limiting to HT/VHT\n");
|
||||
else
|
||||
he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif);
|
||||
|
||||
if (vht_cap.vht_supported && is_5ghz && he_cap) {
|
||||
/* nothing - since HE we can be 20 MHz-only non-AP STA */
|
||||
} else if (vht_cap.vht_supported && is_5ghz) {
|
||||
bool have_80mhz = false;
|
||||
unsigned int i;
|
||||
|
||||
|
|
@ -6626,17 +6631,11 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata,
|
|||
"no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz");
|
||||
}
|
||||
|
||||
if (req && req->flags & ASSOC_REQ_DISABLE_HE) {
|
||||
mlme_link_id_dbg(sdata, link_id,
|
||||
"HE disabled by flag, limiting to HT/VHT\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif);
|
||||
if (!he_cap) {
|
||||
WARN_ON(is_6ghz);
|
||||
mlme_link_id_dbg(sdata, link_id,
|
||||
"no HE support, limiting to HT/VHT\n");
|
||||
if (!req || !(req->flags & ASSOC_REQ_DISABLE_HE))
|
||||
mlme_link_id_dbg(sdata, link_id,
|
||||
"no HE support, limiting to HT/VHT\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -7107,7 +7106,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
err = ieee80211_mgd_setup_link_sta(link, sta, link_sta,
|
||||
err = ieee80211_mgd_setup_link_sta(link, link_sta,
|
||||
assoc_data->link[link_id].bss);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
|
@ -9699,8 +9698,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
err = ieee80211_mgd_setup_link_sta(link, new_sta,
|
||||
link_sta, cbss);
|
||||
err = ieee80211_mgd_setup_link_sta(link, link_sta, cbss);
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
sta_info_free(local, new_sta);
|
||||
|
|
@ -11090,7 +11088,7 @@ ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata,
|
|||
goto disconnect;
|
||||
}
|
||||
|
||||
if (ieee80211_mgd_setup_link_sta(link, sta, link_sta,
|
||||
if (ieee80211_mgd_setup_link_sta(link, link_sta,
|
||||
add_links_data->link[link_id].bss))
|
||||
goto disconnect;
|
||||
|
||||
|
|
@ -11831,12 +11829,10 @@ void ieee80211_sta_rx_queued_frame(struct ieee80211_sub_if_data *sdata,
|
|||
rx_status = (struct ieee80211_rx_status *) skb->cb;
|
||||
fc = le16_to_cpu(mgmt->frame_control);
|
||||
|
||||
if (rx_status->link_valid) {
|
||||
link = sdata_dereference(sdata->link[rx_status->link_id],
|
||||
sdata);
|
||||
if (!link)
|
||||
return;
|
||||
}
|
||||
link = sdata_dereference(sdata->link[rx_status->link_id],
|
||||
sdata);
|
||||
if (!link)
|
||||
return;
|
||||
|
||||
switch (fc & IEEE80211_FCTL_STYPE) {
|
||||
case IEEE80211_STYPE_BEACON:
|
||||
|
|
|
|||
|
|
@ -861,8 +861,10 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
need_offchan = true;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get_bss(sdata, mgmt->da);
|
||||
mlo_sta = sta && sta->sta.mlo;
|
||||
if (!params->no_sta) {
|
||||
sta = sta_info_get_bss(sdata, mgmt->da);
|
||||
mlo_sta = sta && sta->sta.mlo;
|
||||
}
|
||||
|
||||
if (!ieee80211_is_action(mgmt->frame_control) ||
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
|
||||
|
|
@ -891,7 +893,8 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
local->ops->remain_on_channel &&
|
||||
memcmp(sdata->vif.cfg.ap_addr, mgmt->bssid, ETH_ALEN))) {
|
||||
need_offchan = true;
|
||||
} else if (sdata->u.mgd.associated &&
|
||||
} else if (!params->no_sta &&
|
||||
sdata->u.mgd.associated &&
|
||||
ether_addr_equal(sdata->vif.cfg.ap_addr, mgmt->da)) {
|
||||
sta = sta_info_get_bss(sdata, mgmt->da);
|
||||
mlo_sta = sta && sta->sta.mlo;
|
||||
|
|
@ -1029,7 +1032,9 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
}
|
||||
|
||||
if (!need_offchan) {
|
||||
ieee80211_tx_skb_tid(sdata, skb, 7, link_id);
|
||||
ieee80211_tx_skb_tid(sdata, skb,
|
||||
params->no_sta ? ERR_PTR(-ENOENT) : sta,
|
||||
7, link_id);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ void rate_control_rate_init(struct link_sta_info *link_sta)
|
|||
|
||||
/* TODO: check for minstrel_s1g ? */
|
||||
if (sband->band == NL80211_BAND_S1GHZ) {
|
||||
ieee80211_s1g_sta_rate_init(sta);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,43 +222,21 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
|
||||
int link_id,
|
||||
struct sta_info *sta,
|
||||
struct link_sta_info *link_sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
if (link_id >= 0) {
|
||||
status->link_valid = 1;
|
||||
status->link_id = link_id;
|
||||
} else {
|
||||
status->link_valid = 0;
|
||||
}
|
||||
|
||||
skb_queue_tail(&sdata->skb_queue, skb);
|
||||
wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
|
||||
if (sta) {
|
||||
struct link_sta_info *link_sta_info;
|
||||
|
||||
if (link_id >= 0) {
|
||||
link_sta_info = rcu_dereference(sta->link[link_id]);
|
||||
if (!link_sta_info)
|
||||
return;
|
||||
} else {
|
||||
link_sta_info = &sta->deflink;
|
||||
}
|
||||
|
||||
link_sta_info->rx_stats.packets++;
|
||||
}
|
||||
if (link_sta)
|
||||
link_sta->rx_stats.packets++;
|
||||
}
|
||||
|
||||
static void ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
|
||||
int link_id,
|
||||
struct sta_info *sta,
|
||||
struct link_sta_info *link_sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
skb->protocol = 0;
|
||||
__ieee80211_queue_skb_to_iface(sdata, link_id, sta, skb);
|
||||
__ieee80211_queue_skb_to_iface(sdata, link_sta, skb);
|
||||
}
|
||||
|
||||
static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -301,7 +279,7 @@ static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
ieee80211_queue_skb_to_iface(sdata, -1, NULL, skb);
|
||||
ieee80211_queue_skb_to_iface(sdata, NULL, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -452,6 +430,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
if (status->band == NL80211_BAND_5GHZ ||
|
||||
status->band == NL80211_BAND_6GHZ)
|
||||
channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ;
|
||||
else if (status->band == NL80211_BAND_S1GHZ)
|
||||
channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_900MHZ;
|
||||
else if (status->encoding != RX_ENC_LEGACY)
|
||||
channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
|
||||
else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
|
||||
|
|
@ -1498,7 +1478,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
|
|||
/* if this mpdu is fragmented - terminate rx aggregation session */
|
||||
sc = le16_to_cpu(hdr->seq_ctrl);
|
||||
if (sc & IEEE80211_SCTL_FRAG) {
|
||||
ieee80211_queue_skb_to_iface(rx->sdata, rx->link_id, NULL, skb);
|
||||
ieee80211_queue_skb_to_iface(rx->sdata, NULL, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1712,10 +1692,7 @@ static void sta_ps_start(struct sta_info *sta)
|
|||
list_del_init(&txqi->schedule_order);
|
||||
spin_unlock(&local->active_txq_lock[txq->ac]);
|
||||
|
||||
if (txq_has_queue(txq))
|
||||
set_bit(tid, &sta->txq_buffered_tids);
|
||||
else
|
||||
clear_bit(tid, &sta->txq_buffered_tids);
|
||||
assign_bit(tid, &sta->txq_buffered_tids, txq_has_queue(txq));
|
||||
}
|
||||
|
||||
sta_info_recalc_tim(sta);
|
||||
|
|
@ -1744,7 +1721,7 @@ static void sta_ps_end(struct sta_info *sta)
|
|||
ieee80211_sta_ps_deliver_wakeup(sta);
|
||||
}
|
||||
|
||||
int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
|
||||
void ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
|
||||
{
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
bool in_ps;
|
||||
|
|
@ -1753,15 +1730,13 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
|
|||
|
||||
/* Don't let the same PS state be set twice */
|
||||
in_ps = test_sta_flag(sta, WLAN_STA_PS_STA);
|
||||
if ((start && in_ps) || (!start && !in_ps))
|
||||
return -EINVAL;
|
||||
if (start == in_ps)
|
||||
return;
|
||||
|
||||
if (start)
|
||||
sta_ps_start(sta);
|
||||
else
|
||||
sta_ps_end(sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_ps_transition);
|
||||
|
||||
|
|
@ -2524,7 +2499,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
|
|||
|
||||
out:
|
||||
ieee80211_led_rx(rx->local);
|
||||
if (rx->sta)
|
||||
if (rx->link_sta)
|
||||
rx->link_sta->rx_stats.packets++;
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
|
@ -3335,8 +3310,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
|
|||
(tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ||
|
||||
tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) {
|
||||
rx->skb->protocol = cpu_to_be16(ETH_P_TDLS);
|
||||
__ieee80211_queue_skb_to_iface(sdata, rx->link_id,
|
||||
rx->sta, rx->skb);
|
||||
__ieee80211_queue_skb_to_iface(sdata, rx->link_sta,
|
||||
rx->skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
}
|
||||
|
|
@ -3991,7 +3966,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|||
return RX_QUEUED;
|
||||
|
||||
queue:
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_sta, rx->skb);
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
||||
|
|
@ -4005,6 +3980,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
|
|||
.len = rx->skb->len,
|
||||
.link_id = rx->link_id,
|
||||
.have_link_id = rx->link_id >= 0,
|
||||
.no_sta = !rx->sta,
|
||||
};
|
||||
|
||||
/* skip known-bad action frames and return them in the next handler */
|
||||
|
|
@ -4127,7 +4103,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
|
|||
local->hw.offchannel_tx_hw_queue;
|
||||
}
|
||||
|
||||
__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1,
|
||||
__ieee80211_tx_skb_tid_band(rx->sdata, nskb, rx->sta, 7, -1,
|
||||
status->band);
|
||||
}
|
||||
|
||||
|
|
@ -4147,7 +4123,7 @@ ieee80211_rx_h_ext(struct ieee80211_rx_data *rx)
|
|||
return RX_DROP_U_UNEXPECTED_EXT_FRAME;
|
||||
|
||||
/* for now only beacons are ext, so queue them */
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_sta, rx->skb);
|
||||
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
|
@ -4204,7 +4180,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
|
|||
return RX_DROP_U_UNHANDLED_MGMT_STYPE;
|
||||
}
|
||||
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb);
|
||||
ieee80211_queue_skb_to_iface(sdata, rx->link_sta, rx->skb);
|
||||
|
||||
return RX_QUEUED;
|
||||
}
|
||||
|
|
@ -4248,12 +4224,28 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
|
|||
spin_lock_bh(&rx->local->rx_path_lock);
|
||||
|
||||
while ((skb = __skb_dequeue(frames))) {
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
/*
|
||||
* all the other fields are valid across frames
|
||||
* that belong to an aMPDU since they are on the
|
||||
* same TID from the same station
|
||||
* Most fields are valid across frames. However,
|
||||
* in the case of reordering frames may have arrived
|
||||
* on different links, so adjust the link_id, link
|
||||
* and link_sta accordingly.
|
||||
*/
|
||||
rx->skb = skb;
|
||||
if (ieee80211_vif_is_mld(&rx->sdata->vif) &&
|
||||
unlikely(rx->link_id != status->link_id)) {
|
||||
if (rx->sta) {
|
||||
rx->link_sta =
|
||||
rcu_dereference(rx->sta->link[rx->link_id]);
|
||||
|
||||
/* Link got disabled, just use deflink */
|
||||
if (!rx->link_sta)
|
||||
rx->link_sta = &rx->sta->deflink;
|
||||
}
|
||||
rx->link_id = status->link_id;
|
||||
rx->link = rcu_dereference(rx->sdata->link[status->link_id]);
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!rx->link)) {
|
||||
res = RX_DROP_U_NO_LINK;
|
||||
|
|
@ -4323,7 +4315,34 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
|||
static bool
|
||||
ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
|
||||
{
|
||||
return !!(sta->valid_links & BIT(link_id));
|
||||
if (sta->mlo)
|
||||
return sta->valid_links & BIT(link_id);
|
||||
|
||||
return sta->deflink.link_id == link_id;
|
||||
}
|
||||
|
||||
static bool ieee80211_rx_data_set_link_sta(struct ieee80211_rx_data *rx,
|
||||
struct link_sta_info *link_sta)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
if (WARN_ON_ONCE(!link_sta) ||
|
||||
!ieee80211_rx_is_valid_sta_link_id(&link_sta->sta->sta,
|
||||
link_sta->link_id))
|
||||
return false;
|
||||
|
||||
sta = link_sta->sta;
|
||||
|
||||
rx->sta = sta;
|
||||
rx->local = sta->sdata->local;
|
||||
rx->link = rcu_dereference(sta->sdata->link[link_sta->link_id]);
|
||||
if (!rx->link)
|
||||
return false;
|
||||
|
||||
rx->link_id = rx->link->link_id;
|
||||
rx->link_sta = link_sta;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
|
||||
|
|
@ -4360,11 +4379,13 @@ static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
|
|||
|
||||
if (link_id < 0) {
|
||||
if (ieee80211_vif_is_mld(&rx->sdata->vif) &&
|
||||
sta && !sta->sta.valid_links)
|
||||
sta && !sta->sta.valid_links) {
|
||||
rx->link =
|
||||
rcu_dereference(rx->sdata->link[sta->deflink.link_id]);
|
||||
else
|
||||
rx->link_sta = &sta->deflink;
|
||||
} else {
|
||||
rx->link = &rx->sdata->deflink;
|
||||
}
|
||||
} else if (!ieee80211_rx_data_set_link(rx, link_id)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -4387,7 +4408,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
|||
struct tid_ampdu_rx *tid_agg_rx;
|
||||
int link_id = -1;
|
||||
|
||||
/* FIXME: statistics won't be right with this */
|
||||
/* NOTE: the correct link STA for the frame is set later */
|
||||
if (sta->sta.valid_links)
|
||||
link_id = ffs(sta->sta.valid_links) - 1;
|
||||
|
||||
|
|
@ -4914,20 +4935,14 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
|
|||
{
|
||||
struct ieee80211_sta_rx_stats *stats;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
struct sta_info *sta = rx->sta;
|
||||
struct link_sta_info *link_sta;
|
||||
struct link_sta_info *link_sta = rx->link_sta;
|
||||
struct sk_buff *skb = rx->skb;
|
||||
void *sa = skb->data + ETH_ALEN;
|
||||
void *da = skb->data;
|
||||
|
||||
if (rx->link_id >= 0) {
|
||||
link_sta = rcu_dereference(sta->link[rx->link_id]);
|
||||
if (WARN_ON_ONCE(!link_sta)) {
|
||||
dev_kfree_skb(rx->skb);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
link_sta = &sta->deflink;
|
||||
if (WARN_ON_ONCE(!link_sta)) {
|
||||
dev_kfree_skb(rx->skb);
|
||||
return;
|
||||
}
|
||||
|
||||
stats = &link_sta->rx_stats;
|
||||
|
|
@ -5154,6 +5169,9 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
|
|||
goto drop;
|
||||
}
|
||||
|
||||
status = IEEE80211_SKB_RXCB(skb);
|
||||
status->link_id = rx->link_id < 0 ? 0 : rx->link_id;
|
||||
|
||||
ieee80211_rx_8023(rx, fast_rx, orig_len);
|
||||
|
||||
return true;
|
||||
|
|
@ -5178,6 +5196,7 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct link_sta_info *link_sta = rx->link_sta;
|
||||
struct ieee80211_link_data *link = rx->link;
|
||||
struct ieee80211_rx_status *status;
|
||||
|
||||
rx->skb = skb;
|
||||
|
||||
|
|
@ -5221,6 +5240,9 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
}
|
||||
|
||||
status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
status->link_id = rx->link_id < 0 ? 0 : rx->link_id;
|
||||
|
||||
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
|
||||
ieee80211_invoke_rx_handlers(rx);
|
||||
return true;
|
||||
|
|
@ -5256,22 +5278,19 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
}
|
||||
|
||||
static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct ieee80211_link_sta *link_pubsta,
|
||||
struct sk_buff *skb,
|
||||
struct list_head *list)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_fast_rx *fast_rx;
|
||||
struct ieee80211_rx_data rx;
|
||||
struct sta_info *sta;
|
||||
int link_id = -1;
|
||||
|
||||
memset(&rx, 0, sizeof(rx));
|
||||
rx.skb = skb;
|
||||
rx.local = local;
|
||||
rx.list = list;
|
||||
rx.link_id = -1;
|
||||
|
||||
I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
|
||||
|
||||
|
|
@ -5279,23 +5298,15 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
|
|||
if (skb->len < sizeof(struct ethhdr))
|
||||
goto drop;
|
||||
|
||||
if (!pubsta)
|
||||
if (!link_pubsta)
|
||||
goto drop;
|
||||
|
||||
if (status->link_valid)
|
||||
link_id = status->link_id;
|
||||
|
||||
/*
|
||||
* TODO: Should the frame be dropped if the right link_id is not
|
||||
* available? Or may be it is fine in the current form to proceed with
|
||||
* the frame processing because with frame being in 802.3 format,
|
||||
* link_id is used only for stats purpose and updating the stats on
|
||||
* the deflink is fine?
|
||||
*/
|
||||
sta = container_of(pubsta, struct sta_info, sta);
|
||||
if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
|
||||
sta = container_of(link_pubsta->sta, struct sta_info, sta);
|
||||
if (!ieee80211_rx_data_set_sta(&rx, sta, link_pubsta->link_id))
|
||||
goto drop;
|
||||
|
||||
rx.link_id = link_pubsta->link_id;
|
||||
|
||||
fast_rx = rcu_dereference(rx.sta->fast_rx);
|
||||
if (!fast_rx)
|
||||
goto drop;
|
||||
|
|
@ -5307,59 +5318,19 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
|
|||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
|
||||
struct sk_buff *skb, bool consume)
|
||||
static bool ieee80211_rx_valid_freq(int freq, struct ieee80211_link_data *link)
|
||||
{
|
||||
struct link_sta_info *link_sta;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct sta_info *sta;
|
||||
int link_id = -1;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
|
||||
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
|
||||
if (!ieee80211_rx_data_set_sta(rx, NULL, -1))
|
||||
return false;
|
||||
if (!freq || link->sdata->vif.type == NL80211_IFTYPE_NAN ||
|
||||
link->sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
|
||||
return true;
|
||||
|
||||
return ieee80211_prepare_and_rx_handle(rx, skb, consume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up link station first, in case there's a
|
||||
* chance that they might have a link address that
|
||||
* is identical to the MLD address, that way we'll
|
||||
* have the link information if needed.
|
||||
*/
|
||||
link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
|
||||
if (link_sta) {
|
||||
sta = link_sta->sta;
|
||||
link_id = link_sta->link_id;
|
||||
} else {
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
|
||||
sta = sta_info_get_bss(rx->sdata, hdr->addr2);
|
||||
if (status->link_valid) {
|
||||
link_id = status->link_id;
|
||||
} else if (ieee80211_vif_is_mld(&rx->sdata->vif) &&
|
||||
status->freq) {
|
||||
struct ieee80211_link_data *link;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
|
||||
for_each_link_data_rcu(rx->sdata, link) {
|
||||
conf = rcu_dereference(link->conf->chanctx_conf);
|
||||
if (!conf || !conf->def.chan)
|
||||
continue;
|
||||
|
||||
if (status->freq == conf->def.chan->center_freq) {
|
||||
link_id = link->link_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ieee80211_rx_data_set_sta(rx, sta, link_id))
|
||||
conf = rcu_dereference(link->conf->chanctx_conf);
|
||||
if (!conf || !conf->def.chan)
|
||||
return false;
|
||||
|
||||
return ieee80211_prepare_and_rx_handle(rx, skb, consume);
|
||||
return freq == conf->def.chan->center_freq;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -5367,18 +5338,20 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
|
|||
* be called with rcu_read_lock protection.
|
||||
*/
|
||||
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *pubsta,
|
||||
struct ieee80211_link_sta *link_pubsta,
|
||||
struct sk_buff *skb,
|
||||
struct list_head *list)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct link_sta_info *link_sta;
|
||||
struct sta_info *sta;
|
||||
__le16 fc;
|
||||
struct ieee80211_rx_data rx;
|
||||
struct ieee80211_sub_if_data *prev;
|
||||
struct rhlist_head *tmp;
|
||||
bool rx_data_pending;
|
||||
int err = 0;
|
||||
|
||||
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
||||
|
|
@ -5386,7 +5359,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
rx.skb = skb;
|
||||
rx.local = local;
|
||||
rx.list = list;
|
||||
rx.link_id = -1;
|
||||
|
||||
if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
|
||||
I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
|
||||
|
|
@ -5426,97 +5398,102 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
ieee80211_is_s1g_beacon(hdr->frame_control)))
|
||||
ieee80211_scan_rx(local, skb);
|
||||
|
||||
/*
|
||||
* RX of a data frame should only happen to existing stations.
|
||||
* It is therefore more efficient to use the one provided by the driver
|
||||
* or search based on the station's address.
|
||||
*
|
||||
* Note we will fall through and handle a spurious data frame in the
|
||||
* same way as a management frame.
|
||||
*/
|
||||
if (ieee80211_is_data(fc)) {
|
||||
struct sta_info *sta, *prev_sta;
|
||||
int link_id = -1;
|
||||
if (link_pubsta) {
|
||||
sta = container_of(link_pubsta->sta, struct sta_info,
|
||||
sta);
|
||||
link_sta = rcu_dereference(sta->link[link_pubsta->link_id]);
|
||||
|
||||
if (status->link_valid)
|
||||
link_id = status->link_id;
|
||||
|
||||
if (pubsta) {
|
||||
sta = container_of(pubsta, struct sta_info, sta);
|
||||
if (!ieee80211_rx_data_set_sta(&rx, sta, link_id))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* In MLO connection, fetch the link_id using addr2
|
||||
* when the driver does not pass link_id in status.
|
||||
* When the address translation is already performed by
|
||||
* driver/hw, the valid link_id must be passed in
|
||||
* status.
|
||||
*/
|
||||
|
||||
if (!status->link_valid && pubsta->mlo) {
|
||||
struct link_sta_info *link_sta;
|
||||
|
||||
link_sta = link_sta_info_get_bss(rx.sdata,
|
||||
hdr->addr2);
|
||||
if (!link_sta)
|
||||
goto out;
|
||||
|
||||
if (!ieee80211_rx_data_set_link(&rx,
|
||||
link_sta->link_id))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
||||
rx.sdata = sta->sdata;
|
||||
if (ieee80211_rx_data_set_link_sta(&rx, link_sta) &&
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
||||
return;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
prev_sta = NULL;
|
||||
rx_data_pending = false;
|
||||
|
||||
/* Search for stations on non-MLD interfaces */
|
||||
for_each_sta_info(local, hdr->addr2, sta, tmp) {
|
||||
if (!prev_sta) {
|
||||
prev_sta = sta;
|
||||
struct ieee80211_link_data *link;
|
||||
|
||||
if (ieee80211_vif_is_mld(&sta->sdata->vif))
|
||||
continue;
|
||||
|
||||
link = &sta->sdata->deflink;
|
||||
if (!ieee80211_rx_valid_freq(status->freq, link))
|
||||
continue;
|
||||
|
||||
if (rx_data_pending) {
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb,
|
||||
false);
|
||||
rx_data_pending = false;
|
||||
}
|
||||
|
||||
rx.sdata = prev_sta->sdata;
|
||||
if (!status->link_valid && prev_sta->sta.mlo) {
|
||||
struct link_sta_info *link_sta;
|
||||
rx.sdata = sta->sdata;
|
||||
if (!ieee80211_rx_data_set_link_sta(&rx, &sta->deflink))
|
||||
continue;
|
||||
|
||||
link_sta = link_sta_info_get_bss(rx.sdata,
|
||||
hdr->addr2);
|
||||
if (!link_sta)
|
||||
continue;
|
||||
|
||||
link_id = link_sta->link_id;
|
||||
}
|
||||
|
||||
if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
|
||||
goto out;
|
||||
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb, false);
|
||||
|
||||
prev_sta = sta;
|
||||
rx_data_pending = true;
|
||||
}
|
||||
|
||||
if (prev_sta) {
|
||||
rx.sdata = prev_sta->sdata;
|
||||
if (!status->link_valid && prev_sta->sta.mlo) {
|
||||
struct link_sta_info *link_sta;
|
||||
/* And search stations on MLD interfaces */
|
||||
for_each_link_sta_info(local, hdr->addr2, link_sta, tmp) {
|
||||
struct ieee80211_link_data *link;
|
||||
|
||||
link_sta = link_sta_info_get_bss(rx.sdata,
|
||||
hdr->addr2);
|
||||
if (!link_sta)
|
||||
goto out;
|
||||
sta = link_sta->sta;
|
||||
sdata = sta->sdata;
|
||||
link = rcu_dereference(sdata->link[link_sta->link_id]);
|
||||
|
||||
link_id = link_sta->link_id;
|
||||
if (!ieee80211_rx_valid_freq(status->freq, link))
|
||||
continue;
|
||||
|
||||
if (rx_data_pending) {
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb,
|
||||
false);
|
||||
rx_data_pending = false;
|
||||
}
|
||||
|
||||
if (!ieee80211_rx_data_set_sta(&rx, prev_sta, link_id))
|
||||
goto out;
|
||||
rx.sdata = sta->sdata;
|
||||
if (!ieee80211_rx_data_set_link_sta(&rx, link_sta))
|
||||
continue;
|
||||
|
||||
rx_data_pending = true;
|
||||
}
|
||||
|
||||
if (rx_data_pending) {
|
||||
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
||||
return;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* fall through, e.g. for spurious frame notification */
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
/*
|
||||
* This is a management frame (or a data frame without a station) and
|
||||
* it will be delivered independent of whether a station exists,
|
||||
* so iterate the interfaces.
|
||||
*/
|
||||
rx_data_pending = false;
|
||||
|
||||
/* We expect the driver to provide frequency information */
|
||||
if (WARN_ON_ONCE(!local->emulate_chanctx && !status->freq))
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
struct ieee80211_link_data *link = NULL;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
|
|
@ -5524,29 +5501,84 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* frame is destined for this interface, but if it's
|
||||
* not also for the previous one we handle that after
|
||||
* the loop to avoid copying the SKB once too much
|
||||
*/
|
||||
link_sta = NULL;
|
||||
link = NULL;
|
||||
|
||||
/* Try to resolve the station */
|
||||
if (!ieee80211_vif_is_mld(&sdata->vif)) {
|
||||
sta = sta_info_get_bss(sdata, hdr->addr2);
|
||||
|
||||
if (sta) {
|
||||
link_sta = &sta->deflink;
|
||||
link = &sdata->deflink;
|
||||
}
|
||||
} else {
|
||||
link_sta = link_sta_info_get_bss(sdata, hdr->addr2);
|
||||
|
||||
if (link_sta)
|
||||
link = rcu_dereference(sdata->link[link_sta->link_id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found a STA and it has a valid link information, then
|
||||
* RX using the station.
|
||||
*/
|
||||
if (link_sta && link &&
|
||||
ieee80211_rx_valid_freq(status->freq, link)) {
|
||||
if (rx_data_pending) {
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb, false);
|
||||
rx_data_pending = false;
|
||||
}
|
||||
|
||||
/* No valid_links check as we need to RX beacons */
|
||||
|
||||
rx.sdata = sdata;
|
||||
if (ieee80211_rx_data_set_link_sta(&rx, link_sta))
|
||||
rx_data_pending = true;
|
||||
|
||||
if (!prev) {
|
||||
prev = sdata;
|
||||
continue;
|
||||
}
|
||||
|
||||
rx.sdata = prev;
|
||||
ieee80211_rx_for_interface(&rx, skb, false);
|
||||
/* No station, try to resolve the link and RX */
|
||||
if (ieee80211_vif_is_mld(&sdata->vif)) {
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
bool found = false;
|
||||
|
||||
prev = sdata;
|
||||
for_each_link_data_rcu(sdata, link) {
|
||||
conf = rcu_dereference(link->conf->chanctx_conf);
|
||||
if (!conf || !conf->def.chan)
|
||||
continue;
|
||||
|
||||
if (status->freq == conf->def.chan->center_freq) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
link = &sdata->deflink;
|
||||
} else {
|
||||
link = &sdata->deflink;
|
||||
}
|
||||
|
||||
if (rx_data_pending) {
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb, false);
|
||||
rx_data_pending = false;
|
||||
}
|
||||
|
||||
rx.sdata = sdata;
|
||||
rx.local = sdata->local;
|
||||
rx.link = link;
|
||||
rx.link_id = link->link_id;
|
||||
rx.sta = NULL;
|
||||
rx.link_sta = NULL;
|
||||
|
||||
rx_data_pending = true;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
rx.sdata = prev;
|
||||
|
||||
if (ieee80211_rx_for_interface(&rx, skb, true))
|
||||
return;
|
||||
}
|
||||
if (rx_data_pending &&
|
||||
ieee80211_prepare_and_rx_handle(&rx, skb, true))
|
||||
return;
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
|
|
@ -5556,7 +5588,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
* This is the receive path handler. It is called by a low level driver when an
|
||||
* 802.11 MPDU is received from the hardware.
|
||||
*/
|
||||
void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
||||
void ieee80211_rx_list(struct ieee80211_hw *hw,
|
||||
struct ieee80211_link_sta *link_pubsta,
|
||||
struct sk_buff *skb, struct list_head *list)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
|
@ -5694,9 +5727,6 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
|||
}
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(status->link_id >= IEEE80211_LINK_UNSPECIFIED))
|
||||
goto drop;
|
||||
|
||||
status->rx_flags = 0;
|
||||
|
||||
kcov_remote_start_common(skb_get_kcov_handle(skb));
|
||||
|
|
@ -5715,9 +5745,10 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
|||
ieee80211_tpt_led_trig_rx(local, skb->len);
|
||||
|
||||
if (status->flag & RX_FLAG_8023)
|
||||
__ieee80211_rx_handle_8023(hw, pubsta, skb, list);
|
||||
__ieee80211_rx_handle_8023(hw, link_pubsta, skb, list);
|
||||
else
|
||||
__ieee80211_rx_handle_packet(hw, pubsta, skb, list);
|
||||
__ieee80211_rx_handle_packet(hw, link_pubsta, skb,
|
||||
list);
|
||||
}
|
||||
|
||||
kcov_remote_stop();
|
||||
|
|
@ -5727,7 +5758,8 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_rx_list);
|
||||
|
||||
void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
||||
void ieee80211_rx_napi(struct ieee80211_hw *hw,
|
||||
struct ieee80211_link_sta *link_pubsta,
|
||||
struct sk_buff *skb, struct napi_struct *napi)
|
||||
{
|
||||
struct sk_buff *tmp;
|
||||
|
|
@ -5740,7 +5772,7 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
|||
* receive processing
|
||||
*/
|
||||
rcu_read_lock();
|
||||
ieee80211_rx_list(hw, pubsta, skb, &list);
|
||||
ieee80211_rx_list(hw, link_pubsta, skb, &list);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!napi) {
|
||||
|
|
|
|||
|
|
@ -9,14 +9,6 @@
|
|||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
void ieee80211_s1g_sta_rate_init(struct sta_info *sta)
|
||||
{
|
||||
/* avoid indicating legacy bitrates for S1G STAs */
|
||||
sta->deflink.tx_stats.last_rate.flags |= IEEE80211_TX_RC_S1G_MCS;
|
||||
sta->deflink.rx_stats.last_rate =
|
||||
STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
|
||||
}
|
||||
|
||||
bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright 2016-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2018-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/if_arp.h>
|
||||
|
|
@ -204,12 +204,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
* an indication on which of the links the frame was received
|
||||
*/
|
||||
if (ieee80211_vif_is_mld(&scan_sdata->vif)) {
|
||||
if (rx_status->link_valid) {
|
||||
s8 link_id = rx_status->link_id;
|
||||
s8 link_id = rx_status->link_id;
|
||||
|
||||
link_conf =
|
||||
rcu_dereference(scan_sdata->vif.link_conf[link_id]);
|
||||
}
|
||||
link_conf =
|
||||
rcu_dereference(scan_sdata->vif.link_conf[link_id]);
|
||||
} else {
|
||||
link_conf = &scan_sdata->vif.bss_conf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
|
||||
ieee80211_tx_skb_tid(sdata, skb, 7, link_id);
|
||||
ieee80211_tx_skb_tid(sdata, skb, sta, 7, link_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1121,7 +1121,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
|
|||
/* disable bottom halves when entering the Tx path */
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, dev, flags,
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, 0);
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC);
|
||||
local_bh_enable();
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -219,10 +219,8 @@ static void test_determine_chan_mode(struct kunit *test)
|
|||
/* To force EHT downgrade to HE on punctured 80 MHz downgraded to 40 MHz */
|
||||
set_bit(IEEE80211_HW_DISALLOW_PUNCTURING, t_sdata->local.hw.flags);
|
||||
|
||||
if (params->strict)
|
||||
set_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags);
|
||||
else
|
||||
clear_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags);
|
||||
assign_bit(IEEE80211_HW_STRICT, t_sdata->local.hw.flags,
|
||||
params->strict);
|
||||
|
||||
t_sdata->sdata->u.mgd.ht_capa_mask = params->ht_capa_mask;
|
||||
t_sdata->sdata->u.mgd.vht_capa = params->vht_capa;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Utilities for mac80211 unit testing
|
||||
*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024, 2026 Intel Corporation
|
||||
*/
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
|
|
@ -226,10 +226,6 @@ int t_sdata_init(struct kunit_resource *resource, void *ctx)
|
|||
sband = t_sdata->wiphy->bands[band];
|
||||
sband->band = band;
|
||||
|
||||
sband->bitrates =
|
||||
kmemdup(bitrates, sizeof(bitrates), GFP_KERNEL);
|
||||
sband->n_bitrates = ARRAY_SIZE(bitrates);
|
||||
|
||||
/* Initialize channels, feel free to add more channels/bands */
|
||||
switch (band) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
|
|
|
|||
|
|
@ -269,7 +269,6 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
|
|||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
bool assoc = false;
|
||||
|
|
@ -277,20 +276,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
|||
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
|
||||
test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
|
||||
!ieee80211_is_probe_req(hdr->frame_control) &&
|
||||
!ieee80211_is_any_nullfunc(hdr->frame_control))
|
||||
/*
|
||||
* When software scanning only nullfunc frames (to notify
|
||||
* the sleep state to the AP) and probe requests (for the
|
||||
* active scan) are allowed, all other frames should not be
|
||||
* sent and we should not get here, but if we do
|
||||
* nonetheless, drop them to avoid sending them
|
||||
* off-channel. See __ieee80211_start_scan() for more.
|
||||
*/
|
||||
return TX_DROP;
|
||||
|
||||
if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
|
||||
return TX_CONTINUE;
|
||||
|
||||
|
|
@ -589,6 +574,43 @@ ieee80211_select_link_key(struct ieee80211_tx_data *tx)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* An 802.3 frame is always a data frame, so there are no 802.11 addresses to
|
||||
* look at: with a station the pairwise key is all that can apply, without one
|
||||
* the frame is group addressed. On an MLD the driver has to pick the group key
|
||||
* itself, as the same frame goes out on several links that each have their own.
|
||||
*/
|
||||
static ieee80211_tx_result
|
||||
ieee80211_select_key_8023(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (tx->sta) {
|
||||
tx->key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]);
|
||||
if (!tx->key)
|
||||
tx->key = rcu_dereference(tx->sdata->default_unicast_key);
|
||||
|
||||
if (!tx->key && test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION))
|
||||
return TX_DROP;
|
||||
} else if (!ieee80211_vif_is_mld(&tx->sdata->vif)) {
|
||||
tx->key = rcu_dereference(tx->sdata->deflink.default_multicast_key);
|
||||
}
|
||||
|
||||
if (!tx->key)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (unlikely(tx->key->flags & KEY_FLAG_TAINTED))
|
||||
return TX_DROP;
|
||||
|
||||
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
|
||||
info->control.hw_key = &tx->key->conf;
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
|
|
@ -596,6 +618,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
|
||||
return ieee80211_select_key_8023(tx);
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) {
|
||||
tx->key = NULL;
|
||||
return TX_CONTINUE;
|
||||
|
|
@ -612,12 +637,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
else
|
||||
tx->key = NULL;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
|
||||
if (tx->key && tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
|
||||
info->control.hw_key = &tx->key->conf;
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
if (tx->key) {
|
||||
bool skip_hw = false;
|
||||
|
||||
|
|
@ -807,6 +826,33 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static ieee80211_tx_result debug_noinline
|
||||
ieee80211_tx_h_check_offchannel(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
|
||||
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
|
||||
test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
|
||||
!ieee80211_is_probe_req(hdr->frame_control) &&
|
||||
!ieee80211_is_any_nullfunc(hdr->frame_control)) {
|
||||
/*
|
||||
* When software scanning only nullfunc frames (to notify
|
||||
* the sleep state to the AP) and probe requests (for the
|
||||
* active scan) are allowed, all other frames should not be
|
||||
* sent and we should not get here, but if we do
|
||||
* nonetheless, drop them to avoid sending them
|
||||
* off-channel. See __ieee80211_start_scan() for more.
|
||||
*/
|
||||
return TX_DROP;
|
||||
}
|
||||
|
||||
return TX_CONTINUE;
|
||||
}
|
||||
|
||||
static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid)
|
||||
{
|
||||
u16 *seq = &sta->tid_seq[tid];
|
||||
|
|
@ -1873,6 +1919,7 @@ static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
|
|||
goto txh_done;
|
||||
}
|
||||
|
||||
CALL_TXH(ieee80211_tx_h_check_offchannel);
|
||||
CALL_TXH(ieee80211_tx_h_michael_mic_add);
|
||||
CALL_TXH(ieee80211_tx_h_sequence);
|
||||
CALL_TXH(ieee80211_tx_h_fragment);
|
||||
|
|
@ -2127,7 +2174,8 @@ static bool ieee80211_rate_bw_usable(u16 rate_flags,
|
|||
|
||||
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
bool trim_fcs)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_radiotap_iterator iterator;
|
||||
|
|
@ -2184,7 +2232,8 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
|||
if (skb->len < (iterator._max_length + FCS_LEN))
|
||||
return false;
|
||||
|
||||
skb_trim(skb, skb->len - FCS_LEN);
|
||||
if (trim_fcs)
|
||||
skb_trim(skb, skb->len - FCS_LEN);
|
||||
}
|
||||
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
|
||||
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
|
@ -2503,7 +2552,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|||
* selected chandef above to accurately set injection rates and
|
||||
* retransmissions.
|
||||
*/
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, chandef))
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, chandef, true))
|
||||
goto fail_rcu;
|
||||
|
||||
/* remove the injection radiotap header */
|
||||
|
|
@ -2530,9 +2579,16 @@ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
|
|||
skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
|
||||
}
|
||||
|
||||
int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct sta_info **sta_out)
|
||||
/*
|
||||
* Returns an error if the frame should be dropped, otherwise
|
||||
* the *sta_out pointer is filled:
|
||||
* - valid sta pointer: frame goes to that station
|
||||
* - NULL: frame will be unicast to a yet unknown station
|
||||
* - ERR_PTR(-ENOENT): frame will be group addressed
|
||||
*/
|
||||
static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct sta_info **sta_out)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
|
|
@ -2557,6 +2613,10 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
|||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (is_multicast_ether_addr(skb->data)) {
|
||||
*sta_out = ERR_PTR(-ENOENT);
|
||||
return 0;
|
||||
}
|
||||
/* determined much later */
|
||||
*sta_out = NULL;
|
||||
return 0;
|
||||
|
|
@ -2599,17 +2659,15 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
*sta_out = sta ?: ERR_PTR(-ENOENT);
|
||||
*sta_out = sta;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 ieee80211_store_ack_skb(struct ieee80211_local *local,
|
||||
struct sk_buff *skb,
|
||||
u32 *info_flags,
|
||||
u64 cookie)
|
||||
static void ieee80211_store_ack_skb(struct ieee80211_local *local,
|
||||
struct sk_buff *skb, u64 cookie)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct sk_buff *ack_skb;
|
||||
u16 info_id = 0;
|
||||
|
||||
if (skb->sk)
|
||||
ack_skb = skb_clone_sk(skb);
|
||||
|
|
@ -2626,58 +2684,41 @@ static u16 ieee80211_store_ack_skb(struct ieee80211_local *local,
|
|||
spin_unlock_irqrestore(&local->ack_status_lock, flags);
|
||||
|
||||
if (id >= 0) {
|
||||
info_id = id;
|
||||
*info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
info->status_data = id;
|
||||
info->status_data_idr = 1;
|
||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
if (cookie)
|
||||
IEEE80211_SKB_CB(ack_skb)->ack.cookie = cookie;
|
||||
} else {
|
||||
kfree_skb(ack_skb);
|
||||
}
|
||||
}
|
||||
|
||||
return info_id;
|
||||
}
|
||||
|
||||
static void ieee80211_remove_ack_skb(struct ieee80211_local *local, u16 info_id)
|
||||
{
|
||||
struct sk_buff *ack_skb;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&local->ack_status_lock, flags);
|
||||
ack_skb = idr_remove(&local->ack_status_frames, info_id);
|
||||
spin_unlock_irqrestore(&local->ack_status_lock, flags);
|
||||
|
||||
kfree_skb(ack_skb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_build_hdr - build 802.11 header in the given frame
|
||||
* @sdata: virtual interface to build the header for
|
||||
* @skb: the skb to build the header in
|
||||
* @info_flags: skb flags to set
|
||||
* @sta: the station pointer
|
||||
* @ctrl_flags: info control flags to set
|
||||
* @cookie: cookie pointer to fill (if not %NULL)
|
||||
*
|
||||
* This function takes the skb with 802.3 header and reformats the header to
|
||||
* the appropriate IEEE 802.11 header based on which interface the packet is
|
||||
* being transmitted on.
|
||||
*
|
||||
* Note that this function also takes care of the TX status request and
|
||||
* potential unsharing of the SKB - this needs to be interleaved with the
|
||||
* header building.
|
||||
* Note that this function also takes care of the TX status request. The skb
|
||||
* must not be shared, and its TX info must already be initialised - this
|
||||
* function only fills in what it determines itself.
|
||||
*
|
||||
* The function requires the read-side RCU lock held
|
||||
*
|
||||
* Returns: the (possibly reallocated) skb or an ERR_PTR() code
|
||||
*/
|
||||
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, u32 info_flags,
|
||||
struct sta_info *sta, u32 ctrl_flags,
|
||||
u64 cookie)
|
||||
struct sk_buff *skb,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
int head_need;
|
||||
u16 ethertype, hdrlen, meshhdrlen = 0;
|
||||
__le16 fc;
|
||||
|
|
@ -2689,18 +2730,18 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
bool wme_sta = false, authorized = false;
|
||||
bool tdls_peer;
|
||||
bool multicast;
|
||||
u16 info_id = 0;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf = NULL;
|
||||
enum nl80211_band band;
|
||||
int ret;
|
||||
u8 link_id = u32_get_bits(ctrl_flags, IEEE80211_TX_CTRL_MLO_LINK);
|
||||
u8 link_id = u32_get_bits(info->control.flags,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
if (local->force_tx_status)
|
||||
info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
#endif
|
||||
|
||||
/* convert Ethernet header to proper 802.11 header (based on
|
||||
|
|
@ -2841,7 +2882,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
/* For injected frames, fill RA right away as nexthop lookup
|
||||
* will be skipped.
|
||||
*/
|
||||
if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
|
||||
if ((info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
|
||||
is_zero_ether_addr(hdr.addr1))
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
break;
|
||||
|
|
@ -2970,34 +3011,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
goto free;
|
||||
}
|
||||
|
||||
if (unlikely(!multicast &&
|
||||
(sk_requests_wifi_status(skb->sk) ||
|
||||
ctrl_flags & IEEE80211_TX_CTL_REQ_TX_STATUS)))
|
||||
info_id = ieee80211_store_ack_skb(local, skb, &info_flags,
|
||||
cookie);
|
||||
|
||||
/*
|
||||
* If the skb is shared we need to obtain our own copy.
|
||||
*/
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb)) {
|
||||
/* skb_share_check() already freed the skb */
|
||||
if (info_id)
|
||||
ieee80211_remove_ack_skb(local, info_id);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* set this up so failure paths can clean up ack skb */
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
info->flags = info_flags;
|
||||
if (info_id) {
|
||||
info->status_data = info_id;
|
||||
info->status_data_idr = 1;
|
||||
}
|
||||
info->band = band;
|
||||
|
||||
hdr.frame_control = fc;
|
||||
hdr.duration_id = 0;
|
||||
hdr.seq_ctrl = 0;
|
||||
|
|
@ -3037,7 +3050,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
head_need = max_t(int, 0, head_need);
|
||||
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
|
||||
ret = -ENOMEM;
|
||||
goto free_txskb;
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3064,41 +3077,14 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
if (likely(!cookie)) {
|
||||
ctrl_flags |= u32_encode_bits(link_id,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
} else {
|
||||
unsigned int pre_conf_link_id;
|
||||
|
||||
/*
|
||||
* ctrl_flags already have been set by
|
||||
* ieee80211_tx_control_port(), here
|
||||
* we just sanity check that
|
||||
*/
|
||||
|
||||
pre_conf_link_id = u32_get_bits(ctrl_flags,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
if (pre_conf_link_id != link_id &&
|
||||
link_id != IEEE80211_LINK_UNSPECIFIED) {
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
net_info_ratelimited("%s: dropped frame to %pM with bad link ID request (%d vs. %d)\n",
|
||||
sdata->name, hdr.addr1,
|
||||
pre_conf_link_id, link_id);
|
||||
#endif
|
||||
ret = -EINVAL;
|
||||
goto free_txskb;
|
||||
}
|
||||
}
|
||||
|
||||
info->control.flags = ctrl_flags;
|
||||
info->band = band;
|
||||
|
||||
info->control.flags =
|
||||
u32_replace_bits(info->control.flags, link_id,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
return skb;
|
||||
free_txskb:
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
return ERR_PTR(ret);
|
||||
free:
|
||||
kfree_skb(skb);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
@ -3905,6 +3891,38 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ieee80211_drop_unauth_port(struct ieee80211_tx_data *tx)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
if (likely(test_sta_flag(tx->sta, WLAN_STA_AUTHORIZED)))
|
||||
return false;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_INJECTED)
|
||||
return false;
|
||||
|
||||
if (ieee80211_vif_is_mesh(&tx->sdata->vif) ||
|
||||
tx->sdata->vif.type == NL80211_IFTYPE_OCB)
|
||||
return false;
|
||||
|
||||
/* no need to check forwarding here */
|
||||
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
|
||||
return !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO);
|
||||
|
||||
hdr = (struct ieee80211_hdr *)tx->skb->data;
|
||||
|
||||
if (!ieee80211_is_data_present(hdr->frame_control) ||
|
||||
is_multicast_ether_addr(hdr->addr1))
|
||||
return false;
|
||||
|
||||
if ((info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) &&
|
||||
ieee80211_is_our_addr(tx->sdata, hdr->addr2, NULL))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
||||
|
|
@ -3971,20 +3989,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
|||
|
||||
if (txq->sta) {
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
/*
|
||||
* Drop unicast frames to unauthorised stations unless they are
|
||||
* injected frames or EAPOL frames from the local station.
|
||||
*/
|
||||
if (unlikely(!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
|
||||
ieee80211_is_data_present(hdr->frame_control) &&
|
||||
!ieee80211_vif_is_mesh(&tx.sdata->vif) &&
|
||||
tx.sdata->vif.type != NL80211_IFTYPE_OCB &&
|
||||
!is_multicast_ether_addr(hdr->addr1) &&
|
||||
!test_sta_flag(tx.sta, WLAN_STA_AUTHORIZED) &&
|
||||
(!(info->control.flags &
|
||||
IEEE80211_TX_CTRL_PORT_CTRL_PROTO) ||
|
||||
!ieee80211_is_our_addr(tx.sdata, hdr->addr2,
|
||||
NULL)))) {
|
||||
|
||||
if (unlikely(ieee80211_drop_unauth_port(&tx))) {
|
||||
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
goto begin;
|
||||
|
|
@ -4156,7 +4162,7 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
|
|||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
if (!local->schedule_round[ac])
|
||||
if (!local->schedule_open[ac])
|
||||
goto out;
|
||||
|
||||
begin:
|
||||
|
|
@ -4381,12 +4387,12 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
|||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
if (ieee80211_txq_schedule_airtime_check(local, ac)) {
|
||||
local->schedule_open[ac] =
|
||||
ieee80211_txq_schedule_airtime_check(local, ac);
|
||||
if (local->schedule_open[ac]) {
|
||||
local->schedule_round[ac]++;
|
||||
if (!local->schedule_round[ac])
|
||||
local->schedule_round[ac]++;
|
||||
} else {
|
||||
local->schedule_round[ac] = 0;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
|
|
@ -4396,13 +4402,14 @@ EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
|||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags,
|
||||
u32 ctrl_flags,
|
||||
u64 cookie)
|
||||
u32 ctrl_flags)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sta_info *sta;
|
||||
struct sk_buff *next;
|
||||
bool group_addressed;
|
||||
int len = skb->len;
|
||||
|
||||
if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
|
||||
|
|
@ -4422,6 +4429,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
|
||||
goto out_free;
|
||||
|
||||
group_addressed = IS_ERR(sta);
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
|
||||
|
|
@ -4454,8 +4462,22 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
if (skb->protocol == sdata->control_port_protocol)
|
||||
ctrl_flags |= IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP;
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags,
|
||||
sta, ctrl_flags, cookie);
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb)) {
|
||||
kfree_skb_list(next);
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags = info_flags;
|
||||
info->control.flags = ctrl_flags;
|
||||
|
||||
if (unlikely(!group_addressed &&
|
||||
sk_requests_wifi_status(skb->sk)))
|
||||
ieee80211_store_ack_skb(local, skb, 0);
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, sta);
|
||||
if (IS_ERR(skb)) {
|
||||
kfree_skb_list(next);
|
||||
goto out;
|
||||
|
|
@ -4592,7 +4614,7 @@ static void ieee80211_mlo_multicast_tx_one(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
|
||||
ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK);
|
||||
__ieee80211_subif_start_xmit(out, sdata->dev, 0, ctrl_flags, 0);
|
||||
__ieee80211_subif_start_xmit(out, sdata->dev, 0, ctrl_flags);
|
||||
}
|
||||
|
||||
static void ieee80211_mlo_multicast_tx(struct net_device *dev,
|
||||
|
|
@ -4607,7 +4629,7 @@ static void ieee80211_mlo_multicast_tx(struct net_device *dev,
|
|||
ctrl_flags |= u32_encode_bits(__ffs(links),
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
__ieee80211_subif_start_xmit(skb, sdata->dev, 0, ctrl_flags, 0);
|
||||
__ieee80211_subif_start_xmit(skb, sdata->dev, 0, ctrl_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4648,8 +4670,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
ieee80211_convert_to_unicast(skb, dev, &queue);
|
||||
while ((skb = __skb_dequeue(&queue)))
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0,
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
|
||||
0);
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC);
|
||||
} else if (ieee80211_vif_is_mld(&sdata->vif) &&
|
||||
((sdata->vif.type == NL80211_IFTYPE_AP &&
|
||||
!ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) ||
|
||||
|
|
@ -4659,8 +4680,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
} else {
|
||||
normal:
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0,
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
|
||||
0);
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC);
|
||||
}
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
|
@ -4740,10 +4760,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
queue = ieee80211_select_queue(sdata, sta, skb);
|
||||
skb_set_queue_mapping(skb, queue);
|
||||
|
||||
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
|
||||
test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
|
||||
goto out_free;
|
||||
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb))
|
||||
return;
|
||||
|
|
@ -4758,8 +4774,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
|
||||
/* fall back to non-offload slow path */
|
||||
__ieee80211_subif_start_xmit(skb, dev, 0,
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
|
||||
0);
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4793,12 +4808,8 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
|
||||
}
|
||||
|
||||
if (unlikely(sk_requests_wifi_status(skb->sk))) {
|
||||
info->status_data = ieee80211_store_ack_skb(local, skb,
|
||||
&info->flags, 0);
|
||||
if (info->status_data)
|
||||
info->status_data_idr = 1;
|
||||
}
|
||||
if (unlikely(sk_requests_wifi_status(skb->sk)))
|
||||
ieee80211_store_ack_skb(local, skb, 0);
|
||||
|
||||
dev_sw_netstats_tx_add(dev, skbs, len);
|
||||
|
||||
|
|
@ -4810,11 +4821,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_tpt_led_trig_tx(local, len);
|
||||
|
||||
ieee80211_tx_8023(sdata, skb, sta, false);
|
||||
|
||||
return;
|
||||
|
||||
out_free:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static bool ieee80211_check_mcast_offload(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -4927,6 +4933,7 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
|||
.local = sdata->local,
|
||||
.sdata = sdata,
|
||||
};
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
|
@ -4937,8 +4944,12 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
|
|||
goto out;
|
||||
}
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta,
|
||||
IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, 0);
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags = info_flags;
|
||||
info->control.flags = IEEE80211_TX_CTRL_MLO_LINK_UNSPEC;
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, sta);
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
|
||||
|
|
@ -6467,7 +6478,8 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid)
|
|||
EXPORT_SYMBOL(ieee80211_unreserve_tid);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid, int link_id,
|
||||
struct sk_buff *skb, struct sta_info *sta,
|
||||
int tid, int link_id,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
|
|
@ -6519,12 +6531,13 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
local_bh_disable();
|
||||
IEEE80211_SKB_CB(skb)->band = band;
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid, int link_id)
|
||||
struct sk_buff *skb, struct sta_info *sta,
|
||||
int tid, int link_id)
|
||||
{
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
enum nl80211_band band;
|
||||
|
|
@ -6550,7 +6563,7 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
|
|||
band = 0;
|
||||
}
|
||||
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, tid, link_id, band);
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, sta, tid, link_id, band);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
@ -6561,6 +6574,8 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
|||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info;
|
||||
bool group_addressed;
|
||||
struct sta_info *sta;
|
||||
struct sk_buff *skb;
|
||||
struct ethhdr *ehdr;
|
||||
|
|
@ -6585,9 +6600,6 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (unencrypted)
|
||||
flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||
|
||||
if (cookie)
|
||||
ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
|
||||
flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
||||
|
|
@ -6604,15 +6616,11 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
/* we may override the SA for MLO STA later */
|
||||
if (link_id < 0) {
|
||||
ctrl_flags |= u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
link_id = IEEE80211_LINK_UNSPECIFIED;
|
||||
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
|
||||
} else {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
ctrl_flags |= u32_encode_bits(link_id,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
rcu_read_lock();
|
||||
link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
|
||||
if (!link_conf) {
|
||||
|
|
@ -6631,9 +6639,6 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
|||
skb_reset_network_header(skb);
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
goto start_xmit;
|
||||
|
||||
/* update QoS header to prioritize control port frames if possible,
|
||||
* prioritization also happens for control port frames send over
|
||||
* AF_PACKET
|
||||
|
|
@ -6646,24 +6651,47 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!IS_ERR(sta)) {
|
||||
u16 queue = ieee80211_select_queue(sdata, sta, skb);
|
||||
group_addressed = IS_ERR(sta);
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
|
||||
skb_set_queue_mapping(skb, queue);
|
||||
skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
|
||||
|
||||
/*
|
||||
* for MLO STA, the SA should be the AP MLD address, but
|
||||
* the link ID has been selected already
|
||||
*/
|
||||
if (sta && sta->sta.mlo)
|
||||
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
|
||||
/*
|
||||
* for MLO STA, the SA should be the AP MLD address, but
|
||||
* the link ID has been selected already
|
||||
*/
|
||||
if (sta && sta->sta.mlo)
|
||||
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->flags = flags;
|
||||
ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK);
|
||||
info->control.flags = ctrl_flags;
|
||||
|
||||
if (!group_addressed)
|
||||
ieee80211_store_ack_skb(local, skb, cookie);
|
||||
|
||||
skb = ieee80211_build_hdr(sdata, skb, sta);
|
||||
if (IS_ERR(skb)) {
|
||||
rcu_read_unlock();
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
if (link_id != u32_get_bits(info->control.flags,
|
||||
IEEE80211_TX_CTRL_MLO_LINK)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
start_xmit:
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, flags, ctrl_flags, cookie);
|
||||
dev_sw_netstats_tx_add(dev, 1, skb->len);
|
||||
ieee80211_tpt_led_trig_tx(local, skb->len);
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
local_bh_enable();
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6691,8 +6719,7 @@ int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
local_bh_disable();
|
||||
__ieee80211_subif_start_xmit(skb, skb->dev, 0,
|
||||
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP,
|
||||
0);
|
||||
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP);
|
||||
local_bh_enable();
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
|
|||
EXPORT_SYMBOL(wiphy_to_ieee80211_hw);
|
||||
|
||||
const struct ieee80211_conn_settings ieee80211_conn_settings_unlimited = {
|
||||
.mode = IEEE80211_CONN_MODE_EHT,
|
||||
.mode = IEEE80211_CONN_MODE_HIGHEST,
|
||||
.bw_limit = IEEE80211_CONN_BW_LIMIT_320,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -568,8 +568,8 @@ int cfg80211_chandef_add_npca(struct wiphy *wiphy,
|
|||
const struct ieee80211_uhr_npca_info *npca)
|
||||
{
|
||||
struct cfg80211_chan_def new_chandef = *chandef;
|
||||
u32 width, npca_freq;
|
||||
u8 offs;
|
||||
u32 npca_freq;
|
||||
u8 chan;
|
||||
|
||||
if (chandef->npca_chan || chandef->npca_punctured)
|
||||
return -EINVAL;
|
||||
|
|
@ -589,11 +589,10 @@ int cfg80211_chandef_add_npca(struct wiphy *wiphy,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
offs = le32_get_bits(npca->params,
|
||||
IEEE80211_UHR_NPCA_PARAMS_PRIMARY_CHAN_OFFS);
|
||||
chan = le32_get_bits(npca->params,
|
||||
IEEE80211_UHR_NPCA_PARAMS_PRIMARY_CHAN);
|
||||
|
||||
width = cfg80211_chandef_get_width(chandef);
|
||||
npca_freq = chandef->center_freq1 - width / 2 + 10 + 20 * offs;
|
||||
npca_freq = ieee80211_channel_to_frequency(chan, chandef->chan->band);
|
||||
new_chandef.npca_chan = ieee80211_get_channel(wiphy, npca_freq);
|
||||
if (!new_chandef.npca_chan)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -569,6 +569,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
|
|||
[NL80211_TXRATE_EHT_LTF] = NLA_POLICY_RANGE(NLA_U8,
|
||||
NL80211_RATE_INFO_EHT_1XLTF,
|
||||
NL80211_RATE_INFO_EHT_8XLTF),
|
||||
[NL80211_TXRATE_6GHZ_NON_HT_DUP] = { .type = NLA_FLAG },
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -876,7 +877,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_HT_CAPABILITY_MASK] = {
|
||||
.len = NL80211_HT_CAPABILITY_LEN
|
||||
},
|
||||
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_TID_BITMAP] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
||||
|
|
@ -1096,6 +1097,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_NPCA_PUNCT_BITMAP] =
|
||||
NLA_POLICY_FULL_RANGE(NLA_U32, &nl80211_punct_bitmap_range),
|
||||
[NL80211_ATTR_STA_DUMP_LINK_STATS] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_FRAME_NO_STA] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
|
@ -5280,13 +5282,13 @@ static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
|
|||
struct net_device *dev = info->user_ptr[1];
|
||||
u16 noack_map;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_NOACK_MAP])
|
||||
if (!info->attrs[NL80211_ATTR_TID_BITMAP])
|
||||
return -EINVAL;
|
||||
|
||||
if (!rdev->ops->set_noack_map)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
|
||||
noack_map = nla_get_u16(info->attrs[NL80211_ATTR_TID_BITMAP]);
|
||||
|
||||
return rdev_set_noack_map(rdev, dev, noack_map);
|
||||
}
|
||||
|
|
@ -6303,6 +6305,14 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
|||
mask->control[band].eht_ltf =
|
||||
nla_get_u8(tb[NL80211_TXRATE_EHT_LTF]);
|
||||
|
||||
if (tb[NL80211_TXRATE_6GHZ_NON_HT_DUP]) {
|
||||
if (band != NL80211_BAND_6GHZ ||
|
||||
(wdev->iftype != NL80211_IFTYPE_AP &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO))
|
||||
return -EINVAL;
|
||||
mask->control[band].nonht_dup_6ghz = true;
|
||||
}
|
||||
|
||||
if (mask->control[band].legacy == 0) {
|
||||
/* don't allow empty legacy rates if HT, VHT, HE or EHT
|
||||
* are not even supported.
|
||||
|
|
@ -6344,6 +6354,7 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
|
|||
{
|
||||
u32 count_ht, count_vht, count_he, count_eht, i;
|
||||
u32 rate = beacon_rate->control[band].legacy;
|
||||
bool nonht_dup = beacon_rate->control[band].nonht_dup_6ghz;
|
||||
|
||||
/* Allow only one rate */
|
||||
if (hweight32(rate) > 1)
|
||||
|
|
@ -6405,6 +6416,9 @@ static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
|
|||
(!rate && !count_ht && !count_vht && !count_he && !count_eht))
|
||||
return -EINVAL;
|
||||
|
||||
if (nonht_dup && !rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (rate &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
|
||||
|
|
@ -14878,6 +14892,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|||
!(wdev->valid_links & BIT(params.link_id)))
|
||||
return -EINVAL;
|
||||
|
||||
params.no_sta =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_FRAME_NO_STA]);
|
||||
|
||||
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
|
||||
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
|
||||
|
||||
|
|
@ -18449,6 +18466,7 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
|
|||
static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wiphy *wiphy = &rdev->wiphy;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_pmk_conf pmk_conf = {};
|
||||
|
|
@ -18457,7 +18475,9 @@ static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
|
|||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
if (!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_FAST_ROAM_OFFLOAD) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -18487,6 +18507,7 @@ static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
|
|||
static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wiphy *wiphy = &rdev->wiphy;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
const u8 *aa;
|
||||
|
|
@ -18495,7 +18516,9 @@ static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
|
|||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
if (!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_FAST_ROAM_OFFLOAD) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -21538,7 +21561,6 @@ void nl80211_mlo_reconf_add_done(struct net_device *dev,
|
|||
|
||||
nl80211_send_mlme_event(rdev, dev, &event, GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL(nl80211_mlo_reconf_add_done);
|
||||
|
||||
void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
|
|
@ -22039,7 +22061,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
|||
(info->ack_tstamp && nla_put_u64_64bit(msg,
|
||||
NL80211_ATTR_TX_HW_TIMESTAMP,
|
||||
info->ack_tstamp,
|
||||
NL80211_ATTR_PAD)))
|
||||
NL80211_ATTR_PAD)) ||
|
||||
(info->no_sta &&
|
||||
nla_put_flag(msg, NL80211_ATTR_FRAME_NO_STA)))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user