Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * mac80211 - channel management
4 * Copyright 2020 - 2025 Intel Corporation
5 */
6
7#include <linux/nl80211.h>
8#include <linux/export.h>
9#include <linux/rtnetlink.h>
10#include <net/cfg80211.h>
11#include "ieee80211_i.h"
12#include "driver-ops.h"
13#include "rate.h"
14
15struct ieee80211_chanctx_user_iter {
16 struct ieee80211_chan_req *chanreq;
17 struct ieee80211_sub_if_data *sdata;
18 struct ieee80211_link_data *link;
19 enum nl80211_iftype iftype;
20 bool reserved, radar_required, done;
21 enum {
22 CHANCTX_ITER_POS_ASSIGNED,
23 CHANCTX_ITER_POS_RESERVED,
24 CHANCTX_ITER_POS_DONE,
25 } per_link;
26};
27
28enum ieee80211_chanctx_iter_type {
29 CHANCTX_ITER_ALL,
30 CHANCTX_ITER_RESERVED,
31 CHANCTX_ITER_ASSIGNED,
32};
33
34static void ieee80211_chanctx_user_iter_next(struct ieee80211_local *local,
35 struct ieee80211_chanctx *ctx,
36 struct ieee80211_chanctx_user_iter *iter,
37 enum ieee80211_chanctx_iter_type type,
38 bool start)
39{
40 lockdep_assert_wiphy(local->hw.wiphy);
41
42 if (start) {
43 memset(iter, 0, sizeof(*iter));
44 goto next_interface;
45 }
46
47next_link:
48 for (int link_id = iter->link ? iter->link->link_id : 0;
49 link_id < ARRAY_SIZE(iter->sdata->link);
50 link_id++) {
51 struct ieee80211_link_data *link;
52
53 link = sdata_dereference(iter->sdata->link[link_id],
54 iter->sdata);
55 if (!link)
56 continue;
57
58 switch (iter->per_link) {
59 case CHANCTX_ITER_POS_ASSIGNED:
60 iter->per_link = CHANCTX_ITER_POS_RESERVED;
61 if (type != CHANCTX_ITER_RESERVED &&
62 rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
63 iter->link = link;
64 iter->reserved = false;
65 iter->radar_required = link->radar_required;
66 iter->chanreq = &link->conf->chanreq;
67 return;
68 }
69 fallthrough;
70 case CHANCTX_ITER_POS_RESERVED:
71 iter->per_link = CHANCTX_ITER_POS_DONE;
72 if (type != CHANCTX_ITER_ASSIGNED &&
73 link->reserved_chanctx == ctx) {
74 iter->link = link;
75 iter->reserved = true;
76 iter->radar_required =
77 link->reserved_radar_required;
78
79 iter->chanreq = &link->reserved;
80 return;
81 }
82 fallthrough;
83 case CHANCTX_ITER_POS_DONE:
84 iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
85 continue;
86 }
87 }
88
89next_interface:
90 /* next (or first) interface */
91 iter->sdata = list_prepare_entry(iter->sdata, &local->interfaces, list);
92 list_for_each_entry_continue(iter->sdata, &local->interfaces, list) {
93 if (!ieee80211_sdata_running(iter->sdata))
94 continue;
95
96 /* AP_VLAN has a chanctx pointer but follows AP */
97 if (iter->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
98 continue;
99
100 iter->link = NULL;
101 iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
102 iter->iftype = iter->sdata->vif.type;
103 goto next_link;
104 }
105
106 iter->done = true;
107}
108
109#define for_each_chanctx_user_assigned(local, ctx, iter) \
110 for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
111 CHANCTX_ITER_ASSIGNED, \
112 true); \
113 !((iter)->done); \
114 ieee80211_chanctx_user_iter_next(local, ctx, iter, \
115 CHANCTX_ITER_ASSIGNED, \
116 false))
117
118#define for_each_chanctx_user_reserved(local, ctx, iter) \
119 for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
120 CHANCTX_ITER_RESERVED, \
121 true); \
122 !((iter)->done); \
123 ieee80211_chanctx_user_iter_next(local, ctx, iter, \
124 CHANCTX_ITER_RESERVED, \
125 false))
126
127#define for_each_chanctx_user_all(local, ctx, iter) \
128 for (ieee80211_chanctx_user_iter_next(local, ctx, iter, \
129 CHANCTX_ITER_ALL, \
130 true); \
131 !((iter)->done); \
132 ieee80211_chanctx_user_iter_next(local, ctx, iter, \
133 CHANCTX_ITER_ALL, \
134 false))
135
136static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
137 struct ieee80211_chanctx *ctx)
138{
139 struct ieee80211_chanctx_user_iter iter;
140 int num = 0;
141
142 for_each_chanctx_user_assigned(local, ctx, &iter)
143 num++;
144
145 return num;
146}
147
148static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
149 struct ieee80211_chanctx *ctx)
150{
151 struct ieee80211_chanctx_user_iter iter;
152 int num = 0;
153
154 for_each_chanctx_user_reserved(local, ctx, &iter)
155 num++;
156
157 return num;
158}
159
160int ieee80211_chanctx_refcount(struct ieee80211_local *local,
161 struct ieee80211_chanctx *ctx)
162{
163 struct ieee80211_chanctx_user_iter iter;
164 int num = 0;
165
166 for_each_chanctx_user_all(local, ctx, &iter)
167 num++;
168
169 return num;
170}
171
172static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
173{
174 struct ieee80211_chanctx *ctx;
175 int num = 0;
176
177 lockdep_assert_wiphy(local->hw.wiphy);
178
179 list_for_each_entry(ctx, &local->chanctx_list, list) {
180 if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
181 continue;
182 num++;
183 }
184
185 return num;
186}
187
188static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
189 int radio_idx)
190{
191 lockdep_assert_wiphy(local->hw.wiphy);
192
193 return ieee80211_num_chanctx(local, radio_idx) <
194 ieee80211_max_num_channels(local, radio_idx);
195}
196
197static struct ieee80211_chanctx *
198ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
199{
200 struct ieee80211_local *local __maybe_unused = link->sdata->local;
201 struct ieee80211_chanctx_conf *conf;
202
203 conf = rcu_dereference_protected(link->conf->chanctx_conf,
204 lockdep_is_held(&local->hw.wiphy->mtx));
205 if (!conf)
206 return NULL;
207
208 return container_of(conf, struct ieee80211_chanctx, conf);
209}
210
211bool ieee80211_chanreq_identical(const struct ieee80211_chan_req *a,
212 const struct ieee80211_chan_req *b)
213{
214 if (!cfg80211_chandef_identical(&a->oper, &b->oper))
215 return false;
216 if (!a->ap.chan && !b->ap.chan)
217 return true;
218 return cfg80211_chandef_identical(&a->ap, &b->ap);
219}
220
221static const struct ieee80211_chan_req *
222ieee80211_chanreq_compatible(const struct ieee80211_chan_req *a,
223 const struct ieee80211_chan_req *b,
224 struct ieee80211_chan_req *tmp)
225{
226 const struct cfg80211_chan_def *compat;
227
228 if (a->ap.chan && b->ap.chan &&
229 !cfg80211_chandef_identical(&a->ap, &b->ap))
230 return NULL;
231
232 compat = cfg80211_chandef_compatible(&a->oper, &b->oper);
233 if (!compat)
234 return NULL;
235
236 /* Note: later code assumes this always fills & returns tmp if compat */
237 tmp->oper = *compat;
238 tmp->ap = a->ap.chan ? a->ap : b->ap;
239 return tmp;
240}
241
242static const struct ieee80211_chan_req *
243ieee80211_chanctx_compatible(struct ieee80211_chanctx *ctx,
244 const struct ieee80211_chan_req *req,
245 struct ieee80211_chan_req *tmp)
246{
247 const struct ieee80211_chan_req *ret;
248 struct ieee80211_chan_req tmp2;
249
250 *tmp = (struct ieee80211_chan_req){
251 .oper = ctx->conf.def,
252 .ap = ctx->conf.ap,
253 };
254
255 ret = ieee80211_chanreq_compatible(tmp, req, &tmp2);
256 if (!ret)
257 return NULL;
258 *tmp = *ret;
259 return tmp;
260}
261
262static const struct ieee80211_chan_req *
263ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local,
264 struct ieee80211_chanctx *ctx,
265 const struct ieee80211_chan_req *req,
266 struct ieee80211_chan_req *tmp)
267{
268 struct ieee80211_chanctx_user_iter iter;
269
270 lockdep_assert_wiphy(local->hw.wiphy);
271
272 if (WARN_ON(!req))
273 return NULL;
274
275 for_each_chanctx_user_reserved(local, ctx, &iter) {
276 req = ieee80211_chanreq_compatible(iter.chanreq, req, tmp);
277 if (!req)
278 break;
279 }
280
281 return req;
282}
283
284static const struct ieee80211_chan_req *
285ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
286 struct ieee80211_chanctx *ctx,
287 const struct ieee80211_chan_req *compat,
288 struct ieee80211_chan_req *tmp)
289{
290 const struct ieee80211_chan_req *comp_def = compat;
291 struct ieee80211_chanctx_user_iter iter;
292
293 lockdep_assert_wiphy(local->hw.wiphy);
294
295 for_each_chanctx_user_assigned(local, ctx, &iter) {
296 if (iter.link->reserved_chanctx)
297 continue;
298
299 comp_def = ieee80211_chanreq_compatible(iter.chanreq,
300 comp_def, tmp);
301 if (!comp_def)
302 break;
303 }
304
305 return comp_def;
306}
307
308static bool
309ieee80211_chanctx_can_reserve(struct ieee80211_local *local,
310 struct ieee80211_chanctx *ctx,
311 const struct ieee80211_chan_req *req)
312{
313 struct ieee80211_chan_req tmp;
314
315 lockdep_assert_wiphy(local->hw.wiphy);
316
317 if (!ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
318 return false;
319
320 if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req, &tmp))
321 return false;
322
323 if (ieee80211_chanctx_num_reserved(local, ctx) != 0 &&
324 ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
325 return true;
326
327 return false;
328}
329
330static struct ieee80211_chanctx *
331ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
332 const struct ieee80211_chan_req *chanreq,
333 enum ieee80211_chanctx_mode mode)
334{
335 struct ieee80211_chanctx *ctx;
336
337 lockdep_assert_wiphy(local->hw.wiphy);
338
339 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
340 return NULL;
341
342 list_for_each_entry(ctx, &local->chanctx_list, list) {
343 if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
344 continue;
345
346 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
347 continue;
348
349 if (!ieee80211_chanctx_can_reserve(local, ctx, chanreq))
350 continue;
351
352 return ctx;
353 }
354
355 return NULL;
356}
357
358static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
359 unsigned int link_id)
360{
361 enum ieee80211_sta_rx_bandwidth width;
362 struct link_sta_info *link_sta;
363
364 link_sta = wiphy_dereference(sta->local->hw.wiphy, sta->link[link_id]);
365
366 /* no effect if this STA has no presence on this link */
367 if (!link_sta)
368 return NL80211_CHAN_WIDTH_20_NOHT;
369
370 /*
371 * We assume that TX/RX might be asymmetric (so e.g. VHT operating
372 * mode notification changes what a STA wants to receive, but not
373 * necessarily what it will transmit to us), and therefore use the
374 * capabilities here. Calling it RX bandwidth capability is a bit
375 * wrong though, since capabilities are in fact symmetric.
376 */
377 width = ieee80211_sta_cap_rx_bw(link_sta);
378
379 switch (width) {
380 case IEEE80211_STA_RX_BW_20:
381 if (link_sta->pub->ht_cap.ht_supported)
382 return NL80211_CHAN_WIDTH_20;
383 else
384 return NL80211_CHAN_WIDTH_20_NOHT;
385 case IEEE80211_STA_RX_BW_40:
386 return NL80211_CHAN_WIDTH_40;
387 case IEEE80211_STA_RX_BW_80:
388 return NL80211_CHAN_WIDTH_80;
389 case IEEE80211_STA_RX_BW_160:
390 /*
391 * This applied for both 160 and 80+80. since we use
392 * the returned value to consider degradation of
393 * ctx->conf.min_def, we have to make sure to take
394 * the bigger one (NL80211_CHAN_WIDTH_160).
395 * Otherwise we might try degrading even when not
396 * needed, as the max required sta_bw returned (80+80)
397 * might be smaller than the configured bw (160).
398 */
399 return NL80211_CHAN_WIDTH_160;
400 case IEEE80211_STA_RX_BW_320:
401 return NL80211_CHAN_WIDTH_320;
402 default:
403 WARN_ON(1);
404 return NL80211_CHAN_WIDTH_20;
405 }
406}
407
408static enum nl80211_chan_width
409ieee80211_get_max_required_bw(struct ieee80211_link_data *link)
410{
411 struct ieee80211_sub_if_data *sdata = link->sdata;
412 unsigned int link_id = link->link_id;
413 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
414 struct sta_info *sta;
415
416 lockdep_assert_wiphy(sdata->local->hw.wiphy);
417
418 list_for_each_entry(sta, &sdata->local->sta_list, list) {
419 if (sdata != sta->sdata &&
420 !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
421 continue;
422
423 max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
424 }
425
426 return max_bw;
427}
428
429static enum nl80211_chan_width
430ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
431 struct ieee80211_chanctx *ctx,
432 struct ieee80211_link_data *rsvd_for,
433 bool check_reserved)
434{
435 struct ieee80211_sub_if_data *sdata;
436 struct ieee80211_link_data *link;
437 enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
438
439 if (WARN_ON(check_reserved && rsvd_for))
440 return ctx->conf.def.width;
441
442 for_each_sdata_link(local, link) {
443 enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
444
445 if (check_reserved) {
446 if (link->reserved_chanctx != ctx)
447 continue;
448 } else if (link != rsvd_for &&
449 rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
450 continue;
451
452 switch (link->sdata->vif.type) {
453 case NL80211_IFTYPE_STATION:
454 if (!link->sdata->vif.cfg.assoc) {
455 /*
456 * The AP's sta->bandwidth may not yet be set
457 * at this point (pre-association), so simply
458 * take the width from the chandef. We cannot
459 * have TDLS peers yet (only after association).
460 */
461 width = link->conf->chanreq.oper.width;
462 break;
463 }
464 /*
465 * otherwise just use min_def like in AP, depending on what
466 * we currently think the AP STA (and possibly TDLS peers)
467 * require(s)
468 */
469 fallthrough;
470 case NL80211_IFTYPE_AP:
471 case NL80211_IFTYPE_AP_VLAN:
472 width = ieee80211_get_max_required_bw(link);
473 break;
474 case NL80211_IFTYPE_P2P_DEVICE:
475 case NL80211_IFTYPE_NAN:
476 continue;
477 case NL80211_IFTYPE_MONITOR:
478 WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
479 NO_VIRTUAL_MONITOR));
480 fallthrough;
481 case NL80211_IFTYPE_ADHOC:
482 case NL80211_IFTYPE_MESH_POINT:
483 case NL80211_IFTYPE_OCB:
484 width = link->conf->chanreq.oper.width;
485 break;
486 case NL80211_IFTYPE_WDS:
487 case NL80211_IFTYPE_UNSPECIFIED:
488 case NUM_NL80211_IFTYPES:
489 case NL80211_IFTYPE_P2P_CLIENT:
490 case NL80211_IFTYPE_P2P_GO:
491 WARN_ON_ONCE(1);
492 }
493
494 max_bw = max(max_bw, width);
495 }
496
497 /* use the configured bandwidth in case of monitor interface */
498 sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
499 if (sdata &&
500 rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &ctx->conf)
501 max_bw = max(max_bw, ctx->conf.def.width);
502
503 return max_bw;
504}
505
506/*
507 * recalc the min required chan width of the channel context, which is
508 * the max of min required widths of all the interfaces bound to this
509 * channel context.
510 */
511static u32
512__ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
513 struct ieee80211_chanctx *ctx,
514 struct ieee80211_link_data *rsvd_for,
515 bool check_reserved)
516{
517 enum nl80211_chan_width max_bw;
518 struct cfg80211_chan_def min_def;
519
520 lockdep_assert_wiphy(local->hw.wiphy);
521
522 /* don't optimize non-20MHz based and radar_enabled confs */
523 if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
524 ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
525 ctx->conf.def.width == NL80211_CHAN_WIDTH_1 ||
526 ctx->conf.def.width == NL80211_CHAN_WIDTH_2 ||
527 ctx->conf.def.width == NL80211_CHAN_WIDTH_4 ||
528 ctx->conf.def.width == NL80211_CHAN_WIDTH_8 ||
529 ctx->conf.def.width == NL80211_CHAN_WIDTH_16 ||
530 ctx->conf.radar_enabled) {
531 ctx->conf.min_def = ctx->conf.def;
532 return 0;
533 }
534
535 max_bw = ieee80211_get_chanctx_max_required_bw(local, ctx, rsvd_for,
536 check_reserved);
537
538 /* downgrade chandef up to max_bw */
539 min_def = ctx->conf.def;
540 while (min_def.width > max_bw)
541 ieee80211_chandef_downgrade(&min_def, NULL);
542
543 if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
544 return 0;
545
546 ctx->conf.min_def = min_def;
547 if (!ctx->driver_present)
548 return 0;
549
550 return IEEE80211_CHANCTX_CHANGE_MIN_DEF;
551}
552
553static void ieee80211_chan_bw_change(struct ieee80211_local *local,
554 struct ieee80211_chanctx *ctx,
555 bool reserved, bool narrowed)
556{
557 struct sta_info *sta;
558 struct ieee80211_supported_band *sband =
559 local->hw.wiphy->bands[ctx->conf.def.chan->band];
560
561 rcu_read_lock();
562 list_for_each_entry_rcu(sta, &local->sta_list,
563 list) {
564 struct ieee80211_sub_if_data *sdata = sta->sdata;
565 enum ieee80211_sta_rx_bandwidth new_sta_bw;
566 unsigned int link_id;
567
568 if (!ieee80211_sdata_running(sta->sdata))
569 continue;
570
571 for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
572 struct ieee80211_link_data *link =
573 rcu_dereference(sdata->link[link_id]);
574 struct ieee80211_bss_conf *link_conf;
575 struct cfg80211_chan_def *new_chandef;
576 struct link_sta_info *link_sta;
577
578 if (!link)
579 continue;
580
581 link_conf = link->conf;
582
583 if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
584 continue;
585
586 link_sta = rcu_dereference(sta->link[link_id]);
587 if (!link_sta)
588 continue;
589
590 if (reserved)
591 new_chandef = &link->reserved.oper;
592 else
593 new_chandef = &link_conf->chanreq.oper;
594
595 new_sta_bw = _ieee80211_sta_cur_vht_bw(link_sta,
596 new_chandef);
597
598 /* nothing change */
599 if (new_sta_bw == link_sta->pub->bandwidth)
600 continue;
601
602 /* vif changed to narrow BW and narrow BW for station wasn't
603 * requested or vice versa */
604 if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
605 continue;
606
607 link_sta->pub->bandwidth = new_sta_bw;
608 rate_control_rate_update(local, sband, link_sta,
609 IEEE80211_RC_BW_CHANGED);
610 }
611 }
612 rcu_read_unlock();
613}
614
615/*
616 * recalc the min required chan width of the channel context, which is
617 * the max of min required widths of all the interfaces bound to this
618 * channel context.
619 */
620static void
621_ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
622 struct ieee80211_chanctx *ctx,
623 struct ieee80211_link_data *rsvd_for,
624 bool check_reserved)
625{
626 u32 changed = __ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
627 check_reserved);
628
629 if (!changed)
630 return;
631
632 /* check is BW narrowed */
633 ieee80211_chan_bw_change(local, ctx, false, true);
634
635 drv_change_chanctx(local, ctx, changed);
636
637 /* check is BW wider */
638 ieee80211_chan_bw_change(local, ctx, false, false);
639}
640
641void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
642 struct ieee80211_chanctx *ctx)
643{
644 _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
645}
646
647static void _ieee80211_change_chanctx(struct ieee80211_local *local,
648 struct ieee80211_chanctx *ctx,
649 struct ieee80211_chanctx *old_ctx,
650 const struct ieee80211_chan_req *chanreq,
651 struct ieee80211_link_data *rsvd_for)
652{
653 const struct cfg80211_chan_def *chandef = &chanreq->oper;
654 struct ieee80211_chan_req ctx_req = {
655 .oper = ctx->conf.def,
656 .ap = ctx->conf.ap,
657 };
658 u32 changed = 0;
659
660 /* 5/10 MHz not handled here */
661 switch (chandef->width) {
662 case NL80211_CHAN_WIDTH_1:
663 case NL80211_CHAN_WIDTH_2:
664 case NL80211_CHAN_WIDTH_4:
665 case NL80211_CHAN_WIDTH_8:
666 case NL80211_CHAN_WIDTH_16:
667 /*
668 * mac80211 currently only supports sharing identical
669 * chanctx's for S1G interfaces.
670 */
671 WARN_ON(!ieee80211_chanreq_identical(&ctx_req, chanreq));
672 return;
673 case NL80211_CHAN_WIDTH_20_NOHT:
674 case NL80211_CHAN_WIDTH_20:
675 case NL80211_CHAN_WIDTH_40:
676 case NL80211_CHAN_WIDTH_80:
677 case NL80211_CHAN_WIDTH_80P80:
678 case NL80211_CHAN_WIDTH_160:
679 case NL80211_CHAN_WIDTH_320:
680 break;
681 default:
682 WARN_ON(1);
683 }
684
685 /* Check maybe BW narrowed - we do this _before_ calling recalc_chanctx_min_def
686 * due to maybe not returning from it, e.g in case new context was added
687 * first time with all parameters up to date.
688 */
689 ieee80211_chan_bw_change(local, old_ctx, false, true);
690
691 if (ieee80211_chanreq_identical(&ctx_req, chanreq)) {
692 _ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for, false);
693 return;
694 }
695
696 WARN_ON(ieee80211_chanctx_refcount(local, ctx) > 1 &&
697 !cfg80211_chandef_compatible(&ctx->conf.def, &chanreq->oper));
698
699 ieee80211_remove_wbrf(local, &ctx->conf.def);
700
701 if (!cfg80211_chandef_identical(&ctx->conf.def, &chanreq->oper)) {
702 if (ctx->conf.def.width != chanreq->oper.width)
703 changed |= IEEE80211_CHANCTX_CHANGE_WIDTH;
704 if (ctx->conf.def.punctured != chanreq->oper.punctured)
705 changed |= IEEE80211_CHANCTX_CHANGE_PUNCTURING;
706 }
707 if (!cfg80211_chandef_identical(&ctx->conf.ap, &chanreq->ap))
708 changed |= IEEE80211_CHANCTX_CHANGE_AP;
709 ctx->conf.def = *chandef;
710 ctx->conf.ap = chanreq->ap;
711
712 /* check if min chanctx also changed */
713 changed |= __ieee80211_recalc_chanctx_min_def(local, ctx, rsvd_for,
714 false);
715
716 ieee80211_add_wbrf(local, &ctx->conf.def);
717
718 drv_change_chanctx(local, ctx, changed);
719
720 /* check if BW is wider */
721 ieee80211_chan_bw_change(local, old_ctx, false, false);
722}
723
724static void ieee80211_change_chanctx(struct ieee80211_local *local,
725 struct ieee80211_chanctx *ctx,
726 struct ieee80211_chanctx *old_ctx,
727 const struct ieee80211_chan_req *chanreq)
728{
729 _ieee80211_change_chanctx(local, ctx, old_ctx, chanreq, NULL);
730}
731
732/* Note: if successful, the returned chanctx is reserved for the link */
733static struct ieee80211_chanctx *
734ieee80211_find_chanctx(struct ieee80211_local *local,
735 struct ieee80211_link_data *link,
736 const struct ieee80211_chan_req *chanreq,
737 enum ieee80211_chanctx_mode mode)
738{
739 struct ieee80211_chan_req tmp;
740 struct ieee80211_chanctx *ctx;
741
742 lockdep_assert_wiphy(local->hw.wiphy);
743
744 if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
745 return NULL;
746
747 if (WARN_ON(link->reserved_chanctx))
748 return NULL;
749
750 list_for_each_entry(ctx, &local->chanctx_list, list) {
751 const struct ieee80211_chan_req *compat;
752
753 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE)
754 continue;
755
756 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
757 continue;
758
759 compat = ieee80211_chanctx_compatible(ctx, chanreq, &tmp);
760 if (!compat)
761 continue;
762
763 compat = ieee80211_chanctx_reserved_chanreq(local, ctx,
764 compat, &tmp);
765 if (!compat)
766 continue;
767
768 /*
769 * Reserve the chanctx temporarily, as the driver might change
770 * active links during callbacks we make into it below and/or
771 * later during assignment, which could (otherwise) cause the
772 * context to actually be removed.
773 */
774 link->reserved_chanctx = ctx;
775
776 ieee80211_change_chanctx(local, ctx, ctx, compat);
777
778 return ctx;
779 }
780
781 return NULL;
782}
783
784bool ieee80211_is_radar_required(struct ieee80211_local *local,
785 struct cfg80211_scan_request *req)
786{
787 struct wiphy *wiphy = local->hw.wiphy;
788 struct ieee80211_link_data *link;
789 struct ieee80211_channel *chan;
790 int radio_idx;
791
792 lockdep_assert_wiphy(local->hw.wiphy);
793
794 if (!req)
795 return false;
796
797 for_each_sdata_link(local, link) {
798 if (link->radar_required) {
799 chan = link->conf->chanreq.oper.chan;
800 radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan);
801
802 if (ieee80211_is_radio_idx_in_scan_req(wiphy, req,
803 radio_idx))
804 return true;
805 }
806 }
807
808 return false;
809}
810
811static bool
812ieee80211_chanctx_radar_required(struct ieee80211_local *local,
813 struct ieee80211_chanctx *ctx)
814{
815 struct ieee80211_chanctx_user_iter iter;
816
817 lockdep_assert_wiphy(local->hw.wiphy);
818
819 for_each_chanctx_user_assigned(local, ctx, &iter) {
820 if (iter.radar_required)
821 return true;
822 }
823
824 return false;
825}
826
827static struct ieee80211_chanctx *
828ieee80211_alloc_chanctx(struct ieee80211_local *local,
829 const struct ieee80211_chan_req *chanreq,
830 enum ieee80211_chanctx_mode mode,
831 int radio_idx)
832{
833 struct ieee80211_chanctx *ctx;
834
835 lockdep_assert_wiphy(local->hw.wiphy);
836
837 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
838 if (!ctx)
839 return NULL;
840
841 ctx->conf.def = chanreq->oper;
842 ctx->conf.ap = chanreq->ap;
843 ctx->conf.rx_chains_static = 1;
844 ctx->conf.rx_chains_dynamic = 1;
845 ctx->mode = mode;
846 ctx->conf.radar_enabled = false;
847 ctx->conf.radio_idx = radio_idx;
848 ctx->radar_detected = false;
849 __ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
850
851 return ctx;
852}
853
854static int ieee80211_add_chanctx(struct ieee80211_local *local,
855 struct ieee80211_chanctx *ctx)
856{
857 u32 changed;
858 int err;
859
860 lockdep_assert_wiphy(local->hw.wiphy);
861
862 ieee80211_add_wbrf(local, &ctx->conf.def);
863
864 /* turn idle off *before* setting channel -- some drivers need that */
865 changed = ieee80211_idle_off(local);
866 if (changed)
867 ieee80211_hw_config(local, -1, changed);
868
869 err = drv_add_chanctx(local, ctx);
870 if (err) {
871 ieee80211_recalc_idle(local);
872 return err;
873 }
874
875 return 0;
876}
877
878static struct ieee80211_chanctx *
879ieee80211_new_chanctx(struct ieee80211_local *local,
880 const struct ieee80211_chan_req *chanreq,
881 enum ieee80211_chanctx_mode mode,
882 bool assign_on_failure,
883 int radio_idx)
884{
885 struct ieee80211_chanctx *ctx;
886 int err;
887
888 lockdep_assert_wiphy(local->hw.wiphy);
889
890 ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
891 if (!ctx)
892 return ERR_PTR(-ENOMEM);
893
894 err = ieee80211_add_chanctx(local, ctx);
895 if (!assign_on_failure && err) {
896 kfree(ctx);
897 return ERR_PTR(err);
898 }
899 /* We ignored a driver error, see _ieee80211_set_active_links */
900 WARN_ON_ONCE(err && !local->in_reconfig);
901
902 list_add_rcu(&ctx->list, &local->chanctx_list);
903 return ctx;
904}
905
906static void ieee80211_del_chanctx(struct ieee80211_local *local,
907 struct ieee80211_chanctx *ctx,
908 bool skip_idle_recalc)
909{
910 lockdep_assert_wiphy(local->hw.wiphy);
911
912 drv_remove_chanctx(local, ctx);
913
914 if (!skip_idle_recalc)
915 ieee80211_recalc_idle(local);
916
917 ieee80211_remove_wbrf(local, &ctx->conf.def);
918}
919
920static void ieee80211_free_chanctx(struct ieee80211_local *local,
921 struct ieee80211_chanctx *ctx,
922 bool skip_idle_recalc)
923{
924 lockdep_assert_wiphy(local->hw.wiphy);
925
926 WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
927
928 list_del_rcu(&ctx->list);
929 ieee80211_del_chanctx(local, ctx, skip_idle_recalc);
930 kfree_rcu(ctx, rcu_head);
931}
932
933void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
934 struct ieee80211_chanctx *ctx)
935{
936 struct ieee80211_chanctx_conf *conf = &ctx->conf;
937 const struct ieee80211_chan_req *compat = NULL;
938 struct ieee80211_chanctx_user_iter iter;
939 struct ieee80211_chan_req tmp;
940 struct sta_info *sta;
941
942 lockdep_assert_wiphy(local->hw.wiphy);
943
944 for_each_chanctx_user_assigned(local, ctx, &iter) {
945 if (!compat)
946 compat = iter.chanreq;
947
948 compat = ieee80211_chanreq_compatible(iter.chanreq,
949 compat, &tmp);
950 if (WARN_ON_ONCE(!compat))
951 return;
952 }
953
954 if (WARN_ON_ONCE(!compat))
955 return;
956
957 /* TDLS peers can sometimes affect the chandef width */
958 list_for_each_entry(sta, &local->sta_list, list) {
959 struct ieee80211_sub_if_data *sdata = sta->sdata;
960 struct ieee80211_chan_req tdls_chanreq = {};
961 struct ieee80211_link_data *link;
962 int tdls_link_id;
963
964 if (!sta->uploaded ||
965 !test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) ||
966 !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
967 !sta->tdls_chandef.chan)
968 continue;
969
970 tdls_link_id = ieee80211_tdls_sta_link_id(sta);
971 link = sdata_dereference(sdata->link[tdls_link_id], sdata);
972 if (!link)
973 continue;
974
975 if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
976 continue;
977
978 tdls_chanreq.oper = sta->tdls_chandef;
979
980 /* note this always fills and returns &tmp if compat */
981 compat = ieee80211_chanreq_compatible(&tdls_chanreq,
982 compat, &tmp);
983 if (WARN_ON_ONCE(!compat))
984 return;
985 }
986
987 ieee80211_change_chanctx(local, ctx, ctx, compat);
988}
989
990static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
991 struct ieee80211_chanctx *chanctx)
992{
993 bool radar_enabled;
994
995 lockdep_assert_wiphy(local->hw.wiphy);
996
997 radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
998
999 if (radar_enabled == chanctx->conf.radar_enabled)
1000 return;
1001
1002 chanctx->conf.radar_enabled = radar_enabled;
1003
1004 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
1005}
1006
1007static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
1008 struct ieee80211_chanctx *new_ctx,
1009 bool assign_on_failure)
1010{
1011 struct ieee80211_sub_if_data *sdata = link->sdata;
1012 struct ieee80211_local *local = sdata->local;
1013 struct ieee80211_chanctx_conf *conf;
1014 struct ieee80211_chanctx *curr_ctx = NULL;
1015 bool new_idle;
1016 int ret;
1017
1018 if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
1019 return -EOPNOTSUPP;
1020
1021 conf = rcu_dereference_protected(link->conf->chanctx_conf,
1022 lockdep_is_held(&local->hw.wiphy->mtx));
1023
1024 if (conf && !local->in_reconfig) {
1025 curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
1026
1027 drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
1028 conf = NULL;
1029 }
1030
1031 if (new_ctx) {
1032 /* recalc considering the link we'll use it for now */
1033 _ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
1034
1035 ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
1036 if (assign_on_failure || !ret) {
1037 /* Need to continue, see _ieee80211_set_active_links */
1038 WARN_ON_ONCE(ret && !local->in_reconfig);
1039 ret = 0;
1040
1041 /* succeeded, so commit it to the data structures */
1042 conf = &new_ctx->conf;
1043 }
1044 } else {
1045 ret = 0;
1046 }
1047
1048 rcu_assign_pointer(link->conf->chanctx_conf, conf);
1049
1050 if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
1051 ieee80211_recalc_chanctx_chantype(local, curr_ctx);
1052 ieee80211_recalc_smps_chanctx(local, curr_ctx);
1053 ieee80211_recalc_radar_chanctx(local, curr_ctx);
1054 ieee80211_recalc_chanctx_min_def(local, curr_ctx);
1055 }
1056
1057 if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
1058 ieee80211_recalc_txpower(link, false);
1059 ieee80211_recalc_chanctx_min_def(local, new_ctx);
1060 }
1061
1062 if (conf) {
1063 new_idle = false;
1064 } else {
1065 struct ieee80211_link_data *tmp;
1066
1067 new_idle = true;
1068 for_each_sdata_link(local, tmp) {
1069 if (rcu_access_pointer(tmp->conf->chanctx_conf)) {
1070 new_idle = false;
1071 break;
1072 }
1073 }
1074 }
1075
1076 if (new_idle != sdata->vif.cfg.idle) {
1077 sdata->vif.cfg.idle = new_idle;
1078
1079 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
1080 sdata->vif.type != NL80211_IFTYPE_MONITOR)
1081 ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
1082 }
1083
1084 ieee80211_check_fast_xmit_iface(sdata);
1085
1086 return ret;
1087}
1088
1089void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
1090 struct ieee80211_chanctx *chanctx)
1091{
1092 struct ieee80211_chanctx_user_iter iter;
1093 struct ieee80211_sub_if_data *sdata;
1094 u8 rx_chains_static, rx_chains_dynamic;
1095
1096 lockdep_assert_wiphy(local->hw.wiphy);
1097
1098 rx_chains_static = 1;
1099 rx_chains_dynamic = 1;
1100
1101 for_each_chanctx_user_assigned(local, chanctx, &iter) {
1102 u8 needed_static, needed_dynamic;
1103
1104 switch (iter.iftype) {
1105 case NL80211_IFTYPE_STATION:
1106 if (!iter.sdata->u.mgd.associated)
1107 continue;
1108 break;
1109 case NL80211_IFTYPE_MONITOR:
1110 if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
1111 continue;
1112 break;
1113 case NL80211_IFTYPE_AP:
1114 case NL80211_IFTYPE_ADHOC:
1115 case NL80211_IFTYPE_MESH_POINT:
1116 case NL80211_IFTYPE_OCB:
1117 break;
1118 default:
1119 continue;
1120 }
1121
1122 if (iter.iftype == NL80211_IFTYPE_MONITOR) {
1123 rx_chains_dynamic = rx_chains_static = local->rx_chains;
1124 break;
1125 }
1126
1127 switch (iter.link->smps_mode) {
1128 default:
1129 WARN_ONCE(1, "Invalid SMPS mode %d\n",
1130 iter.link->smps_mode);
1131 fallthrough;
1132 case IEEE80211_SMPS_OFF:
1133 needed_static = iter.link->needed_rx_chains;
1134 needed_dynamic = iter.link->needed_rx_chains;
1135 break;
1136 case IEEE80211_SMPS_DYNAMIC:
1137 needed_static = 1;
1138 needed_dynamic = iter.link->needed_rx_chains;
1139 break;
1140 case IEEE80211_SMPS_STATIC:
1141 needed_static = 1;
1142 needed_dynamic = 1;
1143 break;
1144 }
1145
1146 rx_chains_static = max(rx_chains_static, needed_static);
1147 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
1148 }
1149
1150 /* Disable SMPS for the monitor interface */
1151 sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
1152 if (sdata &&
1153 rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
1154 rx_chains_dynamic = rx_chains_static = local->rx_chains;
1155
1156 if (rx_chains_static == chanctx->conf.rx_chains_static &&
1157 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
1158 return;
1159
1160 chanctx->conf.rx_chains_static = rx_chains_static;
1161 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
1162 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
1163}
1164
1165static void
1166__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1167 bool clear)
1168{
1169 struct ieee80211_sub_if_data *sdata = link->sdata;
1170 unsigned int link_id = link->link_id;
1171 struct ieee80211_bss_conf *link_conf = link->conf;
1172 struct ieee80211_local *local __maybe_unused = sdata->local;
1173 struct ieee80211_sub_if_data *vlan;
1174 struct ieee80211_chanctx_conf *conf;
1175
1176 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
1177 return;
1178
1179 lockdep_assert_wiphy(local->hw.wiphy);
1180
1181 /* Check that conf exists, even when clearing this function
1182 * must be called with the AP's channel context still there
1183 * as it would otherwise cause VLANs to have an invalid
1184 * channel context pointer for a while, possibly pointing
1185 * to a channel context that has already been freed.
1186 */
1187 conf = rcu_dereference_protected(link_conf->chanctx_conf,
1188 lockdep_is_held(&local->hw.wiphy->mtx));
1189 WARN_ON(!conf);
1190
1191 if (clear)
1192 conf = NULL;
1193
1194 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1195 struct ieee80211_bss_conf *vlan_conf;
1196
1197 vlan_conf = wiphy_dereference(local->hw.wiphy,
1198 vlan->vif.link_conf[link_id]);
1199 if (WARN_ON(!vlan_conf))
1200 continue;
1201
1202 rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
1203 }
1204}
1205
1206void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1207 bool clear)
1208{
1209 struct ieee80211_local *local = link->sdata->local;
1210
1211 lockdep_assert_wiphy(local->hw.wiphy);
1212
1213 __ieee80211_link_copy_chanctx_to_vlans(link, clear);
1214}
1215
1216void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
1217{
1218 struct ieee80211_sub_if_data *sdata = link->sdata;
1219 struct ieee80211_chanctx *ctx = link->reserved_chanctx;
1220
1221 lockdep_assert_wiphy(sdata->local->hw.wiphy);
1222
1223 if (WARN_ON(!ctx))
1224 return;
1225
1226 link->reserved_chanctx = NULL;
1227
1228 if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
1229 if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1230 if (WARN_ON(!ctx->replace_ctx))
1231 return;
1232
1233 WARN_ON(ctx->replace_ctx->replace_state !=
1234 IEEE80211_CHANCTX_WILL_BE_REPLACED);
1235 WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
1236
1237 ctx->replace_ctx->replace_ctx = NULL;
1238 ctx->replace_ctx->replace_state =
1239 IEEE80211_CHANCTX_REPLACE_NONE;
1240
1241 list_del_rcu(&ctx->list);
1242 kfree_rcu(ctx, rcu_head);
1243 } else {
1244 ieee80211_free_chanctx(sdata->local, ctx, false);
1245 }
1246 }
1247}
1248
1249static struct ieee80211_chanctx *
1250ieee80211_replace_chanctx(struct ieee80211_local *local,
1251 const struct ieee80211_chan_req *chanreq,
1252 enum ieee80211_chanctx_mode mode,
1253 struct ieee80211_chanctx *curr_ctx)
1254{
1255 struct ieee80211_chanctx *new_ctx, *ctx;
1256 struct wiphy *wiphy = local->hw.wiphy;
1257 const struct wiphy_radio *radio;
1258
1259 if (!curr_ctx ||
1260 curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
1261 ieee80211_chanctx_num_reserved(local, curr_ctx) != 0) {
1262 /*
1263 * Another link already requested this context for a
1264 * reservation. Find another one hoping all links assigned
1265 * to it will also switch soon enough.
1266 *
1267 * TODO: This needs a little more work as some cases
1268 * (more than 2 chanctx capable devices) may fail which could
1269 * otherwise succeed provided some channel context juggling was
1270 * performed.
1271 *
1272 * Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
1273 * link2 from ctx1 request new different chandefs starting 2
1274 * in-place reservations with ctx4 and ctx5 replacing ctx1 and
1275 * ctx2 respectively. Next link5 and link6 from ctx3 reserve
1276 * ctx4. If link3 and link4 remain on ctx2 as they are then this
1277 * fails unless `replace_ctx` from ctx5 is replaced with ctx3.
1278 */
1279 list_for_each_entry(ctx, &local->chanctx_list, list) {
1280 if (ctx->replace_state !=
1281 IEEE80211_CHANCTX_REPLACE_NONE)
1282 continue;
1283
1284 if (ieee80211_chanctx_num_reserved(local, ctx) != 0)
1285 continue;
1286
1287 if (ctx->conf.radio_idx >= 0) {
1288 radio = &wiphy->radio[ctx->conf.radio_idx];
1289 if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1290 continue;
1291 }
1292
1293 curr_ctx = ctx;
1294 break;
1295 }
1296 }
1297
1298 /*
1299 * If that's true then all available contexts already have reservations
1300 * and cannot be used.
1301 */
1302 if (!curr_ctx ||
1303 curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
1304 ieee80211_chanctx_num_reserved(local, curr_ctx) != 0)
1305 return ERR_PTR(-EBUSY);
1306
1307 new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
1308 if (!new_ctx)
1309 return ERR_PTR(-ENOMEM);
1310
1311 new_ctx->replace_ctx = curr_ctx;
1312 new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER;
1313
1314 curr_ctx->replace_ctx = new_ctx;
1315 curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED;
1316
1317 list_add_rcu(&new_ctx->list, &local->chanctx_list);
1318
1319 return new_ctx;
1320}
1321
1322static bool
1323ieee80211_find_available_radio(struct ieee80211_local *local,
1324 const struct ieee80211_chan_req *chanreq,
1325 u32 radio_mask, int *radio_idx)
1326{
1327 struct wiphy *wiphy = local->hw.wiphy;
1328 const struct wiphy_radio *radio;
1329 int i;
1330
1331 *radio_idx = -1;
1332 if (!wiphy->n_radio)
1333 return true;
1334
1335 for (i = 0; i < wiphy->n_radio; i++) {
1336 if (!(radio_mask & BIT(i)))
1337 continue;
1338
1339 radio = &wiphy->radio[i];
1340 if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
1341 continue;
1342
1343 if (!ieee80211_can_create_new_chanctx(local, i))
1344 continue;
1345
1346 *radio_idx = i;
1347 return true;
1348 }
1349
1350 return false;
1351}
1352
1353int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
1354 const struct ieee80211_chan_req *chanreq,
1355 enum ieee80211_chanctx_mode mode,
1356 bool radar_required)
1357{
1358 struct ieee80211_sub_if_data *sdata = link->sdata;
1359 struct ieee80211_local *local = sdata->local;
1360 struct ieee80211_chanctx *new_ctx, *curr_ctx;
1361 int radio_idx;
1362
1363 lockdep_assert_wiphy(local->hw.wiphy);
1364
1365 curr_ctx = ieee80211_link_get_chanctx(link);
1366 if (curr_ctx && !local->ops->switch_vif_chanctx)
1367 return -EOPNOTSUPP;
1368
1369 new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
1370 if (!new_ctx) {
1371 if (ieee80211_can_create_new_chanctx(local, -1) &&
1372 ieee80211_find_available_radio(local, chanreq,
1373 sdata->wdev.radio_mask,
1374 &radio_idx))
1375 new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
1376 false, radio_idx);
1377 else
1378 new_ctx = ieee80211_replace_chanctx(local, chanreq,
1379 mode, curr_ctx);
1380 if (IS_ERR(new_ctx))
1381 return PTR_ERR(new_ctx);
1382 }
1383
1384 link->reserved_chanctx = new_ctx;
1385 link->reserved = *chanreq;
1386 link->reserved_radar_required = radar_required;
1387 link->reserved_ready = false;
1388
1389 return 0;
1390}
1391
1392static void
1393ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
1394{
1395 struct ieee80211_sub_if_data *sdata = link->sdata;
1396
1397 switch (sdata->vif.type) {
1398 case NL80211_IFTYPE_ADHOC:
1399 case NL80211_IFTYPE_AP:
1400 case NL80211_IFTYPE_MESH_POINT:
1401 case NL80211_IFTYPE_OCB:
1402 wiphy_work_queue(sdata->local->hw.wiphy,
1403 &link->csa.finalize_work);
1404 break;
1405 case NL80211_IFTYPE_STATION:
1406 wiphy_hrtimer_work_queue(sdata->local->hw.wiphy,
1407 &link->u.mgd.csa.switch_work, 0);
1408 break;
1409 case NL80211_IFTYPE_UNSPECIFIED:
1410 case NL80211_IFTYPE_AP_VLAN:
1411 case NL80211_IFTYPE_WDS:
1412 case NL80211_IFTYPE_MONITOR:
1413 case NL80211_IFTYPE_P2P_CLIENT:
1414 case NL80211_IFTYPE_P2P_GO:
1415 case NL80211_IFTYPE_P2P_DEVICE:
1416 case NL80211_IFTYPE_NAN:
1417 case NUM_NL80211_IFTYPES:
1418 WARN_ON(1);
1419 break;
1420 }
1421}
1422
1423static void
1424ieee80211_link_update_chanreq(struct ieee80211_link_data *link,
1425 const struct ieee80211_chan_req *chanreq)
1426{
1427 struct ieee80211_sub_if_data *sdata = link->sdata;
1428 unsigned int link_id = link->link_id;
1429 struct ieee80211_sub_if_data *vlan;
1430
1431 link->conf->chanreq = *chanreq;
1432
1433 if (sdata->vif.type != NL80211_IFTYPE_AP)
1434 return;
1435
1436 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1437 struct ieee80211_bss_conf *vlan_conf;
1438
1439 vlan_conf = wiphy_dereference(sdata->local->hw.wiphy,
1440 vlan->vif.link_conf[link_id]);
1441 if (WARN_ON(!vlan_conf))
1442 continue;
1443
1444 vlan_conf->chanreq = *chanreq;
1445 }
1446}
1447
1448static int
1449ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
1450{
1451 struct ieee80211_sub_if_data *sdata = link->sdata;
1452 struct ieee80211_bss_conf *link_conf = link->conf;
1453 struct ieee80211_local *local = sdata->local;
1454 struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1455 struct ieee80211_chanctx *old_ctx, *new_ctx;
1456 const struct ieee80211_chan_req *chanreq;
1457 struct ieee80211_chan_req tmp;
1458 u64 changed = 0;
1459 int err;
1460
1461 lockdep_assert_wiphy(local->hw.wiphy);
1462
1463 new_ctx = link->reserved_chanctx;
1464 old_ctx = ieee80211_link_get_chanctx(link);
1465
1466 if (WARN_ON(!link->reserved_ready))
1467 return -EBUSY;
1468
1469 if (WARN_ON(!new_ctx))
1470 return -EINVAL;
1471
1472 if (WARN_ON(!old_ctx))
1473 return -EINVAL;
1474
1475 if (WARN_ON(new_ctx->replace_state ==
1476 IEEE80211_CHANCTX_REPLACES_OTHER))
1477 return -EINVAL;
1478
1479 chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1480 &link->reserved,
1481 &tmp);
1482 if (WARN_ON(!chanreq))
1483 return -EINVAL;
1484
1485 if (link_conf->chanreq.oper.width != link->reserved.oper.width)
1486 changed = BSS_CHANGED_BANDWIDTH;
1487
1488 ieee80211_link_update_chanreq(link, &link->reserved);
1489
1490 _ieee80211_change_chanctx(local, new_ctx, old_ctx, chanreq, link);
1491
1492 vif_chsw[0].vif = &sdata->vif;
1493 vif_chsw[0].old_ctx = &old_ctx->conf;
1494 vif_chsw[0].new_ctx = &new_ctx->conf;
1495 vif_chsw[0].link_conf = link->conf;
1496
1497 link->reserved_chanctx = NULL;
1498
1499 err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1500 CHANCTX_SWMODE_REASSIGN_VIF);
1501 if (err) {
1502 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1503 ieee80211_free_chanctx(local, new_ctx, false);
1504
1505 goto out;
1506 }
1507
1508 link->radar_required = link->reserved_radar_required;
1509 rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
1510
1511 if (sdata->vif.type == NL80211_IFTYPE_AP)
1512 __ieee80211_link_copy_chanctx_to_vlans(link, false);
1513
1514 ieee80211_check_fast_xmit_iface(sdata);
1515
1516 if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1517 ieee80211_free_chanctx(local, old_ctx, false);
1518
1519 ieee80211_recalc_chanctx_min_def(local, new_ctx);
1520 ieee80211_recalc_smps_chanctx(local, new_ctx);
1521 ieee80211_recalc_radar_chanctx(local, new_ctx);
1522
1523 if (changed)
1524 ieee80211_link_info_change_notify(sdata, link, changed);
1525
1526out:
1527 ieee80211_link_chanctx_reservation_complete(link);
1528 return err;
1529}
1530
1531static int
1532ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
1533{
1534 struct ieee80211_sub_if_data *sdata = link->sdata;
1535 struct ieee80211_local *local = sdata->local;
1536 struct ieee80211_chanctx *old_ctx, *new_ctx;
1537 const struct ieee80211_chan_req *chanreq;
1538 struct ieee80211_chan_req tmp;
1539 int err;
1540
1541 old_ctx = ieee80211_link_get_chanctx(link);
1542 new_ctx = link->reserved_chanctx;
1543
1544 if (WARN_ON(!link->reserved_ready))
1545 return -EINVAL;
1546
1547 if (WARN_ON(old_ctx))
1548 return -EINVAL;
1549
1550 if (WARN_ON(!new_ctx))
1551 return -EINVAL;
1552
1553 if (WARN_ON(new_ctx->replace_state ==
1554 IEEE80211_CHANCTX_REPLACES_OTHER))
1555 return -EINVAL;
1556
1557 chanreq = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1558 &link->reserved,
1559 &tmp);
1560 if (WARN_ON(!chanreq))
1561 return -EINVAL;
1562
1563 ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq);
1564
1565 link->reserved_chanctx = NULL;
1566
1567 err = ieee80211_assign_link_chanctx(link, new_ctx, false);
1568 if (err) {
1569 if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1570 ieee80211_free_chanctx(local, new_ctx, false);
1571
1572 goto out;
1573 }
1574
1575out:
1576 ieee80211_link_chanctx_reservation_complete(link);
1577 return err;
1578}
1579
1580static bool
1581ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)
1582{
1583 struct ieee80211_sub_if_data *sdata = link->sdata;
1584 struct ieee80211_chanctx *old_ctx, *new_ctx;
1585
1586 lockdep_assert_wiphy(sdata->local->hw.wiphy);
1587
1588 new_ctx = link->reserved_chanctx;
1589 old_ctx = ieee80211_link_get_chanctx(link);
1590
1591 if (!old_ctx)
1592 return false;
1593
1594 if (WARN_ON(!new_ctx))
1595 return false;
1596
1597 if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1598 return false;
1599
1600 if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1601 return false;
1602
1603 return true;
1604}
1605
1606static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1607 int n_vifs)
1608{
1609 struct ieee80211_vif_chanctx_switch *vif_chsw;
1610 struct ieee80211_chanctx *ctx, *old_ctx;
1611 int i, err;
1612
1613 lockdep_assert_wiphy(local->hw.wiphy);
1614
1615 vif_chsw = kcalloc(n_vifs, sizeof(vif_chsw[0]), GFP_KERNEL);
1616 if (!vif_chsw)
1617 return -ENOMEM;
1618
1619 i = 0;
1620 list_for_each_entry(ctx, &local->chanctx_list, list) {
1621 struct ieee80211_chanctx_user_iter iter;
1622
1623 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1624 continue;
1625
1626 if (WARN_ON(!ctx->replace_ctx)) {
1627 err = -EINVAL;
1628 goto out;
1629 }
1630
1631 for_each_chanctx_user_reserved(local, ctx, &iter) {
1632 if (!ieee80211_link_has_in_place_reservation(iter.link))
1633 continue;
1634
1635 old_ctx = ieee80211_link_get_chanctx(iter.link);
1636 vif_chsw[i].vif = &iter.sdata->vif;
1637 vif_chsw[i].old_ctx = &old_ctx->conf;
1638 vif_chsw[i].new_ctx = &ctx->conf;
1639 vif_chsw[i].link_conf = iter.link->conf;
1640
1641 i++;
1642 }
1643 }
1644
1645 err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
1646 CHANCTX_SWMODE_SWAP_CONTEXTS);
1647
1648out:
1649 kfree(vif_chsw);
1650 return err;
1651}
1652
1653static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
1654{
1655 struct ieee80211_chanctx *ctx;
1656 int err;
1657
1658 lockdep_assert_wiphy(local->hw.wiphy);
1659
1660 list_for_each_entry(ctx, &local->chanctx_list, list) {
1661 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1662 continue;
1663
1664 if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
1665 continue;
1666
1667 ieee80211_del_chanctx(local, ctx->replace_ctx, false);
1668 err = ieee80211_add_chanctx(local, ctx);
1669 if (err)
1670 goto err;
1671 }
1672
1673 return 0;
1674
1675err:
1676 WARN_ON(ieee80211_add_chanctx(local, ctx));
1677 list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1678 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1679 continue;
1680
1681 if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
1682 continue;
1683
1684 ieee80211_del_chanctx(local, ctx, false);
1685 WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1686 }
1687
1688 return err;
1689}
1690
1691static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1692{
1693 struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1694 int err, n_assigned, n_reserved, n_ready;
1695 int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1696
1697 lockdep_assert_wiphy(local->hw.wiphy);
1698
1699 /*
1700 * If there are 2 independent pairs of channel contexts performing
1701 * cross-switch of their vifs this code will still wait until both are
1702 * ready even though it could be possible to switch one before the
1703 * other is ready.
1704 *
1705 * For practical reasons and code simplicity just do a single huge
1706 * switch.
1707 */
1708
1709 /*
1710 * Verify if the reservation is still feasible.
1711 * - if it's not then disconnect
1712 * - if it is but not all vifs necessary are ready then defer
1713 */
1714
1715 list_for_each_entry(ctx, &local->chanctx_list, list) {
1716 struct ieee80211_chanctx_user_iter iter;
1717
1718 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1719 continue;
1720
1721 if (WARN_ON(!ctx->replace_ctx)) {
1722 err = -EINVAL;
1723 goto err;
1724 }
1725
1726 n_ctx++;
1727
1728 n_assigned = 0;
1729 n_reserved = 0;
1730 n_ready = 0;
1731
1732 for_each_chanctx_user_assigned(local, ctx->replace_ctx, &iter) {
1733 n_assigned++;
1734 if (iter.link->reserved_chanctx) {
1735 n_reserved++;
1736 if (iter.link->reserved_ready)
1737 n_ready++;
1738 }
1739 }
1740
1741 if (n_assigned != n_reserved) {
1742 if (n_ready == n_reserved) {
1743 wiphy_info(local->hw.wiphy,
1744 "channel context reservation cannot be finalized because some interfaces aren't switching\n");
1745 err = -EBUSY;
1746 goto err;
1747 }
1748
1749 return -EAGAIN;
1750 }
1751
1752 ctx->conf.radar_enabled = false;
1753 for_each_chanctx_user_reserved(local, ctx, &iter) {
1754 if (ieee80211_link_has_in_place_reservation(iter.link) &&
1755 !iter.link->reserved_ready)
1756 return -EAGAIN;
1757
1758 old_ctx = ieee80211_link_get_chanctx(iter.link);
1759 if (old_ctx) {
1760 if (old_ctx->replace_state ==
1761 IEEE80211_CHANCTX_WILL_BE_REPLACED)
1762 n_vifs_switch++;
1763 else
1764 n_vifs_assign++;
1765 } else {
1766 n_vifs_ctxless++;
1767 }
1768
1769 if (iter.radar_required)
1770 ctx->conf.radar_enabled = true;
1771 }
1772 }
1773
1774 if (WARN_ON(n_ctx == 0) ||
1775 WARN_ON(n_vifs_switch == 0 &&
1776 n_vifs_assign == 0 &&
1777 n_vifs_ctxless == 0)) {
1778 err = -EINVAL;
1779 goto err;
1780 }
1781
1782 /* update station rate control and min width before switch */
1783 list_for_each_entry(ctx, &local->chanctx_list, list) {
1784 struct ieee80211_chanctx_user_iter iter;
1785
1786 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1787 continue;
1788
1789 if (WARN_ON(!ctx->replace_ctx)) {
1790 err = -EINVAL;
1791 goto err;
1792 }
1793
1794 for_each_chanctx_user_reserved(local, ctx, &iter) {
1795 if (!ieee80211_link_has_in_place_reservation(iter.link))
1796 continue;
1797
1798 ieee80211_chan_bw_change(local,
1799 ieee80211_link_get_chanctx(iter.link),
1800 true, true);
1801 }
1802
1803 _ieee80211_recalc_chanctx_min_def(local, ctx, NULL, true);
1804 }
1805
1806 /*
1807 * All necessary vifs are ready. Perform the switch now depending on
1808 * reservations and driver capabilities.
1809 */
1810
1811 if (n_vifs_switch > 0) {
1812 err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1813 if (err)
1814 goto err;
1815 }
1816
1817 if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1818 err = ieee80211_chsw_switch_ctxs(local);
1819 if (err)
1820 goto err;
1821 }
1822
1823 /*
1824 * Update all structures, values and pointers to point to new channel
1825 * context(s).
1826 */
1827 list_for_each_entry(ctx, &local->chanctx_list, list) {
1828 struct ieee80211_chanctx_user_iter iter;
1829
1830 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1831 continue;
1832
1833 if (WARN_ON(!ctx->replace_ctx)) {
1834 err = -EINVAL;
1835 goto err;
1836 }
1837
1838 for_each_chanctx_user_reserved(local, ctx, &iter) {
1839 struct ieee80211_link_data *link = iter.link;
1840 struct ieee80211_sub_if_data *sdata = iter.sdata;
1841 struct ieee80211_bss_conf *link_conf = link->conf;
1842 u64 changed = 0;
1843
1844 if (!ieee80211_link_has_in_place_reservation(link))
1845 continue;
1846
1847 rcu_assign_pointer(link_conf->chanctx_conf,
1848 &ctx->conf);
1849
1850 if (sdata->vif.type == NL80211_IFTYPE_AP)
1851 __ieee80211_link_copy_chanctx_to_vlans(link,
1852 false);
1853
1854 ieee80211_check_fast_xmit_iface(sdata);
1855
1856 link->radar_required = iter.radar_required;
1857
1858 if (link_conf->chanreq.oper.width != iter.chanreq->oper.width)
1859 changed = BSS_CHANGED_BANDWIDTH;
1860
1861 ieee80211_link_update_chanreq(link, &link->reserved);
1862 if (changed)
1863 ieee80211_link_info_change_notify(sdata,
1864 link,
1865 changed);
1866
1867 ieee80211_recalc_txpower(link, false);
1868 }
1869
1870 ieee80211_recalc_chanctx_chantype(local, ctx);
1871 ieee80211_recalc_smps_chanctx(local, ctx);
1872 ieee80211_recalc_radar_chanctx(local, ctx);
1873 ieee80211_recalc_chanctx_min_def(local, ctx);
1874
1875 for_each_chanctx_user_reserved(local, ctx, &iter) {
1876 if (ieee80211_link_get_chanctx(iter.link) != ctx)
1877 continue;
1878
1879 iter.link->reserved_chanctx = NULL;
1880
1881 ieee80211_link_chanctx_reservation_complete(iter.link);
1882 ieee80211_chan_bw_change(local, ctx, false, false);
1883 }
1884
1885 /*
1886 * This context might have been a dependency for an already
1887 * ready re-assign reservation interface that was deferred. Do
1888 * not propagate error to the caller though. The in-place
1889 * reservation for originally requested interface has already
1890 * succeeded at this point.
1891 */
1892 for_each_chanctx_user_reserved(local, ctx, &iter) {
1893 struct ieee80211_link_data *link = iter.link;
1894
1895 if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
1896 continue;
1897
1898 if (!link->reserved_ready)
1899 continue;
1900
1901 if (ieee80211_link_get_chanctx(link))
1902 err = ieee80211_link_use_reserved_reassign(link);
1903 else
1904 err = ieee80211_link_use_reserved_assign(link);
1905
1906 if (err) {
1907 link_info(link,
1908 "failed to finalize (re-)assign reservation (err=%d)\n",
1909 err);
1910 ieee80211_link_unreserve_chanctx(link);
1911 cfg80211_stop_iface(local->hw.wiphy,
1912 &link->sdata->wdev,
1913 GFP_KERNEL);
1914 }
1915 }
1916 }
1917
1918 /*
1919 * Finally free old contexts
1920 */
1921
1922 list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1923 if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1924 continue;
1925
1926 ctx->replace_ctx->replace_ctx = NULL;
1927 ctx->replace_ctx->replace_state =
1928 IEEE80211_CHANCTX_REPLACE_NONE;
1929
1930 list_del_rcu(&ctx->list);
1931 kfree_rcu(ctx, rcu_head);
1932 }
1933
1934 return 0;
1935
1936err:
1937 list_for_each_entry(ctx, &local->chanctx_list, list) {
1938 struct ieee80211_chanctx_user_iter iter;
1939
1940 if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1941 continue;
1942
1943 for_each_chanctx_user_reserved(local, ctx, &iter) {
1944 ieee80211_link_unreserve_chanctx(iter.link);
1945 ieee80211_link_chanctx_reservation_complete(iter.link);
1946 }
1947 }
1948
1949 return err;
1950}
1951
1952void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
1953 bool skip_idle_recalc)
1954{
1955 struct ieee80211_sub_if_data *sdata = link->sdata;
1956 struct ieee80211_bss_conf *link_conf = link->conf;
1957 struct ieee80211_local *local = sdata->local;
1958 struct ieee80211_chanctx_conf *conf;
1959 struct ieee80211_chanctx *ctx;
1960 bool use_reserved_switch = false;
1961
1962 lockdep_assert_wiphy(local->hw.wiphy);
1963
1964 conf = rcu_dereference_protected(link_conf->chanctx_conf,
1965 lockdep_is_held(&local->hw.wiphy->mtx));
1966 if (!conf)
1967 return;
1968
1969 ctx = container_of(conf, struct ieee80211_chanctx, conf);
1970
1971 if (link->reserved_chanctx) {
1972 if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
1973 ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
1974 use_reserved_switch = true;
1975
1976 ieee80211_link_unreserve_chanctx(link);
1977 }
1978
1979 ieee80211_assign_link_chanctx(link, NULL, false);
1980 if (ieee80211_chanctx_refcount(local, ctx) == 0)
1981 ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
1982
1983 link->radar_required = false;
1984
1985 /* Unreserving may ready an in-place reservation. */
1986 if (use_reserved_switch)
1987 ieee80211_vif_use_reserved_switch(local);
1988}
1989
1990int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
1991 const struct ieee80211_chan_req *chanreq,
1992 enum ieee80211_chanctx_mode mode,
1993 bool assign_on_failure)
1994{
1995 struct ieee80211_sub_if_data *sdata = link->sdata;
1996 struct ieee80211_local *local = sdata->local;
1997 struct ieee80211_chanctx *ctx;
1998 u8 radar_detect_width = 0;
1999 bool reserved = false;
2000 int radio_idx;
2001 int ret;
2002
2003 lockdep_assert_wiphy(local->hw.wiphy);
2004
2005 if (!ieee80211_vif_link_active(&sdata->vif, link->link_id)) {
2006 ieee80211_link_update_chanreq(link, chanreq);
2007 return 0;
2008 }
2009
2010 ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
2011 &chanreq->oper,
2012 sdata->wdev.iftype);
2013 if (ret < 0)
2014 goto out;
2015 if (ret > 0)
2016 radar_detect_width = BIT(chanreq->oper.width);
2017
2018 link->radar_required = ret;
2019
2020 ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
2021 radar_detect_width, -1);
2022 if (ret < 0)
2023 goto out;
2024
2025 if (!local->in_reconfig)
2026 __ieee80211_link_release_channel(link, false);
2027
2028 ctx = ieee80211_find_chanctx(local, link, chanreq, mode);
2029 /* Note: context is now reserved */
2030 if (ctx)
2031 reserved = true;
2032 else if (!ieee80211_find_available_radio(local, chanreq,
2033 sdata->wdev.radio_mask,
2034 &radio_idx))
2035 ctx = ERR_PTR(-EBUSY);
2036 else
2037 ctx = ieee80211_new_chanctx(local, chanreq, mode,
2038 assign_on_failure, radio_idx);
2039 if (IS_ERR(ctx)) {
2040 ret = PTR_ERR(ctx);
2041 goto out;
2042 }
2043
2044 ieee80211_link_update_chanreq(link, chanreq);
2045
2046 ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure);
2047
2048 if (reserved) {
2049 /* remove reservation */
2050 WARN_ON(link->reserved_chanctx != ctx);
2051 link->reserved_chanctx = NULL;
2052 }
2053
2054 if (ret) {
2055 /* if assign fails refcount stays the same */
2056 if (ieee80211_chanctx_refcount(local, ctx) == 0)
2057 ieee80211_free_chanctx(local, ctx, false);
2058 goto out;
2059 }
2060
2061 ieee80211_recalc_smps_chanctx(local, ctx);
2062 ieee80211_recalc_radar_chanctx(local, ctx);
2063 out:
2064 if (ret)
2065 link->radar_required = false;
2066
2067 return ret;
2068}
2069
2070int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
2071{
2072 struct ieee80211_sub_if_data *sdata = link->sdata;
2073 struct ieee80211_local *local = sdata->local;
2074 struct ieee80211_chanctx *new_ctx;
2075 struct ieee80211_chanctx *old_ctx;
2076 int err;
2077
2078 lockdep_assert_wiphy(local->hw.wiphy);
2079
2080 new_ctx = link->reserved_chanctx;
2081 old_ctx = ieee80211_link_get_chanctx(link);
2082
2083 if (WARN_ON(!new_ctx))
2084 return -EINVAL;
2085
2086 if (WARN_ON(new_ctx->replace_state ==
2087 IEEE80211_CHANCTX_WILL_BE_REPLACED))
2088 return -EINVAL;
2089
2090 if (WARN_ON(link->reserved_ready))
2091 return -EINVAL;
2092
2093 link->reserved_ready = true;
2094
2095 if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
2096 if (old_ctx)
2097 return ieee80211_link_use_reserved_reassign(link);
2098
2099 return ieee80211_link_use_reserved_assign(link);
2100 }
2101
2102 /*
2103 * In-place reservation may need to be finalized now either if:
2104 * a) sdata is taking part in the swapping itself and is the last one
2105 * b) sdata has switched with a re-assign reservation to an existing
2106 * context readying in-place switching of old_ctx
2107 *
2108 * In case of (b) do not propagate the error up because the requested
2109 * sdata already switched successfully. Just spill an extra warning.
2110 * The ieee80211_vif_use_reserved_switch() already stops all necessary
2111 * interfaces upon failure.
2112 */
2113 if ((old_ctx &&
2114 old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
2115 new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
2116 err = ieee80211_vif_use_reserved_switch(local);
2117 if (err && err != -EAGAIN) {
2118 if (new_ctx->replace_state ==
2119 IEEE80211_CHANCTX_REPLACES_OTHER)
2120 return err;
2121
2122 wiphy_info(local->hw.wiphy,
2123 "depending in-place reservation failed (err=%d)\n",
2124 err);
2125 }
2126 }
2127
2128 return 0;
2129}
2130
2131/*
2132 * This is similar to ieee80211_chanctx_compatible(), but rechecks
2133 * against all the links actually using it (except the one that's
2134 * passed, since that one is changing).
2135 * This is done in order to allow changes to the AP's bandwidth for
2136 * wider bandwidth OFDMA purposes, which wouldn't be treated as
2137 * compatible by ieee80211_chanctx_recheck() but is OK if the link
2138 * requesting the update is the only one using it.
2139 */
2140static const struct ieee80211_chan_req *
2141ieee80211_chanctx_recheck(struct ieee80211_local *local,
2142 struct ieee80211_link_data *skip_link,
2143 struct ieee80211_chanctx *ctx,
2144 const struct ieee80211_chan_req *req,
2145 struct ieee80211_chan_req *tmp)
2146{
2147 const struct ieee80211_chan_req *ret = req;
2148 struct ieee80211_chanctx_user_iter iter;
2149
2150 lockdep_assert_wiphy(local->hw.wiphy);
2151
2152 for_each_chanctx_user_all(local, ctx, &iter) {
2153 if (iter.link == skip_link)
2154 continue;
2155
2156 ret = ieee80211_chanreq_compatible(ret, iter.chanreq, tmp);
2157 if (!ret)
2158 return NULL;
2159 }
2160
2161 *tmp = *ret;
2162 return tmp;
2163}
2164
2165int ieee80211_link_change_chanreq(struct ieee80211_link_data *link,
2166 const struct ieee80211_chan_req *chanreq,
2167 u64 *changed)
2168{
2169 struct ieee80211_sub_if_data *sdata = link->sdata;
2170 struct ieee80211_bss_conf *link_conf = link->conf;
2171 struct ieee80211_local *local = sdata->local;
2172 struct ieee80211_chanctx_conf *conf;
2173 struct ieee80211_chanctx *ctx;
2174 const struct ieee80211_chan_req *compat;
2175 struct ieee80211_chan_req tmp;
2176
2177 lockdep_assert_wiphy(local->hw.wiphy);
2178
2179 if (!cfg80211_chandef_usable(sdata->local->hw.wiphy,
2180 &chanreq->oper,
2181 IEEE80211_CHAN_DISABLED))
2182 return -EINVAL;
2183
2184 /* for non-HT 20 MHz the rest doesn't matter */
2185 if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT &&
2186 cfg80211_chandef_identical(&chanreq->oper, &link_conf->chanreq.oper))
2187 return 0;
2188
2189 /* but you cannot switch to/from it */
2190 if (chanreq->oper.width == NL80211_CHAN_WIDTH_20_NOHT ||
2191 link_conf->chanreq.oper.width == NL80211_CHAN_WIDTH_20_NOHT)
2192 return -EINVAL;
2193
2194 conf = rcu_dereference_protected(link_conf->chanctx_conf,
2195 lockdep_is_held(&local->hw.wiphy->mtx));
2196 if (!conf)
2197 return -EINVAL;
2198
2199 ctx = container_of(conf, struct ieee80211_chanctx, conf);
2200
2201 compat = ieee80211_chanctx_recheck(local, link, ctx, chanreq, &tmp);
2202 if (!compat)
2203 return -EINVAL;
2204
2205 switch (ctx->replace_state) {
2206 case IEEE80211_CHANCTX_REPLACE_NONE:
2207 if (!ieee80211_chanctx_reserved_chanreq(local, ctx, compat,
2208 &tmp))
2209 return -EBUSY;
2210 break;
2211 case IEEE80211_CHANCTX_WILL_BE_REPLACED:
2212 /* TODO: Perhaps the bandwidth change could be treated as a
2213 * reservation itself? */
2214 return -EBUSY;
2215 case IEEE80211_CHANCTX_REPLACES_OTHER:
2216 /* channel context that is going to replace another channel
2217 * context doesn't really exist and shouldn't be assigned
2218 * anywhere yet */
2219 WARN_ON(1);
2220 break;
2221 }
2222
2223 ieee80211_link_update_chanreq(link, chanreq);
2224
2225 ieee80211_recalc_chanctx_chantype(local, ctx);
2226
2227 *changed |= BSS_CHANGED_BANDWIDTH;
2228 return 0;
2229}
2230
2231void ieee80211_link_release_channel(struct ieee80211_link_data *link)
2232{
2233 struct ieee80211_sub_if_data *sdata = link->sdata;
2234
2235 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
2236 return;
2237
2238 lockdep_assert_wiphy(sdata->local->hw.wiphy);
2239
2240 if (rcu_access_pointer(link->conf->chanctx_conf))
2241 __ieee80211_link_release_channel(link, false);
2242}
2243
2244void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
2245{
2246 struct ieee80211_sub_if_data *sdata = link->sdata;
2247 unsigned int link_id = link->link_id;
2248 struct ieee80211_bss_conf *link_conf = link->conf;
2249 struct ieee80211_bss_conf *ap_conf;
2250 struct ieee80211_local *local = sdata->local;
2251 struct ieee80211_sub_if_data *ap;
2252 struct ieee80211_chanctx_conf *conf;
2253
2254 lockdep_assert_wiphy(local->hw.wiphy);
2255
2256 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
2257 return;
2258
2259 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
2260
2261 ap_conf = wiphy_dereference(local->hw.wiphy,
2262 ap->vif.link_conf[link_id]);
2263 conf = wiphy_dereference(local->hw.wiphy,
2264 ap_conf->chanctx_conf);
2265 rcu_assign_pointer(link_conf->chanctx_conf, conf);
2266}
2267
2268void ieee80211_iter_chan_contexts_atomic(
2269 struct ieee80211_hw *hw,
2270 void (*iter)(struct ieee80211_hw *hw,
2271 struct ieee80211_chanctx_conf *chanctx_conf,
2272 void *data),
2273 void *iter_data)
2274{
2275 struct ieee80211_local *local = hw_to_local(hw);
2276 struct ieee80211_chanctx *ctx;
2277
2278 rcu_read_lock();
2279 list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
2280 if (ctx->driver_present)
2281 iter(hw, &ctx->conf, iter_data);
2282 rcu_read_unlock();
2283}
2284EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
2285
2286void ieee80211_iter_chan_contexts_mtx(
2287 struct ieee80211_hw *hw,
2288 void (*iter)(struct ieee80211_hw *hw,
2289 struct ieee80211_chanctx_conf *chanctx_conf,
2290 void *data),
2291 void *iter_data)
2292{
2293 struct ieee80211_local *local = hw_to_local(hw);
2294 struct ieee80211_chanctx *ctx;
2295
2296 lockdep_assert_wiphy(hw->wiphy);
2297
2298 list_for_each_entry(ctx, &local->chanctx_list, list)
2299 if (ctx->driver_present)
2300 iter(hw, &ctx->conf, iter_data);
2301}
2302EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_mtx);