From: Andrei Otcheretianski Implement the nan_set_non_evac_channels operation in mac80211. It marks the provided channels as non-evacuable in the current local schedule and clears the flag on all other channels. All provided channels must exist in the current schedule, otherwise -ENOENT is returned. ieee80211_nan_find_evac_chan() skips channels marked as non-evacuable when selecting a channel to evacuate for concurrent operations. Fixes: 42c9de58d990 ("wifi: mac80211: add NAN channel evacuation support") Signed-off-by: Andrei Otcheretianski Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit --- include/net/mac80211.h | 2 ++ net/mac80211/cfg.c | 13 +++++++++++++ net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/nan.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7bb4618065b6..33ff018c33ec 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -923,12 +923,14 @@ struct ieee80211_bss_conf { * @channel_entry: the Channel Entry blob as defined in Wi-Fi Aware * (TM) 4.0 specification Table 100 (Channel Entry format for the NAN * Availability attribute). + * @no_evacuate: if set, this channel must not be evacuated */ struct ieee80211_nan_channel { struct ieee80211_chan_req chanreq; u8 needed_rx_chains; struct ieee80211_chanctx_conf *chanctx_conf; u8 channel_entry[6]; + bool no_evacuate; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 23f4f9ec86d0..cdcf1f057707 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5973,6 +5973,18 @@ ieee80211_set_peer_nan_sched(struct wiphy *wiphy, return ieee80211_nan_set_peer_sched(sdata, sched); } +static int +ieee80211_set_nan_non_evac_channels(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_nan_non_evac_channels *channels) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + + lockdep_assert_wiphy(wiphy); + + return ieee80211_nan_set_non_evac_channels(sdata, channels); +} + const struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -6091,4 +6103,5 @@ const struct cfg80211_ops mac80211_config_ops = { .set_epcs = ieee80211_set_epcs, .nan_set_local_sched = ieee80211_set_local_nan_sched, .nan_set_peer_sched = ieee80211_set_peer_nan_sched, + .nan_set_non_evac_channels = ieee80211_set_nan_non_evac_channels, }; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 53b0b08d3459..929fc8930a35 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2087,6 +2087,8 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata, struct cfg80211_nan_local_sched *sched); int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata, struct cfg80211_nan_peer_sched *sched); +int ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata, + struct cfg80211_nan_non_evac_channels *channels); 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 * diff --git a/net/mac80211/nan.c b/net/mac80211/nan.c index 19e08661be43..38bd105121ac 100644 --- a/net/mac80211/nan.c +++ b/net/mac80211/nan.c @@ -248,6 +248,35 @@ ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg) return NULL; } +int +ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata, + struct cfg80211_nan_non_evac_channels *channels) +{ + struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched; + + /* + * cfg80211 already validated that all provided channels belong to the + * current schedule, so just clear all non-evacuable flags and set the + * ones in the list. + */ + for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) + sched_cfg->channels[j].no_evacuate = false; + + for (int i = 0; i < channels->n_channels; i++) { + for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) { + if (!sched_cfg->channels[j].chanreq.oper.chan) + continue; + if (cfg80211_chandef_identical(&sched_cfg->channels[j].chanreq.oper, + &channels->chandefs[i])) { + sched_cfg->channels[j].no_evacuate = true; + break; + } + } + } + + return 0; +} + int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata, struct cfg80211_nan_local_sched *sched) { @@ -786,6 +815,10 @@ ieee80211_nan_find_evac_chan(struct ieee80211_local *local, usable_channels++; + /* No-evacuate channel is usable but cannot be evacuated */ + if (chan->no_evacuate) + continue; + chan_ctx = container_of(chan->chanctx_conf, struct ieee80211_chanctx, conf); -- 2.34.1