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