* [PATCH 01/19] wifi: mac80211: add some support for RX OMI power saving
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 02/19] wifi: mac80211: remove an unneeded check in Rx Miri Korenblit
` (17 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
In order to save power, it can be desirable to change the
RX operating mode using OMI to reduce the bandwidth. As the
handshake must be done in the HTC+ field, it cannot be done
by mac80211 directly, so expose functions to the driver to
request and finalize the necessary updates.
Note that RX OMI really only changes what the peer (AP) will
transmit to us, but in order to use it to actually save some
power (by reducing the listen bandwidth) we also update rate
scaling and then the channel context's mindef accordingly.
The updates are split into two in order to sequence them
correctly, when reducing bandwidth first reduce the rate
scaling and thus TX, then send OMI, then reduce the listen
bandwidth (chandef); when increasing bandwidth this is the
other way around. This also requires tracking in different
variables which part is applicable already.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/net/mac80211.h | 46 ++++++++++++++++
net/mac80211/chan.c | 7 +++
net/mac80211/he.c | 119 +++++++++++++++++++++++++++++++++++++++-
net/mac80211/sta_info.c | 18 ++++++
net/mac80211/sta_info.h | 7 +++
net/mac80211/trace.h | 98 +++++++++++++++++++++++++++++++++
net/mac80211/vht.c | 33 +++++++++--
7 files changed, 323 insertions(+), 5 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9320d4bc22ee..9cb88ef4b7c9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2336,6 +2336,8 @@ enum ieee80211_sta_rx_bandwidth {
IEEE80211_STA_RX_BW_320,
};
+#define IEEE80211_STA_RX_BW_MAX IEEE80211_STA_RX_BW_320
+
/**
* struct ieee80211_sta_rates - station rate selection table
*
@@ -7734,6 +7736,50 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
}
}
+/**
+ * ieee80211_prepare_rx_omi_bw - prepare for sending BW RX OMI
+ * @link_sta: the link STA the OMI is going to be sent to
+ * @bw: the bandwidth requested
+ *
+ * When the driver decides to do RX OMI to change bandwidth with a STA
+ * it calls this function to prepare, then sends the OMI, and finally
+ * calls ieee80211_finalize_rx_omi_bw().
+ *
+ * Note that the (link) STA rate control is updated accordingly as well,
+ * but the chanctx might not be updated if there are other users.
+ * If the intention is to reduce the listen bandwidth, the driver must
+ * ensure there are no TDLS stations nor other uses of the chanctx.
+ *
+ * Also note that in order to sequence correctly, narrowing bandwidth
+ * will only happen in ieee80211_finalize_rx_omi_bw(), whereas widening
+ * again (e.g. going back to normal) will happen here.
+ *
+ * Note that we treat this symmetrically, so if the driver calls this
+ * and tells the peer to only send with a lower bandwidth, we assume
+ * that the driver also wants to only send at that lower bandwidth, to
+ * allow narrowing of the chanctx request for this station/interface.
+ *
+ * Finally, the driver must ensure that if the function returned %true,
+ * ieee80211_finalize_rx_omi_bw() is also called, even for example in
+ * case of HW restart.
+ *
+ * Context: Must be called with wiphy mutex held, and will call back
+ * into the driver, so ensure no driver locks are held.
+ *
+ * Return: %true if changes are going to be made, %false otherwise
+ */
+bool ieee80211_prepare_rx_omi_bw(struct ieee80211_link_sta *link_sta,
+ enum ieee80211_sta_rx_bandwidth bw);
+
+/**
+ * ieee80211_finalize_rx_omi_bw - finalize BW RX OMI update
+ * @link_sta: the link STA the OMI was sent to
+ *
+ * See ieee80211_client_prepare_rx_omi_bw(). Context is the same here
+ * as well.
+ */
+void ieee80211_finalize_rx_omi_bw(struct ieee80211_link_sta *link_sta);
+
/* for older drivers - let's not document these ... */
int ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index a442cb667520..dc28f2b0957a 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -247,6 +247,13 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
if (!link_sta)
return NL80211_CHAN_WIDTH_20_NOHT;
+ /*
+ * 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.
+ */
width = ieee80211_sta_cap_rx_bw(link_sta);
switch (width) {
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index ecbb042dd043..5792ef77e986 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -3,10 +3,11 @@
* HE handling
*
* Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(c) 2019 - 2023 Intel Corporation
+ * Copyright(c) 2019 - 2024 Intel Corporation
*/
#include "ieee80211_i.h"
+#include "rate.h"
static void
ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
@@ -248,3 +249,119 @@ ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif,
he_obss_pd->enable = true;
}
}
+
+static void ieee80211_link_sta_rc_update_omi(struct ieee80211_link_data *link,
+ struct link_sta_info *link_sta)
+{
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_sta_rx_bandwidth new_bw;
+ enum nl80211_band band;
+
+ band = link->conf->chanreq.oper.chan->band;
+ sband = sdata->local->hw.wiphy->bands[band];
+
+ new_bw = ieee80211_sta_cur_vht_bw(link_sta);
+ if (link_sta->pub->bandwidth == new_bw)
+ return;
+
+ link_sta->pub->bandwidth = new_bw;
+ rate_control_rate_update(sdata->local, sband, link_sta,
+ IEEE80211_RC_BW_CHANGED);
+}
+
+bool ieee80211_prepare_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta,
+ enum ieee80211_sta_rx_bandwidth bw)
+{
+ struct sta_info *sta = container_of(pub_link_sta->sta,
+ struct sta_info, sta);
+ struct ieee80211_local *local = sta->sdata->local;
+ struct link_sta_info *link_sta =
+ sdata_dereference(sta->link[pub_link_sta->link_id], sta->sdata);
+ struct ieee80211_link_data *link =
+ sdata_dereference(sta->sdata->link[pub_link_sta->link_id],
+ sta->sdata);
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *chanctx;
+ bool ret;
+
+ if (WARN_ON(!link || !link_sta || link_sta->pub != pub_link_sta))
+ return false;
+
+ conf = sdata_dereference(link->conf->chanctx_conf, sta->sdata);
+ if (WARN_ON(!conf))
+ return false;
+
+ trace_api_prepare_rx_omi_bw(local, sta->sdata, link_sta, bw);
+
+ chanctx = container_of(conf, typeof(*chanctx), conf);
+
+ if (link_sta->rx_omi_bw_staging == bw) {
+ ret = false;
+ goto trace;
+ }
+
+ /* must call this API in pairs */
+ if (WARN_ON(link_sta->rx_omi_bw_tx != link_sta->rx_omi_bw_staging ||
+ link_sta->rx_omi_bw_rx != link_sta->rx_omi_bw_staging)) {
+ ret = false;
+ goto trace;
+ }
+
+ if (bw < link_sta->rx_omi_bw_staging) {
+ link_sta->rx_omi_bw_tx = bw;
+ ieee80211_link_sta_rc_update_omi(link, link_sta);
+ } else {
+ link_sta->rx_omi_bw_rx = bw;
+ ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
+ }
+
+ link_sta->rx_omi_bw_staging = bw;
+ ret = true;
+trace:
+ trace_api_return_bool(local, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ieee80211_prepare_rx_omi_bw);
+
+void ieee80211_finalize_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta)
+{
+ struct sta_info *sta = container_of(pub_link_sta->sta,
+ struct sta_info, sta);
+ struct ieee80211_local *local = sta->sdata->local;
+ struct link_sta_info *link_sta =
+ sdata_dereference(sta->link[pub_link_sta->link_id], sta->sdata);
+ struct ieee80211_link_data *link =
+ sdata_dereference(sta->sdata->link[pub_link_sta->link_id],
+ sta->sdata);
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *chanctx;
+
+ if (WARN_ON(!link || !link_sta || link_sta->pub != pub_link_sta))
+ return;
+
+ conf = sdata_dereference(link->conf->chanctx_conf, sta->sdata);
+ if (WARN_ON(!conf))
+ return;
+
+ trace_api_finalize_rx_omi_bw(local, sta->sdata, link_sta);
+
+ chanctx = container_of(conf, typeof(*chanctx), conf);
+
+ if (link_sta->rx_omi_bw_tx != link_sta->rx_omi_bw_staging) {
+ /* rate control in finalize only when widening bandwidth */
+ WARN_ON(link_sta->rx_omi_bw_tx > link_sta->rx_omi_bw_staging);
+ link_sta->rx_omi_bw_tx = link_sta->rx_omi_bw_staging;
+ ieee80211_link_sta_rc_update_omi(link, link_sta);
+ }
+
+ if (link_sta->rx_omi_bw_rx != link_sta->rx_omi_bw_staging) {
+ /* channel context in finalize only when narrowing bandwidth */
+ WARN_ON(link_sta->rx_omi_bw_rx < link_sta->rx_omi_bw_staging);
+ link_sta->rx_omi_bw_rx = link_sta->rx_omi_bw_staging;
+ ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
+ }
+
+ trace_api_return_void(local);
+}
+EXPORT_SYMBOL_GPL(ieee80211_finalize_rx_omi_bw);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index aa22f09e6d14..19bc9cbd34f0 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -509,6 +509,24 @@ static int sta_info_alloc_link(struct ieee80211_local *local,
for (i = 0; i < ARRAY_SIZE(link_info->rx_stats_avg.chain_signal); i++)
ewma_signal_init(&link_info->rx_stats_avg.chain_signal[i]);
+ link_info->rx_omi_bw_rx = IEEE80211_STA_RX_BW_MAX;
+ link_info->rx_omi_bw_tx = IEEE80211_STA_RX_BW_MAX;
+ link_info->rx_omi_bw_staging = 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) {
+ case IEEE80211_STA_RX_BW_20:
+ case IEEE80211_STA_RX_BW_40:
+ case IEEE80211_STA_RX_BW_80:
+ case IEEE80211_STA_RX_BW_160:
+ case IEEE80211_STA_RX_BW_MAX:
+ /* intentionally nothing */
+ break;
+ }
+
return 0;
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9f89fb5bee37..cc5f9e4e2083 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -512,6 +512,10 @@ struct ieee80211_fragment_cache {
* @status_stats.avg_ack_signal: average ACK signal
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
* taken from HT/VHT capabilities or VHT operating mode notification
+ * @rx_omi_bw_rx: RX OMI bandwidth restriction to apply for RX
+ * @rx_omi_bw_tx: RX OMI bandwidth restriction to apply for TX
+ * @rx_omi_bw_staging: RX OMI bandwidth restriction to apply later
+ * during finalize
* @debugfs_dir: debug filesystem directory dentry
* @pub: public (driver visible) link STA data
* TODO Move other link params from sta_info as required for MLD operation
@@ -561,6 +565,9 @@ struct link_sta_info {
} tx_stats;
enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
+ enum ieee80211_sta_rx_bandwidth rx_omi_bw_rx,
+ rx_omi_bw_tx,
+ rx_omi_bw_staging;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfs_dir;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index dc35fed7e9b0..fe26fb46758d 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2590,6 +2590,45 @@ TRACE_EVENT(drv_change_sta_links,
* Tracing for API calls that drivers call.
*/
+TRACE_EVENT(api_return_bool,
+ TP_PROTO(struct ieee80211_local *local, bool result),
+
+ TP_ARGS(local, result),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(bool, result)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->result = result;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " result=%d",
+ LOCAL_PR_ARG, __entry->result
+ )
+);
+
+TRACE_EVENT(api_return_void,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
TRACE_EVENT(api_start_tx_ba_session,
TP_PROTO(struct ieee80211_sta *sta, u16 tid),
@@ -3054,6 +3093,65 @@ TRACE_EVENT(api_request_smps,
)
);
+TRACE_EVENT(api_prepare_rx_omi_bw,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct link_sta_info *link_sta,
+ enum ieee80211_sta_rx_bandwidth bw),
+
+ TP_ARGS(local, sdata, link_sta, bw),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(int, link_id)
+ __field(u32, bw)
+ __field(bool, result)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_NAMED_ASSIGN(link_sta->sta);
+ __entry->link_id = link_sta->link_id;
+ __entry->bw = bw;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " " VIF_PR_FMT " " STA_PR_FMT " link:%d, bw:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
+ __entry->link_id, __entry->bw
+ )
+);
+
+TRACE_EVENT(api_finalize_rx_omi_bw,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct link_sta_info *link_sta),
+
+ TP_ARGS(local, sdata, link_sta),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(int, link_id)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_NAMED_ASSIGN(link_sta->sta);
+ __entry->link_id = link_sta->link_id;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " " VIF_PR_FMT " " STA_PR_FMT " link:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id
+ )
+);
+
/*
* Tracing for internal functions
* (which may also be called in response to driver calls)
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 6a20fa099190..c5c5d16ed6c8 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -350,9 +350,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
}
/* FIXME: move this to some better location - parses HE/EHT now */
-enum ieee80211_sta_rx_bandwidth
-_ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
- struct cfg80211_chan_def *chandef)
+static enum ieee80211_sta_rx_bandwidth
+__ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
+ struct cfg80211_chan_def *chandef)
{
unsigned int link_id = link_sta->link_id;
struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata;
@@ -423,6 +423,28 @@ _ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
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),
+ link_sta->rx_omi_bw_rx);
+}
+
enum nl80211_chan_width
ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta)
{
@@ -503,8 +525,11 @@ _ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta,
rcu_read_unlock();
}
- bw = _ieee80211_sta_cap_rx_bw(link_sta, chandef);
+ /* intentionally do not take rx_bw_omi_rx into account */
+ bw = __ieee80211_sta_cap_rx_bw(link_sta, chandef);
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
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 02/19] wifi: mac80211: remove an unneeded check in Rx
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
2025-01-01 5:05 ` [PATCH 01/19] wifi: mac80211: add some support for RX OMI power saving Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 03/19] wifi: mac80211: clarify key idx documententaion Miri Korenblit
` (16 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Emmanuel Grumbach, Johannes Berg
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Coverity pointed out that __ieee80211_rx_h_amsdu() checks if rx->sta is
NULL before dereferencing it but not always.
Since rx->sta can't be NULL at this point, just remove the check to
avoid confusion
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/rx.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 58c1b9a4e8b5..3c0cc3cf5ec8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3034,8 +3034,7 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
check_da = NULL;
break;
case NL80211_IFTYPE_STATION:
- if (!rx->sta ||
- !test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
+ if (!test_sta_flag(rx->sta, WLAN_STA_TDLS_PEER))
check_sa = NULL;
break;
case NL80211_IFTYPE_MESH_POINT:
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 03/19] wifi: mac80211: clarify key idx documententaion
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
2025-01-01 5:05 ` [PATCH 01/19] wifi: mac80211: add some support for RX OMI power saving Miri Korenblit
2025-01-01 5:05 ` [PATCH 02/19] wifi: mac80211: remove an unneeded check in Rx Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 04/19] wifi: mac80211: reject per-band vendor elements with MLO Miri Korenblit
` (15 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
ieee80211_key_conf::keyidx s in range 0-7, ano not 0-3. Make this clear
in the documentation.
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9cb88ef4b7c9..34382d014c8b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2216,7 +2216,7 @@ enum ieee80211_key_flags {
* @tx_pn: PN used for TX keys, may be used by the driver as well if it
* needs to do software PN assignment by itself (e.g. due to TSO)
* @flags: key flags, see &enum ieee80211_key_flags.
- * @keyidx: the key index (0-3)
+ * @keyidx: the key index (0-7)
* @keylen: key material length
* @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte)
* data block:
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 04/19] wifi: mac80211: reject per-band vendor elements with MLO
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (2 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 03/19] wifi: mac80211: clarify key idx documententaion Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 05/19] wifi: mac80211: mlme: improve messages from config_bw() Miri Korenblit
` (14 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
The MLME code doesn't currently handle adding vendor elements
correctly with multi-link due to element inheritance. Simply
prevent that for now completely, if someone needs it we can
fix this later.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/main.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index f13c14fa82e8..53e5aee46885 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1310,6 +1310,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 */
+ if (WARN_ON(iftd->vendor_elems.len &&
+ hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
+ return -EINVAL;
}
/* HT, VHT, HE require QoS, thus >= 4 queues */
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 05/19] wifi: mac80211: mlme: improve messages from config_bw()
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (3 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 04/19] wifi: mac80211: reject per-band vendor elements with MLO Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 06/19] wifi: cfg80211: scan: skip duplicate RNR entries Miri Korenblit
` (13 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
The ieee80211_config_bw() function is called in different
contexts: during association with the association response
and during beacon tracking with the beacon. This can be a
bit misleading, so disambiguate the messages for those.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mlme.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 61c318f5239f..956eb265fe78 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -988,7 +988,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
static int ieee80211_config_bw(struct ieee80211_link_data *link,
struct ieee802_11_elems *elems,
- bool update, u64 *changed)
+ bool update, u64 *changed,
+ const char *frame)
{
struct ieee80211_channel *channel = link->conf->chanreq.oper.chan;
struct ieee80211_sub_if_data *sdata = link->sdata;
@@ -1013,9 +1014,10 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
if (ap_mode != link->u.mgd.conn.mode) {
link_info(link,
- "AP appears to change mode (expected %s, found %s), disconnect\n",
+ "AP %pM appears to change mode (expected %s, found %s) in %s, disconnect\n",
+ link->u.mgd.bssid,
ieee80211_conn_mode_str(link->u.mgd.conn.mode),
- ieee80211_conn_mode_str(ap_mode));
+ ieee80211_conn_mode_str(ap_mode), frame);
return -EINVAL;
}
@@ -1060,16 +1062,16 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
return 0;
link_info(link,
- "AP %pM changed bandwidth, new used config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n",
- link->u.mgd.bssid, chanreq.oper.chan->center_freq,
+ "AP %pM changed bandwidth in %s, new used config is %d.%03d MHz, width %d (%d.%03d/%d MHz)\n",
+ link->u.mgd.bssid, frame, chanreq.oper.chan->center_freq,
chanreq.oper.chan->freq_offset, chanreq.oper.width,
chanreq.oper.center_freq1, chanreq.oper.freq1_offset,
chanreq.oper.center_freq2);
if (!cfg80211_chandef_valid(&chanreq.oper)) {
sdata_info(sdata,
- "AP %pM changed caps/bw in a way we can't support - disconnect\n",
- link->u.mgd.bssid);
+ "AP %pM changed caps/bw in %s in a way we can't support - disconnect\n",
+ link->u.mgd.bssid, frame);
return -EINVAL;
}
@@ -1098,8 +1100,8 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
ret = ieee80211_link_change_chanreq(link, &chanreq, changed);
if (ret) {
sdata_info(sdata,
- "AP %pM changed bandwidth to incompatible one - disconnect\n",
- link->u.mgd.bssid);
+ "AP %pM changed bandwidth in %s to incompatible one - disconnect\n",
+ link->u.mgd.bssid, frame);
return ret;
}
@@ -4898,7 +4900,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
/* check/update if AP changed anything in assoc response vs. scan */
if (ieee80211_config_bw(link, elems,
link_id == assoc_data->assoc_link_id,
- changed)) {
+ changed, "assoc response")) {
ret = false;
goto out;
}
@@ -7056,7 +7058,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
changed |= ieee80211_recalc_twt_req(sdata, sband, link, link_sta, elems);
- if (ieee80211_config_bw(link, elems, true, &changed)) {
+ if (ieee80211_config_bw(link, elems, true, &changed, "beacon")) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DEAUTH_LEAVING,
true, deauth_buf);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 06/19] wifi: cfg80211: scan: skip duplicate RNR entries
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (4 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 05/19] wifi: mac80211: mlme: improve messages from config_bw() Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 07/19] wifi: cfg80211: check extended MLD capa/ops in assoc Miri Korenblit
` (12 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg, Ilan Peer, Benjamin Berg
From: Johannes Berg <johannes.berg@intel.com>
There really shouldn't be duplicate entries when we give
the list to the driver, and since we already have a list
it's easy to avoid.
While at it, remove the unnecessary allocation there.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Benjamin Berg <benjamin.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/wireless/scan.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index d056248c43d2..ec9c071915f3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -704,7 +704,7 @@ cfg80211_parse_colocated_ap_iter(void *_data, u8 type,
bss_params)))
return RNR_ITER_CONTINUE;
- entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, GFP_ATOMIC);
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry)
return RNR_ITER_ERROR;
@@ -713,6 +713,17 @@ cfg80211_parse_colocated_ap_iter(void *_data, u8 type,
if (!cfg80211_parse_ap_info(entry, tbtt_info, tbtt_info_len,
data->ssid_elem, data->s_ssid_tmp)) {
+ struct cfg80211_colocated_ap *tmp;
+
+ /* Don't add duplicate BSSIDs on the same channel. */
+ list_for_each_entry(tmp, &data->ap_list, list) {
+ if (ether_addr_equal(tmp->bssid, entry->bssid) &&
+ tmp->center_freq == entry->center_freq) {
+ kfree(entry);
+ return RNR_ITER_CONTINUE;
+ }
+ }
+
data->n_coloc++;
list_add_tail(&entry->list, &data->ap_list);
} else {
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 07/19] wifi: cfg80211: check extended MLD capa/ops in assoc
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (5 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 06/19] wifi: cfg80211: scan: skip duplicate RNR entries Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 08/19] wifi: mac80211: improve stop/wake queue tracing Miri Korenblit
` (11 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Check that additionally extended MLD capa/ops for the MLD is
consistent, i.e. the same value is reported by all affiliated
APs/links.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/linux/ieee80211.h | 44 +++++++++++++++++++++++++++++++++++++++
net/wireless/mlme.c | 7 +++++++
2 files changed, 51 insertions(+)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 05dedc45505c..9c0e2617fe8f 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -4961,6 +4961,7 @@ struct ieee80211_multi_link_elem {
#define IEEE80211_MLC_BASIC_PRES_EML_CAPA 0x0080
#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP 0x0100
#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200
+#define IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP 0x0400
#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff
#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00
@@ -5226,6 +5227,47 @@ static inline u16 ieee80211_mle_get_mld_capa_op(const u8 *data)
return get_unaligned_le16(common);
}
+/**
+ * ieee80211_mle_get_ext_mld_capa_op - returns the extended MLD capabilities
+ * and operations.
+ * @data: pointer to the multi-link element
+ * Return: the extended MLD capabilities and operations field value from
+ * the multi-link element, or 0 if not present
+ *
+ * The element is assumed to be of the correct type (BASIC) and big enough,
+ * this must be checked using ieee80211_mle_type_ok().
+ */
+static inline u16 ieee80211_mle_get_ext_mld_capa_op(const u8 *data)
+{
+ const struct ieee80211_multi_link_elem *mle = (const void *)data;
+ u16 control = le16_to_cpu(mle->control);
+ const u8 *common = mle->variable;
+
+ /*
+ * common points now at the beginning of
+ * ieee80211_mle_basic_common_info
+ */
+ common += sizeof(struct ieee80211_mle_basic_common_info);
+
+ if (!(control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP))
+ return 0;
+
+ if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
+ common += 1;
+ if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
+ common += 1;
+ if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)
+ common += 2;
+ if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)
+ common += 2;
+ if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)
+ common += 2;
+ if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID)
+ common += 1;
+
+ return get_unaligned_le16(common);
+}
+
/**
* ieee80211_mle_get_mld_id - returns the MLD ID
* @data: pointer to the multi-link element
@@ -5298,6 +5340,8 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
common += 2;
if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID)
common += 1;
+ if (control & IEEE80211_MLC_BASIC_PRES_EXT_MLD_CAPA_OP)
+ common += 2;
break;
case IEEE80211_ML_CONTROL_TYPE_PREQ:
common += sizeof(struct ieee80211_mle_preq_common_info);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 9d577523462d..5c09bf4cdc2e 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -352,6 +352,13 @@ cfg80211_mlme_check_mlo_compat(const struct ieee80211_multi_link_elem *mle_a,
return -EINVAL;
}
+ if (ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_a) !=
+ ieee80211_mle_get_ext_mld_capa_op((const u8 *)mle_b)) {
+ NL_SET_ERR_MSG(extack,
+ "extended link MLD capabilities/ops mismatch");
+ return -EINVAL;
+ }
+
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 08/19] wifi: mac80211: improve stop/wake queue tracing
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (6 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 07/19] wifi: cfg80211: check extended MLD capa/ops in assoc Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 09/19] wifi: mac80211: Remove unused basic_rates variable Miri Korenblit
` (10 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Emmanuel Grumbach, Johannes Berg
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Add the refcount. This can be useful when we want to understand why a
queue stays stopped after it is woken.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/trace.h | 22 ++++++++++++++--------
net/mac80211/util.c | 10 ++++++----
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index fe26fb46758d..72fad8ea8bb9 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -3159,49 +3159,55 @@ TRACE_EVENT(api_finalize_rx_omi_bw,
TRACE_EVENT(wake_queue,
TP_PROTO(struct ieee80211_local *local, u16 queue,
- enum queue_stop_reason reason),
+ enum queue_stop_reason reason, int refcount),
- TP_ARGS(local, queue, reason),
+ TP_ARGS(local, queue, reason, refcount),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(u16, queue)
__field(u32, reason)
+ __field(int, refcount)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->queue = queue;
__entry->reason = reason;
+ __entry->refcount = refcount;
),
TP_printk(
- LOCAL_PR_FMT " queue:%d, reason:%d",
- LOCAL_PR_ARG, __entry->queue, __entry->reason
+ LOCAL_PR_FMT " queue:%d, reason:%d, refcount: %d",
+ LOCAL_PR_ARG, __entry->queue, __entry->reason,
+ __entry->refcount
)
);
TRACE_EVENT(stop_queue,
TP_PROTO(struct ieee80211_local *local, u16 queue,
- enum queue_stop_reason reason),
+ enum queue_stop_reason reason, int refcount),
- TP_ARGS(local, queue, reason),
+ TP_ARGS(local, queue, reason, refcount),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(u16, queue)
__field(u32, reason)
+ __field(int, refcount)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->queue = queue;
__entry->reason = reason;
+ __entry->refcount = refcount;
),
TP_printk(
- LOCAL_PR_FMT " queue:%d, reason:%d",
- LOCAL_PR_ARG, __entry->queue, __entry->reason
+ LOCAL_PR_FMT " queue:%d, reason:%d, refcount: %d",
+ LOCAL_PR_ARG, __entry->queue, __entry->reason,
+ __entry->refcount
)
);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7b656326e68a..94cf19cf4e28 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -437,8 +437,6 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
{
struct ieee80211_local *local = hw_to_local(hw);
- trace_wake_queue(local, queue, reason);
-
if (WARN_ON(queue >= hw->queues))
return;
@@ -456,6 +454,9 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
if (local->q_stop_reasons[queue][reason] == 0)
__clear_bit(reason, &local->queue_stop_reasons[queue]);
+ trace_wake_queue(local, queue, reason,
+ local->q_stop_reasons[queue][reason]);
+
if (local->queue_stop_reasons[queue] != 0)
/* someone still has this queue stopped */
return;
@@ -502,8 +503,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
{
struct ieee80211_local *local = hw_to_local(hw);
- trace_stop_queue(local, queue, reason);
-
if (WARN_ON(queue >= hw->queues))
return;
@@ -512,6 +511,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
else
local->q_stop_reasons[queue][reason]++;
+ trace_stop_queue(local, queue, reason,
+ local->q_stop_reasons[queue][reason]);
+
set_bit(reason, &local->queue_stop_reasons[queue]);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 09/19] wifi: mac80211: Remove unused basic_rates variable
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (7 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 08/19] wifi: mac80211: improve stop/wake queue tracing Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 10/19] wifi: mac80211: fix typo in HE MCS check Miri Korenblit
` (9 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
The basic_rates variable was passed to mesh_sta_info_init as an out
parameter even though the result is not used. Passing NULL instead is
safe here, so do that.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mesh_plink.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 6ea35c88dc48..5a0156e11c91 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -432,15 +432,14 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
- u32 rates, basic_rates = 0, changed = 0;
+ u32 rates, changed = 0;
enum ieee80211_sta_rx_bandwidth bw = sta->sta.deflink.bandwidth;
sband = ieee80211_get_sband(sdata);
if (!sband)
return;
- rates = ieee80211_sta_get_rates(sdata, elems, sband->band,
- &basic_rates);
+ rates = ieee80211_sta_get_rates(sdata, elems, sband->band, NULL);
spin_lock_bh(&sta->mesh->plink_lock);
sta->deflink.rx_stats.last_rx = jiffies;
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 10/19] wifi: mac80211: fix typo in HE MCS check
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (8 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 09/19] wifi: mac80211: Remove unused basic_rates variable Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 11/19] wifi: mac80211: log link information in ieee80211_determine_chan_mode Miri Korenblit
` (8 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
It printed the AP RX MCS value instead of the TX one.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mlme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 956eb265fe78..2d4beb02114a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -419,7 +419,7 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) {
sdata_info(sdata,
"Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
- nss, ap_rx_val, ap_rx_val, ap_op_val);
+ nss, ap_rx_val, ap_tx_val, ap_op_val);
return false;
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 11/19] wifi: mac80211: log link information in ieee80211_determine_chan_mode
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (9 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 10/19] wifi: mac80211: fix typo in HE MCS check Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 12/19] wifi: mac80211: add HT and VHT basic set verification Miri Korenblit
` (7 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
ieee80211_determine_chan_mode is called for each link and if there is a
downgrade, then it is interesting to know on which link it happened.
Pass through the link_id where relevant and use the new link_id_info
macro instead of sdata_info so that the link ID is printed when
relevant.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/debug.h | 10 +++++++++-
net/mac80211/mlme.c | 30 +++++++++++++++++-------------
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
index 35a8ba25fa57..5b81998cb0c9 100644
--- a/net/mac80211/debug.h
+++ b/net/mac80211/debug.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Portions
- * Copyright (C) 2022 - 2023 Intel Corporation
+ * Copyright (C) 2022 - 2024 Intel Corporation
*/
#ifndef __MAC80211_DEBUG_H
#define __MAC80211_DEBUG_H
@@ -152,6 +152,14 @@ do { \
else \
_sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \
} while (0)
+#define link_id_info(sdata, link_id, fmt, ...) \
+ do { \
+ if (ieee80211_vif_is_mld(&sdata->vif)) \
+ _sdata_info(sdata, "[link %d] " fmt, link_id, \
+ ##__VA_ARGS__); \
+ else \
+ _sdata_info(sdata, fmt, ##__VA_ARGS__); \
+ } while (0)
#define _link_id_dbg(print, sdata, link_id, fmt, ...) \
do { \
if (ieee80211_vif_is_mld(&(sdata)->vif)) \
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2d4beb02114a..2547e0c9e77f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -344,6 +344,7 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
static bool
ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
+ int link_id,
const struct ieee80211_he_cap_elem *he_cap,
const struct ieee80211_he_operation *he_op)
{
@@ -371,9 +372,9 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
*/
if ((mcs_80_map_tx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED ||
(mcs_80_map_rx & 0x3) == IEEE80211_HE_MCS_NOT_SUPPORTED) {
- sdata_info(sdata,
- "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n",
- mcs_80_map_tx, mcs_80_map_rx);
+ link_id_info(sdata, link_id,
+ "Missing mandatory rates for 1 Nss, rx 0x%x, tx 0x%x, disable HE\n",
+ mcs_80_map_tx, mcs_80_map_rx);
return false;
}
@@ -417,9 +418,9 @@ ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
if (ap_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
ap_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
ap_rx_val < ap_op_val || ap_tx_val < ap_op_val) {
- sdata_info(sdata,
- "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
- nss, ap_rx_val, ap_tx_val, ap_op_val);
+ link_id_info(sdata, link_id,
+ "Invalid rates for %d Nss, rx %d, tx %d oper %d, disable HE\n",
+ nss, ap_rx_val, ap_tx_val, ap_op_val);
return false;
}
}
@@ -870,8 +871,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
return elems;
case NL80211_BAND_6GHZ:
if (ap_mode < IEEE80211_CONN_MODE_HE) {
- sdata_info(sdata,
- "Rejecting non-HE 6/7 GHz connection");
+ link_id_info(sdata, link_id,
+ "Rejecting non-HE 6/7 GHz connection");
ret = -EINVAL;
goto free;
}
@@ -942,16 +943,18 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
}
if (chanreq->oper.width != ap_chandef->width || ap_mode != conn->mode)
- sdata_info(sdata,
- "regulatory prevented using AP config, downgraded\n");
+ link_id_info(sdata, link_id,
+ "regulatory prevented using AP config, downgraded\n");
if (conn->mode >= IEEE80211_CONN_MODE_HE &&
- (!ieee80211_verify_peer_he_mcs_support(sdata, (void *)elems->he_cap,
+ (!ieee80211_verify_peer_he_mcs_support(sdata, link_id,
+ (void *)elems->he_cap,
elems->he_operation) ||
!ieee80211_verify_sta_he_mcs_support(sdata, sband,
elems->he_operation))) {
conn->mode = IEEE80211_CONN_MODE_VHT;
- sdata_info(sdata, "required MCSes not supported, disabling HE\n");
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling HE\n");
}
if (conn->mode >= IEEE80211_CONN_MODE_EHT &&
@@ -961,7 +964,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
conn->bw_limit = min_t(enum ieee80211_conn_bw_limit,
conn->bw_limit,
IEEE80211_CONN_BW_LIMIT_160);
- sdata_info(sdata, "required MCSes not supported, disabling EHT\n");
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling EHT\n");
}
/* the mode can only decrease, so this must terminate */
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 12/19] wifi: mac80211: add HT and VHT basic set verification
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (10 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 11/19] wifi: mac80211: log link information in ieee80211_determine_chan_mode Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-13 9:51 ` Johannes Berg
2025-01-01 5:05 ` [PATCH 13/19] wifi: mac80211: skip all known membership selectors Miri Korenblit
` (6 subsequent siblings)
18 siblings, 1 reply; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
So far we did not verify the HT and VHT basic MCS set. However, in
P802.11REVme/D7.0 (6.5.4.2.4) says that the MLME-JOIN.request shall
return an error if the VHT and HT basic set requirements are not met.
Also extend the tests a bit, and for that change the test sdata
registration to only have four spatial streams.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mlme.c | 124 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2547e0c9e77f..061d20ace29c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -342,6 +342,110 @@ ieee80211_determine_ap_chan(struct ieee80211_sub_if_data *sdata,
return IEEE80211_CONN_MODE_EHT;
}
+static bool
+ieee80211_verify_sta_ht_mcs_support(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_supported_band *sband,
+ const struct ieee80211_ht_operation *ht_op)
+{
+ struct ieee80211_sta_ht_cap sta_ht_cap;
+ int i;
+
+ if (sband->band == NL80211_BAND_6GHZ)
+ return true;
+
+ if (!ht_op)
+ return false;
+
+ memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+ ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
+ /*
+ * P802.11REVme/D7.0 - 6.5.4.2.4
+ * ...
+ * If the MLME of an HT STA receives an MLME-JOIN.request primitive
+ * with the SelectedBSS parameter containing a Basic HT-MCS Set field
+ * in the HT Operation parameter that contains any unsupported MCSs,
+ * the MLME response in the resulting MLME-JOIN.confirm primitive shall
+ * contain a ResultCode parameter that is not set to the value SUCCESS.
+ * ...
+ */
+
+ /* Simply check that all basic rates are in the STA RX mask */
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ if ((ht_op->basic_set[i] & sta_ht_cap.mcs.rx_mask[i]) !=
+ ht_op->basic_set[i])
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+ieee80211_verify_sta_vht_mcs_support(struct ieee80211_sub_if_data *sdata,
+ int link_id,
+ struct ieee80211_supported_band *sband,
+ const struct ieee80211_vht_operation *vht_op)
+{
+ struct ieee80211_sta_vht_cap sta_vht_cap;
+ u16 ap_min_req_set, sta_rx_mcs_map, sta_tx_mcs_map;
+ int nss;
+
+ if (sband->band != NL80211_BAND_5GHZ)
+ return true;
+
+ if (!vht_op)
+ return false;
+
+ memcpy(&sta_vht_cap, &sband->vht_cap, sizeof(sta_vht_cap));
+ ieee80211_apply_vhtcap_overrides(sdata, &sta_vht_cap);
+
+ ap_min_req_set = le16_to_cpu(vht_op->basic_mcs_set);
+ sta_rx_mcs_map = le16_to_cpu(sta_vht_cap.vht_mcs.rx_mcs_map);
+ sta_tx_mcs_map = le16_to_cpu(sta_vht_cap.vht_mcs.tx_mcs_map);
+
+ /*
+ * Many APs are incorrectly advertising an all-zero value here,
+ * which really means MCS 0-7 are required for 1-8 streams, but
+ * they don't really mean it that way. Ignore that.
+ */
+ if (!ap_min_req_set)
+ return true;
+
+ /*
+ * P802.11REVme/D7.0 - 6.5.4.2.4
+ * ...
+ * If the MLME of a VHT STA receives an MLME-JOIN.request primitive
+ * with a SelectedBSS parameter containing a Basic VHT-MCS And NSS Set
+ * field in the VHT Operation parameter that contains any unsupported
+ * <VHT-MCS, NSS> tuple, the MLME response in the resulting
+ * MLME-JOIN.confirm primitive shall contain a ResultCode parameter
+ * that is not set to the value SUCCESS.
+ * ...
+ */
+ for (nss = 8; nss > 0; nss--) {
+ u8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
+ u8 sta_rx_val;
+ u8 sta_tx_val;
+
+ if (ap_op_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
+ continue;
+
+ sta_rx_val = (sta_rx_mcs_map >> (2 * (nss - 1))) & 3;
+ sta_tx_val = (sta_tx_mcs_map >> (2 * (nss - 1))) & 3;
+
+ if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
+ sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
+ sta_rx_val < ap_op_val || sta_tx_val < ap_op_val) {
+ link_id_info(sdata, link_id,
+ "Missing mandatory rates for %d Nss, rx %d, tx %d oper %d, disable VHT\n",
+ nss, sta_rx_val, sta_tx_val, ap_op_val);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool
ieee80211_verify_peer_he_mcs_support(struct ieee80211_sub_if_data *sdata,
int link_id,
@@ -946,6 +1050,26 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
link_id_info(sdata, link_id,
"regulatory prevented using AP config, downgraded\n");
+ if (conn->mode >= IEEE80211_CONN_MODE_HT &&
+ !ieee80211_verify_sta_ht_mcs_support(sdata, sband,
+ elems->ht_operation)) {
+ conn->mode = IEEE80211_CONN_MODE_LEGACY;
+ conn->bw_limit = IEEE80211_CONN_BW_LIMIT_20;
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling HT\n");
+ }
+
+ if (conn->mode >= IEEE80211_CONN_MODE_VHT &&
+ !ieee80211_verify_sta_vht_mcs_support(sdata, link_id, sband,
+ elems->vht_operation)) {
+ conn->mode = IEEE80211_CONN_MODE_HT;
+ conn->bw_limit = min_t(enum ieee80211_conn_bw_limit,
+ conn->bw_limit,
+ IEEE80211_CONN_BW_LIMIT_40);
+ link_id_info(sdata, link_id,
+ "required MCSes not supported, disabling VHT\n");
+ }
+
if (conn->mode >= IEEE80211_CONN_MODE_HE &&
(!ieee80211_verify_peer_he_mcs_support(sdata, link_id,
(void *)elems->he_cap,
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH 12/19] wifi: mac80211: add HT and VHT basic set verification
2025-01-01 5:05 ` [PATCH 12/19] wifi: mac80211: add HT and VHT basic set verification Miri Korenblit
@ 2025-01-13 9:51 ` Johannes Berg
0 siblings, 0 replies; 24+ messages in thread
From: Johannes Berg @ 2025-01-13 9:51 UTC (permalink / raw)
To: Miri Korenblit; +Cc: linux-wireless, Benjamin Berg
On Wed, 2025-01-01 at 07:05 +0200, Miri Korenblit wrote:
> From: Benjamin Berg <benjamin.berg@intel.com>
>
> So far we did not verify the HT and VHT basic MCS set. However, in
> P802.11REVme/D7.0 (6.5.4.2.4) says that the MLME-JOIN.request shall
> return an error if the VHT and HT basic set requirements are not met.
>
> Also extend the tests a bit, and for that change the test sdata
> registration to only have four spatial streams.
>
While theoretically correct, this is still broken with many APs, so I'm
dropping it.
johannes
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 13/19] wifi: mac80211: skip all known membership selectors
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (11 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 12/19] wifi: mac80211: add HT and VHT basic set verification Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 14/19] wifi: mac80211: parse BSS selectors and unknown rates Miri Korenblit
` (5 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
The GLK and EPD Selectors are also not rates, so add a new macro for the
minimum value of a selector and test against that instead of the entire
list. Also fix the typo in the EPD selector define.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/linux/ieee80211.h | 4 +++-
net/mac80211/mlme.c | 9 ++-------
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 9c0e2617fe8f..745c3b125d97 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1542,11 +1542,13 @@ struct ieee80211_mgmt {
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_GLK 125
-#define BSS_MEMBERSHIP_SELECTOR_EPS 124
+#define BSS_MEMBERSHIP_SELECTOR_EPD 124
#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E 123
#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
#define BSS_MEMBERSHIP_SELECTOR_EHT_PHY 121
+#define BSS_MEMBERSHIP_SELECTOR_MIN BSS_MEMBERSHIP_SELECTOR_EHT_PHY
+
/* mgmt header + 1 byte category code */
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 061d20ace29c..cc9bf79d631f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4745,18 +4745,13 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*have_higher_than_11mbit = true;
/*
- * Skip HT, VHT, HE, EHT and SAE H2E only BSS membership
- * selectors since they're not rates.
+ * Skip membership selectors since they're not rates.
*
* Note: Even though the membership selector and the basic
* rate flag share the same bit, they are not exactly
* the same.
*/
- if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
- supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) ||
- supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY) ||
- supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY) ||
- supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E))
+ if (supp_rates[i] >= (0x80 | BSS_MEMBERSHIP_SELECTOR_MIN))
continue;
for (j = 0; j < sband->n_bitrates; j++) {
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 14/19] wifi: mac80211: parse BSS selectors and unknown rates
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (12 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 13/19] wifi: mac80211: skip all known membership selectors Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 15/19] wifi: nl80211: permit userspace to pass supported selectors Miri Korenblit
` (4 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
Doing so enables further checking whether we are implementing the
requested features. Also allow passing in NULL for more parameters as
they may not be needed by the caller.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mlme.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cc9bf79d631f..a1197ac68c98 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4732,6 +4732,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
u8 *supp_rates, unsigned int supp_rates_len,
u32 *rates, u32 *basic_rates,
+ unsigned long *unknown_rates_selectors,
bool *have_higher_than_11mbit,
int *min_rate, int *min_rate_index)
{
@@ -4741,7 +4742,7 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
int rate = supp_rates[i] & 0x7f;
bool is_basic = !!(supp_rates[i] & 0x80);
- if ((rate * 5) > 110)
+ if ((rate * 5) > 110 && have_higher_than_11mbit)
*have_higher_than_11mbit = true;
/*
@@ -4751,8 +4752,11 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
* rate flag share the same bit, they are not exactly
* the same.
*/
- if (supp_rates[i] >= (0x80 | BSS_MEMBERSHIP_SELECTOR_MIN))
+ if (is_basic && rate >= BSS_MEMBERSHIP_SELECTOR_MIN) {
+ if (unknown_rates_selectors)
+ set_bit(rate, unknown_rates_selectors);
continue;
+ }
for (j = 0; j < sband->n_bitrates; j++) {
struct ieee80211_rate *br;
@@ -4762,16 +4766,22 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
brate = DIV_ROUND_UP(br->bitrate, 5);
if (brate == rate) {
- *rates |= BIT(j);
- if (is_basic)
+ if (rates)
+ *rates |= BIT(j);
+ if (is_basic && basic_rates)
*basic_rates |= BIT(j);
- if ((rate * 5) < *min_rate) {
+ if (min_rate && (rate * 5) < *min_rate) {
*min_rate = rate * 5;
- *min_rate_index = j;
+ if (min_rate_index)
+ *min_rate_index = j;
}
break;
}
}
+
+ /* Handle an unknown entry as if it is an unknown selector */
+ if (is_basic && unknown_rates_selectors && j == sband->n_bitrates)
+ set_bit(rate, unknown_rates_selectors);
}
}
@@ -5246,7 +5256,8 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link,
sband = local->hw.wiphy->bands[cbss->channel->band];
ieee80211_get_rates(sband, bss->supp_rates, bss->supp_rates_len,
- &rates, &basic_rates, &have_higher_than_11mbit,
+ &rates, &basic_rates, NULL,
+ &have_higher_than_11mbit,
&min_rate, &min_rate_index);
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 15/19] wifi: nl80211: permit userspace to pass supported selectors
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (13 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 14/19] wifi: mac80211: parse BSS selectors and unknown rates Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 16/19] wifi: mac80211: verify BSS membership selectors and basic rates Miri Korenblit
` (3 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
Currently the SAE_H2E selector already exists, which needs to be
implemented by the SME. As new such selectors might be added in the
future, add a feature to permit userspace to report a selector as
supported.
If not given, the kernel should assume that userspace does support
SAE_H2E.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
include/net/cfg80211.h | 12 ++++++++++++
include/uapi/linux/nl80211.h | 9 +++++++++
net/wireless/nl80211.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 53 insertions(+)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7790af534b7f..8a38d66be2c9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3023,6 +3023,10 @@ static inline const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 id)
*
* @bss: The BSS to authenticate with, the callee must obtain a reference
* to it if it needs to keep it.
+ * @supported_selectors: List of selectors that should be assumed to be
+ * supported by the station.
+ * SAE_H2E must be assumed supported if set to %NULL.
+ * @supported_selectors_len: Length of supported_selectors in octets.
* @auth_type: Authentication type (algorithm)
* @ie: Extra IEs to add to Authentication frame or %NULL
* @ie_len: Length of ie buffer in octets
@@ -3045,6 +3049,8 @@ struct cfg80211_auth_request {
struct cfg80211_bss *bss;
const u8 *ie;
size_t ie_len;
+ const u8 *supported_selectors;
+ u8 supported_selectors_len;
enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len;
@@ -3124,6 +3130,10 @@ enum cfg80211_assoc_req_flags {
* included in the Current AP address field of the Reassociation Request
* frame.
* @flags: See &enum cfg80211_assoc_req_flags
+ * @supported_selectors: supported selectors in IEEE 802.11 format
+ * (or %NULL for no change).
+ * If %NULL, then support for SAE_H2E should be assumed.
+ * @supported_selectors_len: Length of supported_selectors in octets.
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
* will be used in ht_capa. Un-supported values will be ignored.
* @ht_capa_mask: The bits of ht_capa which are to be used.
@@ -3150,6 +3160,8 @@ struct cfg80211_assoc_request {
struct cfg80211_crypto_settings crypto;
bool use_mfp;
u32 flags;
+ const u8 *supported_selectors;
+ u8 supported_selectors_len;
struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask;
struct ieee80211_vht_cap vht_capa, vht_capa_mask;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6d11437596b9..ee1cf19803ea 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2871,6 +2871,12 @@ enum nl80211_commands {
* @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32).
* A value of 0 means all radios.
*
+ * @NL80211_ATTR_SUPPORTED_SELECTORS: supported selectors, array of
+ * supported selectors as defined by IEEE 802.11 7.3.2.2 but without the
+ * length restriction (at most %NL80211_MAX_SUPP_SELECTORS).
+ * This can be used to provide a list of selectors that are implemented
+ * by the supplicant. If not given, support for SAE_H2E is assumed.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3421,6 +3427,8 @@ enum nl80211_attrs {
NL80211_ATTR_VIF_RADIO_MASK,
+ NL80211_ATTR_SUPPORTED_SELECTORS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3465,6 +3473,7 @@ enum nl80211_attrs {
#define NL80211_WIPHY_NAME_MAXLEN 64
#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_SELECTORS 128
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 128
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8789d8b73f0f..39c114265db8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -294,6 +294,21 @@ static int validate_he_capa(const struct nlattr *attr,
return 0;
}
+static int validate_supported_selectors(const struct nlattr *attr,
+ struct netlink_ext_ack *extack)
+{
+ const u8 *supported_selectors = nla_data(attr);
+ u8 supported_selectors_len = nla_len(attr);
+
+ /* The top bit must not be set as it is not part of the selector */
+ for (int i = 0; i < supported_selectors_len; i++) {
+ if (supported_selectors[i] & 0x80)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* policy for the attributes */
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
@@ -830,6 +845,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
[NL80211_ATTR_VIF_RADIO_MASK] = { .type = NLA_U32 },
+ [NL80211_ATTR_SUPPORTED_SELECTORS] =
+ NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_supported_selectors,
+ NL80211_MAX_SUPP_SELECTORS),
};
/* policy for the key attributes */
@@ -10858,6 +10876,13 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
+ if (info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]) {
+ req.supported_selectors =
+ nla_data(info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]);
+ req.supported_selectors_len =
+ nla_len(info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]);
+ }
+
auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL;
@@ -11140,6 +11165,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_PREV_BSSID])
req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+ if (info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]) {
+ req.supported_selectors =
+ nla_data(info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]);
+ req.supported_selectors_len =
+ nla_len(info->attrs[NL80211_ATTR_SUPPORTED_SELECTORS]);
+ }
+
if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
req.flags |= ASSOC_REQ_DISABLE_HT;
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 16/19] wifi: mac80211: verify BSS membership selectors and basic rates
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (14 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 15/19] wifi: nl80211: permit userspace to pass supported selectors Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES Miri Korenblit
` (2 subsequent siblings)
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
We should not attempt a connection if the BSS we are connecting to
requires support for a basic rate or other feature using the BSS
membership selector. Add a check verifying this.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/ieee80211_i.h | 4 +
net/mac80211/mlme.c | 193 ++++++++++++++++++++++++-------------
2 files changed, 132 insertions(+), 65 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a98133d5c362..8081607ccbd3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -404,6 +404,8 @@ struct ieee80211_mgd_auth_data {
int tries;
u16 algorithm, expected_transaction;
+ unsigned long userspace_selectors[BITS_TO_LONGS(128)];
+
u8 key[WLAN_KEY_LEN_WEP104];
u8 key_len, key_idx;
bool done, waiting;
@@ -444,6 +446,8 @@ struct ieee80211_mgd_assoc_data {
const u8 *supp_rates;
u8 supp_rates_len;
+ unsigned long userspace_selectors[BITS_TO_LONGS(128)];
+
unsigned long timeout;
int tries;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a1197ac68c98..9735ce4adffe 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -694,6 +694,63 @@ ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata,
return true;
}
+static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
+ const u8 *supp_rates,
+ unsigned int supp_rates_len,
+ u32 *rates, u32 *basic_rates,
+ unsigned long *unknown_rates_selectors,
+ bool *have_higher_than_11mbit,
+ int *min_rate, int *min_rate_index)
+{
+ int i, j;
+
+ for (i = 0; i < supp_rates_len; i++) {
+ int rate = supp_rates[i] & 0x7f;
+ bool is_basic = !!(supp_rates[i] & 0x80);
+
+ if ((rate * 5) > 110 && have_higher_than_11mbit)
+ *have_higher_than_11mbit = true;
+
+ /*
+ * Skip membership selectors since they're not rates.
+ *
+ * Note: Even though the membership selector and the basic
+ * rate flag share the same bit, they are not exactly
+ * the same.
+ */
+ if (is_basic && rate >= BSS_MEMBERSHIP_SELECTOR_MIN) {
+ if (unknown_rates_selectors)
+ set_bit(rate, unknown_rates_selectors);
+ continue;
+ }
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ struct ieee80211_rate *br;
+ int brate;
+
+ br = &sband->bitrates[j];
+
+ brate = DIV_ROUND_UP(br->bitrate, 5);
+ if (brate == rate) {
+ if (rates)
+ *rates |= BIT(j);
+ if (is_basic && basic_rates)
+ *basic_rates |= BIT(j);
+ if (min_rate && (rate * 5) < *min_rate) {
+ *min_rate = rate * 5;
+ if (min_rate_index)
+ *min_rate_index = j;
+ }
+ break;
+ }
+ }
+
+ /* Handle an unknown entry as if it is an unknown selector */
+ if (is_basic && unknown_rates_selectors && j == sband->n_bitrates)
+ set_bit(rate, unknown_rates_selectors);
+ }
+}
+
static bool ieee80211_chandef_usable(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
u32 prohibited_flags)
@@ -924,7 +981,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
struct ieee80211_conn_settings *conn,
struct cfg80211_bss *cbss, int link_id,
struct ieee80211_chan_req *chanreq,
- struct cfg80211_chan_def *ap_chandef)
+ struct cfg80211_chan_def *ap_chandef,
+ unsigned long *userspace_selectors)
{
const struct cfg80211_bss_ies *ies = rcu_dereference(cbss->ies);
struct ieee80211_bss *bss = (void *)cbss->priv;
@@ -938,6 +996,8 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems;
struct ieee80211_supported_band *sband;
enum ieee80211_conn_mode ap_mode;
+ unsigned long unknown_rates_selectors[BITS_TO_LONGS(128)] = {};
+ unsigned long sta_selectors[BITS_TO_LONGS(128)] = {};
int ret;
again:
@@ -966,6 +1026,10 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
sband = sdata->local->hw.wiphy->bands[channel->band];
+ ieee80211_get_rates(sband, elems->supp_rates, elems->supp_rates_len,
+ NULL, NULL, unknown_rates_selectors, NULL, NULL,
+ NULL);
+
switch (channel->band) {
case NL80211_BAND_S1GHZ:
if (WARN_ON(ap_mode != IEEE80211_CONN_MODE_S1G)) {
@@ -1016,6 +1080,29 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
chanreq->oper = *ap_chandef;
+ bitmap_copy(sta_selectors, userspace_selectors, 128);
+ if (conn->mode >= IEEE80211_CONN_MODE_HT)
+ set_bit(BSS_MEMBERSHIP_SELECTOR_HT_PHY, sta_selectors);
+ if (conn->mode >= IEEE80211_CONN_MODE_VHT)
+ set_bit(BSS_MEMBERSHIP_SELECTOR_VHT_PHY, sta_selectors);
+ if (conn->mode >= IEEE80211_CONN_MODE_HE)
+ set_bit(BSS_MEMBERSHIP_SELECTOR_HE_PHY, sta_selectors);
+ if (conn->mode >= IEEE80211_CONN_MODE_EHT)
+ set_bit(BSS_MEMBERSHIP_SELECTOR_EHT_PHY, sta_selectors);
+
+ /*
+ * We do not support EPD or GLK so never add them.
+ * SAE_H2E is handled through userspace_selectors.
+ */
+
+ /* Check if we support all required features */
+ if (!bitmap_subset(unknown_rates_selectors, sta_selectors, 128)) {
+ link_id_info(sdata, link_id,
+ "required basic rate or BSS membership selectors not supported or disabled, rejecting connection\n");
+ ret = -EINVAL;
+ goto free;
+ }
+
ieee80211_set_chanreq_ap(sdata, chanreq, conn, ap_chandef);
while (!ieee80211_chandef_usable(sdata, &chanreq->oper,
@@ -4729,62 +4816,6 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
false);
}
-static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
- u8 *supp_rates, unsigned int supp_rates_len,
- u32 *rates, u32 *basic_rates,
- unsigned long *unknown_rates_selectors,
- bool *have_higher_than_11mbit,
- int *min_rate, int *min_rate_index)
-{
- int i, j;
-
- for (i = 0; i < supp_rates_len; i++) {
- int rate = supp_rates[i] & 0x7f;
- bool is_basic = !!(supp_rates[i] & 0x80);
-
- if ((rate * 5) > 110 && have_higher_than_11mbit)
- *have_higher_than_11mbit = true;
-
- /*
- * Skip membership selectors since they're not rates.
- *
- * Note: Even though the membership selector and the basic
- * rate flag share the same bit, they are not exactly
- * the same.
- */
- if (is_basic && rate >= BSS_MEMBERSHIP_SELECTOR_MIN) {
- if (unknown_rates_selectors)
- set_bit(rate, unknown_rates_selectors);
- continue;
- }
-
- for (j = 0; j < sband->n_bitrates; j++) {
- struct ieee80211_rate *br;
- int brate;
-
- br = &sband->bitrates[j];
-
- brate = DIV_ROUND_UP(br->bitrate, 5);
- if (brate == rate) {
- if (rates)
- *rates |= BIT(j);
- if (is_basic && basic_rates)
- *basic_rates |= BIT(j);
- if (min_rate && (rate * 5) < *min_rate) {
- *min_rate = rate * 5;
- if (min_rate_index)
- *min_rate_index = j;
- }
- break;
- }
- }
-
- /* Handle an unknown entry as if it is an unknown selector */
- if (is_basic && unknown_rates_selectors && j == sband->n_bitrates)
- set_bit(rate, unknown_rates_selectors);
- }
-}
-
static bool ieee80211_twt_req_supported(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
const struct link_sta_info *link_sta,
@@ -5650,7 +5681,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
int link_id,
struct cfg80211_bss *cbss, bool mlo,
- struct ieee80211_conn_settings *conn)
+ struct ieee80211_conn_settings *conn,
+ unsigned long *userspace_selectors)
{
struct ieee80211_local *local = sdata->local;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
@@ -5663,7 +5695,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
elems = ieee80211_determine_chan_mode(sdata, conn, cbss, link_id,
- &chanreq, &ap_chandef);
+ &chanreq, &ap_chandef,
+ userspace_selectors);
if (IS_ERR(elems)) {
rcu_read_unlock();
@@ -5857,7 +5890,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
link->u.mgd.conn = assoc_data->link[link_id].conn;
err = ieee80211_prep_channel(sdata, link, link_id, cbss,
- true, &link->u.mgd.conn);
+ true, &link->u.mgd.conn,
+ assoc_data->userspace_selectors);
if (err) {
link_info(link, "prep_channel failed\n");
goto out_err;
@@ -8367,7 +8401,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss, s8 link_id,
const u8 *ap_mld_addr, bool assoc,
struct ieee80211_conn_settings *conn,
- bool override)
+ bool override,
+ unsigned long *userspace_selectors)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -8506,7 +8541,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
*/
link->u.mgd.conn = *conn;
err = ieee80211_prep_channel(sdata, link, link->link_id, cbss,
- mlo, &link->u.mgd.conn);
+ mlo, &link->u.mgd.conn,
+ userspace_selectors);
if (err) {
if (new_sta)
sta_info_free(local, new_sta);
@@ -8622,6 +8658,22 @@ static bool ieee80211_mgd_csa_in_process(struct ieee80211_sub_if_data *sdata,
return ret;
}
+static void ieee80211_parse_cfg_selectors(unsigned long *userspace_selectors,
+ const u8 *supported_selectors,
+ u8 supported_selectors_len)
+{
+ if (supported_selectors) {
+ for (int i = 0; i < supported_selectors_len; i++) {
+ set_bit(supported_selectors[i],
+ userspace_selectors);
+ }
+ } else {
+ /* Assume SAE_H2E support for backward compatibility. */
+ set_bit(BSS_MEMBERSHIP_SELECTOR_SAE_H2E,
+ userspace_selectors);
+ }
+}
+
/* config hooks */
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
struct cfg80211_auth_request *req)
@@ -8723,6 +8775,10 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
memcpy(auth_data->key, req->key, req->key_len);
}
+ ieee80211_parse_cfg_selectors(auth_data->userspace_selectors,
+ req->supported_selectors,
+ req->supported_selectors_len);
+
auth_data->algorithm = auth_alg;
/* try to authenticate/probe */
@@ -8776,7 +8832,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
err = ieee80211_prep_connection(sdata, req->bss, req->link_id,
req->ap_mld_addr, cont_auth,
- &conn, false);
+ &conn, false,
+ auth_data->userspace_selectors);
if (err)
goto err_clear;
@@ -9063,6 +9120,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
false);
}
+ ieee80211_parse_cfg_selectors(assoc_data->userspace_selectors,
+ req->supported_selectors,
+ req->supported_selectors_len);
+
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
sizeof(ifmgd->ht_capa_mask));
@@ -9309,7 +9370,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
/* only calculate the mode, hence link == NULL */
err = ieee80211_prep_channel(sdata, NULL, i,
assoc_data->link[i].bss, true,
- &assoc_data->link[i].conn);
+ &assoc_data->link[i].conn,
+ assoc_data->userspace_selectors);
if (err) {
req->links[i].error = err;
goto err_clear;
@@ -9325,7 +9387,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
err = ieee80211_prep_connection(sdata, cbss, req->link_id,
req->ap_mld_addr, true,
&assoc_data->link[assoc_link_id].conn,
- override);
+ override,
+ assoc_data->userspace_selectors);
if (err)
goto err_clear;
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (15 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 16/19] wifi: mac80211: verify BSS membership selectors and basic rates Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-08 7:55 ` kernel test robot
2025-01-01 5:05 ` [PATCH 18/19] wifi: mac80211: tests: add utility to create sdata skeleton Miri Korenblit
2025-01-01 5:05 ` [PATCH 19/19] wifi: mac80211: tests: add tests for ieee80211_determine_chan_mode Miri Korenblit
18 siblings, 1 reply; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
Parse both the Supported Rates and BSS Membership Selectors as well as
the extended version of the tag when verifying whether we support all
features.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/mlme.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9735ce4adffe..d2ce5264923e 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -697,6 +697,8 @@ ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata,
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
const u8 *supp_rates,
unsigned int supp_rates_len,
+ const u8 *ext_supp_rates,
+ unsigned int ext_supp_rates_len,
u32 *rates, u32 *basic_rates,
unsigned long *unknown_rates_selectors,
bool *have_higher_than_11mbit,
@@ -704,9 +706,12 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
{
int i, j;
- for (i = 0; i < supp_rates_len; i++) {
- int rate = supp_rates[i] & 0x7f;
- bool is_basic = !!(supp_rates[i] & 0x80);
+ for (i = 0; i < supp_rates_len + ext_supp_rates_len; i++) {
+ u8 supp_rate = i < supp_rates_len ?
+ supp_rates[i] :
+ ext_supp_rates[i - supp_rates_len];
+ int rate = supp_rate & 0x7f;
+ bool is_basic = !!(supp_rate & 0x80);
if ((rate * 5) > 110 && have_higher_than_11mbit)
*have_higher_than_11mbit = true;
@@ -1027,6 +1032,7 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
sband = sdata->local->hw.wiphy->bands[channel->band];
ieee80211_get_rates(sband, elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len,
NULL, NULL, unknown_rates_selectors, NULL, NULL,
NULL);
@@ -5287,6 +5293,7 @@ static int ieee80211_mgd_setup_link_sta(struct ieee80211_link_data *link,
sband = local->hw.wiphy->bands[cbss->channel->band];
ieee80211_get_rates(sband, bss->supp_rates, bss->supp_rates_len,
+ NULL, 0,
&rates, &basic_rates, NULL,
&have_higher_than_11mbit,
&min_rate, &min_rate_index);
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES
2025-01-01 5:05 ` [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES Miri Korenblit
@ 2025-01-08 7:55 ` kernel test robot
2025-01-08 9:17 ` Benjamin Berg
0 siblings, 1 reply; 24+ messages in thread
From: kernel test robot @ 2025-01-08 7:55 UTC (permalink / raw)
To: Miri Korenblit
Cc: oe-lkp, lkp, Johannes Berg, Miri Korenblit, linux-wireless,
johannes, Benjamin Berg, oliver.sang
Hello,
kernel test robot noticed "hwsim.owe_assoc_reject.fail" on:
commit: 1539283361bfb9c62eb3486ded2c4d38e5858510 ("[PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES")
url: https://github.com/intel-lab-lkp/linux/commits/Miri-Korenblit/wifi-mac80211-add-some-support-for-RX-OMI-power-saving/20250101-131018
base: https://git.kernel.org/cgit/linux/kernel/git/wireless/wireless-next.git main
patch link: https://lore.kernel.org/all/20250101070249.f1840f19afa7.I12e3a0e634ce7014f5067256d9a6215fec6bf165@changeid/
patch subject: [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES
in testcase: hwsim
version: hwsim-x86_64-4ea2c336d-1_20241103
with following parameters:
test: owe_assoc_reject
config: x86_64-rhel-9.4-func
compiler: gcc-12
test machine: 8 threads 1 sockets Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz (Haswell) with 8G memory
(please refer to attached dmesg/kmsg for entire log/backtrace)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202501081559.1c188f65-lkp@intel.com
group: group-00, test: owe_assoc_reject
2025-01-04 14:31:54 export USER=root
2025-01-04 14:31:54 ./build.sh
Building TNC testing tools
Building wlantest
Building hs20-osu-client
Building hostapd
Building wpa_supplicant
2025-01-04 14:32:44 ./start.sh
2025-01-04 14:32:45 ./run-tests.py owe_assoc_reject
DEV: wlan0: 02:00:00:00:00:00
DEV: wlan1: 02:00:00:00:01:00
DEV: wlan2: 02:00:00:00:02:00
APDEV: wlan3
APDEV: wlan4
START owe_assoc_reject 1/1
Test: Opportunistic Wireless Encryption association rejection handling
Starting AP wlan3
Connect STA wlan0 to AP
Association result not reported
Traceback (most recent call last):
File "/lkp/benchmarks/hwsim/tests/hwsim/./run-tests.py", line 591, in main
t(dev, apdev)
File "/lkp/benchmarks/hwsim/tests/hwsim/test_owe.py", line 766, in test_owe_assoc_reject
raise Exception("Association result not reported")
Exception: Association result not reported
FAIL owe_assoc_reject 13.055277 2025-01-04 14:32:59.681039
passed 0 test case(s)
skipped 0 test case(s)
failed tests: owe_assoc_reject
2025-01-04 14:32:59 ./stop.sh
The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20250108/202501081559.1c188f65-lkp@intel.com
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES
2025-01-08 7:55 ` kernel test robot
@ 2025-01-08 9:17 ` Benjamin Berg
2025-01-09 2:28 ` Oliver Sang
0 siblings, 1 reply; 24+ messages in thread
From: Benjamin Berg @ 2025-01-08 9:17 UTC (permalink / raw)
To: kernel test robot, Miri Korenblit
Cc: oe-lkp, lkp, Johannes Berg, linux-wireless, johannes
Hi,
On Wed, 2025-01-08 at 15:55 +0800, kernel test robot wrote:
> Kernel test robot noticed "hwsim.owe_assoc_reject.fail" on:
>
> commit: 1539283361bfb9c62eb3486ded2c4d38e5858510 ("[PATCH 17/19]
> wifi: mac80211: also verify requirements in EXT_SUPP_RATES")
> url:
> https://github.com/intel-lab-lkp/linux/commits/Miri-Korenblit/wifi-mac80211-add-some-support-for-RX-OMI-power-saving/20250101-131018
> base:
> https://git.kernel.org/cgit/linux/kernel/git/wireless/wireless-next.git
> main
> patch link:
> https://lore.kernel.org/all/20250101070249.f1840f19afa7.I12e3a0e634ce7014f5067256d9a6215fec6bf165@changeid/
> patch subject: [PATCH 17/19] wifi: mac80211: also verify requirements
> in EXT_SUPP_RATES
>
> in testcase: hwsim
> version: hwsim-x86_64-4ea2c336d-1_20241103
> with following parameters:
>
> test: owe_assoc_reject
These failures happen because mac80211 has become more strict and the
hostap, including the hwsim tests, needs to be updated. The patchset to
update hostap is:
https://patchwork.ozlabs.org/project/hostap/list/?series=439300
Benjamin
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES
2025-01-08 9:17 ` Benjamin Berg
@ 2025-01-09 2:28 ` Oliver Sang
0 siblings, 0 replies; 24+ messages in thread
From: Oliver Sang @ 2025-01-09 2:28 UTC (permalink / raw)
To: Benjamin Berg
Cc: Miri Korenblit, oe-lkp, lkp, Johannes Berg, linux-wireless,
johannes, oliver.sang
hi, Benjamin,
On Wed, Jan 08, 2025 at 10:17:55AM +0100, Benjamin Berg wrote:
> Hi,
>
> On Wed, 2025-01-08 at 15:55 +0800, kernel test robot wrote:
> > Kernel test robot noticed "hwsim.owe_assoc_reject.fail" on:
> >
> > commit: 1539283361bfb9c62eb3486ded2c4d38e5858510 ("[PATCH 17/19]
> > wifi: mac80211: also verify requirements in EXT_SUPP_RATES")
> > url:
> > https://github.com/intel-lab-lkp/linux/commits/Miri-Korenblit/wifi-mac80211-add-some-support-for-RX-OMI-power-saving/20250101-131018
> > base:
> > https://git.kernel.org/cgit/linux/kernel/git/wireless/wireless-next.git
> > main
> > patch link:
> > https://lore.kernel.org/all/20250101070249.f1840f19afa7.I12e3a0e634ce7014f5067256d9a6215fec6bf165@changeid/
> > patch subject: [PATCH 17/19] wifi: mac80211: also verify requirements
> > in EXT_SUPP_RATES
> >
> > in testcase: hwsim
> > version: hwsim-x86_64-4ea2c336d-1_20241103
> > with following parameters:
> >
> > test: owe_assoc_reject
>
> These failures happen because mac80211 has become more strict and the
> hostap, including the hwsim tests, needs to be updated. The patchset to
> update hostap is:
> https://patchwork.ozlabs.org/project/hostap/list/?series=439300
thanks a lot for information!
>
> Benjamin
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 18/19] wifi: mac80211: tests: add utility to create sdata skeleton
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (16 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 17/19] wifi: mac80211: also verify requirements in EXT_SUPP_RATES Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
2025-01-01 5:05 ` [PATCH 19/19] wifi: mac80211: tests: add tests for ieee80211_determine_chan_mode Miri Korenblit
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
Some functions that should be tested may expect an sdata object that is
configured to a basic degree. Add setup code to create such an object
for use by tests.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/tests/Makefile | 2 +-
net/mac80211/tests/util.c | 313 ++++++++++++++++++++++++++++++++++++
net/mac80211/tests/util.h | 36 +++++
3 files changed, 350 insertions(+), 1 deletion(-)
create mode 100644 net/mac80211/tests/util.c
create mode 100644 net/mac80211/tests/util.h
diff --git a/net/mac80211/tests/Makefile b/net/mac80211/tests/Makefile
index 511dfa226699..0f5336bc7314 100644
--- a/net/mac80211/tests/Makefile
+++ b/net/mac80211/tests/Makefile
@@ -1,3 +1,3 @@
-mac80211-tests-y += module.o elems.o mfp.o tpe.o
+mac80211-tests-y += module.o util.o elems.o mfp.o tpe.o
obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o
diff --git a/net/mac80211/tests/util.c b/net/mac80211/tests/util.c
new file mode 100644
index 000000000000..0936a73e3617
--- /dev/null
+++ b/net/mac80211/tests/util.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Utilities for mac80211 unit testing
+ *
+ * Copyright (C) 2024 Intel Corporation
+ */
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include <kunit/test.h>
+#include <kunit/test-bug.h>
+#include "util.h"
+
+#define CHAN2G(_freq) { \
+ .band = NL80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_freq), \
+}
+
+static const struct ieee80211_channel channels_2ghz[] = {
+ CHAN2G(2412), /* Channel 1 */
+ CHAN2G(2417), /* Channel 2 */
+ CHAN2G(2422), /* Channel 3 */
+ CHAN2G(2427), /* Channel 4 */
+ CHAN2G(2432), /* Channel 5 */
+ CHAN2G(2437), /* Channel 6 */
+ CHAN2G(2442), /* Channel 7 */
+ CHAN2G(2447), /* Channel 8 */
+ CHAN2G(2452), /* Channel 9 */
+ CHAN2G(2457), /* Channel 10 */
+ CHAN2G(2462), /* Channel 11 */
+ CHAN2G(2467), /* Channel 12 */
+ CHAN2G(2472), /* Channel 13 */
+ CHAN2G(2484), /* Channel 14 */
+};
+
+#define CHAN5G(_freq) { \
+ .band = NL80211_BAND_5GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_freq), \
+}
+
+static const struct ieee80211_channel channels_5ghz[] = {
+ CHAN5G(5180), /* Channel 36 */
+ CHAN5G(5200), /* Channel 40 */
+ CHAN5G(5220), /* Channel 44 */
+ CHAN5G(5240), /* Channel 48 */
+};
+
+static const struct ieee80211_rate bitrates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60 },
+ { .bitrate = 90 },
+ { .bitrate = 120 },
+ { .bitrate = 180 },
+ { .bitrate = 240 },
+ { .bitrate = 360 },
+ { .bitrate = 480 },
+ { .bitrate = 540 }
+};
+
+/* Copied from hwsim except that it only supports 4 EHT streams and STA/P2P mode */
+static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = {
+ {
+ .types_mask = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT),
+ .he_cap = {
+ .has_he = true,
+ .he_cap_elem = {
+ .mac_cap_info[0] =
+ IEEE80211_HE_MAC_CAP0_HTC_HE,
+ .mac_cap_info[1] =
+ IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
+ IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
+ .mac_cap_info[2] =
+ IEEE80211_HE_MAC_CAP2_BSR |
+ IEEE80211_HE_MAC_CAP2_MU_CASCADING |
+ IEEE80211_HE_MAC_CAP2_ACK_EN,
+ .mac_cap_info[3] =
+ IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
+ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3,
+ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
+ .phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G,
+ .phy_cap_info[1] =
+ IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
+ IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS,
+ .phy_cap_info[2] =
+ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
+ IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
+ IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
+ IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
+ IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO,
+
+ /* Leave all the other PHY capability bytes
+ * unset, as DCM, beam forming, RU and PPE
+ * threshold information are not supported
+ */
+ },
+ .he_mcs_nss_supp = {
+ .rx_mcs_80 = cpu_to_le16(0xfffa),
+ .tx_mcs_80 = cpu_to_le16(0xfffa),
+ .rx_mcs_160 = cpu_to_le16(0xfffa),
+ .tx_mcs_160 = cpu_to_le16(0xfffa),
+ .rx_mcs_80p80 = cpu_to_le16(0xfffa),
+ .tx_mcs_80p80 = cpu_to_le16(0xfffa),
+ },
+ },
+ .eht_cap = {
+ .has_eht = true,
+ .eht_cap_elem = {
+ .mac_cap_info[0] =
+ IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
+ IEEE80211_EHT_MAC_CAP0_OM_CONTROL |
+ IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1,
+ .phy_cap_info[0] =
+ IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ |
+ IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
+ IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE |
+ IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK,
+ .phy_cap_info[1] =
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK |
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK,
+ .phy_cap_info[2] =
+ IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK |
+ IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK,
+ .phy_cap_info[3] =
+ IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK |
+ IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK,
+ .phy_cap_info[4] =
+ IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO |
+ IEEE80211_EHT_PHY_CAP4_PSR_SR_SUPP |
+ IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP |
+ IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI |
+ IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK,
+ .phy_cap_info[5] =
+ IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK |
+ IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP |
+ IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP |
+ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT |
+ IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK |
+ IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK,
+ .phy_cap_info[6] =
+ IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK |
+ IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK,
+ .phy_cap_info[7] =
+ IEEE80211_EHT_PHY_CAP7_20MHZ_STA_RX_NDP_WIDER_BW |
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
+ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
+ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ,
+ },
+
+ /* For all MCS and bandwidth, set 4 NSS for both Tx and
+ * Rx
+ */
+ .eht_mcs_nss_supp = {
+ /*
+ * As B1 and B2 are set in the supported
+ * channel width set field in the HE PHY
+ * capabilities information field include all
+ * the following MCS/NSS.
+ */
+ .bw._80 = {
+ .rx_tx_mcs9_max_nss = 0x44,
+ .rx_tx_mcs11_max_nss = 0x44,
+ .rx_tx_mcs13_max_nss = 0x44,
+ },
+ .bw._160 = {
+ .rx_tx_mcs9_max_nss = 0x44,
+ .rx_tx_mcs11_max_nss = 0x44,
+ .rx_tx_mcs13_max_nss = 0x44,
+ },
+ },
+ /* PPE threshold information is not supported */
+ },
+ },
+};
+
+int t_sdata_init(struct kunit_resource *resource, void *ctx)
+{
+ struct kunit *test = kunit_get_current_test();
+ struct t_sdata *t_sdata;
+
+ t_sdata = kzalloc(sizeof(*t_sdata), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, t_sdata);
+
+ resource->data = t_sdata;
+ resource->name = "sdata";
+
+ t_sdata->sdata = kzalloc(sizeof(*t_sdata->sdata), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, t_sdata->sdata);
+
+ t_sdata->wiphy = kzalloc(sizeof(*t_sdata->wiphy), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, t_sdata->wiphy);
+
+ strscpy(t_sdata->sdata->name, "kunit");
+
+ t_sdata->sdata->local = &t_sdata->local;
+ t_sdata->sdata->local->hw.wiphy = t_sdata->wiphy;
+ t_sdata->sdata->wdev.wiphy = t_sdata->wiphy;
+ t_sdata->sdata->vif.type = NL80211_IFTYPE_STATION;
+
+ t_sdata->sdata->deflink.sdata = t_sdata->sdata;
+ t_sdata->sdata->deflink.link_id = 0;
+
+ t_sdata->wiphy->bands[NL80211_BAND_2GHZ] = &t_sdata->band_2ghz;
+ t_sdata->wiphy->bands[NL80211_BAND_5GHZ] = &t_sdata->band_5ghz;
+
+ for (int band = NL80211_BAND_2GHZ; band <= NL80211_BAND_5GHZ; band++) {
+ struct ieee80211_supported_band *sband;
+
+ 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:
+ sband->channels = kmemdup(channels_2ghz,
+ sizeof(channels_2ghz),
+ GFP_KERNEL);
+ sband->n_channels = ARRAY_SIZE(channels_2ghz);
+ sband->bitrates = kmemdup(bitrates,
+ sizeof(bitrates),
+ GFP_KERNEL);
+ sband->n_bitrates = ARRAY_SIZE(bitrates);
+ break;
+ case NL80211_BAND_5GHZ:
+ sband->channels = kmemdup(channels_5ghz,
+ sizeof(channels_5ghz),
+ GFP_KERNEL);
+ sband->n_channels = ARRAY_SIZE(channels_5ghz);
+ sband->bitrates = kmemdup(bitrates,
+ sizeof(bitrates),
+ GFP_KERNEL);
+ sband->n_bitrates = ARRAY_SIZE(bitrates);
+
+ sband->vht_cap.vht_supported = true;
+ sband->vht_cap.cap =
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+ IEEE80211_VHT_CAP_RXLDPC |
+ IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_TXSTBC |
+ IEEE80211_VHT_CAP_RXSTBC_4 |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ sband->vht_cap.vht_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
+ sband->vht_cap.vht_mcs.tx_mcs_map =
+ sband->vht_cap.vht_mcs.rx_mcs_map;
+ break;
+ default:
+ continue;
+ }
+
+ sband->ht_cap.ht_supported = band != NL80211_BAND_6GHZ;
+ sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_DSSSCCK40;
+ sband->ht_cap.ampdu_factor = 0x3;
+ sband->ht_cap.ampdu_density = 0x6;
+ memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
+ sband->ht_cap.mcs.rx_mask[0] = 0xff;
+ sband->ht_cap.mcs.rx_mask[1] = 0xff;
+ sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ }
+
+ ieee80211_set_sband_iftype_data(&t_sdata->band_5ghz, sband_capa_5ghz);
+
+ return 0;
+}
+
+void t_sdata_exit(struct kunit_resource *resource)
+{
+ struct t_sdata *t_sdata = resource->data;
+
+ kfree(t_sdata->band_2ghz.channels);
+ kfree(t_sdata->band_2ghz.bitrates);
+ kfree(t_sdata->band_5ghz.channels);
+ kfree(t_sdata->band_5ghz.bitrates);
+
+ kfree(t_sdata->sdata);
+ kfree(t_sdata->wiphy);
+
+ kfree(t_sdata);
+}
diff --git a/net/mac80211/tests/util.h b/net/mac80211/tests/util.h
new file mode 100644
index 000000000000..6615880c123f
--- /dev/null
+++ b/net/mac80211/tests/util.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Utilities for mac80211 unit testing
+ *
+ * Copyright (C) 2024 Intel Corporation
+ */
+#ifndef __MAC80211_UTILS_H
+#define __MAC80211_UTILS_H
+
+#include "../ieee80211_i.h"
+
+struct t_sdata {
+ struct ieee80211_sub_if_data *sdata;
+ struct wiphy *wiphy;
+ struct ieee80211_local local;
+
+ void *ctx;
+
+ struct ieee80211_supported_band band_2ghz;
+ struct ieee80211_supported_band band_5ghz;
+};
+
+#define T_SDATA(test) ({ \
+ struct t_sdata *__t_sdata = \
+ kunit_alloc_resource(test, t_sdata_init, \
+ t_sdata_exit, \
+ GFP_KERNEL, NULL); \
+ \
+ KUNIT_ASSERT_NOT_NULL(test, __t_sdata); \
+ __t_sdata; \
+ })
+
+int t_sdata_init(struct kunit_resource *resource, void *data);
+void t_sdata_exit(struct kunit_resource *resource);
+
+#endif /* __MAC80211_UTILS_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH 19/19] wifi: mac80211: tests: add tests for ieee80211_determine_chan_mode
2025-01-01 5:05 [PATCH 00/19] [RESEND] wifi: mac80211: updates - 30-12-24 Miri Korenblit
` (17 preceding siblings ...)
2025-01-01 5:05 ` [PATCH 18/19] wifi: mac80211: tests: add utility to create sdata skeleton Miri Korenblit
@ 2025-01-01 5:05 ` Miri Korenblit
18 siblings, 0 replies; 24+ messages in thread
From: Miri Korenblit @ 2025-01-01 5:05 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Benjamin Berg, Johannes Berg
From: Benjamin Berg <benjamin.berg@intel.com>
Add a few tests for ieee80211_determine_chan_mode that check that
mac80211 will not try to connect to an AP if an advertised basic rate is
not supported.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
net/mac80211/ieee80211_i.h | 7 +
net/mac80211/mlme.c | 3 +-
net/mac80211/tests/Makefile | 2 +-
net/mac80211/tests/chan-mode.c | 245 +++++++++++++++++++++++++++++++++
net/mac80211/tests/util.c | 6 +-
5 files changed, 256 insertions(+), 7 deletions(-)
create mode 100644 net/mac80211/tests/chan-mode.c
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8081607ccbd3..7b8a0da8eaff 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2780,6 +2780,13 @@ int ieee80211_calc_chandef_subchan_offset(const struct cfg80211_chan_def *ap,
void ieee80211_rearrange_tpe_psd(struct ieee80211_parsed_tpe_psd *psd,
const struct cfg80211_chan_def *ap,
const struct cfg80211_chan_def *used);
+struct ieee802_11_elems *
+ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_conn_settings *conn,
+ struct cfg80211_bss *cbss, int link_id,
+ struct ieee80211_chan_req *chanreq,
+ struct cfg80211_chan_def *ap_chandef,
+ unsigned long *userspace_selectors);
#else
#define EXPORT_SYMBOL_IF_MAC80211_KUNIT(sym)
#define VISIBLE_IF_MAC80211_KUNIT static
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d2ce5264923e..ad4a474585e0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -981,7 +981,7 @@ static void ieee80211_set_chanreq_ap(struct ieee80211_sub_if_data *sdata,
chanreq->ap = *ap_chandef;
}
-static struct ieee802_11_elems *
+VISIBLE_IF_MAC80211_KUNIT struct ieee802_11_elems *
ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
struct ieee80211_conn_settings *conn,
struct cfg80211_bss *cbss, int link_id,
@@ -1206,6 +1206,7 @@ ieee80211_determine_chan_mode(struct ieee80211_sub_if_data *sdata,
kfree(elems);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_IF_MAC80211_KUNIT(ieee80211_determine_chan_mode);
static int ieee80211_config_bw(struct ieee80211_link_data *link,
struct ieee802_11_elems *elems,
diff --git a/net/mac80211/tests/Makefile b/net/mac80211/tests/Makefile
index 0f5336bc7314..3b0c08356fc5 100644
--- a/net/mac80211/tests/Makefile
+++ b/net/mac80211/tests/Makefile
@@ -1,3 +1,3 @@
-mac80211-tests-y += module.o util.o elems.o mfp.o tpe.o
+mac80211-tests-y += module.o util.o elems.o mfp.o tpe.o chan-mode.o
obj-$(CONFIG_MAC80211_KUNIT_TEST) += mac80211-tests.o
diff --git a/net/mac80211/tests/chan-mode.c b/net/mac80211/tests/chan-mode.c
new file mode 100644
index 000000000000..6a9359d46472
--- /dev/null
+++ b/net/mac80211/tests/chan-mode.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for channel mode functions
+ *
+ * Copyright (C) 2024 Intel Corporation
+ */
+#include <net/cfg80211.h>
+#include <kunit/test.h>
+
+#include "util.h"
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+static const struct determine_chan_mode_case {
+ const char *desc;
+ u8 extra_supp_rate;
+ enum ieee80211_conn_mode conn_mode;
+ enum ieee80211_conn_mode expected_mode;
+ u8 userspace_selector;
+ struct ieee80211_ht_cap ht_capa_mask;
+ struct ieee80211_vht_cap vht_capa;
+ struct ieee80211_vht_cap vht_capa_mask;
+ u8 vht_basic_mcs_1_4_set:1,
+ vht_basic_mcs_5_8_set:1,
+ he_basic_mcs_1_4_set:1,
+ he_basic_mcs_5_8_set:1;
+ u8 vht_basic_mcs_1_4, vht_basic_mcs_5_8;
+ u8 he_basic_mcs_1_4, he_basic_mcs_5_8;
+ u8 eht_mcs7_min_nss;
+ int error;
+} determine_chan_mode_cases[] = {
+ {
+ .desc = "Normal case, EHT is working",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_EHT,
+ }, {
+ .desc = "Requiring EHT support is fine",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_EHT,
+ .extra_supp_rate = 0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY,
+ }, {
+ .desc = "Lowering the mode limits us",
+ .conn_mode = IEEE80211_CONN_MODE_VHT,
+ .expected_mode = IEEE80211_CONN_MODE_VHT,
+ }, {
+ .desc = "Requesting a basic rate/selector that we do not support",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .extra_supp_rate = 0x80 | (BSS_MEMBERSHIP_SELECTOR_MIN - 1),
+ .error = EINVAL,
+ }, {
+ .desc = "As before, but userspace says it is taking care of it",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .userspace_selector = BSS_MEMBERSHIP_SELECTOR_MIN - 1,
+ .extra_supp_rate = 0x80 | (BSS_MEMBERSHIP_SELECTOR_MIN - 1),
+ .expected_mode = IEEE80211_CONN_MODE_EHT,
+ }, {
+ .desc = "Masking out a supported rate in HT capabilities",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_LEGACY,
+ .ht_capa_mask = {
+ .mcs.rx_mask[0] = 0xf7,
+ },
+ }, {
+ .desc = "Masking out a RX rate in VHT capabilities",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_HT,
+ /* Only one RX stream at MCS 0-7 */
+ .vht_capa = {
+ .supp_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_7),
+ },
+ .vht_capa_mask = {
+ .supp_mcs.rx_mcs_map = cpu_to_le16(0xffff),
+ },
+ }, {
+ .desc = "Masking out a TX rate in VHT capabilities",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_HT,
+ /* Only one TX stream at MCS 0-7 */
+ .vht_capa = {
+ .supp_mcs.tx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_7),
+ },
+ .vht_capa_mask = {
+ .supp_mcs.tx_mcs_map = cpu_to_le16(0xffff),
+ },
+ }, {
+ .desc = "AP has higher VHT requirement than client",
+ .conn_mode = IEEE80211_CONN_MODE_VHT,
+ .expected_mode = IEEE80211_CONN_MODE_HT,
+ .vht_basic_mcs_5_8_set = 1,
+ .vht_basic_mcs_5_8 = 0xFE, /* require 5th stream */
+ }, {
+ .desc = "all zero VHT basic rates are ignored (many APs broken)",
+ .conn_mode = IEEE80211_CONN_MODE_VHT,
+ .expected_mode = IEEE80211_CONN_MODE_VHT,
+ .vht_basic_mcs_1_4_set = 1,
+ .vht_basic_mcs_5_8_set = 1,
+ }, {
+ .desc = "AP requires 3 HE streams but client only has two",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_VHT,
+ .he_basic_mcs_1_4 = 0b11001010,
+ .he_basic_mcs_1_4_set = 1,
+ }, {
+ .desc = "all zero HE basic rates are ignored (iPhone workaround)",
+ .conn_mode = IEEE80211_CONN_MODE_HE,
+ .expected_mode = IEEE80211_CONN_MODE_HE,
+ .he_basic_mcs_1_4_set = 1,
+ .he_basic_mcs_5_8_set = 1,
+ }, {
+ .desc = "AP requires too many RX streams with EHT MCS 7",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_HE,
+ .eht_mcs7_min_nss = 0x15,
+ }, {
+ .desc = "AP requires too many TX streams with EHT MCS 7",
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .expected_mode = IEEE80211_CONN_MODE_HE,
+ .eht_mcs7_min_nss = 0x51,
+ }, {
+ .desc = "AP requires too many RX streams with EHT MCS 7 and EHT is required",
+ .extra_supp_rate = 0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY,
+ .conn_mode = IEEE80211_CONN_MODE_EHT,
+ .eht_mcs7_min_nss = 0x15,
+ .error = EINVAL,
+ }
+};
+KUNIT_ARRAY_PARAM_DESC(determine_chan_mode, determine_chan_mode_cases, desc)
+
+static void test_determine_chan_mode(struct kunit *test)
+{
+ const struct determine_chan_mode_case *params = test->param_value;
+ struct t_sdata *t_sdata = T_SDATA(test);
+ struct ieee80211_conn_settings conn = {
+ .mode = params->conn_mode,
+ .bw_limit = IEEE80211_CONN_BW_LIMIT_20,
+ };
+ struct cfg80211_bss cbss = {
+ .channel = &t_sdata->band_5ghz.channels[0],
+ };
+ unsigned long userspace_selectors[BITS_TO_LONGS(128)] = {};
+ u8 bss_ies[] = {
+ /* Supported Rates */
+ WLAN_EID_SUPP_RATES, 0x08,
+ 0x82, 0x84, 0x8b, 0x96, 0xc, 0x12, 0x18, 0x24,
+ /* Extended Supported Rates */
+ WLAN_EID_EXT_SUPP_RATES, 0x05,
+ 0x30, 0x48, 0x60, 0x6c, params->extra_supp_rate,
+ /* HT Capabilities */
+ WLAN_EID_HT_CAPABILITY, 0x1a,
+ 0x0c, 0x00, 0x1b, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ /* HT Information (0xff for 1 stream) */
+ WLAN_EID_HT_OPERATION, 0x16,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* VHT Capabilities */
+ WLAN_EID_VHT_CAPABILITY, 0xc,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00,
+ /* VHT Operation */
+ WLAN_EID_VHT_OPERATION, 0x05,
+ 0x00, 0x00, 0x00,
+ params->vht_basic_mcs_1_4_set ?
+ params->vht_basic_mcs_1_4 :
+ le16_get_bits(t_sdata->band_5ghz.vht_cap.vht_mcs.rx_mcs_map, 0xff),
+ params->vht_basic_mcs_5_8_set ?
+ params->vht_basic_mcs_5_8 :
+ le16_get_bits(t_sdata->band_5ghz.vht_cap.vht_mcs.rx_mcs_map, 0xff00),
+ /* HE Capabilities */
+ WLAN_EID_EXTENSION, 0x16, WLAN_EID_EXT_HE_CAPABILITY,
+ 0x01, 0x78, 0xc8, 0x1a, 0x40, 0x00, 0x00, 0xbf,
+ 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfa, 0xff, 0xfa, 0xff,
+ /* HE Operation (permit overriding values) */
+ WLAN_EID_EXTENSION, 0x07, WLAN_EID_EXT_HE_OPERATION,
+ 0xf0, 0x3f, 0x00, 0xb0,
+ params->he_basic_mcs_1_4_set ? params->he_basic_mcs_1_4 : 0xfc,
+ params->he_basic_mcs_5_8_set ? params->he_basic_mcs_5_8 : 0xff,
+ /* EHT Capabilities */
+ WLAN_EID_EXTENSION, 0x12, WLAN_EID_EXT_EHT_CAPABILITY,
+ 0x07, 0x00, 0x1c, 0x00, 0x00, 0xfe, 0xff, 0xff,
+ 0x7f, 0x01, 0x00, 0x88, 0x88, 0x88, 0x00, 0x00,
+ 0x00,
+ /* EHT Operation */
+ WLAN_EID_EXTENSION, 0x09, WLAN_EID_EXT_EHT_OPERATION,
+ 0x01, params->eht_mcs7_min_nss ? params->eht_mcs7_min_nss : 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
+ };
+ struct ieee80211_chan_req chanreq = {};
+ struct cfg80211_chan_def ap_chandef = {};
+ struct ieee802_11_elems *elems;
+
+ t_sdata->sdata->u.mgd.ht_capa_mask = params->ht_capa_mask;
+ t_sdata->sdata->u.mgd.vht_capa = params->vht_capa;
+ t_sdata->sdata->u.mgd.vht_capa_mask = params->vht_capa_mask;
+
+ if (params->userspace_selector)
+ set_bit(params->userspace_selector, userspace_selectors);
+
+ rcu_assign_pointer(cbss.ies,
+ kunit_kzalloc(test,
+ sizeof(cbss) + sizeof(bss_ies),
+ GFP_KERNEL));
+ KUNIT_ASSERT_NOT_NULL(test, rcu_access_pointer(cbss.ies));
+ ((struct cfg80211_bss_ies *)rcu_access_pointer(cbss.ies))->len = sizeof(bss_ies);
+
+ memcpy((void *)rcu_access_pointer(cbss.ies)->data, bss_ies,
+ sizeof(bss_ies));
+
+ rcu_read_lock();
+ elems = ieee80211_determine_chan_mode(t_sdata->sdata, &conn, &cbss,
+ 0, &chanreq, &ap_chandef,
+ userspace_selectors);
+ rcu_read_unlock();
+
+ /* We do not need elems, free them if they are valid. */
+ if (!IS_ERR_OR_NULL(elems))
+ kfree(elems);
+
+ if (params->error) {
+ KUNIT_ASSERT_TRUE(test, IS_ERR(elems));
+ KUNIT_ASSERT_EQ(test, PTR_ERR(elems), -params->error);
+ } else {
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, elems);
+ KUNIT_ASSERT_EQ(test, conn.mode, params->expected_mode);
+ }
+}
+
+static struct kunit_case chan_mode_cases[] = {
+ KUNIT_CASE_PARAM(test_determine_chan_mode,
+ determine_chan_mode_gen_params),
+ {}
+};
+
+static struct kunit_suite chan_mode = {
+ .name = "mac80211-mlme-chan-mode",
+ .test_cases = chan_mode_cases,
+};
+
+kunit_test_suite(chan_mode);
diff --git a/net/mac80211/tests/util.c b/net/mac80211/tests/util.c
index 0936a73e3617..9c2d63a5cd2b 100644
--- a/net/mac80211/tests/util.c
+++ b/net/mac80211/tests/util.c
@@ -266,11 +266,7 @@ int t_sdata_init(struct kunit_resource *resource, void *ctx)
cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
- IEEE80211_VHT_MCS_SUPPORT_0_9 << 14);
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 6);
sband->vht_cap.vht_mcs.tx_mcs_map =
sband->vht_cap.vht_mcs.rx_mcs_map;
break;
--
2.34.1
^ permalink raw reply related [flat|nested] 24+ messages in thread