blob: 7dc1bbd0888fffee2cb70acfc10300a12ec9e933 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Johannes Berg59bbb6f2009-08-07 17:22:35 +02002/*
3 * This file contains helper code to handle channel
4 * settings and keeping track of what is possible at
5 * any point in time.
6 *
7 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg2740f0c2014-09-03 15:24:58 +03008 * Copyright 2013-2014 Intel Mobile Communications GmbH
Luca Coelho925b5972018-12-15 11:03:21 +02009 * Copyright 2018 Intel Corporation
Johannes Berg59bbb6f2009-08-07 17:22:35 +020010 */
11
Alexander Simon54858ee5b2011-11-30 16:56:32 +010012#include <linux/export.h>
Johannes Berg59bbb6f2009-08-07 17:22:35 +020013#include <net/cfg80211.h>
14#include "core.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030015#include "rdev-ops.h"
Johannes Berg59bbb6f2009-08-07 17:22:35 +020016
Johannes Berg3d9d1d62012-11-08 23:14:50 +010017void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
18 struct ieee80211_channel *chan,
19 enum nl80211_channel_type chan_type)
20{
21 if (WARN_ON(!chan))
22 return;
23
24 chandef->chan = chan;
25 chandef->center_freq2 = 0;
26
27 switch (chan_type) {
28 case NL80211_CHAN_NO_HT:
29 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
30 chandef->center_freq1 = chan->center_freq;
31 break;
32 case NL80211_CHAN_HT20:
33 chandef->width = NL80211_CHAN_WIDTH_20;
34 chandef->center_freq1 = chan->center_freq;
35 break;
36 case NL80211_CHAN_HT40PLUS:
37 chandef->width = NL80211_CHAN_WIDTH_40;
38 chandef->center_freq1 = chan->center_freq + 10;
39 break;
40 case NL80211_CHAN_HT40MINUS:
41 chandef->width = NL80211_CHAN_WIDTH_40;
42 chandef->center_freq1 = chan->center_freq - 10;
43 break;
44 default:
45 WARN_ON(1);
46 }
47}
48EXPORT_SYMBOL(cfg80211_chandef_create);
49
Johannes Berg9f5e8f62012-11-22 16:59:45 +010050bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
Johannes Berg3d9d1d62012-11-08 23:14:50 +010051{
52 u32 control_freq;
53
54 if (!chandef->chan)
55 return false;
56
57 control_freq = chandef->chan->center_freq;
58
59 switch (chandef->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +020060 case NL80211_CHAN_WIDTH_5:
61 case NL80211_CHAN_WIDTH_10:
Johannes Berg3d9d1d62012-11-08 23:14:50 +010062 case NL80211_CHAN_WIDTH_20:
63 case NL80211_CHAN_WIDTH_20_NOHT:
64 if (chandef->center_freq1 != control_freq)
65 return false;
66 if (chandef->center_freq2)
67 return false;
68 break;
69 case NL80211_CHAN_WIDTH_40:
70 if (chandef->center_freq1 != control_freq + 10 &&
71 chandef->center_freq1 != control_freq - 10)
72 return false;
73 if (chandef->center_freq2)
74 return false;
75 break;
76 case NL80211_CHAN_WIDTH_80P80:
77 if (chandef->center_freq1 != control_freq + 30 &&
78 chandef->center_freq1 != control_freq + 10 &&
79 chandef->center_freq1 != control_freq - 10 &&
80 chandef->center_freq1 != control_freq - 30)
81 return false;
82 if (!chandef->center_freq2)
83 return false;
Johannes Berg9cab3152012-12-14 00:19:08 +010084 /* adjacent is not allowed -- that's a 160 MHz channel */
85 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
86 chandef->center_freq2 - chandef->center_freq1 == 80)
87 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010088 break;
89 case NL80211_CHAN_WIDTH_80:
90 if (chandef->center_freq1 != control_freq + 30 &&
91 chandef->center_freq1 != control_freq + 10 &&
92 chandef->center_freq1 != control_freq - 10 &&
93 chandef->center_freq1 != control_freq - 30)
94 return false;
95 if (chandef->center_freq2)
96 return false;
97 break;
98 case NL80211_CHAN_WIDTH_160:
99 if (chandef->center_freq1 != control_freq + 70 &&
100 chandef->center_freq1 != control_freq + 50 &&
101 chandef->center_freq1 != control_freq + 30 &&
102 chandef->center_freq1 != control_freq + 10 &&
103 chandef->center_freq1 != control_freq - 10 &&
104 chandef->center_freq1 != control_freq - 30 &&
105 chandef->center_freq1 != control_freq - 50 &&
106 chandef->center_freq1 != control_freq - 70)
107 return false;
108 if (chandef->center_freq2)
109 return false;
110 break;
111 default:
112 return false;
113 }
114
115 return true;
116}
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100117EXPORT_SYMBOL(cfg80211_chandef_valid);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100118
119static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
Johannes Bergfc1f48f2014-10-29 17:05:39 +0100120 u32 *pri40, u32 *pri80)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100121{
122 int tmp;
123
124 switch (c->width) {
125 case NL80211_CHAN_WIDTH_40:
126 *pri40 = c->center_freq1;
127 *pri80 = 0;
128 break;
129 case NL80211_CHAN_WIDTH_80:
130 case NL80211_CHAN_WIDTH_80P80:
131 *pri80 = c->center_freq1;
132 /* n_P20 */
133 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
134 /* n_P40 */
135 tmp /= 2;
136 /* freq_P40 */
137 *pri40 = c->center_freq1 - 20 + 40 * tmp;
138 break;
139 case NL80211_CHAN_WIDTH_160:
140 /* n_P20 */
141 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
142 /* n_P40 */
143 tmp /= 2;
144 /* freq_P40 */
145 *pri40 = c->center_freq1 - 60 + 40 * tmp;
146 /* n_P80 */
147 tmp /= 2;
148 *pri80 = c->center_freq1 - 40 + 80 * tmp;
149 break;
150 default:
151 WARN_ON_ONCE(1);
152 }
153}
154
Simon Wunderlich04f39042013-02-08 18:16:19 +0100155static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
156{
157 int width;
158
159 switch (c->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200160 case NL80211_CHAN_WIDTH_5:
161 width = 5;
162 break;
163 case NL80211_CHAN_WIDTH_10:
164 width = 10;
165 break;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100166 case NL80211_CHAN_WIDTH_20:
167 case NL80211_CHAN_WIDTH_20_NOHT:
168 width = 20;
169 break;
170 case NL80211_CHAN_WIDTH_40:
171 width = 40;
172 break;
173 case NL80211_CHAN_WIDTH_80P80:
174 case NL80211_CHAN_WIDTH_80:
175 width = 80;
176 break;
177 case NL80211_CHAN_WIDTH_160:
178 width = 160;
179 break;
180 default:
181 WARN_ON_ONCE(1);
182 return -1;
183 }
184 return width;
185}
186
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100187const struct cfg80211_chan_def *
188cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
189 const struct cfg80211_chan_def *c2)
190{
191 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
192
193 /* If they are identical, return */
194 if (cfg80211_chandef_identical(c1, c2))
195 return c1;
196
197 /* otherwise, must have same control channel */
198 if (c1->chan != c2->chan)
199 return NULL;
200
201 /*
202 * If they have the same width, but aren't identical,
203 * then they can't be compatible.
204 */
205 if (c1->width == c2->width)
206 return NULL;
207
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200208 /*
209 * can't be compatible if one of them is 5 or 10 MHz,
210 * but they don't have the same width.
211 */
212 if (c1->width == NL80211_CHAN_WIDTH_5 ||
213 c1->width == NL80211_CHAN_WIDTH_10 ||
214 c2->width == NL80211_CHAN_WIDTH_5 ||
215 c2->width == NL80211_CHAN_WIDTH_10)
216 return NULL;
217
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100218 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
219 c1->width == NL80211_CHAN_WIDTH_20)
220 return c2;
221
222 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
223 c2->width == NL80211_CHAN_WIDTH_20)
224 return c1;
225
226 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
227 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
228
229 if (c1_pri40 != c2_pri40)
230 return NULL;
231
232 WARN_ON(!c1_pri80 && !c2_pri80);
233 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
234 return NULL;
235
236 if (c1->width > c2->width)
237 return c1;
238 return c2;
239}
240EXPORT_SYMBOL(cfg80211_chandef_compatible);
241
Simon Wunderlich04f39042013-02-08 18:16:19 +0100242static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
243 u32 bandwidth,
244 enum nl80211_dfs_state dfs_state)
245{
246 struct ieee80211_channel *c;
247 u32 freq;
248
249 for (freq = center_freq - bandwidth/2 + 10;
250 freq <= center_freq + bandwidth/2 - 10;
251 freq += 20) {
252 c = ieee80211_get_channel(wiphy, freq);
253 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
254 continue;
255
256 c->dfs_state = dfs_state;
257 c->dfs_state_entered = jiffies;
258 }
259}
260
261void cfg80211_set_dfs_state(struct wiphy *wiphy,
262 const struct cfg80211_chan_def *chandef,
263 enum nl80211_dfs_state dfs_state)
264{
265 int width;
266
267 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
268 return;
269
270 width = cfg80211_chandef_get_width(chandef);
271 if (width < 0)
272 return;
273
274 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
275 width, dfs_state);
276
277 if (!chandef->center_freq2)
278 return;
279 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
280 width, dfs_state);
281}
282
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100283static u32 cfg80211_get_start_freq(u32 center_freq,
284 u32 bandwidth)
285{
286 u32 start_freq;
287
288 if (bandwidth <= 20)
289 start_freq = center_freq;
290 else
291 start_freq = center_freq - bandwidth/2 + 10;
292
293 return start_freq;
294}
295
296static u32 cfg80211_get_end_freq(u32 center_freq,
297 u32 bandwidth)
298{
299 u32 end_freq;
300
301 if (bandwidth <= 20)
302 end_freq = center_freq;
303 else
304 end_freq = center_freq + bandwidth/2 - 10;
305
306 return end_freq;
307}
308
Simon Wunderlich04f39042013-02-08 18:16:19 +0100309static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
310 u32 center_freq,
311 u32 bandwidth)
312{
313 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200314 u32 freq, start_freq, end_freq;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100315
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100316 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
317 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200318
319 for (freq = start_freq; freq <= end_freq; freq += 20) {
Simon Wunderlich04f39042013-02-08 18:16:19 +0100320 c = ieee80211_get_channel(wiphy, freq);
321 if (!c)
322 return -EINVAL;
323
324 if (c->flags & IEEE80211_CHAN_RADAR)
325 return 1;
326 }
327 return 0;
328}
329
330
331int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200332 const struct cfg80211_chan_def *chandef,
333 enum nl80211_iftype iftype)
Simon Wunderlich04f39042013-02-08 18:16:19 +0100334{
335 int width;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200336 int ret;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100337
338 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
339 return -EINVAL;
340
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200341 switch (iftype) {
342 case NL80211_IFTYPE_ADHOC:
343 case NL80211_IFTYPE_AP:
344 case NL80211_IFTYPE_P2P_GO:
345 case NL80211_IFTYPE_MESH_POINT:
346 width = cfg80211_chandef_get_width(chandef);
347 if (width < 0)
348 return -EINVAL;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100349
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200350 ret = cfg80211_get_chans_dfs_required(wiphy,
351 chandef->center_freq1,
352 width);
353 if (ret < 0)
354 return ret;
355 else if (ret > 0)
356 return BIT(chandef->width);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100357
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200358 if (!chandef->center_freq2)
359 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100360
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200361 ret = cfg80211_get_chans_dfs_required(wiphy,
362 chandef->center_freq2,
363 width);
364 if (ret < 0)
365 return ret;
366 else if (ret > 0)
367 return BIT(chandef->width);
368
369 break;
370 case NL80211_IFTYPE_STATION:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100371 case NL80211_IFTYPE_OCB:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200372 case NL80211_IFTYPE_P2P_CLIENT:
373 case NL80211_IFTYPE_MONITOR:
374 case NL80211_IFTYPE_AP_VLAN:
375 case NL80211_IFTYPE_WDS:
376 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300377 case NL80211_IFTYPE_NAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200378 break;
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300379 case NL80211_IFTYPE_UNSPECIFIED:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200380 case NUM_NL80211_IFTYPES:
381 WARN_ON(1);
382 }
383
384 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100385}
Simon Wunderlich774f0732013-08-28 13:41:28 +0200386EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100387
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100388static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
389 u32 center_freq,
390 u32 bandwidth)
391{
392 struct ieee80211_channel *c;
393 u32 freq, start_freq, end_freq;
394 int count = 0;
395
396 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
397 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
398
399 /*
400 * Check entire range of channels for the bandwidth.
401 * Check all channels are DFS channels (DFS_USABLE or
402 * DFS_AVAILABLE). Return number of usable channels
403 * (require CAC). Allow DFS and non-DFS channel mix.
404 */
405 for (freq = start_freq; freq <= end_freq; freq += 20) {
406 c = ieee80211_get_channel(wiphy, freq);
407 if (!c)
408 return -EINVAL;
409
410 if (c->flags & IEEE80211_CHAN_DISABLED)
411 return -EINVAL;
412
413 if (c->flags & IEEE80211_CHAN_RADAR) {
414 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
415 return -EINVAL;
416
417 if (c->dfs_state == NL80211_DFS_USABLE)
418 count++;
419 }
420 }
421
422 return count;
423}
424
425bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
426 const struct cfg80211_chan_def *chandef)
427{
428 int width;
429 int r1, r2 = 0;
430
431 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
432 return false;
433
434 width = cfg80211_chandef_get_width(chandef);
435 if (width < 0)
436 return false;
437
438 r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
439 width);
440
441 if (r1 < 0)
442 return false;
443
444 switch (chandef->width) {
445 case NL80211_CHAN_WIDTH_80P80:
446 WARN_ON(!chandef->center_freq2);
447 r2 = cfg80211_get_chans_dfs_usable(wiphy,
448 chandef->center_freq2,
449 width);
450 if (r2 < 0)
451 return false;
452 break;
453 default:
454 WARN_ON(chandef->center_freq2);
455 break;
456 }
457
458 return (r1 + r2 > 0);
459}
460
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530461/*
462 * Checks if center frequency of chan falls with in the bandwidth
463 * range of chandef.
464 */
465bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
466 struct ieee80211_channel *chan)
467{
468 int width;
Johannes Berga67a4892017-10-12 11:23:04 +0200469 u32 freq;
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530470
471 if (chandef->chan->center_freq == chan->center_freq)
472 return true;
473
474 width = cfg80211_chandef_get_width(chandef);
475 if (width <= 20)
476 return false;
477
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530478 for (freq = chandef->center_freq1 - width / 2 + 10;
479 freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
480 if (chan->center_freq == freq)
481 return true;
482 }
483
484 if (!chandef->center_freq2)
485 return false;
486
487 for (freq = chandef->center_freq2 - width / 2 + 10;
488 freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
489 if (chan->center_freq == freq)
490 return true;
491 }
492
493 return false;
494}
495
496bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
497{
498 bool active = false;
499
500 ASSERT_WDEV_LOCK(wdev);
501
502 if (!wdev->chandef.chan)
503 return false;
504
505 switch (wdev->iftype) {
506 case NL80211_IFTYPE_AP:
507 case NL80211_IFTYPE_P2P_GO:
508 active = wdev->beacon_interval != 0;
509 break;
510 case NL80211_IFTYPE_ADHOC:
511 active = wdev->ssid_len != 0;
512 break;
513 case NL80211_IFTYPE_MESH_POINT:
514 active = wdev->mesh_id_len != 0;
515 break;
516 case NL80211_IFTYPE_STATION:
517 case NL80211_IFTYPE_OCB:
518 case NL80211_IFTYPE_P2P_CLIENT:
519 case NL80211_IFTYPE_MONITOR:
520 case NL80211_IFTYPE_AP_VLAN:
521 case NL80211_IFTYPE_WDS:
522 case NL80211_IFTYPE_P2P_DEVICE:
523 /* Can NAN type be considered as beaconing interface? */
524 case NL80211_IFTYPE_NAN:
525 break;
526 case NL80211_IFTYPE_UNSPECIFIED:
527 case NUM_NL80211_IFTYPES:
528 WARN_ON(1);
529 }
530
531 return active;
532}
533
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530534static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
535 struct ieee80211_channel *chan)
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530536{
537 struct wireless_dev *wdev;
538
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530539 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
540 wdev_lock(wdev);
541 if (!cfg80211_beaconing_iface_active(wdev)) {
542 wdev_unlock(wdev);
543 continue;
544 }
545
546 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
547 wdev_unlock(wdev);
548 return true;
549 }
550 wdev_unlock(wdev);
551 }
552
553 return false;
554}
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100555
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530556bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
557 struct ieee80211_channel *chan)
558{
559 struct cfg80211_registered_device *rdev;
560
561 ASSERT_RTNL();
562
563 if (!(chan->flags & IEEE80211_CHAN_RADAR))
564 return false;
565
566 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
567 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
568 continue;
569
570 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
571 return true;
572 }
573
574 return false;
575}
576
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100577static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
578 u32 center_freq,
579 u32 bandwidth)
580{
581 struct ieee80211_channel *c;
582 u32 freq, start_freq, end_freq;
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300583 bool dfs_offload;
584
585 dfs_offload = wiphy_ext_feature_isset(wiphy,
586 NL80211_EXT_FEATURE_DFS_OFFLOAD);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100587
588 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
589 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
590
591 /*
592 * Check entire range of channels for the bandwidth.
593 * If any channel in between is disabled or has not
594 * had gone through CAC return false
595 */
596 for (freq = start_freq; freq <= end_freq; freq += 20) {
597 c = ieee80211_get_channel(wiphy, freq);
598 if (!c)
599 return false;
600
601 if (c->flags & IEEE80211_CHAN_DISABLED)
602 return false;
603
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300604 if ((c->flags & IEEE80211_CHAN_RADAR) &&
605 (c->dfs_state != NL80211_DFS_AVAILABLE) &&
606 !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100607 return false;
608 }
609
610 return true;
611}
612
613static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
614 const struct cfg80211_chan_def *chandef)
615{
616 int width;
617 int r;
618
619 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
620 return false;
621
622 width = cfg80211_chandef_get_width(chandef);
623 if (width < 0)
624 return false;
625
626 r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
627 width);
628
629 /* If any of channels unavailable for cf1 just return */
630 if (!r)
631 return r;
632
633 switch (chandef->width) {
634 case NL80211_CHAN_WIDTH_80P80:
635 WARN_ON(!chandef->center_freq2);
636 r = cfg80211_get_chans_dfs_available(wiphy,
637 chandef->center_freq2,
638 width);
Colin Ian King680682d2016-07-17 19:55:27 +0100639 break;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100640 default:
641 WARN_ON(chandef->center_freq2);
642 break;
643 }
644
645 return r;
646}
647
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100648static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
649 u32 center_freq,
650 u32 bandwidth)
651{
652 struct ieee80211_channel *c;
653 u32 start_freq, end_freq, freq;
654 unsigned int dfs_cac_ms = 0;
655
656 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
657 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
658
659 for (freq = start_freq; freq <= end_freq; freq += 20) {
660 c = ieee80211_get_channel(wiphy, freq);
661 if (!c)
662 return 0;
663
664 if (c->flags & IEEE80211_CHAN_DISABLED)
665 return 0;
666
667 if (!(c->flags & IEEE80211_CHAN_RADAR))
668 continue;
669
670 if (c->dfs_cac_ms > dfs_cac_ms)
671 dfs_cac_ms = c->dfs_cac_ms;
672 }
673
674 return dfs_cac_ms;
675}
676
677unsigned int
678cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
679 const struct cfg80211_chan_def *chandef)
680{
681 int width;
682 unsigned int t1 = 0, t2 = 0;
683
684 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
685 return 0;
686
687 width = cfg80211_chandef_get_width(chandef);
688 if (width < 0)
689 return 0;
690
691 t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
692 chandef->center_freq1,
693 width);
694
695 if (!chandef->center_freq2)
696 return t1;
697
698 t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
699 chandef->center_freq2,
700 width);
701
702 return max(t1, t2);
703}
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100704
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100705static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
706 u32 center_freq, u32 bandwidth,
707 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100708{
709 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200710 u32 freq, start_freq, end_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100711
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100712 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
713 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200714
715 for (freq = start_freq; freq <= end_freq; freq += 20) {
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100716 c = ieee80211_get_channel(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100717 if (!c || c->flags & prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100718 return false;
719 }
720
721 return true;
722}
723
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100724bool cfg80211_chandef_usable(struct wiphy *wiphy,
725 const struct cfg80211_chan_def *chandef,
726 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100727{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100728 struct ieee80211_sta_ht_cap *ht_cap;
729 struct ieee80211_sta_vht_cap *vht_cap;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200730 u32 width, control_freq, cap;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100731
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100732 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100733 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100734
735 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
736 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
737
738 control_freq = chandef->chan->center_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100739
740 switch (chandef->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200741 case NL80211_CHAN_WIDTH_5:
742 width = 5;
743 break;
744 case NL80211_CHAN_WIDTH_10:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200745 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200746 width = 10;
747 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100748 case NL80211_CHAN_WIDTH_20:
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100749 if (!ht_cap->ht_supported)
750 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200751 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100752 case NL80211_CHAN_WIDTH_20_NOHT:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200753 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100754 width = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500755 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100756 case NL80211_CHAN_WIDTH_40:
757 width = 40;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100758 if (!ht_cap->ht_supported)
759 return false;
760 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
761 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
762 return false;
763 if (chandef->center_freq1 < control_freq &&
764 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
765 return false;
766 if (chandef->center_freq1 > control_freq &&
767 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
768 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100769 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100770 case NL80211_CHAN_WIDTH_80P80:
Jouni Malinen08f6f142014-12-11 23:48:55 +0200771 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
772 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100773 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200774 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100775 case NL80211_CHAN_WIDTH_80:
776 if (!vht_cap->vht_supported)
777 return false;
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100778 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100779 width = 80;
780 break;
781 case NL80211_CHAN_WIDTH_160:
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100782 if (!vht_cap->vht_supported)
783 return false;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200784 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
785 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
786 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100787 return false;
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100788 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100789 width = 160;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500790 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800791 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100792 WARN_ON_ONCE(1);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800793 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +0300794 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800795
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100796 /*
797 * TODO: What if there are only certain 80/160/80+80 MHz channels
798 * allowed by the driver, or only certain combinations?
799 * For 40 MHz the driver can set the NO_HT40 flags, but for
800 * 80/160 MHz and in particular 80+80 MHz this isn't really
801 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
802 * no way to cover 80+80 MHz or more complex restrictions.
803 * Note that such restrictions also need to be advertised to
804 * userspace, for example for P2P channel selection.
805 */
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100806
Johannes Berga6662db2012-12-04 20:49:42 +0100807 if (width > 20)
808 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
809
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200810 /* 5 and 10 MHz are only defined for the OFDM PHY */
811 if (width < 20)
812 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
813
814
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100815 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
816 width, prohibited_flags))
817 return false;
818
819 if (!chandef->center_freq2)
820 return true;
821 return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
822 width, prohibited_flags);
823}
824EXPORT_SYMBOL(cfg80211_chandef_usable);
825
Ilan Peer174e0cd2014-02-23 09:13:01 +0200826/*
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300827 * Check if the channel can be used under permissive conditions mandated by
828 * some regulatory bodies, i.e., the channel is marked with
829 * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
Ilan Peer174e0cd2014-02-23 09:13:01 +0200830 * associated to an AP on the same channel or on the same UNII band
831 * (assuming that the AP is an authorized master).
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300832 * In addition allow operation on a channel on which indoor operation is
Ilan Peerc8866e52014-02-23 09:13:03 +0200833 * allowed, iff we are currently operating in an indoor environment.
Ilan Peer174e0cd2014-02-23 09:13:01 +0200834 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300835static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
836 enum nl80211_iftype iftype,
Ilan Peer174e0cd2014-02-23 09:13:01 +0200837 struct ieee80211_channel *chan)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100838{
Avraham Sternbe69c242015-04-27 16:52:16 +0300839 struct wireless_dev *wdev;
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300840 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Ilan Peer174e0cd2014-02-23 09:13:01 +0200841
842 ASSERT_RTNL();
843
Masahiro Yamada97f26452016-08-03 13:45:50 -0700844 if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
Ilan Peerc8866e52014-02-23 09:13:03 +0200845 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
846 return false;
847
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300848 /* only valid for GO and TDLS off-channel (station/p2p-CL) */
849 if (iftype != NL80211_IFTYPE_P2P_GO &&
850 iftype != NL80211_IFTYPE_STATION &&
851 iftype != NL80211_IFTYPE_P2P_CLIENT)
852 return false;
853
Ilan Peerc8866e52014-02-23 09:13:03 +0200854 if (regulatory_indoor_allowed() &&
855 (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
856 return true;
857
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300858 if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
Ilan Peer174e0cd2014-02-23 09:13:01 +0200859 return false;
860
861 /*
862 * Generally, it is possible to rely on another device/driver to allow
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300863 * the IR concurrent relaxation, however, since the device can further
Ilan Peer174e0cd2014-02-23 09:13:01 +0200864 * enforce the relaxation (by doing a similar verifications as this),
865 * and thus fail the GO instantiation, consider only the interfaces of
866 * the current registered device.
867 */
Johannes Berg53873f12016-05-03 16:52:04 +0300868 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Ilan Peer174e0cd2014-02-23 09:13:01 +0200869 struct ieee80211_channel *other_chan = NULL;
870 int r1, r2;
871
Avraham Sternbe69c242015-04-27 16:52:16 +0300872 wdev_lock(wdev);
873 if (wdev->iftype == NL80211_IFTYPE_STATION &&
874 wdev->current_bss)
875 other_chan = wdev->current_bss->pub.channel;
Ilan Peer174e0cd2014-02-23 09:13:01 +0200876
Avraham Sternbe69c242015-04-27 16:52:16 +0300877 /*
878 * If a GO already operates on the same GO_CONCURRENT channel,
879 * this one (maybe the same one) can beacon as well. We allow
880 * the operation even if the station we relied on with
881 * GO_CONCURRENT is disconnected now. But then we must make sure
882 * we're not outdoor on an indoor-only channel.
883 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300884 if (iftype == NL80211_IFTYPE_P2P_GO &&
885 wdev->iftype == NL80211_IFTYPE_P2P_GO &&
Avraham Sternbe69c242015-04-27 16:52:16 +0300886 wdev->beacon_interval &&
887 !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
888 other_chan = wdev->chandef.chan;
889 wdev_unlock(wdev);
Ilan Peer174e0cd2014-02-23 09:13:01 +0200890
891 if (!other_chan)
892 continue;
893
894 if (chan == other_chan)
895 return true;
896
Johannes Berg57fbcce2016-04-12 15:56:15 +0200897 if (chan->band != NL80211_BAND_5GHZ)
Ilan Peer174e0cd2014-02-23 09:13:01 +0200898 continue;
899
900 r1 = cfg80211_get_unii(chan->center_freq);
901 r2 = cfg80211_get_unii(other_chan->center_freq);
902
Ilan Peer46d53722014-04-23 09:22:58 +0300903 if (r1 != -EINVAL && r1 == r2) {
904 /*
905 * At some locations channels 149-165 are considered a
906 * bundle, but at other locations, e.g., Indonesia,
907 * channels 149-161 are considered a bundle while
908 * channel 165 is left out and considered to be in a
909 * different bundle. Thus, in case that there is a
910 * station interface connected to an AP on channel 165,
911 * it is assumed that channels 149-161 are allowed for
912 * GO operations. However, having a station interface
913 * connected to an AP on channels 149-161, does not
914 * allow GO operation on channel 165.
915 */
916 if (chan->center_freq == 5825 &&
917 other_chan->center_freq != 5825)
918 continue;
Ilan Peer174e0cd2014-02-23 09:13:01 +0200919 return true;
Ilan Peer46d53722014-04-23 09:22:58 +0300920 }
Ilan Peer174e0cd2014-02-23 09:13:01 +0200921 }
922
923 return false;
924}
925
Arik Nemtsov923b3522015-07-08 15:41:44 +0300926static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
927 struct cfg80211_chan_def *chandef,
928 enum nl80211_iftype iftype,
929 bool check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +0200930{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100931 bool res;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100932 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100933 IEEE80211_CHAN_RADAR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100934
Arik Nemtsov923b3522015-07-08 15:41:44 +0300935 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
Ilan Peer174e0cd2014-02-23 09:13:01 +0200936
Arik Nemtsov923b3522015-07-08 15:41:44 +0300937 if (check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +0200938 prohibited_flags |= IEEE80211_CHAN_NO_IR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100939
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300940 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100941 cfg80211_chandef_dfs_available(wiphy, chandef)) {
942 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
943 prohibited_flags = IEEE80211_CHAN_DISABLED;
944 }
945
946 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100947
948 trace_cfg80211_return_bool(res);
949 return res;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800950}
Arik Nemtsov923b3522015-07-08 15:41:44 +0300951
952bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
953 struct cfg80211_chan_def *chandef,
954 enum nl80211_iftype iftype)
955{
956 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
957}
Johannes Berg683b6d32012-11-08 21:25:48 +0100958EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800959
Arik Nemtsov923b3522015-07-08 15:41:44 +0300960bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
961 struct cfg80211_chan_def *chandef,
962 enum nl80211_iftype iftype)
963{
964 bool check_no_ir;
965
966 ASSERT_RTNL();
967
968 /*
969 * Under certain conditions suggested by some regulatory bodies a
970 * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
971 * only if such relaxations are not enabled and the conditions are not
972 * met.
973 */
974 check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
975 chandef->chan);
976
977 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
978}
979EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
980
Johannes Berge8c9bd52012-06-06 08:18:22 +0200981int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +0100982 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200983{
Johannes Berge8c9bd52012-06-06 08:18:22 +0200984 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200985 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +0200986 if (!cfg80211_has_monitors_only(rdev))
987 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200988
Johannes Berg683b6d32012-11-08 21:25:48 +0100989 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +0200990}
Michal Kazior26ab9a02012-06-29 12:47:00 +0200991
992void
Johannes Berg8e95ea42012-07-10 19:39:02 +0200993cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +0200994 struct ieee80211_channel **chan,
Michal Kazior9e0e2962014-01-29 14:22:27 +0100995 enum cfg80211_chan_mode *chanmode,
996 u8 *radar_detect)
Michal Kazior26ab9a02012-06-29 12:47:00 +0200997{
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200998 int ret;
999
Michal Kazior26ab9a02012-06-29 12:47:00 +02001000 *chan = NULL;
1001 *chanmode = CHAN_MODE_UNDEFINED;
1002
Michal Kazior26ab9a02012-06-29 12:47:00 +02001003 ASSERT_WDEV_LOCK(wdev);
1004
Johannes Berg98104fde2012-06-16 00:19:54 +02001005 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +02001006 return;
1007
1008 switch (wdev->iftype) {
1009 case NL80211_IFTYPE_ADHOC:
1010 if (wdev->current_bss) {
1011 *chan = wdev->current_bss->pub.channel;
Simon Wunderlich5336fa82013-10-07 18:41:05 +02001012 *chanmode = (wdev->ibss_fixed &&
1013 !wdev->ibss_dfs_possible)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001014 ? CHAN_MODE_SHARED
1015 : CHAN_MODE_EXCLUSIVE;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001016
1017 /* consider worst-case - IBSS can try to return to the
1018 * original user-specified channel as creator */
1019 if (wdev->ibss_dfs_possible)
1020 *radar_detect |= BIT(wdev->chandef.width);
Michal Kazior26ab9a02012-06-29 12:47:00 +02001021 return;
1022 }
Johannes Berg0f0094b2013-10-25 12:46:44 +02001023 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001024 case NL80211_IFTYPE_STATION:
1025 case NL80211_IFTYPE_P2P_CLIENT:
1026 if (wdev->current_bss) {
1027 *chan = wdev->current_bss->pub.channel;
1028 *chanmode = CHAN_MODE_SHARED;
1029 return;
1030 }
1031 break;
1032 case NL80211_IFTYPE_AP:
1033 case NL80211_IFTYPE_P2P_GO:
Simon Wunderlich04f39042013-02-08 18:16:19 +01001034 if (wdev->cac_started) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001035 *chan = wdev->chandef.chan;
Simon Wunderlich04f39042013-02-08 18:16:19 +01001036 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001037 *radar_detect |= BIT(wdev->chandef.width);
Simon Wunderlich04f39042013-02-08 18:16:19 +01001038 } else if (wdev->beacon_interval) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001039 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001040 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001041
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001042 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1043 &wdev->chandef,
1044 wdev->iftype);
1045 WARN_ON(ret < 0);
1046 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001047 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001048 }
1049 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001050 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +02001051 if (wdev->mesh_id_len) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001052 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001053 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001054
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001055 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1056 &wdev->chandef,
1057 wdev->iftype);
1058 WARN_ON(ret < 0);
1059 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001060 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001061 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001062 return;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001063 case NL80211_IFTYPE_OCB:
1064 if (wdev->chandef.chan) {
1065 *chan = wdev->chandef.chan;
1066 *chanmode = CHAN_MODE_SHARED;
1067 return;
1068 }
1069 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001070 case NL80211_IFTYPE_MONITOR:
1071 case NL80211_IFTYPE_AP_VLAN:
1072 case NL80211_IFTYPE_WDS:
Johannes Berg98104fde2012-06-16 00:19:54 +02001073 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001074 case NL80211_IFTYPE_NAN:
Johannes Berge7aceef2014-02-12 14:21:15 +01001075 /* these interface types don't really have a channel */
Johannes Berg98104fde2012-06-16 00:19:54 +02001076 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001077 case NL80211_IFTYPE_UNSPECIFIED:
1078 case NUM_NL80211_IFTYPES:
1079 WARN_ON(1);
1080 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001081}