* Re: Firmware for reverse engineering b43?
From: Joshua Peisach @ 2026-04-15 17:04 UTC (permalink / raw)
To: Michael Büsch, Jonas Gorski
Cc: Johannes Berg, linux-wireless, b43-dev, b43-dev
In-Reply-To: <20260415175748.61aa7993@barney>
On Wed Apr 15, 2026 at 11:57 AM EDT, Michael Büsch wrote:
> On Wed, 15 Apr 2026 13:54:31 +0200
> Jonas Gorski <jonas.gorski@gmail.com> wrote:
>
>> On Wed, Apr 15, 2026 at 1:44 PM Joshua Peisach <jpeisach@ubuntu.com> wrote:
>> > It does appear to be similar - even the current brcm80211. So much so
>> > that I sometimes need to think about whether b43 is actually a
>> > duplicated driver.
>> >
>> > Since b43 is in an orphan state, I thought it would be a great place to
>> > start for kernel development. 5G doesn't work on that iMac, some of the
>> > PHYs, like the AC PHYs appear to be incomplete - it felt reasonable.
>> >
>> > Because I'm one of those "there's always room for improvement people",
>> > I was going to try to improve the driver, filling out TODOs, fixing
>> > hardcoded register numbers, etc. But if it's best left alone.. then I
>> > guess we can do that.
>> >
>> > That is, assuming b43 is actually supposed to be a separate driver,
>> > because if brcmsmac basically has the same code, then maybe we should
>> > focus to centralizing everything? But then there's b43legacy.. hm...
>>
>> It is/was intentionally a separate driver: Broadcom didn't want to
>> maintain support for obsolete chips (anything SSB, anything older than
>> BCM43224), so the decision was to have b43 support all the "legacy"
>> chips, while brcm80211 supports everything never. Since they were both
>> based on the same driver, they are (more or less) the same
>> architecture.
>>
>> But now that Broadcom has essentially abandoned the softmac part of
>> brcm80211 since several years, I don't think there would be many
>> objections on unifying it with b43.
>
> The hardest part in the b43 development always was not to break already
> working stuff. There are many different types and revisions of the hardware
> out there. Probably in the order of many dozens of variants.
>
> Please keep in mind that changing code means mostly testing.
> Which is hard, if you don't have the hardware variants and basically no
> users exist anymore. Just implementing random TODOs and missing pieces
> will break things. (e.g. not doing some HW calibration or workaround might
> be better than only partially doing it or doing it wrong).
>
Well, if the regression risk is that high, then I guess I'll let it be.
> I would personally not touch this thing anymore, except for security fixes and such.
>
Sure. I might just make sure everything is using register definitions
instead of hardcoded values, but then leave it there.
> But if you want to work on the code, long term, I would welcome that.
> We could even arrange that I ship you some hardware.
> But keep in mind, it's all almost 20 years old legacy stuff.
The only b43 devices I have are the aforementioned iMac, and also the
Wii. And unless the hardware is unique in some other way, I don't think
its worth sending it to me. Besides, if the code is so risky to touch,
then the only technical change I make should just be to fix my 5G
situation.
I didn't intend to become a b43 maintainer, and given where I currently
am lifewise, I don't think it's worth trying to fulfill that role long
term. Hopefully I'll find areas of work in brcm80211 to work in. It
just so happened that "make sure the kernel works on everything you can
get your hands on" stumbled across b43, which I thought would be a good
starting point.
So I guess this driver just sits here.. not quite pointless to be
removed from the main tree, but not quite worth the effort to bring it
up to speed.
^ permalink raw reply
* Re: Firmware for reverse engineering b43?
From: Michael Büsch @ 2026-04-15 17:41 UTC (permalink / raw)
To: Joshua Peisach
Cc: Jonas Gorski, Johannes Berg, linux-wireless, b43-dev, b43-dev
In-Reply-To: <DHTW44HOVZLS.GFYBZTKJTMP4@ubuntu.com>
[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]
On Wed, 15 Apr 2026 13:04:40 -0400
"Joshua Peisach" <jpeisach@ubuntu.com> wrote:
> Well, if the regression risk is that high, then I guess I'll let it be.
> Sure. I might just make sure everything is using register definitions
> instead of hardcoded values, but then leave it there.
I mean, I don't want to discourage you from doing anything,
but I just wanted to point out that this is a lot more work than just implement
a TODO here and there.
For most of the code we don't really know what it does exactly.
That may change a bit, if you pull over some code from the newer drivers.
But I don't think the situation will improve fundamentally.
> So I guess this driver just sits here.. not quite pointless to be
> removed from the main tree, but not quite worth the effort to bring it
> up to speed.
Well, it probably still works well on the (few) devices it worked well on,
because it basically hasn't changed.
There are many devices which were never supported at all or were never supported
properly. It's not that just your device is missing to complete
the perfect picture :-)
There might be better uses of your time than working on this legacy stuff.
For example working on the microcode reverse engineering and tools and
get them updated for the current generation of devices is probably
much more useful. And I think much more fun, too.
Or something else altogether.
--
Michael Büsch
https://bues.ch/
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH] zd1211rw/mac: Fix out-of-bounds upon RX when unassociated
From: Lubomir Rintel @ 2026-04-15 17:08 UTC (permalink / raw)
To: linux-wireless; +Cc: linux-kernel, Lubomir Rintel
Upon plugging the adapter, UBSAN complains about an out of bounds read:
zd1211rw 1-12:1.0: firmware version 4725
zd1211rw 1-12:1.0: zd1211b chip 083a:4505 v4810 high 00-13-f7 AL2230_RF pa0 g--NS
------------[ cut here ]------------
UBSAN: array-index-out-of-bounds in drivers/net/wireless/zydas/zd1211rw/zd_mac.c:1059:26
index -1 is out of range for type 'ieee80211_channel [14]'
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.17.12-300.fc43.x86_64 #1 PREEMPT(lazy)
Hardware name: MSI MS-7A68/B250 KRAIT GAMING (MS-7A68), BIOS H.00 12/15/2016
Call Trace:
<IRQ>
dump_stack_lvl+0x5d/0x80
ubsan_epilogue+0x5/0x2b
__ubsan_handle_out_of_bounds.cold+0x54/0x59
zd_mac_rx+0x453/0x470 [zd1211rw]
? raise_softirq_irqoff+0x9/0x30
rx_urb_complete+0x178/0x260 [zd1211rw]
? queue_work_on+0x73/0x80
? led_trigger_blink_oneshot+0x78/0xa0
__usb_hcd_giveback_urb+0x9d/0x120
usb_giveback_urb_bh+0xb1/0x140
process_one_work+0x18f/0x350
bh_worker+0x1ac/0x210
tasklet_action+0x10/0x30
handle_softirqs+0xed/0x340
__irq_exit_rcu+0xcb/0xf0
common_interrupt+0x85/0xa0
</IRQ>
<TASK>
asm_common_interrupt+0x26/0x40
RIP: 0010:cpuidle_enter_state+0xcc/0x660
Code: 00 00 e8 f7 36 ef fe e8 72 f0 ff ff 49 89 c4 0f
1f 44 00 00 31 ff e8 23 55 ed fe 45 84 ff 0f 85
02 02 00 00 fb 0f 1f 44 00 00 <85> ed 0f 88 d3 01
00 00 4c 63 f5 49 83 fe 0a 0f 83 9f 04 00 00 49
RSP: 0018:ffffffff9dc03df8 EFLAGS: 00000246
RAX: ffff8a5440447000 RBX: ffff8a53df03ea40 RCX: 0000000000000000
RDX: 001bd812ca957581 RSI: 00000000248799d1 RDI: 0000000000000000
RBP: 0000000000000002 R08: fffffffc74360e92 R09: ffff8a53df02cbe0
R10: 001bd81656731313 R11: 0000000000000000 R12: 001bd812ca957581
R13: ffffffff9df0fa60 R14: 0000000000000002 R15: 0000000000000000
? cpuidle_enter_state+0xbd/0x660
cpuidle_enter+0x31/0x50
cpuidle_idle_call+0xf5/0x160
? ktime_get+0x3c/0xf0
do_idle+0x78/0xd0
cpu_startup_entry+0x29/0x30
rest_init+0xe7/0xf0
start_kernel+0x49d/0x4a0
x86_64_start_reservations+0x24/0x30
x86_64_start_kernel+0x126/0x130
common_startup_64+0x13e/0x141
</TASK>
---[ end trace ]---
It is correct: if zd_mac_rx() is called when unassociated, the channel
is 0, becomes -1 under assumption there's a proper channel number
starting from 1.
Add a missing bounds check.
Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
---
drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
index 03948f0b4628..c59d1929a69c 100644
--- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
@@ -1022,6 +1022,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
const struct rx_status *status;
struct sk_buff *skb;
int bad_frame = 0;
+ u8 channel;
__le16 fc;
int need_padding;
int i;
@@ -1055,7 +1056,9 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
}
}
- stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
+ channel = _zd_chip_get_channel(&mac->chip);
+ if (channel > 0 && channel <= ARRAY_SIZE(zd_channels))
+ stats.freq = zd_channels[channel - 1].center_freq;
stats.band = NL80211_BAND_2GHZ;
stats.signal = zd_check_signal(hw, status->signal_strength);
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v3] wifi: rtw88: Add NULL check for chip->edcca_th in rtw_fw_adaptivity_result()
From: LB F @ 2026-04-15 17:03 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: Panagiotis Petrakopoulos, linux-wireless@vger.kernel.org
In-Reply-To: <ad69b2f3dbc74ea6b9b1a17f2a77fbb4@realtek.com>
On Tue, 15 Apr 2026, Panagiotis Petrakopoulos wrote:
> Add a NULL check for edcca_th before dereferencing
> it in rtw_fw_adaptivity_result() in fw.c.
Hi Panagiotis,
I have applied this v3 patch to my local out-of-tree rtw88 build
(openSUSE Tumbleweed, kernel 6.19) on the affected RTL8821CE
hardware. The driver compiles cleanly and the module loads
without issues.
I am now starting a structured stability test covering suspend,
hibernation, high-throughput transfers, and long uptime. I will
follow up with a Tested-by once I have sufficient confidence in
the results.
Best regards,
Oleksandr Havrylov
^ permalink raw reply
* [PATCH v2] wifi: mac80211: skip ieee80211_verify_sta_ht_mcs_support check in non-strict mode
From: Rio Liu @ 2026-04-15 16:57 UTC (permalink / raw)
To: Johannes Berg
Cc: linux-kernel@vger.kernel.org, linux-wireless@vger.kernel.org,
benjamin.berg@intel.com
Some Xfinity XB8 firmware advertises >1 spatial stream MCS indexes in
their basic HT-MCS set. On cards with lower spatial streams, the check
would fail, and we'd be stuck with no HT when in fact work fine with its
own supported rate. This change makes it so the check is only performed
in strict mode.
Fixes: 574faa0e936d ("wifi: mac80211: add HT and VHT basic set verification")
Signed-off-by: Rio Liu <rio@r26.me>
---
v2 changes:
- update comment to include Xfinity router model
- generalize comment to include devices with only single spatial stream
- add Fixes tag
- add wifi: mac80211: to patch title
Link to v1: https://lore.kernel.org/linux-wireless/AKVRf_yEu2mRCJekCJpre5xXMuHa_3_dO7_H1UU8fiKZRjJUf96ZKepiR999NwpiVwmzWBYoKipBpx1rqZatVihMYOCvANUnbeoyI2U7ct0=@r26.me/T/#u
net/mac80211/mlme.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 810bea1aacc5..44cb826263ba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -419,6 +419,15 @@ ieee80211_verify_sta_ht_mcs_support(struct ieee80211_sub_if_data *sdata,
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+ /*
+ * Some Xfinity XB8 firmware advertises >1 spatial stream MCS indexes in
+ * their basic HT-MCS set. On cards with lower spatial streams, the check
+ * would fail, and we'd be stuck with no HT when it in fact work fine with
+ * its own supported rate. So check it only in strict mode.
+ */
+ if (!ieee80211_hw_check(&sdata->local->hw, STRICT))
+ return true;
+
/*
* P802.11REVme/D7.0 - 6.5.4.2.4
* ...
base-commit: d65b175cfac64ee65506eea7fa573d291a9694ca
--
2.53.0
^ permalink raw reply related
* Re: Firmware for reverse engineering b43?
From: Michael Büsch @ 2026-04-15 15:57 UTC (permalink / raw)
To: Jonas Gorski; +Cc: Joshua Peisach, Johannes Berg, b43-dev, linux-wireless
In-Reply-To: <CAOiHx=n8awRRvArvG8sWqEokojXL6ppFRJ8_SOuGAddDb1D32A@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2481 bytes --]
On Wed, 15 Apr 2026 13:54:31 +0200
Jonas Gorski <jonas.gorski@gmail.com> wrote:
> On Wed, Apr 15, 2026 at 1:44 PM Joshua Peisach <jpeisach@ubuntu.com> wrote:
> > It does appear to be similar - even the current brcm80211. So much so
> > that I sometimes need to think about whether b43 is actually a
> > duplicated driver.
> >
> > Since b43 is in an orphan state, I thought it would be a great place to
> > start for kernel development. 5G doesn't work on that iMac, some of the
> > PHYs, like the AC PHYs appear to be incomplete - it felt reasonable.
> >
> > Because I'm one of those "there's always room for improvement people",
> > I was going to try to improve the driver, filling out TODOs, fixing
> > hardcoded register numbers, etc. But if it's best left alone.. then I
> > guess we can do that.
> >
> > That is, assuming b43 is actually supposed to be a separate driver,
> > because if brcmsmac basically has the same code, then maybe we should
> > focus to centralizing everything? But then there's b43legacy.. hm...
>
> It is/was intentionally a separate driver: Broadcom didn't want to
> maintain support for obsolete chips (anything SSB, anything older than
> BCM43224), so the decision was to have b43 support all the "legacy"
> chips, while brcm80211 supports everything never. Since they were both
> based on the same driver, they are (more or less) the same
> architecture.
>
> But now that Broadcom has essentially abandoned the softmac part of
> brcm80211 since several years, I don't think there would be many
> objections on unifying it with b43.
The hardest part in the b43 development always was not to break already
working stuff. There are many different types and revisions of the hardware
out there. Probably in the order of many dozens of variants.
Please keep in mind that changing code means mostly testing.
Which is hard, if you don't have the hardware variants and basically no
users exist anymore. Just implementing random TODOs and missing pieces
will break things. (e.g. not doing some HW calibration or workaround might
be better than only partially doing it or doing it wrong).
I would personally not touch this thing anymore, except for security fixes and such.
But if you want to work on the code, long term, I would welcome that.
We could even arrange that I ship you some hardware.
But keep in mind, it's all almost 20 years old legacy stuff.
--
Michael Büsch
https://bues.ch/
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 17/20] wifi: cfg80211: provide HT/VHT operation for AP beacon
From: Johannes Berg @ 2026-04-15 16:05 UTC (permalink / raw)
To: Pablo MARTIN-GOMEZ, linux-wireless; +Cc: Miriam Rachel Korenblit
In-Reply-To: <5633ace2-45df-4ee6-a41f-831de3e90d60@freebox.fr>
On Wed, 2026-04-15 at 18:02 +0200, Pablo MARTIN-GOMEZ wrote:
> On 15/04/2026 17:42, Johannes Berg wrote:
> > On Wed, 2026-04-15 at 17:22 +0200, Pablo MARTIN-GOMEZ wrote:
> > >
> > > > + * @ht_oper: HT operation element (or %NULL if HT isn't enabled)
> > > Might be some nitpicking you can ignore, but HT operation element is optional when HT is enabled. With the current comment, someone might (wrongly) deduce that if `ht_oper` is NULL then HT is not enabled.
> > >
> >
> > Not sure how you mean that, but not really? If the AP has HT then it
> > must have HT operation, otherwise the clients can't use it?
> Oh my bad, you can ignore my comment. I wasn't sure if HT operation
> element was mandatory, so I quickly checked the standard and the wording
> of second table of 6.5.3.3.2 misled me in thinking it was optional ("The
> parameter is optionally present if dot11HighThroughputOptionImplemented
> is true; otherwise not present.")
>
Huh. I'm not sure what you're referring to (spec version is highly
relevant), but HT operation in a beacon frame, REVmf D2.0 says:
The HT Operation element is included by an AP and a mesh STA
when dot11HighThroughputOperationImplemented is true and the AP
or mesh STA is not a STA 6G.
johannes
^ permalink raw reply
* Re: [PATCH 17/20] wifi: cfg80211: provide HT/VHT operation for AP beacon
From: Pablo MARTIN-GOMEZ @ 2026-04-15 16:02 UTC (permalink / raw)
To: Johannes Berg, linux-wireless; +Cc: Miriam Rachel Korenblit
In-Reply-To: <b5a0822b7ebf8e816e096e6a628db6b21fad40ef.camel@sipsolutions.net>
On 15/04/2026 17:42, Johannes Berg wrote:
> On Wed, 2026-04-15 at 17:22 +0200, Pablo MARTIN-GOMEZ wrote:
>>
>>> + * @ht_oper: HT operation element (or %NULL if HT isn't enabled)
>> Might be some nitpicking you can ignore, but HT operation element is optional when HT is enabled. With the current comment, someone might (wrongly) deduce that if `ht_oper` is NULL then HT is not enabled.
>>
>
> Not sure how you mean that, but not really? If the AP has HT then it
> must have HT operation, otherwise the clients can't use it?
Oh my bad, you can ignore my comment. I wasn't sure if HT operation
element was mandatory, so I quickly checked the standard and the wording
of second table of 6.5.3.3.2 misled me in thinking it was optional ("The
parameter is optionally present if dot11HighThroughputOptionImplemented
is true; otherwise not present.")
>
> johannes
Pablo MG
^ permalink raw reply
* [PATCH mt76] wifi: mt76: mt7996: reduce phy work in set_coverage
From: dylan.eskew @ 2026-04-15 15:53 UTC (permalink / raw)
To: nbd, lorenzo, ryder.lee
Cc: linux-wireless, shayne.chen, sean.wang, Dylan Eskew
From: Dylan Eskew <dylan.eskew@candelatech.com>
In mt7996_set_coverage_class(), each phy is iterated over in calling
mt7996_mac_set_coverage_class(). Thus, the phy2 and phy3 configuration
logic in mt7996_mac_set_coverage_class() can be dropped.
Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index e2a83da3a09c..55efa3df86a6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2059,8 +2059,6 @@ void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
{
s16 coverage_class = phy->coverage_class;
struct mt7996_dev *dev = phy->dev;
- struct mt7996_phy *phy2 = mt7996_phy2(dev);
- struct mt7996_phy *phy3 = mt7996_phy3(dev);
u32 reg_offset;
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
@@ -2072,14 +2070,6 @@ void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
return;
- if (phy2)
- coverage_class = max_t(s16, dev->phy.coverage_class,
- phy2->coverage_class);
-
- if (phy3)
- coverage_class = max_t(s16, coverage_class,
- phy3->coverage_class);
-
offset = 3 * coverage_class;
reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
--
2.52.0
^ permalink raw reply related
* Re: [PATCH 17/20] wifi: cfg80211: provide HT/VHT operation for AP beacon
From: Johannes Berg @ 2026-04-15 15:42 UTC (permalink / raw)
To: Pablo MARTIN-GOMEZ, linux-wireless; +Cc: Miriam Rachel Korenblit
In-Reply-To: <ddfdac5d-602f-4f67-80bf-d41924b0b7e7@freebox.fr>
On Wed, 2026-04-15 at 17:22 +0200, Pablo MARTIN-GOMEZ wrote:
>
> > + * @ht_oper: HT operation element (or %NULL if HT isn't enabled)
> Might be some nitpicking you can ignore, but HT operation element is optional when HT is enabled. With the current comment, someone might (wrongly) deduce that if `ht_oper` is NULL then HT is not enabled.
>
Not sure how you mean that, but not really? If the AP has HT then it
must have HT operation, otherwise the clients can't use it?
johannes
^ permalink raw reply
* Re: [PATCH wireless-next] wifi: radiotap: add definitions for the new UHR TLVs
From: Johannes Berg @ 2026-04-15 15:42 UTC (permalink / raw)
To: Pablo MARTIN-GOMEZ, Miri Korenblit, linux-wireless
In-Reply-To: <d0144694-13b9-4d6c-9a6b-59d41a9562bf@freebox.fr>
On Wed, 2026-04-15 at 17:10 +0200, Pablo MARTIN-GOMEZ wrote:
> On 15/04/2026 16:54, Johannes Berg wrote:
> > On Wed, 2026-04-15 at 15:27 +0200, Pablo MARTIN-GOMEZ wrote:
> > >
> > > > + IEEE80211_RADIOTAP_UHR_ELR = 37,
> > > > + IEEE80211_RADIOTAP_UHR = 38,
> > > Why are the values 37 and 38 but below in the doc 35 and 38?
> >
> > The doc doesn't even exist yet as you say? Other things are being
> > assigned to 35/36.
> I wasn't clear, I didn't mean the doc like the actual documentation but
> the code comments that are used to document the defined value, e.g.
> `ieee80211_radiotap_uhr_elr - content of UHR-ELR TLV (type 35)`, it
> should be `type 37`, no?
Ah! That would be due to last minute renumbering here, indeed it should.
> Just the little brain of mine that likes when things follow expected
> patterns :) But more seriously, given that I didn't have access to the
> specs, the only thing I could use that could point out an issue was
> comparing to the patterns of existing fields and matching `known` fields
> with `data` fields.
>
Sure, fair. I don't really remember, I do remember mostly copying from
EHT (it is necessarily similar since UHR doesn't really even define its
own MCS set etc.), and then filling in the remainder in reserved (or no
longer used) bits...
johannes
^ permalink raw reply
* [PATCH wireless-next] wifi: cfg80211: validate cipher suite for NAN Data keys
From: Miri Korenblit @ 2026-04-15 15:35 UTC (permalink / raw)
To: linux-wireless; +Cc: Daniel Gabay, Ilan Peer, Johannes Berg
From: Daniel Gabay <daniel.gabay@intel.com>
Per Wi-Fi Aware v4.0 section 7.1.2, NAN Data interfaces shall only
use CCMP-128 or GCMP-256 for frame protection. Enforce this in
cfg80211_validate_key_settings() by passing the wdev down to it.
Signed-off-by: Daniel Gabay <daniel.gabay@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/wireless/core.h | 3 ++-
net/wireless/nl80211.c | 11 +++++++----
net/wireless/util.c | 10 ++++++++++
net/wireless/wext-compat.c | 3 ++-
4 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ae2d56d3ad90..0e6f9bd4ba1b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -3,7 +3,7 @@
* Wireless configuration interface internals.
*
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
*/
#ifndef __NET_WIRELESS_CORE_H
#define __NET_WIRELESS_CORE_H
@@ -446,6 +446,7 @@ bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
int key_idx, bool pairwise);
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr);
void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f334cdef8958..31a39ffc7d0d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1733,6 +1733,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
static struct cfg80211_cached_keys *
nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
struct genl_info *info, bool *no_ht)
{
struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
@@ -1782,7 +1783,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
goto error;
} else if (parse.defmgmt)
goto error;
- err = cfg80211_validate_key_settings(rdev, &parse.p,
+ err = cfg80211_validate_key_settings(rdev, wdev, &parse.p,
parse.idx, false, NULL);
if (err)
goto error;
@@ -5407,7 +5408,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->add_key)
return -EOPNOTSUPP;
- if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
+ if (cfg80211_validate_key_settings(rdev, wdev, &key.p, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr)) {
GENL_SET_ERR_MSG(info, "key setting validation failed");
@@ -13163,7 +13164,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
bool no_ht = false;
- connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
+ connkeys = nl80211_parse_connkeys(rdev, dev->ieee80211_ptr,
+ info, &no_ht);
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);
@@ -13605,7 +13607,8 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
}
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
- connkeys = nl80211_parse_connkeys(rdev, info, NULL);
+ connkeys = nl80211_parse_connkeys(rdev, dev->ieee80211_ptr,
+ info, NULL);
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index cff5a1bd95cc..95ae06e94f10 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -284,6 +284,7 @@ bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
}
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr)
{
@@ -344,6 +345,15 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
break;
}
+ /*
+ * Per Wi-Fi Aware v4.0 section 7.1.2, NAN Data interfaces
+ * shall only use CCMP-128 or GCMP-256.
+ */
+ if (wdev->iftype == NL80211_IFTYPE_NAN_DATA &&
+ params->cipher != WLAN_CIPHER_SUITE_CCMP &&
+ params->cipher != WLAN_CIPHER_SUITE_GCMP_256)
+ return -EINVAL;
+
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
if (params->key_len != WLAN_KEY_LEN_WEP40)
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 22d9d9bae8f5..28bc996c1437 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -489,7 +489,8 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (addr)
tx_key = false;
- if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
+ if (cfg80211_validate_key_settings(rdev, wdev, params, idx,
+ pairwise, addr))
return -EINVAL;
err = 0;
--
2.34.1
^ permalink raw reply related
* Re: [PATCH 17/20] wifi: cfg80211: provide HT/VHT operation for AP beacon
From: Pablo MARTIN-GOMEZ @ 2026-04-15 15:22 UTC (permalink / raw)
To: Johannes Berg, linux-wireless; +Cc: Johannes Berg, Miriam Rachel Korenblit
In-Reply-To: <20260415144514.32ad98454543.Ia9692671b699164edcc0bdaf4fdbdbefc50b18f8@changeid>
On 15/04/2026 14:42, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> In addition to providing HE/EHT/UHR operation, also check
> and provide HT/VHT operation, so that drivers have it and
> can use it, e.g. to correctly calculate station bandwidth.
>
> Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
> include/net/cfg80211.h | 4 ++++
> net/wireless/nl80211.c | 18 ++++++++++++++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 7070e577342b..a40ab36b8edb 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -1398,6 +1398,8 @@ struct cfg80211_rnr_elems {
> * attribute is present in beacon data or not.
> * @ht_required: stations must support HT
> * @vht_required: stations must support VHT
> + * @ht_oper: HT operation element (or %NULL if HT isn't enabled)
Might be some nitpicking you can ignore, but HT operation element is optional when HT is enabled. With the current comment, someone might (wrongly) deduce that if `ht_oper` is NULL then HT is not enabled.
> + * @vht_oper: VHT operation element (or %NULL if VHT isn't enabled)
> * @he_oper: HE operation IE (or %NULL if HE isn't enabled)
> * @eht_oper: EHT operation IE (or %NULL if EHT isn't enabled)
> * @uhr_oper: UHR operation (or %NULL if UHR isn't enabled)
> @@ -1427,6 +1429,8 @@ struct cfg80211_beacon_data {
> bool he_bss_color_valid;
>
> bool ht_required, vht_required;
> + const struct ieee80211_ht_operation *ht_oper;
> + const struct ieee80211_vht_operation *vht_oper;
> const struct ieee80211_he_operation *he_oper;
> const struct ieee80211_eht_operation *eht_oper;
> const struct ieee80211_uhr_operation *uhr_oper;
[...]
Pablo MG
^ permalink raw reply
* Re: [PATCH wireless-next] wifi: radiotap: add definitions for the new UHR TLVs
From: Pablo MARTIN-GOMEZ @ 2026-04-15 15:10 UTC (permalink / raw)
To: Johannes Berg, Miri Korenblit, linux-wireless
In-Reply-To: <60e2d9cdb781ad0bed35ef664f7d63dfc49fb9eb.camel@sipsolutions.net>
On 15/04/2026 16:54, Johannes Berg wrote:
> On Wed, 2026-04-15 at 15:27 +0200, Pablo MARTIN-GOMEZ wrote:
>>
>>> + IEEE80211_RADIOTAP_UHR_ELR = 37,
>>> + IEEE80211_RADIOTAP_UHR = 38,
>> Why are the values 37 and 38 but below in the doc 35 and 38?
>
> The doc doesn't even exist yet as you say? Other things are being
> assigned to 35/36.
I wasn't clear, I didn't mean the doc like the actual documentation but
the code comments that are used to document the defined value, e.g.
`ieee80211_radiotap_uhr_elr - content of UHR-ELR TLV (type 35)`, it
should be `type 37`, no?
>
>>> +/*
>>> + * ieee80211_radiotap_uhr_elr - content of UHR-ELR TLV (type 35)
>>> + * see https://www.radiotap.org/fields/UHR-ELR for details
>> The URL gives a error 404
>
> Yeah it's not merged yet. For now you can see the (draft) at
> https://jmberg.github.io/radiotap.github.io/fields/UHR-ELR (etc)
Thanks for a working URL :)
>
>>> +enum ieee80211_radiotap_uhr_known {
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_SPATIAL_REUSE = 0x00000001,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_GI_LTF_SIZE = 0x00000002,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_UHR_LTF_SYMBOLS = 0x00000004,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_LDPC_EXTRA_SYMBOL_SEGMENT = 0x00000008,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_PRE_FEC_PADDING_FACTOR = 0x00000010,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_PE_DISAMBIGUITY = 0x00000020,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_OFDMA = 0x00000040,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_CRC1 = 0x00000080,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL1 = 0x00000100,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_CRC2 = 0x00000200,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL2 = 0x00000400,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_INTERFERENCE_MITIGATION = 0x00000800,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_NON_OFDMA = 0x00001000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_NON_OFDMA_USERS = 0x00002000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_CRC = 0x00004000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_TAIL = 0x00008000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_DRU_SIZE = 0x00010000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_INDEX = 0x00020000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_DRU_RRU_ALLOC_TB_FMT = 0x00040000,
>>> + IEEE80211_RADIOTAP_UHR_KNOWN_PRI80_CHAN_POS = 0x00080000,
>>> +};
>> In the other radiotap fields, the `known` fields are (as far as I
>> checked) have the same order than the data, but here, for example,
>> `PRI80_CHAN_POS` is before `INTERFERENCE_MITIGATION ` in `known` but
>> after in `data`. Any reason for that?
>
> Any reason you care? ;-) I think I just assigned them in the order I
> needed them, and in this case you really should look at the radiotap
> spec for it too. Some of it may also be due to having copied some things
> from EHT and then filling gaps with new bits, perhaps. Since other
> people are already working on wireshark support etc. I don't think we'll
> be changing this without a good reason.
Just the little brain of mine that likes when things follow expected
patterns :) But more seriously, given that I didn't have access to the
specs, the only thing I could use that could point out an issue was
comparing to the patterns of existing fields and matching `known` fields
with `data` fields.
>
> johannes
^ permalink raw reply
* Re: [PATCH wireless-next] wifi: radiotap: add definitions for the new UHR TLVs
From: Johannes Berg @ 2026-04-15 14:54 UTC (permalink / raw)
To: Pablo MARTIN-GOMEZ, Miri Korenblit, linux-wireless
In-Reply-To: <e3af2190-3941-4ec8-9c59-91eafc6eb156@freebox.fr>
On Wed, 2026-04-15 at 15:27 +0200, Pablo MARTIN-GOMEZ wrote:
>
> > + IEEE80211_RADIOTAP_UHR_ELR = 37,
> > + IEEE80211_RADIOTAP_UHR = 38,
> Why are the values 37 and 38 but below in the doc 35 and 38?
The doc doesn't even exist yet as you say? Other things are being
assigned to 35/36.
> > +/*
> > + * ieee80211_radiotap_uhr_elr - content of UHR-ELR TLV (type 35)
> > + * see https://www.radiotap.org/fields/UHR-ELR for details
> The URL gives a error 404
Yeah it's not merged yet. For now you can see the (draft) at
https://jmberg.github.io/radiotap.github.io/fields/UHR-ELR (etc)
> > +enum ieee80211_radiotap_uhr_known {
> > + IEEE80211_RADIOTAP_UHR_KNOWN_SPATIAL_REUSE = 0x00000001,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_GI_LTF_SIZE = 0x00000002,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_UHR_LTF_SYMBOLS = 0x00000004,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_LDPC_EXTRA_SYMBOL_SEGMENT = 0x00000008,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_PRE_FEC_PADDING_FACTOR = 0x00000010,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_PE_DISAMBIGUITY = 0x00000020,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_OFDMA = 0x00000040,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_CRC1 = 0x00000080,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL1 = 0x00000100,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_CRC2 = 0x00000200,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL2 = 0x00000400,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_INTERFERENCE_MITIGATION = 0x00000800,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_NON_OFDMA = 0x00001000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_NON_OFDMA_USERS = 0x00002000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_CRC = 0x00004000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_TAIL = 0x00008000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_DRU_SIZE = 0x00010000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_INDEX = 0x00020000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_DRU_RRU_ALLOC_TB_FMT = 0x00040000,
> > + IEEE80211_RADIOTAP_UHR_KNOWN_PRI80_CHAN_POS = 0x00080000,
> > +};
> In the other radiotap fields, the `known` fields are (as far as I
> checked) have the same order than the data, but here, for example,
> `PRI80_CHAN_POS` is before `INTERFERENCE_MITIGATION ` in `known` but
> after in `data`. Any reason for that?
Any reason you care? ;-) I think I just assigned them in the order I
needed them, and in this case you really should look at the radiotap
spec for it too. Some of it may also be due to having copied some things
from EHT and then filling gaps with new bits, perhaps. Since other
people are already working on wireshark support etc. I don't think we'll
be changing this without a good reason.
johannes
^ permalink raw reply
* [PATCH v2 1/1] wifi: libertas: add wake_up() call to properly notify fw_wq during disconnect
From: Jakov Novak @ 2026-04-15 13:36 UTC (permalink / raw)
To: linux-wireless
Cc: Kees Cook, Szymon Wilczek, Ingo Molnar, Johannes Berg,
Thomas Gleixner, John W . Linville, Dan Williams, libertas-dev,
linux-kernel, skhan, Jakov Novak, syzbot+c99d17aa44dbdba16ad2
In-Reply-To: <20260415133626.172702-2-jakovnovak30@gmail.com>
This is necessary because the thread would be stuck if the
firmware is not fully loaded before the if_usb_disconnect function is
called. In that case if_usb_prog_firmware would be stuck in
wait_event_interruptible and lbs_remove_card would also be stuck waiting
for firmware loading to be done which was the original bug reported.
Fixes: 954ee164f4f4 ("[PATCH] libertas: reorganize and simplify init sequence")
Reported-and-tested-by: syzbot+c99d17aa44dbdba16ad2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c99d17aa44dbdba16ad2
Signed-off-by: Jakov Novak <jakovnovak30@gmail.com>
---
drivers/net/wireless/marvell/libertas/if_usb.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 245c902a7e42..8a6bf1365cfa 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -310,7 +310,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
struct lbs_private *priv = cardp->priv;
cardp->surprise_removed = 1;
+ wake_up(&cardp->fw_wq);
if (priv) {
lbs_stop_card(priv);
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/1] wifi: libertas: fix bug in Marvell Libertas driver
From: Jakov Novak @ 2026-04-15 13:36 UTC (permalink / raw)
To: linux-wireless
Cc: Kees Cook, Szymon Wilczek, Ingo Molnar, Johannes Berg,
Thomas Gleixner, John W . Linville, Dan Williams, libertas-dev,
linux-kernel, skhan, Jakov Novak
Please ignore the previous email. I sent the wrong patch.
Jakov Novak (1):
wifi: libertas: add wake_up() call to properly notify fw_wq during
disconnect
drivers/net/wireless/marvell/libertas/if_usb.c | 1 -
1 file changed, 1 deletion(-)
--
2.53.0
^ permalink raw reply
* [PATCH v2 1/1] wifi: libertas: add wake_up() call to properly notify fw_wq during disconnect
From: Jakov Novak @ 2026-04-15 13:31 UTC (permalink / raw)
To: johannes
Cc: dcbw, jakovnovak30, kees, libertas-dev, linux-kernel,
linux-wireless, linville, mingo, skhan, swilczek.lx,
syzbot+c99d17aa44dbdba16ad2, tglx
In-Reply-To: <20260415133134.167783-2-jakovnovak30@gmail.com>
This is necessary because the thread would be stuck if the
firmware is not fully loaded before the if_usb_disconnect function is
called. In that case if_usb_prog_firmware would be stuck in
wait_event_interruptible and lbs_remove_card would also be stuck waiting
for firmware loading to be done which was the original bug reported.
Fixes: 954ee164f4f4 ("[PATCH] libertas: reorganize and simplify init sequence")
Reported-and-tested-by: syzbot+c99d17aa44dbdba16ad2@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c99d17aa44dbdba16ad2
Signed-off-by: Jakov Novak <jakovnovak30@gmail.com>
---
drivers/net/wireless/marvell/libertas/if_usb.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 245c902a7e42..8a6bf1365cfa 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -310,7 +310,6 @@ static void if_usb_disconnect(struct usb_interface *intf)
struct lbs_private *priv = cardp->priv;
cardp->surprise_removed = 1;
- wake_up(&cardp->fw_wq);
if (priv) {
lbs_stop_card(priv);
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/1] wifi: libertas: fix bug in Marvell Libertas driver
From: Jakov Novak @ 2026-04-15 13:31 UTC (permalink / raw)
To: johannes
Cc: dcbw, jakovnovak30, kees, libertas-dev, linux-kernel,
linux-wireless, linville, mingo, skhan, swilczek.lx,
syzbot+c99d17aa44dbdba16ad2, tglx
In-Reply-To: <57275e905a67e789ea438bf637be0aeb442fc880.camel@sipsolutions.net>
Thank you for the reply. It should be fixed now.
Jakov Novak (1):
wifi: libertas: add wake_up() call to properly notify fw_wq during
disconnect
drivers/net/wireless/marvell/libertas/if_usb.c | 1 -
1 file changed, 1 deletion(-)
--
2.53.0
^ permalink raw reply
* Re: [PATCH wireless-next] wifi: radiotap: add definitions for the new UHR TLVs
From: Pablo MARTIN-GOMEZ @ 2026-04-15 13:27 UTC (permalink / raw)
To: Miri Korenblit, linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260412152605.73e682d0c8c3.I5a0c858467c852b7a2a00f580bd073af29c37705@changeid>
Hello,
On 12/04/2026 14:26, Miri Korenblit wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Add the necessary definitions to create radiotap UHR TLVs
> for UHR sniffers.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
> ---
> include/net/ieee80211_radiotap.h | 190 +++++++++++++++++++++++++++++++
> 1 file changed, 190 insertions(+)
>
> diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
> index c60867e7e43c..6c2210a253cd 100644
> --- a/include/net/ieee80211_radiotap.h
> +++ b/include/net/ieee80211_radiotap.h
> @@ -95,6 +95,8 @@ enum ieee80211_radiotap_presence {
> IEEE80211_RADIOTAP_EXT = 31,
> IEEE80211_RADIOTAP_EHT_USIG = 33,
> IEEE80211_RADIOTAP_EHT = 34,
> + IEEE80211_RADIOTAP_UHR_ELR = 37,
> + IEEE80211_RADIOTAP_UHR = 38,
Why are the values 37 and 38 but below in the doc 35 and 38?
> };
>
> /* for IEEE80211_RADIOTAP_FLAGS */
> @@ -602,6 +604,194 @@ enum ieee80211_radiotap_eht_usig_tb {
> IEEE80211_RADIOTAP_EHT_USIG2_TB_B20_B25_TAIL = 0xfc000000,
> };
>
> +/*
> + * ieee80211_radiotap_uhr_elr - content of UHR-ELR TLV (type 35)
> + * see https://www.radiotap.org/fields/UHR-ELR for details
The URL gives a error 404
> + */
> +struct ieee80211_radiotap_uhr_elr {
> + __le32 known;
> + __le32 sig1, sig2, mark;
> +} __packed;
> +
[...]
> +
> +/*
> + * ieee80211_radiotap_uhr - content of UHR TLV (type 36)
> + * see https://www.radiotap.org/fields/UHR for details
Error 404
> + */
> +struct ieee80211_radiotap_uhr {
> + __le32 known;
> + __le32 data[9];
> + struct {
> + __le32 known, info;
> + } user[];
> +} __packed;
> +
> +enum ieee80211_radiotap_uhr_known {
> + IEEE80211_RADIOTAP_UHR_KNOWN_SPATIAL_REUSE = 0x00000001,
> + IEEE80211_RADIOTAP_UHR_KNOWN_GI_LTF_SIZE = 0x00000002,
> + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_UHR_LTF_SYMBOLS = 0x00000004,
> + IEEE80211_RADIOTAP_UHR_KNOWN_LDPC_EXTRA_SYMBOL_SEGMENT = 0x00000008,
> + IEEE80211_RADIOTAP_UHR_KNOWN_PRE_FEC_PADDING_FACTOR = 0x00000010,
> + IEEE80211_RADIOTAP_UHR_KNOWN_PE_DISAMBIGUITY = 0x00000020,
> + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_OFDMA = 0x00000040,
> + IEEE80211_RADIOTAP_UHR_KNOWN_CRC1 = 0x00000080,
> + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL1 = 0x00000100,
> + IEEE80211_RADIOTAP_UHR_KNOWN_CRC2 = 0x00000200,
> + IEEE80211_RADIOTAP_UHR_KNOWN_TAIL2 = 0x00000400,
> + IEEE80211_RADIOTAP_UHR_KNOWN_INTERFERENCE_MITIGATION = 0x00000800,
> + IEEE80211_RADIOTAP_UHR_KNOWN_DISREGARD_NON_OFDMA = 0x00001000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_NON_OFDMA_USERS = 0x00002000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_CRC = 0x00004000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_COMMON_ENCODING_BLOCK_TAIL = 0x00008000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_DRU_SIZE = 0x00010000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_RU_MRU_INDEX = 0x00020000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_DRU_RRU_ALLOC_TB_FMT = 0x00040000,
> + IEEE80211_RADIOTAP_UHR_KNOWN_PRI80_CHAN_POS = 0x00080000,
> +};
In the other radiotap fields, the `known` fields are (as far as I
checked) have the same order than the data, but here, for example,
`PRI80_CHAN_POS` is before `INTERFERENCE_MITIGATION ` in `known` but
after in `data`. Any reason for that?
[...]
Pablo MG
^ permalink raw reply
* Re: [PATCH 09/20] wifi: mac80211: clean up STA NSS handling
From: Johannes Berg @ 2026-04-15 13:02 UTC (permalink / raw)
To: linux-wireless; +Cc: Miriam Rachel Korenblit
In-Reply-To: <20260415144514.bef3d07beeb6.I97fb93ccc1b366110ab23de58fcd73676cdd85d6@changeid>
On Wed, 2026-04-15 at 14:42 +0200, Johannes Berg wrote:
>
> type=cleanup
> ticket=none
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> Reviewed-on: https://gerritwcs.ir.intel.com/c/iwlwifi-stack-dev/+/273695
> Tested-by: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM>
> tested: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM>
Meh, sorry about that. I'm not going to resend for it right away though.
johannes
^ permalink raw reply
* [PATCH] wifi: nl80211: check link is beaconing for color change
From: Johannes Berg @ 2026-04-15 12:53 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Miriam Rachel Korenblit
From: Johannes Berg <johannes.berg@intel.com>
When trying to do a color change, validate that the link is
beaconing first, to avoid calling the driver with an invalid
link.
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/nl80211.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f334cdef8958..e2ba6dfb8c70 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -18324,6 +18324,10 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]);
params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
+ params.link_id = nl80211_link_id(info->attrs);
+ if (!wdev->links[params.link_id].ap.beacon_interval)
+ return -EINVAL;
+
err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
info->extack);
if (err)
@@ -18397,7 +18401,6 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- params.link_id = nl80211_link_id(info->attrs);
err = rdev_color_change(rdev, dev, ¶ms);
out:
--
2.53.0
^ permalink raw reply related
* [PATCH] wifi: mac80211: clarify an 802.11 VHT spec reference
From: Johannes Berg @ 2026-04-15 12:51 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Miriam Rachel Korenblit
From: Johannes Berg <johannes.berg@intel.com>
Just saying "Table 9-250" isn't useful, without the version
of the spec. Fix the number according to the latest released
version (-2020) and add the table name.
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/util.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b093bc203c81..c31c5ce48cbd 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3149,7 +3149,9 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
ext_nss_bw_supp = 0;
/*
- * Cf. IEEE 802.11 Table 9-250
+ * Cf. IEEE 802.11-2020 Table 9-272 - Setting of the Supported Channel
+ * Width Set subfield and Extended NSS BW Support subfield at a STA
+ * transmitting the VHT Capabilities Information field
*
* We really just consider that because it's inefficient to connect
* at a higher bandwidth than we'll actually be able to use.
--
2.53.0
^ permalink raw reply related
* [PATCH 20/20] wifi: mac80211: fix per-station PHY capability bandwidth
From: Johannes Berg @ 2026-04-15 12:42 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Miriam Rachel Korenblit
In-Reply-To: <20260415124514.284345-22-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
When a (link) station connected to an AP interface is not
capable of EHT, it's possible that the AP interface is in
160 MHz but the HE channel is narrower, e.g. when EHT has
puncturing. In this case, the code doesn't correctly set
the STAs bandwidth, the station might be capable of using
160 MHz, but it can't use EHT 160 MHz with puncturing, so
it must be set to narrower.
Track the AP's 'he_and_lower_bw' bandwidth, use that when
calculating the maximum bandwidth to transmit to/from any
station not capable of EHT, and update all stations and
the chanctx min_def when it changes.
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 116 +++++++++++++++++++++++++++++++++++++
net/mac80211/chan.c | 9 +--
net/mac80211/ieee80211_i.h | 4 ++
net/mac80211/sta_info.c | 47 ++++++++++++++-
4 files changed, 170 insertions(+), 6 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bc4a8e5ad039..00261bd6674b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1312,6 +1312,120 @@ ieee80211_copy_rnr_beacon(u8 *pos, struct cfg80211_rnr_elems *dst,
return offset;
}
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_calc_ap_he_and_lower(struct cfg80211_beacon_data *params)
+{
+ const struct ieee80211_vht_operation *vht_oper = params->vht_oper;
+ int ccfs0, ccfs1;
+
+ if (params->he_oper) {
+ const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
+
+ if (params->he_oper->he_oper_params &
+ cpu_to_le32(IEEE80211_HE_OPERATION_VHT_OPER_INFO))
+ vht_oper = (void *)params->he_oper->optional;
+
+ he_6ghz_oper = ieee80211_he_6ghz_oper(params->he_oper);
+ if (he_6ghz_oper) {
+ switch (u8_get_bits(he_6ghz_oper->control,
+ IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
+ case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
+ return IEEE80211_STA_RX_BW_20;
+ case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ:
+ return IEEE80211_STA_RX_BW_40;
+ case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ:
+ return IEEE80211_STA_RX_BW_80;
+ case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ:
+ return IEEE80211_STA_RX_BW_160;
+ }
+ }
+ }
+
+ if (vht_oper) {
+ switch (vht_oper->chan_width) {
+ case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ /* check for HT (or fall down to 20) below */
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ /* deprecated encodings */
+ return IEEE80211_STA_RX_BW_160;
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ /*
+ * See IEEE 802.11-2020 Table 9-352-BSS bandwidth
+ * when the VHT Operation Information field Channel
+ * Width subfield is 1
+ *
+ * (IEEE80211_VHT_CHANWIDTH_80MHZ == 1)
+ */
+ ccfs0 = vht_oper->center_freq_seg0_idx;
+ ccfs1 = vht_oper->center_freq_seg1_idx;
+ if (!ccfs0)
+ return IEEE80211_STA_RX_BW_80;
+ if (ccfs1 && abs(ccfs1 - ccfs0) == 8)
+ return IEEE80211_STA_RX_BW_160;
+ /* 80+80 - RX BW doesn't cover that / uses 160 */
+ if (ccfs1 && abs(ccfs1 - ccfs0) > 16)
+ return IEEE80211_STA_RX_BW_160;
+ fallthrough;
+ default:
+ /* reserved encoding - assume 80 */
+ return IEEE80211_STA_RX_BW_80;
+ }
+ }
+
+ if (params->ht_oper) {
+ switch (u8_get_bits(params->ht_oper->ht_param,
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET)) {
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+ default: /* invalid values */
+ return IEEE80211_STA_RX_BW_20;
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ return IEEE80211_STA_RX_BW_40;
+ }
+ }
+
+ /* nothing found, must be 20 MHz */
+ return IEEE80211_STA_RX_BW_20;
+}
+
+static void ieee80211_update_ap_bandwidth(struct ieee80211_link_data *link,
+ struct cfg80211_beacon_data *params)
+{
+ struct ieee80211_local *local = link->sdata->local;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_chanctx *chanctx;
+
+ /*
+ * Updating the beacon might, without even changing the channel, cause
+ * the usable bandwidth for some stations to be changed, for example
+ * if the beacon configuration is EHT with 160 MHz, HE could change
+ * between 20, 40, 80 and 160 MHz, and HE (or lower) clients need to
+ * be handled accordingly.
+ * Calculate the HE and lower bandwidth and apply that to all stations.
+ *
+ * In the future, this also needs to calculate EHT bandwidth and apply
+ * it to all stations not using UHR DBE, since the chandef would then
+ * include DBE.
+ */
+
+ if (link->conf->chanreq.oper.chan->band == NL80211_BAND_S1GHZ)
+ return;
+
+ link->bss_bw.he_and_lower = ieee80211_calc_ap_he_and_lower(params);
+
+ chanctx_conf = sdata_dereference(link->conf->chanctx_conf, link->sdata);
+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+
+ /*
+ * Note: this relies on ieee80211_recalc_chanctx_min_def() having
+ * the side effect of updating all stations, if they changed; that
+ * was normally for when the chandef changed but is used here too.
+ */
+ ieee80211_recalc_chanctx_min_def(local, chanctx);
+}
+
static int
ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
@@ -1450,6 +1564,8 @@ ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
if (old)
kfree_rcu(old, rcu_head);
+ ieee80211_update_ap_bandwidth(link, params);
+
*changed |= _changed;
return 0;
}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index ecc0123ed448..248531051a4e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -718,6 +718,9 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
* recalc the min required chan width of the channel context, which is
* the max of min required widths of all the interfaces bound to this
* channel context.
+ *
+ * Note: ieee80211_update_ap_bandwidth() relies on this iterating all
+ * affected stations, even if min_def didn't change.
*/
static void
_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
@@ -728,13 +731,11 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
u32 changed = __ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
check_reserved);
- if (!changed)
- return;
-
/* check is BW narrowed */
ieee80211_chan_bw_change(local, ctx, false, true);
- drv_change_chanctx(local, ctx, changed);
+ if (changed)
+ drv_change_chanctx(local, ctx, changed);
/* check is BW wider */
ieee80211_chan_bw_change(local, ctx, false, false);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f1bab633697e..e23e347f870d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1133,6 +1133,10 @@ struct ieee80211_link_data {
struct ieee80211_bss_conf *conf;
+ struct {
+ enum ieee80211_sta_rx_bandwidth he_and_lower;
+ } bss_bw;
+
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfs_dir;
#endif
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ec043d88a6a9..aba2fabfe0db 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -3623,6 +3623,49 @@ ieee80211_sta_bw_capability(struct link_sta_info *link_sta,
return IEEE80211_STA_RX_BW_80;
}
+/**
+ * ieee80211_sta_usable_bw - get STA's usable bandwidth capability
+ * @link_sta: the (link) STA to get the capability for
+ * @band: the band to get the capability on
+ *
+ * If the STA is on an AP interface, take into account the AP's
+ * bandwidth corresponding to this station's PHY capability
+ *
+ * Return: the maximum bandwidth supported by the STA on the
+ * connection to the interface it's connected to
+ */
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_usable_bw(struct link_sta_info *link_sta,
+ enum nl80211_band band)
+{
+ struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata;
+ enum ieee80211_sta_rx_bandwidth bw;
+ struct ieee80211_link_data *link;
+
+ bw = ieee80211_sta_bw_capability(link_sta, band);
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ sdata = get_bss_sdata(sdata);
+
+ /* for a STA to exist on VLAN, it must have AP */
+ if (WARN_ON(!sdata))
+ return IEEE80211_STA_RX_BW_20;
+ }
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
+ return bw;
+
+ /* for a link STA to exist, vif must have the link */
+ link = sdata_dereference(sdata->link[link_sta->link_id], sdata);
+ if (WARN_ON(!link))
+ return IEEE80211_STA_RX_BW_20;
+
+ if (link_sta->pub->eht_cap.has_eht)
+ return bw;
+
+ return min(bw, link->bss_bw.he_and_lower);
+}
+
static enum ieee80211_sta_rx_bandwidth
ieee80211_sta_current_bw_rx_from_sta(struct link_sta_info *link_sta,
struct cfg80211_chan_def *chandef)
@@ -3637,7 +3680,7 @@ ieee80211_sta_current_bw_rx_from_sta(struct link_sta_info *link_sta,
* at a higher bandwidth first while reducing bandwidth, and
* change the chanctx only after the peer accepts, etc.)
*/
- return min(ieee80211_sta_bw_capability(link_sta, chandef->chan->band),
+ return min(ieee80211_sta_usable_bw(link_sta, chandef->chan->band),
link_sta->rx_omi_bw_rx);
}
@@ -3653,7 +3696,7 @@ ieee80211_sta_current_bw_tx_to_sta(struct link_sta_info *link_sta,
bss_width = chandef->width;
band = chandef->chan->band;
- bw = ieee80211_sta_bw_capability(link_sta, band);
+ bw = ieee80211_sta_usable_bw(link_sta, band);
bw = min(bw, link_sta->op_mode_bw);
/* also limit to RX OMI bandwidth we TX to the STA */
bw = min(bw, link_sta->rx_omi_bw_tx);
--
2.53.0
^ permalink raw reply related
* [PATCH 19/20] wifi: mac80211: clarify per-STA bandwidth handling
From: Johannes Berg @ 2026-04-15 12:42 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Miriam Rachel Korenblit
In-Reply-To: <20260415124514.284345-22-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
The per-STA bandwidth handling is completely confusing, given
the function names etc.
Move everything to sta_info.c and rename the functions to
accurately reflect what they return:
- ieee80211_sta_bw_capability()
- ieee80211_sta_current_bw() can return the appropriate
bandwidth in the desired direction (a new enum)
At any given time, the bandwidth with which we expect to receive
frames from a station may differ from the bandwidth with which
we may transmit frames to the station; this will happen either
during RX OMI negotiation, or for a long time if the station
used an HT Notify Channel Width frame. We also implement the
(VHT) Operating Mode Notification as an asymmetric setting, even
if the spec would seem to imply it could be symmetric.
Also rename the 'cur_max_bandwidth' value to 'op_mode_bw' which
matches the 'op_mode_nss', indicating more clearly what it _is_
rather than how it's _used_. It's not quite precise (NSS is)
since it's also HT chanwidth notification, but that seems OK.
Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/chan.c | 11 +--
net/mac80211/he.c | 3 +-
net/mac80211/ht.c | 7 +-
net/mac80211/ieee80211_i.h | 7 --
net/mac80211/mlme.c | 5 +-
net/mac80211/sta_info.c | 157 ++++++++++++++++++++++++++++++++++++-
net/mac80211/sta_info.h | 14 +++-
net/mac80211/tdls.c | 8 +-
net/mac80211/vht.c | 136 ++------------------------------
9 files changed, 193 insertions(+), 155 deletions(-)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 13c0d080ef2a..ecc0123ed448 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -455,10 +455,10 @@ ieee80211_get_sta_bw(struct sta_info *sta, struct ieee80211_link_data *link)
* We assume that TX/RX might be asymmetric (so e.g. VHT operating
* mode notification changes what a STA wants to receive, but not
* necessarily what it will transmit to us), and therefore use the
- * capabilities here. Calling it RX bandwidth capability is a bit
- * wrong though, since capabilities are in fact symmetric.
+ * "from station" bandwidth here.
*/
- width = ieee80211_sta_cap_rx_bw(link_sta, &link->conf->chanreq.oper);
+ width = ieee80211_sta_current_bw(link_sta, &link->conf->chanreq.oper,
+ IEEE80211_STA_BW_RX_FROM_STA);
if (width == IEEE80211_STA_RX_BW_20 &&
!link_sta->pub->ht_cap.ht_supported &&
@@ -693,8 +693,9 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
else
new_chandef = &link_conf->chanreq.oper;
- new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta,
- new_chandef);
+ new_sta_bw = ieee80211_sta_current_bw(link_sta,
+ new_chandef,
+ IEEE80211_STA_BW_TX_TO_STA);
/* nothing change */
if (new_sta_bw == link_sta->pub->bandwidth)
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index 1e8ce33bfe2e..b7d9e4cb6ba6 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -273,7 +273,8 @@ static void ieee80211_link_sta_rc_update_omi(struct ieee80211_link_data *link,
band = link->conf->chanreq.oper.chan->band;
sband = sdata->local->hw.wiphy->bands[band];
- new_bw = ieee80211_sta_cur_vht_bw(link_sta, &link->conf->chanreq.oper);
+ new_bw = ieee80211_sta_current_bw(link_sta, &link->conf->chanreq.oper,
+ IEEE80211_STA_BW_TX_TO_STA);
if (link_sta->pub->bandwidth == new_bw)
return;
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 02ca6e1edc49..6285ac15c16c 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -600,9 +600,10 @@ void ieee80211_ht_handle_chanwidth_notif(struct ieee80211_local *local,
else
max_bw = IEEE80211_STA_RX_BW_MAX;
- /* set cur_max_bandwidth and recalc sta bw */
- link_sta->cur_max_bandwidth = max_bw;
- new_bw = ieee80211_sta_cur_vht_bw(link_sta, &link->conf->chanreq.oper);
+ /* set op_mode_bw and recalc sta bw */
+ link_sta->op_mode_bw = max_bw;
+ new_bw = ieee80211_sta_current_bw(link_sta, &link->conf->chanreq.oper,
+ IEEE80211_STA_BW_TX_TO_STA);
if (link_sta->pub->bandwidth == new_bw)
return;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6b72be762dbe..f1bab633697e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2299,13 +2299,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_vht_cap *vht_cap_ie,
const struct ieee80211_vht_cap *vht_cap_ie2,
struct link_sta_info *link_sta);
-enum ieee80211_sta_rx_bandwidth
-ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
- struct cfg80211_chan_def *chandef);
-enum ieee80211_sta_rx_bandwidth
-ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta,
- struct cfg80211_chan_def *chandef);
-
void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
struct ieee80211_mgmt *mgmt);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6e0e5d3f5015..00b4beff0e43 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2571,8 +2571,9 @@ static void ieee80211_csa_switch_work(struct wiphy *wiphy,
return;
link_sta->pub->bandwidth =
- ieee80211_sta_cur_vht_bw(link_sta,
- &link->csa.chanreq.oper);
+ ieee80211_sta_current_bw(link_sta,
+ &link->csa.chanreq.oper,
+ IEEE80211_STA_BW_TX_TO_STA);
return;
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 508aad14bdf6..ec043d88a6a9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -572,13 +572,13 @@ static int sta_info_alloc_link(struct ieee80211_local *local,
link_info->rx_omi_bw_tx = IEEE80211_STA_RX_BW_MAX;
link_info->rx_omi_bw_staging = IEEE80211_STA_RX_BW_MAX;
- link_info->cur_max_bandwidth = IEEE80211_STA_RX_BW_MAX;
+ link_info->op_mode_bw = IEEE80211_STA_RX_BW_MAX;
/*
* Cause (a) warning(s) if IEEE80211_STA_RX_BW_MAX != 320
* or if new values are added to the enum.
*/
- switch (link_info->cur_max_bandwidth) {
+ switch (link_info->op_mode_bw) {
case IEEE80211_STA_RX_BW_20:
case IEEE80211_STA_RX_BW_40:
case IEEE80211_STA_RX_BW_80:
@@ -3519,7 +3519,9 @@ void ieee80211_sta_init_nss_bw_capa(struct link_sta_info *link_sta,
link_sta->capa_nss = ieee80211_sta_nss_capability(link_sta);
link_sta->pub->rx_nss = link_sta->capa_nss;
- link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta, chandef);
+ link_sta->pub->bandwidth =
+ ieee80211_sta_current_bw(link_sta, chandef,
+ IEEE80211_STA_BW_TX_TO_STA);
}
void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta,
@@ -3554,3 +3556,152 @@ bool lockdep_sta_mutex_held(struct ieee80211_sta *pubsta)
}
EXPORT_SYMBOL(lockdep_sta_mutex_held);
#endif
+
+/**
+ * ieee80211_sta_bw_capability - get STA's bandwidth capability
+ * @link_sta: the (link) STA to get the capability for
+ * @band: the band to get the capability on
+ *
+ * Return: the maximum bandwidth supported by the STA
+ */
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_bw_capability(struct link_sta_info *link_sta,
+ enum nl80211_band band)
+{
+ struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
+ struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
+ struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
+ u32 cap_width;
+
+ if (he_cap->has_he) {
+ u8 info;
+
+ if (eht_cap->has_eht && band == NL80211_BAND_6GHZ) {
+ info = eht_cap->eht_cap_elem.phy_cap_info[0];
+
+ if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
+ return IEEE80211_STA_RX_BW_320;
+ }
+
+ info = he_cap->he_cap_elem.phy_cap_info[0];
+
+ if (band == NL80211_BAND_2GHZ) {
+ if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
+ return IEEE80211_STA_RX_BW_40;
+ return IEEE80211_STA_RX_BW_20;
+ }
+
+ if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
+ info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+ return IEEE80211_STA_RX_BW_160;
+
+ if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
+ return IEEE80211_STA_RX_BW_80;
+
+ return IEEE80211_STA_RX_BW_20;
+ }
+
+ if (!vht_cap->vht_supported)
+ return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
+ IEEE80211_STA_RX_BW_40 :
+ IEEE80211_STA_RX_BW_20;
+
+ cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+
+ if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
+ cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+ return IEEE80211_STA_RX_BW_160;
+
+ /*
+ * If this is non-zero, then it does support 160 MHz after all,
+ * in one form or the other. We don't distinguish here (or even
+ * above) between 160 and 80+80 yet.
+ */
+ if (vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
+ return IEEE80211_STA_RX_BW_160;
+
+ return IEEE80211_STA_RX_BW_80;
+}
+
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_current_bw_rx_from_sta(struct link_sta_info *link_sta,
+ struct cfg80211_chan_def *chandef)
+{
+ /*
+ * Take RX OMI into account. The value "rx_omi_bw_rx" is what
+ * we've indicated to the STA we can currently receive.
+ *
+ * This is needed since the RX OMI is done by us to save power,
+ * requiring changing both our TX (rate control) and RX (chanctx),
+ * which in turn needs to be done in the right order (stop TX
+ * at a higher bandwidth first while reducing bandwidth, and
+ * change the chanctx only after the peer accepts, etc.)
+ */
+ return min(ieee80211_sta_bw_capability(link_sta, chandef->chan->band),
+ link_sta->rx_omi_bw_rx);
+}
+
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_current_bw_tx_to_sta(struct link_sta_info *link_sta,
+ struct cfg80211_chan_def *chandef)
+{
+ struct sta_info *sta = link_sta->sta;
+ enum nl80211_chan_width bss_width;
+ enum ieee80211_sta_rx_bandwidth bw;
+ enum nl80211_band band;
+
+ bss_width = chandef->width;
+ band = chandef->chan->band;
+
+ bw = ieee80211_sta_bw_capability(link_sta, band);
+ bw = min(bw, link_sta->op_mode_bw);
+ /* also limit to RX OMI bandwidth we TX to the STA */
+ bw = min(bw, link_sta->rx_omi_bw_tx);
+
+ /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
+ * IEEE80211-2016 specification makes higher bandwidth operation
+ * possible on the TDLS link if the peers have wider bandwidth
+ * capability.
+ *
+ * However, in this case, and only if the TDLS peer is authorized,
+ * limit to the tdls_chandef so that the configuration here isn't
+ * wider than what's actually requested on the channel context.
+ */
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+ test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) &&
+ test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
+ sta->tdls_chandef.chan)
+ bw = min(bw, ieee80211_chan_width_to_rx_bw(sta->tdls_chandef.width));
+ else
+ bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
+
+ return bw;
+}
+
+/**
+ * ieee80211_sta_current_bw - get STA's current usable bandwidth
+ * @link_sta: the (link) STA to get the bandwidth for
+ * @chandef: the chandef for the channel the STA is on
+ * @direction: the direction (to or from STA)
+ *
+ * Return: the maximum bandwidth that the station can/may
+ * (currently) use in the given direction
+ */
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_current_bw(struct link_sta_info *link_sta,
+ struct cfg80211_chan_def *chandef,
+ enum ieee80211_sta_bw_direction direction)
+{
+ if (WARN_ON(!chandef))
+ return IEEE80211_STA_RX_BW_20;
+
+ switch (direction) {
+ case IEEE80211_STA_BW_RX_FROM_STA:
+ return ieee80211_sta_current_bw_rx_from_sta(link_sta, chandef);
+ case IEEE80211_STA_BW_TX_TO_STA:
+ return ieee80211_sta_current_bw_tx_to_sta(link_sta, chandef);
+ }
+
+ /* unreachable */
+ return IEEE80211_STA_RX_BW_20;
+}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f0497d7d488a..39608a0abbb5 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -504,7 +504,7 @@ struct ieee80211_fragment_cache {
* @status_stats.last_ack_signal: last ACK signal
* @status_stats.ack_signal_filled: last ACK signal validity
* @status_stats.avg_ack_signal: average ACK signal
- * @cur_max_bandwidth: dynamic bandwidth limit for the station,
+ * @op_mode_bw: dynamic bandwidth limit to transmit to the STA,
* taken from HT/VHT capabilities or VHT operating mode notification.
* Invalid for NAN since that is operating on multiple bands.
* @rx_omi_bw_rx: RX OMI bandwidth restriction to apply for RX
@@ -558,7 +558,7 @@ struct link_sta_info {
u64 msdu[IEEE80211_NUM_TIDS + 1];
} tx_stats;
- enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
+ enum ieee80211_sta_rx_bandwidth op_mode_bw;
enum ieee80211_sta_rx_bandwidth rx_omi_bw_rx,
rx_omi_bw_tx,
rx_omi_bw_staging;
@@ -1005,6 +1005,16 @@ void ieee80211_sta_set_max_amsdu_subframes(struct sta_info *sta,
void __ieee80211_sta_recalc_aggregates(struct sta_info *sta, u16 active_links);
+enum ieee80211_sta_bw_direction {
+ IEEE80211_STA_BW_RX_FROM_STA,
+ IEEE80211_STA_BW_TX_TO_STA,
+};
+
+enum ieee80211_sta_rx_bandwidth
+ieee80211_sta_current_bw(struct link_sta_info *link_sta,
+ struct cfg80211_chan_def *chandef,
+ enum ieee80211_sta_bw_direction direction);
+
enum sta_stats_type {
STA_STATS_RATE_TYPE_INVALID = 0,
STA_STATS_RATE_TYPE_LEGACY,
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index dcb5fe98ec55..ffd575a8d188 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -314,7 +314,8 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata,
enum nl80211_chan_width max_width;
int i;
- switch (ieee80211_sta_cap_rx_bw(&sta->deflink, &uc)) {
+ switch (ieee80211_sta_current_bw(&sta->deflink, &uc,
+ IEEE80211_STA_BW_RX_FROM_STA)) {
case IEEE80211_STA_RX_BW_20:
max_width = NL80211_CHAN_WIDTH_20;
break;
@@ -1337,8 +1338,9 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_sta_rx_bandwidth bw;
bw = ieee80211_chan_width_to_rx_bw(conf->def.width);
- bw = min(bw, ieee80211_sta_cap_rx_bw(&sta->deflink,
- &conf->def));
+ bw = min(bw, ieee80211_sta_current_bw(&sta->deflink,
+ &conf->def,
+ IEEE80211_STA_BW_RX_FROM_STA));
if (bw != sta->sta.deflink.bandwidth) {
sta->sta.deflink.bandwidth = bw;
rate_control_rate_update(local, sband,
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 3df5f6c3f777..92a4e0450593 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -331,129 +331,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_recalc_aggregates(&link_sta->sta->sta);
}
-/* FIXME: move this to some better location - parses HE/EHT now */
-static enum ieee80211_sta_rx_bandwidth
-_ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta, enum nl80211_band band)
-{
- struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap;
- struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
- struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap;
- u32 cap_width;
-
- if (he_cap->has_he) {
- u8 info;
-
- if (eht_cap->has_eht && band == NL80211_BAND_6GHZ) {
- info = eht_cap->eht_cap_elem.phy_cap_info[0];
-
- if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)
- return IEEE80211_STA_RX_BW_320;
- }
-
- info = he_cap->he_cap_elem.phy_cap_info[0];
-
- if (band == NL80211_BAND_2GHZ) {
- if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
- return IEEE80211_STA_RX_BW_40;
- return IEEE80211_STA_RX_BW_20;
- }
-
- if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
- info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
- return IEEE80211_STA_RX_BW_160;
-
- if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
- return IEEE80211_STA_RX_BW_80;
-
- return IEEE80211_STA_RX_BW_20;
- }
-
- if (!vht_cap->vht_supported)
- return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
- IEEE80211_STA_RX_BW_40 :
- IEEE80211_STA_RX_BW_20;
-
- cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
-
- if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
- cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
- return IEEE80211_STA_RX_BW_160;
-
- /*
- * If this is non-zero, then it does support 160 MHz after all,
- * in one form or the other. We don't distinguish here (or even
- * above) between 160 and 80+80 yet.
- */
- if (vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)
- return IEEE80211_STA_RX_BW_160;
-
- return IEEE80211_STA_RX_BW_80;
-}
-
-enum ieee80211_sta_rx_bandwidth
-ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
- struct cfg80211_chan_def *chandef)
-{
- /*
- * With RX OMI, also pretend that the STA's capability changed.
- * Of course this isn't really true, it didn't change, only our
- * RX capability was changed by notifying RX OMI to the STA.
- * The purpose, however, is to save power, and that requires
- * changing also transmissions to the AP and the chanctx. The
- * transmissions depend on link_sta->bandwidth which is set in
- * ieee80211_sta_cur_vht_bw() below, but the chanctx depends
- * on the result of this function which is also called by
- * ieee80211_sta_cur_vht_bw(), so we need to do that here as
- * well. This is sufficient for the steady state, but during
- * the transition we already need to change TX/RX separately,
- * so ieee80211_sta_cur_vht_bw() below applies the _tx one.
- */
- return min(_ieee80211_sta_cap_rx_bw(link_sta, chandef->chan->band),
- link_sta->rx_omi_bw_rx);
-}
-
-/* FIXME: rename/move - this deals with everything not just VHT */
-enum ieee80211_sta_rx_bandwidth
-ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta,
- struct cfg80211_chan_def *chandef)
-{
- struct sta_info *sta = link_sta->sta;
- enum nl80211_chan_width bss_width;
- enum ieee80211_sta_rx_bandwidth bw;
- enum nl80211_band band;
-
- if (WARN_ON(!chandef))
- return IEEE80211_STA_RX_BW_20;
-
- bss_width = chandef->width;
- band = chandef->chan->band;
-
- /* intentionally do not take rx_bw_omi_rx into account */
- bw = _ieee80211_sta_cap_rx_bw(link_sta, band);
- bw = min(bw, link_sta->cur_max_bandwidth);
- /* but do apply rx_omi_bw_tx */
- bw = min(bw, link_sta->rx_omi_bw_tx);
-
- /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of
- * IEEE80211-2016 specification makes higher bandwidth operation
- * possible on the TDLS link if the peers have wider bandwidth
- * capability.
- *
- * However, in this case, and only if the TDLS peer is authorized,
- * limit to the tdls_chandef so that the configuration here isn't
- * wider than what's actually requested on the channel context.
- */
- if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
- test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) &&
- test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
- sta->tdls_chandef.chan)
- bw = min(bw, ieee80211_chan_width_to_rx_bw(sta->tdls_chandef.width));
- else
- bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
-
- return bw;
-}
-
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct link_sta_info *link_sta,
u8 opmode, enum nl80211_band band)
@@ -496,25 +373,26 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
/* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
- link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
+ link_sta->op_mode_bw = IEEE80211_STA_RX_BW_20;
break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
/* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
- link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
+ link_sta->op_mode_bw = IEEE80211_STA_RX_BW_40;
break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80)
- link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+ link_sta->op_mode_bw = IEEE80211_STA_RX_BW_160;
else
- link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
+ link_sta->op_mode_bw = IEEE80211_STA_RX_BW_80;
break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
/* legacy only, no longer used by newer spec */
- link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+ link_sta->op_mode_bw = IEEE80211_STA_RX_BW_160;
break;
}
- new_bw = ieee80211_sta_cur_vht_bw(link_sta, &link->conf->chanreq.oper);
+ new_bw = ieee80211_sta_current_bw(link_sta, &link->conf->chanreq.oper,
+ IEEE80211_STA_BW_TX_TO_STA);
if (new_bw != link_sta->pub->bandwidth) {
link_sta->pub->bandwidth = new_bw;
sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(new_bw);
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox