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
22static 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
54static 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
77static 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
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
139static 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
191static 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 */
208static 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
266static 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] */
315static 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 */
402static 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 */
422static 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 */
450static 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
473static struct hostapd_channel_data *
474dfs_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
571static 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
597static 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
663static 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
728static 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 */
756int 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
862int 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
879int 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
921int 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
940static struct hostapd_channel_data *
941dfs_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
978static 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
1025static 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
1171int 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
1206int 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
1230int 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
1258int 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 */
1285int 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
1319int 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