2 * This file contains helper code to handle channel
3 * settings and keeping track of what is possible at
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;
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 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
375 case NL80211_CHAN_WIDTH_80:
376 if (!vht_cap->vht_supported)
378 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
381 case NL80211_CHAN_WIDTH_160:
382 if (!vht_cap->vht_supported)
384 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
386 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
395 * TODO: What if there are only certain 80/160/80+80 MHz channels
396 * allowed by the driver, or only certain combinations?
397 * For 40 MHz the driver can set the NO_HT40 flags, but for
398 * 80/160 MHz and in particular 80+80 MHz this isn't really
399 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
400 * no way to cover 80+80 MHz or more complex restrictions.
401 * Note that such restrictions also need to be advertised to
402 * userspace, for example for P2P channel selection.
406 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
408 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
409 width, prohibited_flags))
412 if (!chandef->center_freq2)
414 return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
415 width, prohibited_flags);
417 EXPORT_SYMBOL(cfg80211_chandef_usable);
419 bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
420 struct cfg80211_chan_def *chandef)
424 trace_cfg80211_reg_can_beacon(wiphy, chandef);
426 res = cfg80211_chandef_usable(wiphy, chandef,
427 IEEE80211_CHAN_DISABLED |
428 IEEE80211_CHAN_PASSIVE_SCAN |
429 IEEE80211_CHAN_NO_IBSS |
430 IEEE80211_CHAN_RADAR);
432 trace_cfg80211_return_bool(res);
435 EXPORT_SYMBOL(cfg80211_reg_can_beacon);
437 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
438 struct cfg80211_chan_def *chandef)
440 if (!rdev->ops->set_monitor_channel)
442 if (!cfg80211_has_monitors_only(rdev))
445 return rdev_set_monitor_channel(rdev, chandef);
449 cfg80211_get_chan_state(struct wireless_dev *wdev,
450 struct ieee80211_channel **chan,
451 enum cfg80211_chan_mode *chanmode)
454 *chanmode = CHAN_MODE_UNDEFINED;
456 ASSERT_WDEV_LOCK(wdev);
458 if (wdev->netdev && !netif_running(wdev->netdev))
461 switch (wdev->iftype) {
462 case NL80211_IFTYPE_ADHOC:
463 if (wdev->current_bss) {
464 *chan = wdev->current_bss->pub.channel;
465 *chanmode = wdev->ibss_fixed
467 : CHAN_MODE_EXCLUSIVE;
470 case NL80211_IFTYPE_STATION:
471 case NL80211_IFTYPE_P2P_CLIENT:
472 if (wdev->current_bss) {
473 *chan = wdev->current_bss->pub.channel;
474 *chanmode = CHAN_MODE_SHARED;
478 case NL80211_IFTYPE_AP:
479 case NL80211_IFTYPE_P2P_GO:
480 if (wdev->cac_started) {
481 *chan = wdev->channel;
482 *chanmode = CHAN_MODE_SHARED;
483 } else if (wdev->beacon_interval) {
484 *chan = wdev->channel;
485 *chanmode = CHAN_MODE_SHARED;
488 case NL80211_IFTYPE_MESH_POINT:
489 if (wdev->mesh_id_len) {
490 *chan = wdev->channel;
491 *chanmode = CHAN_MODE_SHARED;
494 case NL80211_IFTYPE_MONITOR:
495 case NL80211_IFTYPE_AP_VLAN:
496 case NL80211_IFTYPE_WDS:
497 /* these interface types don't really have a channel */
499 case NL80211_IFTYPE_P2P_DEVICE:
500 if (wdev->wiphy->features &
501 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
502 *chanmode = CHAN_MODE_EXCLUSIVE;
504 case NL80211_IFTYPE_UNSPECIFIED:
505 case NUM_NL80211_IFTYPES: