mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:38:03 +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);
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wiphy *wiphy,
|
|||||||
|
|
||||||
lockdep_assert_wiphy(sdata->local->hw.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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -4008,7 +4008,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* if reservation is invalid then this will fail */
|
/* 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) {
|
if (err) {
|
||||||
ieee80211_link_unreserve_chanctx(link_data);
|
ieee80211_link_unreserve_chanctx(link_data);
|
||||||
goto out;
|
goto out;
|
||||||
@ -5203,4 +5203,5 @@ const struct cfg80211_ops mac80211_config_ops = {
|
|||||||
.del_link_station = ieee80211_del_link_station,
|
.del_link_station = ieee80211_del_link_station,
|
||||||
.set_hw_timestamp = ieee80211_set_hw_timestamp,
|
.set_hw_timestamp = ieee80211_set_hw_timestamp,
|
||||||
.set_ttlm = ieee80211_set_ttlm,
|
.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);
|
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;
|
struct ieee80211_chanctx *ctx;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
lockdep_assert_wiphy(local->hw.wiphy);
|
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++;
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
return 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);
|
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 *
|
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);
|
new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
|
||||||
if (!new_ctx) {
|
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,
|
new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
|
||||||
false);
|
false);
|
||||||
if (IS_ERR(new_ctx))
|
if (IS_ERR(new_ctx))
|
||||||
@ -1822,7 +1827,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
|
|||||||
link->radar_required = ret;
|
link->radar_required = ret;
|
||||||
|
|
||||||
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
|
ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
|
||||||
radar_detect_width);
|
radar_detect_width, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -1746,7 +1746,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|||||||
IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
|
IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
|
||||||
|
|
||||||
ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode,
|
ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode,
|
||||||
radar_detect_width);
|
radar_detect_width, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -2640,8 +2640,9 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
|
|||||||
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
enum ieee80211_chanctx_mode chanmode,
|
enum ieee80211_chanctx_mode chanmode,
|
||||||
u8 radar_detect);
|
u8 radar_detect, int radio_idx);
|
||||||
int ieee80211_max_num_channels(struct ieee80211_local *local);
|
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,
|
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
|
||||||
struct ieee80211_chanctx *ctx);
|
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,
|
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;
|
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,
|
int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
enum ieee80211_chanctx_mode chanmode,
|
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_local *local = sdata->local;
|
||||||
struct ieee80211_sub_if_data *sdata_iter;
|
|
||||||
enum nl80211_iftype iftype = sdata->wdev.iftype;
|
enum nl80211_iftype iftype = sdata->wdev.iftype;
|
||||||
struct ieee80211_chanctx *ctx;
|
|
||||||
int total = 1;
|
|
||||||
struct iface_combination_params params = {
|
struct iface_combination_params params = {
|
||||||
.radar_detect = radar_detect,
|
.radar_detect = radar_detect,
|
||||||
.radio_idx = -1,
|
.radio_idx = radio_idx,
|
||||||
};
|
};
|
||||||
|
int total;
|
||||||
|
|
||||||
lockdep_assert_wiphy(local->hw.wiphy);
|
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)
|
if (iftype != NL80211_IFTYPE_UNSPECIFIED)
|
||||||
params.iftype_num[iftype] = 1;
|
params.iftype_num[iftype] = 1;
|
||||||
|
|
||||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
total = ieee80211_fill_ifcomb_params(local, ¶ms,
|
||||||
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
|
shared ? chandef : NULL,
|
||||||
continue;
|
sdata);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total == 1 && !params.radar_detect)
|
if (total == 1 && !params.radar_detect)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -4029,30 +4084,17 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
|
|||||||
c->num_different_channels);
|
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;
|
u32 max_num_different_channels = 1;
|
||||||
int err;
|
int err;
|
||||||
struct iface_combination_params params = {
|
struct iface_combination_params params = {
|
||||||
.radio_idx = -1,
|
.radio_idx = radio_idx,
|
||||||
};
|
};
|
||||||
|
|
||||||
lockdep_assert_wiphy(local->hw.wiphy);
|
lockdep_assert_wiphy(local->hw.wiphy);
|
||||||
|
|
||||||
list_for_each_entry(ctx, &local->chanctx_list, list) {
|
ieee80211_fill_ifcomb_params(local, ¶ms, NULL, NULL);
|
||||||
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]++;
|
|
||||||
|
|
||||||
err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
|
err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
|
||||||
ieee80211_iter_max_chans,
|
ieee80211_iter_max_chans,
|
||||||
|
Loading…
Reference in New Issue
Block a user