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