From: Gregory Greenman <[email protected]>
Hi,
A bunch of patches from our internal tree with mac80211 and
cfg80211 changes. It's the usual developement, cleanups and
bugfixes.
Thanks,
Gregory
Emmanuel Grumbach (1):
wifi: mac80211: fetch and store the EML capability information
Ilan Peer (1):
wifi: mac80211: Fix elements scratch buffer allocation
Johannes Berg (8):
wifi: mac80211: fix min center freq offset tracing
wifi: mac80211: simplify chanctx allocation
wifi: mac80211: consider reserved chanctx for mindef
wifi: mac80211: recalc chanctx mindef before assigning
wifi: mac80211: HW restart for MLO
wifi: mac80211_hwsim: avoid warning with MLO PS stations
wifi: mac80211: skip EHT BSS membership selector
wifi: mac80211: implement proper AP MLD HW restart
Mukesh Sisodiya (1):
wifi: cfg80211: Add null check for ie data
drivers/net/wireless/virtual/mac80211_hwsim.c | 9 +-
include/linux/ieee80211.h | 40 ++++-
include/net/mac80211.h | 2 +
net/mac80211/chan.c | 75 +++++----
net/mac80211/ieee80211_i.h | 6 +-
net/mac80211/mlme.c | 16 +-
net/mac80211/trace.h | 2 +-
net/mac80211/util.c | 155 +++++++++++++-----
net/wireless/sme.c | 2 +-
9 files changed, 232 insertions(+), 75 deletions(-)
--
2.38.1
From: Johannes Berg <[email protected]>
We need to set the correct trace variable, otherwise we're
overwriting something else instead and the right one that
we print later is not initialized.
Fixes: b6011960f392 ("mac80211: handle channel frequency offset")
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/trace.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index de5d69f21306..db0d0132c58c 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -67,7 +67,7 @@
__entry->min_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0; \
__entry->min_chan_width = (c)->width; \
__entry->min_center_freq1 = (c)->center_freq1; \
- __entry->freq1_offset = (c)->freq1_offset; \
+ __entry->min_freq1_offset = (c)->freq1_offset; \
__entry->min_center_freq2 = (c)->center_freq2;
#define MIN_CHANDEF_PR_FMT " min_control:%d.%03d MHz min_width:%d min_center: %d.%03d/%d MHz"
#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \
--
2.38.1
From: Johannes Berg <[email protected]>
When a chanctx is reserved for a new vif and we recalculate
the minimal definition for it, we need to consider the new
interface it's being reserved for before we assign it, so it
can be used directly with the correct min channel width.
Fix the code to - optionally - consider that, and use that
option just before doing the reassignment.
Also, when considering channel context reservations, we
should only consider the one link we're currently working with.
Change the boolean argument to a link pointer to do that.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/chan.c | 72 +++++++++++++++++++++++---------------
net/mac80211/ieee80211_i.h | 3 +-
net/mac80211/util.c | 2 +-
3 files changed, 47 insertions(+), 30 deletions(-)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index d23d1a7b4cc3..1b182cf9d661 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -258,7 +258,8 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
static enum nl80211_chan_width
ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_chanctx_conf *conf)
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_link_data *rsvd_for)
{
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
struct ieee80211_vif *vif = &sdata->vif;
@@ -267,13 +268,14 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
- struct ieee80211_bss_conf *link_conf =
- rcu_dereference(sdata->vif.link_conf[link_id]);
+ struct ieee80211_link_data *link =
+ rcu_dereference(sdata->link[link_id]);
- if (!link_conf)
+ if (!link)
continue;
- if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
+ if (link != rsvd_for &&
+ rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
continue;
switch (vif->type) {
@@ -287,7 +289,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
* point, so take the width from the chandef, but
* account also for TDLS peers
*/
- width = max(link_conf->chandef.width,
+ width = max(link->conf->chandef.width,
ieee80211_get_max_required_bw(sdata, link_id));
break;
case NL80211_IFTYPE_P2P_DEVICE:
@@ -296,7 +298,7 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
- width = link_conf->chandef.width;
+ width = link->conf->chandef.width;
break;
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_UNSPECIFIED:
@@ -316,7 +318,8 @@ ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
static enum nl80211_chan_width
ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
- struct ieee80211_chanctx_conf *conf)
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_link_data *rsvd_for)
{
struct ieee80211_sub_if_data *sdata;
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
@@ -328,7 +331,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
if (!ieee80211_sdata_running(sdata))
continue;
- width = ieee80211_get_chanctx_vif_max_required_bw(sdata, conf);
+ width = ieee80211_get_chanctx_vif_max_required_bw(sdata, ctx,
+ rsvd_for);
max_bw = max(max_bw, width);
}
@@ -336,8 +340,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
/* use the configured bandwidth in case of monitor interface */
sdata = rcu_dereference(local->monitor_sdata);
if (sdata &&
- rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf)
- max_bw = max(max_bw, conf->def.width);
+ rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &ctx->conf)
+ max_bw = max(max_bw, ctx->conf.def.width);
rcu_read_unlock();
@@ -349,8 +353,10 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
* the max of min required widths of all the interfaces bound to this
* channel context.
*/
-static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
+static u32
+_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_link_data *rsvd_for)
{
enum nl80211_chan_width max_bw;
struct cfg80211_chan_def min_def;
@@ -370,7 +376,7 @@ static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
return 0;
}
- max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
+ max_bw = ieee80211_get_chanctx_max_required_bw(local, ctx, rsvd_for);
/* downgrade chandef up to max_bw */
min_def = ctx->conf.def;
@@ -448,9 +454,10 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
* channel context.
*/
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_link_data *rsvd_for)
{
- u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx);
+ u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
if (!changed)
return;
@@ -464,10 +471,11 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, ctx, false);
}
-static void ieee80211_change_chanctx(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx,
- struct ieee80211_chanctx *old_ctx,
- const struct cfg80211_chan_def *chandef)
+static void _ieee80211_change_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_chanctx *old_ctx,
+ const struct cfg80211_chan_def *chandef,
+ struct ieee80211_link_data *rsvd_for)
{
u32 changed;
@@ -492,7 +500,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, old_ctx, true);
if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) {
- ieee80211_recalc_chanctx_min_def(local, ctx);
+ ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
return;
}
@@ -502,7 +510,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
/* check if min chanctx also changed */
changed = IEEE80211_CHANCTX_CHANGE_WIDTH |
- _ieee80211_recalc_chanctx_min_def(local, ctx);
+ _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
drv_change_chanctx(local, ctx, changed);
if (!local->use_chanctx) {
@@ -514,6 +522,14 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, old_ctx, false);
}
+static void ieee80211_change_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_chanctx *old_ctx,
+ const struct cfg80211_chan_def *chandef)
+{
+ _ieee80211_change_chanctx(local, ctx, old_ctx, chandef, NULL);
+}
+
static struct ieee80211_chanctx *
ieee80211_find_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
@@ -638,7 +654,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
ctx->conf.radar_enabled = false;
- _ieee80211_recalc_chanctx_min_def(local, ctx);
+ _ieee80211_recalc_chanctx_min_def(local, ctx, NULL);
return ctx;
}
@@ -873,12 +889,12 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
ieee80211_recalc_chanctx_chantype(local, curr_ctx);
ieee80211_recalc_smps_chanctx(local, curr_ctx);
ieee80211_recalc_radar_chanctx(local, curr_ctx);
- ieee80211_recalc_chanctx_min_def(local, curr_ctx);
+ ieee80211_recalc_chanctx_min_def(local, curr_ctx, NULL);
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
ieee80211_recalc_txpower(sdata, false);
- ieee80211_recalc_chanctx_min_def(local, new_ctx);
+ ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL);
}
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
@@ -1270,7 +1286,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
ieee80211_link_update_chandef(link, &link->reserved_chandef);
- ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef);
+ _ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef, link);
vif_chsw[0].vif = &sdata->vif;
vif_chsw[0].old_ctx = &old_ctx->conf;
@@ -1300,7 +1316,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
ieee80211_free_chanctx(local, old_ctx);
- ieee80211_recalc_chanctx_min_def(local, new_ctx);
+ ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL);
ieee80211_recalc_smps_chanctx(local, new_ctx);
ieee80211_recalc_radar_chanctx(local, new_ctx);
@@ -1665,7 +1681,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_recalc_chanctx_chantype(local, ctx);
ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx);
- ieee80211_recalc_chanctx_min_def(local, ctx);
+ ieee80211_recalc_chanctx_min_def(local, ctx, NULL);
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a0a7839cb961..b0372e76f373 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2537,7 +2537,8 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local,
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx);
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx);
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_link_data *rsvd_for);
bool ieee80211_is_radar_required(struct ieee80211_local *local);
void ieee80211_dfs_cac_timer(unsigned long data);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 1527d6aafc14..4bf76150925d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3015,7 +3015,7 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
conf);
- ieee80211_recalc_chanctx_min_def(local, chanctx);
+ ieee80211_recalc_chanctx_min_def(local, chanctx, NULL);
}
unlock:
mutex_unlock(&local->chanctx_mtx);
--
2.38.1
From: Johannes Berg <[email protected]>
When we allocate a new channel context, or find an existing one
that is compatible, we currently assign it to a link before its
mindef is updated. This leads to strange situations, especially
in link switching where you switch to an 80 MHz link and expect
it to be active immediately, but the mindef is still configured
to 20 MHz while assigning. Also, it's strange that the chandef
passed to the assign method's argument is wider than the one in
the context.
Fix this by calculating the mindef with the new link considered
before calling the driver.
In particular, this fixes an iwlwifi problem during link switch
where the firmware would assert because the (link) station that
was added for the AP is configured to transmit at a bandwidth
that's wider than the channel context that it's configured on.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/chan.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 1b182cf9d661..77c90ed8f5d7 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -871,6 +871,9 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
}
if (new_ctx) {
+ /* recalc considering the link we'll use it for now */
+ ieee80211_recalc_chanctx_min_def(local, new_ctx, link);
+
ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
if (ret)
goto out;
--
2.38.1
From: Johannes Berg <[email protected]>
Implement proper reconfiguration for interfaces that are
doing MLO, in order to be able to recover from HW restart
correctly.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/util.c | 107 ++++++++++++++++++++++++++++++--------------
1 file changed, 73 insertions(+), 34 deletions(-)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4bf76150925d..ead4b095cc4d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2624,21 +2624,55 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
+ /* common change flags for all interface types - link only */
+ u32 changed = BSS_CHANGED_ERP_CTS_PROT |
+ BSS_CHANGED_ERP_PREAMBLE |
+ BSS_CHANGED_ERP_SLOT |
+ BSS_CHANGED_HT |
+ BSS_CHANGED_BASIC_RATES |
+ BSS_CHANGED_BEACON_INT |
+ BSS_CHANGED_BSSID |
+ BSS_CHANGED_CQM |
+ BSS_CHANGED_QOS |
+ BSS_CHANGED_TXPOWER |
+ BSS_CHANGED_MCAST_RATE;
+ struct ieee80211_link_data *link = NULL;
unsigned int link_id;
- u32 changed;
+ u32 active_links = 0;
if (!ieee80211_sdata_running(sdata))
continue;
sdata_lock(sdata);
+ if (sdata->vif.valid_links) {
+ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS] = {
+ [0] = &sdata->vif.bss_conf,
+ };
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ /* start with a single active link */
+ active_links = sdata->vif.active_links;
+ link_id = ffs(active_links) - 1;
+ sdata->vif.active_links = BIT(link_id);
+ }
+
+ drv_change_vif_links(local, sdata, 0,
+ sdata->vif.active_links,
+ old);
+ }
+
for (link_id = 0;
link_id < ARRAY_SIZE(sdata->vif.link_conf);
link_id++) {
- struct ieee80211_link_data *link;
+ if (sdata->vif.valid_links &&
+ !(sdata->vif.active_links & BIT(link_id)))
+ continue;
link = sdata_dereference(sdata->link[link_id], sdata);
- if (link)
- ieee80211_assign_chanctx(local, sdata, link);
+ if (!link)
+ continue;
+
+ ieee80211_assign_chanctx(local, sdata, link);
}
switch (sdata->vif.type) {
@@ -2658,42 +2692,42 @@ int ieee80211_reconfig(struct ieee80211_local *local)
&sdata->deflink.tx_conf[i]);
break;
}
- sdata_unlock(sdata);
-
- /* common change flags for all interface types */
- changed = BSS_CHANGED_ERP_CTS_PROT |
- BSS_CHANGED_ERP_PREAMBLE |
- BSS_CHANGED_ERP_SLOT |
- BSS_CHANGED_HT |
- BSS_CHANGED_BASIC_RATES |
- BSS_CHANGED_BEACON_INT |
- BSS_CHANGED_BSSID |
- BSS_CHANGED_CQM |
- BSS_CHANGED_QOS |
- BSS_CHANGED_IDLE |
- BSS_CHANGED_TXPOWER |
- BSS_CHANGED_MCAST_RATE;
if (sdata->vif.bss_conf.mu_mimo_owner)
changed |= BSS_CHANGED_MU_GROUPS;
+ if (!sdata->vif.valid_links)
+ changed |= BSS_CHANGED_IDLE;
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
- changed |= BSS_CHANGED_ASSOC |
- BSS_CHANGED_ARP_FILTER |
- BSS_CHANGED_PS;
-
- /* Re-send beacon info report to the driver */
- if (sdata->deflink.u.mgd.have_beacon)
- changed |= BSS_CHANGED_BEACON_INFO;
-
- if (sdata->vif.bss_conf.max_idle_period ||
- sdata->vif.bss_conf.protected_keep_alive)
- changed |= BSS_CHANGED_KEEP_ALIVE;
-
- sdata_lock(sdata);
- ieee80211_bss_info_change_notify(sdata, changed);
- sdata_unlock(sdata);
+ if (!sdata->vif.valid_links) {
+ changed |= BSS_CHANGED_ASSOC |
+ BSS_CHANGED_ARP_FILTER |
+ BSS_CHANGED_PS;
+
+ /* Re-send beacon info report to the driver */
+ if (sdata->deflink.u.mgd.have_beacon)
+ changed |= BSS_CHANGED_BEACON_INFO;
+
+ if (sdata->vif.bss_conf.max_idle_period ||
+ sdata->vif.bss_conf.protected_keep_alive)
+ changed |= BSS_CHANGED_KEEP_ALIVE;
+
+ if (sdata->vif.bss_conf.eht_puncturing)
+ changed |= BSS_CHANGED_EHT_PUNCTURING;
+
+ ieee80211_bss_info_change_notify(sdata,
+ changed);
+ } else if (!WARN_ON(!link)) {
+ ieee80211_link_info_change_notify(sdata, link,
+ changed);
+ changed = BSS_CHANGED_ASSOC |
+ BSS_CHANGED_IDLE |
+ BSS_CHANGED_PS |
+ BSS_CHANGED_ARP_FILTER;
+ ieee80211_vif_cfg_change_notify(sdata, changed);
+ }
break;
case NL80211_IFTYPE_OCB:
changed |= BSS_CHANGED_OCB;
@@ -2728,6 +2762,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NL80211_IFTYPE_NAN:
res = ieee80211_reconfig_nan(sdata);
if (res < 0) {
+ sdata_unlock(sdata);
ieee80211_handle_reconfig_failure(local);
return res;
}
@@ -2745,6 +2780,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(1);
break;
}
+ sdata_unlock(sdata);
+
+ if (active_links)
+ ieee80211_set_active_links(&sdata->vif, active_links);
}
ieee80211_recalc_ps(local);
--
2.38.1
From: Johannes Berg <[email protected]>
There's no need to call ieee80211_recalc_chanctx_min_def()
since it cannot and won't call the driver anyway; just use
_ieee80211_recalc_chanctx_min_def() instead.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/chan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index dbc34fbe7c8f..d23d1a7b4cc3 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -638,7 +638,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
ctx->conf.radar_enabled = false;
- ieee80211_recalc_chanctx_min_def(local, ctx);
+ _ieee80211_recalc_chanctx_min_def(local, ctx);
return ctx;
}
--
2.38.1
From: Johannes Berg <[email protected]>
If the station disables all links it's in powersave and
we shouldn't transmit anything to it, but we don't handle
that correctly yet. For now, just avoid the warning, once
we really add support for this case we can revert to the
old warning.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/virtual/mac80211_hwsim.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 2211fa58fe41..4f44d87a5c13 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -1940,7 +1940,14 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
hdr, &link_sta);
}
- if (WARN_ON(!bss_conf)) {
+ if (unlikely(!bss_conf)) {
+ /* if it's an MLO STA, it might have deactivated all
+ * links temporarily - but we don't handle real PS in
+ * this code yet, so just drop the frame in that case
+ */
+ WARN(link != IEEE80211_LINK_UNSPECIFIED || !sta || !sta->mlo,
+ "link:%d, sta:%pM, sta->mlo:%d\n",
+ link, sta ? sta->addr : NULL, sta ? sta->mlo : -1);
ieee80211_free_txskb(hw, skb);
return;
}
--
2.38.1
From: Mukesh Sisodiya <[email protected]>
It's valid to pass NULL "ies" pointer to cfg80211_sme_get_conn_ies().
Add the corresponding NULL-check to avoid NULL pointer access.
Signed-off-by: Mukesh Sisodiya <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/wireless/sme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 7bdeb8eea92d..77277e4bca50 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -513,7 +513,7 @@ static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev,
if (!buf)
return -ENOMEM;
- if (ies_len) {
+ if (ies) {
static const u8 before_extcapa[] = {
/* not listing IEs expected to be created by driver */
WLAN_EID_RSN,
--
2.38.1
From: Ilan Peer <[email protected]>
Current code allocated a scratch buffer that is the length
of the elements. However this is not sufficient as the
defragmentation can happen in the following places concurrently:
- MBSSID element defragmentation
- EHT ML element defragmentation
- EHT ML element sub element defragmentation
Fix the length and the scratch buffer allocation to allow
up to 3 defragmentations.
While at it remove the 'scratch_len' field from
'struct ieee80211_elems_parse_params' as it is not
really needed or used.
Fixes: ff05d4b45dd8 ("wifi: mac80211: fix MBSSID parsing use-after-free")
Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 ---
net/mac80211/util.c | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b0372e76f373..e67c5c754be1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2269,8 +2269,6 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
* (or re-association) response frame if this is given
* @from_ap: frame is received from an AP (currently used only
* for EHT capabilities parsing)
- * @scratch_len: if non zero, specifies the requested length of the scratch
- * buffer; otherwise, 'len' is used.
*/
struct ieee80211_elems_parse_params {
const u8 *start;
@@ -2281,7 +2279,6 @@ struct ieee80211_elems_parse_params {
struct cfg80211_bss *bss;
int link_id;
bool from_ap;
- size_t scratch_len;
};
struct ieee802_11_elems *
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ead4b095cc4d..b0c035cf13da 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1604,7 +1604,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
const struct element *non_inherit = NULL;
u8 *nontransmitted_profile;
int nontransmitted_profile_len = 0;
- size_t scratch_len = params->scratch_len ?: 3 * params->len;
+ size_t scratch_len = 3 * params->len;
elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC);
if (!elems)
--
2.38.1
From: Johannes Berg <[email protected]>
Skip the EHT BSS membership selector for getting rates.
While at it, add the definitions for GLK and EPS, and
sort the list.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
include/linux/ieee80211.h | 5 ++++-
net/mac80211/mlme.c | 5 +++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index c4cf296e7eaf..c271184a3968 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1349,8 +1349,11 @@ struct ieee80211_mgmt {
/* Supported rates membership selectors */
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
-#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
+#define BSS_MEMBERSHIP_SELECTOR_GLK 125
+#define BSS_MEMBERSHIP_SELECTOR_EPS 124
#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E 123
+#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
+#define BSS_MEMBERSHIP_SELECTOR_EHT_PHY 121
/* 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 e13a0354c397..0020c9e41caa 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3902,8 +3902,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*have_higher_than_11mbit = true;
/*
- * Skip HT, VHT, HE and SAE H2E only BSS membership selectors
- * since they're not rates.
+ * Skip HT, VHT, HE, EHT and SAE H2E only BSS 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
@@ -3912,6 +3912,7 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
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))
continue;
--
2.38.1
From: Johannes Berg <[email protected]>
Previously, I didn't implement restarting here at all if the
interface is an MLD, so it only worked for non-MLO. Add the
needed code to restart an AP MLD correctly.
Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
net/mac80211/util.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index b0c035cf13da..cd323fbea8df 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2475,6 +2475,35 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
return 0;
}
+static void ieee80211_reconfig_ap_links(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u32 changed)
+{
+ int link_id;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
+ struct ieee80211_link_data *link;
+
+ if (!(sdata->vif.active_links & BIT(link_id)))
+ continue;
+
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ continue;
+
+ if (rcu_access_pointer(link->u.ap.beacon))
+ drv_start_ap(local, sdata, link->conf);
+
+ if (!link->conf->enable_beacon)
+ continue;
+
+ changed |= BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED;
+
+ ieee80211_link_info_change_notify(sdata, link, changed);
+ }
+}
+
int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;
@@ -2737,7 +2766,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
changed |= BSS_CHANGED_IBSS;
fallthrough;
case NL80211_IFTYPE_AP:
- changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS;
+ changed |= BSS_CHANGED_P2P_PS;
+
+ if (sdata->vif.valid_links)
+ ieee80211_vif_cfg_change_notify(sdata,
+ BSS_CHANGED_SSID);
+ else
+ changed |= BSS_CHANGED_SSID;
if (sdata->vif.bss_conf.ftm_responder == 1 &&
wiphy_ext_feature_isset(sdata->local->hw.wiphy,
@@ -2747,6 +2782,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (sdata->vif.type == NL80211_IFTYPE_AP) {
changed |= BSS_CHANGED_AP_PROBE_RESP;
+ if (sdata->vif.valid_links) {
+ ieee80211_reconfig_ap_links(local,
+ sdata,
+ changed);
+ break;
+ }
+
if (rcu_access_pointer(sdata->deflink.u.ap.beacon))
drv_start_ap(local, sdata,
sdata->deflink.conf);
--
2.38.1
From: Emmanuel Grumbach <[email protected]>
We need to teach the low level driver about the EML capability which
includes information for EMLSR / EMLMR operation.
Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
include/linux/ieee80211.h | 35 +++++++++++++++++++++++++++++++++++
include/net/mac80211.h | 2 ++
net/mac80211/mlme.c | 11 +++++++++++
3 files changed, 48 insertions(+)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index c271184a3968..fba4c44da832 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -4635,6 +4635,41 @@ static inline u8 ieee80211_mle_common_size(const u8 *data)
return sizeof(*mle) + common + mle->variable[0];
}
+/**
+ * ieee80211_mle_get_eml_cap - returns the EML capability
+ * @data: pointer to the multi link EHT IE
+ *
+ * The element is assumed to be big enough. This must be checked by
+ * ieee80211_mle_size_ok().
+ * If the EML capability can't be found (the type is not basic, or
+ * the EML capability presence bit is clear), 0 will be returned.
+ */
+static inline u16 ieee80211_mle_get_eml_cap(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;
+
+ if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) !=
+ IEEE80211_ML_CONTROL_TYPE_BASIC)
+ return 0;
+
+ /* 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_EML_CAPA))
+ 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;
+
+ return get_unaligned_le16(common);
+}
+
/**
* ieee80211_mle_size_ok - validate multi-link element size
* @data: pointer to the element data
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index ac0370e76874..f75d941eece8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1790,6 +1790,7 @@ enum ieee80211_offload_flags {
* @ps: power-save mode (STA only). This flag is NOT affected by
* offchannel/dynamic_ps operations.
* @aid: association ID number, valid only when @assoc is true
+ * @eml_cap: EML capabilities as described in P802.11be_D2.2 Figure 9-1002k.
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
* may filter ARP queries targeted for other addresses than listed here.
* The driver must allow ARP queries targeted for all address listed here
@@ -1812,6 +1813,7 @@ struct ieee80211_vif_cfg {
bool ibss_creator;
bool ps;
u16 aid;
+ u16 eml_cap;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
int arp_addr_cnt;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0020c9e41caa..4ea383aafcac 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4838,6 +4838,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
IEEE80211_CONN_DISABLE_EHT)) &&
he_oper) {
const struct cfg80211_bss_ies *cbss_ies;
+ const struct element *eht_ml_elem;
const u8 *eht_oper_ie;
cbss_ies = rcu_dereference(cbss->ies);
@@ -4848,6 +4849,16 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
eht_oper = (void *)(eht_oper_ie + 3);
else
eht_oper = NULL;
+
+ eht_ml_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK,
+ cbss_ies->data, cbss_ies->len);
+
+ /* data + 1 / datalen - 1 since it's an extended element */
+ if (eht_ml_elem &&
+ ieee80211_mle_size_ok(eht_ml_elem->data + 1,
+ eht_ml_elem->datalen - 1))
+ sdata->vif.cfg.eml_cap =
+ ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1);
}
/* Allow VHT if at least one channel on the sband supports 80 MHz */
--
2.38.1
On Thu, 2023-05-04 at 16:45 +0300, [email protected] wrote:
> From: Mukesh Sisodiya <[email protected]>
>
> It's valid to pass NULL "ies" pointer to cfg80211_sme_get_conn_ies().
> Add the corresponding NULL-check to avoid NULL pointer access.
Yes ... but it's not valid to do that when ies_len is 0, since you can't
have NULL ies with a length ...
So ... maybe we can do this patch but certainly the description is
bogus. Maybe you're trying to fix some static checker warnings or
something, which maybe is fine, but there was never any chance for an
NPD.
johannes