2 * mac80211 - channel management
5 #include <linux/nl80211.h>
6 #include <linux/export.h>
7 #include <linux/rtnetlink.h>
8 #include <net/cfg80211.h>
9 #include "ieee80211_i.h"
10 #include "driver-ops.h"
12 static enum nl80211_chan_width
ieee80211_get_sta_bw(struct ieee80211_sta
*sta
)
14 switch (sta
->bandwidth
) {
15 case IEEE80211_STA_RX_BW_20
:
16 if (sta
->ht_cap
.ht_supported
)
17 return NL80211_CHAN_WIDTH_20
;
19 return NL80211_CHAN_WIDTH_20_NOHT
;
20 case IEEE80211_STA_RX_BW_40
:
21 return NL80211_CHAN_WIDTH_40
;
22 case IEEE80211_STA_RX_BW_80
:
23 return NL80211_CHAN_WIDTH_80
;
24 case IEEE80211_STA_RX_BW_160
:
26 * This applied for both 160 and 80+80. since we use
27 * the returned value to consider degradation of
28 * ctx->conf.min_def, we have to make sure to take
29 * the bigger one (NL80211_CHAN_WIDTH_160).
30 * Otherwise we might try degrading even when not
31 * needed, as the max required sta_bw returned (80+80)
32 * might be smaller than the configured bw (160).
34 return NL80211_CHAN_WIDTH_160
;
37 return NL80211_CHAN_WIDTH_20
;
41 static enum nl80211_chan_width
42 ieee80211_get_max_required_bw(struct ieee80211_sub_if_data
*sdata
)
44 enum nl80211_chan_width max_bw
= NL80211_CHAN_WIDTH_20_NOHT
;
48 list_for_each_entry_rcu(sta
, &sdata
->local
->sta_list
, list
) {
49 if (sdata
!= sta
->sdata
&&
50 !(sta
->sdata
->bss
&& sta
->sdata
->bss
== sdata
->bss
))
56 max_bw
= max(max_bw
, ieee80211_get_sta_bw(&sta
->sta
));
63 static enum nl80211_chan_width
64 ieee80211_get_chanctx_max_required_bw(struct ieee80211_local
*local
,
65 struct ieee80211_chanctx_conf
*conf
)
67 struct ieee80211_sub_if_data
*sdata
;
68 enum nl80211_chan_width max_bw
= NL80211_CHAN_WIDTH_20_NOHT
;
71 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
72 struct ieee80211_vif
*vif
= &sdata
->vif
;
73 enum nl80211_chan_width width
= NL80211_CHAN_WIDTH_20_NOHT
;
75 if (!ieee80211_sdata_running(sdata
))
78 if (rcu_access_pointer(sdata
->vif
.chanctx_conf
) != conf
)
82 case NL80211_IFTYPE_AP
:
83 case NL80211_IFTYPE_AP_VLAN
:
84 width
= ieee80211_get_max_required_bw(sdata
);
86 case NL80211_IFTYPE_P2P_DEVICE
:
88 case NL80211_IFTYPE_STATION
:
89 case NL80211_IFTYPE_ADHOC
:
90 case NL80211_IFTYPE_WDS
:
91 case NL80211_IFTYPE_MESH_POINT
:
92 width
= vif
->bss_conf
.chandef
.width
;
94 case NL80211_IFTYPE_UNSPECIFIED
:
95 case NUM_NL80211_IFTYPES
:
96 case NL80211_IFTYPE_MONITOR
:
97 case NL80211_IFTYPE_P2P_CLIENT
:
98 case NL80211_IFTYPE_P2P_GO
:
101 max_bw
= max(max_bw
, width
);
104 /* use the configured bandwidth in case of monitor interface */
105 sdata
= rcu_dereference(local
->monitor_sdata
);
106 if (sdata
&& rcu_access_pointer(sdata
->vif
.chanctx_conf
) == conf
)
107 max_bw
= max(max_bw
, conf
->def
.width
);
115 * recalc the min required chan width of the channel context, which is
116 * the max of min required widths of all the interfaces bound to this
119 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local
*local
,
120 struct ieee80211_chanctx
*ctx
)
122 enum nl80211_chan_width max_bw
;
123 struct cfg80211_chan_def min_def
;
125 lockdep_assert_held(&local
->chanctx_mtx
);
127 /* don't optimize 5MHz, 10MHz, and radar_enabled confs */
128 if (ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_5
||
129 ctx
->conf
.def
.width
== NL80211_CHAN_WIDTH_10
||
130 ctx
->conf
.radar_enabled
) {
131 ctx
->conf
.min_def
= ctx
->conf
.def
;
135 max_bw
= ieee80211_get_chanctx_max_required_bw(local
, &ctx
->conf
);
137 /* downgrade chandef up to max_bw */
138 min_def
= ctx
->conf
.def
;
139 while (min_def
.width
> max_bw
)
140 ieee80211_chandef_downgrade(&min_def
);
142 if (cfg80211_chandef_identical(&ctx
->conf
.min_def
, &min_def
))
145 ctx
->conf
.min_def
= min_def
;
146 if (!ctx
->driver_present
)
149 drv_change_chanctx(local
, ctx
, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH
);
152 static void ieee80211_change_chanctx(struct ieee80211_local
*local
,
153 struct ieee80211_chanctx
*ctx
,
154 const struct cfg80211_chan_def
*chandef
)
156 if (cfg80211_chandef_identical(&ctx
->conf
.def
, chandef
))
159 WARN_ON(!cfg80211_chandef_compatible(&ctx
->conf
.def
, chandef
));
161 ctx
->conf
.def
= *chandef
;
162 drv_change_chanctx(local
, ctx
, IEEE80211_CHANCTX_CHANGE_WIDTH
);
163 ieee80211_recalc_chanctx_min_def(local
, ctx
);
165 if (!local
->use_chanctx
) {
166 local
->_oper_chandef
= *chandef
;
167 ieee80211_hw_config(local
, 0);
171 static struct ieee80211_chanctx
*
172 ieee80211_find_chanctx(struct ieee80211_local
*local
,
173 const struct cfg80211_chan_def
*chandef
,
174 enum ieee80211_chanctx_mode mode
)
176 struct ieee80211_chanctx
*ctx
;
178 lockdep_assert_held(&local
->chanctx_mtx
);
180 if (mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
183 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
184 const struct cfg80211_chan_def
*compat
;
186 if (ctx
->mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
189 compat
= cfg80211_chandef_compatible(&ctx
->conf
.def
, chandef
);
193 ieee80211_change_chanctx(local
, ctx
, compat
);
201 static bool ieee80211_is_radar_required(struct ieee80211_local
*local
)
203 struct ieee80211_sub_if_data
*sdata
;
205 lockdep_assert_held(&local
->mtx
);
208 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
209 if (sdata
->radar_required
) {
219 static struct ieee80211_chanctx
*
220 ieee80211_new_chanctx(struct ieee80211_local
*local
,
221 const struct cfg80211_chan_def
*chandef
,
222 enum ieee80211_chanctx_mode mode
)
224 struct ieee80211_chanctx
*ctx
;
228 lockdep_assert_held(&local
->chanctx_mtx
);
230 ctx
= kzalloc(sizeof(*ctx
) + local
->hw
.chanctx_data_size
, GFP_KERNEL
);
232 return ERR_PTR(-ENOMEM
);
234 ctx
->conf
.def
= *chandef
;
235 ctx
->conf
.rx_chains_static
= 1;
236 ctx
->conf
.rx_chains_dynamic
= 1;
238 ctx
->conf
.radar_enabled
= ieee80211_is_radar_required(local
);
239 ieee80211_recalc_chanctx_min_def(local
, ctx
);
240 if (!local
->use_chanctx
)
241 local
->hw
.conf
.radar_enabled
= ctx
->conf
.radar_enabled
;
243 /* we hold the mutex to prevent idle from changing */
244 lockdep_assert_held(&local
->mtx
);
245 /* turn idle off *before* setting channel -- some drivers need that */
246 changed
= ieee80211_idle_off(local
);
248 ieee80211_hw_config(local
, changed
);
250 if (!local
->use_chanctx
) {
251 local
->_oper_chandef
= *chandef
;
252 ieee80211_hw_config(local
, IEEE80211_CONF_CHANGE_CHANNEL
);
254 err
= drv_add_chanctx(local
, ctx
);
257 ieee80211_recalc_idle(local
);
262 /* and keep the mutex held until the new chanctx is on the list */
263 list_add_rcu(&ctx
->list
, &local
->chanctx_list
);
268 static void ieee80211_free_chanctx(struct ieee80211_local
*local
,
269 struct ieee80211_chanctx
*ctx
)
271 bool check_single_channel
= false;
272 lockdep_assert_held(&local
->chanctx_mtx
);
274 WARN_ON_ONCE(ctx
->refcount
!= 0);
276 if (!local
->use_chanctx
) {
277 struct cfg80211_chan_def
*chandef
= &local
->_oper_chandef
;
278 chandef
->width
= NL80211_CHAN_WIDTH_20_NOHT
;
279 chandef
->center_freq1
= chandef
->chan
->center_freq
;
280 chandef
->center_freq2
= 0;
282 /* NOTE: Disabling radar is only valid here for
283 * single channel context. To be sure, check it ...
285 if (local
->hw
.conf
.radar_enabled
)
286 check_single_channel
= true;
287 local
->hw
.conf
.radar_enabled
= false;
289 ieee80211_hw_config(local
, IEEE80211_CONF_CHANGE_CHANNEL
);
291 drv_remove_chanctx(local
, ctx
);
294 list_del_rcu(&ctx
->list
);
295 kfree_rcu(ctx
, rcu_head
);
297 /* throw a warning if this wasn't the only channel context. */
298 WARN_ON(check_single_channel
&& !list_empty(&local
->chanctx_list
));
300 ieee80211_recalc_idle(local
);
303 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data
*sdata
,
304 struct ieee80211_chanctx
*ctx
)
306 struct ieee80211_local
*local
= sdata
->local
;
309 lockdep_assert_held(&local
->chanctx_mtx
);
311 ret
= drv_assign_vif_chanctx(local
, sdata
, ctx
);
315 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, &ctx
->conf
);
318 ieee80211_recalc_txpower(sdata
);
319 ieee80211_recalc_chanctx_min_def(local
, ctx
);
320 sdata
->vif
.bss_conf
.idle
= false;
322 if (sdata
->vif
.type
!= NL80211_IFTYPE_P2P_DEVICE
&&
323 sdata
->vif
.type
!= NL80211_IFTYPE_MONITOR
)
324 ieee80211_bss_info_change_notify(sdata
, BSS_CHANGED_IDLE
);
329 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local
*local
,
330 struct ieee80211_chanctx
*ctx
)
332 struct ieee80211_chanctx_conf
*conf
= &ctx
->conf
;
333 struct ieee80211_sub_if_data
*sdata
;
334 const struct cfg80211_chan_def
*compat
= NULL
;
336 lockdep_assert_held(&local
->chanctx_mtx
);
339 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
341 if (!ieee80211_sdata_running(sdata
))
343 if (rcu_access_pointer(sdata
->vif
.chanctx_conf
) != conf
)
347 compat
= &sdata
->vif
.bss_conf
.chandef
;
349 compat
= cfg80211_chandef_compatible(
350 &sdata
->vif
.bss_conf
.chandef
, compat
);
356 if (WARN_ON_ONCE(!compat
))
359 ieee80211_change_chanctx(local
, ctx
, compat
);
362 static void ieee80211_recalc_radar_chanctx(struct ieee80211_local
*local
,
363 struct ieee80211_chanctx
*chanctx
)
367 lockdep_assert_held(&local
->chanctx_mtx
);
368 /* for setting local->radar_detect_enabled */
369 lockdep_assert_held(&local
->mtx
);
371 radar_enabled
= ieee80211_is_radar_required(local
);
373 if (radar_enabled
== chanctx
->conf
.radar_enabled
)
376 chanctx
->conf
.radar_enabled
= radar_enabled
;
377 local
->radar_detect_enabled
= chanctx
->conf
.radar_enabled
;
379 if (!local
->use_chanctx
) {
380 local
->hw
.conf
.radar_enabled
= chanctx
->conf
.radar_enabled
;
381 ieee80211_hw_config(local
, IEEE80211_CONF_CHANGE_CHANNEL
);
384 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RADAR
);
387 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data
*sdata
,
388 struct ieee80211_chanctx
*ctx
)
390 struct ieee80211_local
*local
= sdata
->local
;
392 lockdep_assert_held(&local
->chanctx_mtx
);
395 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, NULL
);
397 sdata
->vif
.bss_conf
.idle
= true;
399 if (sdata
->vif
.type
!= NL80211_IFTYPE_P2P_DEVICE
&&
400 sdata
->vif
.type
!= NL80211_IFTYPE_MONITOR
)
401 ieee80211_bss_info_change_notify(sdata
, BSS_CHANGED_IDLE
);
403 drv_unassign_vif_chanctx(local
, sdata
, ctx
);
405 if (ctx
->refcount
> 0) {
406 ieee80211_recalc_chanctx_chantype(sdata
->local
, ctx
);
407 ieee80211_recalc_smps_chanctx(local
, ctx
);
408 ieee80211_recalc_radar_chanctx(local
, ctx
);
409 ieee80211_recalc_chanctx_min_def(local
, ctx
);
413 static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data
*sdata
)
415 struct ieee80211_local
*local
= sdata
->local
;
416 struct ieee80211_chanctx_conf
*conf
;
417 struct ieee80211_chanctx
*ctx
;
419 lockdep_assert_held(&local
->chanctx_mtx
);
421 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
422 lockdep_is_held(&local
->chanctx_mtx
));
426 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
428 ieee80211_unassign_vif_chanctx(sdata
, ctx
);
429 if (ctx
->refcount
== 0)
430 ieee80211_free_chanctx(local
, ctx
);
433 void ieee80211_recalc_smps_chanctx(struct ieee80211_local
*local
,
434 struct ieee80211_chanctx
*chanctx
)
436 struct ieee80211_sub_if_data
*sdata
;
437 u8 rx_chains_static
, rx_chains_dynamic
;
439 lockdep_assert_held(&local
->chanctx_mtx
);
441 rx_chains_static
= 1;
442 rx_chains_dynamic
= 1;
445 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
446 u8 needed_static
, needed_dynamic
;
448 if (!ieee80211_sdata_running(sdata
))
451 if (rcu_access_pointer(sdata
->vif
.chanctx_conf
) !=
455 switch (sdata
->vif
.type
) {
456 case NL80211_IFTYPE_P2P_DEVICE
:
458 case NL80211_IFTYPE_STATION
:
459 if (!sdata
->u
.mgd
.associated
)
462 case NL80211_IFTYPE_AP_VLAN
:
464 case NL80211_IFTYPE_AP
:
465 case NL80211_IFTYPE_ADHOC
:
466 case NL80211_IFTYPE_WDS
:
467 case NL80211_IFTYPE_MESH_POINT
:
473 switch (sdata
->smps_mode
) {
475 WARN_ONCE(1, "Invalid SMPS mode %d\n",
478 case IEEE80211_SMPS_OFF
:
479 needed_static
= sdata
->needed_rx_chains
;
480 needed_dynamic
= sdata
->needed_rx_chains
;
482 case IEEE80211_SMPS_DYNAMIC
:
484 needed_dynamic
= sdata
->needed_rx_chains
;
486 case IEEE80211_SMPS_STATIC
:
492 rx_chains_static
= max(rx_chains_static
, needed_static
);
493 rx_chains_dynamic
= max(rx_chains_dynamic
, needed_dynamic
);
496 /* Disable SMPS for the monitor interface */
497 sdata
= rcu_dereference(local
->monitor_sdata
);
499 rcu_access_pointer(sdata
->vif
.chanctx_conf
) == &chanctx
->conf
)
500 rx_chains_dynamic
= rx_chains_static
= local
->rx_chains
;
504 if (!local
->use_chanctx
) {
505 if (rx_chains_static
> 1)
506 local
->smps_mode
= IEEE80211_SMPS_OFF
;
507 else if (rx_chains_dynamic
> 1)
508 local
->smps_mode
= IEEE80211_SMPS_DYNAMIC
;
510 local
->smps_mode
= IEEE80211_SMPS_STATIC
;
511 ieee80211_hw_config(local
, 0);
514 if (rx_chains_static
== chanctx
->conf
.rx_chains_static
&&
515 rx_chains_dynamic
== chanctx
->conf
.rx_chains_dynamic
)
518 chanctx
->conf
.rx_chains_static
= rx_chains_static
;
519 chanctx
->conf
.rx_chains_dynamic
= rx_chains_dynamic
;
520 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RX_CHAINS
);
523 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data
*sdata
,
524 const struct cfg80211_chan_def
*chandef
,
525 enum ieee80211_chanctx_mode mode
)
527 struct ieee80211_local
*local
= sdata
->local
;
528 struct ieee80211_chanctx
*ctx
;
531 lockdep_assert_held(&local
->mtx
);
533 WARN_ON(sdata
->dev
&& netif_carrier_ok(sdata
->dev
));
535 mutex_lock(&local
->chanctx_mtx
);
536 __ieee80211_vif_release_channel(sdata
);
538 ctx
= ieee80211_find_chanctx(local
, chandef
, mode
);
540 ctx
= ieee80211_new_chanctx(local
, chandef
, mode
);
546 sdata
->vif
.bss_conf
.chandef
= *chandef
;
548 ret
= ieee80211_assign_vif_chanctx(sdata
, ctx
);
550 /* if assign fails refcount stays the same */
551 if (ctx
->refcount
== 0)
552 ieee80211_free_chanctx(local
, ctx
);
556 ieee80211_recalc_smps_chanctx(local
, ctx
);
557 ieee80211_recalc_radar_chanctx(local
, ctx
);
559 mutex_unlock(&local
->chanctx_mtx
);
563 int ieee80211_vif_change_channel(struct ieee80211_sub_if_data
*sdata
,
566 struct ieee80211_local
*local
= sdata
->local
;
567 struct ieee80211_chanctx_conf
*conf
;
568 struct ieee80211_chanctx
*ctx
;
569 const struct cfg80211_chan_def
*chandef
= &sdata
->csa_chandef
;
571 u32 chanctx_changed
= 0;
573 lockdep_assert_held(&local
->mtx
);
575 /* should never be called if not performing a channel switch. */
576 if (WARN_ON(!sdata
->vif
.csa_active
))
579 if (!cfg80211_chandef_usable(sdata
->local
->hw
.wiphy
, chandef
,
580 IEEE80211_CHAN_DISABLED
))
583 mutex_lock(&local
->chanctx_mtx
);
584 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
585 lockdep_is_held(&local
->chanctx_mtx
));
591 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
592 if (ctx
->refcount
!= 1) {
597 if (sdata
->vif
.bss_conf
.chandef
.width
!= chandef
->width
) {
598 chanctx_changed
= IEEE80211_CHANCTX_CHANGE_WIDTH
;
599 *changed
|= BSS_CHANGED_BANDWIDTH
;
602 sdata
->vif
.bss_conf
.chandef
= *chandef
;
603 ctx
->conf
.def
= *chandef
;
605 chanctx_changed
|= IEEE80211_CHANCTX_CHANGE_CHANNEL
;
606 drv_change_chanctx(local
, ctx
, chanctx_changed
);
608 ieee80211_recalc_chanctx_chantype(local
, ctx
);
609 ieee80211_recalc_smps_chanctx(local
, ctx
);
610 ieee80211_recalc_radar_chanctx(local
, ctx
);
611 ieee80211_recalc_chanctx_min_def(local
, ctx
);
615 mutex_unlock(&local
->chanctx_mtx
);
619 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data
*sdata
,
620 const struct cfg80211_chan_def
*chandef
,
623 struct ieee80211_local
*local
= sdata
->local
;
624 struct ieee80211_chanctx_conf
*conf
;
625 struct ieee80211_chanctx
*ctx
;
628 if (!cfg80211_chandef_usable(sdata
->local
->hw
.wiphy
, chandef
,
629 IEEE80211_CHAN_DISABLED
))
632 mutex_lock(&local
->chanctx_mtx
);
633 if (cfg80211_chandef_identical(chandef
, &sdata
->vif
.bss_conf
.chandef
)) {
638 if (chandef
->width
== NL80211_CHAN_WIDTH_20_NOHT
||
639 sdata
->vif
.bss_conf
.chandef
.width
== NL80211_CHAN_WIDTH_20_NOHT
) {
644 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
645 lockdep_is_held(&local
->chanctx_mtx
));
651 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
652 if (!cfg80211_chandef_compatible(&conf
->def
, chandef
)) {
657 sdata
->vif
.bss_conf
.chandef
= *chandef
;
659 ieee80211_recalc_chanctx_chantype(local
, ctx
);
661 *changed
|= BSS_CHANGED_BANDWIDTH
;
664 mutex_unlock(&local
->chanctx_mtx
);
668 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data
*sdata
)
670 WARN_ON(sdata
->dev
&& netif_carrier_ok(sdata
->dev
));
672 lockdep_assert_held(&sdata
->local
->mtx
);
674 mutex_lock(&sdata
->local
->chanctx_mtx
);
675 __ieee80211_vif_release_channel(sdata
);
676 mutex_unlock(&sdata
->local
->chanctx_mtx
);
679 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data
*sdata
)
681 struct ieee80211_local
*local
= sdata
->local
;
682 struct ieee80211_sub_if_data
*ap
;
683 struct ieee80211_chanctx_conf
*conf
;
685 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP_VLAN
|| !sdata
->bss
))
688 ap
= container_of(sdata
->bss
, struct ieee80211_sub_if_data
, u
.ap
);
690 mutex_lock(&local
->chanctx_mtx
);
692 conf
= rcu_dereference_protected(ap
->vif
.chanctx_conf
,
693 lockdep_is_held(&local
->chanctx_mtx
));
694 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, conf
);
695 mutex_unlock(&local
->chanctx_mtx
);
698 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data
*sdata
,
701 struct ieee80211_local
*local
= sdata
->local
;
702 struct ieee80211_sub_if_data
*vlan
;
703 struct ieee80211_chanctx_conf
*conf
;
707 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP
))
710 mutex_lock(&local
->chanctx_mtx
);
713 * Check that conf exists, even when clearing this function
714 * must be called with the AP's channel context still there
715 * as it would otherwise cause VLANs to have an invalid
716 * channel context pointer for a while, possibly pointing
717 * to a channel context that has already been freed.
719 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
720 lockdep_is_held(&local
->chanctx_mtx
));
726 list_for_each_entry(vlan
, &sdata
->u
.ap
.vlans
, u
.vlan
.list
)
727 rcu_assign_pointer(vlan
->vif
.chanctx_conf
, conf
);
729 mutex_unlock(&local
->chanctx_mtx
);
732 void ieee80211_iter_chan_contexts_atomic(
733 struct ieee80211_hw
*hw
,
734 void (*iter
)(struct ieee80211_hw
*hw
,
735 struct ieee80211_chanctx_conf
*chanctx_conf
,
739 struct ieee80211_local
*local
= hw_to_local(hw
);
740 struct ieee80211_chanctx
*ctx
;
743 list_for_each_entry_rcu(ctx
, &local
->chanctx_list
, list
)
744 if (ctx
->driver_present
)
745 iter(hw
, &ctx
->conf
, iter_data
);
748 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic
);