Commit dd7b1bdb authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: update STA/chandef width during switch

In channel switch without an additional channel context,
where the reassign logic kicks in, we also need to update
the station bandwidth and chandef minimum width correctly
to avoid having station rate control configured to wider
bandwidth than the channel context. Do that now.
Reviewed-by: default avatarMiriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20240612143418.0bc3d28231b3.I51e76df86212057ca0469e235ba9bf4461cbee75@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b2751236
......@@ -295,17 +295,24 @@ ieee80211_get_max_required_bw(struct ieee80211_link_data *link)
static enum nl80211_chan_width
ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for)
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_link_data *link;
enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
if (WARN_ON(check_reserved && rsvd_for))
return ctx->conf.def.width;
for_each_sdata_link(local, link) {
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
if (link != rsvd_for &&
rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
if (check_reserved) {
if (link->reserved_chanctx != ctx)
continue;
} else if (link != rsvd_for &&
rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
continue;
switch (link->sdata->vif.type) {
......@@ -359,7 +366,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
static u32
_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for)
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
{
enum nl80211_chan_width max_bw;
struct cfg80211_chan_def min_def;
......@@ -379,7 +387,8 @@ _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
return 0;
}
max_bw = ieee80211_get_chanctx_max_required_bw(local, ctx, rsvd_for);
max_bw = ieee80211_get_chanctx_max_required_bw(local, ctx, rsvd_for,
check_reserved);
/* downgrade chandef up to max_bw */
min_def = ctx->conf.def;
......@@ -465,9 +474,11 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local,
*/
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for)
struct ieee80211_link_data *rsvd_for,
bool check_reserved)
{
u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
check_reserved);
if (!changed)
return;
......@@ -515,7 +526,7 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,
ieee80211_chan_bw_change(local, old_ctx, false, true);
if (ieee80211_chanreq_identical(&ctx_req, chanreq)) {
ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
return;
}
......@@ -536,7 +547,7 @@ static void _ieee80211_change_chanctx(struct ieee80211_local *local,
ctx->conf.ap = chanreq->ap;
/* check if min chanctx also changed */
changed |= _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for);
changed |= _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
ieee80211_add_wbrf(local, &ctx->conf.def);
......@@ -663,7 +674,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, NULL);
_ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
return ctx;
}
......@@ -845,7 +856,7 @@ 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);
ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
if (assign_on_failure || !ret) {
......@@ -868,12 +879,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, NULL);
ieee80211_recalc_chanctx_min_def(local, curr_ctx, NULL, false);
}
if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
ieee80211_recalc_txpower(sdata, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
}
if (conf) {
......@@ -1286,7 +1297,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, false);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL);
ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false);
ieee80211_recalc_smps_chanctx(local, new_ctx);
ieee80211_recalc_radar_chanctx(local, new_ctx);
......@@ -1552,6 +1563,31 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
goto err;
}
/* update station rate control and min width before switch */
list_for_each_entry(ctx, &local->chanctx_list, list) {
struct ieee80211_link_data *link;
if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
continue;
if (WARN_ON(!ctx->replace_ctx)) {
err = -EINVAL;
goto err;
}
list_for_each_entry(link, &ctx->reserved_links,
reserved_chanctx_list) {
if (!ieee80211_link_has_in_place_reservation(link))
continue;
ieee80211_chan_bw_change(local,
ieee80211_link_get_chanctx(link),
true, true);
}
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
}
/*
* All necessary vifs are ready. Perform the switch now depending on
* reservations and driver capabilities.
......@@ -1619,7 +1655,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, NULL);
ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
reserved_chanctx_list) {
......@@ -1632,6 +1668,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
link->reserved_chanctx = NULL;
ieee80211_link_chanctx_reservation_complete(link);
ieee80211_chan_bw_change(local, ctx, false, false);
}
/*
......
......@@ -2624,7 +2624,8 @@ 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_link_data *rsvd_for);
struct ieee80211_link_data *rsvd_for,
bool check_reserved);
bool ieee80211_is_radar_required(struct ieee80211_local *local);
void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work);
......
......@@ -2334,7 +2334,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, NULL);
ieee80211_recalc_chanctx_min_def(local, chanctx, NULL, false);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment