blob: eb822052d344f644ca5c41d1b5443a5c7f4d7f36 [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 Bergbe989892021-06-18 13:41:39 +03009 * Copyright 2018-2021 Intel Corporation
Johannes Berg59bbb6f2009-08-07 17:22:35 +020010 */
11
Alexander Simon54858ee5b2011-11-30 16:56:32 +010012#include <linux/export.h>
Shay Bar35799942020-08-26 17:31:39 +030013#include <linux/bitfield.h>
Johannes Berg59bbb6f2009-08-07 17:22:35 +020014#include <net/cfg80211.h>
15#include "core.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030016#include "rdev-ops.h"
Johannes Berg59bbb6f2009-08-07 17:22:35 +020017
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030018static bool cfg80211_valid_60g_freq(u32 freq)
19{
20 return freq >= 58320 && freq <= 70200;
21}
22
Johannes Berg3d9d1d62012-11-08 23:14:50 +010023void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
24 struct ieee80211_channel *chan,
25 enum nl80211_channel_type chan_type)
26{
27 if (WARN_ON(!chan))
28 return;
29
30 chandef->chan = chan;
Thomas Pedersen934f4c72020-04-01 18:18:03 -070031 chandef->freq1_offset = chan->freq_offset;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010032 chandef->center_freq2 = 0;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030033 chandef->edmg.bw_config = 0;
34 chandef->edmg.channels = 0;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010035
36 switch (chan_type) {
37 case NL80211_CHAN_NO_HT:
38 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
39 chandef->center_freq1 = chan->center_freq;
40 break;
41 case NL80211_CHAN_HT20:
42 chandef->width = NL80211_CHAN_WIDTH_20;
43 chandef->center_freq1 = chan->center_freq;
44 break;
45 case NL80211_CHAN_HT40PLUS:
46 chandef->width = NL80211_CHAN_WIDTH_40;
47 chandef->center_freq1 = chan->center_freq + 10;
48 break;
49 case NL80211_CHAN_HT40MINUS:
50 chandef->width = NL80211_CHAN_WIDTH_40;
51 chandef->center_freq1 = chan->center_freq - 10;
52 break;
53 default:
54 WARN_ON(1);
55 }
56}
57EXPORT_SYMBOL(cfg80211_chandef_create);
58
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030059static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
60{
61 int max_contiguous = 0;
62 int num_of_enabled = 0;
63 int contiguous = 0;
64 int i;
65
66 if (!chandef->edmg.channels || !chandef->edmg.bw_config)
67 return false;
68
69 if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
70 return false;
71
72 for (i = 0; i < 6; i++) {
73 if (chandef->edmg.channels & BIT(i)) {
74 contiguous++;
75 num_of_enabled++;
76 } else {
77 contiguous = 0;
78 }
79
80 max_contiguous = max(contiguous, max_contiguous);
81 }
82 /* basic verification of edmg configuration according to
83 * IEEE P802.11ay/D4.0 section 9.4.2.251
84 */
85 /* check bw_config against contiguous edmg channels */
86 switch (chandef->edmg.bw_config) {
87 case IEEE80211_EDMG_BW_CONFIG_4:
88 case IEEE80211_EDMG_BW_CONFIG_8:
89 case IEEE80211_EDMG_BW_CONFIG_12:
90 if (max_contiguous < 1)
91 return false;
92 break;
93 case IEEE80211_EDMG_BW_CONFIG_5:
94 case IEEE80211_EDMG_BW_CONFIG_9:
95 case IEEE80211_EDMG_BW_CONFIG_13:
96 if (max_contiguous < 2)
97 return false;
98 break;
99 case IEEE80211_EDMG_BW_CONFIG_6:
100 case IEEE80211_EDMG_BW_CONFIG_10:
101 case IEEE80211_EDMG_BW_CONFIG_14:
102 if (max_contiguous < 3)
103 return false;
104 break;
105 case IEEE80211_EDMG_BW_CONFIG_7:
106 case IEEE80211_EDMG_BW_CONFIG_11:
107 case IEEE80211_EDMG_BW_CONFIG_15:
108 if (max_contiguous < 4)
109 return false;
110 break;
111
112 default:
113 return false;
114 }
115
116 /* check bw_config against aggregated (non contiguous) edmg channels */
117 switch (chandef->edmg.bw_config) {
118 case IEEE80211_EDMG_BW_CONFIG_4:
119 case IEEE80211_EDMG_BW_CONFIG_5:
120 case IEEE80211_EDMG_BW_CONFIG_6:
121 case IEEE80211_EDMG_BW_CONFIG_7:
122 break;
123 case IEEE80211_EDMG_BW_CONFIG_8:
124 case IEEE80211_EDMG_BW_CONFIG_9:
125 case IEEE80211_EDMG_BW_CONFIG_10:
126 case IEEE80211_EDMG_BW_CONFIG_11:
127 if (num_of_enabled < 2)
128 return false;
129 break;
130 case IEEE80211_EDMG_BW_CONFIG_12:
131 case IEEE80211_EDMG_BW_CONFIG_13:
132 case IEEE80211_EDMG_BW_CONFIG_14:
133 case IEEE80211_EDMG_BW_CONFIG_15:
134 if (num_of_enabled < 4 || max_contiguous < 2)
135 return false;
136 break;
137 default:
138 return false;
139 }
140
141 return true;
142}
143
Thomas Pedersen11b34732020-09-08 12:03:06 -0700144static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
145{
146 int mhz;
147
148 switch (chan_width) {
149 case NL80211_CHAN_WIDTH_1:
150 mhz = 1;
151 break;
152 case NL80211_CHAN_WIDTH_2:
153 mhz = 2;
154 break;
155 case NL80211_CHAN_WIDTH_4:
156 mhz = 4;
157 break;
158 case NL80211_CHAN_WIDTH_8:
159 mhz = 8;
160 break;
161 case NL80211_CHAN_WIDTH_16:
162 mhz = 16;
163 break;
164 case NL80211_CHAN_WIDTH_5:
165 mhz = 5;
166 break;
167 case NL80211_CHAN_WIDTH_10:
168 mhz = 10;
169 break;
170 case NL80211_CHAN_WIDTH_20:
171 case NL80211_CHAN_WIDTH_20_NOHT:
172 mhz = 20;
173 break;
174 case NL80211_CHAN_WIDTH_40:
175 mhz = 40;
176 break;
177 case NL80211_CHAN_WIDTH_80P80:
178 case NL80211_CHAN_WIDTH_80:
179 mhz = 80;
180 break;
181 case NL80211_CHAN_WIDTH_160:
182 mhz = 160;
183 break;
184 default:
185 WARN_ON_ONCE(1);
186 return -1;
187 }
188 return mhz;
189}
190
191static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
192{
193 return nl80211_chan_width_to_mhz(c->width);
194}
195
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100196bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100197{
Thomas Pedersen11b34732020-09-08 12:03:06 -0700198 u32 control_freq, oper_freq;
199 int oper_width, control_width;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100200
201 if (!chandef->chan)
202 return false;
203
Johannes Bergbe689f62020-04-24 12:01:04 +0200204 if (chandef->freq1_offset >= 1000)
205 return false;
206
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100207 control_freq = chandef->chan->center_freq;
208
209 switch (chandef->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200210 case NL80211_CHAN_WIDTH_5:
211 case NL80211_CHAN_WIDTH_10:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100212 case NL80211_CHAN_WIDTH_20:
213 case NL80211_CHAN_WIDTH_20_NOHT:
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700214 if (ieee80211_chandef_to_khz(chandef) !=
215 ieee80211_channel_to_khz(chandef->chan))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100216 return false;
217 if (chandef->center_freq2)
218 return false;
219 break;
Thomas Pedersenc1cd35c2020-10-05 09:51:22 -0700220 case NL80211_CHAN_WIDTH_1:
Thomas Pedersen11b34732020-09-08 12:03:06 -0700221 case NL80211_CHAN_WIDTH_2:
222 case NL80211_CHAN_WIDTH_4:
223 case NL80211_CHAN_WIDTH_8:
224 case NL80211_CHAN_WIDTH_16:
Thomas Pedersenc1cd35c2020-10-05 09:51:22 -0700225 if (chandef->chan->band != NL80211_BAND_S1GHZ)
226 return false;
227
Thomas Pedersen11b34732020-09-08 12:03:06 -0700228 control_freq = ieee80211_channel_to_khz(chandef->chan);
229 oper_freq = ieee80211_chandef_to_khz(chandef);
230 control_width = nl80211_chan_width_to_mhz(
231 ieee80211_s1g_channel_width(
232 chandef->chan));
233 oper_width = cfg80211_chandef_get_width(chandef);
234
235 if (oper_width < 0 || control_width < 0)
236 return false;
237 if (chandef->center_freq2)
238 return false;
239
240 if (control_freq + MHZ_TO_KHZ(control_width) / 2 >
241 oper_freq + MHZ_TO_KHZ(oper_width) / 2)
242 return false;
243
244 if (control_freq - MHZ_TO_KHZ(control_width) / 2 <
245 oper_freq - MHZ_TO_KHZ(oper_width) / 2)
246 return false;
247 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100248 case NL80211_CHAN_WIDTH_80P80:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100249 if (!chandef->center_freq2)
250 return false;
Johannes Berg9cab3152012-12-14 00:19:08 +0100251 /* adjacent is not allowed -- that's a 160 MHz channel */
252 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
253 chandef->center_freq2 - chandef->center_freq1 == 80)
254 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100255 break;
Johannes Berg3bb1ccc2021-11-29 15:32:43 +0200256 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100257 if (chandef->center_freq2)
258 return false;
259 break;
Johannes Berg3bb1ccc2021-11-29 15:32:43 +0200260 }
261
262 switch (chandef->width) {
263 case NL80211_CHAN_WIDTH_5:
264 case NL80211_CHAN_WIDTH_10:
265 case NL80211_CHAN_WIDTH_20:
266 case NL80211_CHAN_WIDTH_20_NOHT:
267 case NL80211_CHAN_WIDTH_1:
268 case NL80211_CHAN_WIDTH_2:
269 case NL80211_CHAN_WIDTH_4:
270 case NL80211_CHAN_WIDTH_8:
271 case NL80211_CHAN_WIDTH_16:
272 /* all checked above */
273 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100274 case NL80211_CHAN_WIDTH_160:
Johannes Berg3bb1ccc2021-11-29 15:32:43 +0200275 if (chandef->center_freq1 == control_freq + 70 ||
276 chandef->center_freq1 == control_freq + 50 ||
277 chandef->center_freq1 == control_freq - 50 ||
278 chandef->center_freq1 == control_freq - 70)
279 break;
280 fallthrough;
281 case NL80211_CHAN_WIDTH_80P80:
282 case NL80211_CHAN_WIDTH_80:
283 if (chandef->center_freq1 == control_freq + 30 ||
284 chandef->center_freq1 == control_freq - 30)
285 break;
286 fallthrough;
287 case NL80211_CHAN_WIDTH_40:
288 if (chandef->center_freq1 == control_freq + 10 ||
289 chandef->center_freq1 == control_freq - 10)
290 break;
291 fallthrough;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100292 default:
293 return false;
294 }
295
Masashi Honmaec649fe2019-10-21 16:50:45 +0900296 /* channel 14 is only for IEEE 802.11b */
297 if (chandef->center_freq1 == 2484 &&
298 chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
299 return false;
300
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300301 if (cfg80211_chandef_is_edmg(chandef) &&
302 !cfg80211_edmg_chandef_valid(chandef))
303 return false;
304
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100305 return true;
306}
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100307EXPORT_SYMBOL(cfg80211_chandef_valid);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100308
309static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
Johannes Bergfc1f48f2014-10-29 17:05:39 +0100310 u32 *pri40, u32 *pri80)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100311{
312 int tmp;
313
314 switch (c->width) {
315 case NL80211_CHAN_WIDTH_40:
316 *pri40 = c->center_freq1;
317 *pri80 = 0;
318 break;
319 case NL80211_CHAN_WIDTH_80:
320 case NL80211_CHAN_WIDTH_80P80:
321 *pri80 = c->center_freq1;
322 /* n_P20 */
323 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
324 /* n_P40 */
325 tmp /= 2;
326 /* freq_P40 */
327 *pri40 = c->center_freq1 - 20 + 40 * tmp;
328 break;
329 case NL80211_CHAN_WIDTH_160:
330 /* n_P20 */
331 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
332 /* n_P40 */
333 tmp /= 2;
334 /* freq_P40 */
335 *pri40 = c->center_freq1 - 60 + 40 * tmp;
336 /* n_P80 */
337 tmp /= 2;
338 *pri80 = c->center_freq1 - 40 + 80 * tmp;
339 break;
340 default:
341 WARN_ON_ONCE(1);
342 }
343}
344
345const struct cfg80211_chan_def *
346cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
347 const struct cfg80211_chan_def *c2)
348{
349 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
350
351 /* If they are identical, return */
352 if (cfg80211_chandef_identical(c1, c2))
353 return c1;
354
355 /* otherwise, must have same control channel */
356 if (c1->chan != c2->chan)
357 return NULL;
358
359 /*
360 * If they have the same width, but aren't identical,
361 * then they can't be compatible.
362 */
363 if (c1->width == c2->width)
364 return NULL;
365
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200366 /*
367 * can't be compatible if one of them is 5 or 10 MHz,
368 * but they don't have the same width.
369 */
370 if (c1->width == NL80211_CHAN_WIDTH_5 ||
371 c1->width == NL80211_CHAN_WIDTH_10 ||
372 c2->width == NL80211_CHAN_WIDTH_5 ||
373 c2->width == NL80211_CHAN_WIDTH_10)
374 return NULL;
375
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100376 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
377 c1->width == NL80211_CHAN_WIDTH_20)
378 return c2;
379
380 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
381 c2->width == NL80211_CHAN_WIDTH_20)
382 return c1;
383
384 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
385 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
386
387 if (c1_pri40 != c2_pri40)
388 return NULL;
389
390 WARN_ON(!c1_pri80 && !c2_pri80);
391 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
392 return NULL;
393
394 if (c1->width > c2->width)
395 return c1;
396 return c2;
397}
398EXPORT_SYMBOL(cfg80211_chandef_compatible);
399
Simon Wunderlich04f39042013-02-08 18:16:19 +0100400static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
401 u32 bandwidth,
402 enum nl80211_dfs_state dfs_state)
403{
404 struct ieee80211_channel *c;
405 u32 freq;
406
407 for (freq = center_freq - bandwidth/2 + 10;
408 freq <= center_freq + bandwidth/2 - 10;
409 freq += 20) {
410 c = ieee80211_get_channel(wiphy, freq);
411 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
412 continue;
413
414 c->dfs_state = dfs_state;
415 c->dfs_state_entered = jiffies;
416 }
417}
418
419void cfg80211_set_dfs_state(struct wiphy *wiphy,
420 const struct cfg80211_chan_def *chandef,
421 enum nl80211_dfs_state dfs_state)
422{
423 int width;
424
425 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
426 return;
427
428 width = cfg80211_chandef_get_width(chandef);
429 if (width < 0)
430 return;
431
432 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
433 width, dfs_state);
434
435 if (!chandef->center_freq2)
436 return;
437 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
438 width, dfs_state);
439}
440
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100441static u32 cfg80211_get_start_freq(u32 center_freq,
442 u32 bandwidth)
443{
444 u32 start_freq;
445
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700446 bandwidth = MHZ_TO_KHZ(bandwidth);
447 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100448 start_freq = center_freq;
449 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700450 start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100451
452 return start_freq;
453}
454
455static u32 cfg80211_get_end_freq(u32 center_freq,
456 u32 bandwidth)
457{
458 u32 end_freq;
459
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700460 bandwidth = MHZ_TO_KHZ(bandwidth);
461 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100462 end_freq = center_freq;
463 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700464 end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100465
466 return end_freq;
467}
468
Simon Wunderlich04f39042013-02-08 18:16:19 +0100469static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
470 u32 center_freq,
471 u32 bandwidth)
472{
473 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200474 u32 freq, start_freq, end_freq;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100475
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100476 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
477 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200478
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700479 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
480 c = ieee80211_get_channel_khz(wiphy, freq);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100481 if (!c)
482 return -EINVAL;
483
484 if (c->flags & IEEE80211_CHAN_RADAR)
485 return 1;
486 }
487 return 0;
488}
489
490
491int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200492 const struct cfg80211_chan_def *chandef,
493 enum nl80211_iftype iftype)
Simon Wunderlich04f39042013-02-08 18:16:19 +0100494{
495 int width;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200496 int ret;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100497
498 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
499 return -EINVAL;
500
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200501 switch (iftype) {
502 case NL80211_IFTYPE_ADHOC:
503 case NL80211_IFTYPE_AP:
504 case NL80211_IFTYPE_P2P_GO:
505 case NL80211_IFTYPE_MESH_POINT:
506 width = cfg80211_chandef_get_width(chandef);
507 if (width < 0)
508 return -EINVAL;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100509
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200510 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700511 ieee80211_chandef_to_khz(chandef),
512 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200513 if (ret < 0)
514 return ret;
515 else if (ret > 0)
516 return BIT(chandef->width);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100517
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200518 if (!chandef->center_freq2)
519 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100520
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200521 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700522 MHZ_TO_KHZ(chandef->center_freq2),
523 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200524 if (ret < 0)
525 return ret;
526 else if (ret > 0)
527 return BIT(chandef->width);
528
529 break;
530 case NL80211_IFTYPE_STATION:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100531 case NL80211_IFTYPE_OCB:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200532 case NL80211_IFTYPE_P2P_CLIENT:
533 case NL80211_IFTYPE_MONITOR:
534 case NL80211_IFTYPE_AP_VLAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200535 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300536 case NL80211_IFTYPE_NAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200537 break;
Johannes Berge7e05172020-11-09 10:57:47 +0100538 case NL80211_IFTYPE_WDS:
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300539 case NL80211_IFTYPE_UNSPECIFIED:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200540 case NUM_NL80211_IFTYPES:
541 WARN_ON(1);
542 }
543
544 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100545}
Simon Wunderlich774f0732013-08-28 13:41:28 +0200546EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100547
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100548static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
549 u32 center_freq,
550 u32 bandwidth)
551{
552 struct ieee80211_channel *c;
553 u32 freq, start_freq, end_freq;
554 int count = 0;
555
556 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
557 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
558
559 /*
560 * Check entire range of channels for the bandwidth.
561 * Check all channels are DFS channels (DFS_USABLE or
562 * DFS_AVAILABLE). Return number of usable channels
563 * (require CAC). Allow DFS and non-DFS channel mix.
564 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700565 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
566 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100567 if (!c)
568 return -EINVAL;
569
570 if (c->flags & IEEE80211_CHAN_DISABLED)
571 return -EINVAL;
572
573 if (c->flags & IEEE80211_CHAN_RADAR) {
574 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
575 return -EINVAL;
576
577 if (c->dfs_state == NL80211_DFS_USABLE)
578 count++;
579 }
580 }
581
582 return count;
583}
584
585bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
586 const struct cfg80211_chan_def *chandef)
587{
588 int width;
589 int r1, r2 = 0;
590
591 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
592 return false;
593
594 width = cfg80211_chandef_get_width(chandef);
595 if (width < 0)
596 return false;
597
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700598 r1 = cfg80211_get_chans_dfs_usable(wiphy,
599 MHZ_TO_KHZ(chandef->center_freq1),
600 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100601
602 if (r1 < 0)
603 return false;
604
605 switch (chandef->width) {
606 case NL80211_CHAN_WIDTH_80P80:
607 WARN_ON(!chandef->center_freq2);
608 r2 = cfg80211_get_chans_dfs_usable(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700609 MHZ_TO_KHZ(chandef->center_freq2),
610 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100611 if (r2 < 0)
612 return false;
613 break;
614 default:
615 WARN_ON(chandef->center_freq2);
616 break;
617 }
618
619 return (r1 + r2 > 0);
620}
621
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530622/*
623 * Checks if center frequency of chan falls with in the bandwidth
624 * range of chandef.
625 */
626bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
627 struct ieee80211_channel *chan)
628{
629 int width;
Johannes Berga67a4892017-10-12 11:23:04 +0200630 u32 freq;
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530631
632 if (chandef->chan->center_freq == chan->center_freq)
633 return true;
634
635 width = cfg80211_chandef_get_width(chandef);
636 if (width <= 20)
637 return false;
638
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530639 for (freq = chandef->center_freq1 - width / 2 + 10;
640 freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
641 if (chan->center_freq == freq)
642 return true;
643 }
644
645 if (!chandef->center_freq2)
646 return false;
647
648 for (freq = chandef->center_freq2 - width / 2 + 10;
649 freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
650 if (chan->center_freq == freq)
651 return true;
652 }
653
654 return false;
655}
656
657bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
658{
659 bool active = false;
660
661 ASSERT_WDEV_LOCK(wdev);
662
663 if (!wdev->chandef.chan)
664 return false;
665
666 switch (wdev->iftype) {
667 case NL80211_IFTYPE_AP:
668 case NL80211_IFTYPE_P2P_GO:
669 active = wdev->beacon_interval != 0;
670 break;
671 case NL80211_IFTYPE_ADHOC:
672 active = wdev->ssid_len != 0;
673 break;
674 case NL80211_IFTYPE_MESH_POINT:
675 active = wdev->mesh_id_len != 0;
676 break;
677 case NL80211_IFTYPE_STATION:
678 case NL80211_IFTYPE_OCB:
679 case NL80211_IFTYPE_P2P_CLIENT:
680 case NL80211_IFTYPE_MONITOR:
681 case NL80211_IFTYPE_AP_VLAN:
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530682 case NL80211_IFTYPE_P2P_DEVICE:
683 /* Can NAN type be considered as beaconing interface? */
684 case NL80211_IFTYPE_NAN:
685 break;
686 case NL80211_IFTYPE_UNSPECIFIED:
Johannes Berge7e05172020-11-09 10:57:47 +0100687 case NL80211_IFTYPE_WDS:
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530688 case NUM_NL80211_IFTYPES:
689 WARN_ON(1);
690 }
691
692 return active;
693}
694
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530695static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
696 struct ieee80211_channel *chan)
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530697{
698 struct wireless_dev *wdev;
699
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530700 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
701 wdev_lock(wdev);
702 if (!cfg80211_beaconing_iface_active(wdev)) {
703 wdev_unlock(wdev);
704 continue;
705 }
706
707 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
708 wdev_unlock(wdev);
709 return true;
710 }
711 wdev_unlock(wdev);
712 }
713
714 return false;
715}
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100716
Lorenzo Bianconi84158162021-11-16 15:03:36 +0100717static bool
718cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
719 struct ieee80211_channel *channel)
720{
Lorenzo Bianconia95bfb82021-11-29 14:11:24 +0100721 if (!rdev->background_radar_wdev)
Lorenzo Bianconi84158162021-11-16 15:03:36 +0100722 return false;
723
Lorenzo Bianconia95bfb82021-11-29 14:11:24 +0100724 if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
Lorenzo Bianconi84158162021-11-16 15:03:36 +0100725 return false;
726
Lorenzo Bianconia95bfb82021-11-29 14:11:24 +0100727 return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel);
Lorenzo Bianconi84158162021-11-16 15:03:36 +0100728}
729
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530730bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
731 struct ieee80211_channel *chan)
732{
733 struct cfg80211_registered_device *rdev;
734
735 ASSERT_RTNL();
736
737 if (!(chan->flags & IEEE80211_CHAN_RADAR))
738 return false;
739
740 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
741 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
742 continue;
743
744 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
745 return true;
Lorenzo Bianconi84158162021-11-16 15:03:36 +0100746
747 if (cfg80211_offchan_chain_is_active(rdev, chan))
748 return true;
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530749 }
750
751 return false;
752}
753
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100754static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
755 u32 center_freq,
756 u32 bandwidth)
757{
758 struct ieee80211_channel *c;
759 u32 freq, start_freq, end_freq;
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300760 bool dfs_offload;
761
762 dfs_offload = wiphy_ext_feature_isset(wiphy,
763 NL80211_EXT_FEATURE_DFS_OFFLOAD);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100764
765 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
766 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
767
768 /*
769 * Check entire range of channels for the bandwidth.
770 * If any channel in between is disabled or has not
771 * had gone through CAC return false
772 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700773 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
774 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100775 if (!c)
776 return false;
777
778 if (c->flags & IEEE80211_CHAN_DISABLED)
779 return false;
780
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300781 if ((c->flags & IEEE80211_CHAN_RADAR) &&
782 (c->dfs_state != NL80211_DFS_AVAILABLE) &&
783 !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100784 return false;
785 }
786
787 return true;
788}
789
790static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
791 const struct cfg80211_chan_def *chandef)
792{
793 int width;
794 int r;
795
796 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
797 return false;
798
799 width = cfg80211_chandef_get_width(chandef);
800 if (width < 0)
801 return false;
802
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700803 r = cfg80211_get_chans_dfs_available(wiphy,
804 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100805 width);
806
807 /* If any of channels unavailable for cf1 just return */
808 if (!r)
809 return r;
810
811 switch (chandef->width) {
812 case NL80211_CHAN_WIDTH_80P80:
813 WARN_ON(!chandef->center_freq2);
814 r = cfg80211_get_chans_dfs_available(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700815 MHZ_TO_KHZ(chandef->center_freq2),
816 width);
Colin Ian King680682d2016-07-17 19:55:27 +0100817 break;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100818 default:
819 WARN_ON(chandef->center_freq2);
820 break;
821 }
822
823 return r;
824}
825
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100826static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
827 u32 center_freq,
828 u32 bandwidth)
829{
830 struct ieee80211_channel *c;
831 u32 start_freq, end_freq, freq;
832 unsigned int dfs_cac_ms = 0;
833
834 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
835 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
836
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700837 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
838 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100839 if (!c)
840 return 0;
841
842 if (c->flags & IEEE80211_CHAN_DISABLED)
843 return 0;
844
845 if (!(c->flags & IEEE80211_CHAN_RADAR))
846 continue;
847
848 if (c->dfs_cac_ms > dfs_cac_ms)
849 dfs_cac_ms = c->dfs_cac_ms;
850 }
851
852 return dfs_cac_ms;
853}
854
855unsigned int
856cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
857 const struct cfg80211_chan_def *chandef)
858{
859 int width;
860 unsigned int t1 = 0, t2 = 0;
861
862 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
863 return 0;
864
865 width = cfg80211_chandef_get_width(chandef);
866 if (width < 0)
867 return 0;
868
869 t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700870 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100871 width);
872
873 if (!chandef->center_freq2)
874 return t1;
875
876 t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700877 MHZ_TO_KHZ(chandef->center_freq2),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100878 width);
879
880 return max(t1, t2);
881}
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100882
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100883static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
884 u32 center_freq, u32 bandwidth,
885 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100886{
887 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200888 u32 freq, start_freq, end_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100889
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100890 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
891 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200892
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700893 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
894 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100895 if (!c || c->flags & prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100896 return false;
897 }
898
899 return true;
900}
901
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300902/* check if the operating channels are valid and supported */
903static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
904 enum ieee80211_edmg_bw_config edmg_bw_config,
905 int primary_channel,
906 struct ieee80211_edmg *edmg_cap)
907{
908 struct ieee80211_channel *chan;
909 int i, freq;
910 int channels_counter = 0;
911
912 if (!edmg_channels && !edmg_bw_config)
913 return true;
914
915 if ((!edmg_channels && edmg_bw_config) ||
916 (edmg_channels && !edmg_bw_config))
917 return false;
918
919 if (!(edmg_channels & BIT(primary_channel - 1)))
920 return false;
921
922 /* 60GHz channels 1..6 */
923 for (i = 0; i < 6; i++) {
924 if (!(edmg_channels & BIT(i)))
925 continue;
926
927 if (!(edmg_cap->channels & BIT(i)))
928 return false;
929
930 channels_counter++;
931
932 freq = ieee80211_channel_to_frequency(i + 1,
933 NL80211_BAND_60GHZ);
934 chan = ieee80211_get_channel(wiphy, freq);
935 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
936 return false;
937 }
938
939 /* IEEE802.11 allows max 4 channels */
940 if (channels_counter > 4)
941 return false;
942
943 /* check bw_config is a subset of what driver supports
944 * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
945 */
946 if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
947 return false;
948
949 if (edmg_bw_config > edmg_cap->bw_config)
950 return false;
951
952 return true;
953}
954
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100955bool cfg80211_chandef_usable(struct wiphy *wiphy,
956 const struct cfg80211_chan_def *chandef,
957 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100958{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100959 struct ieee80211_sta_ht_cap *ht_cap;
960 struct ieee80211_sta_vht_cap *vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300961 struct ieee80211_edmg *edmg_cap;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200962 u32 width, control_freq, cap;
Wen Gonge6ed9292021-05-23 23:36:24 -0400963 bool ext_nss_cap, support_80_80 = false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100964
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100965 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100966 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100967
968 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
969 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300970 edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
Wen Gonge6ed9292021-05-23 23:36:24 -0400971 ext_nss_cap = __le16_to_cpu(vht_cap->vht_mcs.tx_highest) &
972 IEEE80211_VHT_EXT_NSS_BW_CAPABLE;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300973
974 if (edmg_cap->channels &&
975 !cfg80211_edmg_usable(wiphy,
976 chandef->edmg.channels,
977 chandef->edmg.bw_config,
978 chandef->chan->hw_value,
979 edmg_cap))
980 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100981
982 control_freq = chandef->chan->center_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100983
984 switch (chandef->width) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700985 case NL80211_CHAN_WIDTH_1:
986 width = 1;
987 break;
988 case NL80211_CHAN_WIDTH_2:
989 width = 2;
990 break;
991 case NL80211_CHAN_WIDTH_4:
992 width = 4;
993 break;
994 case NL80211_CHAN_WIDTH_8:
995 width = 8;
996 break;
997 case NL80211_CHAN_WIDTH_16:
998 width = 16;
999 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02001000 case NL80211_CHAN_WIDTH_5:
1001 width = 5;
1002 break;
1003 case NL80211_CHAN_WIDTH_10:
Rostislav Lisovyea077c12014-04-15 14:37:55 +02001004 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02001005 width = 10;
1006 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001007 case NL80211_CHAN_WIDTH_20:
Johannes Bergba8f6a02020-05-28 21:34:40 +02001008 if (!ht_cap->ht_supported &&
1009 chandef->chan->band != NL80211_BAND_6GHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001010 return false;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001011 fallthrough;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001012 case NL80211_CHAN_WIDTH_20_NOHT:
Rostislav Lisovyea077c12014-04-15 14:37:55 +02001013 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001014 width = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -05001015 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001016 case NL80211_CHAN_WIDTH_40:
1017 width = 40;
Johannes Bergba8f6a02020-05-28 21:34:40 +02001018 if (chandef->chan->band == NL80211_BAND_6GHZ)
1019 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001020 if (!ht_cap->ht_supported)
1021 return false;
1022 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
1023 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
1024 return false;
1025 if (chandef->center_freq1 < control_freq &&
1026 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
1027 return false;
1028 if (chandef->center_freq1 > control_freq &&
1029 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
1030 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001031 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001032 case NL80211_CHAN_WIDTH_80P80:
Shay Bar35799942020-08-26 17:31:39 +03001033 cap = vht_cap->cap;
1034 support_80_80 =
1035 (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
1036 (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
1037 cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
Wen Gonge6ed9292021-05-23 23:36:24 -04001038 (ext_nss_cap &&
1039 u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1);
Shay Bar35799942020-08-26 17:31:39 +03001040 if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001041 return false;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001042 fallthrough;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001043 case NL80211_CHAN_WIDTH_80:
Johannes Bergc7a6ee22012-12-12 17:50:39 +01001044 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001045 width = 80;
Johannes Bergba8f6a02020-05-28 21:34:40 +02001046 if (chandef->chan->band == NL80211_BAND_6GHZ)
1047 break;
1048 if (!vht_cap->vht_supported)
1049 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001050 break;
1051 case NL80211_CHAN_WIDTH_160:
Johannes Bergba8f6a02020-05-28 21:34:40 +02001052 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
1053 width = 160;
1054 if (chandef->chan->band == NL80211_BAND_6GHZ)
1055 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001056 if (!vht_cap->vht_supported)
1057 return false;
Jouni Malinen08f6f142014-12-11 23:48:55 +02001058 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
1059 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
Shay Bar35799942020-08-26 17:31:39 +03001060 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ &&
Wen Gonge6ed9292021-05-23 23:36:24 -04001061 !(ext_nss_cap &&
1062 (vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)))
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001063 return false;
Mark Mentovai09a02fd2010-11-17 16:34:37 -05001064 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001065 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001066 WARN_ON_ONCE(1);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001067 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +03001068 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001069
Johannes Bergc7a6ee22012-12-12 17:50:39 +01001070 /*
1071 * TODO: What if there are only certain 80/160/80+80 MHz channels
1072 * allowed by the driver, or only certain combinations?
1073 * For 40 MHz the driver can set the NO_HT40 flags, but for
1074 * 80/160 MHz and in particular 80+80 MHz this isn't really
1075 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
1076 * no way to cover 80+80 MHz or more complex restrictions.
1077 * Note that such restrictions also need to be advertised to
1078 * userspace, for example for P2P channel selection.
1079 */
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001080
Johannes Berga6662db2012-12-04 20:49:42 +01001081 if (width > 20)
1082 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1083
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02001084 /* 5 and 10 MHz are only defined for the OFDM PHY */
1085 if (width < 20)
1086 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1087
1088
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001089 if (!cfg80211_secondary_chans_ok(wiphy,
1090 ieee80211_chandef_to_khz(chandef),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001091 width, prohibited_flags))
1092 return false;
1093
1094 if (!chandef->center_freq2)
1095 return true;
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001096 return cfg80211_secondary_chans_ok(wiphy,
1097 MHZ_TO_KHZ(chandef->center_freq2),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001098 width, prohibited_flags);
1099}
1100EXPORT_SYMBOL(cfg80211_chandef_usable);
1101
Ilan Peer174e0cd2014-02-23 09:13:01 +02001102/*
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001103 * Check if the channel can be used under permissive conditions mandated by
1104 * some regulatory bodies, i.e., the channel is marked with
1105 * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
Ilan Peer174e0cd2014-02-23 09:13:01 +02001106 * associated to an AP on the same channel or on the same UNII band
1107 * (assuming that the AP is an authorized master).
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001108 * In addition allow operation on a channel on which indoor operation is
Ilan Peerc8866e52014-02-23 09:13:03 +02001109 * allowed, iff we are currently operating in an indoor environment.
Ilan Peer174e0cd2014-02-23 09:13:01 +02001110 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001111static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
1112 enum nl80211_iftype iftype,
Ilan Peer174e0cd2014-02-23 09:13:01 +02001113 struct ieee80211_channel *chan)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001114{
Avraham Sternbe69c242015-04-27 16:52:16 +03001115 struct wireless_dev *wdev;
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001116 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001117
Johannes Berga05829a2021-01-22 16:19:43 +01001118 lockdep_assert_held(&rdev->wiphy.mtx);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001119
Masahiro Yamada97f26452016-08-03 13:45:50 -07001120 if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
Ilan Peerc8866e52014-02-23 09:13:03 +02001121 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
1122 return false;
1123
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001124 /* only valid for GO and TDLS off-channel (station/p2p-CL) */
1125 if (iftype != NL80211_IFTYPE_P2P_GO &&
1126 iftype != NL80211_IFTYPE_STATION &&
1127 iftype != NL80211_IFTYPE_P2P_CLIENT)
1128 return false;
1129
Ilan Peerc8866e52014-02-23 09:13:03 +02001130 if (regulatory_indoor_allowed() &&
1131 (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1132 return true;
1133
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001134 if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
Ilan Peer174e0cd2014-02-23 09:13:01 +02001135 return false;
1136
1137 /*
1138 * Generally, it is possible to rely on another device/driver to allow
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001139 * the IR concurrent relaxation, however, since the device can further
Ilan Peer174e0cd2014-02-23 09:13:01 +02001140 * enforce the relaxation (by doing a similar verifications as this),
1141 * and thus fail the GO instantiation, consider only the interfaces of
1142 * the current registered device.
1143 */
Johannes Berg53873f12016-05-03 16:52:04 +03001144 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Ilan Peer174e0cd2014-02-23 09:13:01 +02001145 struct ieee80211_channel *other_chan = NULL;
1146 int r1, r2;
1147
Avraham Sternbe69c242015-04-27 16:52:16 +03001148 wdev_lock(wdev);
1149 if (wdev->iftype == NL80211_IFTYPE_STATION &&
1150 wdev->current_bss)
1151 other_chan = wdev->current_bss->pub.channel;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001152
Avraham Sternbe69c242015-04-27 16:52:16 +03001153 /*
1154 * If a GO already operates on the same GO_CONCURRENT channel,
1155 * this one (maybe the same one) can beacon as well. We allow
1156 * the operation even if the station we relied on with
1157 * GO_CONCURRENT is disconnected now. But then we must make sure
1158 * we're not outdoor on an indoor-only channel.
1159 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001160 if (iftype == NL80211_IFTYPE_P2P_GO &&
1161 wdev->iftype == NL80211_IFTYPE_P2P_GO &&
Avraham Sternbe69c242015-04-27 16:52:16 +03001162 wdev->beacon_interval &&
1163 !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1164 other_chan = wdev->chandef.chan;
1165 wdev_unlock(wdev);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001166
1167 if (!other_chan)
1168 continue;
1169
1170 if (chan == other_chan)
1171 return true;
1172
Arend van Spriel0816e6b2019-08-02 13:31:03 +02001173 if (chan->band != NL80211_BAND_5GHZ &&
1174 chan->band != NL80211_BAND_6GHZ)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001175 continue;
1176
1177 r1 = cfg80211_get_unii(chan->center_freq);
1178 r2 = cfg80211_get_unii(other_chan->center_freq);
1179
Ilan Peer46d53722014-04-23 09:22:58 +03001180 if (r1 != -EINVAL && r1 == r2) {
1181 /*
1182 * At some locations channels 149-165 are considered a
1183 * bundle, but at other locations, e.g., Indonesia,
1184 * channels 149-161 are considered a bundle while
1185 * channel 165 is left out and considered to be in a
1186 * different bundle. Thus, in case that there is a
1187 * station interface connected to an AP on channel 165,
1188 * it is assumed that channels 149-161 are allowed for
1189 * GO operations. However, having a station interface
1190 * connected to an AP on channels 149-161, does not
1191 * allow GO operation on channel 165.
1192 */
1193 if (chan->center_freq == 5825 &&
1194 other_chan->center_freq != 5825)
1195 continue;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001196 return true;
Ilan Peer46d53722014-04-23 09:22:58 +03001197 }
Ilan Peer174e0cd2014-02-23 09:13:01 +02001198 }
1199
1200 return false;
1201}
1202
Arik Nemtsov923b3522015-07-08 15:41:44 +03001203static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
1204 struct cfg80211_chan_def *chandef,
1205 enum nl80211_iftype iftype,
1206 bool check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001207{
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001208 bool res;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001209 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001210 IEEE80211_CHAN_RADAR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001211
Arik Nemtsov923b3522015-07-08 15:41:44 +03001212 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001213
Arik Nemtsov923b3522015-07-08 15:41:44 +03001214 if (check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001215 prohibited_flags |= IEEE80211_CHAN_NO_IR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001216
Luciano Coelho00ec75f2014-05-15 13:05:39 +03001217 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001218 cfg80211_chandef_dfs_available(wiphy, chandef)) {
1219 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
1220 prohibited_flags = IEEE80211_CHAN_DISABLED;
1221 }
1222
1223 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001224
1225 trace_cfg80211_return_bool(res);
1226 return res;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001227}
Arik Nemtsov923b3522015-07-08 15:41:44 +03001228
1229bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
1230 struct cfg80211_chan_def *chandef,
1231 enum nl80211_iftype iftype)
1232{
1233 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
1234}
Johannes Berg683b6d32012-11-08 21:25:48 +01001235EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001236
Arik Nemtsov923b3522015-07-08 15:41:44 +03001237bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
1238 struct cfg80211_chan_def *chandef,
1239 enum nl80211_iftype iftype)
1240{
Johannes Berga05829a2021-01-22 16:19:43 +01001241 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Arik Nemtsov923b3522015-07-08 15:41:44 +03001242 bool check_no_ir;
1243
Johannes Berga05829a2021-01-22 16:19:43 +01001244 lockdep_assert_held(&rdev->wiphy.mtx);
Arik Nemtsov923b3522015-07-08 15:41:44 +03001245
1246 /*
1247 * Under certain conditions suggested by some regulatory bodies a
1248 * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
1249 * only if such relaxations are not enabled and the conditions are not
1250 * met.
1251 */
1252 check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
1253 chandef->chan);
1254
1255 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1256}
1257EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
1258
Johannes Berge8c9bd52012-06-06 08:18:22 +02001259int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +01001260 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001261{
Johannes Berge8c9bd52012-06-06 08:18:22 +02001262 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001263 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +02001264 if (!cfg80211_has_monitors_only(rdev))
1265 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001266
Johannes Berg683b6d32012-11-08 21:25:48 +01001267 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001268}
Michal Kazior26ab9a02012-06-29 12:47:00 +02001269
1270void
Johannes Berg8e95ea42012-07-10 19:39:02 +02001271cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +02001272 struct ieee80211_channel **chan,
Michal Kazior9e0e2962014-01-29 14:22:27 +01001273 enum cfg80211_chan_mode *chanmode,
1274 u8 *radar_detect)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001275{
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001276 int ret;
1277
Michal Kazior26ab9a02012-06-29 12:47:00 +02001278 *chan = NULL;
1279 *chanmode = CHAN_MODE_UNDEFINED;
1280
Michal Kazior26ab9a02012-06-29 12:47:00 +02001281 ASSERT_WDEV_LOCK(wdev);
1282
Johannes Berg98104fde2012-06-16 00:19:54 +02001283 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +02001284 return;
1285
1286 switch (wdev->iftype) {
1287 case NL80211_IFTYPE_ADHOC:
1288 if (wdev->current_bss) {
1289 *chan = wdev->current_bss->pub.channel;
Simon Wunderlich5336fa82013-10-07 18:41:05 +02001290 *chanmode = (wdev->ibss_fixed &&
1291 !wdev->ibss_dfs_possible)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001292 ? CHAN_MODE_SHARED
1293 : CHAN_MODE_EXCLUSIVE;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001294
1295 /* consider worst-case - IBSS can try to return to the
1296 * original user-specified channel as creator */
1297 if (wdev->ibss_dfs_possible)
1298 *radar_detect |= BIT(wdev->chandef.width);
Michal Kazior26ab9a02012-06-29 12:47:00 +02001299 return;
1300 }
Johannes Berg0f0094b2013-10-25 12:46:44 +02001301 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001302 case NL80211_IFTYPE_STATION:
1303 case NL80211_IFTYPE_P2P_CLIENT:
1304 if (wdev->current_bss) {
1305 *chan = wdev->current_bss->pub.channel;
1306 *chanmode = CHAN_MODE_SHARED;
1307 return;
1308 }
1309 break;
1310 case NL80211_IFTYPE_AP:
1311 case NL80211_IFTYPE_P2P_GO:
Simon Wunderlich04f39042013-02-08 18:16:19 +01001312 if (wdev->cac_started) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001313 *chan = wdev->chandef.chan;
Simon Wunderlich04f39042013-02-08 18:16:19 +01001314 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001315 *radar_detect |= BIT(wdev->chandef.width);
Simon Wunderlich04f39042013-02-08 18:16:19 +01001316 } else if (wdev->beacon_interval) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001317 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001318 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001319
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001320 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1321 &wdev->chandef,
1322 wdev->iftype);
1323 WARN_ON(ret < 0);
1324 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001325 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001326 }
1327 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001328 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +02001329 if (wdev->mesh_id_len) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001330 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001331 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001332
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001333 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1334 &wdev->chandef,
1335 wdev->iftype);
1336 WARN_ON(ret < 0);
1337 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001338 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001339 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001340 return;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001341 case NL80211_IFTYPE_OCB:
1342 if (wdev->chandef.chan) {
1343 *chan = wdev->chandef.chan;
1344 *chanmode = CHAN_MODE_SHARED;
1345 return;
1346 }
1347 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001348 case NL80211_IFTYPE_MONITOR:
1349 case NL80211_IFTYPE_AP_VLAN:
Johannes Berg98104fde2012-06-16 00:19:54 +02001350 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001351 case NL80211_IFTYPE_NAN:
Johannes Berge7aceef2014-02-12 14:21:15 +01001352 /* these interface types don't really have a channel */
Johannes Berg98104fde2012-06-16 00:19:54 +02001353 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001354 case NL80211_IFTYPE_UNSPECIFIED:
Johannes Berge7e05172020-11-09 10:57:47 +01001355 case NL80211_IFTYPE_WDS:
Michal Kazior26ab9a02012-06-29 12:47:00 +02001356 case NUM_NL80211_IFTYPES:
1357 WARN_ON(1);
1358 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001359}
Johannes Bergbe989892021-06-18 13:41:39 +03001360
1361bool cfg80211_any_usable_channels(struct wiphy *wiphy,
1362 unsigned long sband_mask,
1363 u32 prohibited_flags)
1364{
1365 int idx;
1366
1367 prohibited_flags |= IEEE80211_CHAN_DISABLED;
1368
1369 for_each_set_bit(idx, &sband_mask, NUM_NL80211_BANDS) {
1370 struct ieee80211_supported_band *sband = wiphy->bands[idx];
1371 int chanidx;
1372
1373 if (!sband)
1374 continue;
1375
1376 for (chanidx = 0; chanidx < sband->n_channels; chanidx++) {
1377 struct ieee80211_channel *chan;
1378
1379 chan = &sband->channels[chanidx];
1380
1381 if (chan->flags & prohibited_flags)
1382 continue;
1383
1384 return true;
1385 }
1386 }
1387
1388 return false;
1389}
1390EXPORT_SYMBOL(cfg80211_any_usable_channels);