blob: cddf92c5d09eff68cedf85264db2e49ec37096fc [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Johannes Berg59bbb6f2009-08-07 17:22:35 +02002/*
3 * This file contains helper code to handle channel
4 * settings and keeping track of what is possible at
5 * any point in time.
6 *
7 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg2740f0c2014-09-03 15:24:58 +03008 * Copyright 2013-2014 Intel Mobile Communications GmbH
Johannes Bergba8f6a02020-05-28 21:34:40 +02009 * Copyright 2018-2020 Intel Corporation
Johannes Berg59bbb6f2009-08-07 17:22:35 +020010 */
11
Alexander Simon54858ee5b2011-11-30 16:56:32 +010012#include <linux/export.h>
Johannes Berg59bbb6f2009-08-07 17:22:35 +020013#include <net/cfg80211.h>
14#include "core.h"
Hila Gonene35e4d22012-06-27 17:19:42 +030015#include "rdev-ops.h"
Johannes Berg59bbb6f2009-08-07 17:22:35 +020016
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030017static bool cfg80211_valid_60g_freq(u32 freq)
18{
19 return freq >= 58320 && freq <= 70200;
20}
21
Johannes Berg3d9d1d62012-11-08 23:14:50 +010022void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
23 struct ieee80211_channel *chan,
24 enum nl80211_channel_type chan_type)
25{
26 if (WARN_ON(!chan))
27 return;
28
29 chandef->chan = chan;
Thomas Pedersen934f4c72020-04-01 18:18:03 -070030 chandef->freq1_offset = chan->freq_offset;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010031 chandef->center_freq2 = 0;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030032 chandef->edmg.bw_config = 0;
33 chandef->edmg.channels = 0;
Johannes Berg3d9d1d62012-11-08 23:14:50 +010034
35 switch (chan_type) {
36 case NL80211_CHAN_NO_HT:
37 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
38 chandef->center_freq1 = chan->center_freq;
39 break;
40 case NL80211_CHAN_HT20:
41 chandef->width = NL80211_CHAN_WIDTH_20;
42 chandef->center_freq1 = chan->center_freq;
43 break;
44 case NL80211_CHAN_HT40PLUS:
45 chandef->width = NL80211_CHAN_WIDTH_40;
46 chandef->center_freq1 = chan->center_freq + 10;
47 break;
48 case NL80211_CHAN_HT40MINUS:
49 chandef->width = NL80211_CHAN_WIDTH_40;
50 chandef->center_freq1 = chan->center_freq - 10;
51 break;
52 default:
53 WARN_ON(1);
54 }
55}
56EXPORT_SYMBOL(cfg80211_chandef_create);
57
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +030058static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
59{
60 int max_contiguous = 0;
61 int num_of_enabled = 0;
62 int contiguous = 0;
63 int i;
64
65 if (!chandef->edmg.channels || !chandef->edmg.bw_config)
66 return false;
67
68 if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
69 return false;
70
71 for (i = 0; i < 6; i++) {
72 if (chandef->edmg.channels & BIT(i)) {
73 contiguous++;
74 num_of_enabled++;
75 } else {
76 contiguous = 0;
77 }
78
79 max_contiguous = max(contiguous, max_contiguous);
80 }
81 /* basic verification of edmg configuration according to
82 * IEEE P802.11ay/D4.0 section 9.4.2.251
83 */
84 /* check bw_config against contiguous edmg channels */
85 switch (chandef->edmg.bw_config) {
86 case IEEE80211_EDMG_BW_CONFIG_4:
87 case IEEE80211_EDMG_BW_CONFIG_8:
88 case IEEE80211_EDMG_BW_CONFIG_12:
89 if (max_contiguous < 1)
90 return false;
91 break;
92 case IEEE80211_EDMG_BW_CONFIG_5:
93 case IEEE80211_EDMG_BW_CONFIG_9:
94 case IEEE80211_EDMG_BW_CONFIG_13:
95 if (max_contiguous < 2)
96 return false;
97 break;
98 case IEEE80211_EDMG_BW_CONFIG_6:
99 case IEEE80211_EDMG_BW_CONFIG_10:
100 case IEEE80211_EDMG_BW_CONFIG_14:
101 if (max_contiguous < 3)
102 return false;
103 break;
104 case IEEE80211_EDMG_BW_CONFIG_7:
105 case IEEE80211_EDMG_BW_CONFIG_11:
106 case IEEE80211_EDMG_BW_CONFIG_15:
107 if (max_contiguous < 4)
108 return false;
109 break;
110
111 default:
112 return false;
113 }
114
115 /* check bw_config against aggregated (non contiguous) edmg channels */
116 switch (chandef->edmg.bw_config) {
117 case IEEE80211_EDMG_BW_CONFIG_4:
118 case IEEE80211_EDMG_BW_CONFIG_5:
119 case IEEE80211_EDMG_BW_CONFIG_6:
120 case IEEE80211_EDMG_BW_CONFIG_7:
121 break;
122 case IEEE80211_EDMG_BW_CONFIG_8:
123 case IEEE80211_EDMG_BW_CONFIG_9:
124 case IEEE80211_EDMG_BW_CONFIG_10:
125 case IEEE80211_EDMG_BW_CONFIG_11:
126 if (num_of_enabled < 2)
127 return false;
128 break;
129 case IEEE80211_EDMG_BW_CONFIG_12:
130 case IEEE80211_EDMG_BW_CONFIG_13:
131 case IEEE80211_EDMG_BW_CONFIG_14:
132 case IEEE80211_EDMG_BW_CONFIG_15:
133 if (num_of_enabled < 4 || max_contiguous < 2)
134 return false;
135 break;
136 default:
137 return false;
138 }
139
140 return true;
141}
142
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100143bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100144{
145 u32 control_freq;
146
147 if (!chandef->chan)
148 return false;
149
Johannes Bergbe689f682020-04-24 12:01:04 +0200150 if (chandef->freq1_offset >= 1000)
151 return false;
152
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100153 control_freq = chandef->chan->center_freq;
154
155 switch (chandef->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200156 case NL80211_CHAN_WIDTH_5:
157 case NL80211_CHAN_WIDTH_10:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100158 case NL80211_CHAN_WIDTH_20:
159 case NL80211_CHAN_WIDTH_20_NOHT:
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700160 if (ieee80211_chandef_to_khz(chandef) !=
161 ieee80211_channel_to_khz(chandef->chan))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100162 return false;
163 if (chandef->center_freq2)
164 return false;
165 break;
166 case NL80211_CHAN_WIDTH_40:
167 if (chandef->center_freq1 != control_freq + 10 &&
168 chandef->center_freq1 != control_freq - 10)
169 return false;
170 if (chandef->center_freq2)
171 return false;
172 break;
173 case NL80211_CHAN_WIDTH_80P80:
174 if (chandef->center_freq1 != control_freq + 30 &&
175 chandef->center_freq1 != control_freq + 10 &&
176 chandef->center_freq1 != control_freq - 10 &&
177 chandef->center_freq1 != control_freq - 30)
178 return false;
179 if (!chandef->center_freq2)
180 return false;
Johannes Berg9cab3152012-12-14 00:19:08 +0100181 /* adjacent is not allowed -- that's a 160 MHz channel */
182 if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
183 chandef->center_freq2 - chandef->center_freq1 == 80)
184 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100185 break;
186 case NL80211_CHAN_WIDTH_80:
187 if (chandef->center_freq1 != control_freq + 30 &&
188 chandef->center_freq1 != control_freq + 10 &&
189 chandef->center_freq1 != control_freq - 10 &&
190 chandef->center_freq1 != control_freq - 30)
191 return false;
192 if (chandef->center_freq2)
193 return false;
194 break;
195 case NL80211_CHAN_WIDTH_160:
196 if (chandef->center_freq1 != control_freq + 70 &&
197 chandef->center_freq1 != control_freq + 50 &&
198 chandef->center_freq1 != control_freq + 30 &&
199 chandef->center_freq1 != control_freq + 10 &&
200 chandef->center_freq1 != control_freq - 10 &&
201 chandef->center_freq1 != control_freq - 30 &&
202 chandef->center_freq1 != control_freq - 50 &&
203 chandef->center_freq1 != control_freq - 70)
204 return false;
205 if (chandef->center_freq2)
206 return false;
207 break;
208 default:
209 return false;
210 }
211
Masashi Honmaec649fe2019-10-21 16:50:45 +0900212 /* channel 14 is only for IEEE 802.11b */
213 if (chandef->center_freq1 == 2484 &&
214 chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
215 return false;
216
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300217 if (cfg80211_chandef_is_edmg(chandef) &&
218 !cfg80211_edmg_chandef_valid(chandef))
219 return false;
220
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100221 return true;
222}
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100223EXPORT_SYMBOL(cfg80211_chandef_valid);
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100224
225static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
Johannes Bergfc1f48f2014-10-29 17:05:39 +0100226 u32 *pri40, u32 *pri80)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100227{
228 int tmp;
229
230 switch (c->width) {
231 case NL80211_CHAN_WIDTH_40:
232 *pri40 = c->center_freq1;
233 *pri80 = 0;
234 break;
235 case NL80211_CHAN_WIDTH_80:
236 case NL80211_CHAN_WIDTH_80P80:
237 *pri80 = c->center_freq1;
238 /* n_P20 */
239 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
240 /* n_P40 */
241 tmp /= 2;
242 /* freq_P40 */
243 *pri40 = c->center_freq1 - 20 + 40 * tmp;
244 break;
245 case NL80211_CHAN_WIDTH_160:
246 /* n_P20 */
247 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
248 /* n_P40 */
249 tmp /= 2;
250 /* freq_P40 */
251 *pri40 = c->center_freq1 - 60 + 40 * tmp;
252 /* n_P80 */
253 tmp /= 2;
254 *pri80 = c->center_freq1 - 40 + 80 * tmp;
255 break;
256 default:
257 WARN_ON_ONCE(1);
258 }
259}
260
Simon Wunderlich04f39042013-02-08 18:16:19 +0100261static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
262{
263 int width;
264
265 switch (c->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200266 case NL80211_CHAN_WIDTH_5:
267 width = 5;
268 break;
269 case NL80211_CHAN_WIDTH_10:
270 width = 10;
271 break;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100272 case NL80211_CHAN_WIDTH_20:
273 case NL80211_CHAN_WIDTH_20_NOHT:
274 width = 20;
275 break;
276 case NL80211_CHAN_WIDTH_40:
277 width = 40;
278 break;
279 case NL80211_CHAN_WIDTH_80P80:
280 case NL80211_CHAN_WIDTH_80:
281 width = 80;
282 break;
283 case NL80211_CHAN_WIDTH_160:
284 width = 160;
285 break;
286 default:
287 WARN_ON_ONCE(1);
288 return -1;
289 }
290 return width;
291}
292
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100293const struct cfg80211_chan_def *
294cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
295 const struct cfg80211_chan_def *c2)
296{
297 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
298
299 /* If they are identical, return */
300 if (cfg80211_chandef_identical(c1, c2))
301 return c1;
302
303 /* otherwise, must have same control channel */
304 if (c1->chan != c2->chan)
305 return NULL;
306
307 /*
308 * If they have the same width, but aren't identical,
309 * then they can't be compatible.
310 */
311 if (c1->width == c2->width)
312 return NULL;
313
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200314 /*
315 * can't be compatible if one of them is 5 or 10 MHz,
316 * but they don't have the same width.
317 */
318 if (c1->width == NL80211_CHAN_WIDTH_5 ||
319 c1->width == NL80211_CHAN_WIDTH_10 ||
320 c2->width == NL80211_CHAN_WIDTH_5 ||
321 c2->width == NL80211_CHAN_WIDTH_10)
322 return NULL;
323
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100324 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
325 c1->width == NL80211_CHAN_WIDTH_20)
326 return c2;
327
328 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
329 c2->width == NL80211_CHAN_WIDTH_20)
330 return c1;
331
332 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
333 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
334
335 if (c1_pri40 != c2_pri40)
336 return NULL;
337
338 WARN_ON(!c1_pri80 && !c2_pri80);
339 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
340 return NULL;
341
342 if (c1->width > c2->width)
343 return c1;
344 return c2;
345}
346EXPORT_SYMBOL(cfg80211_chandef_compatible);
347
Simon Wunderlich04f39042013-02-08 18:16:19 +0100348static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
349 u32 bandwidth,
350 enum nl80211_dfs_state dfs_state)
351{
352 struct ieee80211_channel *c;
353 u32 freq;
354
355 for (freq = center_freq - bandwidth/2 + 10;
356 freq <= center_freq + bandwidth/2 - 10;
357 freq += 20) {
358 c = ieee80211_get_channel(wiphy, freq);
359 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
360 continue;
361
362 c->dfs_state = dfs_state;
363 c->dfs_state_entered = jiffies;
364 }
365}
366
367void cfg80211_set_dfs_state(struct wiphy *wiphy,
368 const struct cfg80211_chan_def *chandef,
369 enum nl80211_dfs_state dfs_state)
370{
371 int width;
372
373 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
374 return;
375
376 width = cfg80211_chandef_get_width(chandef);
377 if (width < 0)
378 return;
379
380 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
381 width, dfs_state);
382
383 if (!chandef->center_freq2)
384 return;
385 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
386 width, dfs_state);
387}
388
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100389static u32 cfg80211_get_start_freq(u32 center_freq,
390 u32 bandwidth)
391{
392 u32 start_freq;
393
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700394 bandwidth = MHZ_TO_KHZ(bandwidth);
395 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100396 start_freq = center_freq;
397 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700398 start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100399
400 return start_freq;
401}
402
403static u32 cfg80211_get_end_freq(u32 center_freq,
404 u32 bandwidth)
405{
406 u32 end_freq;
407
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700408 bandwidth = MHZ_TO_KHZ(bandwidth);
409 if (bandwidth <= MHZ_TO_KHZ(20))
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100410 end_freq = center_freq;
411 else
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700412 end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100413
414 return end_freq;
415}
416
Simon Wunderlich04f39042013-02-08 18:16:19 +0100417static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
418 u32 center_freq,
419 u32 bandwidth)
420{
421 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200422 u32 freq, start_freq, end_freq;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100423
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100424 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
425 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200426
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700427 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
428 c = ieee80211_get_channel_khz(wiphy, freq);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100429 if (!c)
430 return -EINVAL;
431
432 if (c->flags & IEEE80211_CHAN_RADAR)
433 return 1;
434 }
435 return 0;
436}
437
438
439int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200440 const struct cfg80211_chan_def *chandef,
441 enum nl80211_iftype iftype)
Simon Wunderlich04f39042013-02-08 18:16:19 +0100442{
443 int width;
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200444 int ret;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100445
446 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
447 return -EINVAL;
448
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200449 switch (iftype) {
450 case NL80211_IFTYPE_ADHOC:
451 case NL80211_IFTYPE_AP:
452 case NL80211_IFTYPE_P2P_GO:
453 case NL80211_IFTYPE_MESH_POINT:
454 width = cfg80211_chandef_get_width(chandef);
455 if (width < 0)
456 return -EINVAL;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100457
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200458 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700459 ieee80211_chandef_to_khz(chandef),
460 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200461 if (ret < 0)
462 return ret;
463 else if (ret > 0)
464 return BIT(chandef->width);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100465
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200466 if (!chandef->center_freq2)
467 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100468
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200469 ret = cfg80211_get_chans_dfs_required(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700470 MHZ_TO_KHZ(chandef->center_freq2),
471 width);
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200472 if (ret < 0)
473 return ret;
474 else if (ret > 0)
475 return BIT(chandef->width);
476
477 break;
478 case NL80211_IFTYPE_STATION:
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +0100479 case NL80211_IFTYPE_OCB:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200480 case NL80211_IFTYPE_P2P_CLIENT:
481 case NL80211_IFTYPE_MONITOR:
482 case NL80211_IFTYPE_AP_VLAN:
483 case NL80211_IFTYPE_WDS:
484 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +0300485 case NL80211_IFTYPE_NAN:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200486 break;
Luciano Coelho00ec75f2014-05-15 13:05:39 +0300487 case NL80211_IFTYPE_UNSPECIFIED:
Luciano Coelho2beb6dab2014-02-18 11:40:36 +0200488 case NUM_NL80211_IFTYPES:
489 WARN_ON(1);
490 }
491
492 return 0;
Simon Wunderlich04f39042013-02-08 18:16:19 +0100493}
Simon Wunderlich774f0732013-08-28 13:41:28 +0200494EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
Simon Wunderlich04f39042013-02-08 18:16:19 +0100495
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100496static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
497 u32 center_freq,
498 u32 bandwidth)
499{
500 struct ieee80211_channel *c;
501 u32 freq, start_freq, end_freq;
502 int count = 0;
503
504 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
505 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
506
507 /*
508 * Check entire range of channels for the bandwidth.
509 * Check all channels are DFS channels (DFS_USABLE or
510 * DFS_AVAILABLE). Return number of usable channels
511 * (require CAC). Allow DFS and non-DFS channel mix.
512 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700513 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
514 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100515 if (!c)
516 return -EINVAL;
517
518 if (c->flags & IEEE80211_CHAN_DISABLED)
519 return -EINVAL;
520
521 if (c->flags & IEEE80211_CHAN_RADAR) {
522 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
523 return -EINVAL;
524
525 if (c->dfs_state == NL80211_DFS_USABLE)
526 count++;
527 }
528 }
529
530 return count;
531}
532
533bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
534 const struct cfg80211_chan_def *chandef)
535{
536 int width;
537 int r1, r2 = 0;
538
539 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
540 return false;
541
542 width = cfg80211_chandef_get_width(chandef);
543 if (width < 0)
544 return false;
545
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700546 r1 = cfg80211_get_chans_dfs_usable(wiphy,
547 MHZ_TO_KHZ(chandef->center_freq1),
548 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100549
550 if (r1 < 0)
551 return false;
552
553 switch (chandef->width) {
554 case NL80211_CHAN_WIDTH_80P80:
555 WARN_ON(!chandef->center_freq2);
556 r2 = cfg80211_get_chans_dfs_usable(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700557 MHZ_TO_KHZ(chandef->center_freq2),
558 width);
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100559 if (r2 < 0)
560 return false;
561 break;
562 default:
563 WARN_ON(chandef->center_freq2);
564 break;
565 }
566
567 return (r1 + r2 > 0);
568}
569
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530570/*
571 * Checks if center frequency of chan falls with in the bandwidth
572 * range of chandef.
573 */
574bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
575 struct ieee80211_channel *chan)
576{
577 int width;
Johannes Berga67a4892017-10-12 11:23:04 +0200578 u32 freq;
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530579
580 if (chandef->chan->center_freq == chan->center_freq)
581 return true;
582
583 width = cfg80211_chandef_get_width(chandef);
584 if (width <= 20)
585 return false;
586
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530587 for (freq = chandef->center_freq1 - width / 2 + 10;
588 freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
589 if (chan->center_freq == freq)
590 return true;
591 }
592
593 if (!chandef->center_freq2)
594 return false;
595
596 for (freq = chandef->center_freq2 - width / 2 + 10;
597 freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
598 if (chan->center_freq == freq)
599 return true;
600 }
601
602 return false;
603}
604
605bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
606{
607 bool active = false;
608
609 ASSERT_WDEV_LOCK(wdev);
610
611 if (!wdev->chandef.chan)
612 return false;
613
614 switch (wdev->iftype) {
615 case NL80211_IFTYPE_AP:
616 case NL80211_IFTYPE_P2P_GO:
617 active = wdev->beacon_interval != 0;
618 break;
619 case NL80211_IFTYPE_ADHOC:
620 active = wdev->ssid_len != 0;
621 break;
622 case NL80211_IFTYPE_MESH_POINT:
623 active = wdev->mesh_id_len != 0;
624 break;
625 case NL80211_IFTYPE_STATION:
626 case NL80211_IFTYPE_OCB:
627 case NL80211_IFTYPE_P2P_CLIENT:
628 case NL80211_IFTYPE_MONITOR:
629 case NL80211_IFTYPE_AP_VLAN:
630 case NL80211_IFTYPE_WDS:
631 case NL80211_IFTYPE_P2P_DEVICE:
632 /* Can NAN type be considered as beaconing interface? */
633 case NL80211_IFTYPE_NAN:
634 break;
635 case NL80211_IFTYPE_UNSPECIFIED:
636 case NUM_NL80211_IFTYPES:
637 WARN_ON(1);
638 }
639
640 return active;
641}
642
Vasanthakumar Thiagarajan897667272017-02-27 17:04:35 +0530643static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
644 struct ieee80211_channel *chan)
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530645{
646 struct wireless_dev *wdev;
647
Vasanthakumar Thiagarajanb35a51c2017-02-27 17:04:33 +0530648 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
649 wdev_lock(wdev);
650 if (!cfg80211_beaconing_iface_active(wdev)) {
651 wdev_unlock(wdev);
652 continue;
653 }
654
655 if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
656 wdev_unlock(wdev);
657 return true;
658 }
659 wdev_unlock(wdev);
660 }
661
662 return false;
663}
Janusz Dziedzicfe7c3a12013-11-05 14:48:48 +0100664
Vasanthakumar Thiagarajan897667272017-02-27 17:04:35 +0530665bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
666 struct ieee80211_channel *chan)
667{
668 struct cfg80211_registered_device *rdev;
669
670 ASSERT_RTNL();
671
672 if (!(chan->flags & IEEE80211_CHAN_RADAR))
673 return false;
674
675 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
676 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
677 continue;
678
679 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
680 return true;
681 }
682
683 return false;
684}
685
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100686static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
687 u32 center_freq,
688 u32 bandwidth)
689{
690 struct ieee80211_channel *c;
691 u32 freq, start_freq, end_freq;
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300692 bool dfs_offload;
693
694 dfs_offload = wiphy_ext_feature_isset(wiphy,
695 NL80211_EXT_FEATURE_DFS_OFFLOAD);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100696
697 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
698 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
699
700 /*
701 * Check entire range of channels for the bandwidth.
702 * If any channel in between is disabled or has not
703 * had gone through CAC return false
704 */
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700705 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
706 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100707 if (!c)
708 return false;
709
710 if (c->flags & IEEE80211_CHAN_DISABLED)
711 return false;
712
Dmitry Lebed2c390e42018-03-26 16:36:32 +0300713 if ((c->flags & IEEE80211_CHAN_RADAR) &&
714 (c->dfs_state != NL80211_DFS_AVAILABLE) &&
715 !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100716 return false;
717 }
718
719 return true;
720}
721
722static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
723 const struct cfg80211_chan_def *chandef)
724{
725 int width;
726 int r;
727
728 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
729 return false;
730
731 width = cfg80211_chandef_get_width(chandef);
732 if (width < 0)
733 return false;
734
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700735 r = cfg80211_get_chans_dfs_available(wiphy,
736 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100737 width);
738
739 /* If any of channels unavailable for cf1 just return */
740 if (!r)
741 return r;
742
743 switch (chandef->width) {
744 case NL80211_CHAN_WIDTH_80P80:
745 WARN_ON(!chandef->center_freq2);
746 r = cfg80211_get_chans_dfs_available(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700747 MHZ_TO_KHZ(chandef->center_freq2),
748 width);
Colin Ian King680682d2016-07-17 19:55:27 +0100749 break;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100750 default:
751 WARN_ON(chandef->center_freq2);
752 break;
753 }
754
755 return r;
756}
757
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100758static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
759 u32 center_freq,
760 u32 bandwidth)
761{
762 struct ieee80211_channel *c;
763 u32 start_freq, end_freq, freq;
764 unsigned int dfs_cac_ms = 0;
765
766 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
767 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
768
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700769 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
770 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100771 if (!c)
772 return 0;
773
774 if (c->flags & IEEE80211_CHAN_DISABLED)
775 return 0;
776
777 if (!(c->flags & IEEE80211_CHAN_RADAR))
778 continue;
779
780 if (c->dfs_cac_ms > dfs_cac_ms)
781 dfs_cac_ms = c->dfs_cac_ms;
782 }
783
784 return dfs_cac_ms;
785}
786
787unsigned int
788cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
789 const struct cfg80211_chan_def *chandef)
790{
791 int width;
792 unsigned int t1 = 0, t2 = 0;
793
794 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
795 return 0;
796
797 width = cfg80211_chandef_get_width(chandef);
798 if (width < 0)
799 return 0;
800
801 t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700802 MHZ_TO_KHZ(chandef->center_freq1),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100803 width);
804
805 if (!chandef->center_freq2)
806 return t1;
807
808 t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700809 MHZ_TO_KHZ(chandef->center_freq2),
Janusz Dziedzic31559f32014-02-21 19:46:13 +0100810 width);
811
812 return max(t1, t2);
813}
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100814
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100815static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
816 u32 center_freq, u32 bandwidth,
817 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100818{
819 struct ieee80211_channel *c;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200820 u32 freq, start_freq, end_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100821
Janusz Dziedzic40d1ba62013-11-05 14:48:47 +0100822 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
823 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200824
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700825 for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
826 c = ieee80211_get_channel_khz(wiphy, freq);
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +0100827 if (!c || c->flags & prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100828 return false;
829 }
830
831 return true;
832}
833
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300834/* check if the operating channels are valid and supported */
835static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
836 enum ieee80211_edmg_bw_config edmg_bw_config,
837 int primary_channel,
838 struct ieee80211_edmg *edmg_cap)
839{
840 struct ieee80211_channel *chan;
841 int i, freq;
842 int channels_counter = 0;
843
844 if (!edmg_channels && !edmg_bw_config)
845 return true;
846
847 if ((!edmg_channels && edmg_bw_config) ||
848 (edmg_channels && !edmg_bw_config))
849 return false;
850
851 if (!(edmg_channels & BIT(primary_channel - 1)))
852 return false;
853
854 /* 60GHz channels 1..6 */
855 for (i = 0; i < 6; i++) {
856 if (!(edmg_channels & BIT(i)))
857 continue;
858
859 if (!(edmg_cap->channels & BIT(i)))
860 return false;
861
862 channels_counter++;
863
864 freq = ieee80211_channel_to_frequency(i + 1,
865 NL80211_BAND_60GHZ);
866 chan = ieee80211_get_channel(wiphy, freq);
867 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
868 return false;
869 }
870
871 /* IEEE802.11 allows max 4 channels */
872 if (channels_counter > 4)
873 return false;
874
875 /* check bw_config is a subset of what driver supports
876 * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
877 */
878 if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
879 return false;
880
881 if (edmg_bw_config > edmg_cap->bw_config)
882 return false;
883
884 return true;
885}
886
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100887bool cfg80211_chandef_usable(struct wiphy *wiphy,
888 const struct cfg80211_chan_def *chandef,
889 u32 prohibited_flags)
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100890{
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100891 struct ieee80211_sta_ht_cap *ht_cap;
892 struct ieee80211_sta_vht_cap *vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300893 struct ieee80211_edmg *edmg_cap;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200894 u32 width, control_freq, cap;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100895
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100896 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100897 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100898
899 ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
900 vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
Alexei Avshalom Lazar2a380752019-08-18 17:35:17 +0300901 edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
902
903 if (edmg_cap->channels &&
904 !cfg80211_edmg_usable(wiphy,
905 chandef->edmg.channels,
906 chandef->edmg.bw_config,
907 chandef->chan->hw_value,
908 edmg_cap))
909 return false;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100910
911 control_freq = chandef->chan->center_freq;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100912
913 switch (chandef->width) {
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200914 case NL80211_CHAN_WIDTH_5:
915 width = 5;
916 break;
917 case NL80211_CHAN_WIDTH_10:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200918 prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200919 width = 10;
920 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100921 case NL80211_CHAN_WIDTH_20:
Johannes Bergba8f6a02020-05-28 21:34:40 +0200922 if (!ht_cap->ht_supported &&
923 chandef->chan->band != NL80211_BAND_6GHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100924 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200925 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100926 case NL80211_CHAN_WIDTH_20_NOHT:
Rostislav Lisovyea077c12014-04-15 14:37:55 +0200927 prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100928 width = 20;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500929 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100930 case NL80211_CHAN_WIDTH_40:
931 width = 40;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200932 if (chandef->chan->band == NL80211_BAND_6GHZ)
933 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100934 if (!ht_cap->ht_supported)
935 return false;
936 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
937 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
938 return false;
939 if (chandef->center_freq1 < control_freq &&
940 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
941 return false;
942 if (chandef->center_freq1 > control_freq &&
943 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
944 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100945 break;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100946 case NL80211_CHAN_WIDTH_80P80:
Jouni Malinen08f6f142014-12-11 23:48:55 +0200947 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200948 if (chandef->chan->band != NL80211_BAND_6GHZ &&
949 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100950 return false;
Luca Coelho925b5972018-12-15 11:03:21 +0200951 /* fall through */
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100952 case NL80211_CHAN_WIDTH_80:
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100953 prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100954 width = 80;
Johannes Bergba8f6a02020-05-28 21:34:40 +0200955 if (chandef->chan->band == NL80211_BAND_6GHZ)
956 break;
957 if (!vht_cap->vht_supported)
958 return false;
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100959 break;
960 case NL80211_CHAN_WIDTH_160:
Johannes Bergba8f6a02020-05-28 21:34:40 +0200961 prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
962 width = 160;
963 if (chandef->chan->band == NL80211_BAND_6GHZ)
964 break;
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100965 if (!vht_cap->vht_supported)
966 return false;
Jouni Malinen08f6f142014-12-11 23:48:55 +0200967 cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
968 if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
969 cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100970 return false;
Mark Mentovai09a02fd2010-11-17 16:34:37 -0500971 break;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800972 default:
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100973 WARN_ON_ONCE(1);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800974 return false;
Beni Lev4ee3e062012-08-27 12:49:39 +0300975 }
Luis R. Rodriguez9236d832010-11-12 16:31:23 -0800976
Johannes Bergc7a6ee22012-12-12 17:50:39 +0100977 /*
978 * TODO: What if there are only certain 80/160/80+80 MHz channels
979 * allowed by the driver, or only certain combinations?
980 * For 40 MHz the driver can set the NO_HT40 flags, but for
981 * 80/160 MHz and in particular 80+80 MHz this isn't really
982 * feasible and we only have NO_80MHZ/NO_160MHZ so far but
983 * no way to cover 80+80 MHz or more complex restrictions.
984 * Note that such restrictions also need to be advertised to
985 * userspace, for example for P2P channel selection.
986 */
Johannes Berg3d9d1d62012-11-08 23:14:50 +0100987
Johannes Berga6662db2012-12-04 20:49:42 +0100988 if (width > 20)
989 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
990
Simon Wunderlich2f301ab2013-05-16 13:00:28 +0200991 /* 5 and 10 MHz are only defined for the OFDM PHY */
992 if (width < 20)
993 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
994
995
Thomas Pedersen934f4c72020-04-01 18:18:03 -0700996 if (!cfg80211_secondary_chans_ok(wiphy,
997 ieee80211_chandef_to_khz(chandef),
Johannes Berg9f5e8f62012-11-22 16:59:45 +0100998 width, prohibited_flags))
999 return false;
1000
1001 if (!chandef->center_freq2)
1002 return true;
Thomas Pedersen934f4c72020-04-01 18:18:03 -07001003 return cfg80211_secondary_chans_ok(wiphy,
1004 MHZ_TO_KHZ(chandef->center_freq2),
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001005 width, prohibited_flags);
1006}
1007EXPORT_SYMBOL(cfg80211_chandef_usable);
1008
Ilan Peer174e0cd2014-02-23 09:13:01 +02001009/*
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001010 * Check if the channel can be used under permissive conditions mandated by
1011 * some regulatory bodies, i.e., the channel is marked with
1012 * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
Ilan Peer174e0cd2014-02-23 09:13:01 +02001013 * associated to an AP on the same channel or on the same UNII band
1014 * (assuming that the AP is an authorized master).
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001015 * In addition allow operation on a channel on which indoor operation is
Ilan Peerc8866e52014-02-23 09:13:03 +02001016 * allowed, iff we are currently operating in an indoor environment.
Ilan Peer174e0cd2014-02-23 09:13:01 +02001017 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001018static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
1019 enum nl80211_iftype iftype,
Ilan Peer174e0cd2014-02-23 09:13:01 +02001020 struct ieee80211_channel *chan)
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001021{
Avraham Sternbe69c242015-04-27 16:52:16 +03001022 struct wireless_dev *wdev;
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001023 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001024
1025 ASSERT_RTNL();
1026
Masahiro Yamada97f26452016-08-03 13:45:50 -07001027 if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
Ilan Peerc8866e52014-02-23 09:13:03 +02001028 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
1029 return false;
1030
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001031 /* only valid for GO and TDLS off-channel (station/p2p-CL) */
1032 if (iftype != NL80211_IFTYPE_P2P_GO &&
1033 iftype != NL80211_IFTYPE_STATION &&
1034 iftype != NL80211_IFTYPE_P2P_CLIENT)
1035 return false;
1036
Ilan Peerc8866e52014-02-23 09:13:03 +02001037 if (regulatory_indoor_allowed() &&
1038 (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1039 return true;
1040
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001041 if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
Ilan Peer174e0cd2014-02-23 09:13:01 +02001042 return false;
1043
1044 /*
1045 * Generally, it is possible to rely on another device/driver to allow
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001046 * the IR concurrent relaxation, however, since the device can further
Ilan Peer174e0cd2014-02-23 09:13:01 +02001047 * enforce the relaxation (by doing a similar verifications as this),
1048 * and thus fail the GO instantiation, consider only the interfaces of
1049 * the current registered device.
1050 */
Johannes Berg53873f12016-05-03 16:52:04 +03001051 list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
Ilan Peer174e0cd2014-02-23 09:13:01 +02001052 struct ieee80211_channel *other_chan = NULL;
1053 int r1, r2;
1054
Avraham Sternbe69c242015-04-27 16:52:16 +03001055 wdev_lock(wdev);
1056 if (wdev->iftype == NL80211_IFTYPE_STATION &&
1057 wdev->current_bss)
1058 other_chan = wdev->current_bss->pub.channel;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001059
Avraham Sternbe69c242015-04-27 16:52:16 +03001060 /*
1061 * If a GO already operates on the same GO_CONCURRENT channel,
1062 * this one (maybe the same one) can beacon as well. We allow
1063 * the operation even if the station we relied on with
1064 * GO_CONCURRENT is disconnected now. But then we must make sure
1065 * we're not outdoor on an indoor-only channel.
1066 */
Arik Nemtsov06f207f2015-05-06 16:28:31 +03001067 if (iftype == NL80211_IFTYPE_P2P_GO &&
1068 wdev->iftype == NL80211_IFTYPE_P2P_GO &&
Avraham Sternbe69c242015-04-27 16:52:16 +03001069 wdev->beacon_interval &&
1070 !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1071 other_chan = wdev->chandef.chan;
1072 wdev_unlock(wdev);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001073
1074 if (!other_chan)
1075 continue;
1076
1077 if (chan == other_chan)
1078 return true;
1079
Arend van Spriel0816e6b2019-08-02 13:31:03 +02001080 if (chan->band != NL80211_BAND_5GHZ &&
1081 chan->band != NL80211_BAND_6GHZ)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001082 continue;
1083
1084 r1 = cfg80211_get_unii(chan->center_freq);
1085 r2 = cfg80211_get_unii(other_chan->center_freq);
1086
Ilan Peer46d53722014-04-23 09:22:58 +03001087 if (r1 != -EINVAL && r1 == r2) {
1088 /*
1089 * At some locations channels 149-165 are considered a
1090 * bundle, but at other locations, e.g., Indonesia,
1091 * channels 149-161 are considered a bundle while
1092 * channel 165 is left out and considered to be in a
1093 * different bundle. Thus, in case that there is a
1094 * station interface connected to an AP on channel 165,
1095 * it is assumed that channels 149-161 are allowed for
1096 * GO operations. However, having a station interface
1097 * connected to an AP on channels 149-161, does not
1098 * allow GO operation on channel 165.
1099 */
1100 if (chan->center_freq == 5825 &&
1101 other_chan->center_freq != 5825)
1102 continue;
Ilan Peer174e0cd2014-02-23 09:13:01 +02001103 return true;
Ilan Peer46d53722014-04-23 09:22:58 +03001104 }
Ilan Peer174e0cd2014-02-23 09:13:01 +02001105 }
1106
1107 return false;
1108}
1109
Arik Nemtsov923b3522015-07-08 15:41:44 +03001110static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
1111 struct cfg80211_chan_def *chandef,
1112 enum nl80211_iftype iftype,
1113 bool check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001114{
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001115 bool res;
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001116 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001117 IEEE80211_CHAN_RADAR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001118
Arik Nemtsov923b3522015-07-08 15:41:44 +03001119 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
Ilan Peer174e0cd2014-02-23 09:13:01 +02001120
Arik Nemtsov923b3522015-07-08 15:41:44 +03001121 if (check_no_ir)
Ilan Peer174e0cd2014-02-23 09:13:01 +02001122 prohibited_flags |= IEEE80211_CHAN_NO_IR;
Johannes Berg9f5e8f62012-11-22 16:59:45 +01001123
Luciano Coelho00ec75f2014-05-15 13:05:39 +03001124 if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
Janusz Dziedzic6bc54fb2013-11-06 13:55:53 +01001125 cfg80211_chandef_dfs_available(wiphy, chandef)) {
1126 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
1127 prohibited_flags = IEEE80211_CHAN_DISABLED;
1128 }
1129
1130 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
Johannes Berg3d9d1d62012-11-08 23:14:50 +01001131
1132 trace_cfg80211_return_bool(res);
1133 return res;
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001134}
Arik Nemtsov923b3522015-07-08 15:41:44 +03001135
1136bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
1137 struct cfg80211_chan_def *chandef,
1138 enum nl80211_iftype iftype)
1139{
1140 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
1141}
Johannes Berg683b6d32012-11-08 21:25:48 +01001142EXPORT_SYMBOL(cfg80211_reg_can_beacon);
Luis R. Rodriguez9236d832010-11-12 16:31:23 -08001143
Arik Nemtsov923b3522015-07-08 15:41:44 +03001144bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
1145 struct cfg80211_chan_def *chandef,
1146 enum nl80211_iftype iftype)
1147{
1148 bool check_no_ir;
1149
1150 ASSERT_RTNL();
1151
1152 /*
1153 * Under certain conditions suggested by some regulatory bodies a
1154 * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
1155 * only if such relaxations are not enabled and the conditions are not
1156 * met.
1157 */
1158 check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
1159 chandef->chan);
1160
1161 return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1162}
1163EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
1164
Johannes Berge8c9bd52012-06-06 08:18:22 +02001165int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
Johannes Berg683b6d32012-11-08 21:25:48 +01001166 struct cfg80211_chan_def *chandef)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001167{
Johannes Berge8c9bd52012-06-06 08:18:22 +02001168 if (!rdev->ops->set_monitor_channel)
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001169 return -EOPNOTSUPP;
Michal Kazior4f03c1e2012-06-29 12:47:03 +02001170 if (!cfg80211_has_monitors_only(rdev))
1171 return -EBUSY;
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001172
Johannes Berg683b6d32012-11-08 21:25:48 +01001173 return rdev_set_monitor_channel(rdev, chandef);
Johannes Berg59bbb6f2009-08-07 17:22:35 +02001174}
Michal Kazior26ab9a02012-06-29 12:47:00 +02001175
1176void
Johannes Berg8e95ea42012-07-10 19:39:02 +02001177cfg80211_get_chan_state(struct wireless_dev *wdev,
Michal Kazior26ab9a02012-06-29 12:47:00 +02001178 struct ieee80211_channel **chan,
Michal Kazior9e0e2962014-01-29 14:22:27 +01001179 enum cfg80211_chan_mode *chanmode,
1180 u8 *radar_detect)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001181{
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001182 int ret;
1183
Michal Kazior26ab9a02012-06-29 12:47:00 +02001184 *chan = NULL;
1185 *chanmode = CHAN_MODE_UNDEFINED;
1186
Michal Kazior26ab9a02012-06-29 12:47:00 +02001187 ASSERT_WDEV_LOCK(wdev);
1188
Johannes Berg98104fde2012-06-16 00:19:54 +02001189 if (wdev->netdev && !netif_running(wdev->netdev))
Michal Kazior26ab9a02012-06-29 12:47:00 +02001190 return;
1191
1192 switch (wdev->iftype) {
1193 case NL80211_IFTYPE_ADHOC:
1194 if (wdev->current_bss) {
1195 *chan = wdev->current_bss->pub.channel;
Simon Wunderlich5336fa82013-10-07 18:41:05 +02001196 *chanmode = (wdev->ibss_fixed &&
1197 !wdev->ibss_dfs_possible)
Michal Kazior26ab9a02012-06-29 12:47:00 +02001198 ? CHAN_MODE_SHARED
1199 : CHAN_MODE_EXCLUSIVE;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001200
1201 /* consider worst-case - IBSS can try to return to the
1202 * original user-specified channel as creator */
1203 if (wdev->ibss_dfs_possible)
1204 *radar_detect |= BIT(wdev->chandef.width);
Michal Kazior26ab9a02012-06-29 12:47:00 +02001205 return;
1206 }
Johannes Berg0f0094b2013-10-25 12:46:44 +02001207 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001208 case NL80211_IFTYPE_STATION:
1209 case NL80211_IFTYPE_P2P_CLIENT:
1210 if (wdev->current_bss) {
1211 *chan = wdev->current_bss->pub.channel;
1212 *chanmode = CHAN_MODE_SHARED;
1213 return;
1214 }
1215 break;
1216 case NL80211_IFTYPE_AP:
1217 case NL80211_IFTYPE_P2P_GO:
Simon Wunderlich04f39042013-02-08 18:16:19 +01001218 if (wdev->cac_started) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001219 *chan = wdev->chandef.chan;
Simon Wunderlich04f39042013-02-08 18:16:19 +01001220 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001221 *radar_detect |= BIT(wdev->chandef.width);
Simon Wunderlich04f39042013-02-08 18:16:19 +01001222 } else if (wdev->beacon_interval) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001223 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001224 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001225
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001226 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1227 &wdev->chandef,
1228 wdev->iftype);
1229 WARN_ON(ret < 0);
1230 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001231 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001232 }
1233 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001234 case NL80211_IFTYPE_MESH_POINT:
Felix Fietkauf53594a2012-07-12 16:10:02 +02001235 if (wdev->mesh_id_len) {
Michal Kazior9e0e2962014-01-29 14:22:27 +01001236 *chan = wdev->chandef.chan;
Felix Fietkauf53594a2012-07-12 16:10:02 +02001237 *chanmode = CHAN_MODE_SHARED;
Michal Kazior9e0e2962014-01-29 14:22:27 +01001238
Luciano Coelho2beb6dab2014-02-18 11:40:36 +02001239 ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1240 &wdev->chandef,
1241 wdev->iftype);
1242 WARN_ON(ret < 0);
1243 if (ret > 0)
Michal Kazior9e0e2962014-01-29 14:22:27 +01001244 *radar_detect |= BIT(wdev->chandef.width);
Felix Fietkauf53594a2012-07-12 16:10:02 +02001245 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001246 return;
Rostislav Lisovy6e0bd6c2014-11-03 10:33:18 +01001247 case NL80211_IFTYPE_OCB:
1248 if (wdev->chandef.chan) {
1249 *chan = wdev->chandef.chan;
1250 *chanmode = CHAN_MODE_SHARED;
1251 return;
1252 }
1253 break;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001254 case NL80211_IFTYPE_MONITOR:
1255 case NL80211_IFTYPE_AP_VLAN:
1256 case NL80211_IFTYPE_WDS:
Johannes Berg98104fde2012-06-16 00:19:54 +02001257 case NL80211_IFTYPE_P2P_DEVICE:
Ayala Bekercb3b7d82016-09-20 17:31:13 +03001258 case NL80211_IFTYPE_NAN:
Johannes Berge7aceef42014-02-12 14:21:15 +01001259 /* these interface types don't really have a channel */
Johannes Berg98104fde2012-06-16 00:19:54 +02001260 return;
Michal Kazior26ab9a02012-06-29 12:47:00 +02001261 case NL80211_IFTYPE_UNSPECIFIED:
1262 case NUM_NL80211_IFTYPES:
1263 WARN_ON(1);
1264 }
Michal Kazior26ab9a02012-06-29 12:47:00 +02001265}