1 // SPDX-License-Identifier: GPL-2.0-only
3 * mac80211 - channel management
4 * Copyright 2020 - 2024 Intel Corporation
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"
15 static int ieee80211_chanctx_num_assigned(struct ieee80211_local
*local
,
16 struct ieee80211_chanctx
*ctx
)
18 struct ieee80211_link_data
*link
;
21 lockdep_assert_wiphy(local
->hw
.wiphy
);
23 list_for_each_entry(link
, &ctx
->assigned_links
, assigned_chanctx_list
)
29 static int ieee80211_chanctx_num_reserved(struct ieee80211_local
*local
,
30 struct ieee80211_chanctx
*ctx
)
32 struct ieee80211_link_data
*link
;
35 lockdep_assert_wiphy(local
->hw
.wiphy
);
37 list_for_each_entry(link
, &ctx
->reserved_links
, reserved_chanctx_list
)
43 int ieee80211_chanctx_refcount(struct ieee80211_local
*local
,
44 struct ieee80211_chanctx
*ctx
)
46 return ieee80211_chanctx_num_assigned(local
, ctx
) +
47 ieee80211_chanctx_num_reserved(local
, ctx
);
50 static int ieee80211_num_chanctx(struct ieee80211_local
*local
, int radio_idx
)
52 struct ieee80211_chanctx
*ctx
;
55 lockdep_assert_wiphy(local
->hw
.wiphy
);
57 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
58 if (radio_idx
>= 0 && ctx
->conf
.radio_idx
!= radio_idx
)
66 static bool ieee80211_can_create_new_chanctx(struct ieee80211_local
*local
,
69 lockdep_assert_wiphy(local
->hw
.wiphy
);
71 return ieee80211_num_chanctx(local
, radio_idx
) <
72 ieee80211_max_num_channels(local
, radio_idx
);
75 static struct ieee80211_chanctx
*
76 ieee80211_link_get_chanctx(struct ieee80211_link_data
*link
)
78 struct ieee80211_local
*local __maybe_unused
= link
->sdata
->local
;
79 struct ieee80211_chanctx_conf
*conf
;
81 conf
= rcu_dereference_protected(link
->conf
->chanctx_conf
,
82 lockdep_is_held(&local
->hw
.wiphy
->mtx
));
86 return container_of(conf
, struct ieee80211_chanctx
, conf
);
89 bool ieee80211_chanreq_identical(const struct ieee80211_chan_req
*a
,
90 const struct ieee80211_chan_req
*b
)
92 if (!cfg80211_chandef_identical(&a
->oper
, &b
->oper
))
94 if (!a
->ap
.chan
&& !b
->ap
.chan
)
96 return cfg80211_chandef_identical(&a
->ap
, &b
->ap
);
99 static const struct ieee80211_chan_req
*
100 ieee80211_chanreq_compatible(const struct ieee80211_chan_req
*a
,
101 const struct ieee80211_chan_req
*b
,
102 struct ieee80211_chan_req
*tmp
)
104 const struct cfg80211_chan_def
*compat
;
106 if (a
->ap
.chan
&& b
->ap
.chan
&&
107 !cfg80211_chandef_identical(&a
->ap
, &b
->ap
))
110 compat
= cfg80211_chandef_compatible(&a
->oper
, &b
->oper
);
114 /* Note: later code assumes this always fills & returns tmp if compat */
116 tmp
->ap
= a
->ap
.chan
? a
->ap
: b
->ap
;
120 static const struct ieee80211_chan_req
*
121 ieee80211_chanctx_compatible(struct ieee80211_chanctx
*ctx
,
122 const struct ieee80211_chan_req
*req
,
123 struct ieee80211_chan_req
*tmp
)
125 const struct ieee80211_chan_req
*ret
;
126 struct ieee80211_chan_req tmp2
;
128 *tmp
= (struct ieee80211_chan_req
){
129 .oper
= ctx
->conf
.def
,
133 ret
= ieee80211_chanreq_compatible(tmp
, req
, &tmp2
);
140 static const struct ieee80211_chan_req
*
141 ieee80211_chanctx_reserved_chanreq(struct ieee80211_local
*local
,
142 struct ieee80211_chanctx
*ctx
,
143 const struct ieee80211_chan_req
*req
,
144 struct ieee80211_chan_req
*tmp
)
146 struct ieee80211_link_data
*link
;
148 lockdep_assert_wiphy(local
->hw
.wiphy
);
153 list_for_each_entry(link
, &ctx
->reserved_links
, reserved_chanctx_list
) {
154 req
= ieee80211_chanreq_compatible(&link
->reserved
, req
, tmp
);
162 static const struct ieee80211_chan_req
*
163 ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local
*local
,
164 struct ieee80211_chanctx
*ctx
,
165 const struct ieee80211_chan_req
*compat
,
166 struct ieee80211_chan_req
*tmp
)
168 struct ieee80211_link_data
*link
;
169 const struct ieee80211_chan_req
*comp_def
= compat
;
171 lockdep_assert_wiphy(local
->hw
.wiphy
);
173 list_for_each_entry(link
, &ctx
->assigned_links
, assigned_chanctx_list
) {
174 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
176 if (link
->reserved_chanctx
)
179 comp_def
= ieee80211_chanreq_compatible(&link_conf
->chanreq
,
189 ieee80211_chanctx_can_reserve(struct ieee80211_local
*local
,
190 struct ieee80211_chanctx
*ctx
,
191 const struct ieee80211_chan_req
*req
)
193 struct ieee80211_chan_req tmp
;
195 lockdep_assert_wiphy(local
->hw
.wiphy
);
197 if (!ieee80211_chanctx_reserved_chanreq(local
, ctx
, req
, &tmp
))
200 if (!ieee80211_chanctx_non_reserved_chandef(local
, ctx
, req
, &tmp
))
203 if (!list_empty(&ctx
->reserved_links
) &&
204 ieee80211_chanctx_reserved_chanreq(local
, ctx
, req
, &tmp
))
210 static struct ieee80211_chanctx
*
211 ieee80211_find_reservation_chanctx(struct ieee80211_local
*local
,
212 const struct ieee80211_chan_req
*chanreq
,
213 enum ieee80211_chanctx_mode mode
)
215 struct ieee80211_chanctx
*ctx
;
217 lockdep_assert_wiphy(local
->hw
.wiphy
);
219 if (mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
222 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
223 if (ctx
->replace_state
== IEEE80211_CHANCTX_WILL_BE_REPLACED
)
226 if (ctx
->mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
229 if (!ieee80211_chanctx_can_reserve(local
, ctx
, chanreq
))
238 static enum nl80211_chan_width
ieee80211_get_sta_bw(struct sta_info
*sta
,
239 unsigned int link_id
)
241 enum ieee80211_sta_rx_bandwidth width
;
242 struct link_sta_info
*link_sta
;
244 link_sta
= wiphy_dereference(sta
->local
->hw
.wiphy
, sta
->link
[link_id
]);
246 /* no effect if this STA has no presence on this link */
248 return NL80211_CHAN_WIDTH_20_NOHT
;
250 width
= ieee80211_sta_cap_rx_bw(link_sta
);
253 case IEEE80211_STA_RX_BW_20
:
254 if (link_sta
->pub
->ht_cap
.ht_supported
)
255 return NL80211_CHAN_WIDTH_20
;
257 return NL80211_CHAN_WIDTH_20_NOHT
;
258 case IEEE80211_STA_RX_BW_40
:
259 return NL80211_CHAN_WIDTH_40
;
260 case IEEE80211_STA_RX_BW_80
:
261 return NL80211_CHAN_WIDTH_80
;
262 case IEEE80211_STA_RX_BW_160
:
264 * This applied for both 160 and 80+80. since we use
265 * the returned value to consider degradation of
266 * ctx->conf.min_def, we have to make sure to take
267 * the bigger one (NL80211_CHAN_WIDTH_160).
268 * Otherwise we might try degrading even when not
269 * needed, as the max required sta_bw returned (80+80)
270 * might be smaller than the configured bw (160).
272 return NL80211_CHAN_WIDTH_160
;
273 case IEEE80211_STA_RX_BW_320
:
274 return NL80211_CHAN_WIDTH_320
;
277 return NL80211_CHAN_WIDTH_20
;
281 static enum nl80211_chan_width
282 ieee80211_get_max_required_bw(struct ieee80211_link_data
*link
)
284 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
285 unsigned int link_id
= link
->link_id
;
286 enum nl80211_chan_width max_bw
= NL80211_CHAN_WIDTH_20_NOHT
;
287 struct sta_info
*sta
;
289 lockdep_assert_wiphy(sdata
->local
->hw
.wiphy
);
291 list_for_each_entry(sta
, &sdata
->local
->sta_list
, list
) {
292 if (sdata
!= sta
->sdata
&&
293 !(sta
->sdata
->bss
&& sta
->sdata
->bss
== sdata
->bss
))
296 max_bw
= max(max_bw
, ieee80211_get_sta_bw(sta
, link_id
));
302 static enum nl80211_chan_width
303 ieee80211_get_chanctx_max_required_bw(struct ieee80211_local
*local
,
304 struct ieee80211_chanctx
*ctx
,
305 struct ieee80211_link_data
*rsvd_for
,
308 struct ieee80211_sub_if_data
*sdata
;
309 struct ieee80211_link_data
*link
;
310 enum nl80211_chan_width max_bw
= NL80211_CHAN_WIDTH_20_NOHT
;
312 if (WARN_ON(check_reserved
&& rsvd_for
))
313 return ctx
->conf
.def
.width
;
315 for_each_sdata_link(local
, link
) {
316 enum nl80211_chan_width width
= NL80211_CHAN_WIDTH_20_NOHT
;
318 if (check_reserved
) {
319 if (link
->reserved_chanctx
!= ctx
)
321 } else if (link
!= rsvd_for
&&
322 rcu_access_pointer(link
->conf
->chanctx_conf
) != &ctx
->conf
)
325 switch (link
->sdata
->vif
.type
) {
326 case NL80211_IFTYPE_AP
:
327 case NL80211_IFTYPE_AP_VLAN
:
328 width
= ieee80211_get_max_required_bw(link
);
330 case NL80211_IFTYPE_STATION
:
332 * The ap's sta->bandwidth is not set yet at this
333 * point, so take the width from the chandef, but
334 * account also for TDLS peers
336 width
= max(link
->conf
->chanreq
.oper
.width
,
337 ieee80211_get_max_required_bw(link
));
339 case NL80211_IFTYPE_P2P_DEVICE
:
340 case NL80211_IFTYPE_NAN
:
342 case NL80211_IFTYPE_ADHOC
:
343 case NL80211_IFTYPE_MESH_POINT
:
344 case NL80211_IFTYPE_OCB
:
345 width
= link
->conf
->chanreq
.oper
.width
;
347 case NL80211_IFTYPE_WDS
:
348 case NL80211_IFTYPE_UNSPECIFIED
:
349 case NUM_NL80211_IFTYPES
:
350 case NL80211_IFTYPE_MONITOR
:
351 case NL80211_IFTYPE_P2P_CLIENT
:
352 case NL80211_IFTYPE_P2P_GO
:
356 max_bw
= max(max_bw
, width
);
359 /* use the configured bandwidth in case of monitor interface */
360 sdata
= wiphy_dereference(local
->hw
.wiphy
, local
->monitor_sdata
);
362 rcu_access_pointer(sdata
->vif
.bss_conf
.chanctx_conf
) == &ctx
->conf
)
363 max_bw
= max(max_bw
, ctx
->conf
.def
.width
);
369 * recalc the min required chan width of the channel context, which is
370 * the max of min required widths of all the interfaces bound to this
374 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local
*local
,
375 struct ieee80211_chanctx
*ctx
,
376 struct ieee80211_link_data
*rsvd_for
,
379 enum nl80211_chan_width max_bw
;
380 struct cfg80211_chan_def min_def
;
382 lockdep_assert_wiphy(local
->hw
.wiphy
);
384 /* don't optimize non-20MHz based and radar_enabled confs */
385 if (ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_5
||
386 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_10
||
387 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_1
||
388 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_2
||
389 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_4
||
390 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_8
||
391 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_16
||
392 ctx
->conf
.radar_enabled
) {
393 ctx
->conf
.min_def
= ctx
->conf
.def
;
397 max_bw
= ieee80211_get_chanctx_max_required_bw(local
, ctx
, rsvd_for
,
400 /* downgrade chandef up to max_bw */
401 min_def
= ctx
->conf
.def
;
402 while (min_def
.width
> max_bw
)
403 ieee80211_chandef_downgrade(&min_def
, NULL
);
405 if (cfg80211_chandef_identical(&ctx
->conf
.min_def
, &min_def
))
408 ctx
->conf
.min_def
= min_def
;
409 if (!ctx
->driver_present
)
412 return IEEE80211_CHANCTX_CHANGE_MIN_WIDTH
;
415 static void ieee80211_chan_bw_change(struct ieee80211_local
*local
,
416 struct ieee80211_chanctx
*ctx
,
417 bool reserved
, bool narrowed
)
419 struct sta_info
*sta
;
420 struct ieee80211_supported_band
*sband
=
421 local
->hw
.wiphy
->bands
[ctx
->conf
.def
.chan
->band
];
424 list_for_each_entry_rcu(sta
, &local
->sta_list
,
426 struct ieee80211_sub_if_data
*sdata
= sta
->sdata
;
427 enum ieee80211_sta_rx_bandwidth new_sta_bw
;
428 unsigned int link_id
;
430 if (!ieee80211_sdata_running(sta
->sdata
))
433 for (link_id
= 0; link_id
< ARRAY_SIZE(sta
->sdata
->link
); link_id
++) {
434 struct ieee80211_link_data
*link
=
435 rcu_dereference(sdata
->link
[link_id
]);
436 struct ieee80211_bss_conf
*link_conf
;
437 struct cfg80211_chan_def
*new_chandef
;
438 struct link_sta_info
*link_sta
;
443 link_conf
= link
->conf
;
445 if (rcu_access_pointer(link_conf
->chanctx_conf
) != &ctx
->conf
)
448 link_sta
= rcu_dereference(sta
->link
[link_id
]);
453 new_chandef
= &link
->reserved
.oper
;
455 new_chandef
= &link_conf
->chanreq
.oper
;
457 new_sta_bw
= _ieee80211_sta_cur_vht_bw(link_sta
,
461 if (new_sta_bw
== link_sta
->pub
->bandwidth
)
464 /* vif changed to narrow BW and narrow BW for station wasn't
465 * requested or vise versa */
466 if ((new_sta_bw
< link_sta
->pub
->bandwidth
) == !narrowed
)
469 link_sta
->pub
->bandwidth
= new_sta_bw
;
470 rate_control_rate_update(local
, sband
, sta
, link_id
,
471 IEEE80211_RC_BW_CHANGED
);
478 * recalc the min required chan width of the channel context, which is
479 * the max of min required widths of all the interfaces bound to this
482 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local
*local
,
483 struct ieee80211_chanctx
*ctx
,
484 struct ieee80211_link_data
*rsvd_for
,
487 u32 changed
= _ieee80211_recalc_chanctx_min_def(local
, ctx
, rsvd_for
,
493 /* check is BW narrowed */
494 ieee80211_chan_bw_change(local
, ctx
, false, true);
496 drv_change_chanctx(local
, ctx
, changed
);
498 /* check is BW wider */
499 ieee80211_chan_bw_change(local
, ctx
, false, false);
502 static void _ieee80211_change_chanctx(struct ieee80211_local
*local
,
503 struct ieee80211_chanctx
*ctx
,
504 struct ieee80211_chanctx
*old_ctx
,
505 const struct ieee80211_chan_req
*chanreq
,
506 struct ieee80211_link_data
*rsvd_for
)
508 const struct cfg80211_chan_def
*chandef
= &chanreq
->oper
;
509 struct ieee80211_chan_req ctx_req
= {
510 .oper
= ctx
->conf
.def
,
515 /* expected to handle only 20/40/80/160/320 channel widths */
516 switch (chandef
->width
) {
517 case NL80211_CHAN_WIDTH_20_NOHT
:
518 case NL80211_CHAN_WIDTH_20
:
519 case NL80211_CHAN_WIDTH_40
:
520 case NL80211_CHAN_WIDTH_80
:
521 case NL80211_CHAN_WIDTH_80P80
:
522 case NL80211_CHAN_WIDTH_160
:
523 case NL80211_CHAN_WIDTH_320
:
529 /* Check maybe BW narrowed - we do this _before_ calling recalc_chanctx_min_def
530 * due to maybe not returning from it, e.g in case new context was added
531 * first time with all parameters up to date.
533 ieee80211_chan_bw_change(local
, old_ctx
, false, true);
535 if (ieee80211_chanreq_identical(&ctx_req
, chanreq
)) {
536 ieee80211_recalc_chanctx_min_def(local
, ctx
, rsvd_for
, false);
540 WARN_ON(ieee80211_chanctx_refcount(local
, ctx
) > 1 &&
541 !cfg80211_chandef_compatible(&ctx
->conf
.def
, &chanreq
->oper
));
543 ieee80211_remove_wbrf(local
, &ctx
->conf
.def
);
545 if (!cfg80211_chandef_identical(&ctx
->conf
.def
, &chanreq
->oper
)) {
546 if (ctx
->conf
.def
.width
!= chanreq
->oper
.width
)
547 changed
|= IEEE80211_CHANCTX_CHANGE_WIDTH
;
548 if (ctx
->conf
.def
.punctured
!= chanreq
->oper
.punctured
)
549 changed
|= IEEE80211_CHANCTX_CHANGE_PUNCTURING
;
551 if (!cfg80211_chandef_identical(&ctx
->conf
.ap
, &chanreq
->ap
))
552 changed
|= IEEE80211_CHANCTX_CHANGE_AP
;
553 ctx
->conf
.def
= *chandef
;
554 ctx
->conf
.ap
= chanreq
->ap
;
556 /* check if min chanctx also changed */
557 changed
|= _ieee80211_recalc_chanctx_min_def(local
, ctx
, rsvd_for
, false);
559 ieee80211_add_wbrf(local
, &ctx
->conf
.def
);
561 drv_change_chanctx(local
, ctx
, changed
);
563 /* check if BW is wider */
564 ieee80211_chan_bw_change(local
, old_ctx
, false, false);
567 static void ieee80211_change_chanctx(struct ieee80211_local
*local
,
568 struct ieee80211_chanctx
*ctx
,
569 struct ieee80211_chanctx
*old_ctx
,
570 const struct ieee80211_chan_req
*chanreq
)
572 _ieee80211_change_chanctx(local
, ctx
, old_ctx
, chanreq
, NULL
);
575 /* Note: if successful, the returned chanctx is reserved for the link */
576 static struct ieee80211_chanctx
*
577 ieee80211_find_chanctx(struct ieee80211_local
*local
,
578 struct ieee80211_link_data
*link
,
579 const struct ieee80211_chan_req
*chanreq
,
580 enum ieee80211_chanctx_mode mode
)
582 struct ieee80211_chan_req tmp
;
583 struct ieee80211_chanctx
*ctx
;
585 lockdep_assert_wiphy(local
->hw
.wiphy
);
587 if (mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
590 if (WARN_ON(link
->reserved_chanctx
))
593 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
594 const struct ieee80211_chan_req
*compat
;
596 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACE_NONE
)
599 if (ctx
->mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
602 compat
= ieee80211_chanctx_compatible(ctx
, chanreq
, &tmp
);
606 compat
= ieee80211_chanctx_reserved_chanreq(local
, ctx
,
612 * Reserve the chanctx temporarily, as the driver might change
613 * active links during callbacks we make into it below and/or
614 * later during assignment, which could (otherwise) cause the
615 * context to actually be removed.
617 link
->reserved_chanctx
= ctx
;
618 list_add(&link
->reserved_chanctx_list
,
619 &ctx
->reserved_links
);
621 ieee80211_change_chanctx(local
, ctx
, ctx
, compat
);
629 bool ieee80211_is_radar_required(struct ieee80211_local
*local
)
631 struct ieee80211_link_data
*link
;
633 lockdep_assert_wiphy(local
->hw
.wiphy
);
635 for_each_sdata_link(local
, link
) {
636 if (link
->radar_required
)
644 ieee80211_chanctx_radar_required(struct ieee80211_local
*local
,
645 struct ieee80211_chanctx
*ctx
)
647 struct ieee80211_chanctx_conf
*conf
= &ctx
->conf
;
648 struct ieee80211_link_data
*link
;
650 lockdep_assert_wiphy(local
->hw
.wiphy
);
652 for_each_sdata_link(local
, link
) {
653 if (rcu_access_pointer(link
->conf
->chanctx_conf
) != conf
)
655 if (!link
->radar_required
)
663 static struct ieee80211_chanctx
*
664 ieee80211_alloc_chanctx(struct ieee80211_local
*local
,
665 const struct ieee80211_chan_req
*chanreq
,
666 enum ieee80211_chanctx_mode mode
,
669 struct ieee80211_chanctx
*ctx
;
671 lockdep_assert_wiphy(local
->hw
.wiphy
);
673 ctx
= kzalloc(sizeof(*ctx
) + local
->hw
.chanctx_data_size
, GFP_KERNEL
);
677 INIT_LIST_HEAD(&ctx
->assigned_links
);
678 INIT_LIST_HEAD(&ctx
->reserved_links
);
679 ctx
->conf
.def
= chanreq
->oper
;
680 ctx
->conf
.ap
= chanreq
->ap
;
681 ctx
->conf
.rx_chains_static
= 1;
682 ctx
->conf
.rx_chains_dynamic
= 1;
684 ctx
->conf
.radar_enabled
= false;
685 ctx
->conf
.radio_idx
= radio_idx
;
686 ctx
->radar_detected
= false;
687 _ieee80211_recalc_chanctx_min_def(local
, ctx
, NULL
, false);
692 static int ieee80211_add_chanctx(struct ieee80211_local
*local
,
693 struct ieee80211_chanctx
*ctx
)
698 lockdep_assert_wiphy(local
->hw
.wiphy
);
700 ieee80211_add_wbrf(local
, &ctx
->conf
.def
);
702 /* turn idle off *before* setting channel -- some drivers need that */
703 changed
= ieee80211_idle_off(local
);
705 ieee80211_hw_config(local
, changed
);
707 err
= drv_add_chanctx(local
, ctx
);
709 ieee80211_recalc_idle(local
);
716 static struct ieee80211_chanctx
*
717 ieee80211_new_chanctx(struct ieee80211_local
*local
,
718 const struct ieee80211_chan_req
*chanreq
,
719 enum ieee80211_chanctx_mode mode
,
720 bool assign_on_failure
,
723 struct ieee80211_chanctx
*ctx
;
726 lockdep_assert_wiphy(local
->hw
.wiphy
);
728 ctx
= ieee80211_alloc_chanctx(local
, chanreq
, mode
, radio_idx
);
730 return ERR_PTR(-ENOMEM
);
732 err
= ieee80211_add_chanctx(local
, ctx
);
733 if (!assign_on_failure
&& err
) {
737 /* We ignored a driver error, see _ieee80211_set_active_links */
738 WARN_ON_ONCE(err
&& !local
->in_reconfig
);
740 list_add_rcu(&ctx
->list
, &local
->chanctx_list
);
744 static void ieee80211_del_chanctx(struct ieee80211_local
*local
,
745 struct ieee80211_chanctx
*ctx
,
746 bool skip_idle_recalc
)
748 lockdep_assert_wiphy(local
->hw
.wiphy
);
750 drv_remove_chanctx(local
, ctx
);
752 if (!skip_idle_recalc
)
753 ieee80211_recalc_idle(local
);
755 ieee80211_remove_wbrf(local
, &ctx
->conf
.def
);
758 static void ieee80211_free_chanctx(struct ieee80211_local
*local
,
759 struct ieee80211_chanctx
*ctx
,
760 bool skip_idle_recalc
)
762 lockdep_assert_wiphy(local
->hw
.wiphy
);
764 WARN_ON_ONCE(ieee80211_chanctx_refcount(local
, ctx
) != 0);
766 list_del_rcu(&ctx
->list
);
767 ieee80211_del_chanctx(local
, ctx
, skip_idle_recalc
);
768 kfree_rcu(ctx
, rcu_head
);
771 void ieee80211_recalc_chanctx_chantype(struct ieee80211_local
*local
,
772 struct ieee80211_chanctx
*ctx
)
774 struct ieee80211_chanctx_conf
*conf
= &ctx
->conf
;
775 const struct ieee80211_chan_req
*compat
= NULL
;
776 struct ieee80211_link_data
*link
;
777 struct ieee80211_chan_req tmp
;
778 struct sta_info
*sta
;
780 lockdep_assert_wiphy(local
->hw
.wiphy
);
782 for_each_sdata_link(local
, link
) {
783 struct ieee80211_bss_conf
*link_conf
;
785 if (link
->sdata
->vif
.type
== NL80211_IFTYPE_AP_VLAN
)
788 link_conf
= link
->conf
;
790 if (rcu_access_pointer(link_conf
->chanctx_conf
) != conf
)
794 compat
= &link_conf
->chanreq
;
796 compat
= ieee80211_chanreq_compatible(&link_conf
->chanreq
,
798 if (WARN_ON_ONCE(!compat
))
802 if (WARN_ON_ONCE(!compat
))
805 /* TDLS peers can sometimes affect the chandef width */
806 list_for_each_entry(sta
, &local
->sta_list
, list
) {
807 struct ieee80211_sub_if_data
*sdata
= sta
->sdata
;
808 struct ieee80211_chan_req tdls_chanreq
= {};
811 if (!sta
->uploaded
||
812 !test_sta_flag(sta
, WLAN_STA_TDLS_WIDER_BW
) ||
813 !test_sta_flag(sta
, WLAN_STA_AUTHORIZED
) ||
814 !sta
->tdls_chandef
.chan
)
817 tdls_link_id
= ieee80211_tdls_sta_link_id(sta
);
818 link
= sdata_dereference(sdata
->link
[tdls_link_id
], sdata
);
822 if (rcu_access_pointer(link
->conf
->chanctx_conf
) != conf
)
825 tdls_chanreq
.oper
= sta
->tdls_chandef
;
827 /* note this always fills and returns &tmp if compat */
828 compat
= ieee80211_chanreq_compatible(&tdls_chanreq
,
830 if (WARN_ON_ONCE(!compat
))
834 ieee80211_change_chanctx(local
, ctx
, ctx
, compat
);
837 static void ieee80211_recalc_radar_chanctx(struct ieee80211_local
*local
,
838 struct ieee80211_chanctx
*chanctx
)
842 lockdep_assert_wiphy(local
->hw
.wiphy
);
844 radar_enabled
= ieee80211_chanctx_radar_required(local
, chanctx
);
846 if (radar_enabled
== chanctx
->conf
.radar_enabled
)
849 chanctx
->conf
.radar_enabled
= radar_enabled
;
851 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RADAR
);
854 static int ieee80211_assign_link_chanctx(struct ieee80211_link_data
*link
,
855 struct ieee80211_chanctx
*new_ctx
,
856 bool assign_on_failure
)
858 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
859 struct ieee80211_local
*local
= sdata
->local
;
860 struct ieee80211_chanctx_conf
*conf
;
861 struct ieee80211_chanctx
*curr_ctx
= NULL
;
865 if (WARN_ON(sdata
->vif
.type
== NL80211_IFTYPE_NAN
))
868 conf
= rcu_dereference_protected(link
->conf
->chanctx_conf
,
869 lockdep_is_held(&local
->hw
.wiphy
->mtx
));
872 curr_ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
874 drv_unassign_vif_chanctx(local
, sdata
, link
->conf
, curr_ctx
);
876 list_del(&link
->assigned_chanctx_list
);
880 /* recalc considering the link we'll use it for now */
881 ieee80211_recalc_chanctx_min_def(local
, new_ctx
, link
, false);
883 ret
= drv_assign_vif_chanctx(local
, sdata
, link
->conf
, new_ctx
);
884 if (assign_on_failure
|| !ret
) {
885 /* Need to continue, see _ieee80211_set_active_links */
886 WARN_ON_ONCE(ret
&& !local
->in_reconfig
);
889 /* succeeded, so commit it to the data structures */
890 conf
= &new_ctx
->conf
;
891 list_add(&link
->assigned_chanctx_list
,
892 &new_ctx
->assigned_links
);
898 rcu_assign_pointer(link
->conf
->chanctx_conf
, conf
);
900 if (curr_ctx
&& ieee80211_chanctx_num_assigned(local
, curr_ctx
) > 0) {
901 ieee80211_recalc_chanctx_chantype(local
, curr_ctx
);
902 ieee80211_recalc_smps_chanctx(local
, curr_ctx
);
903 ieee80211_recalc_radar_chanctx(local
, curr_ctx
);
904 ieee80211_recalc_chanctx_min_def(local
, curr_ctx
, NULL
, false);
907 if (new_ctx
&& ieee80211_chanctx_num_assigned(local
, new_ctx
) > 0) {
908 ieee80211_recalc_txpower(sdata
, false);
909 ieee80211_recalc_chanctx_min_def(local
, new_ctx
, NULL
, false);
915 struct ieee80211_link_data
*tmp
;
918 for_each_sdata_link(local
, tmp
) {
919 if (rcu_access_pointer(tmp
->conf
->chanctx_conf
)) {
926 if (new_idle
!= sdata
->vif
.cfg
.idle
) {
927 sdata
->vif
.cfg
.idle
= new_idle
;
929 if (sdata
->vif
.type
!= NL80211_IFTYPE_P2P_DEVICE
&&
930 sdata
->vif
.type
!= NL80211_IFTYPE_MONITOR
)
931 ieee80211_vif_cfg_change_notify(sdata
, BSS_CHANGED_IDLE
);
934 ieee80211_check_fast_xmit_iface(sdata
);
939 void ieee80211_recalc_smps_chanctx(struct ieee80211_local
*local
,
940 struct ieee80211_chanctx
*chanctx
)
942 struct ieee80211_sub_if_data
*sdata
;
943 u8 rx_chains_static
, rx_chains_dynamic
;
944 struct ieee80211_link_data
*link
;
946 lockdep_assert_wiphy(local
->hw
.wiphy
);
948 rx_chains_static
= 1;
949 rx_chains_dynamic
= 1;
951 for_each_sdata_link(local
, link
) {
952 u8 needed_static
, needed_dynamic
;
954 switch (link
->sdata
->vif
.type
) {
955 case NL80211_IFTYPE_STATION
:
956 if (!link
->sdata
->u
.mgd
.associated
)
959 case NL80211_IFTYPE_AP
:
960 case NL80211_IFTYPE_ADHOC
:
961 case NL80211_IFTYPE_MESH_POINT
:
962 case NL80211_IFTYPE_OCB
:
968 if (rcu_access_pointer(link
->conf
->chanctx_conf
) != &chanctx
->conf
)
971 switch (link
->smps_mode
) {
973 WARN_ONCE(1, "Invalid SMPS mode %d\n",
976 case IEEE80211_SMPS_OFF
:
977 needed_static
= link
->needed_rx_chains
;
978 needed_dynamic
= link
->needed_rx_chains
;
980 case IEEE80211_SMPS_DYNAMIC
:
982 needed_dynamic
= link
->needed_rx_chains
;
984 case IEEE80211_SMPS_STATIC
:
990 rx_chains_static
= max(rx_chains_static
, needed_static
);
991 rx_chains_dynamic
= max(rx_chains_dynamic
, needed_dynamic
);
994 /* Disable SMPS for the monitor interface */
995 sdata
= wiphy_dereference(local
->hw
.wiphy
, local
->monitor_sdata
);
997 rcu_access_pointer(sdata
->vif
.bss_conf
.chanctx_conf
) == &chanctx
->conf
)
998 rx_chains_dynamic
= rx_chains_static
= local
->rx_chains
;
1000 if (rx_chains_static
== chanctx
->conf
.rx_chains_static
&&
1001 rx_chains_dynamic
== chanctx
->conf
.rx_chains_dynamic
)
1004 chanctx
->conf
.rx_chains_static
= rx_chains_static
;
1005 chanctx
->conf
.rx_chains_dynamic
= rx_chains_dynamic
;
1006 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RX_CHAINS
);
1010 __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data
*link
,
1013 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1014 unsigned int link_id
= link
->link_id
;
1015 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
1016 struct ieee80211_local
*local __maybe_unused
= sdata
->local
;
1017 struct ieee80211_sub_if_data
*vlan
;
1018 struct ieee80211_chanctx_conf
*conf
;
1020 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP
))
1023 lockdep_assert_wiphy(local
->hw
.wiphy
);
1025 /* Check that conf exists, even when clearing this function
1026 * must be called with the AP's channel context still there
1027 * as it would otherwise cause VLANs to have an invalid
1028 * channel context pointer for a while, possibly pointing
1029 * to a channel context that has already been freed.
1031 conf
= rcu_dereference_protected(link_conf
->chanctx_conf
,
1032 lockdep_is_held(&local
->hw
.wiphy
->mtx
));
1038 list_for_each_entry(vlan
, &sdata
->u
.ap
.vlans
, u
.vlan
.list
) {
1039 struct ieee80211_bss_conf
*vlan_conf
;
1041 vlan_conf
= wiphy_dereference(local
->hw
.wiphy
,
1042 vlan
->vif
.link_conf
[link_id
]);
1043 if (WARN_ON(!vlan_conf
))
1046 rcu_assign_pointer(vlan_conf
->chanctx_conf
, conf
);
1050 void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data
*link
,
1053 struct ieee80211_local
*local
= link
->sdata
->local
;
1055 lockdep_assert_wiphy(local
->hw
.wiphy
);
1057 __ieee80211_link_copy_chanctx_to_vlans(link
, clear
);
1060 int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data
*link
)
1062 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1063 struct ieee80211_chanctx
*ctx
= link
->reserved_chanctx
;
1065 lockdep_assert_wiphy(sdata
->local
->hw
.wiphy
);
1070 list_del(&link
->reserved_chanctx_list
);
1071 link
->reserved_chanctx
= NULL
;
1073 if (ieee80211_chanctx_refcount(sdata
->local
, ctx
) == 0) {
1074 if (ctx
->replace_state
== IEEE80211_CHANCTX_REPLACES_OTHER
) {
1075 if (WARN_ON(!ctx
->replace_ctx
))
1078 WARN_ON(ctx
->replace_ctx
->replace_state
!=
1079 IEEE80211_CHANCTX_WILL_BE_REPLACED
);
1080 WARN_ON(ctx
->replace_ctx
->replace_ctx
!= ctx
);
1082 ctx
->replace_ctx
->replace_ctx
= NULL
;
1083 ctx
->replace_ctx
->replace_state
=
1084 IEEE80211_CHANCTX_REPLACE_NONE
;
1086 list_del_rcu(&ctx
->list
);
1087 kfree_rcu(ctx
, rcu_head
);
1089 ieee80211_free_chanctx(sdata
->local
, ctx
, false);
1096 static struct ieee80211_chanctx
*
1097 ieee80211_replace_chanctx(struct ieee80211_local
*local
,
1098 const struct ieee80211_chan_req
*chanreq
,
1099 enum ieee80211_chanctx_mode mode
,
1100 struct ieee80211_chanctx
*curr_ctx
)
1102 struct ieee80211_chanctx
*new_ctx
, *ctx
;
1103 struct wiphy
*wiphy
= local
->hw
.wiphy
;
1104 const struct wiphy_radio
*radio
;
1106 if (!curr_ctx
|| (curr_ctx
->replace_state
==
1107 IEEE80211_CHANCTX_WILL_BE_REPLACED
) ||
1108 !list_empty(&curr_ctx
->reserved_links
)) {
1110 * Another link already requested this context for a
1111 * reservation. Find another one hoping all links assigned
1112 * to it will also switch soon enough.
1114 * TODO: This needs a little more work as some cases
1115 * (more than 2 chanctx capable devices) may fail which could
1116 * otherwise succeed provided some channel context juggling was
1119 * Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
1120 * link2 from ctx1 request new different chandefs starting 2
1121 * in-place reserations with ctx4 and ctx5 replacing ctx1 and
1122 * ctx2 respectively. Next link5 and link6 from ctx3 reserve
1123 * ctx4. If link3 and link4 remain on ctx2 as they are then this
1124 * fails unless `replace_ctx` from ctx5 is replaced with ctx3.
1126 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1127 if (ctx
->replace_state
!=
1128 IEEE80211_CHANCTX_REPLACE_NONE
)
1131 if (!list_empty(&ctx
->reserved_links
))
1134 if (ctx
->conf
.radio_idx
>= 0) {
1135 radio
= &wiphy
->radio
[ctx
->conf
.radio_idx
];
1136 if (!cfg80211_radio_chandef_valid(radio
, &chanreq
->oper
))
1146 * If that's true then all available contexts already have reservations
1147 * and cannot be used.
1149 if (!curr_ctx
|| (curr_ctx
->replace_state
==
1150 IEEE80211_CHANCTX_WILL_BE_REPLACED
) ||
1151 !list_empty(&curr_ctx
->reserved_links
))
1152 return ERR_PTR(-EBUSY
);
1154 new_ctx
= ieee80211_alloc_chanctx(local
, chanreq
, mode
, -1);
1156 return ERR_PTR(-ENOMEM
);
1158 new_ctx
->replace_ctx
= curr_ctx
;
1159 new_ctx
->replace_state
= IEEE80211_CHANCTX_REPLACES_OTHER
;
1161 curr_ctx
->replace_ctx
= new_ctx
;
1162 curr_ctx
->replace_state
= IEEE80211_CHANCTX_WILL_BE_REPLACED
;
1164 list_add_rcu(&new_ctx
->list
, &local
->chanctx_list
);
1170 ieee80211_find_available_radio(struct ieee80211_local
*local
,
1171 const struct ieee80211_chan_req
*chanreq
,
1174 struct wiphy
*wiphy
= local
->hw
.wiphy
;
1175 const struct wiphy_radio
*radio
;
1179 if (!wiphy
->n_radio
)
1182 for (i
= 0; i
< wiphy
->n_radio
; i
++) {
1183 radio
= &wiphy
->radio
[i
];
1184 if (!cfg80211_radio_chandef_valid(radio
, &chanreq
->oper
))
1187 if (!ieee80211_can_create_new_chanctx(local
, i
))
1197 int ieee80211_link_reserve_chanctx(struct ieee80211_link_data
*link
,
1198 const struct ieee80211_chan_req
*chanreq
,
1199 enum ieee80211_chanctx_mode mode
,
1200 bool radar_required
)
1202 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1203 struct ieee80211_local
*local
= sdata
->local
;
1204 struct ieee80211_chanctx
*new_ctx
, *curr_ctx
;
1207 lockdep_assert_wiphy(local
->hw
.wiphy
);
1209 curr_ctx
= ieee80211_link_get_chanctx(link
);
1210 if (curr_ctx
&& !local
->ops
->switch_vif_chanctx
)
1213 new_ctx
= ieee80211_find_reservation_chanctx(local
, chanreq
, mode
);
1215 if (ieee80211_can_create_new_chanctx(local
, -1) &&
1216 ieee80211_find_available_radio(local
, chanreq
, &radio_idx
))
1217 new_ctx
= ieee80211_new_chanctx(local
, chanreq
, mode
,
1220 new_ctx
= ieee80211_replace_chanctx(local
, chanreq
,
1222 if (IS_ERR(new_ctx
))
1223 return PTR_ERR(new_ctx
);
1226 list_add(&link
->reserved_chanctx_list
, &new_ctx
->reserved_links
);
1227 link
->reserved_chanctx
= new_ctx
;
1228 link
->reserved
= *chanreq
;
1229 link
->reserved_radar_required
= radar_required
;
1230 link
->reserved_ready
= false;
1236 ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data
*link
)
1238 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1240 switch (sdata
->vif
.type
) {
1241 case NL80211_IFTYPE_ADHOC
:
1242 case NL80211_IFTYPE_AP
:
1243 case NL80211_IFTYPE_MESH_POINT
:
1244 case NL80211_IFTYPE_OCB
:
1245 wiphy_work_queue(sdata
->local
->hw
.wiphy
,
1246 &link
->csa
.finalize_work
);
1248 case NL80211_IFTYPE_STATION
:
1249 wiphy_delayed_work_queue(sdata
->local
->hw
.wiphy
,
1250 &link
->u
.mgd
.csa
.switch_work
, 0);
1252 case NL80211_IFTYPE_UNSPECIFIED
:
1253 case NL80211_IFTYPE_AP_VLAN
:
1254 case NL80211_IFTYPE_WDS
:
1255 case NL80211_IFTYPE_MONITOR
:
1256 case NL80211_IFTYPE_P2P_CLIENT
:
1257 case NL80211_IFTYPE_P2P_GO
:
1258 case NL80211_IFTYPE_P2P_DEVICE
:
1259 case NL80211_IFTYPE_NAN
:
1260 case NUM_NL80211_IFTYPES
:
1267 ieee80211_link_update_chanreq(struct ieee80211_link_data
*link
,
1268 const struct ieee80211_chan_req
*chanreq
)
1270 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1271 unsigned int link_id
= link
->link_id
;
1272 struct ieee80211_sub_if_data
*vlan
;
1274 link
->conf
->chanreq
= *chanreq
;
1276 if (sdata
->vif
.type
!= NL80211_IFTYPE_AP
)
1279 list_for_each_entry(vlan
, &sdata
->u
.ap
.vlans
, u
.vlan
.list
) {
1280 struct ieee80211_bss_conf
*vlan_conf
;
1282 vlan_conf
= wiphy_dereference(sdata
->local
->hw
.wiphy
,
1283 vlan
->vif
.link_conf
[link_id
]);
1284 if (WARN_ON(!vlan_conf
))
1287 vlan_conf
->chanreq
= *chanreq
;
1292 ieee80211_link_use_reserved_reassign(struct ieee80211_link_data
*link
)
1294 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1295 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
1296 struct ieee80211_local
*local
= sdata
->local
;
1297 struct ieee80211_vif_chanctx_switch vif_chsw
[1] = {};
1298 struct ieee80211_chanctx
*old_ctx
, *new_ctx
;
1299 const struct ieee80211_chan_req
*chanreq
;
1300 struct ieee80211_chan_req tmp
;
1304 lockdep_assert_wiphy(local
->hw
.wiphy
);
1306 new_ctx
= link
->reserved_chanctx
;
1307 old_ctx
= ieee80211_link_get_chanctx(link
);
1309 if (WARN_ON(!link
->reserved_ready
))
1312 if (WARN_ON(!new_ctx
))
1315 if (WARN_ON(!old_ctx
))
1318 if (WARN_ON(new_ctx
->replace_state
==
1319 IEEE80211_CHANCTX_REPLACES_OTHER
))
1322 chanreq
= ieee80211_chanctx_non_reserved_chandef(local
, new_ctx
,
1325 if (WARN_ON(!chanreq
))
1328 if (link_conf
->chanreq
.oper
.width
!= link
->reserved
.oper
.width
)
1329 changed
= BSS_CHANGED_BANDWIDTH
;
1331 ieee80211_link_update_chanreq(link
, &link
->reserved
);
1333 _ieee80211_change_chanctx(local
, new_ctx
, old_ctx
, chanreq
, link
);
1335 vif_chsw
[0].vif
= &sdata
->vif
;
1336 vif_chsw
[0].old_ctx
= &old_ctx
->conf
;
1337 vif_chsw
[0].new_ctx
= &new_ctx
->conf
;
1338 vif_chsw
[0].link_conf
= link
->conf
;
1340 list_del(&link
->reserved_chanctx_list
);
1341 link
->reserved_chanctx
= NULL
;
1343 err
= drv_switch_vif_chanctx(local
, vif_chsw
, 1,
1344 CHANCTX_SWMODE_REASSIGN_VIF
);
1346 if (ieee80211_chanctx_refcount(local
, new_ctx
) == 0)
1347 ieee80211_free_chanctx(local
, new_ctx
, false);
1352 list_move(&link
->assigned_chanctx_list
, &new_ctx
->assigned_links
);
1353 rcu_assign_pointer(link_conf
->chanctx_conf
, &new_ctx
->conf
);
1355 if (sdata
->vif
.type
== NL80211_IFTYPE_AP
)
1356 __ieee80211_link_copy_chanctx_to_vlans(link
, false);
1358 ieee80211_check_fast_xmit_iface(sdata
);
1360 if (ieee80211_chanctx_refcount(local
, old_ctx
) == 0)
1361 ieee80211_free_chanctx(local
, old_ctx
, false);
1363 ieee80211_recalc_chanctx_min_def(local
, new_ctx
, NULL
, false);
1364 ieee80211_recalc_smps_chanctx(local
, new_ctx
);
1365 ieee80211_recalc_radar_chanctx(local
, new_ctx
);
1368 ieee80211_link_info_change_notify(sdata
, link
, changed
);
1371 ieee80211_link_chanctx_reservation_complete(link
);
1376 ieee80211_link_use_reserved_assign(struct ieee80211_link_data
*link
)
1378 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1379 struct ieee80211_local
*local
= sdata
->local
;
1380 struct ieee80211_chanctx
*old_ctx
, *new_ctx
;
1381 const struct ieee80211_chan_req
*chanreq
;
1382 struct ieee80211_chan_req tmp
;
1385 old_ctx
= ieee80211_link_get_chanctx(link
);
1386 new_ctx
= link
->reserved_chanctx
;
1388 if (WARN_ON(!link
->reserved_ready
))
1391 if (WARN_ON(old_ctx
))
1394 if (WARN_ON(!new_ctx
))
1397 if (WARN_ON(new_ctx
->replace_state
==
1398 IEEE80211_CHANCTX_REPLACES_OTHER
))
1401 chanreq
= ieee80211_chanctx_non_reserved_chandef(local
, new_ctx
,
1404 if (WARN_ON(!chanreq
))
1407 ieee80211_change_chanctx(local
, new_ctx
, new_ctx
, chanreq
);
1409 list_del(&link
->reserved_chanctx_list
);
1410 link
->reserved_chanctx
= NULL
;
1412 err
= ieee80211_assign_link_chanctx(link
, new_ctx
, false);
1414 if (ieee80211_chanctx_refcount(local
, new_ctx
) == 0)
1415 ieee80211_free_chanctx(local
, new_ctx
, false);
1421 ieee80211_link_chanctx_reservation_complete(link
);
1426 ieee80211_link_has_in_place_reservation(struct ieee80211_link_data
*link
)
1428 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1429 struct ieee80211_chanctx
*old_ctx
, *new_ctx
;
1431 lockdep_assert_wiphy(sdata
->local
->hw
.wiphy
);
1433 new_ctx
= link
->reserved_chanctx
;
1434 old_ctx
= ieee80211_link_get_chanctx(link
);
1439 if (WARN_ON(!new_ctx
))
1442 if (old_ctx
->replace_state
!= IEEE80211_CHANCTX_WILL_BE_REPLACED
)
1445 if (new_ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1451 static int ieee80211_chsw_switch_vifs(struct ieee80211_local
*local
,
1454 struct ieee80211_vif_chanctx_switch
*vif_chsw
;
1455 struct ieee80211_link_data
*link
;
1456 struct ieee80211_chanctx
*ctx
, *old_ctx
;
1459 lockdep_assert_wiphy(local
->hw
.wiphy
);
1461 vif_chsw
= kcalloc(n_vifs
, sizeof(vif_chsw
[0]), GFP_KERNEL
);
1466 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1467 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1470 if (WARN_ON(!ctx
->replace_ctx
)) {
1475 list_for_each_entry(link
, &ctx
->reserved_links
,
1476 reserved_chanctx_list
) {
1477 if (!ieee80211_link_has_in_place_reservation(link
))
1480 old_ctx
= ieee80211_link_get_chanctx(link
);
1481 vif_chsw
[i
].vif
= &link
->sdata
->vif
;
1482 vif_chsw
[i
].old_ctx
= &old_ctx
->conf
;
1483 vif_chsw
[i
].new_ctx
= &ctx
->conf
;
1484 vif_chsw
[i
].link_conf
= link
->conf
;
1490 err
= drv_switch_vif_chanctx(local
, vif_chsw
, n_vifs
,
1491 CHANCTX_SWMODE_SWAP_CONTEXTS
);
1498 static int ieee80211_chsw_switch_ctxs(struct ieee80211_local
*local
)
1500 struct ieee80211_chanctx
*ctx
;
1503 lockdep_assert_wiphy(local
->hw
.wiphy
);
1505 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1506 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1509 if (!list_empty(&ctx
->replace_ctx
->assigned_links
))
1512 ieee80211_del_chanctx(local
, ctx
->replace_ctx
, false);
1513 err
= ieee80211_add_chanctx(local
, ctx
);
1521 WARN_ON(ieee80211_add_chanctx(local
, ctx
));
1522 list_for_each_entry_continue_reverse(ctx
, &local
->chanctx_list
, list
) {
1523 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1526 if (!list_empty(&ctx
->replace_ctx
->assigned_links
))
1529 ieee80211_del_chanctx(local
, ctx
, false);
1530 WARN_ON(ieee80211_add_chanctx(local
, ctx
->replace_ctx
));
1536 static int ieee80211_vif_use_reserved_switch(struct ieee80211_local
*local
)
1538 struct ieee80211_chanctx
*ctx
, *ctx_tmp
, *old_ctx
;
1539 int err
, n_assigned
, n_reserved
, n_ready
;
1540 int n_ctx
= 0, n_vifs_switch
= 0, n_vifs_assign
= 0, n_vifs_ctxless
= 0;
1542 lockdep_assert_wiphy(local
->hw
.wiphy
);
1545 * If there are 2 independent pairs of channel contexts performing
1546 * cross-switch of their vifs this code will still wait until both are
1547 * ready even though it could be possible to switch one before the
1550 * For practical reasons and code simplicity just do a single huge
1555 * Verify if the reservation is still feasible.
1556 * - if it's not then disconnect
1557 * - if it is but not all vifs necessary are ready then defer
1560 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1561 struct ieee80211_link_data
*link
;
1563 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1566 if (WARN_ON(!ctx
->replace_ctx
)) {
1577 list_for_each_entry(link
, &ctx
->replace_ctx
->assigned_links
,
1578 assigned_chanctx_list
) {
1580 if (link
->reserved_chanctx
) {
1582 if (link
->reserved_ready
)
1587 if (n_assigned
!= n_reserved
) {
1588 if (n_ready
== n_reserved
) {
1589 wiphy_info(local
->hw
.wiphy
,
1590 "channel context reservation cannot be finalized because some interfaces aren't switching\n");
1598 ctx
->conf
.radar_enabled
= false;
1599 list_for_each_entry(link
, &ctx
->reserved_links
,
1600 reserved_chanctx_list
) {
1601 if (ieee80211_link_has_in_place_reservation(link
) &&
1602 !link
->reserved_ready
)
1605 old_ctx
= ieee80211_link_get_chanctx(link
);
1607 if (old_ctx
->replace_state
==
1608 IEEE80211_CHANCTX_WILL_BE_REPLACED
)
1616 if (link
->reserved_radar_required
)
1617 ctx
->conf
.radar_enabled
= true;
1621 if (WARN_ON(n_ctx
== 0) ||
1622 WARN_ON(n_vifs_switch
== 0 &&
1623 n_vifs_assign
== 0 &&
1624 n_vifs_ctxless
== 0)) {
1629 /* update station rate control and min width before switch */
1630 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1631 struct ieee80211_link_data
*link
;
1633 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1636 if (WARN_ON(!ctx
->replace_ctx
)) {
1641 list_for_each_entry(link
, &ctx
->reserved_links
,
1642 reserved_chanctx_list
) {
1643 if (!ieee80211_link_has_in_place_reservation(link
))
1646 ieee80211_chan_bw_change(local
,
1647 ieee80211_link_get_chanctx(link
),
1651 ieee80211_recalc_chanctx_min_def(local
, ctx
, NULL
, true);
1655 * All necessary vifs are ready. Perform the switch now depending on
1656 * reservations and driver capabilities.
1659 if (n_vifs_switch
> 0) {
1660 err
= ieee80211_chsw_switch_vifs(local
, n_vifs_switch
);
1665 if (n_vifs_assign
> 0 || n_vifs_ctxless
> 0) {
1666 err
= ieee80211_chsw_switch_ctxs(local
);
1672 * Update all structures, values and pointers to point to new channel
1675 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1676 struct ieee80211_link_data
*link
, *link_tmp
;
1678 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1681 if (WARN_ON(!ctx
->replace_ctx
)) {
1686 list_for_each_entry(link
, &ctx
->reserved_links
,
1687 reserved_chanctx_list
) {
1688 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1689 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
1692 if (!ieee80211_link_has_in_place_reservation(link
))
1695 rcu_assign_pointer(link_conf
->chanctx_conf
,
1698 if (sdata
->vif
.type
== NL80211_IFTYPE_AP
)
1699 __ieee80211_link_copy_chanctx_to_vlans(link
,
1702 ieee80211_check_fast_xmit_iface(sdata
);
1704 link
->radar_required
= link
->reserved_radar_required
;
1706 if (link_conf
->chanreq
.oper
.width
!= link
->reserved
.oper
.width
)
1707 changed
= BSS_CHANGED_BANDWIDTH
;
1709 ieee80211_link_update_chanreq(link
, &link
->reserved
);
1711 ieee80211_link_info_change_notify(sdata
,
1715 ieee80211_recalc_txpower(sdata
, false);
1718 ieee80211_recalc_chanctx_chantype(local
, ctx
);
1719 ieee80211_recalc_smps_chanctx(local
, ctx
);
1720 ieee80211_recalc_radar_chanctx(local
, ctx
);
1721 ieee80211_recalc_chanctx_min_def(local
, ctx
, NULL
, false);
1723 list_for_each_entry_safe(link
, link_tmp
, &ctx
->reserved_links
,
1724 reserved_chanctx_list
) {
1725 if (ieee80211_link_get_chanctx(link
) != ctx
)
1728 list_del(&link
->reserved_chanctx_list
);
1729 list_move(&link
->assigned_chanctx_list
,
1730 &ctx
->assigned_links
);
1731 link
->reserved_chanctx
= NULL
;
1733 ieee80211_link_chanctx_reservation_complete(link
);
1734 ieee80211_chan_bw_change(local
, ctx
, false, false);
1738 * This context might have been a dependency for an already
1739 * ready re-assign reservation interface that was deferred. Do
1740 * not propagate error to the caller though. The in-place
1741 * reservation for originally requested interface has already
1742 * succeeded at this point.
1744 list_for_each_entry_safe(link
, link_tmp
, &ctx
->reserved_links
,
1745 reserved_chanctx_list
) {
1746 if (WARN_ON(ieee80211_link_has_in_place_reservation(link
)))
1749 if (WARN_ON(link
->reserved_chanctx
!= ctx
))
1752 if (!link
->reserved_ready
)
1755 if (ieee80211_link_get_chanctx(link
))
1756 err
= ieee80211_link_use_reserved_reassign(link
);
1758 err
= ieee80211_link_use_reserved_assign(link
);
1762 "failed to finalize (re-)assign reservation (err=%d)\n",
1764 ieee80211_link_unreserve_chanctx(link
);
1765 cfg80211_stop_iface(local
->hw
.wiphy
,
1773 * Finally free old contexts
1776 list_for_each_entry_safe(ctx
, ctx_tmp
, &local
->chanctx_list
, list
) {
1777 if (ctx
->replace_state
!= IEEE80211_CHANCTX_WILL_BE_REPLACED
)
1780 ctx
->replace_ctx
->replace_ctx
= NULL
;
1781 ctx
->replace_ctx
->replace_state
=
1782 IEEE80211_CHANCTX_REPLACE_NONE
;
1784 list_del_rcu(&ctx
->list
);
1785 kfree_rcu(ctx
, rcu_head
);
1791 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
1792 struct ieee80211_link_data
*link
, *link_tmp
;
1794 if (ctx
->replace_state
!= IEEE80211_CHANCTX_REPLACES_OTHER
)
1797 list_for_each_entry_safe(link
, link_tmp
, &ctx
->reserved_links
,
1798 reserved_chanctx_list
) {
1799 ieee80211_link_unreserve_chanctx(link
);
1800 ieee80211_link_chanctx_reservation_complete(link
);
1807 void __ieee80211_link_release_channel(struct ieee80211_link_data
*link
,
1808 bool skip_idle_recalc
)
1810 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1811 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
1812 struct ieee80211_local
*local
= sdata
->local
;
1813 struct ieee80211_chanctx_conf
*conf
;
1814 struct ieee80211_chanctx
*ctx
;
1815 bool use_reserved_switch
= false;
1817 lockdep_assert_wiphy(local
->hw
.wiphy
);
1819 conf
= rcu_dereference_protected(link_conf
->chanctx_conf
,
1820 lockdep_is_held(&local
->hw
.wiphy
->mtx
));
1824 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
1826 if (link
->reserved_chanctx
) {
1827 if (link
->reserved_chanctx
->replace_state
== IEEE80211_CHANCTX_REPLACES_OTHER
&&
1828 ieee80211_chanctx_num_reserved(local
, link
->reserved_chanctx
) > 1)
1829 use_reserved_switch
= true;
1831 ieee80211_link_unreserve_chanctx(link
);
1834 ieee80211_assign_link_chanctx(link
, NULL
, false);
1835 if (ieee80211_chanctx_refcount(local
, ctx
) == 0)
1836 ieee80211_free_chanctx(local
, ctx
, skip_idle_recalc
);
1838 link
->radar_required
= false;
1840 /* Unreserving may ready an in-place reservation. */
1841 if (use_reserved_switch
)
1842 ieee80211_vif_use_reserved_switch(local
);
1845 int _ieee80211_link_use_channel(struct ieee80211_link_data
*link
,
1846 const struct ieee80211_chan_req
*chanreq
,
1847 enum ieee80211_chanctx_mode mode
,
1848 bool assign_on_failure
)
1850 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1851 struct ieee80211_local
*local
= sdata
->local
;
1852 struct ieee80211_chanctx
*ctx
;
1853 u8 radar_detect_width
= 0;
1854 bool reserved
= false;
1858 lockdep_assert_wiphy(local
->hw
.wiphy
);
1860 if (!ieee80211_vif_link_active(&sdata
->vif
, link
->link_id
)) {
1861 ieee80211_link_update_chanreq(link
, chanreq
);
1865 ret
= cfg80211_chandef_dfs_required(local
->hw
.wiphy
,
1867 sdata
->wdev
.iftype
);
1871 radar_detect_width
= BIT(chanreq
->oper
.width
);
1873 link
->radar_required
= ret
;
1875 ret
= ieee80211_check_combinations(sdata
, &chanreq
->oper
, mode
,
1876 radar_detect_width
, -1);
1880 __ieee80211_link_release_channel(link
, false);
1882 ctx
= ieee80211_find_chanctx(local
, link
, chanreq
, mode
);
1883 /* Note: context is now reserved */
1886 else if (!ieee80211_find_available_radio(local
, chanreq
, &radio_idx
))
1887 ctx
= ERR_PTR(-EBUSY
);
1889 ctx
= ieee80211_new_chanctx(local
, chanreq
, mode
,
1890 assign_on_failure
, radio_idx
);
1896 ieee80211_link_update_chanreq(link
, chanreq
);
1898 ret
= ieee80211_assign_link_chanctx(link
, ctx
, assign_on_failure
);
1901 /* remove reservation */
1902 WARN_ON(link
->reserved_chanctx
!= ctx
);
1903 link
->reserved_chanctx
= NULL
;
1904 list_del(&link
->reserved_chanctx_list
);
1908 /* if assign fails refcount stays the same */
1909 if (ieee80211_chanctx_refcount(local
, ctx
) == 0)
1910 ieee80211_free_chanctx(local
, ctx
, false);
1914 ieee80211_recalc_smps_chanctx(local
, ctx
);
1915 ieee80211_recalc_radar_chanctx(local
, ctx
);
1918 link
->radar_required
= false;
1923 int ieee80211_link_use_reserved_context(struct ieee80211_link_data
*link
)
1925 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
1926 struct ieee80211_local
*local
= sdata
->local
;
1927 struct ieee80211_chanctx
*new_ctx
;
1928 struct ieee80211_chanctx
*old_ctx
;
1931 lockdep_assert_wiphy(local
->hw
.wiphy
);
1933 new_ctx
= link
->reserved_chanctx
;
1934 old_ctx
= ieee80211_link_get_chanctx(link
);
1936 if (WARN_ON(!new_ctx
))
1939 if (WARN_ON(new_ctx
->replace_state
==
1940 IEEE80211_CHANCTX_WILL_BE_REPLACED
))
1943 if (WARN_ON(link
->reserved_ready
))
1946 link
->reserved_ready
= true;
1948 if (new_ctx
->replace_state
== IEEE80211_CHANCTX_REPLACE_NONE
) {
1950 return ieee80211_link_use_reserved_reassign(link
);
1952 return ieee80211_link_use_reserved_assign(link
);
1956 * In-place reservation may need to be finalized now either if:
1957 * a) sdata is taking part in the swapping itself and is the last one
1958 * b) sdata has switched with a re-assign reservation to an existing
1959 * context readying in-place switching of old_ctx
1961 * In case of (b) do not propagate the error up because the requested
1962 * sdata already switched successfully. Just spill an extra warning.
1963 * The ieee80211_vif_use_reserved_switch() already stops all necessary
1964 * interfaces upon failure.
1967 old_ctx
->replace_state
== IEEE80211_CHANCTX_WILL_BE_REPLACED
) ||
1968 new_ctx
->replace_state
== IEEE80211_CHANCTX_REPLACES_OTHER
) {
1969 err
= ieee80211_vif_use_reserved_switch(local
);
1970 if (err
&& err
!= -EAGAIN
) {
1971 if (new_ctx
->replace_state
==
1972 IEEE80211_CHANCTX_REPLACES_OTHER
)
1975 wiphy_info(local
->hw
.wiphy
,
1976 "depending in-place reservation failed (err=%d)\n",
1985 * This is similar to ieee80211_chanctx_compatible(), but rechecks
1986 * against all the links actually using it (except the one that's
1987 * passed, since that one is changing).
1988 * This is done in order to allow changes to the AP's bandwidth for
1989 * wider bandwidth OFDMA purposes, which wouldn't be treated as
1990 * compatible by ieee80211_chanctx_recheck() but is OK if the link
1991 * requesting the update is the only one using it.
1993 static const struct ieee80211_chan_req
*
1994 ieee80211_chanctx_recheck(struct ieee80211_local
*local
,
1995 struct ieee80211_link_data
*skip_link
,
1996 struct ieee80211_chanctx
*ctx
,
1997 const struct ieee80211_chan_req
*req
,
1998 struct ieee80211_chan_req
*tmp
)
2000 const struct ieee80211_chan_req
*ret
= req
;
2001 struct ieee80211_link_data
*link
;
2003 lockdep_assert_wiphy(local
->hw
.wiphy
);
2005 for_each_sdata_link(local
, link
) {
2006 if (link
== skip_link
)
2009 if (rcu_access_pointer(link
->conf
->chanctx_conf
) == &ctx
->conf
) {
2010 ret
= ieee80211_chanreq_compatible(ret
,
2011 &link
->conf
->chanreq
,
2017 if (link
->reserved_chanctx
== ctx
) {
2018 ret
= ieee80211_chanreq_compatible(ret
,
2030 int ieee80211_link_change_chanreq(struct ieee80211_link_data
*link
,
2031 const struct ieee80211_chan_req
*chanreq
,
2034 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
2035 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
2036 struct ieee80211_local
*local
= sdata
->local
;
2037 struct ieee80211_chanctx_conf
*conf
;
2038 struct ieee80211_chanctx
*ctx
;
2039 const struct ieee80211_chan_req
*compat
;
2040 struct ieee80211_chan_req tmp
;
2042 lockdep_assert_wiphy(local
->hw
.wiphy
);
2044 if (!cfg80211_chandef_usable(sdata
->local
->hw
.wiphy
,
2046 IEEE80211_CHAN_DISABLED
))
2049 /* for non-HT 20 MHz the rest doesn't matter */
2050 if (chanreq
->oper
.width
== NL80211_CHAN_WIDTH_20_NOHT
&&
2051 cfg80211_chandef_identical(&chanreq
->oper
, &link_conf
->chanreq
.oper
))
2054 /* but you cannot switch to/from it */
2055 if (chanreq
->oper
.width
== NL80211_CHAN_WIDTH_20_NOHT
||
2056 link_conf
->chanreq
.oper
.width
== NL80211_CHAN_WIDTH_20_NOHT
)
2059 conf
= rcu_dereference_protected(link_conf
->chanctx_conf
,
2060 lockdep_is_held(&local
->hw
.wiphy
->mtx
));
2064 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
2066 compat
= ieee80211_chanctx_recheck(local
, link
, ctx
, chanreq
, &tmp
);
2070 switch (ctx
->replace_state
) {
2071 case IEEE80211_CHANCTX_REPLACE_NONE
:
2072 if (!ieee80211_chanctx_reserved_chanreq(local
, ctx
, compat
,
2076 case IEEE80211_CHANCTX_WILL_BE_REPLACED
:
2077 /* TODO: Perhaps the bandwidth change could be treated as a
2078 * reservation itself? */
2080 case IEEE80211_CHANCTX_REPLACES_OTHER
:
2081 /* channel context that is going to replace another channel
2082 * context doesn't really exist and shouldn't be assigned
2088 ieee80211_link_update_chanreq(link
, chanreq
);
2090 ieee80211_recalc_chanctx_chantype(local
, ctx
);
2092 *changed
|= BSS_CHANGED_BANDWIDTH
;
2096 void ieee80211_link_release_channel(struct ieee80211_link_data
*link
)
2098 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
2100 lockdep_assert_wiphy(sdata
->local
->hw
.wiphy
);
2102 if (rcu_access_pointer(link
->conf
->chanctx_conf
))
2103 __ieee80211_link_release_channel(link
, false);
2106 void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data
*link
)
2108 struct ieee80211_sub_if_data
*sdata
= link
->sdata
;
2109 unsigned int link_id
= link
->link_id
;
2110 struct ieee80211_bss_conf
*link_conf
= link
->conf
;
2111 struct ieee80211_bss_conf
*ap_conf
;
2112 struct ieee80211_local
*local
= sdata
->local
;
2113 struct ieee80211_sub_if_data
*ap
;
2114 struct ieee80211_chanctx_conf
*conf
;
2116 lockdep_assert_wiphy(local
->hw
.wiphy
);
2118 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP_VLAN
|| !sdata
->bss
))
2121 ap
= container_of(sdata
->bss
, struct ieee80211_sub_if_data
, u
.ap
);
2123 ap_conf
= wiphy_dereference(local
->hw
.wiphy
,
2124 ap
->vif
.link_conf
[link_id
]);
2125 conf
= wiphy_dereference(local
->hw
.wiphy
,
2126 ap_conf
->chanctx_conf
);
2127 rcu_assign_pointer(link_conf
->chanctx_conf
, conf
);
2130 void ieee80211_iter_chan_contexts_atomic(
2131 struct ieee80211_hw
*hw
,
2132 void (*iter
)(struct ieee80211_hw
*hw
,
2133 struct ieee80211_chanctx_conf
*chanctx_conf
,
2137 struct ieee80211_local
*local
= hw_to_local(hw
);
2138 struct ieee80211_chanctx
*ctx
;
2141 list_for_each_entry_rcu(ctx
, &local
->chanctx_list
, list
)
2142 if (ctx
->driver_present
)
2143 iter(hw
, &ctx
->conf
, iter_data
);
2146 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic
);