1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Tue, 4 Jun 2024 21:48:48 +0200
3 Subject: [PATCH] wifi: mac80211: extend ifcomb check functions for
6 Add support for counting global and per-radio max/current number of
7 channels, as well as checking radio-specific interface combinations.
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
12 --- a/net/mac80211/cfg.c
13 +++ b/net/mac80211/cfg.c
14 @@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(st
16 lockdep_assert_wiphy(sdata->local->hw.wiphy);
18 - ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
19 + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
23 @@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wi
25 lockdep_assert_wiphy(sdata->local->hw.wiphy);
27 - ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
28 + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
32 @@ -3992,7 +3992,7 @@ __ieee80211_channel_switch(struct wiphy
35 /* if reservation is invalid then this will fail */
36 - err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
37 + err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1);
39 ieee80211_link_unreserve_chanctx(link_data);
41 @@ -5161,4 +5161,5 @@ const struct cfg80211_ops mac80211_confi
42 .del_link_station = ieee80211_del_link_station,
43 .set_hw_timestamp = ieee80211_set_hw_timestamp,
44 .set_ttlm = ieee80211_set_ttlm,
45 + .get_radio_mask = ieee80211_get_radio_mask,
47 --- a/net/mac80211/chan.c
48 +++ b/net/mac80211/chan.c
49 @@ -47,24 +47,29 @@ int ieee80211_chanctx_refcount(struct ie
50 ieee80211_chanctx_num_reserved(local, ctx);
53 -static int ieee80211_num_chanctx(struct ieee80211_local *local)
54 +static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
56 struct ieee80211_chanctx *ctx;
59 lockdep_assert_wiphy(local->hw.wiphy);
61 - list_for_each_entry(ctx, &local->chanctx_list, list)
62 + list_for_each_entry(ctx, &local->chanctx_list, list) {
63 + if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
71 -static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
72 +static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
75 lockdep_assert_wiphy(local->hw.wiphy);
77 - return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
78 + return ieee80211_num_chanctx(local, radio_idx) <
79 + ieee80211_max_num_channels(local, radio_idx);
82 static struct ieee80211_chanctx *
83 @@ -1045,7 +1050,7 @@ int ieee80211_link_reserve_chanctx(struc
85 new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
87 - if (ieee80211_can_create_new_chanctx(local)) {
88 + if (ieee80211_can_create_new_chanctx(local, -1)) {
89 new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
91 return PTR_ERR(new_ctx);
92 @@ -1736,7 +1741,7 @@ int ieee80211_link_use_channel(struct ie
93 link->radar_required = ret;
95 ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
96 - radar_detect_width);
97 + radar_detect_width, -1);
101 --- a/net/mac80211/ibss.c
102 +++ b/net/mac80211/ibss.c
103 @@ -1745,7 +1745,7 @@ int ieee80211_ibss_join(struct ieee80211
104 IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
106 ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode,
107 - radar_detect_width);
108 + radar_detect_width, -1);
112 --- a/net/mac80211/ieee80211_i.h
113 +++ b/net/mac80211/ieee80211_i.h
114 @@ -2596,8 +2596,9 @@ void ieee80211_recalc_dtim(struct ieee80
115 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
116 const struct cfg80211_chan_def *chandef,
117 enum ieee80211_chanctx_mode chanmode,
119 -int ieee80211_max_num_channels(struct ieee80211_local *local);
120 + u8 radar_detect, int radio_idx);
121 +int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx);
122 +u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev);
123 void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
124 struct ieee80211_chanctx *ctx);
126 --- a/net/mac80211/iface.c
127 +++ b/net/mac80211/iface.c
128 @@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_if
132 - return ieee80211_check_combinations(sdata, NULL, 0, 0);
133 + return ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
136 static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
137 --- a/net/mac80211/util.c
138 +++ b/net/mac80211/util.c
139 @@ -3918,20 +3918,103 @@ static u8 ieee80211_chanctx_radar_detect
144 +__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
146 + struct ieee80211_bss_conf *link_conf;
147 + struct ieee80211_chanctx_conf *conf;
148 + unsigned int link_id;
151 + for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
152 + conf = sdata_dereference(link_conf->chanctx_conf, sdata);
153 + if (!conf || conf->radio_idx < 0)
156 + mask |= BIT(conf->radio_idx);
162 +u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev)
164 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
166 + return __ieee80211_get_radio_mask(sdata);
170 +ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx)
175 + return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx);
179 +ieee80211_fill_ifcomb_params(struct ieee80211_local *local,
180 + struct iface_combination_params *params,
181 + const struct cfg80211_chan_def *chandef,
182 + struct ieee80211_sub_if_data *sdata)
184 + struct ieee80211_sub_if_data *sdata_iter;
185 + struct ieee80211_chanctx *ctx;
186 + int total = !!sdata;
188 + list_for_each_entry(ctx, &local->chanctx_list, list) {
189 + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
192 + if (params->radio_idx >= 0 &&
193 + ctx->conf.radio_idx != params->radio_idx)
196 + params->radar_detect |=
197 + ieee80211_chanctx_radar_detect(local, ctx);
199 + if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE &&
200 + cfg80211_chandef_compatible(chandef, &ctx->conf.def))
203 + params->num_different_channels++;
206 + list_for_each_entry(sdata_iter, &local->interfaces, list) {
207 + struct wireless_dev *wdev_iter;
209 + wdev_iter = &sdata_iter->wdev;
211 + if (sdata_iter == sdata ||
212 + !ieee80211_sdata_running(sdata_iter) ||
213 + cfg80211_iftype_allowed(local->hw.wiphy,
214 + wdev_iter->iftype, 0, 1))
217 + if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx))
220 + params->iftype_num[wdev_iter->iftype]++;
227 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
228 const struct cfg80211_chan_def *chandef,
229 enum ieee80211_chanctx_mode chanmode,
231 + u8 radar_detect, int radio_idx)
233 + bool shared = chanmode == IEEE80211_CHANCTX_SHARED;
234 struct ieee80211_local *local = sdata->local;
235 - struct ieee80211_sub_if_data *sdata_iter;
236 enum nl80211_iftype iftype = sdata->wdev.iftype;
237 - struct ieee80211_chanctx *ctx;
239 struct iface_combination_params params = {
240 .radar_detect = radar_detect,
242 + .radio_idx = radio_idx,
246 lockdep_assert_wiphy(local->hw.wiphy);
248 @@ -3968,37 +4051,9 @@ int ieee80211_check_combinations(struct
249 if (iftype != NL80211_IFTYPE_UNSPECIFIED)
250 params.iftype_num[iftype] = 1;
252 - list_for_each_entry(ctx, &local->chanctx_list, list) {
253 - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
255 - params.radar_detect |=
256 - ieee80211_chanctx_radar_detect(local, ctx);
257 - if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
258 - params.num_different_channels++;
261 - if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
262 - cfg80211_chandef_compatible(chandef,
265 - params.num_different_channels++;
268 - list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
269 - struct wireless_dev *wdev_iter;
271 - wdev_iter = &sdata_iter->wdev;
273 - if (sdata_iter == sdata ||
274 - !ieee80211_sdata_running(sdata_iter) ||
275 - cfg80211_iftype_allowed(local->hw.wiphy,
276 - wdev_iter->iftype, 0, 1))
279 - params.iftype_num[wdev_iter->iftype]++;
283 + total = ieee80211_fill_ifcomb_params(local, ¶ms,
284 + shared ? chandef : NULL,
286 if (total == 1 && !params.radar_detect)
289 @@ -4015,30 +4070,17 @@ ieee80211_iter_max_chans(const struct ie
290 c->num_different_channels);
293 -int ieee80211_max_num_channels(struct ieee80211_local *local)
294 +int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx)
296 - struct ieee80211_sub_if_data *sdata;
297 - struct ieee80211_chanctx *ctx;
298 u32 max_num_different_channels = 1;
300 struct iface_combination_params params = {
302 + .radio_idx = radio_idx,
305 lockdep_assert_wiphy(local->hw.wiphy);
307 - list_for_each_entry(ctx, &local->chanctx_list, list) {
308 - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
311 - params.num_different_channels++;
313 - params.radar_detect |=
314 - ieee80211_chanctx_radar_detect(local, ctx);
317 - list_for_each_entry_rcu(sdata, &local->interfaces, list)
318 - params.iftype_num[sdata->wdev.iftype]++;
319 + ieee80211_fill_ifcomb_params(local, ¶ms, NULL, NULL);
321 err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
322 ieee80211_iter_max_chans,