blob: 96e24ee4c7e8c1af5d8cb5b994da0049f8ca32fc [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>
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) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700210 case NL80211_CHAN_WIDTH_1:
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200211 case NL80211_CHAN_WIDTH_5:
212 case NL80211_CHAN_WIDTH_10:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100213 case NL80211_CHAN_WIDTH_20:
214 case NL80211_CHAN_WIDTH_20_NOHT:
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700215 if (ieee80211_chandef_to_khz(chandef) !=
216 ieee80211_channel_to_khz(chandef->chan))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100217 return false;
218 if (chandef->center_freq2)
219 return false;
220 break;
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:
225 control_freq = ieee80211_channel_to_khz(chandef->chan);
226 oper_freq = ieee80211_chandef_to_khz(chandef);
227 control_width = nl80211_chan_width_to_mhz(
228 ieee80211_s1g_channel_width(
229 chandef->chan));
230 oper_width = cfg80211_chandef_get_width(chandef);
231
232 if (oper_width < 0 || control_width < 0)
233 return false;
234 if (chandef->center_freq2)
235 return false;
236
237 if (control_freq + MHZ_TO_KHZ(control_width) / 2 >
238 oper_freq + MHZ_TO_KHZ(oper_width) / 2)
239 return false;
240
241 if (control_freq - MHZ_TO_KHZ(control_width) / 2 <
242 oper_freq - MHZ_TO_KHZ(oper_width) / 2)
243 return false;
244 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100245 case NL80211_CHAN_WIDTH_40:
246 if (chandef->center_freq1 != control_freq + 10 &&
247 chandef->center_freq1 != control_freq - 10)
248 return false;
249 if (chandef->center_freq2)
250 return false;
251 break;
252 case NL80211_CHAN_WIDTH_80P80:
253 if (chandef->center_freq1 != control_freq + 30 &&
254 chandef->center_freq1 != control_freq + 10 &&
255 chandef->center_freq1 != control_freq - 10 &&
256 chandef->center_freq1 != control_freq - 30)
257 return false;
258 if (!chandef->center_freq2)
259 return false;
Johannes Berg9cab3152012-12-14 00:19:08 +0100260 /* adjacent is not allowed -- that's a 160 MHz channel */
261 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
262 chandef->center_freq2 - chandef->center_freq1 == 80)
263 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100264 break;
265 case NL80211_CHAN_WIDTH_80:
266 if (chandef->center_freq1 != control_freq + 30 &&
267 chandef->center_freq1 != control_freq + 10 &&
268 chandef->center_freq1 != control_freq - 10 &&
269 chandef->center_freq1 != control_freq - 30)
270 return false;
271 if (chandef->center_freq2)
272 return false;
273 break;
274 case NL80211_CHAN_WIDTH_160:
275 if (chandef->center_freq1 != control_freq + 70 &&
276 chandef->center_freq1 != control_freq + 50 &&
277 chandef->center_freq1 != control_freq + 30 &&
278 chandef->center_freq1 != control_freq + 10 &&
279 chandef->center_freq1 != control_freq - 10 &&
280 chandef->center_freq1 != control_freq - 30 &&
281 chandef->center_freq1 != control_freq - 50 &&
282 chandef->center_freq1 != control_freq - 70)
283 return false;
284 if (chandef->center_freq2)
285 return false;
286 break;
287 default:
288 return false;
289 }
290
Masashi Honmaec649fe2019-10-21 16:50:45 +0900291 /* channel 14 is only for IEEE 802.11b */
292 if (chandef->center_freq1 == 2484 &&
293 chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
294 return false;
295
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300296 if (cfg80211_chandef_is_edmg(chandef) &&
297 !cfg80211_edmg_chandef_valid(chandef))
298 return false;
299
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100300 return true;
301}
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100302EXPORT_SYMBOL(cfg80211_chandef_valid);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100303
304static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
Johannes Bergfc1f48f2014-10-29 17:05:39 +0100305 u32 *pri40, u32 *pri80)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100306{
307 int tmp;
308
309 switch (c->width) {
310 case NL80211_CHAN_WIDTH_40:
311 *pri40 = c->center_freq1;
312 *pri80 = 0;
313 break;
314 case NL80211_CHAN_WIDTH_80:
315 case NL80211_CHAN_WIDTH_80P80:
316 *pri80 = c->center_freq1;
317 /* n_P20 */
318 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
319 /* n_P40 */
320 tmp /= 2;
321 /* freq_P40 */
322 *pri40 = c->center_freq1 - 20 + 40 * tmp;
323 break;
324 case NL80211_CHAN_WIDTH_160:
325 /* n_P20 */
326 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
327 /* n_P40 */
328 tmp /= 2;
329 /* freq_P40 */
330 *pri40 = c->center_freq1 - 60 + 40 * tmp;
331 /* n_P80 */
332 tmp /= 2;
333 *pri80 = c->center_freq1 - 40 + 80 * tmp;
334 break;
335 default:
336 WARN_ON_ONCE(1);
337 }
338}
339
340const struct cfg80211_chan_def *
341cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
342 const struct cfg80211_chan_def *c2)
343{
344 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
345
346 /* If they are identical, return */
347 if (cfg80211_chandef_identical(c1, c2))
348 return c1;
349
350 /* otherwise, must have same control channel */
351 if (c1->chan != c2->chan)
352 return NULL;
353
354 /*
355 * If they have the same width, but aren't identical,
356 * then they can't be compatible.
357 */
358 if (c1->width == c2->width)
359 return NULL;
360
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200361 /*
362 * can't be compatible if one of them is 5 or 10 MHz,
363 * but they don't have the same width.
364 */
365 if (c1->width == NL80211_CHAN_WIDTH_5 ||
366 c1->width == NL80211_CHAN_WIDTH_10 ||
367 c2->width == NL80211_CHAN_WIDTH_5 ||
368 c2->width == NL80211_CHAN_WIDTH_10)
369 return NULL;
370
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100371 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
372 c1->width == NL80211_CHAN_WIDTH_20)
373 return c2;
374
375 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
376 c2->width == NL80211_CHAN_WIDTH_20)
377 return c1;
378
379 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
380 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
381
382 if (c1_pri40 != c2_pri40)
383 return NULL;
384
385 WARN_ON(!c1_pri80 && !c2_pri80);
386 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
387 return NULL;
388
389 if (c1->width > c2->width)
390 return c1;
391 return c2;
392}
393EXPORT_SYMBOL(cfg80211_chandef_compatible);
394
Simon Wunderlich04f39042013-02-08 18:16:19 +0100395static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
396 u32 bandwidth,
397 enum nl80211_dfs_state dfs_state)
398{
399 struct ieee80211_channel *c;
400 u32 freq;
401
402 for (freq = center_freq - bandwidth/2 + 10;
403 freq <= center_freq + bandwidth/2 - 10;
404 freq += 20) {
405 c = ieee80211_get_channel(wiphy, freq);
406 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
407 continue;
408
409 c->dfs_state = dfs_state;
410 c->dfs_state_entered = jiffies;
411 }
412}
413
414void cfg80211_set_dfs_state(struct wiphy *wiphy,
415 const struct cfg80211_chan_def *chandef,
416 enum nl80211_dfs_state dfs_state)
417{
418 int width;
419
420 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
421 return;
422
423 width = cfg80211_chandef_get_width(chandef);
424 if (width < 0)
425 return;
426
427 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
428 width, dfs_state);
429
430 if (!chandef->center_freq2)
431 return;
432 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
433 width, dfs_state);
434}
435
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100436static u32 cfg80211_get_start_freq(u32 center_freq,
437 u32 bandwidth)
438{
439 u32 start_freq;
440
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700441 bandwidth = MHZ_TO_KHZ(bandwidth);
442 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100443 start_freq = center_freq;
444 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700445 start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100446
447 return start_freq;
448}
449
450static u32 cfg80211_get_end_freq(u32 center_freq,
451 u32 bandwidth)
452{
453 u32 end_freq;
454
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700455 bandwidth = MHZ_TO_KHZ(bandwidth);
456 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100457 end_freq = center_freq;
458 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700459 end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100460
461 return end_freq;
462}
463
Simon Wunderlich04f39042013-02-08 18:16:19 +0100464static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
465 u32 center_freq,
466 u32 bandwidth)
467{
468 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200469 u32 freq, start_freq, end_freq;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100470
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100471 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
472 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200473
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700474 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
475 c = ieee80211_get_channel_khz(wiphy, freq);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100476 if (!c)
477 return -EINVAL;
478
479 if (c->flags & IEEE80211_CHAN_RADAR)
480 return 1;
481 }
482 return 0;
483}
484
485
486int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200487 const struct cfg80211_chan_def *chandef,
488 enum nl80211_iftype iftype)
Simon Wunderlich04f39042013-02-08 18:16:19 +0100489{
490 int width;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200491 int ret;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100492
493 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
494 return -EINVAL;
495
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200496 switch (iftype) {
497 case NL80211_IFTYPE_ADHOC:
498 case NL80211_IFTYPE_AP:
499 case NL80211_IFTYPE_P2P_GO:
500 case NL80211_IFTYPE_MESH_POINT:
501 width = cfg80211_chandef_get_width(chandef);
502 if (width < 0)
503 return -EINVAL;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100504
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200505 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700506 ieee80211_chandef_to_khz(chandef),
507 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200508 if (ret < 0)
509 return ret;
510 else if (ret > 0)
511 return BIT(chandef->width);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100512
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200513 if (!chandef->center_freq2)
514 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100515
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200516 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700517 MHZ_TO_KHZ(chandef->center_freq2),
518 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200519 if (ret < 0)
520 return ret;
521 else if (ret > 0)
522 return BIT(chandef->width);
523
524 break;
525 case NL80211_IFTYPE_STATION:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100526 case NL80211_IFTYPE_OCB:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200527 case NL80211_IFTYPE_P2P_CLIENT:
528 case NL80211_IFTYPE_MONITOR:
529 case NL80211_IFTYPE_AP_VLAN:
530 case NL80211_IFTYPE_WDS:
531 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300532 case NL80211_IFTYPE_NAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200533 break;
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300534 case NL80211_IFTYPE_UNSPECIFIED:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200535 case NUM_NL80211_IFTYPES:
536 WARN_ON(1);
537 }
538
539 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100540}
Simon Wunderlich774f0732013-08-28 13:41:28 +0200541EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100542
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100543static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
544 u32 center_freq,
545 u32 bandwidth)
546{
547 struct ieee80211_channel *c;
548 u32 freq, start_freq, end_freq;
549 int count = 0;
550
551 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
552 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
553
554 /*
555 * Check entire range of channels for the bandwidth.
556 * Check all channels are DFS channels (DFS_USABLE or
557 * DFS_AVAILABLE). Return number of usable channels
558 * (require CAC). Allow DFS and non-DFS channel mix.
559 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700560 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
561 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100562 if (!c)
563 return -EINVAL;
564
565 if (c->flags & IEEE80211_CHAN_DISABLED)
566 return -EINVAL;
567
568 if (c->flags & IEEE80211_CHAN_RADAR) {
569 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
570 return -EINVAL;
571
572 if (c->dfs_state == NL80211_DFS_USABLE)
573 count++;
574 }
575 }
576
577 return count;
578}
579
580bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
581 const struct cfg80211_chan_def *chandef)
582{
583 int width;
584 int r1, r2 = 0;
585
586 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
587 return false;
588
589 width = cfg80211_chandef_get_width(chandef);
590 if (width < 0)
591 return false;
592
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700593 r1 = cfg80211_get_chans_dfs_usable(wiphy,
594 MHZ_TO_KHZ(chandef->center_freq1),
595 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100596
597 if (r1 < 0)
598 return false;
599
600 switch (chandef->width) {
601 case NL80211_CHAN_WIDTH_80P80:
602 WARN_ON(!chandef->center_freq2);
603 r2 = cfg80211_get_chans_dfs_usable(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700604 MHZ_TO_KHZ(chandef->center_freq2),
605 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100606 if (r2 < 0)
607 return false;
608 break;
609 default:
610 WARN_ON(chandef->center_freq2);
611 break;
612 }
613
614 return (r1 + r2 > 0);
615}
616
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530617/*
618 * Checks if center frequency of chan falls with in the bandwidth
619 * range of chandef.
620 */
621bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
622 struct ieee80211_channel *chan)
623{
624 int width;
Johannes Berga67a4892017-10-12 11:23:04 +0200625 u32 freq;
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530626
627 if (chandef->chan->center_freq == chan->center_freq)
628 return true;
629
630 width = cfg80211_chandef_get_width(chandef);
631 if (width <= 20)
632 return false;
633
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530634 for (freq = chandef->center_freq1 - width / 2 + 10;
635 freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
636 if (chan->center_freq == freq)
637 return true;
638 }
639
640 if (!chandef->center_freq2)
641 return false;
642
643 for (freq = chandef->center_freq2 - width / 2 + 10;
644 freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
645 if (chan->center_freq == freq)
646 return true;
647 }
648
649 return false;
650}
651
652bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
653{
654 bool active = false;
655
656 ASSERT_WDEV_LOCK(wdev);
657
658 if (!wdev->chandef.chan)
659 return false;
660
661 switch (wdev->iftype) {
662 case NL80211_IFTYPE_AP:
663 case NL80211_IFTYPE_P2P_GO:
664 active = wdev->beacon_interval != 0;
665 break;
666 case NL80211_IFTYPE_ADHOC:
667 active = wdev->ssid_len != 0;
668 break;
669 case NL80211_IFTYPE_MESH_POINT:
670 active = wdev->mesh_id_len != 0;
671 break;
672 case NL80211_IFTYPE_STATION:
673 case NL80211_IFTYPE_OCB:
674 case NL80211_IFTYPE_P2P_CLIENT:
675 case NL80211_IFTYPE_MONITOR:
676 case NL80211_IFTYPE_AP_VLAN:
677 case NL80211_IFTYPE_WDS:
678 case NL80211_IFTYPE_P2P_DEVICE:
679 /* Can NAN type be considered as beaconing interface? */
680 case NL80211_IFTYPE_NAN:
681 break;
682 case NL80211_IFTYPE_UNSPECIFIED:
683 case NUM_NL80211_IFTYPES:
684 WARN_ON(1);
685 }
686
687 return active;
688}
689
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530690static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
691 struct ieee80211_channel *chan)
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530692{
693 struct wireless_dev *wdev;
694
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530695 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
696 wdev_lock(wdev);
697 if (!cfg80211_beaconing_iface_active(wdev)) {
698 wdev_unlock(wdev);
699 continue;
700 }
701
702 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
703 wdev_unlock(wdev);
704 return true;
705 }
706 wdev_unlock(wdev);
707 }
708
709 return false;
710}
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100711
Vasanthakumar Thiagarajan89766722017-02-27 17:04:35 +0530712bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
713 struct ieee80211_channel *chan)
714{
715 struct cfg80211_registered_device *rdev;
716
717 ASSERT_RTNL();
718
719 if (!(chan->flags & IEEE80211_CHAN_RADAR))
720 return false;
721
722 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
723 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
724 continue;
725
726 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
727 return true;
728 }
729
730 return false;
731}
732
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100733static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
734 u32 center_freq,
735 u32 bandwidth)
736{
737 struct ieee80211_channel *c;
738 u32 freq, start_freq, end_freq;
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300739 bool dfs_offload;
740
741 dfs_offload = wiphy_ext_feature_isset(wiphy,
742 NL80211_EXT_FEATURE_DFS_OFFLOAD);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100743
744 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
745 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
746
747 /*
748 * Check entire range of channels for the bandwidth.
749 * If any channel in between is disabled or has not
750 * had gone through CAC return false
751 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700752 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
753 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100754 if (!c)
755 return false;
756
757 if (c->flags & IEEE80211_CHAN_DISABLED)
758 return false;
759
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300760 if ((c->flags & IEEE80211_CHAN_RADAR) &&
761 (c->dfs_state != NL80211_DFS_AVAILABLE) &&
762 !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100763 return false;
764 }
765
766 return true;
767}
768
769static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
770 const struct cfg80211_chan_def *chandef)
771{
772 int width;
773 int r;
774
775 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
776 return false;
777
778 width = cfg80211_chandef_get_width(chandef);
779 if (width < 0)
780 return false;
781
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700782 r = cfg80211_get_chans_dfs_available(wiphy,
783 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100784 width);
785
786 /* If any of channels unavailable for cf1 just return */
787 if (!r)
788 return r;
789
790 switch (chandef->width) {
791 case NL80211_CHAN_WIDTH_80P80:
792 WARN_ON(!chandef->center_freq2);
793 r = cfg80211_get_chans_dfs_available(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700794 MHZ_TO_KHZ(chandef->center_freq2),
795 width);
Colin Ian King680682d2016-07-17 19:55:27 +0100796 break;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100797 default:
798 WARN_ON(chandef->center_freq2);
799 break;
800 }
801
802 return r;
803}
804
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100805static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
806 u32 center_freq,
807 u32 bandwidth)
808{
809 struct ieee80211_channel *c;
810 u32 start_freq, end_freq, freq;
811 unsigned int dfs_cac_ms = 0;
812
813 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
814 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
815
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700816 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
817 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100818 if (!c)
819 return 0;
820
821 if (c->flags & IEEE80211_CHAN_DISABLED)
822 return 0;
823
824 if (!(c->flags & IEEE80211_CHAN_RADAR))
825 continue;
826
827 if (c->dfs_cac_ms > dfs_cac_ms)
828 dfs_cac_ms = c->dfs_cac_ms;
829 }
830
831 return dfs_cac_ms;
832}
833
834unsigned int
835cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
836 const struct cfg80211_chan_def *chandef)
837{
838 int width;
839 unsigned int t1 = 0, t2 = 0;
840
841 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
842 return 0;
843
844 width = cfg80211_chandef_get_width(chandef);
845 if (width < 0)
846 return 0;
847
848 t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700849 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100850 width);
851
852 if (!chandef->center_freq2)
853 return t1;
854
855 t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700856 MHZ_TO_KHZ(chandef->center_freq2),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100857 width);
858
859 return max(t1, t2);
860}
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100861
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100862static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
863 u32 center_freq, u32 bandwidth,
864 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100865{
866 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200867 u32 freq, start_freq, end_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100868
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100869 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
870 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200871
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700872 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
873 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100874 if (!c || c->flags & prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100875 return false;
876 }
877
878 return true;
879}
880
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300881/* check if the operating channels are valid and supported */
882static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
883 enum ieee80211_edmg_bw_config edmg_bw_config,
884 int primary_channel,
885 struct ieee80211_edmg *edmg_cap)
886{
887 struct ieee80211_channel *chan;
888 int i, freq;
889 int channels_counter = 0;
890
891 if (!edmg_channels && !edmg_bw_config)
892 return true;
893
894 if ((!edmg_channels && edmg_bw_config) ||
895 (edmg_channels && !edmg_bw_config))
896 return false;
897
898 if (!(edmg_channels & BIT(primary_channel - 1)))
899 return false;
900
901 /* 60GHz channels 1..6 */
902 for (i = 0; i < 6; i++) {
903 if (!(edmg_channels & BIT(i)))
904 continue;
905
906 if (!(edmg_cap->channels & BIT(i)))
907 return false;
908
909 channels_counter++;
910
911 freq = ieee80211_channel_to_frequency(i + 1,
912 NL80211_BAND_60GHZ);
913 chan = ieee80211_get_channel(wiphy, freq);
914 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
915 return false;
916 }
917
918 /* IEEE802.11 allows max 4 channels */
919 if (channels_counter > 4)
920 return false;
921
922 /* check bw_config is a subset of what driver supports
923 * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
924 */
925 if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
926 return false;
927
928 if (edmg_bw_config > edmg_cap->bw_config)
929 return false;
930
931 return true;
932}
933
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100934bool cfg80211_chandef_usable(struct wiphy *wiphy,
935 const struct cfg80211_chan_def *chandef,
936 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100937{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100938 struct ieee80211_sta_ht_cap *ht_cap;
939 struct ieee80211_sta_vht_cap *vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300940 struct ieee80211_edmg *edmg_cap;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200941 u32 width, control_freq, cap;
Shay Bar35799942020-08-26 17:31:39 +0300942 bool support_80_80 = false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100943
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100944 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100945 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100946
947 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
948 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300949 edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
950
951 if (edmg_cap->channels &&
952 !cfg80211_edmg_usable(wiphy,
953 chandef->edmg.channels,
954 chandef->edmg.bw_config,
955 chandef->chan->hw_value,
956 edmg_cap))
957 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100958
959 control_freq = chandef->chan->center_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100960
961 switch (chandef->width) {
Thomas Pedersendf78a0c2020-06-01 23:22:47 -0700962 case NL80211_CHAN_WIDTH_1:
963 width = 1;
964 break;
965 case NL80211_CHAN_WIDTH_2:
966 width = 2;
967 break;
968 case NL80211_CHAN_WIDTH_4:
969 width = 4;
970 break;
971 case NL80211_CHAN_WIDTH_8:
972 width = 8;
973 break;
974 case NL80211_CHAN_WIDTH_16:
975 width = 16;
976 break;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200977 case NL80211_CHAN_WIDTH_5:
978 width = 5;
979 break;
980 case NL80211_CHAN_WIDTH_10:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200981 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200982 width = 10;
983 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100984 case NL80211_CHAN_WIDTH_20:
Johannes Bergba8f6a02020-05-28 21:34:40 +0200985 if (!ht_cap->ht_supported &&
986 chandef->chan->band != NL80211_BAND_6GHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100987 return false;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -0500988 fallthrough;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100989 case NL80211_CHAN_WIDTH_20_NOHT:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200990 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100991 width = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500992 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100993 case NL80211_CHAN_WIDTH_40:
994 width = 40;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200995 if (chandef->chan->band == NL80211_BAND_6GHZ)
996 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100997 if (!ht_cap->ht_supported)
998 return false;
999 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
1000 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
1001 return false;
1002 if (chandef->center_freq1 < control_freq &&
1003 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
1004 return false;
1005 if (chandef->center_freq1 > control_freq &&
1006 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
1007 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001008 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001009 case NL80211_CHAN_WIDTH_80P80:
Shay Bar35799942020-08-26 17:31:39 +03001010 cap = vht_cap->cap;
1011 support_80_80 =
1012 (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
1013 (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
1014 cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
1015 u32_get_bits(cap, IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) > 1;
1016 if (chandef->chan->band != NL80211_BAND_6GHZ && !support_80_80)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001017 return false;
Gustavo A. R. Silvadf561f662020-08-23 17:36:59 -05001018 fallthrough;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001019 case NL80211_CHAN_WIDTH_80:
Johannes Bergc7a6ee22012-12-12 17:50:39 +01001020 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001021 width = 80;
Johannes Bergba8f6a02020-05-28 21:34:40 +02001022 if (chandef->chan->band == NL80211_BAND_6GHZ)
1023 break;
1024 if (!vht_cap->vht_supported)
1025 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001026 break;
1027 case NL80211_CHAN_WIDTH_160:
Johannes Bergba8f6a02020-05-28 21:34:40 +02001028 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
1029 width = 160;
1030 if (chandef->chan->band == NL80211_BAND_6GHZ)
1031 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001032 if (!vht_cap->vht_supported)
1033 return false;
Jouni Malinen08f6f142014-12-11 23:48:55 +02001034 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
1035 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
Shay Bar35799942020-08-26 17:31:39 +03001036 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ &&
1037 !(vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001038 return false;
Mark Mentovai09a02fd2010-11-17 16:34:37 -05001039 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001040 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001041 WARN_ON_ONCE(1);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001042 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +03001043 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001044
Johannes Bergc7a6ee22012-12-12 17:50:39 +01001045 /*
1046 * TODO: What if there are only certain 80/160/80+80 MHz channels
1047 * allowed by the driver, or only certain combinations?
1048 * For 40 MHz the driver can set the NO_HT40 flags, but for
1049 * 80/160 MHz and in particular 80+80 MHz this isn't really
1050 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
1051 * no way to cover 80+80 MHz or more complex restrictions.
1052 * Note that such restrictions also need to be advertised to
1053 * userspace, for example for P2P channel selection.
1054 */
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001055
Johannes Berga6662db2012-12-04 20:49:42 +01001056 if (width > 20)
1057 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1058
Simon Wunderlich2f301ab2013-05-16 13:00:28 +02001059 /* 5 and 10 MHz are only defined for the OFDM PHY */
1060 if (width < 20)
1061 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
1062
1063
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001064 if (!cfg80211_secondary_chans_ok(wiphy,
1065 ieee80211_chandef_to_khz(chandef),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001066 width, prohibited_flags))
1067 return false;
1068
1069 if (!chandef->center_freq2)
1070 return true;
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001071 return cfg80211_secondary_chans_ok(wiphy,
1072 MHZ_TO_KHZ(chandef->center_freq2),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001073 width, prohibited_flags);
1074}
1075EXPORT_SYMBOL(cfg80211_chandef_usable);
1076
Ilan Peer174e0cd2014-02-23 09:13:01 +02001077/*
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001078 * Check if the channel can be used under permissive conditions mandated by
1079 * some regulatory bodies, i.e., the channel is marked with
1080 * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
Ilan Peer174e0cd2014-02-23 09:13:01 +02001081 * associated to an AP on the same channel or on the same UNII band
1082 * (assuming that the AP is an authorized master).
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001083 * In addition allow operation on a channel on which indoor operation is
Ilan Peerc8866e52014-02-23 09:13:03 +02001084 * allowed, iff we are currently operating in an indoor environment.
Ilan Peer174e0cd2014-02-23 09:13:01 +02001085 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001086static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
1087 enum nl80211_iftype iftype,
Ilan Peer174e0cd2014-02-23 09:13:01 +02001088 struct ieee80211_channel *chan)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001089{
Avraham Sternbe69c242015-04-27 16:52:16 +03001090 struct wireless_dev *wdev;
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001091 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001092
1093 ASSERT_RTNL();
1094
Masahiro Yamada97f26452016-08-03 13:45:50 -07001095 if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
Ilan Peerc8866e52014-02-23 09:13:03 +02001096 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
1097 return false;
1098
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001099 /* only valid for GO and TDLS off-channel (station/p2p-CL) */
1100 if (iftype != NL80211_IFTYPE_P2P_GO &&
1101 iftype != NL80211_IFTYPE_STATION &&
1102 iftype != NL80211_IFTYPE_P2P_CLIENT)
1103 return false;
1104
Ilan Peerc8866e52014-02-23 09:13:03 +02001105 if (regulatory_indoor_allowed() &&
1106 (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1107 return true;
1108
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001109 if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
Ilan Peer174e0cd2014-02-23 09:13:01 +02001110 return false;
1111
1112 /*
1113 * Generally, it is possible to rely on another device/driver to allow
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001114 * the IR concurrent relaxation, however, since the device can further
Ilan Peer174e0cd2014-02-23 09:13:01 +02001115 * enforce the relaxation (by doing a similar verifications as this),
1116 * and thus fail the GO instantiation, consider only the interfaces of
1117 * the current registered device.
1118 */
Johannes Berg53873f12016-05-03 16:52:04 +03001119 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Ilan Peer174e0cd2014-02-23 09:13:01 +02001120 struct ieee80211_channel *other_chan = NULL;
1121 int r1, r2;
1122
Avraham Sternbe69c242015-04-27 16:52:16 +03001123 wdev_lock(wdev);
1124 if (wdev->iftype == NL80211_IFTYPE_STATION &&
1125 wdev->current_bss)
1126 other_chan = wdev->current_bss->pub.channel;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001127
Avraham Sternbe69c242015-04-27 16:52:16 +03001128 /*
1129 * If a GO already operates on the same GO_CONCURRENT channel,
1130 * this one (maybe the same one) can beacon as well. We allow
1131 * the operation even if the station we relied on with
1132 * GO_CONCURRENT is disconnected now. But then we must make sure
1133 * we're not outdoor on an indoor-only channel.
1134 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001135 if (iftype == NL80211_IFTYPE_P2P_GO &&
1136 wdev->iftype == NL80211_IFTYPE_P2P_GO &&
Avraham Sternbe69c242015-04-27 16:52:16 +03001137 wdev->beacon_interval &&
1138 !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1139 other_chan = wdev->chandef.chan;
1140 wdev_unlock(wdev);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001141
1142 if (!other_chan)
1143 continue;
1144
1145 if (chan == other_chan)
1146 return true;
1147
Arend van Spriel0816e6b2019-08-02 13:31:03 +02001148 if (chan->band != NL80211_BAND_5GHZ &&
1149 chan->band != NL80211_BAND_6GHZ)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001150 continue;
1151
1152 r1 = cfg80211_get_unii(chan->center_freq);
1153 r2 = cfg80211_get_unii(other_chan->center_freq);
1154
Ilan Peer46d53722014-04-23 09:22:58 +03001155 if (r1 != -EINVAL && r1 == r2) {
1156 /*
1157 * At some locations channels 149-165 are considered a
1158 * bundle, but at other locations, e.g., Indonesia,
1159 * channels 149-161 are considered a bundle while
1160 * channel 165 is left out and considered to be in a
1161 * different bundle. Thus, in case that there is a
1162 * station interface connected to an AP on channel 165,
1163 * it is assumed that channels 149-161 are allowed for
1164 * GO operations. However, having a station interface
1165 * connected to an AP on channels 149-161, does not
1166 * allow GO operation on channel 165.
1167 */
1168 if (chan->center_freq == 5825 &&
1169 other_chan->center_freq != 5825)
1170 continue;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001171 return true;
Ilan Peer46d53722014-04-23 09:22:58 +03001172 }
Ilan Peer174e0cd2014-02-23 09:13:01 +02001173 }
1174
1175 return false;
1176}
1177
Arik Nemtsov923b3522015-07-08 15:41:44 +03001178static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
1179 struct cfg80211_chan_def *chandef,
1180 enum nl80211_iftype iftype,
1181 bool check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001182{
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001183 bool res;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001184 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001185 IEEE80211_CHAN_RADAR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001186
Arik Nemtsov923b3522015-07-08 15:41:44 +03001187 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001188
Arik Nemtsov923b3522015-07-08 15:41:44 +03001189 if (check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001190 prohibited_flags |= IEEE80211_CHAN_NO_IR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001191
Luciano Coelho00ec75f2014-05-15 13:05:39 +03001192 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001193 cfg80211_chandef_dfs_available(wiphy, chandef)) {
1194 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
1195 prohibited_flags = IEEE80211_CHAN_DISABLED;
1196 }
1197
1198 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001199
1200 trace_cfg80211_return_bool(res);
1201 return res;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001202}
Arik Nemtsov923b3522015-07-08 15:41:44 +03001203
1204bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
1205 struct cfg80211_chan_def *chandef,
1206 enum nl80211_iftype iftype)
1207{
1208 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
1209}
Johannes Berg683b6d32012-11-08 21:25:48 +01001210EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001211
Arik Nemtsov923b3522015-07-08 15:41:44 +03001212bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
1213 struct cfg80211_chan_def *chandef,
1214 enum nl80211_iftype iftype)
1215{
1216 bool check_no_ir;
1217
1218 ASSERT_RTNL();
1219
1220 /*
1221 * Under certain conditions suggested by some regulatory bodies a
1222 * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
1223 * only if such relaxations are not enabled and the conditions are not
1224 * met.
1225 */
1226 check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
1227 chandef->chan);
1228
1229 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1230}
1231EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
1232
Johannes Berge8c9bd52012-06-06 08:18:22 +02001233int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +01001234 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001235{
Johannes Berge8c9bd52012-06-06 08:18:22 +02001236 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001237 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +02001238 if (!cfg80211_has_monitors_only(rdev))
1239 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001240
Johannes Berg683b6d32012-11-08 21:25:48 +01001241 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001242}
Michal Kazior26ab9a02012-06-29 12:47:00 +02001243
1244void
Johannes Berg8e95ea42012-07-10 19:39:02 +02001245cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +02001246 struct ieee80211_channel **chan,
Michal Kazior9e0e2962014-01-29 14:22:27 +01001247 enum cfg80211_chan_mode *chanmode,
1248 u8 *radar_detect)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001249{
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001250 int ret;
1251
Michal Kazior26ab9a02012-06-29 12:47:00 +02001252 *chan = NULL;
1253 *chanmode = CHAN_MODE_UNDEFINED;
1254
Michal Kazior26ab9a02012-06-29 12:47:00 +02001255 ASSERT_WDEV_LOCK(wdev);
1256
Johannes Berg98104fde2012-06-16 00:19:54 +02001257 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +02001258 return;
1259
1260 switch (wdev->iftype) {
1261 case NL80211_IFTYPE_ADHOC:
1262 if (wdev->current_bss) {
1263 *chan = wdev->current_bss->pub.channel;
Simon Wunderlich5336fa82013-10-07 18:41:05 +02001264 *chanmode = (wdev->ibss_fixed &&
1265 !wdev->ibss_dfs_possible)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001266 ? CHAN_MODE_SHARED
1267 : CHAN_MODE_EXCLUSIVE;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001268
1269 /* consider worst-case - IBSS can try to return to the
1270 * original user-specified channel as creator */
1271 if (wdev->ibss_dfs_possible)
1272 *radar_detect |= BIT(wdev->chandef.width);
Michal Kazior26ab9a02012-06-29 12:47:00 +02001273 return;
1274 }
Johannes Berg0f0094b2013-10-25 12:46:44 +02001275 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001276 case NL80211_IFTYPE_STATION:
1277 case NL80211_IFTYPE_P2P_CLIENT:
1278 if (wdev->current_bss) {
1279 *chan = wdev->current_bss->pub.channel;
1280 *chanmode = CHAN_MODE_SHARED;
1281 return;
1282 }
1283 break;
1284 case NL80211_IFTYPE_AP:
1285 case NL80211_IFTYPE_P2P_GO:
Simon Wunderlich04f39042013-02-08 18:16:19 +01001286 if (wdev->cac_started) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001287 *chan = wdev->chandef.chan;
Simon Wunderlich04f39042013-02-08 18:16:19 +01001288 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001289 *radar_detect |= BIT(wdev->chandef.width);
Simon Wunderlich04f39042013-02-08 18:16:19 +01001290 } else if (wdev->beacon_interval) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001291 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001292 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001293
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001294 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1295 &wdev->chandef,
1296 wdev->iftype);
1297 WARN_ON(ret < 0);
1298 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001299 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001300 }
1301 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001302 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +02001303 if (wdev->mesh_id_len) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001304 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001305 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001306
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001307 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1308 &wdev->chandef,
1309 wdev->iftype);
1310 WARN_ON(ret < 0);
1311 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001312 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001313 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001314 return;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001315 case NL80211_IFTYPE_OCB:
1316 if (wdev->chandef.chan) {
1317 *chan = wdev->chandef.chan;
1318 *chanmode = CHAN_MODE_SHARED;
1319 return;
1320 }
1321 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001322 case NL80211_IFTYPE_MONITOR:
1323 case NL80211_IFTYPE_AP_VLAN:
1324 case NL80211_IFTYPE_WDS:
Johannes Berg98104fde2012-06-16 00:19:54 +02001325 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001326 case NL80211_IFTYPE_NAN:
Johannes Berge7aceef2014-02-12 14:21:15 +01001327 /* these interface types don't really have a channel */
Johannes Berg98104fde2012-06-16 00:19:54 +02001328 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001329 case NL80211_IFTYPE_UNSPECIFIED:
1330 case NUM_NL80211_IFTYPES:
1331 WARN_ON(1);
1332 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001333}