]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/dfs.c
6 GHz: Do not check for HT capability on 6 GHz channels
[thirdparty/hostap.git] / src / ap / dfs.c
CommitLineData
e76da505
JD
1/*
2 * DFS - Dynamic Frequency Selection
3 * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
7cbb5f1a 4 * Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
e76da505
JD
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
11
12#include "utils/common.h"
13#include "common/ieee802_11_defs.h"
ada157f3 14#include "common/hw_features_common.h"
186c9059 15#include "common/wpa_ctrl.h"
e76da505 16#include "hostapd.h"
e76da505
JD
17#include "ap_drv_ops.h"
18#include "drivers/driver.h"
19#include "dfs.h"
20
21
4a274f48 22static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
58b73e3d
JD
23{
24 int n_chans = 1;
25
4a274f48
JM
26 *seg1 = 0;
27
dc036d9e 28 if (iface->conf->ieee80211n && iface->conf->secondary_channel)
58b73e3d
JD
29 n_chans = 2;
30
958cb348 31 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
c6b7ac07 32 switch (hostapd_get_oper_chwidth(iface->conf)) {
464dcfd0 33 case CHANWIDTH_USE_HT:
58b73e3d 34 break;
464dcfd0 35 case CHANWIDTH_80MHZ:
58b73e3d
JD
36 n_chans = 4;
37 break;
464dcfd0 38 case CHANWIDTH_160MHZ:
899cc14e
JD
39 n_chans = 8;
40 break;
464dcfd0 41 case CHANWIDTH_80P80MHZ:
4a274f48
JM
42 n_chans = 4;
43 *seg1 = 4;
44 break;
58b73e3d
JD
45 default:
46 break;
47 }
48 }
49
50 return n_chans;
51}
52
53
b72f949b
MK
54static int dfs_channel_available(struct hostapd_channel_data *chan,
55 int skip_radar)
58b73e3d 56{
b72f949b
MK
57 /*
58 * When radar detection happens, CSA is performed. However, there's no
59 * time for CAC, so radar channels must be skipped when finding a new
01b99998 60 * channel for CSA, unless they are available for immediate use.
b72f949b 61 */
01b99998
SW
62 if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
63 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
64 HOSTAPD_CHAN_DFS_AVAILABLE))
b72f949b
MK
65 return 0;
66
58b73e3d
JD
67 if (chan->flag & HOSTAPD_CHAN_DISABLED)
68 return 0;
69 if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
70 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
71 HOSTAPD_CHAN_DFS_UNAVAILABLE))
72 return 0;
73 return 1;
74}
75
76
1dc17db3 77static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
58b73e3d 78{
1dc17db3
JD
79 /*
80 * The tables contain first valid channel number based on channel width.
81 * We will also choose this first channel as the control one.
82 */
83 int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
84 184, 192 };
85 /*
86 * VHT80, valid channels based on center frequency:
87 * 42, 58, 106, 122, 138, 155
88 */
89 int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
4f1e01b8
JD
90 /*
91 * VHT160 valid channels based on center frequency:
92 * 50, 114
93 */
94 int allowed_160[] = { 36, 100 };
1dc17db3
JD
95 int *allowed = allowed_40;
96 unsigned int i, allowed_no = 0;
97
98 switch (n_chans) {
99 case 2:
100 allowed = allowed_40;
e7ecab4a 101 allowed_no = ARRAY_SIZE(allowed_40);
1dc17db3
JD
102 break;
103 case 4:
104 allowed = allowed_80;
e7ecab4a 105 allowed_no = ARRAY_SIZE(allowed_80);
1dc17db3 106 break;
4f1e01b8
JD
107 case 8:
108 allowed = allowed_160;
109 allowed_no = ARRAY_SIZE(allowed_160);
110 break;
1dc17db3
JD
111 default:
112 wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
113 break;
114 }
58b73e3d 115
1dc17db3 116 for (i = 0; i < allowed_no; i++) {
58b73e3d
JD
117 if (chan->chan == allowed[i])
118 return 1;
119 }
120
121 return 0;
122}
123
124
56ef9925
EP
125static struct hostapd_channel_data *
126dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
127{
128 int i;
129
130 for (i = first_chan_idx; i < mode->num_channels; i++) {
131 if (mode->channels[i].freq == freq)
132 return &mode->channels[i];
133 }
134
135 return NULL;
136}
137
138
6a398ddc 139static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
b72f949b
MK
140 int first_chan_idx, int num_chans,
141 int skip_radar)
6a398ddc
MK
142{
143 struct hostapd_channel_data *first_chan, *chan;
144 int i;
59bf0f97 145 u32 bw = num_chan_to_bw(num_chans);
6a398ddc 146
030a3e12 147 if (first_chan_idx + num_chans > mode->num_channels)
6a398ddc
MK
148 return 0;
149
150 first_chan = &mode->channels[first_chan_idx];
151
59bf0f97
DL
152 /* hostapd DFS implementation assumes the first channel as primary.
153 * If it's not allowed to use the first channel as primary, decline the
154 * whole channel range. */
155 if (!chan_pri_allowed(first_chan))
156 return 0;
157
6a398ddc 158 for (i = 0; i < num_chans; i++) {
56ef9925
EP
159 chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
160 first_chan_idx);
161 if (!chan)
6a398ddc
MK
162 return 0;
163
59bf0f97
DL
164 /* HT 40 MHz secondary channel availability checked only for
165 * primary channel */
166 if (!chan_bw_allowed(chan, bw, 1, !i))
167 return 0;
168
b72f949b 169 if (!dfs_channel_available(chan, skip_radar))
6a398ddc
MK
170 return 0;
171 }
172
173 return 1;
174}
175
176
70ee1be2
SW
177static int is_in_chanlist(struct hostapd_iface *iface,
178 struct hostapd_channel_data *chan)
179{
857d9422 180 if (!iface->conf->acs_ch_list.num)
70ee1be2
SW
181 return 1;
182
857d9422 183 return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
70ee1be2
SW
184}
185
186
32595da6
MK
187/*
188 * The function assumes HT40+ operation.
189 * Make sure to adjust the following variables after calling this:
190 * - hapd->secondary_channel
c6b7ac07
JC
191 * - hapd->vht/he_oper_centr_freq_seg0_idx
192 * - hapd->vht/he_oper_centr_freq_seg1_idx
32595da6 193 */
dc036d9e 194static int dfs_find_channel(struct hostapd_iface *iface,
6de0e0c9 195 struct hostapd_channel_data **ret_chan,
b72f949b 196 int idx, int skip_radar)
e76da505
JD
197{
198 struct hostapd_hw_modes *mode;
6a398ddc 199 struct hostapd_channel_data *chan;
4a274f48 200 int i, channel_idx = 0, n_chans, n_chans1;
e76da505 201
dc036d9e 202 mode = iface->current_mode;
4a274f48 203 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
e76da505 204
58b73e3d 205 wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
e76da505
JD
206 for (i = 0; i < mode->num_channels; i++) {
207 chan = &mode->channels[i];
208
6a398ddc 209 /* Skip HT40/VHT incompatible channels */
dc036d9e
JM
210 if (iface->conf->ieee80211n &&
211 iface->conf->secondary_channel &&
59bf0f97
DL
212 (!dfs_is_chan_allowed(chan, n_chans) ||
213 !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
e76da505
JD
214 continue;
215
6a398ddc 216 /* Skip incompatible chandefs */
b72f949b 217 if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
6a398ddc 218 continue;
e76da505 219
70ee1be2
SW
220 if (!is_in_chanlist(iface, chan))
221 continue;
222
e76da505
JD
223 if (ret_chan && idx == channel_idx) {
224 wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
225 *ret_chan = chan;
226 return idx;
227 }
58b73e3d 228 wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
e76da505
JD
229 channel_idx++;
230 }
231 return channel_idx;
232}
233
234
7118a697
JC
235static void dfs_adjust_center_freq(struct hostapd_iface *iface,
236 struct hostapd_channel_data *chan,
237 int secondary_channel,
238 u8 *oper_centr_freq_seg0_idx,
239 u8 *oper_centr_freq_seg1_idx)
58b73e3d 240{
958cb348 241 if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
58b73e3d
JD
242 return;
243
244 if (!chan)
245 return;
246
7118a697 247 *oper_centr_freq_seg1_idx = 0;
32595da6 248
c6b7ac07 249 switch (hostapd_get_oper_chwidth(iface->conf)) {
464dcfd0 250 case CHANWIDTH_USE_HT:
eed65aad 251 if (secondary_channel == 1)
7118a697 252 *oper_centr_freq_seg0_idx = chan->chan + 2;
eed65aad 253 else if (secondary_channel == -1)
7118a697 254 *oper_centr_freq_seg0_idx = chan->chan - 2;
345276a6 255 else
7118a697 256 *oper_centr_freq_seg0_idx = chan->chan;
58b73e3d 257 break;
464dcfd0 258 case CHANWIDTH_80MHZ:
7118a697 259 *oper_centr_freq_seg0_idx = chan->chan + 6;
58b73e3d 260 break;
464dcfd0 261 case CHANWIDTH_160MHZ:
7118a697 262 *oper_centr_freq_seg0_idx = chan->chan + 14;
35f83637 263 break;
58b73e3d 264 default:
899cc14e 265 wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
7118a697 266 *oper_centr_freq_seg0_idx = 0;
58b73e3d
JD
267 break;
268 }
269
32595da6 270 wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
7118a697
JC
271 *oper_centr_freq_seg0_idx,
272 *oper_centr_freq_seg1_idx);
58b73e3d
JD
273}
274
275
276/* Return start channel idx we will use for mode->channels[idx] */
4a274f48 277static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
58b73e3d
JD
278{
279 struct hostapd_hw_modes *mode;
280 struct hostapd_channel_data *chan;
dc036d9e 281 int channel_no = iface->conf->channel;
58b73e3d 282 int res = -1, i;
4a274f48
JM
283 int chan_seg1 = -1;
284
285 *seg1_start = -1;
58b73e3d
JD
286
287 /* HT40- */
dc036d9e 288 if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
58b73e3d
JD
289 channel_no -= 4;
290
958cb348
JC
291 /* VHT/HE */
292 if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
c6b7ac07 293 switch (hostapd_get_oper_chwidth(iface->conf)) {
464dcfd0 294 case CHANWIDTH_USE_HT:
58b73e3d 295 break;
464dcfd0 296 case CHANWIDTH_80MHZ:
c6b7ac07
JC
297 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
298 iface->conf) - 6;
58b73e3d 299 break;
464dcfd0 300 case CHANWIDTH_160MHZ:
c6b7ac07
JC
301 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
302 iface->conf) - 14;
899cc14e 303 break;
464dcfd0 304 case CHANWIDTH_80P80MHZ:
c6b7ac07
JC
305 channel_no = hostapd_get_oper_centr_freq_seg0_idx(
306 iface->conf) - 6;
307 chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
308 iface->conf) - 6;
4a274f48 309 break;
58b73e3d
JD
310 default:
311 wpa_printf(MSG_INFO,
4a274f48 312 "DFS only VHT20/40/80/160/80+80 is supported now");
58b73e3d
JD
313 channel_no = -1;
314 break;
315 }
316 }
317
318 /* Get idx */
dc036d9e 319 mode = iface->current_mode;
58b73e3d
JD
320 for (i = 0; i < mode->num_channels; i++) {
321 chan = &mode->channels[i];
322 if (chan->chan == channel_no) {
323 res = i;
324 break;
325 }
326 }
327
4a274f48
JM
328 if (res != -1 && chan_seg1 > -1) {
329 int found = 0;
330
331 /* Get idx for seg1 */
332 mode = iface->current_mode;
333 for (i = 0; i < mode->num_channels; i++) {
334 chan = &mode->channels[i];
335 if (chan->chan == chan_seg1) {
336 *seg1_start = i;
337 found = 1;
338 break;
339 }
340 }
341 if (!found)
342 res = -1;
343 }
344
7450c128
BG
345 if (res == -1) {
346 wpa_printf(MSG_DEBUG,
347 "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
348 mode->num_channels, channel_no, iface->conf->channel,
349 iface->conf->ieee80211n,
350 iface->conf->secondary_channel,
c6b7ac07 351 hostapd_get_oper_chwidth(iface->conf));
7450c128
BG
352
353 for (i = 0; i < mode->num_channels; i++) {
354 wpa_printf(MSG_DEBUG, "Available channel: %d",
355 mode->channels[i].chan);
356 }
357 }
58b73e3d
JD
358
359 return res;
360}
361
362
363/* At least one channel have radar flag */
dc036d9e
JM
364static int dfs_check_chans_radar(struct hostapd_iface *iface,
365 int start_chan_idx, int n_chans)
58b73e3d
JD
366{
367 struct hostapd_channel_data *channel;
368 struct hostapd_hw_modes *mode;
369 int i, res = 0;
370
dc036d9e 371 mode = iface->current_mode;
58b73e3d
JD
372
373 for (i = 0; i < n_chans; i++) {
374 channel = &mode->channels[start_chan_idx + i];
375 if (channel->flag & HOSTAPD_CHAN_RADAR)
376 res++;
377 }
378
379 return res;
380}
381
382
383/* All channels available */
dc036d9e 384static int dfs_check_chans_available(struct hostapd_iface *iface,
58b73e3d
JD
385 int start_chan_idx, int n_chans)
386{
387 struct hostapd_channel_data *channel;
388 struct hostapd_hw_modes *mode;
389 int i;
390
dc036d9e 391 mode = iface->current_mode;
58b73e3d 392
8c9cb81f 393 for (i = 0; i < n_chans; i++) {
58b73e3d 394 channel = &mode->channels[start_chan_idx + i];
b8058a69
JD
395
396 if (channel->flag & HOSTAPD_CHAN_DISABLED)
397 break;
398
399 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
400 continue;
401
58b73e3d
JD
402 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
403 HOSTAPD_CHAN_DFS_AVAILABLE)
404 break;
405 }
406
407 return i == n_chans;
408}
409
410
411/* At least one channel unavailable */
dc036d9e 412static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
58b73e3d
JD
413 int start_chan_idx,
414 int n_chans)
415{
416 struct hostapd_channel_data *channel;
417 struct hostapd_hw_modes *mode;
418 int i, res = 0;
419
dc036d9e 420 mode = iface->current_mode;
58b73e3d 421
8c9cb81f 422 for (i = 0; i < n_chans; i++) {
58b73e3d
JD
423 channel = &mode->channels[start_chan_idx + i];
424 if (channel->flag & HOSTAPD_CHAN_DISABLED)
425 res++;
426 if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
427 HOSTAPD_CHAN_DFS_UNAVAILABLE)
428 res++;
429 }
430
431 return res;
432}
433
434
32595da6 435static struct hostapd_channel_data *
dc036d9e 436dfs_get_valid_channel(struct hostapd_iface *iface,
32595da6 437 int *secondary_channel,
7118a697
JC
438 u8 *oper_centr_freq_seg0_idx,
439 u8 *oper_centr_freq_seg1_idx,
b72f949b 440 int skip_radar)
e76da505
JD
441{
442 struct hostapd_hw_modes *mode;
443 struct hostapd_channel_data *chan = NULL;
32595da6
MK
444 int num_available_chandefs;
445 int chan_idx;
e76da505
JD
446 u32 _rand;
447
448 wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
3d91a047 449 *secondary_channel = 0;
7118a697
JC
450 *oper_centr_freq_seg0_idx = 0;
451 *oper_centr_freq_seg1_idx = 0;
e76da505 452
dc036d9e 453 if (iface->current_mode == NULL)
e76da505
JD
454 return NULL;
455
dc036d9e 456 mode = iface->current_mode;
e76da505
JD
457 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
458 return NULL;
459
32595da6 460 /* Get the count first */
b72f949b 461 num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
32595da6
MK
462 if (num_available_chandefs == 0)
463 return NULL;
e76da505 464
7c0e5b58 465 if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
239952b4 466 return NULL;
32595da6 467 chan_idx = _rand % num_available_chandefs;
b72f949b 468 dfs_find_channel(iface, &chan, chan_idx, skip_radar);
32595da6
MK
469
470 /* dfs_find_channel() calculations assume HT40+ */
dc036d9e 471 if (iface->conf->secondary_channel)
32595da6
MK
472 *secondary_channel = 1;
473 else
474 *secondary_channel = 0;
475
7118a697
JC
476 dfs_adjust_center_freq(iface, chan,
477 *secondary_channel,
478 oper_centr_freq_seg0_idx,
479 oper_centr_freq_seg1_idx);
58b73e3d 480
e76da505
JD
481 return chan;
482}
483
484
dc036d9e 485static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
e76da505
JD
486{
487 struct hostapd_hw_modes *mode;
488 struct hostapd_channel_data *chan = NULL;
489 int i;
490
dc036d9e 491 mode = iface->current_mode;
e76da505
JD
492 if (mode == NULL)
493 return 0;
494
58b73e3d 495 wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
dc036d9e
JM
496 for (i = 0; i < iface->current_mode->num_channels; i++) {
497 chan = &iface->current_mode->channels[i];
e76da505
JD
498 if (chan->freq == freq) {
499 if (chan->flag & HOSTAPD_CHAN_RADAR) {
500 chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
501 chan->flag |= state;
502 return 1; /* Channel found */
503 }
504 }
505 }
506 wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
507 return 0;
508}
509
510
dc036d9e 511static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
58b73e3d
JD
512 int chan_offset, int chan_width, int cf1,
513 int cf2, u32 state)
514{
515 int n_chans = 1, i;
516 struct hostapd_hw_modes *mode;
517 int frequency = freq;
530b8ee3 518 int frequency2 = 0;
58b73e3d
JD
519 int ret = 0;
520
dc036d9e 521 mode = iface->current_mode;
58b73e3d
JD
522 if (mode == NULL)
523 return 0;
524
525 if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
526 wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
527 return 0;
528 }
529
530 /* Seems cf1 and chan_width is enough here */
531 switch (chan_width) {
532 case CHAN_WIDTH_20_NOHT:
533 case CHAN_WIDTH_20:
534 n_chans = 1;
bb337dda
JM
535 if (frequency == 0)
536 frequency = cf1;
58b73e3d
JD
537 break;
538 case CHAN_WIDTH_40:
539 n_chans = 2;
540 frequency = cf1 - 10;
541 break;
542 case CHAN_WIDTH_80:
543 n_chans = 4;
544 frequency = cf1 - 30;
545 break;
530b8ee3
LW
546 case CHAN_WIDTH_80P80:
547 n_chans = 4;
548 frequency = cf1 - 30;
549 frequency2 = cf2 - 30;
550 break;
899cc14e
JD
551 case CHAN_WIDTH_160:
552 n_chans = 8;
553 frequency = cf1 - 70;
554 break;
58b73e3d
JD
555 default:
556 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
557 chan_width);
558 break;
559 }
560
561 wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
562 n_chans);
563 for (i = 0; i < n_chans; i++) {
dc036d9e 564 ret += set_dfs_state_freq(iface, frequency, state);
58b73e3d 565 frequency = frequency + 20;
530b8ee3
LW
566
567 if (chan_width == CHAN_WIDTH_80P80) {
568 ret += set_dfs_state_freq(iface, frequency2, state);
569 frequency2 = frequency2 + 20;
570 }
58b73e3d
JD
571 }
572
573 return ret;
574}
575
576
dc036d9e 577static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
58b73e3d
JD
578 int chan_width, int cf1, int cf2)
579{
4a274f48 580 int start_chan_idx, start_chan_idx1;
58b73e3d
JD
581 struct hostapd_hw_modes *mode;
582 struct hostapd_channel_data *chan;
4a274f48 583 int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
58b73e3d
JD
584 u8 radar_chan;
585 int res = 0;
586
58b73e3d 587 /* Our configuration */
dc036d9e 588 mode = iface->current_mode;
4a274f48
JM
589 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
590 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
58b73e3d 591
5eaf240a 592 /* Check we are on DFS channel(s) */
dc036d9e 593 if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
5eaf240a
JD
594 return 0;
595
58b73e3d
JD
596 /* Reported via radar event */
597 switch (chan_width) {
598 case CHAN_WIDTH_20_NOHT:
599 case CHAN_WIDTH_20:
600 radar_n_chans = 1;
bb337dda
JM
601 if (frequency == 0)
602 frequency = cf1;
58b73e3d
JD
603 break;
604 case CHAN_WIDTH_40:
605 radar_n_chans = 2;
606 frequency = cf1 - 10;
607 break;
608 case CHAN_WIDTH_80:
609 radar_n_chans = 4;
610 frequency = cf1 - 30;
611 break;
899cc14e
JD
612 case CHAN_WIDTH_160:
613 radar_n_chans = 8;
614 frequency = cf1 - 70;
615 break;
58b73e3d
JD
616 default:
617 wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
618 chan_width);
619 break;
620 }
621
622 ieee80211_freq_to_chan(frequency, &radar_chan);
623
624 for (i = 0; i < n_chans; i++) {
625 chan = &mode->channels[start_chan_idx + i];
5eaf240a
JD
626 if (!(chan->flag & HOSTAPD_CHAN_RADAR))
627 continue;
58b73e3d
JD
628 for (j = 0; j < radar_n_chans; j++) {
629 wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
630 chan->chan, radar_chan + j * 4);
631 if (chan->chan == radar_chan + j * 4)
632 res++;
633 }
634 }
635
636 wpa_printf(MSG_DEBUG, "overlapped: %d", res);
637
638 return res;
639}
640
641
bbbacbf2
JD
642static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
643 int start_chan_idx, int n_chans)
644{
645 struct hostapd_channel_data *channel;
646 struct hostapd_hw_modes *mode;
647 int i;
648 unsigned int cac_time_ms = 0;
649
650 mode = iface->current_mode;
651
652 for (i = 0; i < n_chans; i++) {
653 channel = &mode->channels[start_chan_idx + i];
654 if (!(channel->flag & HOSTAPD_CHAN_RADAR))
655 continue;
656 if (channel->dfs_cac_ms > cac_time_ms)
657 cac_time_ms = channel->dfs_cac_ms;
658 }
659
660 return cac_time_ms;
661}
662
663
e76da505
JD
664/*
665 * Main DFS handler
666 * 1 - continue channel/ap setup
667 * 0 - channel/ap setup will be continued after CAC
668 * -1 - hit critical error
669 */
dc036d9e 670int hostapd_handle_dfs(struct hostapd_iface *iface)
e76da505 671{
e76da505 672 struct hostapd_channel_data *channel;
4a274f48 673 int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
b72f949b 674 int skip_radar = 0;
58b73e3d 675
afbe57d9
JM
676 if (!iface->current_mode) {
677 /*
678 * This can happen with drivers that do not provide mode
679 * information and as such, cannot really use hostapd for DFS.
680 */
681 wpa_printf(MSG_DEBUG,
682 "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
683 return 1;
684 }
685
dc036d9e 686 iface->cac_started = 0;
954e71d2 687
58b73e3d
JD
688 do {
689 /* Get start (first) channel for current configuration */
4a274f48
JM
690 start_chan_idx = dfs_get_start_chan_idx(iface,
691 &start_chan_idx1);
58b73e3d
JD
692 if (start_chan_idx == -1)
693 return -1;
694
695 /* Get number of used channels, depend on width */
4a274f48 696 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
58b73e3d 697
bbbacbf2
JD
698 /* Setup CAC time */
699 iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
700 n_chans);
701
58b73e3d 702 /* Check if any of configured channels require DFS */
dc036d9e 703 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
58b73e3d
JD
704 wpa_printf(MSG_DEBUG,
705 "DFS %d channels required radar detection",
706 res);
707 if (!res)
708 return 1;
709
710 /* Check if all channels are DFS available */
dc036d9e 711 res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
58b73e3d
JD
712 wpa_printf(MSG_DEBUG,
713 "DFS all channels available, (SKIP CAC): %s",
714 res ? "yes" : "no");
715 if (res)
716 return 1;
717
718 /* Check if any of configured channels is unavailable */
dc036d9e 719 res = dfs_check_chans_unavailable(iface, start_chan_idx,
58b73e3d
JD
720 n_chans);
721 wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
722 res, res ? "yes": "no");
723 if (res) {
5479ff90
MS
724 int sec = 0;
725 u8 cf1 = 0, cf2 = 0;
32595da6 726
b72f949b
MK
727 channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
728 skip_radar);
e76da505
JD
729 if (!channel) {
730 wpa_printf(MSG_ERROR, "could not get valid channel");
3bd58861
ZK
731 hostapd_set_state(iface, HAPD_IFACE_DFS);
732 return 0;
e76da505 733 }
32595da6 734
dc036d9e
JM
735 iface->freq = channel->freq;
736 iface->conf->channel = channel->chan;
737 iface->conf->secondary_channel = sec;
c6b7ac07
JC
738 hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
739 hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
e76da505 740 }
58b73e3d
JD
741 } while (res);
742
743 /* Finally start CAC */
dc036d9e
JM
744 hostapd_set_state(iface, HAPD_IFACE_DFS);
745 wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
746 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
bbbacbf2 747 "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
dc036d9e 748 iface->freq,
1f374834 749 iface->conf->channel, iface->conf->secondary_channel,
c6b7ac07
JC
750 hostapd_get_oper_chwidth(iface->conf),
751 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
752 hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
bbbacbf2 753 iface->dfs_cac_ms / 1000);
1f374834 754
c6b7ac07
JC
755 res = hostapd_start_dfs_cac(
756 iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
757 iface->conf->ieee80211n, iface->conf->ieee80211ac,
88005ee9 758 iface->conf->ieee80211ax,
c6b7ac07
JC
759 iface->conf->secondary_channel,
760 hostapd_get_oper_chwidth(iface->conf),
761 hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
762 hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
1f374834
JD
763
764 if (res) {
765 wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
58b73e3d 766 return -1;
e76da505
JD
767 }
768
58b73e3d 769 return 0;
e76da505
JD
770}
771
772
3dcd735c
VT
773static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
774{
775 int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
776
777 /* Get the start (first) channel for current configuration */
778 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
779 if (start_chan_idx < 0)
780 return 0;
781
782 /* Get the number of used channels, depending on width */
783 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
784
785 /* Check if all channels are DFS available */
786 return dfs_check_chans_available(iface, start_chan_idx, n_chans);
787}
788
789
dc036d9e 790int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
58b73e3d
JD
791 int ht_enabled, int chan_offset, int chan_width,
792 int cf1, int cf2)
e76da505 793{
dc036d9e 794 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
186c9059
JM
795 "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
796 success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
797
e76da505
JD
798 if (success) {
799 /* Complete iface/ap configuration */
5de81d7a
AK
800 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
801 /* Complete AP configuration for the first bring up. */
802 if (iface->state != HAPD_IFACE_ENABLED)
803 hostapd_setup_interface_complete(iface, 0);
804 else
805 iface->cac_started = 0;
806 } else {
807 set_dfs_state(iface, freq, ht_enabled, chan_offset,
808 chan_width, cf1, cf2,
809 HOSTAPD_CHAN_DFS_AVAILABLE);
3dcd735c
VT
810 /*
811 * Just mark the channel available when CAC completion
812 * event is received in enabled state. CAC result could
813 * have been propagated from another radio having the
814 * same regulatory configuration. When CAC completion is
815 * received during non-HAPD_IFACE_ENABLED state, make
816 * sure the configured channel is available because this
817 * CAC completion event could have been propagated from
818 * another radio.
819 */
820 if (iface->state != HAPD_IFACE_ENABLED &&
821 hostapd_config_dfs_chan_available(iface)) {
822 hostapd_setup_interface_complete(iface, 0);
823 iface->cac_started = 0;
824 }
5de81d7a 825 }
e76da505
JD
826 }
827
828 return 0;
829}
830
831
7cbb5f1a
VT
832int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
833 int ht_enabled, int chan_offset, int chan_width,
834 int cf1, int cf2)
835{
836 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
837 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
838 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
839
840 /* Proceed only if DFS is not offloaded to the driver */
841 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
842 return 0;
843
844 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
845 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
846
847 return 0;
848}
849
850
f7154cee 851static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
e76da505
JD
852{
853 struct hostapd_channel_data *channel;
f7154cee 854 int secondary_channel;
7118a697
JC
855 u8 oper_centr_freq_seg0_idx = 0;
856 u8 oper_centr_freq_seg1_idx = 0;
f7154cee 857 int skip_radar = 0;
e76da505 858 int err = 1;
f7154cee
JD
859
860 /* Radar detected during active CAC */
861 iface->cac_started = 0;
862 channel = dfs_get_valid_channel(iface, &secondary_channel,
7118a697
JC
863 &oper_centr_freq_seg0_idx,
864 &oper_centr_freq_seg1_idx,
f7154cee
JD
865 skip_radar);
866
867 if (!channel) {
868 wpa_printf(MSG_ERROR, "No valid channel available");
f7154cee
JD
869 return err;
870 }
871
872 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
873 channel->chan);
874 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
875 "freq=%d chan=%d sec_chan=%d", channel->freq,
876 channel->chan, secondary_channel);
877
878 iface->freq = channel->freq;
879 iface->conf->channel = channel->chan;
880 iface->conf->secondary_channel = secondary_channel;
c6b7ac07
JC
881 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
882 oper_centr_freq_seg0_idx);
883 hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
884 oper_centr_freq_seg1_idx);
f7154cee
JD
885 err = 0;
886
887 hostapd_setup_interface_complete(iface, err);
888 return err;
889}
890
891
892static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
893{
894 struct hostapd_channel_data *channel;
32595da6 895 int secondary_channel;
7118a697
JC
896 u8 oper_centr_freq_seg0_idx;
897 u8 oper_centr_freq_seg1_idx;
b72f949b 898 int skip_radar = 1;
f7154cee 899 struct csa_settings csa_settings;
8974620e 900 unsigned int i;
f7154cee 901 int err = 1;
29d8bd1d 902 struct hostapd_hw_modes *cmode = iface->current_mode;
f7154cee 903
25592b23
JD
904 wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
905 __func__, iface->cac_started ? "yes" : "no",
6782b684 906 hostapd_csa_in_progress(iface) ? "yes" : "no");
25592b23
JD
907
908 /* Check if CSA in progress */
6782b684 909 if (hostapd_csa_in_progress(iface))
25592b23 910 return 0;
f7154cee
JD
911
912 /* Check if active CAC */
913 if (iface->cac_started)
914 return hostapd_dfs_start_channel_switch_cac(iface);
e76da505 915
04f667fc
VT
916 /*
917 * Allow selection of DFS channel in ETSI to comply with
918 * uniform spreading.
919 */
920 if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
921 skip_radar = 0;
922
f7154cee 923 /* Perform channel switch/CSA */
dc036d9e 924 channel = dfs_get_valid_channel(iface, &secondary_channel,
7118a697
JC
925 &oper_centr_freq_seg0_idx,
926 &oper_centr_freq_seg1_idx,
b72f949b 927 skip_radar);
813d4bac 928
f7154cee 929 if (!channel) {
e0700512
SW
930 /*
931 * If there is no channel to switch immediately to, check if
932 * there is another channel where we can switch even if it
933 * requires to perform a CAC first.
934 */
935 skip_radar = 0;
936 channel = dfs_get_valid_channel(iface, &secondary_channel,
7118a697
JC
937 &oper_centr_freq_seg0_idx,
938 &oper_centr_freq_seg1_idx,
e0700512
SW
939 skip_radar);
940 if (!channel) {
3bd58861
ZK
941 wpa_printf(MSG_INFO,
942 "%s: no DFS channels left, waiting for NOP to finish",
943 __func__);
e0700512
SW
944 return err;
945 }
946
947 iface->freq = channel->freq;
948 iface->conf->channel = channel->chan;
949 iface->conf->secondary_channel = secondary_channel;
c6b7ac07
JC
950 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
951 oper_centr_freq_seg0_idx);
952 hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
953 oper_centr_freq_seg1_idx);
e0700512 954
f7154cee 955 hostapd_disable_iface(iface);
e0700512
SW
956 hostapd_enable_iface(iface);
957 return 0;
f7154cee
JD
958 }
959
960 wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
961 channel->chan);
962 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
963 "freq=%d chan=%d sec_chan=%d", channel->freq,
964 channel->chan, secondary_channel);
965
966 /* Setup CSA request */
967 os_memset(&csa_settings, 0, sizeof(csa_settings));
968 csa_settings.cs_count = 5;
969 csa_settings.block_tx = 1;
970 err = hostapd_set_freq_params(&csa_settings.freq_params,
971 iface->conf->hw_mode,
972 channel->freq,
973 channel->chan,
bebd91e9
AAL
974 iface->conf->enable_edmg,
975 iface->conf->edmg_channel,
f7154cee
JD
976 iface->conf->ieee80211n,
977 iface->conf->ieee80211ac,
88005ee9 978 iface->conf->ieee80211ax,
f7154cee 979 secondary_channel,
c6b7ac07 980 hostapd_get_oper_chwidth(iface->conf),
7118a697
JC
981 oper_centr_freq_seg0_idx,
982 oper_centr_freq_seg1_idx,
29d8bd1d
SE
983 cmode->vht_capab,
984 &cmode->he_capab[IEEE80211_MODE_AP]);
f7154cee
JD
985
986 if (err) {
987 wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
988 hostapd_disable_iface(iface);
989 return err;
990 }
991
8974620e
MK
992 for (i = 0; i < iface->num_bss; i++) {
993 err = hostapd_switch_channel(iface->bss[i], &csa_settings);
994 if (err)
995 break;
996 }
997
f7154cee
JD
998 if (err) {
999 wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
1000 err);
dc036d9e
JM
1001 iface->freq = channel->freq;
1002 iface->conf->channel = channel->chan;
1003 iface->conf->secondary_channel = secondary_channel;
c6b7ac07
JC
1004 hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1005 oper_centr_freq_seg0_idx);
1006 hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1007 oper_centr_freq_seg1_idx);
813d4bac 1008
dc036d9e 1009 hostapd_disable_iface(iface);
f7154cee
JD
1010 hostapd_enable_iface(iface);
1011 return 0;
2e946249 1012 }
e76da505 1013
f7154cee
JD
1014 /* Channel configuration will be updated once CSA completes and
1015 * ch_switch_notify event is received */
1016
1017 wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
e76da505
JD
1018 return 0;
1019}
58b73e3d
JD
1020
1021
dc036d9e 1022int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
58b73e3d
JD
1023 int ht_enabled, int chan_offset, int chan_width,
1024 int cf1, int cf2)
1025{
1026 int res;
1027
dc036d9e 1028 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
186c9059
JM
1029 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1030 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1031
5de81d7a
AK
1032 /* Proceed only if DFS is not offloaded to the driver */
1033 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1034 return 0;
1035
1036 if (!iface->conf->ieee80211h)
1037 return 0;
1038
58b73e3d 1039 /* mark radar frequency as invalid */
c0e46bb7
JM
1040 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1041 cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
58b73e3d
JD
1042
1043 /* Skip if reported radar event not overlapped our channels */
dc036d9e 1044 res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
58b73e3d
JD
1045 if (!res)
1046 return 0;
1047
58b73e3d 1048 /* radar detected while operating, switch the channel. */
dc036d9e 1049 res = hostapd_dfs_start_channel_switch(iface);
58b73e3d
JD
1050
1051 return res;
1052}
1053
1054
dc036d9e 1055int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
58b73e3d
JD
1056 int ht_enabled, int chan_offset, int chan_width,
1057 int cf1, int cf2)
1058{
dc036d9e 1059 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
186c9059
JM
1060 "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1061 freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
5de81d7a
AK
1062
1063 /* Proceed only if DFS is not offloaded to the driver */
1064 if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1065 return 0;
1066
58b73e3d 1067 /* TODO add correct implementation here */
dc036d9e
JM
1068 set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1069 cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
3bd58861
ZK
1070
1071 /* Handle cases where all channels were initially unavailable */
1072 if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
1073 hostapd_handle_dfs(iface);
1074
58b73e3d
JD
1075 return 0;
1076}
3d7ad2f6
C
1077
1078
1079int hostapd_is_dfs_required(struct hostapd_iface *iface)
1080{
4a274f48 1081 int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
3d7ad2f6 1082
8a0f3bf6
MP
1083 if (!iface->conf->ieee80211h || !iface->current_mode ||
1084 iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1085 return 0;
3d7ad2f6
C
1086
1087 /* Get start (first) channel for current configuration */
4a274f48 1088 start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
3d7ad2f6
C
1089 if (start_chan_idx == -1)
1090 return -1;
1091
1092 /* Get number of used channels, depend on width */
4a274f48 1093 n_chans = dfs_get_used_n_chans(iface, &n_chans1);
3d7ad2f6
C
1094
1095 /* Check if any of configured channels require DFS */
4a274f48
JM
1096 res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1097 if (res)
1098 return res;
1099 if (start_chan_idx1 >= 0 && n_chans1 > 0)
1100 res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1101 return res;
3d7ad2f6 1102}
c13578c3
AK
1103
1104
1105int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
1106 int ht_enabled, int chan_offset, int chan_width,
1107 int cf1, int cf2)
1108{
02292618
HW
1109 /* This is called when the driver indicates that an offloaded DFS has
1110 * started CAC. */
1111 hostapd_set_state(iface, HAPD_IFACE_DFS);
1112 /* TODO: How to check CAC time for ETSI weather channels? */
1113 iface->dfs_cac_ms = 60000;
c13578c3
AK
1114 wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1115 "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1116 "seg1=%d cac_time=%ds",
02292618
HW
1117 freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
1118 iface->dfs_cac_ms / 1000);
c13578c3 1119 iface->cac_started = 1;
02292618 1120 os_get_reltime(&iface->dfs_cac_start);
c13578c3
AK
1121 return 0;
1122}
1123
1124
1125/*
1126 * Main DFS handler for offloaded case.
1127 * 2 - continue channel/AP setup for non-DFS channel
1128 * 1 - continue channel/AP setup for DFS channel
1129 * 0 - channel/AP setup will be continued after CAC
1130 * -1 - hit critical error
1131 */
1132int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1133{
1134 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1135 __func__, iface->cac_started);
1136
1137 /*
1138 * If DFS has already been started, then we are being called from a
1139 * callback to continue AP/channel setup. Reset the CAC start flag and
1140 * return.
1141 */
1142 if (iface->cac_started) {
1143 wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1144 __func__, iface->cac_started);
1145 iface->cac_started = 0;
1146 return 1;
1147 }
1148
d239ab39 1149 if (ieee80211_is_dfs(iface->freq, iface->hw_features,
1150 iface->num_hw_features)) {
c13578c3
AK
1151 wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
1152 __func__, iface->freq);
1153 return 0;
1154 }
1155
1156 wpa_printf(MSG_DEBUG,
1157 "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1158 __func__, iface->freq);
1159 return 2;
1160}