168cf6fad09b8609b38174158d6f9022f4ba6966
[openwrt/staging/ldir.git] /
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
4 multi-radio
5
6 Add support for counting global and per-radio max/current number of
7 channels, as well as checking radio-specific interface combinations.
8
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 ---
11
12 --- a/net/mac80211/cfg.c
13 +++ b/net/mac80211/cfg.c
14 @@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(st
15
16 lockdep_assert_wiphy(sdata->local->hw.wiphy);
17
18 - ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
19 + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
20 if (ret < 0)
21 return ret;
22
23 @@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wi
24
25 lockdep_assert_wiphy(sdata->local->hw.wiphy);
26
27 - ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
28 + ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
29 if (ret < 0)
30 return ret;
31
32 @@ -3992,7 +3992,7 @@ __ieee80211_channel_switch(struct wiphy
33 goto out;
34
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);
38 if (err) {
39 ieee80211_link_unreserve_chanctx(link_data);
40 goto out;
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,
46 };
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);
51 }
52
53 -static int ieee80211_num_chanctx(struct ieee80211_local *local)
54 +static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
55 {
56 struct ieee80211_chanctx *ctx;
57 int num = 0;
58
59 lockdep_assert_wiphy(local->hw.wiphy);
60
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)
64 + continue;
65 num++;
66 + }
67
68 return num;
69 }
70
71 -static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
72 +static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
73 + int radio_idx)
74 {
75 lockdep_assert_wiphy(local->hw.wiphy);
76
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);
80 }
81
82 static struct ieee80211_chanctx *
83 @@ -1045,7 +1050,7 @@ int ieee80211_link_reserve_chanctx(struc
84
85 new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
86 if (!new_ctx) {
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);
90 if (IS_ERR(new_ctx))
91 return PTR_ERR(new_ctx);
92 @@ -1736,7 +1741,7 @@ int ieee80211_link_use_channel(struct ie
93 link->radar_required = ret;
94
95 ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
96 - radar_detect_width);
97 + radar_detect_width, -1);
98 if (ret < 0)
99 goto out;
100
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;
105
106 ret = ieee80211_check_combinations(sdata, &params->chandef, chanmode,
107 - radar_detect_width);
108 + radar_detect_width, -1);
109 if (ret < 0)
110 return ret;
111
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,
118 - u8 radar_detect);
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);
125
126 --- a/net/mac80211/iface.c
127 +++ b/net/mac80211/iface.c
128 @@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_if
129 }
130 }
131
132 - return ieee80211_check_combinations(sdata, NULL, 0, 0);
133 + return ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
134 }
135
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
140 return radar_detect;
141 }
142
143 +static u32
144 +__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
145 +{
146 + struct ieee80211_bss_conf *link_conf;
147 + struct ieee80211_chanctx_conf *conf;
148 + unsigned int link_id;
149 + u32 mask = 0;
150 +
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)
154 + continue;
155 +
156 + mask |= BIT(conf->radio_idx);
157 + }
158 +
159 + return mask;
160 +}
161 +
162 +u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev)
163 +{
164 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
165 +
166 + return __ieee80211_get_radio_mask(sdata);
167 +}
168 +
169 +static bool
170 +ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx)
171 +{
172 + if (radio_idx < 0)
173 + return true;
174 +
175 + return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx);
176 +}
177 +
178 +static int
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)
183 +{
184 + struct ieee80211_sub_if_data *sdata_iter;
185 + struct ieee80211_chanctx *ctx;
186 + int total = !!sdata;
187 +
188 + list_for_each_entry(ctx, &local->chanctx_list, list) {
189 + if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
190 + continue;
191 +
192 + if (params->radio_idx >= 0 &&
193 + ctx->conf.radio_idx != params->radio_idx)
194 + continue;
195 +
196 + params->radar_detect |=
197 + ieee80211_chanctx_radar_detect(local, ctx);
198 +
199 + if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE &&
200 + cfg80211_chandef_compatible(chandef, &ctx->conf.def))
201 + continue;
202 +
203 + params->num_different_channels++;
204 + }
205 +
206 + list_for_each_entry(sdata_iter, &local->interfaces, list) {
207 + struct wireless_dev *wdev_iter;
208 +
209 + wdev_iter = &sdata_iter->wdev;
210 +
211 + if (sdata_iter == sdata ||
212 + !ieee80211_sdata_running(sdata_iter) ||
213 + cfg80211_iftype_allowed(local->hw.wiphy,
214 + wdev_iter->iftype, 0, 1))
215 + continue;
216 +
217 + if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx))
218 + continue;
219 +
220 + params->iftype_num[wdev_iter->iftype]++;
221 + total++;
222 + }
223 +
224 + return total;
225 +}
226 +
227 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
228 const struct cfg80211_chan_def *chandef,
229 enum ieee80211_chanctx_mode chanmode,
230 - u8 radar_detect)
231 + u8 radar_detect, int radio_idx)
232 {
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;
238 - int total = 1;
239 struct iface_combination_params params = {
240 .radar_detect = radar_detect,
241 - .radio_idx = -1,
242 + .radio_idx = radio_idx,
243 };
244 + int total;
245
246 lockdep_assert_wiphy(local->hw.wiphy);
247
248 @@ -3968,37 +4051,9 @@ int ieee80211_check_combinations(struct
249 if (iftype != NL80211_IFTYPE_UNSPECIFIED)
250 params.iftype_num[iftype] = 1;
251
252 - list_for_each_entry(ctx, &local->chanctx_list, list) {
253 - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
254 - continue;
255 - params.radar_detect |=
256 - ieee80211_chanctx_radar_detect(local, ctx);
257 - if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
258 - params.num_different_channels++;
259 - continue;
260 - }
261 - if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
262 - cfg80211_chandef_compatible(chandef,
263 - &ctx->conf.def))
264 - continue;
265 - params.num_different_channels++;
266 - }
267 -
268 - list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
269 - struct wireless_dev *wdev_iter;
270 -
271 - wdev_iter = &sdata_iter->wdev;
272 -
273 - if (sdata_iter == sdata ||
274 - !ieee80211_sdata_running(sdata_iter) ||
275 - cfg80211_iftype_allowed(local->hw.wiphy,
276 - wdev_iter->iftype, 0, 1))
277 - continue;
278 -
279 - params.iftype_num[wdev_iter->iftype]++;
280 - total++;
281 - }
282 -
283 + total = ieee80211_fill_ifcomb_params(local, &params,
284 + shared ? chandef : NULL,
285 + sdata);
286 if (total == 1 && !params.radar_detect)
287 return 0;
288
289 @@ -4015,30 +4070,17 @@ ieee80211_iter_max_chans(const struct ie
290 c->num_different_channels);
291 }
292
293 -int ieee80211_max_num_channels(struct ieee80211_local *local)
294 +int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx)
295 {
296 - struct ieee80211_sub_if_data *sdata;
297 - struct ieee80211_chanctx *ctx;
298 u32 max_num_different_channels = 1;
299 int err;
300 struct iface_combination_params params = {
301 - .radio_idx = -1,
302 + .radio_idx = radio_idx,
303 };
304
305 lockdep_assert_wiphy(local->hw.wiphy);
306
307 - list_for_each_entry(ctx, &local->chanctx_list, list) {
308 - if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
309 - continue;
310 -
311 - params.num_different_channels++;
312 -
313 - params.radar_detect |=
314 - ieee80211_chanctx_radar_detect(local, ctx);
315 - }
316 -
317 - list_for_each_entry_rcu(sdata, &local->interfaces, list)
318 - params.iftype_num[sdata->wdev.iftype]++;
319 + ieee80211_fill_ifcomb_params(local, &params, NULL, NULL);
320
321 err = cfg80211_iter_combinations(local->hw.wiphy, &params,
322 ieee80211_iter_max_chans,