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 void ieee80211_change_chanctx(struct ieee80211_local
*local
,
13 struct ieee80211_chanctx
*ctx
,
14 const struct cfg80211_chan_def
*chandef
)
16 if (cfg80211_chandef_identical(&ctx
->conf
.def
, chandef
))
19 WARN_ON(!cfg80211_chandef_compatible(&ctx
->conf
.def
, chandef
));
21 ctx
->conf
.def
= *chandef
;
22 drv_change_chanctx(local
, ctx
, IEEE80211_CHANCTX_CHANGE_WIDTH
);
24 if (!local
->use_chanctx
) {
25 local
->_oper_channel_type
= cfg80211_get_chandef_type(chandef
);
26 ieee80211_hw_config(local
, 0);
30 static struct ieee80211_chanctx
*
31 ieee80211_find_chanctx(struct ieee80211_local
*local
,
32 const struct cfg80211_chan_def
*chandef
,
33 enum ieee80211_chanctx_mode mode
)
35 struct ieee80211_chanctx
*ctx
;
37 lockdep_assert_held(&local
->chanctx_mtx
);
39 if (mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
42 list_for_each_entry(ctx
, &local
->chanctx_list
, list
) {
43 const struct cfg80211_chan_def
*compat
;
45 if (ctx
->mode
== IEEE80211_CHANCTX_EXCLUSIVE
)
48 compat
= cfg80211_chandef_compatible(&ctx
->conf
.def
, chandef
);
52 ieee80211_change_chanctx(local
, ctx
, compat
);
60 static struct ieee80211_chanctx
*
61 ieee80211_new_chanctx(struct ieee80211_local
*local
,
62 const struct cfg80211_chan_def
*chandef
,
63 enum ieee80211_chanctx_mode mode
)
65 struct ieee80211_chanctx
*ctx
;
68 lockdep_assert_held(&local
->chanctx_mtx
);
70 ctx
= kzalloc(sizeof(*ctx
) + local
->hw
.chanctx_data_size
, GFP_KERNEL
);
72 return ERR_PTR(-ENOMEM
);
74 ctx
->conf
.def
= *chandef
;
75 ctx
->conf
.rx_chains_static
= 1;
76 ctx
->conf
.rx_chains_dynamic
= 1;
79 if (!local
->use_chanctx
) {
80 local
->_oper_channel_type
=
81 cfg80211_get_chandef_type(chandef
);
82 local
->_oper_channel
= chandef
->chan
;
83 ieee80211_hw_config(local
, 0);
85 err
= drv_add_chanctx(local
, ctx
);
92 list_add_rcu(&ctx
->list
, &local
->chanctx_list
);
94 mutex_lock(&local
->mtx
);
95 ieee80211_recalc_idle(local
);
96 mutex_unlock(&local
->mtx
);
101 static void ieee80211_free_chanctx(struct ieee80211_local
*local
,
102 struct ieee80211_chanctx
*ctx
)
104 lockdep_assert_held(&local
->chanctx_mtx
);
106 WARN_ON_ONCE(ctx
->refcount
!= 0);
108 if (!local
->use_chanctx
) {
109 local
->_oper_channel_type
= NL80211_CHAN_NO_HT
;
110 ieee80211_hw_config(local
, 0);
112 drv_remove_chanctx(local
, ctx
);
115 list_del_rcu(&ctx
->list
);
116 kfree_rcu(ctx
, rcu_head
);
118 mutex_lock(&local
->mtx
);
119 ieee80211_recalc_idle(local
);
120 mutex_unlock(&local
->mtx
);
123 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data
*sdata
,
124 struct ieee80211_chanctx
*ctx
)
126 struct ieee80211_local
*local
= sdata
->local
;
129 lockdep_assert_held(&local
->chanctx_mtx
);
131 ret
= drv_assign_vif_chanctx(local
, sdata
, ctx
);
135 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, &ctx
->conf
);
138 ieee80211_recalc_txpower(sdata
);
139 sdata
->vif
.bss_conf
.idle
= false;
141 if (sdata
->vif
.type
!= NL80211_IFTYPE_P2P_DEVICE
&&
142 sdata
->vif
.type
!= NL80211_IFTYPE_MONITOR
)
143 ieee80211_bss_info_change_notify(sdata
, BSS_CHANGED_IDLE
);
148 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local
*local
,
149 struct ieee80211_chanctx
*ctx
)
151 struct ieee80211_chanctx_conf
*conf
= &ctx
->conf
;
152 struct ieee80211_sub_if_data
*sdata
;
153 const struct cfg80211_chan_def
*compat
= NULL
;
155 lockdep_assert_held(&local
->chanctx_mtx
);
158 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
160 if (!ieee80211_sdata_running(sdata
))
162 if (rcu_access_pointer(sdata
->vif
.chanctx_conf
) != conf
)
166 compat
= &sdata
->vif
.bss_conf
.chandef
;
168 compat
= cfg80211_chandef_compatible(
169 &sdata
->vif
.bss_conf
.chandef
, compat
);
175 if (WARN_ON_ONCE(!compat
))
178 ieee80211_change_chanctx(local
, ctx
, compat
);
181 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data
*sdata
,
182 struct ieee80211_chanctx
*ctx
)
184 struct ieee80211_local
*local
= sdata
->local
;
186 lockdep_assert_held(&local
->chanctx_mtx
);
189 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, NULL
);
191 sdata
->vif
.bss_conf
.idle
= true;
193 if (sdata
->vif
.type
!= NL80211_IFTYPE_P2P_DEVICE
&&
194 sdata
->vif
.type
!= NL80211_IFTYPE_MONITOR
)
195 ieee80211_bss_info_change_notify(sdata
, BSS_CHANGED_IDLE
);
197 drv_unassign_vif_chanctx(local
, sdata
, ctx
);
199 if (ctx
->refcount
> 0) {
200 ieee80211_recalc_chanctx_chantype(sdata
->local
, ctx
);
201 ieee80211_recalc_smps_chanctx(local
, ctx
);
202 ieee80211_recalc_radar_chanctx(local
, ctx
);
206 static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data
*sdata
)
208 struct ieee80211_local
*local
= sdata
->local
;
209 struct ieee80211_chanctx_conf
*conf
;
210 struct ieee80211_chanctx
*ctx
;
212 lockdep_assert_held(&local
->chanctx_mtx
);
214 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
215 lockdep_is_held(&local
->chanctx_mtx
));
219 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
221 ieee80211_unassign_vif_chanctx(sdata
, ctx
);
222 if (ctx
->refcount
== 0)
223 ieee80211_free_chanctx(local
, ctx
);
226 void ieee80211_recalc_radar_chanctx(struct ieee80211_local
*local
,
227 struct ieee80211_chanctx
*chanctx
)
229 struct ieee80211_sub_if_data
*sdata
;
230 bool radar_enabled
= false;
232 lockdep_assert_held(&local
->chanctx_mtx
);
235 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
236 if (sdata
->radar_required
) {
237 radar_enabled
= true;
243 if (radar_enabled
== chanctx
->conf
.radar_enabled
)
246 chanctx
->conf
.radar_enabled
= radar_enabled
;
247 local
->radar_detect_enabled
= chanctx
->conf
.radar_enabled
;
249 if (!local
->use_chanctx
) {
250 local
->hw
.conf
.radar_enabled
= chanctx
->conf
.radar_enabled
;
251 ieee80211_hw_config(local
, IEEE80211_CONF_CHANGE_CHANNEL
);
254 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RADAR
);
257 void ieee80211_recalc_smps_chanctx(struct ieee80211_local
*local
,
258 struct ieee80211_chanctx
*chanctx
)
260 struct ieee80211_sub_if_data
*sdata
;
261 u8 rx_chains_static
, rx_chains_dynamic
;
263 lockdep_assert_held(&local
->chanctx_mtx
);
265 rx_chains_static
= 1;
266 rx_chains_dynamic
= 1;
269 list_for_each_entry_rcu(sdata
, &local
->interfaces
, list
) {
270 u8 needed_static
, needed_dynamic
;
272 if (!ieee80211_sdata_running(sdata
))
275 if (rcu_access_pointer(sdata
->vif
.chanctx_conf
) !=
279 switch (sdata
->vif
.type
) {
280 case NL80211_IFTYPE_P2P_DEVICE
:
282 case NL80211_IFTYPE_STATION
:
283 if (!sdata
->u
.mgd
.associated
)
286 case NL80211_IFTYPE_AP_VLAN
:
288 case NL80211_IFTYPE_AP
:
289 case NL80211_IFTYPE_ADHOC
:
290 case NL80211_IFTYPE_WDS
:
291 case NL80211_IFTYPE_MESH_POINT
:
297 switch (sdata
->smps_mode
) {
299 WARN_ONCE(1, "Invalid SMPS mode %d\n",
302 case IEEE80211_SMPS_OFF
:
303 needed_static
= sdata
->needed_rx_chains
;
304 needed_dynamic
= sdata
->needed_rx_chains
;
306 case IEEE80211_SMPS_DYNAMIC
:
308 needed_dynamic
= sdata
->needed_rx_chains
;
310 case IEEE80211_SMPS_STATIC
:
316 rx_chains_static
= max(rx_chains_static
, needed_static
);
317 rx_chains_dynamic
= max(rx_chains_dynamic
, needed_dynamic
);
321 if (!local
->use_chanctx
) {
322 if (rx_chains_static
> 1)
323 local
->smps_mode
= IEEE80211_SMPS_OFF
;
324 else if (rx_chains_dynamic
> 1)
325 local
->smps_mode
= IEEE80211_SMPS_DYNAMIC
;
327 local
->smps_mode
= IEEE80211_SMPS_STATIC
;
328 ieee80211_hw_config(local
, 0);
331 if (rx_chains_static
== chanctx
->conf
.rx_chains_static
&&
332 rx_chains_dynamic
== chanctx
->conf
.rx_chains_dynamic
)
335 chanctx
->conf
.rx_chains_static
= rx_chains_static
;
336 chanctx
->conf
.rx_chains_dynamic
= rx_chains_dynamic
;
337 drv_change_chanctx(local
, chanctx
, IEEE80211_CHANCTX_CHANGE_RX_CHAINS
);
340 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data
*sdata
,
341 const struct cfg80211_chan_def
*chandef
,
342 enum ieee80211_chanctx_mode mode
)
344 struct ieee80211_local
*local
= sdata
->local
;
345 struct ieee80211_chanctx
*ctx
;
348 WARN_ON(sdata
->dev
&& netif_carrier_ok(sdata
->dev
));
350 mutex_lock(&local
->chanctx_mtx
);
351 __ieee80211_vif_release_channel(sdata
);
353 ctx
= ieee80211_find_chanctx(local
, chandef
, mode
);
355 ctx
= ieee80211_new_chanctx(local
, chandef
, mode
);
361 sdata
->vif
.bss_conf
.chandef
= *chandef
;
363 ret
= ieee80211_assign_vif_chanctx(sdata
, ctx
);
365 /* if assign fails refcount stays the same */
366 if (ctx
->refcount
== 0)
367 ieee80211_free_chanctx(local
, ctx
);
371 ieee80211_recalc_smps_chanctx(local
, ctx
);
372 ieee80211_recalc_radar_chanctx(local
, ctx
);
374 mutex_unlock(&local
->chanctx_mtx
);
378 int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data
*sdata
,
379 const struct cfg80211_chan_def
*chandef
,
382 struct ieee80211_local
*local
= sdata
->local
;
383 struct ieee80211_chanctx_conf
*conf
;
384 struct ieee80211_chanctx
*ctx
;
387 if (!cfg80211_chandef_usable(sdata
->local
->hw
.wiphy
, chandef
,
388 IEEE80211_CHAN_DISABLED
))
391 mutex_lock(&local
->chanctx_mtx
);
392 if (cfg80211_chandef_identical(chandef
, &sdata
->vif
.bss_conf
.chandef
)) {
397 if (chandef
->width
== NL80211_CHAN_WIDTH_20_NOHT
||
398 sdata
->vif
.bss_conf
.chandef
.width
== NL80211_CHAN_WIDTH_20_NOHT
) {
403 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
404 lockdep_is_held(&local
->chanctx_mtx
));
410 ctx
= container_of(conf
, struct ieee80211_chanctx
, conf
);
411 if (!cfg80211_chandef_compatible(&conf
->def
, chandef
)) {
416 sdata
->vif
.bss_conf
.chandef
= *chandef
;
418 ieee80211_recalc_chanctx_chantype(local
, ctx
);
420 *changed
|= BSS_CHANGED_BANDWIDTH
;
423 mutex_unlock(&local
->chanctx_mtx
);
427 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data
*sdata
)
429 WARN_ON(sdata
->dev
&& netif_carrier_ok(sdata
->dev
));
431 mutex_lock(&sdata
->local
->chanctx_mtx
);
432 __ieee80211_vif_release_channel(sdata
);
433 mutex_unlock(&sdata
->local
->chanctx_mtx
);
436 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data
*sdata
)
438 struct ieee80211_local
*local
= sdata
->local
;
439 struct ieee80211_sub_if_data
*ap
;
440 struct ieee80211_chanctx_conf
*conf
;
442 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP_VLAN
|| !sdata
->bss
))
445 ap
= container_of(sdata
->bss
, struct ieee80211_sub_if_data
, u
.ap
);
447 mutex_lock(&local
->chanctx_mtx
);
449 conf
= rcu_dereference_protected(ap
->vif
.chanctx_conf
,
450 lockdep_is_held(&local
->chanctx_mtx
));
451 rcu_assign_pointer(sdata
->vif
.chanctx_conf
, conf
);
452 mutex_unlock(&local
->chanctx_mtx
);
455 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data
*sdata
,
458 struct ieee80211_local
*local
= sdata
->local
;
459 struct ieee80211_sub_if_data
*vlan
;
460 struct ieee80211_chanctx_conf
*conf
;
464 if (WARN_ON(sdata
->vif
.type
!= NL80211_IFTYPE_AP
))
467 mutex_lock(&local
->chanctx_mtx
);
470 * Check that conf exists, even when clearing this function
471 * must be called with the AP's channel context still there
472 * as it would otherwise cause VLANs to have an invalid
473 * channel context pointer for a while, possibly pointing
474 * to a channel context that has already been freed.
476 conf
= rcu_dereference_protected(sdata
->vif
.chanctx_conf
,
477 lockdep_is_held(&local
->chanctx_mtx
));
483 list_for_each_entry(vlan
, &sdata
->u
.ap
.vlans
, u
.vlan
.list
)
484 rcu_assign_pointer(vlan
->vif
.chanctx_conf
, conf
);
486 mutex_unlock(&local
->chanctx_mtx
);
489 void ieee80211_iter_chan_contexts_atomic(
490 struct ieee80211_hw
*hw
,
491 void (*iter
)(struct ieee80211_hw
*hw
,
492 struct ieee80211_chanctx_conf
*chanctx_conf
,
496 struct ieee80211_local
*local
= hw_to_local(hw
);
497 struct ieee80211_chanctx
*ctx
;
500 list_for_each_entry_rcu(ctx
, &local
->chanctx_list
, list
)
501 if (ctx
->driver_present
)
502 iter(hw
, &ctx
->conf
, iter_data
);
505 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic
);