mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:46:16 +00:00
wifi: mac80211: extend ifcomb check functions for multi-radio
Add support for counting global and per-radio max/current number of channels, as well as checking radio-specific interface combinations. Signed-off-by: Felix Fietkau <nbd@nbd.name> Link: https://patch.msgid.link/e76307f8ce562a91a74faab274ae01f6a5ba0a2e.1720514221.git-series.nbd@nbd.name Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
2920bc8d91
commit
0874bcd0e1
@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(struct wiphy *wiphy,
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
|
||||
ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wiphy *wiphy,
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
|
||||
ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -4008,7 +4008,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
goto out;
|
||||
|
||||
/* if reservation is invalid then this will fail */
|
||||
err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
|
||||
err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1);
|
||||
if (err) {
|
||||
ieee80211_link_unreserve_chanctx(link_data);
|
||||
goto out;
|
||||
@ -5203,4 +5203,5 @@ const struct cfg80211_ops mac80211_config_ops = {
|
||||
.del_link_station = ieee80211_del_link_station,
|
||||
.set_hw_timestamp = ieee80211_set_hw_timestamp,
|
||||
.set_ttlm = ieee80211_set_ttlm,
|
||||
.get_radio_mask = ieee80211_get_radio_mask,
|
||||
};
|
||||
|
@ -47,24 +47,29 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local,
|
||||
ieee80211_chanctx_num_reserved(local, ctx);
|
||||
}
|
||||
|
||||
static int ieee80211_num_chanctx(struct ieee80211_local *local)
|
||||
static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
|
||||
{
|
||||
struct ieee80211_chanctx *ctx;
|
||||
int num = 0;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list)
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
||||
if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
|
||||
continue;
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
|
||||
static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
|
||||
int radio_idx)
|
||||
{
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
|
||||
return ieee80211_num_chanctx(local, radio_idx) <
|
||||
ieee80211_max_num_channels(local, radio_idx);
|
||||
}
|
||||
|
||||
static struct ieee80211_chanctx *
|
||||
@ -1101,7 +1106,7 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
|
||||
|
||||
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
|
||||
if (!new_ctx) {
|
||||
if (ieee80211_can_create_new_chanctx(local)) {
|
||||
if (ieee80211_can_create_new_chanctx(local, -1)) {
|
||||
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
||||
false);
|
||||
if (IS_ERR(new_ctx))
|
||||
@ -1822,7 +1827,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
|
||||
link->radar_required = ret;
|
||||
|
||||
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
|
||||
radar_detect_width);
|
||||
radar_detect_width, -1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1746,7 +1746,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
|
||||
|
||||
ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode,
|
||||
radar_detect_width);
|
||||
radar_detect_width, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -2640,8 +2640,9 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
||||
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
enum ieee80211_chanctx_mode chanmode,
|
||||
u8 radar_detect);
|
||||
int ieee80211_max_num_channels(struct ieee80211_local *local);
|
||||
u8 radar_detect, int radio_idx);
|
||||
int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx);
|
||||
u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev);
|
||||
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *ctx);
|
||||
|
||||
|
@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
return ieee80211_check_combinations(sdata, NULL, 0, 0);
|
||||
return ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
|
||||
}
|
||||
|
||||
static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -3932,20 +3932,103 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
|
||||
return radar_detect;
|
||||
}
|
||||
|
||||
static u32
|
||||
__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct ieee80211_chanctx_conf *conf;
|
||||
unsigned int link_id;
|
||||
u32 mask = 0;
|
||||
|
||||
for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
|
||||
conf = sdata_dereference(link_conf->chanctx_conf, sdata);
|
||||
if (!conf || conf->radio_idx < 0)
|
||||
continue;
|
||||
|
||||
mask |= BIT(conf->radio_idx);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
return __ieee80211_get_radio_mask(sdata);
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx)
|
||||
{
|
||||
if (radio_idx < 0)
|
||||
return true;
|
||||
|
||||
return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee80211_fill_ifcomb_params(struct ieee80211_local *local,
|
||||
struct iface_combination_params *params,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata_iter;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
int total = !!sdata;
|
||||
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
||||
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
|
||||
continue;
|
||||
|
||||
if (params->radio_idx >= 0 &&
|
||||
ctx->conf.radio_idx != params->radio_idx)
|
||||
continue;
|
||||
|
||||
params->radar_detect |=
|
||||
ieee80211_chanctx_radar_detect(local, ctx);
|
||||
|
||||
if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE &&
|
||||
cfg80211_chandef_compatible(chandef, &ctx->conf.def))
|
||||
continue;
|
||||
|
||||
params->num_different_channels++;
|
||||
}
|
||||
|
||||
list_for_each_entry(sdata_iter, &local->interfaces, list) {
|
||||
struct wireless_dev *wdev_iter;
|
||||
|
||||
wdev_iter = &sdata_iter->wdev;
|
||||
|
||||
if (sdata_iter == sdata ||
|
||||
!ieee80211_sdata_running(sdata_iter) ||
|
||||
cfg80211_iftype_allowed(local->hw.wiphy,
|
||||
wdev_iter->iftype, 0, 1))
|
||||
continue;
|
||||
|
||||
if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx))
|
||||
continue;
|
||||
|
||||
params->iftype_num[wdev_iter->iftype]++;
|
||||
total++;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
enum ieee80211_chanctx_mode chanmode,
|
||||
u8 radar_detect)
|
||||
u8 radar_detect, int radio_idx)
|
||||
{
|
||||
bool shared = chanmode == IEEE80211_CHANCTX_SHARED;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *sdata_iter;
|
||||
enum nl80211_iftype iftype = sdata->wdev.iftype;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
int total = 1;
|
||||
struct iface_combination_params params = {
|
||||
.radar_detect = radar_detect,
|
||||
.radio_idx = -1,
|
||||
.radio_idx = radio_idx,
|
||||
};
|
||||
int total;
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
@ -3982,37 +4065,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
||||
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
|
||||
params.iftype_num[iftype] = 1;
|
||||
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
||||
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
|
||||
continue;
|
||||
params.radar_detect |=
|
||||
ieee80211_chanctx_radar_detect(local, ctx);
|
||||
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
|
||||
params.num_different_channels++;
|
||||
continue;
|
||||
}
|
||||
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
|
||||
cfg80211_chandef_compatible(chandef,
|
||||
&ctx->conf.def))
|
||||
continue;
|
||||
params.num_different_channels++;
|
||||
}
|
||||
|
||||
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
|
||||
struct wireless_dev *wdev_iter;
|
||||
|
||||
wdev_iter = &sdata_iter->wdev;
|
||||
|
||||
if (sdata_iter == sdata ||
|
||||
!ieee80211_sdata_running(sdata_iter) ||
|
||||
cfg80211_iftype_allowed(local->hw.wiphy,
|
||||
wdev_iter->iftype, 0, 1))
|
||||
continue;
|
||||
|
||||
params.iftype_num[wdev_iter->iftype]++;
|
||||
total++;
|
||||
}
|
||||
|
||||
total = ieee80211_fill_ifcomb_params(local, ¶ms,
|
||||
shared ? chandef : NULL,
|
||||
sdata);
|
||||
if (total == 1 && !params.radar_detect)
|
||||
return 0;
|
||||
|
||||
@ -4029,30 +4084,17 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
|
||||
c->num_different_channels);
|
||||
}
|
||||
|
||||
int ieee80211_max_num_channels(struct ieee80211_local *local)
|
||||
int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_chanctx *ctx;
|
||||
u32 max_num_different_channels = 1;
|
||||
int err;
|
||||
struct iface_combination_params params = {
|
||||
.radio_idx = -1,
|
||||
.radio_idx = radio_idx,
|
||||
};
|
||||
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
||||
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
|
||||
continue;
|
||||
|
||||
params.num_different_channels++;
|
||||
|
||||
params.radar_detect |=
|
||||
ieee80211_chanctx_radar_detect(local, ctx);
|
||||
}
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
params.iftype_num[sdata->wdev.iftype]++;
|
||||
ieee80211_fill_ifcomb_params(local, ¶ms, NULL, NULL);
|
||||
|
||||
err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
|
||||
ieee80211_iter_max_chans,
|
||||
|
Loading…
Reference in New Issue
Block a user