mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
wifi: mac80211: fix channel evacuation logic
When we try to assign a chanctx to a link, if ieee80211_find_or_create_chanctx() failed, we try to evacuate a NAN channel and call it again. This logic is broken: In case there are not enough chanctxs we will fail earlier, when we check ieee80211_check_combinations(). To fix this, do the following in case ieee80211_check_combinations() failed: - check if there is a NAN channel that can be evacuated - make ieee80211_check_combinations() not consider the chanctx of that NAN channel, so we pretend that it was already evacuated - If now ieee80211_check_combinations() is successful, we know that it helped, and we can remove that NAN channel for real. Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20260527224745.5f7b10505145.I1712bc64f9eec9c99f05994208ad124624a29f1c@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
a5b9ebd5c3
commit
f1a389fcc3
|
|
@ -2216,6 +2216,64 @@ ieee80211_find_or_create_chanctx(struct ieee80211_sub_if_data *sdata,
|
|||
assign_on_failure, radio_idx);
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_nan_evac_chanctx_filter(struct ieee80211_chanctx *ctx,
|
||||
void *filter_data)
|
||||
{
|
||||
return ctx == filter_data;
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_try_nan_chan_evacuation(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
enum ieee80211_chanctx_mode mode,
|
||||
u8 radar_detect_width)
|
||||
{
|
||||
struct ieee80211_sub_if_data *nan_sdata = ieee80211_find_nan_sdata(local);
|
||||
struct ieee80211_check_combinations_data comb_data = {
|
||||
.chandef = chandef,
|
||||
.chanmode = mode,
|
||||
.radar_detect = radar_detect_width,
|
||||
.radio_idx = -1,
|
||||
.chanctx_filter = ieee80211_nan_evac_chanctx_filter,
|
||||
};
|
||||
struct ieee80211_nan_channel *evac_chan;
|
||||
struct ieee80211_chanctx *evac_ctx;
|
||||
int ret;
|
||||
|
||||
if (!nan_sdata)
|
||||
return -ENOENT;
|
||||
|
||||
/* Find an evacuation candidate... */
|
||||
evac_chan = ieee80211_nan_find_evac_chan(local, nan_sdata, NULL);
|
||||
if (!evac_chan || WARN_ON(!evac_chan->chanctx_conf))
|
||||
return -ENOENT;
|
||||
|
||||
evac_ctx = container_of(evac_chan->chanctx_conf,
|
||||
struct ieee80211_chanctx, conf);
|
||||
|
||||
/*
|
||||
* ... check combinations assuming to-be-evacuated ctx is already
|
||||
* released
|
||||
*/
|
||||
comb_data.filter_data = evac_ctx;
|
||||
ret = ieee80211_check_combinations_ext(sdata, &comb_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* That helped! Let's evacuate the channel */
|
||||
ieee80211_nan_evacuate_channel(nan_sdata, evac_chan);
|
||||
|
||||
/* Re-check, just to be on the safe-side */
|
||||
ret = ieee80211_check_combinations(sdata, chandef, mode,
|
||||
radar_detect_width, -1);
|
||||
|
||||
/* That shouldn't happen, we checked before! */
|
||||
WARN_ON(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
|
||||
const struct ieee80211_chan_req *chanreq,
|
||||
enum ieee80211_chanctx_mode mode,
|
||||
|
|
@ -2247,23 +2305,21 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
|
|||
|
||||
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
|
||||
radar_detect_width, -1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (ret < 0) {
|
||||
/* Let's check if evacuating a NAN channel will help */
|
||||
ret = ieee80211_try_nan_chan_evacuation(local, sdata,
|
||||
&chanreq->oper,
|
||||
mode,
|
||||
radar_detect_width);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!local->in_reconfig)
|
||||
__ieee80211_link_release_channel(link, false);
|
||||
|
||||
ctx = ieee80211_find_or_create_chanctx(sdata, chanreq, mode,
|
||||
assign_on_failure, &reused_ctx);
|
||||
if (IS_ERR(ctx)) {
|
||||
/* Try to evacuate a NAN channel to free up a chanctx */
|
||||
if (ieee80211_nan_try_evacuate(&local->hw, NULL))
|
||||
ctx = ieee80211_find_or_create_chanctx(sdata, chanreq,
|
||||
mode,
|
||||
assign_on_failure,
|
||||
&reused_ctx);
|
||||
}
|
||||
|
||||
if (IS_ERR(ctx)) {
|
||||
ret = PTR_ERR(ctx);
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -2059,6 +2059,12 @@ int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
|
|||
struct cfg80211_nan_peer_sched *sched);
|
||||
void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched);
|
||||
void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata);
|
||||
struct ieee80211_nan_channel *
|
||||
ieee80211_nan_find_evac_chan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_chanctx *ctx);
|
||||
void ieee80211_nan_evacuate_channel(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_nan_channel *nan_channel);
|
||||
|
||||
static inline struct ieee80211_sub_if_data *
|
||||
ieee80211_find_nan_sdata(struct ieee80211_local *local)
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
ieee80211_nan_evacuate_channel(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_nan_channel *nan_channel)
|
||||
{
|
||||
|
|
@ -754,7 +754,7 @@ ieee80211_nan_evacuate_channel(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_free_chanctx(sdata->local, ctx, false);
|
||||
}
|
||||
|
||||
static struct ieee80211_nan_channel *
|
||||
struct ieee80211_nan_channel *
|
||||
ieee80211_nan_find_evac_chan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_chanctx *ctx)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user