Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
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>
8 : : * Copyright 2013-2014 Intel Mobile Communications GmbH
9 : : * Copyright 2018 Intel Corporation
10 : : */
11 : :
12 : : #include <linux/export.h>
13 : : #include <net/cfg80211.h>
14 : : #include "core.h"
15 : : #include "rdev-ops.h"
16 : :
17 : : static bool cfg80211_valid_60g_freq(u32 freq)
18 : : {
19 : 0 : return freq >= 58320 && freq <= 70200;
20 : : }
21 : :
22 : 0 : void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
23 : : struct ieee80211_channel *chan,
24 : : enum nl80211_channel_type chan_type)
25 : : {
26 [ # # # # ]: 0 : if (WARN_ON(!chan))
27 : 0 : return;
28 : :
29 : 0 : chandef->chan = chan;
30 : 0 : chandef->center_freq2 = 0;
31 : 0 : chandef->edmg.bw_config = 0;
32 : 0 : chandef->edmg.channels = 0;
33 : :
34 [ # # # # : 0 : switch (chan_type) {
# ]
35 : : case NL80211_CHAN_NO_HT:
36 : 0 : chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
37 : 0 : chandef->center_freq1 = chan->center_freq;
38 : 0 : break;
39 : : case NL80211_CHAN_HT20:
40 : 0 : chandef->width = NL80211_CHAN_WIDTH_20;
41 : 0 : chandef->center_freq1 = chan->center_freq;
42 : 0 : break;
43 : : case NL80211_CHAN_HT40PLUS:
44 : 0 : chandef->width = NL80211_CHAN_WIDTH_40;
45 : 0 : chandef->center_freq1 = chan->center_freq + 10;
46 : 0 : break;
47 : : case NL80211_CHAN_HT40MINUS:
48 : 0 : chandef->width = NL80211_CHAN_WIDTH_40;
49 : 0 : chandef->center_freq1 = chan->center_freq - 10;
50 : 0 : break;
51 : : default:
52 : 0 : WARN_ON(1);
53 : : }
54 : : }
55 : : EXPORT_SYMBOL(cfg80211_chandef_create);
56 : :
57 : 0 : static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
58 : : {
59 : : int max_contiguous = 0;
60 : : int num_of_enabled = 0;
61 : : int contiguous = 0;
62 : : int i;
63 : :
64 [ # # # # ]: 0 : if (!chandef->edmg.channels || !chandef->edmg.bw_config)
65 : : return false;
66 : :
67 [ # # ]: 0 : if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
68 : : return false;
69 : :
70 [ # # ]: 0 : for (i = 0; i < 6; i++) {
71 [ # # ]: 0 : if (chandef->edmg.channels & BIT(i)) {
72 : 0 : contiguous++;
73 : 0 : num_of_enabled++;
74 : : } else {
75 : : contiguous = 0;
76 : : }
77 : :
78 : 0 : max_contiguous = max(contiguous, max_contiguous);
79 : : }
80 : : /* basic verification of edmg configuration according to
81 : : * IEEE P802.11ay/D4.0 section 9.4.2.251
82 : : */
83 : : /* check bw_config against contiguous edmg channels */
84 [ # # # # : 0 : switch (chandef->edmg.bw_config) {
# ]
85 : : case IEEE80211_EDMG_BW_CONFIG_4:
86 : : case IEEE80211_EDMG_BW_CONFIG_8:
87 : : case IEEE80211_EDMG_BW_CONFIG_12:
88 [ # # ]: 0 : if (max_contiguous < 1)
89 : : return false;
90 : : break;
91 : : case IEEE80211_EDMG_BW_CONFIG_5:
92 : : case IEEE80211_EDMG_BW_CONFIG_9:
93 : : case IEEE80211_EDMG_BW_CONFIG_13:
94 [ # # ]: 0 : if (max_contiguous < 2)
95 : : return false;
96 : : break;
97 : : case IEEE80211_EDMG_BW_CONFIG_6:
98 : : case IEEE80211_EDMG_BW_CONFIG_10:
99 : : case IEEE80211_EDMG_BW_CONFIG_14:
100 [ # # ]: 0 : if (max_contiguous < 3)
101 : : return false;
102 : : break;
103 : : case IEEE80211_EDMG_BW_CONFIG_7:
104 : : case IEEE80211_EDMG_BW_CONFIG_11:
105 : : case IEEE80211_EDMG_BW_CONFIG_15:
106 [ # # ]: 0 : if (max_contiguous < 4)
107 : : return false;
108 : : break;
109 : :
110 : : default:
111 : : return false;
112 : : }
113 : :
114 : : /* check bw_config against aggregated (non contiguous) edmg channels */
115 [ # # # # ]: 0 : switch (chandef->edmg.bw_config) {
116 : : case IEEE80211_EDMG_BW_CONFIG_4:
117 : : case IEEE80211_EDMG_BW_CONFIG_5:
118 : : case IEEE80211_EDMG_BW_CONFIG_6:
119 : : case IEEE80211_EDMG_BW_CONFIG_7:
120 : : break;
121 : : case IEEE80211_EDMG_BW_CONFIG_8:
122 : : case IEEE80211_EDMG_BW_CONFIG_9:
123 : : case IEEE80211_EDMG_BW_CONFIG_10:
124 : : case IEEE80211_EDMG_BW_CONFIG_11:
125 [ # # ]: 0 : if (num_of_enabled < 2)
126 : : return false;
127 : : break;
128 : : case IEEE80211_EDMG_BW_CONFIG_12:
129 : : case IEEE80211_EDMG_BW_CONFIG_13:
130 : : case IEEE80211_EDMG_BW_CONFIG_14:
131 : : case IEEE80211_EDMG_BW_CONFIG_15:
132 [ # # ]: 0 : if (num_of_enabled < 4 || max_contiguous < 2)
133 : : return false;
134 : : break;
135 : : default:
136 : : return false;
137 : : }
138 : :
139 : 0 : return true;
140 : : }
141 : :
142 : 0 : bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
143 : : {
144 : : u32 control_freq;
145 : :
146 [ # # ]: 0 : if (!chandef->chan)
147 : : return false;
148 : :
149 : 0 : control_freq = chandef->chan->center_freq;
150 : :
151 [ # # # # : 0 : switch (chandef->width) {
# # ]
152 : : case NL80211_CHAN_WIDTH_5:
153 : : case NL80211_CHAN_WIDTH_10:
154 : : case NL80211_CHAN_WIDTH_20:
155 : : case NL80211_CHAN_WIDTH_20_NOHT:
156 [ # # ]: 0 : if (chandef->center_freq1 != control_freq)
157 : : return false;
158 [ # # ]: 0 : if (chandef->center_freq2)
159 : : return false;
160 : : break;
161 : : case NL80211_CHAN_WIDTH_40:
162 [ # # # # ]: 0 : if (chandef->center_freq1 != control_freq + 10 &&
163 : 0 : chandef->center_freq1 != control_freq - 10)
164 : : return false;
165 [ # # ]: 0 : if (chandef->center_freq2)
166 : : return false;
167 : : break;
168 : : case NL80211_CHAN_WIDTH_80P80:
169 [ # # # # ]: 0 : if (chandef->center_freq1 != control_freq + 30 &&
170 [ # # ]: 0 : chandef->center_freq1 != control_freq + 10 &&
171 [ # # ]: 0 : chandef->center_freq1 != control_freq - 10 &&
172 : 0 : chandef->center_freq1 != control_freq - 30)
173 : : return false;
174 [ # # ]: 0 : if (!chandef->center_freq2)
175 : : return false;
176 : : /* adjacent is not allowed -- that's a 160 MHz channel */
177 [ # # # # ]: 0 : if (chandef->center_freq1 - chandef->center_freq2 == 80 ||
178 : 0 : chandef->center_freq2 - chandef->center_freq1 == 80)
179 : : return false;
180 : : break;
181 : : case NL80211_CHAN_WIDTH_80:
182 [ # # # # ]: 0 : if (chandef->center_freq1 != control_freq + 30 &&
183 [ # # ]: 0 : chandef->center_freq1 != control_freq + 10 &&
184 [ # # ]: 0 : chandef->center_freq1 != control_freq - 10 &&
185 : 0 : chandef->center_freq1 != control_freq - 30)
186 : : return false;
187 [ # # ]: 0 : if (chandef->center_freq2)
188 : : return false;
189 : : break;
190 : : case NL80211_CHAN_WIDTH_160:
191 [ # # # # ]: 0 : if (chandef->center_freq1 != control_freq + 70 &&
192 [ # # ]: 0 : chandef->center_freq1 != control_freq + 50 &&
193 [ # # ]: 0 : chandef->center_freq1 != control_freq + 30 &&
194 [ # # ]: 0 : chandef->center_freq1 != control_freq + 10 &&
195 [ # # ]: 0 : chandef->center_freq1 != control_freq - 10 &&
196 [ # # ]: 0 : chandef->center_freq1 != control_freq - 30 &&
197 [ # # ]: 0 : chandef->center_freq1 != control_freq - 50 &&
198 : 0 : chandef->center_freq1 != control_freq - 70)
199 : : return false;
200 [ # # ]: 0 : if (chandef->center_freq2)
201 : : return false;
202 : : break;
203 : : default:
204 : : return false;
205 : : }
206 : :
207 : : /* channel 14 is only for IEEE 802.11b */
208 [ # # # # ]: 0 : if (chandef->center_freq1 == 2484 &&
209 : : chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
210 : : return false;
211 : :
212 [ # # # # ]: 0 : if (cfg80211_chandef_is_edmg(chandef) &&
213 : 0 : !cfg80211_edmg_chandef_valid(chandef))
214 : : return false;
215 : :
216 : 0 : return true;
217 : : }
218 : : EXPORT_SYMBOL(cfg80211_chandef_valid);
219 : :
220 : 0 : static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
221 : : u32 *pri40, u32 *pri80)
222 : : {
223 : : int tmp;
224 : :
225 [ # # # # ]: 0 : switch (c->width) {
226 : : case NL80211_CHAN_WIDTH_40:
227 : 0 : *pri40 = c->center_freq1;
228 : 0 : *pri80 = 0;
229 : 0 : break;
230 : : case NL80211_CHAN_WIDTH_80:
231 : : case NL80211_CHAN_WIDTH_80P80:
232 : 0 : *pri80 = c->center_freq1;
233 : : /* n_P20 */
234 : 0 : tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
235 : : /* n_P40 */
236 : 0 : tmp /= 2;
237 : : /* freq_P40 */
238 : 0 : *pri40 = c->center_freq1 - 20 + 40 * tmp;
239 : 0 : break;
240 : : case NL80211_CHAN_WIDTH_160:
241 : : /* n_P20 */
242 : 0 : tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
243 : : /* n_P40 */
244 : 0 : tmp /= 2;
245 : : /* freq_P40 */
246 : 0 : *pri40 = c->center_freq1 - 60 + 40 * tmp;
247 : : /* n_P80 */
248 : 0 : tmp /= 2;
249 : 0 : *pri80 = c->center_freq1 - 40 + 80 * tmp;
250 : 0 : break;
251 : : default:
252 [ # # ]: 0 : WARN_ON_ONCE(1);
253 : : }
254 : 0 : }
255 : :
256 : 0 : static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
257 : : {
258 : : int width;
259 : :
260 [ # # # # : 0 : switch (c->width) {
# # # ]
261 : : case NL80211_CHAN_WIDTH_5:
262 : : width = 5;
263 : : break;
264 : : case NL80211_CHAN_WIDTH_10:
265 : : width = 10;
266 : 0 : break;
267 : : case NL80211_CHAN_WIDTH_20:
268 : : case NL80211_CHAN_WIDTH_20_NOHT:
269 : : width = 20;
270 : 0 : break;
271 : : case NL80211_CHAN_WIDTH_40:
272 : : width = 40;
273 : 0 : break;
274 : : case NL80211_CHAN_WIDTH_80P80:
275 : : case NL80211_CHAN_WIDTH_80:
276 : : width = 80;
277 : 0 : break;
278 : : case NL80211_CHAN_WIDTH_160:
279 : : width = 160;
280 : 0 : break;
281 : : default:
282 [ # # ]: 0 : WARN_ON_ONCE(1);
283 : : return -1;
284 : : }
285 : 0 : return width;
286 : : }
287 : :
288 : : const struct cfg80211_chan_def *
289 : 0 : cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
290 : : const struct cfg80211_chan_def *c2)
291 : : {
292 : : u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
293 : :
294 : : /* If they are identical, return */
295 [ # # ]: 0 : if (cfg80211_chandef_identical(c1, c2))
296 : : return c1;
297 : :
298 : : /* otherwise, must have same control channel */
299 [ # # ]: 0 : if (c1->chan != c2->chan)
300 : : return NULL;
301 : :
302 : : /*
303 : : * If they have the same width, but aren't identical,
304 : : * then they can't be compatible.
305 : : */
306 [ # # ]: 0 : if (c1->width == c2->width)
307 : : return NULL;
308 : :
309 : : /*
310 : : * can't be compatible if one of them is 5 or 10 MHz,
311 : : * but they don't have the same width.
312 : : */
313 [ # # ]: 0 : if (c1->width == NL80211_CHAN_WIDTH_5 ||
314 [ # # ]: 0 : c1->width == NL80211_CHAN_WIDTH_10 ||
315 [ # # ]: 0 : c2->width == NL80211_CHAN_WIDTH_5 ||
316 : : c2->width == NL80211_CHAN_WIDTH_10)
317 : : return NULL;
318 : :
319 [ # # ]: 0 : if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
320 : : c1->width == NL80211_CHAN_WIDTH_20)
321 : : return c2;
322 : :
323 [ # # ]: 0 : if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
324 : : c2->width == NL80211_CHAN_WIDTH_20)
325 : : return c1;
326 : :
327 : 0 : chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
328 : 0 : chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
329 : :
330 [ # # ]: 0 : if (c1_pri40 != c2_pri40)
331 : : return NULL;
332 : :
333 [ # # # # : 0 : WARN_ON(!c1_pri80 && !c2_pri80);
# # ]
334 [ # # # # : 0 : if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
# # ]
335 : : return NULL;
336 : :
337 [ # # ]: 0 : if (c1->width > c2->width)
338 : : return c1;
339 : 0 : return c2;
340 : : }
341 : : EXPORT_SYMBOL(cfg80211_chandef_compatible);
342 : :
343 : 0 : static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
344 : : u32 bandwidth,
345 : : enum nl80211_dfs_state dfs_state)
346 : : {
347 : : struct ieee80211_channel *c;
348 : : u32 freq;
349 : :
350 [ # # ]: 0 : for (freq = center_freq - bandwidth/2 + 10;
351 : 0 : freq <= center_freq + bandwidth/2 - 10;
352 : 0 : freq += 20) {
353 : 0 : c = ieee80211_get_channel(wiphy, freq);
354 [ # # # # ]: 0 : if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
355 : 0 : continue;
356 : :
357 : 0 : c->dfs_state = dfs_state;
358 : 0 : c->dfs_state_entered = jiffies;
359 : : }
360 : 0 : }
361 : :
362 : 0 : void cfg80211_set_dfs_state(struct wiphy *wiphy,
363 : : const struct cfg80211_chan_def *chandef,
364 : : enum nl80211_dfs_state dfs_state)
365 : : {
366 : : int width;
367 : :
368 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
369 : : return;
370 : :
371 : 0 : width = cfg80211_chandef_get_width(chandef);
372 [ # # ]: 0 : if (width < 0)
373 : : return;
374 : :
375 : 0 : cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
376 : : width, dfs_state);
377 : :
378 [ # # ]: 0 : if (!chandef->center_freq2)
379 : : return;
380 : 0 : cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
381 : : width, dfs_state);
382 : : }
383 : :
384 : : static u32 cfg80211_get_start_freq(u32 center_freq,
385 : : u32 bandwidth)
386 : : {
387 : : u32 start_freq;
388 : :
389 [ # # # # : 0 : if (bandwidth <= 20)
# # # # #
# ]
390 : : start_freq = center_freq;
391 : : else
392 : 0 : start_freq = center_freq - bandwidth/2 + 10;
393 : :
394 : : return start_freq;
395 : : }
396 : :
397 : : static u32 cfg80211_get_end_freq(u32 center_freq,
398 : : u32 bandwidth)
399 : : {
400 : : u32 end_freq;
401 : :
402 [ # # # # : 0 : if (bandwidth <= 20)
# # # # #
# ]
403 : : end_freq = center_freq;
404 : : else
405 : 0 : end_freq = center_freq + bandwidth/2 - 10;
406 : :
407 : : return end_freq;
408 : : }
409 : :
410 : 0 : static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
411 : : u32 center_freq,
412 : : u32 bandwidth)
413 : : {
414 : : struct ieee80211_channel *c;
415 : : u32 freq, start_freq, end_freq;
416 : :
417 : : start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
418 : : end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
419 : :
420 [ # # ]: 0 : for (freq = start_freq; freq <= end_freq; freq += 20) {
421 : 0 : c = ieee80211_get_channel(wiphy, freq);
422 [ # # ]: 0 : if (!c)
423 : : return -EINVAL;
424 : :
425 [ # # ]: 0 : if (c->flags & IEEE80211_CHAN_RADAR)
426 : : return 1;
427 : : }
428 : : return 0;
429 : : }
430 : :
431 : :
432 : 0 : int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
433 : : const struct cfg80211_chan_def *chandef,
434 : : enum nl80211_iftype iftype)
435 : : {
436 : : int width;
437 : : int ret;
438 : :
439 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
440 : : return -EINVAL;
441 : :
442 [ # # # ]: 0 : switch (iftype) {
443 : : case NL80211_IFTYPE_ADHOC:
444 : : case NL80211_IFTYPE_AP:
445 : : case NL80211_IFTYPE_P2P_GO:
446 : : case NL80211_IFTYPE_MESH_POINT:
447 : 0 : width = cfg80211_chandef_get_width(chandef);
448 [ # # ]: 0 : if (width < 0)
449 : : return -EINVAL;
450 : :
451 : 0 : ret = cfg80211_get_chans_dfs_required(wiphy,
452 : : chandef->center_freq1,
453 : : width);
454 [ # # ]: 0 : if (ret < 0)
455 : : return ret;
456 [ # # ]: 0 : else if (ret > 0)
457 : 0 : return BIT(chandef->width);
458 : :
459 [ # # ]: 0 : if (!chandef->center_freq2)
460 : : return 0;
461 : :
462 : 0 : ret = cfg80211_get_chans_dfs_required(wiphy,
463 : : chandef->center_freq2,
464 : : width);
465 [ # # ]: 0 : if (ret < 0)
466 : : return ret;
467 [ # # ]: 0 : else if (ret > 0)
468 : 0 : return BIT(chandef->width);
469 : :
470 : : break;
471 : : case NL80211_IFTYPE_STATION:
472 : : case NL80211_IFTYPE_OCB:
473 : : case NL80211_IFTYPE_P2P_CLIENT:
474 : : case NL80211_IFTYPE_MONITOR:
475 : : case NL80211_IFTYPE_AP_VLAN:
476 : : case NL80211_IFTYPE_WDS:
477 : : case NL80211_IFTYPE_P2P_DEVICE:
478 : : case NL80211_IFTYPE_NAN:
479 : : break;
480 : : case NL80211_IFTYPE_UNSPECIFIED:
481 : : case NUM_NL80211_IFTYPES:
482 : 0 : WARN_ON(1);
483 : : }
484 : :
485 : : return 0;
486 : : }
487 : : EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
488 : :
489 : 0 : static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
490 : : u32 center_freq,
491 : : u32 bandwidth)
492 : : {
493 : : struct ieee80211_channel *c;
494 : : u32 freq, start_freq, end_freq;
495 : : int count = 0;
496 : :
497 : : start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
498 : : end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
499 : :
500 : : /*
501 : : * Check entire range of channels for the bandwidth.
502 : : * Check all channels are DFS channels (DFS_USABLE or
503 : : * DFS_AVAILABLE). Return number of usable channels
504 : : * (require CAC). Allow DFS and non-DFS channel mix.
505 : : */
506 [ # # ]: 0 : for (freq = start_freq; freq <= end_freq; freq += 20) {
507 : 0 : c = ieee80211_get_channel(wiphy, freq);
508 [ # # ]: 0 : if (!c)
509 : : return -EINVAL;
510 : :
511 [ # # ]: 0 : if (c->flags & IEEE80211_CHAN_DISABLED)
512 : : return -EINVAL;
513 : :
514 [ # # ]: 0 : if (c->flags & IEEE80211_CHAN_RADAR) {
515 [ # # ]: 0 : if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
516 : : return -EINVAL;
517 : :
518 [ # # ]: 0 : if (c->dfs_state == NL80211_DFS_USABLE)
519 : 0 : count++;
520 : : }
521 : : }
522 : :
523 : 0 : return count;
524 : : }
525 : :
526 : 0 : bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
527 : : const struct cfg80211_chan_def *chandef)
528 : : {
529 : : int width;
530 : : int r1, r2 = 0;
531 : :
532 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
533 : : return false;
534 : :
535 : 0 : width = cfg80211_chandef_get_width(chandef);
536 [ # # ]: 0 : if (width < 0)
537 : : return false;
538 : :
539 : 0 : r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
540 : : width);
541 : :
542 [ # # ]: 0 : if (r1 < 0)
543 : : return false;
544 : :
545 [ # # ]: 0 : switch (chandef->width) {
546 : : case NL80211_CHAN_WIDTH_80P80:
547 [ # # ]: 0 : WARN_ON(!chandef->center_freq2);
548 : 0 : r2 = cfg80211_get_chans_dfs_usable(wiphy,
549 : : chandef->center_freq2,
550 : : width);
551 [ # # ]: 0 : if (r2 < 0)
552 : : return false;
553 : : break;
554 : : default:
555 [ # # ]: 0 : WARN_ON(chandef->center_freq2);
556 : : break;
557 : : }
558 : :
559 : 0 : return (r1 + r2 > 0);
560 : : }
561 : :
562 : : /*
563 : : * Checks if center frequency of chan falls with in the bandwidth
564 : : * range of chandef.
565 : : */
566 : 0 : bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
567 : : struct ieee80211_channel *chan)
568 : : {
569 : : int width;
570 : : u32 freq;
571 : :
572 [ # # ]: 0 : if (chandef->chan->center_freq == chan->center_freq)
573 : : return true;
574 : :
575 : 0 : width = cfg80211_chandef_get_width(chandef);
576 [ # # ]: 0 : if (width <= 20)
577 : : return false;
578 : :
579 [ # # ]: 0 : for (freq = chandef->center_freq1 - width / 2 + 10;
580 : 0 : freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
581 [ # # ]: 0 : if (chan->center_freq == freq)
582 : : return true;
583 : : }
584 : :
585 [ # # ]: 0 : if (!chandef->center_freq2)
586 : : return false;
587 : :
588 [ # # ]: 0 : for (freq = chandef->center_freq2 - width / 2 + 10;
589 : 0 : freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
590 [ # # ]: 0 : if (chan->center_freq == freq)
591 : : return true;
592 : : }
593 : :
594 : : return false;
595 : : }
596 : :
597 : 0 : bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
598 : : {
599 : : bool active = false;
600 : :
601 : : ASSERT_WDEV_LOCK(wdev);
602 : :
603 [ # # ]: 0 : if (!wdev->chandef.chan)
604 : : return false;
605 : :
606 [ # # # # : 0 : switch (wdev->iftype) {
# ]
607 : : case NL80211_IFTYPE_AP:
608 : : case NL80211_IFTYPE_P2P_GO:
609 : 0 : active = wdev->beacon_interval != 0;
610 : 0 : break;
611 : : case NL80211_IFTYPE_ADHOC:
612 : 0 : active = wdev->ssid_len != 0;
613 : 0 : break;
614 : : case NL80211_IFTYPE_MESH_POINT:
615 : 0 : active = wdev->mesh_id_len != 0;
616 : 0 : break;
617 : : case NL80211_IFTYPE_STATION:
618 : : case NL80211_IFTYPE_OCB:
619 : : case NL80211_IFTYPE_P2P_CLIENT:
620 : : case NL80211_IFTYPE_MONITOR:
621 : : case NL80211_IFTYPE_AP_VLAN:
622 : : case NL80211_IFTYPE_WDS:
623 : : case NL80211_IFTYPE_P2P_DEVICE:
624 : : /* Can NAN type be considered as beaconing interface? */
625 : : case NL80211_IFTYPE_NAN:
626 : : break;
627 : : case NL80211_IFTYPE_UNSPECIFIED:
628 : : case NUM_NL80211_IFTYPES:
629 : 0 : WARN_ON(1);
630 : : }
631 : :
632 : 0 : return active;
633 : : }
634 : :
635 : 0 : static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
636 : : struct ieee80211_channel *chan)
637 : : {
638 : : struct wireless_dev *wdev;
639 : :
640 [ # # ]: 0 : list_for_each_entry(wdev, &wiphy->wdev_list, list) {
641 : : wdev_lock(wdev);
642 [ # # ]: 0 : if (!cfg80211_beaconing_iface_active(wdev)) {
643 : : wdev_unlock(wdev);
644 : 0 : continue;
645 : : }
646 : :
647 [ # # ]: 0 : if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
648 : : wdev_unlock(wdev);
649 : 0 : return true;
650 : : }
651 : : wdev_unlock(wdev);
652 : : }
653 : :
654 : : return false;
655 : : }
656 : :
657 : 0 : bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
658 : : struct ieee80211_channel *chan)
659 : : {
660 : : struct cfg80211_registered_device *rdev;
661 : :
662 [ # # # # ]: 0 : ASSERT_RTNL();
663 : :
664 [ # # ]: 0 : if (!(chan->flags & IEEE80211_CHAN_RADAR))
665 : : return false;
666 : :
667 [ # # ]: 0 : list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
668 [ # # ]: 0 : if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
669 : 0 : continue;
670 : :
671 [ # # ]: 0 : if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
672 : : return true;
673 : : }
674 : :
675 : : return false;
676 : : }
677 : :
678 : 0 : static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
679 : : u32 center_freq,
680 : : u32 bandwidth)
681 : : {
682 : : struct ieee80211_channel *c;
683 : : u32 freq, start_freq, end_freq;
684 : : bool dfs_offload;
685 : :
686 : : dfs_offload = wiphy_ext_feature_isset(wiphy,
687 : : NL80211_EXT_FEATURE_DFS_OFFLOAD);
688 : :
689 : : start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
690 : : end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
691 : :
692 : : /*
693 : : * Check entire range of channels for the bandwidth.
694 : : * If any channel in between is disabled or has not
695 : : * had gone through CAC return false
696 : : */
697 [ # # ]: 0 : for (freq = start_freq; freq <= end_freq; freq += 20) {
698 : 0 : c = ieee80211_get_channel(wiphy, freq);
699 [ # # ]: 0 : if (!c)
700 : : return false;
701 : :
702 [ # # ]: 0 : if (c->flags & IEEE80211_CHAN_DISABLED)
703 : : return false;
704 : :
705 [ # # # # ]: 0 : if ((c->flags & IEEE80211_CHAN_RADAR) &&
706 [ # # ]: 0 : (c->dfs_state != NL80211_DFS_AVAILABLE) &&
707 [ # # ]: 0 : !(c->dfs_state == NL80211_DFS_USABLE && dfs_offload))
708 : : return false;
709 : : }
710 : :
711 : : return true;
712 : : }
713 : :
714 : 0 : static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
715 : : const struct cfg80211_chan_def *chandef)
716 : : {
717 : : int width;
718 : : int r;
719 : :
720 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
721 : : return false;
722 : :
723 : 0 : width = cfg80211_chandef_get_width(chandef);
724 [ # # ]: 0 : if (width < 0)
725 : : return false;
726 : :
727 : 0 : r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
728 : : width);
729 : :
730 : : /* If any of channels unavailable for cf1 just return */
731 [ # # ]: 0 : if (!r)
732 : : return r;
733 : :
734 [ # # ]: 0 : switch (chandef->width) {
735 : : case NL80211_CHAN_WIDTH_80P80:
736 [ # # ]: 0 : WARN_ON(!chandef->center_freq2);
737 : 0 : r = cfg80211_get_chans_dfs_available(wiphy,
738 : : chandef->center_freq2,
739 : : width);
740 : 0 : break;
741 : : default:
742 [ # # ]: 0 : WARN_ON(chandef->center_freq2);
743 : : break;
744 : : }
745 : :
746 : 0 : return r;
747 : : }
748 : :
749 : 0 : static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
750 : : u32 center_freq,
751 : : u32 bandwidth)
752 : : {
753 : : struct ieee80211_channel *c;
754 : : u32 start_freq, end_freq, freq;
755 : : unsigned int dfs_cac_ms = 0;
756 : :
757 : : start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
758 : : end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
759 : :
760 [ # # ]: 0 : for (freq = start_freq; freq <= end_freq; freq += 20) {
761 : 0 : c = ieee80211_get_channel(wiphy, freq);
762 [ # # ]: 0 : if (!c)
763 : : return 0;
764 : :
765 [ # # ]: 0 : if (c->flags & IEEE80211_CHAN_DISABLED)
766 : : return 0;
767 : :
768 [ # # ]: 0 : if (!(c->flags & IEEE80211_CHAN_RADAR))
769 : 0 : continue;
770 : :
771 [ # # ]: 0 : if (c->dfs_cac_ms > dfs_cac_ms)
772 : : dfs_cac_ms = c->dfs_cac_ms;
773 : : }
774 : :
775 : 0 : return dfs_cac_ms;
776 : : }
777 : :
778 : : unsigned int
779 : 0 : cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
780 : : const struct cfg80211_chan_def *chandef)
781 : : {
782 : : int width;
783 : : unsigned int t1 = 0, t2 = 0;
784 : :
785 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
786 : : return 0;
787 : :
788 : 0 : width = cfg80211_chandef_get_width(chandef);
789 [ # # ]: 0 : if (width < 0)
790 : : return 0;
791 : :
792 : 0 : t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
793 : : chandef->center_freq1,
794 : : width);
795 : :
796 [ # # ]: 0 : if (!chandef->center_freq2)
797 : : return t1;
798 : :
799 : 0 : t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
800 : : chandef->center_freq2,
801 : : width);
802 : :
803 : 0 : return max(t1, t2);
804 : : }
805 : :
806 : 0 : static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
807 : : u32 center_freq, u32 bandwidth,
808 : : u32 prohibited_flags)
809 : : {
810 : : struct ieee80211_channel *c;
811 : : u32 freq, start_freq, end_freq;
812 : :
813 : : start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
814 : : end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
815 : :
816 [ # # ]: 0 : for (freq = start_freq; freq <= end_freq; freq += 20) {
817 : 0 : c = ieee80211_get_channel(wiphy, freq);
818 [ # # # # ]: 0 : if (!c || c->flags & prohibited_flags)
819 : : return false;
820 : : }
821 : :
822 : : return true;
823 : : }
824 : :
825 : : /* check if the operating channels are valid and supported */
826 : 0 : static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
827 : : enum ieee80211_edmg_bw_config edmg_bw_config,
828 : : int primary_channel,
829 : : struct ieee80211_edmg *edmg_cap)
830 : : {
831 : : struct ieee80211_channel *chan;
832 : : int i, freq;
833 : : int channels_counter = 0;
834 : :
835 [ # # ]: 0 : if (!edmg_channels && !edmg_bw_config)
836 : : return true;
837 : :
838 [ # # ]: 0 : if ((!edmg_channels && edmg_bw_config) ||
839 : : (edmg_channels && !edmg_bw_config))
840 : : return false;
841 : :
842 [ # # ]: 0 : if (!(edmg_channels & BIT(primary_channel - 1)))
843 : : return false;
844 : :
845 : : /* 60GHz channels 1..6 */
846 [ # # ]: 0 : for (i = 0; i < 6; i++) {
847 [ # # ]: 0 : if (!(edmg_channels & BIT(i)))
848 : 0 : continue;
849 : :
850 [ # # ]: 0 : if (!(edmg_cap->channels & BIT(i)))
851 : : return false;
852 : :
853 : 0 : channels_counter++;
854 : :
855 : 0 : freq = ieee80211_channel_to_frequency(i + 1,
856 : : NL80211_BAND_60GHZ);
857 : 0 : chan = ieee80211_get_channel(wiphy, freq);
858 [ # # # # ]: 0 : if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
859 : : return false;
860 : : }
861 : :
862 : : /* IEEE802.11 allows max 4 channels */
863 [ # # ]: 0 : if (channels_counter > 4)
864 : : return false;
865 : :
866 : : /* check bw_config is a subset of what driver supports
867 : : * (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
868 : : */
869 [ # # ]: 0 : if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
870 : : return false;
871 : :
872 [ # # ]: 0 : if (edmg_bw_config > edmg_cap->bw_config)
873 : : return false;
874 : :
875 : 0 : return true;
876 : : }
877 : :
878 : 0 : bool cfg80211_chandef_usable(struct wiphy *wiphy,
879 : : const struct cfg80211_chan_def *chandef,
880 : : u32 prohibited_flags)
881 : : {
882 : : struct ieee80211_sta_ht_cap *ht_cap;
883 : : struct ieee80211_sta_vht_cap *vht_cap;
884 : : struct ieee80211_edmg *edmg_cap;
885 : : u32 width, control_freq, cap;
886 : :
887 [ # # # # ]: 0 : if (WARN_ON(!cfg80211_chandef_valid(chandef)))
888 : : return false;
889 : :
890 : 0 : ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
891 : : vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
892 : 0 : edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
893 : :
894 [ # # # # ]: 0 : if (edmg_cap->channels &&
895 : 0 : !cfg80211_edmg_usable(wiphy,
896 : : chandef->edmg.channels,
897 : : chandef->edmg.bw_config,
898 : 0 : chandef->chan->hw_value,
899 : : edmg_cap))
900 : : return false;
901 : :
902 : 0 : control_freq = chandef->chan->center_freq;
903 : :
904 [ # # # # : 0 : switch (chandef->width) {
# # # #
# ]
905 : : case NL80211_CHAN_WIDTH_5:
906 : : width = 5;
907 : : break;
908 : : case NL80211_CHAN_WIDTH_10:
909 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_10MHZ;
910 : : width = 10;
911 : 0 : break;
912 : : case NL80211_CHAN_WIDTH_20:
913 [ # # ]: 0 : if (!ht_cap->ht_supported)
914 : : return false;
915 : : /* fall through */
916 : : case NL80211_CHAN_WIDTH_20_NOHT:
917 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_20MHZ;
918 : : width = 20;
919 : 0 : break;
920 : : case NL80211_CHAN_WIDTH_40:
921 : : width = 40;
922 [ # # ]: 0 : if (!ht_cap->ht_supported)
923 : : return false;
924 [ # # ]: 0 : if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
925 : : ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
926 : : return false;
927 [ # # # # ]: 0 : if (chandef->center_freq1 < control_freq &&
928 : 0 : chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
929 : : return false;
930 [ # # # # ]: 0 : if (chandef->center_freq1 > control_freq &&
931 : 0 : chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
932 : : return false;
933 : : break;
934 : : case NL80211_CHAN_WIDTH_80P80:
935 : 0 : cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
936 [ # # ]: 0 : if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
937 : : return false;
938 : : /* fall through */
939 : : case NL80211_CHAN_WIDTH_80:
940 [ # # ]: 0 : if (!vht_cap->vht_supported)
941 : : return false;
942 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
943 : : width = 80;
944 : 0 : break;
945 : : case NL80211_CHAN_WIDTH_160:
946 [ # # ]: 0 : if (!vht_cap->vht_supported)
947 : : return false;
948 : 0 : cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
949 [ # # ]: 0 : if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
950 : 0 : cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
951 : : return false;
952 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
953 : : width = 160;
954 : 0 : break;
955 : : default:
956 [ # # ]: 0 : WARN_ON_ONCE(1);
957 : : return false;
958 : : }
959 : :
960 : : /*
961 : : * TODO: What if there are only certain 80/160/80+80 MHz channels
962 : : * allowed by the driver, or only certain combinations?
963 : : * For 40 MHz the driver can set the NO_HT40 flags, but for
964 : : * 80/160 MHz and in particular 80+80 MHz this isn't really
965 : : * feasible and we only have NO_80MHZ/NO_160MHZ so far but
966 : : * no way to cover 80+80 MHz or more complex restrictions.
967 : : * Note that such restrictions also need to be advertised to
968 : : * userspace, for example for P2P channel selection.
969 : : */
970 : :
971 [ # # ]: 0 : if (width > 20)
972 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
973 : :
974 : : /* 5 and 10 MHz are only defined for the OFDM PHY */
975 [ # # ]: 0 : if (width < 20)
976 : 0 : prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
977 : :
978 : :
979 [ # # ]: 0 : if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
980 : : width, prohibited_flags))
981 : : return false;
982 : :
983 [ # # ]: 0 : if (!chandef->center_freq2)
984 : : return true;
985 : 0 : return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
986 : : width, prohibited_flags);
987 : : }
988 : : EXPORT_SYMBOL(cfg80211_chandef_usable);
989 : :
990 : : /*
991 : : * Check if the channel can be used under permissive conditions mandated by
992 : : * some regulatory bodies, i.e., the channel is marked with
993 : : * IEEE80211_CHAN_IR_CONCURRENT and there is an additional station interface
994 : : * associated to an AP on the same channel or on the same UNII band
995 : : * (assuming that the AP is an authorized master).
996 : : * In addition allow operation on a channel on which indoor operation is
997 : : * allowed, iff we are currently operating in an indoor environment.
998 : : */
999 : 0 : static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
1000 : : enum nl80211_iftype iftype,
1001 : : struct ieee80211_channel *chan)
1002 : : {
1003 : : struct wireless_dev *wdev;
1004 : : struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1005 : :
1006 [ # # # # ]: 0 : ASSERT_RTNL();
1007 : :
1008 : : if (!IS_ENABLED(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
1009 : : !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR))
1010 : : return false;
1011 : :
1012 : : /* only valid for GO and TDLS off-channel (station/p2p-CL) */
1013 : : if (iftype != NL80211_IFTYPE_P2P_GO &&
1014 : : iftype != NL80211_IFTYPE_STATION &&
1015 : : iftype != NL80211_IFTYPE_P2P_CLIENT)
1016 : : return false;
1017 : :
1018 : : if (regulatory_indoor_allowed() &&
1019 : : (chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1020 : : return true;
1021 : :
1022 : : if (!(chan->flags & IEEE80211_CHAN_IR_CONCURRENT))
1023 : : return false;
1024 : :
1025 : : /*
1026 : : * Generally, it is possible to rely on another device/driver to allow
1027 : : * the IR concurrent relaxation, however, since the device can further
1028 : : * enforce the relaxation (by doing a similar verifications as this),
1029 : : * and thus fail the GO instantiation, consider only the interfaces of
1030 : : * the current registered device.
1031 : : */
1032 : : list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
1033 : : struct ieee80211_channel *other_chan = NULL;
1034 : : int r1, r2;
1035 : :
1036 : : wdev_lock(wdev);
1037 : : if (wdev->iftype == NL80211_IFTYPE_STATION &&
1038 : : wdev->current_bss)
1039 : : other_chan = wdev->current_bss->pub.channel;
1040 : :
1041 : : /*
1042 : : * If a GO already operates on the same GO_CONCURRENT channel,
1043 : : * this one (maybe the same one) can beacon as well. We allow
1044 : : * the operation even if the station we relied on with
1045 : : * GO_CONCURRENT is disconnected now. But then we must make sure
1046 : : * we're not outdoor on an indoor-only channel.
1047 : : */
1048 : : if (iftype == NL80211_IFTYPE_P2P_GO &&
1049 : : wdev->iftype == NL80211_IFTYPE_P2P_GO &&
1050 : : wdev->beacon_interval &&
1051 : : !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
1052 : : other_chan = wdev->chandef.chan;
1053 : : wdev_unlock(wdev);
1054 : :
1055 : : if (!other_chan)
1056 : : continue;
1057 : :
1058 : : if (chan == other_chan)
1059 : : return true;
1060 : :
1061 : : if (chan->band != NL80211_BAND_5GHZ &&
1062 : : chan->band != NL80211_BAND_6GHZ)
1063 : : continue;
1064 : :
1065 : : r1 = cfg80211_get_unii(chan->center_freq);
1066 : : r2 = cfg80211_get_unii(other_chan->center_freq);
1067 : :
1068 : : if (r1 != -EINVAL && r1 == r2) {
1069 : : /*
1070 : : * At some locations channels 149-165 are considered a
1071 : : * bundle, but at other locations, e.g., Indonesia,
1072 : : * channels 149-161 are considered a bundle while
1073 : : * channel 165 is left out and considered to be in a
1074 : : * different bundle. Thus, in case that there is a
1075 : : * station interface connected to an AP on channel 165,
1076 : : * it is assumed that channels 149-161 are allowed for
1077 : : * GO operations. However, having a station interface
1078 : : * connected to an AP on channels 149-161, does not
1079 : : * allow GO operation on channel 165.
1080 : : */
1081 : : if (chan->center_freq == 5825 &&
1082 : : other_chan->center_freq != 5825)
1083 : : continue;
1084 : : return true;
1085 : : }
1086 : : }
1087 : :
1088 : : return false;
1089 : : }
1090 : :
1091 : 0 : static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
1092 : : struct cfg80211_chan_def *chandef,
1093 : : enum nl80211_iftype iftype,
1094 : : bool check_no_ir)
1095 : : {
1096 : : bool res;
1097 : : u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
1098 : : IEEE80211_CHAN_RADAR;
1099 : :
1100 : 0 : trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1101 : :
1102 [ # # ]: 0 : if (check_no_ir)
1103 : : prohibited_flags |= IEEE80211_CHAN_NO_IR;
1104 : :
1105 [ # # # # ]: 0 : if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
1106 : 0 : cfg80211_chandef_dfs_available(wiphy, chandef)) {
1107 : : /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
1108 : : prohibited_flags = IEEE80211_CHAN_DISABLED;
1109 : : }
1110 : :
1111 : 0 : res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
1112 : :
1113 : 0 : trace_cfg80211_return_bool(res);
1114 : 0 : return res;
1115 : : }
1116 : :
1117 : 0 : bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
1118 : : struct cfg80211_chan_def *chandef,
1119 : : enum nl80211_iftype iftype)
1120 : : {
1121 : 0 : return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
1122 : : }
1123 : : EXPORT_SYMBOL(cfg80211_reg_can_beacon);
1124 : :
1125 : 0 : bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
1126 : : struct cfg80211_chan_def *chandef,
1127 : : enum nl80211_iftype iftype)
1128 : : {
1129 : : bool check_no_ir;
1130 : :
1131 [ # # # # ]: 0 : ASSERT_RTNL();
1132 : :
1133 : : /*
1134 : : * Under certain conditions suggested by some regulatory bodies a
1135 : : * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
1136 : : * only if such relaxations are not enabled and the conditions are not
1137 : : * met.
1138 : : */
1139 : 0 : check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
1140 : 0 : chandef->chan);
1141 : :
1142 : 0 : return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
1143 : : }
1144 : : EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
1145 : :
1146 : 0 : int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
1147 : : struct cfg80211_chan_def *chandef)
1148 : : {
1149 [ # # ]: 0 : if (!rdev->ops->set_monitor_channel)
1150 : : return -EOPNOTSUPP;
1151 [ # # ]: 0 : if (!cfg80211_has_monitors_only(rdev))
1152 : : return -EBUSY;
1153 : :
1154 : 0 : return rdev_set_monitor_channel(rdev, chandef);
1155 : : }
1156 : :
1157 : : void
1158 : 0 : cfg80211_get_chan_state(struct wireless_dev *wdev,
1159 : : struct ieee80211_channel **chan,
1160 : : enum cfg80211_chan_mode *chanmode,
1161 : : u8 *radar_detect)
1162 : : {
1163 : : int ret;
1164 : :
1165 : 0 : *chan = NULL;
1166 : 0 : *chanmode = CHAN_MODE_UNDEFINED;
1167 : :
1168 : : ASSERT_WDEV_LOCK(wdev);
1169 : :
1170 [ # # # # ]: 0 : if (wdev->netdev && !netif_running(wdev->netdev))
1171 : : return;
1172 : :
1173 [ # # # # : 0 : switch (wdev->iftype) {
# # # ]
1174 : : case NL80211_IFTYPE_ADHOC:
1175 [ # # ]: 0 : if (wdev->current_bss) {
1176 : 0 : *chan = wdev->current_bss->pub.channel;
1177 [ # # # # ]: 0 : *chanmode = (wdev->ibss_fixed &&
1178 : 0 : !wdev->ibss_dfs_possible)
1179 : : ? CHAN_MODE_SHARED
1180 : : : CHAN_MODE_EXCLUSIVE;
1181 : :
1182 : : /* consider worst-case - IBSS can try to return to the
1183 : : * original user-specified channel as creator */
1184 [ # # ]: 0 : if (wdev->ibss_dfs_possible)
1185 : 0 : *radar_detect |= BIT(wdev->chandef.width);
1186 : : return;
1187 : : }
1188 : : break;
1189 : : case NL80211_IFTYPE_STATION:
1190 : : case NL80211_IFTYPE_P2P_CLIENT:
1191 [ # # ]: 0 : if (wdev->current_bss) {
1192 : 0 : *chan = wdev->current_bss->pub.channel;
1193 : 0 : *chanmode = CHAN_MODE_SHARED;
1194 : 0 : return;
1195 : : }
1196 : : break;
1197 : : case NL80211_IFTYPE_AP:
1198 : : case NL80211_IFTYPE_P2P_GO:
1199 [ # # ]: 0 : if (wdev->cac_started) {
1200 : 0 : *chan = wdev->chandef.chan;
1201 : 0 : *chanmode = CHAN_MODE_SHARED;
1202 : 0 : *radar_detect |= BIT(wdev->chandef.width);
1203 [ # # ]: 0 : } else if (wdev->beacon_interval) {
1204 : 0 : *chan = wdev->chandef.chan;
1205 : 0 : *chanmode = CHAN_MODE_SHARED;
1206 : :
1207 : 0 : ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1208 : 0 : &wdev->chandef,
1209 : : wdev->iftype);
1210 [ # # ]: 0 : WARN_ON(ret < 0);
1211 [ # # ]: 0 : if (ret > 0)
1212 : 0 : *radar_detect |= BIT(wdev->chandef.width);
1213 : : }
1214 : : return;
1215 : : case NL80211_IFTYPE_MESH_POINT:
1216 [ # # ]: 0 : if (wdev->mesh_id_len) {
1217 : 0 : *chan = wdev->chandef.chan;
1218 : 0 : *chanmode = CHAN_MODE_SHARED;
1219 : :
1220 : 0 : ret = cfg80211_chandef_dfs_required(wdev->wiphy,
1221 : 0 : &wdev->chandef,
1222 : : wdev->iftype);
1223 [ # # ]: 0 : WARN_ON(ret < 0);
1224 [ # # ]: 0 : if (ret > 0)
1225 : 0 : *radar_detect |= BIT(wdev->chandef.width);
1226 : : }
1227 : : return;
1228 : : case NL80211_IFTYPE_OCB:
1229 [ # # ]: 0 : if (wdev->chandef.chan) {
1230 : 0 : *chan = wdev->chandef.chan;
1231 : 0 : *chanmode = CHAN_MODE_SHARED;
1232 : 0 : return;
1233 : : }
1234 : : break;
1235 : : case NL80211_IFTYPE_MONITOR:
1236 : : case NL80211_IFTYPE_AP_VLAN:
1237 : : case NL80211_IFTYPE_WDS:
1238 : : case NL80211_IFTYPE_P2P_DEVICE:
1239 : : case NL80211_IFTYPE_NAN:
1240 : : /* these interface types don't really have a channel */
1241 : : return;
1242 : : case NL80211_IFTYPE_UNSPECIFIED:
1243 : : case NUM_NL80211_IFTYPES:
1244 : 0 : WARN_ON(1);
1245 : : }
1246 : : }
|