blob: 90f0f82cd9ca76722e529573b4fa0ff9da2055ff [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
Johannes Bergba8f6a02020-05-28 21:34:40 +02009 * Copyright 2018-2020 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
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030017static bool cfg80211_valid_60g_freq(u32 freq)
18{
19 return freq >= 58320 && freq <= 70200;
20}
21
Johannes Berg3d9d1d62012-11-08 23:14:50 +010022void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
23 struct ieee80211_channel *chan,
24 enum nl80211_channel_type chan_type)
25{
26 if (WARN_ON(!chan))
27 return;
28
29 chandef->chan = chan;
Thomas Pedersen934f4c72020-04-01 18:18:03 -070030 chandef->freq1_offset = chan->freq_offset;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010031 chandef->center_freq2 = 0;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030032 chandef->edmg.bw_config = 0;
33 chandef->edmg.channels = 0;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010034
35 switch (chan_type) {
36 case NL80211_CHAN_NO_HT:
37 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
38 chandef->center_freq1 = chan->center_freq;
39 break;
40 case NL80211_CHAN_HT20:
41 chandef->width = NL80211_CHAN_WIDTH_20;
42 chandef->center_freq1 = chan->center_freq;
43 break;
44 case NL80211_CHAN_HT40PLUS:
45 chandef->width = NL80211_CHAN_WIDTH_40;
46 chandef->center_freq1 = chan->center_freq + 10;
47 break;
48 case NL80211_CHAN_HT40MINUS:
49 chandef->width = NL80211_CHAN_WIDTH_40;
50 chandef->center_freq1 = chan->center_freq - 10;
51 break;
52 default:
53 WARN_ON(1);
54 }
55}
56EXPORT_SYMBOL(cfg80211_chandef_create);
57
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030058static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
59{
60 int max_contiguous = 0;
61 int num_of_enabled = 0;
62 int contiguous = 0;
63 int i;
64
65 if (!chandef->edmg.channels || !chandef->edmg.bw_config)
66 return false;
67
68 if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
69 return false;
70
71 for (i = 0; i < 6; i++) {
72 if (chandef->edmg.channels & BIT(i)) {
73 contiguous++;
74 num_of_enabled++;
75 } else {
76 contiguous = 0;
77 }
78
79 max_contiguous = max(contiguous, max_contiguous);
80 }
81 /* basic verification of edmg configuration according to
82 * IEEE P802.11ay/D4.0 section 9.4.2.251
83 */
84 /* check bw_config against contiguous edmg channels */
85 switch (chandef->edmg.bw_config) {
86 case IEEE80211_EDMG_BW_CONFIG_4:
87 case IEEE80211_EDMG_BW_CONFIG_8:
88 case IEEE80211_EDMG_BW_CONFIG_12:
89 if (max_contiguous < 1)
90 return false;
91 break;
92 case IEEE80211_EDMG_BW_CONFIG_5:
93 case IEEE80211_EDMG_BW_CONFIG_9:
94 case IEEE80211_EDMG_BW_CONFIG_13:
95 if (max_contiguous < 2)
96 return false;
97 break;
98 case IEEE80211_EDMG_BW_CONFIG_6:
99 case IEEE80211_EDMG_BW_CONFIG_10:
100 case IEEE80211_EDMG_BW_CONFIG_14:
101 if (max_contiguous < 3)
102 return false;
103 break;
104 case IEEE80211_EDMG_BW_CONFIG_7:
105 case IEEE80211_EDMG_BW_CONFIG_11:
106 case IEEE80211_EDMG_BW_CONFIG_15:
107 if (max_contiguous < 4)
108 return false;
109 break;
110
111 default:
112 return false;
113 }
114
115 /* check bw_config against aggregated (non contiguous) edmg channels */
116 switch (chandef->edmg.bw_config) {
117 case IEEE80211_EDMG_BW_CONFIG_4:
118 case IEEE80211_EDMG_BW_CONFIG_5:
119 case IEEE80211_EDMG_BW_CONFIG_6:
120 case IEEE80211_EDMG_BW_CONFIG_7:
121 break;
122 case IEEE80211_EDMG_BW_CONFIG_8:
123 case IEEE80211_EDMG_BW_CONFIG_9:
124 case IEEE80211_EDMG_BW_CONFIG_10:
125 case IEEE80211_EDMG_BW_CONFIG_11:
126 if (num_of_enabled < 2)
127 return false;
128 break;
129 case IEEE80211_EDMG_BW_CONFIG_12:
130 case IEEE80211_EDMG_BW_CONFIG_13:
131 case IEEE80211_EDMG_BW_CONFIG_14:
132 case IEEE80211_EDMG_BW_CONFIG_15:
133 if (num_of_enabled < 4 || max_contiguous < 2)
134 return false;
135 break;
136 default:
137 return false;
138 }
139
140 return true;
141}
142
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100143bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100144{
145 u32 control_freq;
146
147 if (!chandef->chan)
148 return false;
149
Johannes Bergbe689f62020-04-24 12:01:04 +0200150 if (chandef->freq1_offset >= 1000)
151 return false;
152
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100153 control_freq = chandef->chan->center_freq;
154
155 switch (chandef->width) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700156 case NL80211_CHAN_WIDTH_1:
157 case NL80211_CHAN_WIDTH_2:
158 case NL80211_CHAN_WIDTH_4:
159 case NL80211_CHAN_WIDTH_8:
160 case NL80211_CHAN_WIDTH_16:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200161 case NL80211_CHAN_WIDTH_5:
162 case NL80211_CHAN_WIDTH_10:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100163 case NL80211_CHAN_WIDTH_20:
164 case NL80211_CHAN_WIDTH_20_NOHT:
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700165 if (ieee80211_chandef_to_khz(chandef) !=
166 ieee80211_channel_to_khz(chandef->chan))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100167 return false;
168 if (chandef->center_freq2)
169 return false;
170 break;
171 case NL80211_CHAN_WIDTH_40:
172 if (chandef->center_freq1 != control_freq + 10 &&
173 chandef->center_freq1 != control_freq - 10)
174 return false;
175 if (chandef->center_freq2)
176 return false;
177 break;
178 case NL80211_CHAN_WIDTH_80P80:
179 if (chandef->center_freq1 != control_freq + 30 &&
180 chandef->center_freq1 != control_freq + 10 &&
181 chandef->center_freq1 != control_freq - 10 &&
182 chandef->center_freq1 != control_freq - 30)
183 return false;
184 if (!chandef->center_freq2)
185 return false;
Johannes Berg9cab3152012-12-14 00:19:08 +0100186 /* adjacent is not allowed -- that's a 160 MHz channel */
187 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
188 chandef->center_freq2 - chandef->center_freq1 == 80)
189 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100190 break;
191 case NL80211_CHAN_WIDTH_80:
192 if (chandef->center_freq1 != control_freq + 30 &&
193 chandef->center_freq1 != control_freq + 10 &&
194 chandef->center_freq1 != control_freq - 10 &&
195 chandef->center_freq1 != control_freq - 30)
196 return false;
197 if (chandef->center_freq2)
198 return false;
199 break;
200 case NL80211_CHAN_WIDTH_160:
201 if (chandef->center_freq1 != control_freq + 70 &&
202 chandef->center_freq1 != control_freq + 50 &&
203 chandef->center_freq1 != control_freq + 30 &&
204 chandef->center_freq1 != control_freq + 10 &&
205 chandef->center_freq1 != control_freq - 10 &&
206 chandef->center_freq1 != control_freq - 30 &&
207 chandef->center_freq1 != control_freq - 50 &&
208 chandef->center_freq1 != control_freq - 70)
209 return false;
210 if (chandef->center_freq2)
211 return false;
212 break;
213 default:
214 return false;
215 }
216
Masashi Honmaec649fe2019-10-21 16:50:45 +0900217 /* channel 14 is only for IEEE 802.11b */
218 if (chandef->center_freq1 == 2484 &&
219 chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
220 return false;
221
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300222 if (cfg80211_chandef_is_edmg(chandef) &&
223 !cfg80211_edmg_chandef_valid(chandef))
224 return false;
225
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100226 return true;
227}
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100228EXPORT_SYMBOL(cfg80211_chandef_valid);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100229
230static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
Johannes Bergfc1f48f2014-10-29 17:05:39 +0100231 u32 *pri40, u32 *pri80)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100232{
233 int tmp;
234
235 switch (c->width) {
236 case NL80211_CHAN_WIDTH_40:
237 *pri40 = c->center_freq1;
238 *pri80 = 0;
239 break;
240 case NL80211_CHAN_WIDTH_80:
241 case NL80211_CHAN_WIDTH_80P80:
242 *pri80 = c->center_freq1;
243 /* n_P20 */
244 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
245 /* n_P40 */
246 tmp /= 2;
247 /* freq_P40 */
248 *pri40 = c->center_freq1 - 20 + 40 * tmp;
249 break;
250 case NL80211_CHAN_WIDTH_160:
251 /* n_P20 */
252 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
253 /* n_P40 */
254 tmp /= 2;
255 /* freq_P40 */
256 *pri40 = c->center_freq1 - 60 + 40 * tmp;
257 /* n_P80 */
258 tmp /= 2;
259 *pri80 = c->center_freq1 - 40 + 80 * tmp;
260 break;
261 default:
262 WARN_ON_ONCE(1);
263 }
264}
265
Simon Wunderlich04f39042013-02-08 18:16:19 +0100266static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
267{
268 int width;
269
270 switch (c->width) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700271 case NL80211_CHAN_WIDTH_1:
272 width = 1;
273 break;
274 case NL80211_CHAN_WIDTH_2:
275 width = 2;
276 break;
277 case NL80211_CHAN_WIDTH_4:
278 width = 4;
279 break;
280 case NL80211_CHAN_WIDTH_8:
281 width = 8;
282 break;
283 case NL80211_CHAN_WIDTH_16:
284 width = 16;
285 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200286 case NL80211_CHAN_WIDTH_5:
287 width = 5;
288 break;
289 case NL80211_CHAN_WIDTH_10:
290 width = 10;
291 break;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100292 case NL80211_CHAN_WIDTH_20:
293 case NL80211_CHAN_WIDTH_20_NOHT:
294 width = 20;
295 break;
296 case NL80211_CHAN_WIDTH_40:
297 width = 40;
298 break;
299 case NL80211_CHAN_WIDTH_80P80:
300 case NL80211_CHAN_WIDTH_80:
301 width = 80;
302 break;
303 case NL80211_CHAN_WIDTH_160:
304 width = 160;
305 break;
306 default:
307 WARN_ON_ONCE(1);
308 return -1;
309 }
310 return width;
311}
312
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100313const struct cfg80211_chan_def *
314cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
315 const struct cfg80211_chan_def *c2)
316{
317 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
318
319 /* If they are identical, return */
320 if (cfg80211_chandef_identical(c1, c2))
321 return c1;
322
323 /* otherwise, must have same control channel */
324 if (c1->chan != c2->chan)
325 return NULL;
326
327 /*
328 * If they have the same width, but aren't identical,
329 * then they can't be compatible.
330 */
331 if (c1->width == c2->width)
332 return NULL;
333
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200334 /*
335 * can't be compatible if one of them is 5 or 10 MHz,
336 * but they don't have the same width.
337 */
338 if (c1->width == NL80211_CHAN_WIDTH_5 ||
339 c1->width == NL80211_CHAN_WIDTH_10 ||
340 c2->width == NL80211_CHAN_WIDTH_5 ||
341 c2->width == NL80211_CHAN_WIDTH_10)
342 return NULL;
343
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100344 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
345 c1->width == NL80211_CHAN_WIDTH_20)
346 return c2;
347
348 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
349 c2->width == NL80211_CHAN_WIDTH_20)
350 return c1;
351
352 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
353 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
354
355 if (c1_pri40 != c2_pri40)
356 return NULL;
357
358 WARN_ON(!c1_pri80 && !c2_pri80);
359 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
360 return NULL;
361
362 if (c1->width > c2->width)
363 return c1;
364 return c2;
365}
366EXPORT_SYMBOL(cfg80211_chandef_compatible);
367
Simon Wunderlich04f39042013-02-08 18:16:19 +0100368static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
369 u32 bandwidth,
370 enum nl80211_dfs_state dfs_state)
371{
372 struct ieee80211_channel *c;
373 u32 freq;
374
375 for (freq = center_freq - bandwidth/2 + 10;
376 freq <= center_freq + bandwidth/2 - 10;
377 freq += 20) {
378 c = ieee80211_get_channel(wiphy, freq);
379 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
380 continue;
381
382 c->dfs_state = dfs_state;
383 c->dfs_state_entered = jiffies;
384 }
385}
386
387void cfg80211_set_dfs_state(struct wiphy *wiphy,
388 const struct cfg80211_chan_def *chandef,
389 enum nl80211_dfs_state dfs_state)
390{
391 int width;
392
393 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
394 return;
395
396 width = cfg80211_chandef_get_width(chandef);
397 if (width < 0)
398 return;
399
400 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
401 width, dfs_state);
402
403 if (!chandef->center_freq2)
404 return;
405 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
406 width, dfs_state);
407}
408
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100409static u32 cfg80211_get_start_freq(u32 center_freq,
410 u32 bandwidth)
411{
412 u32 start_freq;
413
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700414 bandwidth = MHZ_TO_KHZ(bandwidth);
415 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100416 start_freq = center_freq;
417 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700418 start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100419
420 return start_freq;
421}
422
423static u32 cfg80211_get_end_freq(u32 center_freq,
424 u32 bandwidth)
425{
426 u32 end_freq;
427
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700428 bandwidth = MHZ_TO_KHZ(bandwidth);
429 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100430 end_freq = center_freq;
431 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700432 end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100433
434 return end_freq;
435}
436
Simon Wunderlich04f39042013-02-08 18:16:19 +0100437static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
438 u32 center_freq,
439 u32 bandwidth)
440{
441 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200442 u32 freq, start_freq, end_freq;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100443
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100444 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
445 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200446
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700447 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
448 c = ieee80211_get_channel_khz(wiphy, freq);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100449 if (!c)
450 return -EINVAL;
451
452 if (c->flags & IEEE80211_CHAN_RADAR)
453 return 1;
454 }
455 return 0;
456}
457
458
459int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200460 const struct cfg80211_chan_def *chandef,
461 enum nl80211_iftype iftype)
Simon Wunderlich04f39042013-02-08 18:16:19 +0100462{
463 int width;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200464 int ret;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100465
466 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
467 return -EINVAL;
468
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200469 switch (iftype) {
470 case NL80211_IFTYPE_ADHOC:
471 case NL80211_IFTYPE_AP:
472 case NL80211_IFTYPE_P2P_GO:
473 case NL80211_IFTYPE_MESH_POINT:
474 width = cfg80211_chandef_get_width(chandef);
475 if (width < 0)
476 return -EINVAL;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100477
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200478 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700479 ieee80211_chandef_to_khz(chandef),
480 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200481 if (ret < 0)
482 return ret;
483 else if (ret > 0)
484 return BIT(chandef->width);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100485
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200486 if (!chandef->center_freq2)
487 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100488
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200489 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700490 MHZ_TO_KHZ(chandef->center_freq2),
491 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200492 if (ret < 0)
493 return ret;
494 else if (ret > 0)
495 return BIT(chandef->width);
496
497 break;
498 case NL80211_IFTYPE_STATION:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100499 case NL80211_IFTYPE_OCB:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200500 case NL80211_IFTYPE_P2P_CLIENT:
501 case NL80211_IFTYPE_MONITOR:
502 case NL80211_IFTYPE_AP_VLAN:
503 case NL80211_IFTYPE_WDS:
504 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300505 case NL80211_IFTYPE_NAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200506 break;
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300507 case NL80211_IFTYPE_UNSPECIFIED:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200508 case NUM_NL80211_IFTYPES:
509 WARN_ON(1);
510 }
511
512 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100513}
Simon Wunderlich774f0732013-08-28 13:41:28 +0200514EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100515
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100516static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
517 u32 center_freq,
518 u32 bandwidth)
519{
520 struct ieee80211_channel *c;
521 u32 freq, start_freq, end_freq;
522 int count = 0;
523
524 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
525 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
526
527 /*
528 * Check entire range of channels for the bandwidth.
529 * Check all channels are DFS channels (DFS_USABLE or
530 * DFS_AVAILABLE). Return number of usable channels
531 * (require CAC). Allow DFS and non-DFS channel mix.
532 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700533 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
534 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100535 if (!c)
536 return -EINVAL;
537
538 if (c->flags & IEEE80211_CHAN_DISABLED)
539 return -EINVAL;
540
541 if (c->flags & IEEE80211_CHAN_RADAR) {
542 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
543 return -EINVAL;
544
545 if (c->dfs_state == NL80211_DFS_USABLE)
546 count++;
547 }
548 }
549
550 return count;
551}
552
553bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
554 const struct cfg80211_chan_def *chandef)
555{
556 int width;
557 int r1, r2 = 0;
558
559 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
560 return false;
561
562 width = cfg80211_chandef_get_width(chandef);
563 if (width < 0)
564 return false;
565
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700566 r1 = cfg80211_get_chans_dfs_usable(wiphy,
567 MHZ_TO_KHZ(chandef->center_freq1),
568 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100569
570 if (r1 < 0)
571 return false;
572
573 switch (chandef->width) {
574 case NL80211_CHAN_WIDTH_80P80:
575 WARN_ON(!chandef->center_freq2);
576 r2 = cfg80211_get_chans_dfs_usable(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700577 MHZ_TO_KHZ(chandef->center_freq2),
578 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100579 if (r2 < 0)
580 return false;
581 break;
582 default:
583 WARN_ON(chandef->center_freq2);
584 break;
585 }
586
587 return (r1 + r2 > 0);
588}
589
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530590/*
591 * Checks if center frequency of chan falls with in the bandwidth
592 * range of chandef.
593 */
594bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
595 struct ieee80211_channel *chan)
596{
597 int width;
Johannes Berga67a4892017-10-12 11:23:04 +0200598 u32 freq;
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530599
600 if (chandef->chan->center_freq == chan->center_freq)
601 return true;
602
603 width = cfg80211_chandef_get_width(chandef);
604 if (width <= 20)
605 return false;
606
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530607 for (freq = chandef->center_freq1 - width / 2 + 10;
608 freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
609 if (chan->center_freq == freq)
610 return true;
611 }
612
613 if (!chandef->center_freq2)
614 return false;
615
616 for (freq = chandef->center_freq2 - width / 2 + 10;
617 freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
618 if (chan->center_freq == freq)
619 return true;
620 }
621
622 return false;
623}
624
625bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
626{
627 bool active = false;
628
629 ASSERT_WDEV_LOCK(wdev);
630
631 if (!wdev->chandef.chan)
632 return false;
633
634 switch (wdev->iftype) {
635 case NL80211_IFTYPE_AP:
636 case NL80211_IFTYPE_P2P_GO:
637 active = wdev->beacon_interval != 0;
638 break;
639 case NL80211_IFTYPE_ADHOC:
640 active = wdev->ssid_len != 0;
641 break;
642 case NL80211_IFTYPE_MESH_POINT:
643 active = wdev->mesh_id_len != 0;
644 break;
645 case NL80211_IFTYPE_STATION:
646 case NL80211_IFTYPE_OCB:
647 case NL80211_IFTYPE_P2P_CLIENT:
648 case NL80211_IFTYPE_MONITOR:
649 case NL80211_IFTYPE_AP_VLAN:
650 case NL80211_IFTYPE_WDS:
651 case NL80211_IFTYPE_P2P_DEVICE:
652 /* Can NAN type be considered as beaconing interface? */
653 case NL80211_IFTYPE_NAN:
654 break;
655 case NL80211_IFTYPE_UNSPECIFIED:
656 case NUM_NL80211_IFTYPES:
657 WARN_ON(1);
658 }
659
660 return active;
661}
662
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530663static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
664 struct ieee80211_channel *chan)
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530665{
666 struct wireless_dev *wdev;
667
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530668 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
669 wdev_lock(wdev);
670 if (!cfg80211_beaconing_iface_active(wdev)) {
671 wdev_unlock(wdev);
672 continue;
673 }
674
675 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
676 wdev_unlock(wdev);
677 return true;
678 }
679 wdev_unlock(wdev);
680 }
681
682 return false;
683}
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100684
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530685bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
686 struct ieee80211_channel *chan)
687{
688 struct cfg80211_registered_device *rdev;
689
690 ASSERT_RTNL();
691
692 if (!(chan->flags & IEEE80211_CHAN_RADAR))
693 return false;
694
695 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
696 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
697 continue;
698
699 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
700 return true;
701 }
702
703 return false;
704}
705
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100706static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
707 u32 center_freq,
708 u32 bandwidth)
709{
710 struct ieee80211_channel *c;
711 u32 freq, start_freq, end_freq;
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300712 bool dfs_offload;
713
714 dfs_offload = wiphy_ext_feature_isset(wiphy,
715 NL80211_EXT_FEATURE_DFS_OFFLOAD);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100716
717 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
718 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
719
720 /*
721 * Check entire range of channels for the bandwidth.
722 * If any channel in between is disabled or has not
723 * had gone through CAC return false
724 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700725 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
726 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100727 if (!c)
728 return false;
729
730 if (c->flags & IEEE80211_CHAN_DISABLED)
731 return false;
732
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300733 if ((c->flags & IEEE80211_CHAN_RADAR) &&
734 (c->dfs_state != NL80211_DFS_AVAILABLE) &&
735 !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100736 return false;
737 }
738
739 return true;
740}
741
742static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
743 const struct cfg80211_chan_def *chandef)
744{
745 int width;
746 int r;
747
748 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
749 return false;
750
751 width = cfg80211_chandef_get_width(chandef);
752 if (width < 0)
753 return false;
754
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700755 r = cfg80211_get_chans_dfs_available(wiphy,
756 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100757 width);
758
759 /* If any of channels unavailable for cf1 just return */
760 if (!r)
761 return r;
762
763 switch (chandef->width) {
764 case NL80211_CHAN_WIDTH_80P80:
765 WARN_ON(!chandef->center_freq2);
766 r = cfg80211_get_chans_dfs_available(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700767 MHZ_TO_KHZ(chandef->center_freq2),
768 width);
Colin Ian King680682d2016-07-17 19:55:27 +0100769 break;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100770 default:
771 WARN_ON(chandef->center_freq2);
772 break;
773 }
774
775 return r;
776}
777
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100778static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
779 u32 center_freq,
780 u32 bandwidth)
781{
782 struct ieee80211_channel *c;
783 u32 start_freq, end_freq, freq;
784 unsigned int dfs_cac_ms = 0;
785
786 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
787 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
788
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700789 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
790 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100791 if (!c)
792 return 0;
793
794 if (c->flags & IEEE80211_CHAN_DISABLED)
795 return 0;
796
797 if (!(c->flags & IEEE80211_CHAN_RADAR))
798 continue;
799
800 if (c->dfs_cac_ms > dfs_cac_ms)
801 dfs_cac_ms = c->dfs_cac_ms;
802 }
803
804 return dfs_cac_ms;
805}
806
807unsigned int
808cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
809 const struct cfg80211_chan_def *chandef)
810{
811 int width;
812 unsigned int t1 = 0, t2 = 0;
813
814 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
815 return 0;
816
817 width = cfg80211_chandef_get_width(chandef);
818 if (width < 0)
819 return 0;
820
821 t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700822 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100823 width);
824
825 if (!chandef->center_freq2)
826 return t1;
827
828 t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700829 MHZ_TO_KHZ(chandef->center_freq2),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100830 width);
831
832 return max(t1, t2);
833}
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100834
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100835static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
836 u32 center_freq, u32 bandwidth,
837 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100838{
839 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200840 u32 freq, start_freq, end_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100841
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100842 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
843 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200844
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700845 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
846 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100847 if (!c || c->flags & prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100848 return false;
849 }
850
851 return true;
852}
853
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300854/* check if the operating channels are valid and supported */
855static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
856 enum ieee80211_edmg_bw_config edmg_bw_config,
857 int primary_channel,
858 struct ieee80211_edmg *edmg_cap)
859{
860 struct ieee80211_channel *chan;
861 int i, freq;
862 int channels_counter = 0;
863
864 if (!edmg_channels && !edmg_bw_config)
865 return true;
866
867 if ((!edmg_channels && edmg_bw_config) ||
868 (edmg_channels && !edmg_bw_config))
869 return false;
870
871 if (!(edmg_channels & BIT(primary_channel - 1)))
872 return false;
873
874 /* 60GHz channels 1..6 */
875 for (i = 0; i < 6; i++) {
876 if (!(edmg_channels & BIT(i)))
877 continue;
878
879 if (!(edmg_cap->channels & BIT(i)))
880 return false;
881
882 channels_counter++;
883
884 freq = ieee80211_channel_to_frequency(i + 1,
885 NL80211_BAND_60GHZ);
886 chan = ieee80211_get_channel(wiphy, freq);
887 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
888 return false;
889 }
890
891 /* IEEE802.11 allows max 4 channels */
892 if (channels_counter > 4)
893 return false;
894
895 /* check bw_config is a subset of what driver supports
896 * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
897 */
898 if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
899 return false;
900
901 if (edmg_bw_config > edmg_cap->bw_config)
902 return false;
903
904 return true;
905}
906
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100907bool cfg80211_chandef_usable(struct wiphy *wiphy,
908 const struct cfg80211_chan_def *chandef,
909 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100910{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100911 struct ieee80211_sta_ht_cap *ht_cap;
912 struct ieee80211_sta_vht_cap *vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300913 struct ieee80211_edmg *edmg_cap;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200914 u32 width, control_freq, cap;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100915
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100916 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100917 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100918
919 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
920 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300921 edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
922
923 if (edmg_cap->channels &&
924 !cfg80211_edmg_usable(wiphy,
925 chandef->edmg.channels,
926 chandef->edmg.bw_config,
927 chandef->chan->hw_value,
928 edmg_cap))
929 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100930
931 control_freq = chandef->chan->center_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100932
933 switch (chandef->width) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700934 case NL80211_CHAN_WIDTH_1:
935 width = 1;
936 break;
937 case NL80211_CHAN_WIDTH_2:
938 width = 2;
939 break;
940 case NL80211_CHAN_WIDTH_4:
941 width = 4;
942 break;
943 case NL80211_CHAN_WIDTH_8:
944 width = 8;
945 break;
946 case NL80211_CHAN_WIDTH_16:
947 width = 16;
948 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200949 case NL80211_CHAN_WIDTH_5:
950 width = 5;
951 break;
952 case NL80211_CHAN_WIDTH_10:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200953 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200954 width = 10;
955 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100956 case NL80211_CHAN_WIDTH_20:
Johannes Bergba8f6a02020-05-28 21:34:40 +0200957 if (!ht_cap->ht_supported &&
958 chandef->chan->band != NL80211_BAND_6GHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100959 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200960 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100961 case NL80211_CHAN_WIDTH_20_NOHT:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200962 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100963 width = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500964 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100965 case NL80211_CHAN_WIDTH_40:
966 width = 40;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200967 if (chandef->chan->band == NL80211_BAND_6GHZ)
968 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100969 if (!ht_cap->ht_supported)
970 return false;
971 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
972 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
973 return false;
974 if (chandef->center_freq1 < control_freq &&
975 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
976 return false;
977 if (chandef->center_freq1 > control_freq &&
978 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
979 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100980 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100981 case NL80211_CHAN_WIDTH_80P80:
Jouni Malinen08f6f142014-12-11 23:48:55 +0200982 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200983 if (chandef->chan->band != NL80211_BAND_6GHZ &&
984 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100985 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200986 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100987 case NL80211_CHAN_WIDTH_80:
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100988 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100989 width = 80;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200990 if (chandef->chan->band == NL80211_BAND_6GHZ)
991 break;
992 if (!vht_cap->vht_supported)
993 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100994 break;
995 case NL80211_CHAN_WIDTH_160:
Johannes Bergba8f6a02020-05-28 21:34:40 +0200996 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
997 width = 160;
998 if (chandef->chan->band == NL80211_BAND_6GHZ)
999 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001000 if (!vht_cap->vht_supported)
1001 return false;
Jouni Malinen08f6f142014-12-11 23:48:55 +02001002 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
1003 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
1004 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001005 return false;
Mark Mentovai09a02fd2010-11-17 16:34:37 -05001006 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001007 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001008 WARN_ON_ONCE(1);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001009 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +03001010 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001011
Johannes Bergc7a6ee22012-12-12 17:50:39 +01001012 /*
1013 * TODO: What if there are only certain 80/160/80+80 MHz channels
1014 * allowed by the driver, or only certain combinations?
1015 * For 40 MHz the driver can set the NO_HT40 flags, but for
1016 * 80/160 MHz and in particular 80+80 MHz this isn't really
1017 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
1018 * no way to cover 80+80 MHz or more complex restrictions.
1019 * Note that such restrictions also need to be advertised to
1020 * userspace, for example for P2P channel selection.
1021 */
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001022
Johannes Berga6662db2012-12-04 20:49:42 +01001023 if (width > 20)
1024 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1025
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02001026 /* 5 and 10 MHz are only defined for the OFDM PHY */
1027 if (width < 20)
1028 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1029
1030
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001031 if (!cfg80211_secondary_chans_ok(wiphy,
1032 ieee80211_chandef_to_khz(chandef),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001033 width, prohibited_flags))
1034 return false;
1035
1036 if (!chandef->center_freq2)
1037 return true;
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001038 return cfg80211_secondary_chans_ok(wiphy,
1039 MHZ_TO_KHZ(chandef->center_freq2),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001040 width, prohibited_flags);
1041}
1042EXPORT_SYMBOL(cfg80211_chandef_usable);
1043
Ilan Peer174e0cd2014-02-23 09:13:01 +02001044/*
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001045 * Check if the channel can be used under permissive conditions mandated by
1046 * some regulatory bodies, i.e., the channel is marked with
1047 * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
Ilan Peer174e0cd2014-02-23 09:13:01 +02001048 * associated to an AP on the same channel or on the same UNII band
1049 * (assuming that the AP is an authorized master).
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001050 * In addition allow operation on a channel on which indoor operation is
Ilan Peerc8866e52014-02-23 09:13:03 +02001051 * allowed, iff we are currently operating in an indoor environment.
Ilan Peer174e0cd2014-02-23 09:13:01 +02001052 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001053static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
1054 enum nl80211_iftype iftype,
Ilan Peer174e0cd2014-02-23 09:13:01 +02001055 struct ieee80211_channel *chan)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001056{
Avraham Sternbe69c242015-04-27 16:52:16 +03001057 struct wireless_dev *wdev;
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001058 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001059
1060 ASSERT_RTNL();
1061
Masahiro Yamada97f26452016-08-03 13:45:50 -07001062 if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
Ilan Peerc8866e52014-02-23 09:13:03 +02001063 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
1064 return false;
1065
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001066 /* only valid for GO and TDLS off-channel (station/p2p-CL) */
1067 if (iftype != NL80211_IFTYPE_P2P_GO &&
1068 iftype != NL80211_IFTYPE_STATION &&
1069 iftype != NL80211_IFTYPE_P2P_CLIENT)
1070 return false;
1071
Ilan Peerc8866e52014-02-23 09:13:03 +02001072 if (regulatory_indoor_allowed() &&
1073 (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1074 return true;
1075
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001076 if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
Ilan Peer174e0cd2014-02-23 09:13:01 +02001077 return false;
1078
1079 /*
1080 * Generally, it is possible to rely on another device/driver to allow
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001081 * the IR concurrent relaxation, however, since the device can further
Ilan Peer174e0cd2014-02-23 09:13:01 +02001082 * enforce the relaxation (by doing a similar verifications as this),
1083 * and thus fail the GO instantiation, consider only the interfaces of
1084 * the current registered device.
1085 */
Johannes Berg53873f12016-05-03 16:52:04 +03001086 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Ilan Peer174e0cd2014-02-23 09:13:01 +02001087 struct ieee80211_channel *other_chan = NULL;
1088 int r1, r2;
1089
Avraham Sternbe69c242015-04-27 16:52:16 +03001090 wdev_lock(wdev);
1091 if (wdev->iftype == NL80211_IFTYPE_STATION &&
1092 wdev->current_bss)
1093 other_chan = wdev->current_bss->pub.channel;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001094
Avraham Sternbe69c242015-04-27 16:52:16 +03001095 /*
1096 * If a GO already operates on the same GO_CONCURRENT channel,
1097 * this one (maybe the same one) can beacon as well. We allow
1098 * the operation even if the station we relied on with
1099 * GO_CONCURRENT is disconnected now. But then we must make sure
1100 * we're not outdoor on an indoor-only channel.
1101 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001102 if (iftype == NL80211_IFTYPE_P2P_GO &&
1103 wdev->iftype == NL80211_IFTYPE_P2P_GO &&
Avraham Sternbe69c242015-04-27 16:52:16 +03001104 wdev->beacon_interval &&
1105 !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1106 other_chan = wdev->chandef.chan;
1107 wdev_unlock(wdev);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001108
1109 if (!other_chan)
1110 continue;
1111
1112 if (chan == other_chan)
1113 return true;
1114
Arend van Spriel0816e6b2019-08-02 13:31:03 +02001115 if (chan->band != NL80211_BAND_5GHZ &&
1116 chan->band != NL80211_BAND_6GHZ)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001117 continue;
1118
1119 r1 = cfg80211_get_unii(chan->center_freq);
1120 r2 = cfg80211_get_unii(other_chan->center_freq);
1121
Ilan Peer46d53722014-04-23 09:22:58 +03001122 if (r1 != -EINVAL && r1 == r2) {
1123 /*
1124 * At some locations channels 149-165 are considered a
1125 * bundle, but at other locations, e.g., Indonesia,
1126 * channels 149-161 are considered a bundle while
1127 * channel 165 is left out and considered to be in a
1128 * different bundle. Thus, in case that there is a
1129 * station interface connected to an AP on channel 165,
1130 * it is assumed that channels 149-161 are allowed for
1131 * GO operations. However, having a station interface
1132 * connected to an AP on channels 149-161, does not
1133 * allow GO operation on channel 165.
1134 */
1135 if (chan->center_freq == 5825 &&
1136 other_chan->center_freq != 5825)
1137 continue;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001138 return true;
Ilan Peer46d53722014-04-23 09:22:58 +03001139 }
Ilan Peer174e0cd2014-02-23 09:13:01 +02001140 }
1141
1142 return false;
1143}
1144
Arik Nemtsov923b3522015-07-08 15:41:44 +03001145static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
1146 struct cfg80211_chan_def *chandef,
1147 enum nl80211_iftype iftype,
1148 bool check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001149{
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001150 bool res;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001151 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001152 IEEE80211_CHAN_RADAR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001153
Arik Nemtsov923b3522015-07-08 15:41:44 +03001154 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001155
Arik Nemtsov923b3522015-07-08 15:41:44 +03001156 if (check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001157 prohibited_flags |= IEEE80211_CHAN_NO_IR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001158
Luciano Coelho00ec75f2014-05-15 13:05:39 +03001159 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001160 cfg80211_chandef_dfs_available(wiphy, chandef)) {
1161 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
1162 prohibited_flags = IEEE80211_CHAN_DISABLED;
1163 }
1164
1165 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001166
1167 trace_cfg80211_return_bool(res);
1168 return res;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001169}
Arik Nemtsov923b3522015-07-08 15:41:44 +03001170
1171bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
1172 struct cfg80211_chan_def *chandef,
1173 enum nl80211_iftype iftype)
1174{
1175 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
1176}
Johannes Berg683b6d32012-11-08 21:25:48 +01001177EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001178
Arik Nemtsov923b3522015-07-08 15:41:44 +03001179bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
1180 struct cfg80211_chan_def *chandef,
1181 enum nl80211_iftype iftype)
1182{
1183 bool check_no_ir;
1184
1185 ASSERT_RTNL();
1186
1187 /*
1188 * Under certain conditions suggested by some regulatory bodies a
1189 * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
1190 * only if such relaxations are not enabled and the conditions are not
1191 * met.
1192 */
1193 check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
1194 chandef->chan);
1195
1196 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1197}
1198EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
1199
Johannes Berge8c9bd52012-06-06 08:18:22 +02001200int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +01001201 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001202{
Johannes Berge8c9bd52012-06-06 08:18:22 +02001203 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001204 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +02001205 if (!cfg80211_has_monitors_only(rdev))
1206 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001207
Johannes Berg683b6d32012-11-08 21:25:48 +01001208 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001209}
Michal Kazior26ab9a02012-06-29 12:47:00 +02001210
1211void
Johannes Berg8e95ea42012-07-10 19:39:02 +02001212cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +02001213 struct ieee80211_channel **chan,
Michal Kazior9e0e2962014-01-29 14:22:27 +01001214 enum cfg80211_chan_mode *chanmode,
1215 u8 *radar_detect)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001216{
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001217 int ret;
1218
Michal Kazior26ab9a02012-06-29 12:47:00 +02001219 *chan = NULL;
1220 *chanmode = CHAN_MODE_UNDEFINED;
1221
Michal Kazior26ab9a02012-06-29 12:47:00 +02001222 ASSERT_WDEV_LOCK(wdev);
1223
Johannes Berg98104fde2012-06-16 00:19:54 +02001224 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +02001225 return;
1226
1227 switch (wdev->iftype) {
1228 case NL80211_IFTYPE_ADHOC:
1229 if (wdev->current_bss) {
1230 *chan = wdev->current_bss->pub.channel;
Simon Wunderlich5336fa82013-10-07 18:41:05 +02001231 *chanmode = (wdev->ibss_fixed &&
1232 !wdev->ibss_dfs_possible)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001233 ? CHAN_MODE_SHARED
1234 : CHAN_MODE_EXCLUSIVE;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001235
1236 /* consider worst-case - IBSS can try to return to the
1237 * original user-specified channel as creator */
1238 if (wdev->ibss_dfs_possible)
1239 *radar_detect |= BIT(wdev->chandef.width);
Michal Kazior26ab9a02012-06-29 12:47:00 +02001240 return;
1241 }
Johannes Berg0f0094b2013-10-25 12:46:44 +02001242 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001243 case NL80211_IFTYPE_STATION:
1244 case NL80211_IFTYPE_P2P_CLIENT:
1245 if (wdev->current_bss) {
1246 *chan = wdev->current_bss->pub.channel;
1247 *chanmode = CHAN_MODE_SHARED;
1248 return;
1249 }
1250 break;
1251 case NL80211_IFTYPE_AP:
1252 case NL80211_IFTYPE_P2P_GO:
Simon Wunderlich04f39042013-02-08 18:16:19 +01001253 if (wdev->cac_started) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001254 *chan = wdev->chandef.chan;
Simon Wunderlich04f39042013-02-08 18:16:19 +01001255 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001256 *radar_detect |= BIT(wdev->chandef.width);
Simon Wunderlich04f39042013-02-08 18:16:19 +01001257 } else if (wdev->beacon_interval) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001258 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001259 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001260
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001261 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1262 &wdev->chandef,
1263 wdev->iftype);
1264 WARN_ON(ret < 0);
1265 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001266 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001267 }
1268 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001269 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +02001270 if (wdev->mesh_id_len) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001271 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001272 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001273
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001274 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1275 &wdev->chandef,
1276 wdev->iftype);
1277 WARN_ON(ret < 0);
1278 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001279 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001280 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001281 return;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001282 case NL80211_IFTYPE_OCB:
1283 if (wdev->chandef.chan) {
1284 *chan = wdev->chandef.chan;
1285 *chanmode = CHAN_MODE_SHARED;
1286 return;
1287 }
1288 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001289 case NL80211_IFTYPE_MONITOR:
1290 case NL80211_IFTYPE_AP_VLAN:
1291 case NL80211_IFTYPE_WDS:
Johannes Berg98104fde2012-06-16 00:19:54 +02001292 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001293 case NL80211_IFTYPE_NAN:
Johannes Berge7aceef2014-02-12 14:21:15 +01001294 /* these interface types don't really have a channel */
Johannes Berg98104fde2012-06-16 00:19:54 +02001295 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001296 case NL80211_IFTYPE_UNSPECIFIED:
1297 case NUM_NL80211_IFTYPES:
1298 WARN_ON(1);
1299 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001300}