2 * This file contains helper code to handle channel
3 * settings and keeping track of what is possible at
6 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
9 #include <linux/export.h>
10 #include <net/cfg80211.h>
14 void cfg80211_chandef_create(struct cfg80211_chan_def
*chandef
,
15 struct ieee80211_channel
*chan
,
16 enum nl80211_channel_type chan_type
)
22 chandef
->center_freq2
= 0;
25 case NL80211_CHAN_NO_HT
:
26 chandef
->width
= NL80211_CHAN_WIDTH_20_NOHT
;
27 chandef
->center_freq1
= chan
->center_freq
;
29 case NL80211_CHAN_HT20
:
30 chandef
->width
= NL80211_CHAN_WIDTH_20
;
31 chandef
->center_freq1
= chan
->center_freq
;
33 case NL80211_CHAN_HT40PLUS
:
34 chandef
->width
= NL80211_CHAN_WIDTH_40
;
35 chandef
->center_freq1
= chan
->center_freq
+ 10;
37 case NL80211_CHAN_HT40MINUS
:
38 chandef
->width
= NL80211_CHAN_WIDTH_40
;
39 chandef
->center_freq1
= chan
->center_freq
- 10;
45 EXPORT_SYMBOL(cfg80211_chandef_create
);
47 bool cfg80211_chandef_valid(const struct cfg80211_chan_def
*chandef
)
54 control_freq
= chandef
->chan
->center_freq
;
56 switch (chandef
->width
) {
57 case NL80211_CHAN_WIDTH_20
:
58 case NL80211_CHAN_WIDTH_20_NOHT
:
59 if (chandef
->center_freq1
!= control_freq
)
61 if (chandef
->center_freq2
)
64 case NL80211_CHAN_WIDTH_40
:
65 if (chandef
->center_freq1
!= control_freq
+ 10 &&
66 chandef
->center_freq1
!= control_freq
- 10)
68 if (chandef
->center_freq2
)
71 case NL80211_CHAN_WIDTH_80P80
:
72 if (chandef
->center_freq1
!= control_freq
+ 30 &&
73 chandef
->center_freq1
!= control_freq
+ 10 &&
74 chandef
->center_freq1
!= control_freq
- 10 &&
75 chandef
->center_freq1
!= control_freq
- 30)
77 if (!chandef
->center_freq2
)
79 /* adjacent is not allowed -- that's a 160 MHz channel */
80 if (chandef
->center_freq1
- chandef
->center_freq2
== 80 ||
81 chandef
->center_freq2
- chandef
->center_freq1
== 80)
84 case NL80211_CHAN_WIDTH_80
:
85 if (chandef
->center_freq1
!= control_freq
+ 30 &&
86 chandef
->center_freq1
!= control_freq
+ 10 &&
87 chandef
->center_freq1
!= control_freq
- 10 &&
88 chandef
->center_freq1
!= control_freq
- 30)
90 if (chandef
->center_freq2
)
93 case NL80211_CHAN_WIDTH_160
:
94 if (chandef
->center_freq1
!= control_freq
+ 70 &&
95 chandef
->center_freq1
!= control_freq
+ 50 &&
96 chandef
->center_freq1
!= control_freq
+ 30 &&
97 chandef
->center_freq1
!= control_freq
+ 10 &&
98 chandef
->center_freq1
!= control_freq
- 10 &&
99 chandef
->center_freq1
!= control_freq
- 30 &&
100 chandef
->center_freq1
!= control_freq
- 50 &&
101 chandef
->center_freq1
!= control_freq
- 70)
103 if (chandef
->center_freq2
)
112 EXPORT_SYMBOL(cfg80211_chandef_valid
);
114 static void chandef_primary_freqs(const struct cfg80211_chan_def
*c
,
115 int *pri40
, int *pri80
)
120 case NL80211_CHAN_WIDTH_40
:
121 *pri40
= c
->center_freq1
;
124 case NL80211_CHAN_WIDTH_80
:
125 case NL80211_CHAN_WIDTH_80P80
:
126 *pri80
= c
->center_freq1
;
128 tmp
= (30 + c
->chan
->center_freq
- c
->center_freq1
)/20;
132 *pri40
= c
->center_freq1
- 20 + 40 * tmp
;
134 case NL80211_CHAN_WIDTH_160
:
136 tmp
= (70 + c
->chan
->center_freq
- c
->center_freq1
)/20;
140 *pri40
= c
->center_freq1
- 60 + 40 * tmp
;
143 *pri80
= c
->center_freq1
- 40 + 80 * tmp
;
150 static int cfg80211_chandef_get_width(const struct cfg80211_chan_def
*c
)
155 case NL80211_CHAN_WIDTH_20
:
156 case NL80211_CHAN_WIDTH_20_NOHT
:
159 case NL80211_CHAN_WIDTH_40
:
162 case NL80211_CHAN_WIDTH_80P80
:
163 case NL80211_CHAN_WIDTH_80
:
166 case NL80211_CHAN_WIDTH_160
:
176 const struct cfg80211_chan_def
*
177 cfg80211_chandef_compatible(const struct cfg80211_chan_def
*c1
,
178 const struct cfg80211_chan_def
*c2
)
180 u32 c1_pri40
, c1_pri80
, c2_pri40
, c2_pri80
;
182 /* If they are identical, return */
183 if (cfg80211_chandef_identical(c1
, c2
))
186 /* otherwise, must have same control channel */
187 if (c1
->chan
!= c2
->chan
)
191 * If they have the same width, but aren't identical,
192 * then they can't be compatible.
194 if (c1
->width
== c2
->width
)
197 if (c1
->width
== NL80211_CHAN_WIDTH_20_NOHT
||
198 c1
->width
== NL80211_CHAN_WIDTH_20
)
201 if (c2
->width
== NL80211_CHAN_WIDTH_20_NOHT
||
202 c2
->width
== NL80211_CHAN_WIDTH_20
)
205 chandef_primary_freqs(c1
, &c1_pri40
, &c1_pri80
);
206 chandef_primary_freqs(c2
, &c2_pri40
, &c2_pri80
);
208 if (c1_pri40
!= c2_pri40
)
211 WARN_ON(!c1_pri80
&& !c2_pri80
);
212 if (c1_pri80
&& c2_pri80
&& c1_pri80
!= c2_pri80
)
215 if (c1
->width
> c2
->width
)
219 EXPORT_SYMBOL(cfg80211_chandef_compatible
);
221 static void cfg80211_set_chans_dfs_state(struct wiphy
*wiphy
, u32 center_freq
,
223 enum nl80211_dfs_state dfs_state
)
225 struct ieee80211_channel
*c
;
228 for (freq
= center_freq
- bandwidth
/2 + 10;
229 freq
<= center_freq
+ bandwidth
/2 - 10;
231 c
= ieee80211_get_channel(wiphy
, freq
);
232 if (!c
|| !(c
->flags
& IEEE80211_CHAN_RADAR
))
235 c
->dfs_state
= dfs_state
;
236 c
->dfs_state_entered
= jiffies
;
240 void cfg80211_set_dfs_state(struct wiphy
*wiphy
,
241 const struct cfg80211_chan_def
*chandef
,
242 enum nl80211_dfs_state dfs_state
)
246 if (WARN_ON(!cfg80211_chandef_valid(chandef
)))
249 width
= cfg80211_chandef_get_width(chandef
);
253 cfg80211_set_chans_dfs_state(wiphy
, chandef
->center_freq1
,
256 if (!chandef
->center_freq2
)
258 cfg80211_set_chans_dfs_state(wiphy
, chandef
->center_freq2
,
262 static int cfg80211_get_chans_dfs_required(struct wiphy
*wiphy
,
266 struct ieee80211_channel
*c
;
269 for (freq
= center_freq
- bandwidth
/2 + 10;
270 freq
<= center_freq
+ bandwidth
/2 - 10;
272 c
= ieee80211_get_channel(wiphy
, freq
);
276 if (c
->flags
& IEEE80211_CHAN_RADAR
)
283 int cfg80211_chandef_dfs_required(struct wiphy
*wiphy
,
284 const struct cfg80211_chan_def
*chandef
)
289 if (WARN_ON(!cfg80211_chandef_valid(chandef
)))
292 width
= cfg80211_chandef_get_width(chandef
);
296 r
= cfg80211_get_chans_dfs_required(wiphy
, chandef
->center_freq1
,
301 if (!chandef
->center_freq2
)
304 return cfg80211_get_chans_dfs_required(wiphy
, chandef
->center_freq2
,
308 static bool cfg80211_secondary_chans_ok(struct wiphy
*wiphy
,
309 u32 center_freq
, u32 bandwidth
,
310 u32 prohibited_flags
)
312 struct ieee80211_channel
*c
;
315 for (freq
= center_freq
- bandwidth
/2 + 10;
316 freq
<= center_freq
+ bandwidth
/2 - 10;
318 c
= ieee80211_get_channel(wiphy
, freq
);
322 /* check for radar flags */
323 if ((prohibited_flags
& c
->flags
& IEEE80211_CHAN_RADAR
) &&
324 (c
->dfs_state
!= NL80211_DFS_AVAILABLE
))
327 /* check for the other flags */
328 if (c
->flags
& prohibited_flags
& ~IEEE80211_CHAN_RADAR
)
335 bool cfg80211_chandef_usable(struct wiphy
*wiphy
,
336 const struct cfg80211_chan_def
*chandef
,
337 u32 prohibited_flags
)
339 struct ieee80211_sta_ht_cap
*ht_cap
;
340 struct ieee80211_sta_vht_cap
*vht_cap
;
341 u32 width
, control_freq
, cap
;
343 if (WARN_ON(!cfg80211_chandef_valid(chandef
)))
346 ht_cap
= &wiphy
->bands
[chandef
->chan
->band
]->ht_cap
;
347 vht_cap
= &wiphy
->bands
[chandef
->chan
->band
]->vht_cap
;
349 control_freq
= chandef
->chan
->center_freq
;
351 switch (chandef
->width
) {
352 case NL80211_CHAN_WIDTH_20
:
353 if (!ht_cap
->ht_supported
)
355 case NL80211_CHAN_WIDTH_20_NOHT
:
358 case NL80211_CHAN_WIDTH_40
:
360 if (!ht_cap
->ht_supported
)
362 if (!(ht_cap
->cap
& IEEE80211_HT_CAP_SUP_WIDTH_20_40
) ||
363 ht_cap
->cap
& IEEE80211_HT_CAP_40MHZ_INTOLERANT
)
365 if (chandef
->center_freq1
< control_freq
&&
366 chandef
->chan
->flags
& IEEE80211_CHAN_NO_HT40MINUS
)
368 if (chandef
->center_freq1
> control_freq
&&
369 chandef
->chan
->flags
& IEEE80211_CHAN_NO_HT40PLUS
)
372 case NL80211_CHAN_WIDTH_80P80
:
373 cap
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
374 if (cap
!= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
376 case NL80211_CHAN_WIDTH_80
:
377 if (!vht_cap
->vht_supported
)
379 prohibited_flags
|= IEEE80211_CHAN_NO_80MHZ
;
382 case NL80211_CHAN_WIDTH_160
:
383 if (!vht_cap
->vht_supported
)
385 cap
= vht_cap
->cap
& IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK
;
386 if (cap
!= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
&&
387 cap
!= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ
)
389 prohibited_flags
|= IEEE80211_CHAN_NO_160MHZ
;
398 * TODO: What if there are only certain 80/160/80+80 MHz channels
399 * allowed by the driver, or only certain combinations?
400 * For 40 MHz the driver can set the NO_HT40 flags, but for
401 * 80/160 MHz and in particular 80+80 MHz this isn't really
402 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
403 * no way to cover 80+80 MHz or more complex restrictions.
404 * Note that such restrictions also need to be advertised to
405 * userspace, for example for P2P channel selection.
409 prohibited_flags
|= IEEE80211_CHAN_NO_OFDM
;
411 if (!cfg80211_secondary_chans_ok(wiphy
, chandef
->center_freq1
,
412 width
, prohibited_flags
))
415 if (!chandef
->center_freq2
)
417 return cfg80211_secondary_chans_ok(wiphy
, chandef
->center_freq2
,
418 width
, prohibited_flags
);
420 EXPORT_SYMBOL(cfg80211_chandef_usable
);
422 bool cfg80211_reg_can_beacon(struct wiphy
*wiphy
,
423 struct cfg80211_chan_def
*chandef
)
427 trace_cfg80211_reg_can_beacon(wiphy
, chandef
);
429 res
= cfg80211_chandef_usable(wiphy
, chandef
,
430 IEEE80211_CHAN_DISABLED
|
431 IEEE80211_CHAN_PASSIVE_SCAN
|
432 IEEE80211_CHAN_NO_IBSS
|
433 IEEE80211_CHAN_RADAR
);
435 trace_cfg80211_return_bool(res
);
438 EXPORT_SYMBOL(cfg80211_reg_can_beacon
);
440 int cfg80211_set_monitor_channel(struct cfg80211_registered_device
*rdev
,
441 struct cfg80211_chan_def
*chandef
)
443 if (!rdev
->ops
->set_monitor_channel
)
445 if (!cfg80211_has_monitors_only(rdev
))
448 return rdev_set_monitor_channel(rdev
, chandef
);
452 cfg80211_get_chan_state(struct wireless_dev
*wdev
,
453 struct ieee80211_channel
**chan
,
454 enum cfg80211_chan_mode
*chanmode
)
457 *chanmode
= CHAN_MODE_UNDEFINED
;
459 ASSERT_WDEV_LOCK(wdev
);
461 if (wdev
->netdev
&& !netif_running(wdev
->netdev
))
464 switch (wdev
->iftype
) {
465 case NL80211_IFTYPE_ADHOC
:
466 if (wdev
->current_bss
) {
467 *chan
= wdev
->current_bss
->pub
.channel
;
468 *chanmode
= wdev
->ibss_fixed
470 : CHAN_MODE_EXCLUSIVE
;
473 case NL80211_IFTYPE_STATION
:
474 case NL80211_IFTYPE_P2P_CLIENT
:
475 if (wdev
->current_bss
) {
476 *chan
= wdev
->current_bss
->pub
.channel
;
477 *chanmode
= CHAN_MODE_SHARED
;
481 case NL80211_IFTYPE_AP
:
482 case NL80211_IFTYPE_P2P_GO
:
483 if (wdev
->cac_started
) {
484 *chan
= wdev
->channel
;
485 *chanmode
= CHAN_MODE_SHARED
;
486 } else if (wdev
->beacon_interval
) {
487 *chan
= wdev
->channel
;
488 *chanmode
= CHAN_MODE_SHARED
;
491 case NL80211_IFTYPE_MESH_POINT
:
492 if (wdev
->mesh_id_len
) {
493 *chan
= wdev
->channel
;
494 *chanmode
= CHAN_MODE_SHARED
;
497 case NL80211_IFTYPE_MONITOR
:
498 case NL80211_IFTYPE_AP_VLAN
:
499 case NL80211_IFTYPE_WDS
:
500 /* these interface types don't really have a channel */
502 case NL80211_IFTYPE_P2P_DEVICE
:
503 if (wdev
->wiphy
->features
&
504 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL
)
505 *chanmode
= CHAN_MODE_EXCLUSIVE
;
507 case NL80211_IFTYPE_UNSPECIFIED
:
508 case NUM_NL80211_IFTYPES
: