xref: /freebsd/contrib/wpa/src/ap/dfs.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
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  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10 
11 #include "utils/includes.h"
12 
13 #include "utils/common.h"
14 #include "common/ieee802_11_defs.h"
15 #include "common/hw_features_common.h"
16 #include "common/wpa_ctrl.h"
17 #include "hostapd.h"
18 #include "beacon.h"
19 #include "ap_drv_ops.h"
20 #include "drivers/driver.h"
21 #include "dfs.h"
22 
23 
24 enum dfs_channel_type {
25 	DFS_ANY_CHANNEL,
26 	DFS_AVAILABLE, /* non-radar or radar-available */
27 	DFS_NO_CAC_YET, /* radar-not-yet-available */
28 };
29 
30 static struct hostapd_channel_data *
31 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
32 			u8 *oper_centr_freq_seg0_idx,
33 			u8 *oper_centr_freq_seg1_idx,
34 			enum dfs_channel_type *channel_type);
35 
36 
dfs_use_radar_background(struct hostapd_iface * iface)37 static bool dfs_use_radar_background(struct hostapd_iface *iface)
38 {
39 	return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) &&
40 		iface->conf->enable_background_radar;
41 }
42 
43 
dfs_get_used_n_chans(struct hostapd_iface * iface,int * seg1)44 static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
45 {
46 	int n_chans = 1;
47 
48 	*seg1 = 0;
49 
50 	if (iface->conf->ieee80211n && iface->conf->secondary_channel)
51 		n_chans = 2;
52 
53 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
54 		switch (hostapd_get_oper_chwidth(iface->conf)) {
55 		case CONF_OPER_CHWIDTH_USE_HT:
56 			break;
57 		case CONF_OPER_CHWIDTH_80MHZ:
58 			n_chans = 4;
59 			break;
60 		case CONF_OPER_CHWIDTH_160MHZ:
61 			n_chans = 8;
62 			break;
63 		case CONF_OPER_CHWIDTH_80P80MHZ:
64 			n_chans = 4;
65 			*seg1 = 4;
66 			break;
67 		default:
68 			break;
69 		}
70 	}
71 
72 	return n_chans;
73 }
74 
75 
76 /* dfs_channel_available: select new channel according to type parameter */
dfs_channel_available(struct hostapd_channel_data * chan,enum dfs_channel_type type)77 static int dfs_channel_available(struct hostapd_channel_data *chan,
78 				 enum dfs_channel_type type)
79 {
80 	if (type == DFS_NO_CAC_YET) {
81 		/* Select only radar channel where CAC has not been
82 		 * performed yet
83 		 */
84 		if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
85 		    (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
86 		     HOSTAPD_CHAN_DFS_USABLE)
87 			return 1;
88 		return 0;
89 	}
90 
91 	/*
92 	 * When radar detection happens, CSA is performed. However, there's no
93 	 * time for CAC, so radar channels must be skipped when finding a new
94 	 * channel for CSA, unless they are available for immediate use.
95 	 */
96 	if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
97 	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
98 	     HOSTAPD_CHAN_DFS_AVAILABLE))
99 		return 0;
100 
101 	if (chan->flag & HOSTAPD_CHAN_DISABLED)
102 		return 0;
103 	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
104 	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
105 	     HOSTAPD_CHAN_DFS_UNAVAILABLE))
106 		return 0;
107 	return 1;
108 }
109 
110 
dfs_is_chan_allowed(struct hostapd_channel_data * chan,int n_chans)111 static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
112 {
113 	/*
114 	 * The tables contain first valid channel number based on channel width.
115 	 * We will also choose this first channel as the control one.
116 	 */
117 	int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
118 			     165, 173, 184, 192 };
119 	/*
120 	 * VHT80, valid channels based on center frequency:
121 	 * 42, 58, 106, 122, 138, 155, 171
122 	 */
123 	int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
124 	/*
125 	 * VHT160 valid channels based on center frequency:
126 	 * 50, 114, 163
127 	 */
128 	int allowed_160[] = { 36, 100, 149 };
129 	int *allowed = allowed_40;
130 	unsigned int i, allowed_no = 0;
131 
132 	switch (n_chans) {
133 	case 2:
134 		allowed = allowed_40;
135 		allowed_no = ARRAY_SIZE(allowed_40);
136 		break;
137 	case 4:
138 		allowed = allowed_80;
139 		allowed_no = ARRAY_SIZE(allowed_80);
140 		break;
141 	case 8:
142 		allowed = allowed_160;
143 		allowed_no = ARRAY_SIZE(allowed_160);
144 		break;
145 	default:
146 		wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
147 		break;
148 	}
149 
150 	for (i = 0; i < allowed_no; i++) {
151 		if (chan->chan == allowed[i])
152 			return 1;
153 	}
154 
155 	return 0;
156 }
157 
158 
159 static struct hostapd_channel_data *
dfs_get_chan_data(struct hostapd_hw_modes * mode,int freq,int first_chan_idx)160 dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
161 {
162 	int i;
163 
164 	for (i = first_chan_idx; i < mode->num_channels; i++) {
165 		if (mode->channels[i].freq == freq)
166 			return &mode->channels[i];
167 	}
168 
169 	return NULL;
170 }
171 
172 
dfs_chan_range_available(struct hostapd_hw_modes * mode,int first_chan_idx,int num_chans,enum dfs_channel_type type)173 static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
174 				    int first_chan_idx, int num_chans,
175 				    enum dfs_channel_type type)
176 {
177 	struct hostapd_channel_data *first_chan, *chan;
178 	int i;
179 	u32 bw = num_chan_to_bw(num_chans);
180 
181 	if (first_chan_idx + num_chans > mode->num_channels) {
182 		wpa_printf(MSG_DEBUG,
183 			   "DFS: some channels in range not defined");
184 		return 0;
185 	}
186 
187 	first_chan = &mode->channels[first_chan_idx];
188 
189 	/* hostapd DFS implementation assumes the first channel as primary.
190 	 * If it's not allowed to use the first channel as primary, decline the
191 	 * whole channel range. */
192 	if (!chan_pri_allowed(first_chan)) {
193 		wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed");
194 		return 0;
195 	}
196 
197 	for (i = 0; i < num_chans; i++) {
198 		chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
199 					 first_chan_idx);
200 		if (!chan) {
201 			wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
202 				   first_chan->freq + i * 20);
203 			return 0;
204 		}
205 
206 		/* HT 40 MHz secondary channel availability checked only for
207 		 * primary channel */
208 		if (!chan_bw_allowed(chan, bw, 1, !i)) {
209 			wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
210 				   first_chan->freq + i * 20);
211 			return 0;
212 		}
213 
214 		if (!dfs_channel_available(chan, type)) {
215 			wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
216 				   first_chan->freq + i * 20);
217 			return 0;
218 		}
219 	}
220 
221 	return 1;
222 }
223 
224 
is_in_chanlist(struct hostapd_iface * iface,struct hostapd_channel_data * chan)225 static int is_in_chanlist(struct hostapd_iface *iface,
226 			  struct hostapd_channel_data *chan)
227 {
228 	if (!iface->conf->acs_ch_list.num)
229 		return 1;
230 
231 	return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
232 }
233 
234 
235 /*
236  * The function assumes HT40+ operation.
237  * Make sure to adjust the following variables after calling this:
238  *  - hapd->secondary_channel
239  *  - hapd->vht/he_oper_centr_freq_seg0_idx
240  *  - hapd->vht/he_oper_centr_freq_seg1_idx
241  */
dfs_find_channel(struct hostapd_iface * iface,struct hostapd_channel_data ** ret_chan,int idx,enum dfs_channel_type type)242 static int dfs_find_channel(struct hostapd_iface *iface,
243 			    struct hostapd_channel_data **ret_chan,
244 			    int idx, enum dfs_channel_type type)
245 {
246 	struct hostapd_hw_modes *mode;
247 	struct hostapd_channel_data *chan;
248 	int i, channel_idx = 0, n_chans, n_chans1;
249 
250 	mode = iface->current_mode;
251 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
252 
253 	wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
254 	for (i = 0; i < mode->num_channels; i++) {
255 		chan = &mode->channels[i];
256 
257 		if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
258 			wpa_printf(MSG_DEBUG,
259 				   "DFS: channel %d (%d) is not under current hardware index",
260 				   chan->freq, chan->chan);
261 			continue;
262 		}
263 
264 		/* Skip HT40/VHT incompatible channels */
265 		if (iface->conf->ieee80211n &&
266 		    iface->conf->secondary_channel &&
267 		    (!dfs_is_chan_allowed(chan, n_chans) ||
268 		     !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
269 			wpa_printf(MSG_DEBUG,
270 				   "DFS: channel %d (%d) is incompatible",
271 				   chan->freq, chan->chan);
272 			continue;
273 		}
274 
275 		/* Skip incompatible chandefs */
276 		if (!dfs_chan_range_available(mode, i, n_chans, type)) {
277 			wpa_printf(MSG_DEBUG,
278 				   "DFS: range not available for %d (%d)",
279 				   chan->freq, chan->chan);
280 			continue;
281 		}
282 
283 		if (!is_in_chanlist(iface, chan)) {
284 			wpa_printf(MSG_DEBUG,
285 				   "DFS: channel %d (%d) not in chanlist",
286 				   chan->freq, chan->chan);
287 			continue;
288 		}
289 
290 		if (chan->max_tx_power < iface->conf->min_tx_power)
291 			continue;
292 
293 		if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
294 		    iface->conf->country[2] == 0x4f)
295 			continue;
296 
297 		if (ret_chan && idx == channel_idx) {
298 			wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
299 				   chan->freq, chan->chan);
300 			*ret_chan = chan;
301 			return idx;
302 		}
303 		wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
304 			   chan->freq, chan->chan);
305 		channel_idx++;
306 	}
307 	return channel_idx;
308 }
309 
310 
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)311 static void dfs_adjust_center_freq(struct hostapd_iface *iface,
312 				   struct hostapd_channel_data *chan,
313 				   int secondary_channel,
314 				   int sec_chan_idx_80p80,
315 				   u8 *oper_centr_freq_seg0_idx,
316 				   u8 *oper_centr_freq_seg1_idx)
317 {
318 	if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
319 		return;
320 
321 	if (!chan)
322 		return;
323 
324 	*oper_centr_freq_seg1_idx = 0;
325 
326 	switch (hostapd_get_oper_chwidth(iface->conf)) {
327 	case CONF_OPER_CHWIDTH_USE_HT:
328 		if (secondary_channel == 1)
329 			*oper_centr_freq_seg0_idx = chan->chan + 2;
330 		else if (secondary_channel == -1)
331 			*oper_centr_freq_seg0_idx = chan->chan - 2;
332 		else
333 			*oper_centr_freq_seg0_idx = chan->chan;
334 		break;
335 	case CONF_OPER_CHWIDTH_80MHZ:
336 		*oper_centr_freq_seg0_idx = chan->chan + 6;
337 		break;
338 	case CONF_OPER_CHWIDTH_160MHZ:
339 		*oper_centr_freq_seg0_idx = chan->chan + 14;
340 		break;
341 	case CONF_OPER_CHWIDTH_80P80MHZ:
342 		*oper_centr_freq_seg0_idx = chan->chan + 6;
343 		*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
344 		break;
345 
346 	default:
347 		wpa_printf(MSG_INFO,
348 			   "DFS: Unsupported channel width configuration");
349 		*oper_centr_freq_seg0_idx = 0;
350 		break;
351 	}
352 
353 	wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
354 		   *oper_centr_freq_seg0_idx,
355 		   *oper_centr_freq_seg1_idx);
356 }
357 
358 
359 /* Return start channel idx we will use for mode->channels[idx] */
dfs_get_start_chan_idx(struct hostapd_iface * iface,int * seg1_start)360 static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
361 {
362 	struct hostapd_hw_modes *mode;
363 	struct hostapd_channel_data *chan;
364 	int channel_no = iface->conf->channel;
365 	int res = -1, i;
366 	int chan_seg1 = -1;
367 
368 	*seg1_start = -1;
369 
370 	/* HT40- */
371 	if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
372 		channel_no -= 4;
373 
374 	/* VHT/HE/EHT */
375 	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
376 	    iface->conf->ieee80211be) {
377 		switch (hostapd_get_oper_chwidth(iface->conf)) {
378 		case CONF_OPER_CHWIDTH_USE_HT:
379 			break;
380 		case CONF_OPER_CHWIDTH_80MHZ:
381 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
382 				iface->conf) - 6;
383 			break;
384 		case CONF_OPER_CHWIDTH_160MHZ:
385 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
386 				iface->conf) - 14;
387 			break;
388 		case CONF_OPER_CHWIDTH_80P80MHZ:
389 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
390 				iface->conf) - 6;
391 			chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
392 				iface->conf) - 6;
393 			break;
394 		case CONF_OPER_CHWIDTH_320MHZ:
395 			channel_no = hostapd_get_oper_centr_freq_seg0_idx(
396 				iface->conf) - 30;
397 			break;
398 		default:
399 			wpa_printf(MSG_INFO,
400 				   "DFS only EHT20/40/80/160/80+80/320 is supported now");
401 			channel_no = -1;
402 			break;
403 		}
404 	}
405 
406 	/* Get idx */
407 	mode = iface->current_mode;
408 	for (i = 0; i < mode->num_channels; i++) {
409 		chan = &mode->channels[i];
410 		if (chan->chan == channel_no) {
411 			res = i;
412 			break;
413 		}
414 	}
415 
416 	if (res != -1 && chan_seg1 > -1) {
417 		int found = 0;
418 
419 		/* Get idx for seg1 */
420 		mode = iface->current_mode;
421 		for (i = 0; i < mode->num_channels; i++) {
422 			chan = &mode->channels[i];
423 			if (chan->chan == chan_seg1) {
424 				*seg1_start = i;
425 				found = 1;
426 				break;
427 			}
428 		}
429 		if (!found)
430 			res = -1;
431 	}
432 
433 	if (res == -1) {
434 		wpa_printf(MSG_DEBUG,
435 			   "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
436 			   mode->num_channels, channel_no, iface->conf->channel,
437 			   iface->conf->ieee80211n,
438 			   iface->conf->secondary_channel,
439 			   hostapd_get_oper_chwidth(iface->conf));
440 
441 		for (i = 0; i < mode->num_channels; i++) {
442 			wpa_printf(MSG_DEBUG, "Available channel: %d",
443 				   mode->channels[i].chan);
444 		}
445 	}
446 
447 	return res;
448 }
449 
450 
451 /* At least one channel have radar flag */
dfs_check_chans_radar(struct hostapd_iface * iface,int start_chan_idx,int n_chans)452 static int dfs_check_chans_radar(struct hostapd_iface *iface,
453 				 int start_chan_idx, int n_chans)
454 {
455 	struct hostapd_channel_data *channel;
456 	struct hostapd_hw_modes *mode;
457 	int i, res = 0;
458 
459 	mode = iface->current_mode;
460 
461 	for (i = 0; i < n_chans; i++) {
462 		if (start_chan_idx + i >= mode->num_channels)
463 			break;
464 		channel = &mode->channels[start_chan_idx + i];
465 		if (channel->flag & HOSTAPD_CHAN_RADAR)
466 			res++;
467 	}
468 
469 	return res;
470 }
471 
472 
473 /* All channels available */
dfs_check_chans_available(struct hostapd_iface * iface,int start_chan_idx,int n_chans)474 static int dfs_check_chans_available(struct hostapd_iface *iface,
475 				     int start_chan_idx, int n_chans)
476 {
477 	struct hostapd_channel_data *channel;
478 	struct hostapd_hw_modes *mode;
479 	int i;
480 
481 	mode = iface->current_mode;
482 
483 	for (i = 0; i < n_chans; i++) {
484 		channel = &mode->channels[start_chan_idx + i];
485 
486 		if (channel->flag & HOSTAPD_CHAN_DISABLED)
487 			break;
488 
489 		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
490 			continue;
491 
492 		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
493 		    HOSTAPD_CHAN_DFS_AVAILABLE)
494 			break;
495 	}
496 
497 	return i == n_chans;
498 }
499 
500 
501 /* At least one channel unavailable */
dfs_check_chans_unavailable(struct hostapd_iface * iface,int start_chan_idx,int n_chans)502 static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
503 				       int start_chan_idx,
504 				       int n_chans)
505 {
506 	struct hostapd_channel_data *channel;
507 	struct hostapd_hw_modes *mode;
508 	int i, res = 0;
509 
510 	mode = iface->current_mode;
511 
512 	for (i = 0; i < n_chans; i++) {
513 		channel = &mode->channels[start_chan_idx + i];
514 		if (channel->flag & HOSTAPD_CHAN_DISABLED)
515 			res++;
516 		if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
517 		    HOSTAPD_CHAN_DFS_UNAVAILABLE)
518 			res++;
519 	}
520 
521 	return res;
522 }
523 
524 
525 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,enum dfs_channel_type type)526 dfs_get_valid_channel(struct hostapd_iface *iface,
527 		      int *secondary_channel,
528 		      u8 *oper_centr_freq_seg0_idx,
529 		      u8 *oper_centr_freq_seg1_idx,
530 		      enum dfs_channel_type type)
531 {
532 	struct hostapd_hw_modes *mode;
533 	struct hostapd_channel_data *chan = NULL;
534 	struct hostapd_channel_data *chan2 = NULL;
535 	int num_available_chandefs;
536 	int chan_idx, chan_idx2;
537 	int sec_chan_idx_80p80 = -1;
538 	int i;
539 	u32 _rand;
540 
541 	wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
542 	*secondary_channel = 0;
543 	*oper_centr_freq_seg0_idx = 0;
544 	*oper_centr_freq_seg1_idx = 0;
545 
546 	if (iface->current_mode == NULL)
547 		return NULL;
548 
549 	mode = iface->current_mode;
550 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
551 		return NULL;
552 
553 	/* Get the count first */
554 	num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
555 	wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
556 		   num_available_chandefs);
557 	if (num_available_chandefs == 0)
558 		return NULL;
559 
560 	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
561 		return NULL;
562 	chan_idx = _rand % num_available_chandefs;
563 	wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d",
564 		   chan_idx, num_available_chandefs);
565 	dfs_find_channel(iface, &chan, chan_idx, type);
566 	if (!chan) {
567 		wpa_printf(MSG_DEBUG, "DFS: no random channel found");
568 		return NULL;
569 	}
570 	wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
571 		   chan->freq, chan->chan);
572 
573 	/* dfs_find_channel() calculations assume HT40+ */
574 	if (iface->conf->secondary_channel)
575 		*secondary_channel = 1;
576 	else
577 		*secondary_channel = 0;
578 
579 	/* Get secondary channel for HT80P80 */
580 	if (hostapd_get_oper_chwidth(iface->conf) ==
581 	    CONF_OPER_CHWIDTH_80P80MHZ) {
582 		if (num_available_chandefs <= 1) {
583 			wpa_printf(MSG_ERROR,
584 				   "only 1 valid chan, can't support 80+80");
585 			return NULL;
586 		}
587 
588 		/*
589 		 * Loop all channels except channel1 to find a valid channel2
590 		 * that is not adjacent to channel1.
591 		 */
592 		for (i = 0; i < num_available_chandefs - 1; i++) {
593 			/* start from chan_idx + 1, end when chan_idx - 1 */
594 			chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
595 			dfs_find_channel(iface, &chan2, chan_idx2, type);
596 			if (chan2 && abs(chan2->chan - chan->chan) > 12) {
597 				/* two channels are not adjacent */
598 				sec_chan_idx_80p80 = chan2->chan;
599 				wpa_printf(MSG_DEBUG,
600 					   "DFS: got second chan: %d (%d)",
601 					   chan2->freq, chan2->chan);
602 				break;
603 			}
604 		}
605 
606 		/* Check if we got a valid secondary channel which is not
607 		 * adjacent to the first channel.
608 		 */
609 		if (sec_chan_idx_80p80 == -1) {
610 			wpa_printf(MSG_INFO,
611 				   "DFS: failed to get chan2 for 80+80");
612 			return NULL;
613 		}
614 	}
615 
616 	dfs_adjust_center_freq(iface, chan,
617 			       *secondary_channel,
618 			       sec_chan_idx_80p80,
619 			       oper_centr_freq_seg0_idx,
620 			       oper_centr_freq_seg1_idx);
621 
622 	return chan;
623 }
624 
625 
dfs_set_valid_channel(struct hostapd_iface * iface,int skip_radar)626 static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
627 {
628 	struct hostapd_channel_data *channel;
629 	u8 cf1 = 0, cf2 = 0;
630 	int sec = 0;
631 
632 	channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
633 					skip_radar ? DFS_AVAILABLE :
634 					DFS_ANY_CHANNEL);
635 	if (!channel) {
636 		wpa_printf(MSG_ERROR, "could not get valid channel");
637 		return -1;
638 	}
639 
640 	iface->freq = channel->freq;
641 	iface->conf->channel = channel->chan;
642 	iface->conf->secondary_channel = sec;
643 	hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
644 	hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
645 
646 	return 0;
647 }
648 
649 
set_dfs_state_freq(struct hostapd_iface * iface,int freq,u32 state)650 static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
651 {
652 	struct hostapd_hw_modes *mode;
653 	struct hostapd_channel_data *chan = NULL;
654 	int i;
655 
656 	mode = iface->current_mode;
657 	if (mode == NULL)
658 		return 0;
659 
660 	wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
661 	for (i = 0; i < iface->current_mode->num_channels; i++) {
662 		chan = &iface->current_mode->channels[i];
663 		if (chan->freq == freq) {
664 			if (chan->flag & HOSTAPD_CHAN_RADAR) {
665 				chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
666 				chan->flag |= state;
667 				return 1; /* Channel found */
668 			}
669 		}
670 	}
671 	wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
672 	return 0;
673 }
674 
675 
set_dfs_state(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2,u32 state)676 static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
677 			 int chan_offset, int chan_width, int cf1,
678 			 int cf2, u32 state)
679 {
680 	int n_chans = 1, i;
681 	struct hostapd_hw_modes *mode;
682 	int frequency = freq;
683 	int frequency2 = 0;
684 	int ret = 0;
685 
686 	mode = iface->current_mode;
687 	if (mode == NULL)
688 		return 0;
689 
690 	if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
691 		wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
692 		return 0;
693 	}
694 
695 	/* Seems cf1 and chan_width is enough here */
696 	switch (chan_width) {
697 	case CHAN_WIDTH_20_NOHT:
698 	case CHAN_WIDTH_20:
699 		n_chans = 1;
700 		if (frequency == 0)
701 			frequency = cf1;
702 		break;
703 	case CHAN_WIDTH_40:
704 		n_chans = 2;
705 		frequency = cf1 - 10;
706 		break;
707 	case CHAN_WIDTH_80:
708 		n_chans = 4;
709 		frequency = cf1 - 30;
710 		break;
711 	case CHAN_WIDTH_80P80:
712 		n_chans = 4;
713 		frequency = cf1 - 30;
714 		frequency2 = cf2 - 30;
715 		break;
716 	case CHAN_WIDTH_160:
717 		n_chans = 8;
718 		frequency = cf1 - 70;
719 		break;
720 	default:
721 		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
722 			   chan_width);
723 		break;
724 	}
725 
726 	wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
727 		   n_chans);
728 	for (i = 0; i < n_chans; i++) {
729 		ret += set_dfs_state_freq(iface, frequency, state);
730 		frequency = frequency + 20;
731 
732 		if (chan_width == CHAN_WIDTH_80P80) {
733 			ret += set_dfs_state_freq(iface, frequency2, state);
734 			frequency2 = frequency2 + 20;
735 		}
736 	}
737 
738 	return ret;
739 }
740 
741 
dfs_are_channels_overlapped(struct hostapd_iface * iface,int freq,int chan_width,int cf1,int cf2)742 static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
743 				       int chan_width, int cf1, int cf2)
744 {
745 	int start_chan_idx, start_chan_idx1;
746 	struct hostapd_hw_modes *mode;
747 	struct hostapd_channel_data *chan;
748 	int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1;
749 	u8 radar_chan;
750 	int res = 0;
751 
752 	/* Our configuration */
753 	mode = iface->current_mode;
754 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
755 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
756 
757 	/* Check we are on DFS channel(s) */
758 	if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
759 		return 0;
760 
761 	/* Reported via radar event */
762 	switch (chan_width) {
763 	case CHAN_WIDTH_20_NOHT:
764 	case CHAN_WIDTH_20:
765 		radar_n_chans = 1;
766 		if (frequency == 0)
767 			frequency = cf1;
768 		break;
769 	case CHAN_WIDTH_40:
770 		radar_n_chans = 2;
771 		frequency = cf1 - 10;
772 		break;
773 	case CHAN_WIDTH_80:
774 		radar_n_chans = 4;
775 		frequency = cf1 - 30;
776 		break;
777 	case CHAN_WIDTH_160:
778 		radar_n_chans = 8;
779 		frequency = cf1 - 70;
780 		break;
781 	default:
782 		wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
783 			   chan_width);
784 		break;
785 	}
786 
787 	ieee80211_freq_to_chan(frequency, &radar_chan);
788 
789 	for (i = 0; i < n_chans; i++) {
790 		chan = &mode->channels[start_chan_idx + i];
791 		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
792 			continue;
793 		for (j = 0; j < radar_n_chans; j++) {
794 			wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
795 				   chan->chan, radar_chan + j * 4);
796 			if (chan->chan == radar_chan + j * 4)
797 				res++;
798 		}
799 	}
800 
801 	wpa_printf(MSG_DEBUG, "overlapped: %d", res);
802 
803 	return res;
804 }
805 
806 
dfs_get_cac_time(struct hostapd_iface * iface,int start_chan_idx,int n_chans)807 static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
808 				     int start_chan_idx, int n_chans)
809 {
810 	struct hostapd_channel_data *channel;
811 	struct hostapd_hw_modes *mode;
812 	int i;
813 	unsigned int cac_time_ms = 0;
814 
815 	mode = iface->current_mode;
816 
817 	for (i = 0; i < n_chans; i++) {
818 		if (start_chan_idx + i >= mode->num_channels)
819 			break;
820 		channel = &mode->channels[start_chan_idx + i];
821 		if (!(channel->flag & HOSTAPD_CHAN_RADAR))
822 			continue;
823 		if (channel->dfs_cac_ms > cac_time_ms)
824 			cac_time_ms = channel->dfs_cac_ms;
825 	}
826 
827 	return cac_time_ms;
828 }
829 
830 
831 /*
832  * Main DFS handler
833  * 1 - continue channel/ap setup
834  * 0 - channel/ap setup will be continued after CAC
835  * -1 - hit critical error
836  */
hostapd_handle_dfs(struct hostapd_iface * iface)837 int hostapd_handle_dfs(struct hostapd_iface *iface)
838 {
839 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
840 	int skip_radar = 0;
841 
842 	if (is_6ghz_freq(iface->freq))
843 		return 1;
844 
845 	if (!iface->current_mode) {
846 		/*
847 		 * This can happen with drivers that do not provide mode
848 		 * information and as such, cannot really use hostapd for DFS.
849 		 */
850 		wpa_printf(MSG_DEBUG,
851 			   "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
852 		return 1;
853 	}
854 
855 	iface->cac_started = 0;
856 
857 	do {
858 		/* Get start (first) channel for current configuration */
859 		start_chan_idx = dfs_get_start_chan_idx(iface,
860 							&start_chan_idx1);
861 		if (start_chan_idx == -1)
862 			return -1;
863 
864 		/* Get number of used channels, depend on width */
865 		n_chans = dfs_get_used_n_chans(iface, &n_chans1);
866 
867 		/* Setup CAC time */
868 		iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
869 						     n_chans);
870 
871 		/* Check if any of configured channels require DFS */
872 		res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
873 		wpa_printf(MSG_DEBUG,
874 			   "DFS %d channels required radar detection",
875 			   res);
876 		if (!res)
877 			return 1;
878 
879 		/* Check if all channels are DFS available */
880 		res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
881 		wpa_printf(MSG_DEBUG,
882 			   "DFS all channels available, (SKIP CAC): %s",
883 			   res ? "yes" : "no");
884 		if (res)
885 			return 1;
886 
887 		/* Check if any of configured channels is unavailable */
888 		res = dfs_check_chans_unavailable(iface, start_chan_idx,
889 						  n_chans);
890 		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
891 			   res, res ? "yes": "no");
892 		if (res) {
893 			if (dfs_set_valid_channel(iface, skip_radar) < 0) {
894 				hostapd_set_state(iface, HAPD_IFACE_DFS);
895 				return 0;
896 			}
897 		}
898 	} while (res);
899 
900 	/* Finally start CAC */
901 	hostapd_set_state(iface, HAPD_IFACE_DFS);
902 	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
903 		   dfs_use_radar_background(iface) ? " (background)" : "");
904 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
905 		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
906 		iface->freq,
907 		iface->conf->channel, iface->conf->secondary_channel,
908 		hostapd_get_oper_chwidth(iface->conf),
909 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
910 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
911 		iface->dfs_cac_ms / 1000);
912 
913 	res = hostapd_start_dfs_cac(
914 		iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
915 		iface->conf->ieee80211n, iface->conf->ieee80211ac,
916 		iface->conf->ieee80211ax, iface->conf->ieee80211be,
917 		iface->conf->secondary_channel,
918 		hostapd_get_oper_chwidth(iface->conf),
919 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
920 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
921 		dfs_use_radar_background(iface));
922 
923 	if (res) {
924 		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
925 		return -1;
926 	}
927 
928 	if (dfs_use_radar_background(iface)) {
929 		/* Cache background radar parameters. */
930 		iface->radar_background.channel = iface->conf->channel;
931 		iface->radar_background.secondary_channel =
932 			iface->conf->secondary_channel;
933 		iface->radar_background.freq = iface->freq;
934 		iface->radar_background.centr_freq_seg0_idx =
935 			hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
936 		iface->radar_background.centr_freq_seg1_idx =
937 			hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
938 
939 		/*
940 		 * Let's select a random channel according to the
941 		 * regulations and perform CAC on dedicated radar chain.
942 		 */
943 		res = dfs_set_valid_channel(iface, 1);
944 		if (res < 0)
945 			return res;
946 
947 		iface->radar_background.temp_ch = 1;
948 		return 1;
949 	}
950 
951 	return 0;
952 }
953 
954 
hostapd_is_dfs_chan_available(struct hostapd_iface * iface)955 int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
956 {
957 	int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
958 
959 	/* Get the start (first) channel for current configuration */
960 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
961 	if (start_chan_idx < 0)
962 		return 0;
963 
964 	/* Get the number of used channels, depending on width */
965 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
966 
967 	/* Check if all channels are DFS available */
968 	return dfs_check_chans_available(iface, start_chan_idx, n_chans);
969 }
970 
971 
hostapd_dfs_request_channel_switch(struct hostapd_iface * iface,int channel,int freq,int secondary_channel,u8 current_vht_oper_chwidth,u8 oper_centr_freq_seg0_idx,u8 oper_centr_freq_seg1_idx)972 static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
973 					      int channel, int freq,
974 					      int secondary_channel,
975 					      u8 current_vht_oper_chwidth,
976 					      u8 oper_centr_freq_seg0_idx,
977 					      u8 oper_centr_freq_seg1_idx)
978 {
979 	struct hostapd_hw_modes *cmode = iface->current_mode;
980 	int ieee80211_mode = IEEE80211_MODE_AP, err;
981 	struct csa_settings csa_settings;
982 	u8 new_vht_oper_chwidth;
983 	unsigned int i;
984 	unsigned int num_err = 0;
985 	u8 op_class, chan;
986 
987 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
988 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
989 		"freq=%d chan=%d sec_chan=%d", freq, channel,
990 		secondary_channel);
991 
992 	new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
993 	hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
994 	if (ieee80211_freq_to_channel_ext(freq, secondary_channel,
995 					  new_vht_oper_chwidth, &op_class,
996 					  &chan) != NUM_HOSTAPD_MODES) {
997 		wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
998 			   iface->conf->op_class, op_class);
999 		iface->conf->op_class = op_class;
1000 	}
1001 
1002 	/* Setup CSA request */
1003 	os_memset(&csa_settings, 0, sizeof(csa_settings));
1004 	csa_settings.cs_count = 5;
1005 	csa_settings.block_tx = 1;
1006 	csa_settings.link_id = -1;
1007 #ifdef CONFIG_IEEE80211BE
1008 	if (iface->bss[0]->conf->mld_ap)
1009 		csa_settings.link_id = iface->bss[0]->mld_link_id;
1010 #endif /* CONFIG_IEEE80211BE */
1011 #ifdef CONFIG_MESH
1012 	if (iface->mconf)
1013 		ieee80211_mode = IEEE80211_MODE_MESH;
1014 #endif /* CONFIG_MESH */
1015 	err = hostapd_set_freq_params(&csa_settings.freq_params,
1016 				      iface->conf->hw_mode,
1017 				      freq, channel,
1018 				      iface->conf->enable_edmg,
1019 				      iface->conf->edmg_channel,
1020 				      iface->conf->ieee80211n,
1021 				      iface->conf->ieee80211ac,
1022 				      iface->conf->ieee80211ax,
1023 				      iface->conf->ieee80211be,
1024 				      secondary_channel,
1025 				      new_vht_oper_chwidth,
1026 				      oper_centr_freq_seg0_idx,
1027 				      oper_centr_freq_seg1_idx,
1028 				      cmode->vht_capab,
1029 				      &cmode->he_capab[ieee80211_mode],
1030 				      &cmode->eht_capab[ieee80211_mode],
1031 				      hostapd_get_punct_bitmap(iface->bss[0]));
1032 
1033 	if (err) {
1034 		wpa_printf(MSG_ERROR,
1035 			   "DFS failed to calculate CSA freq params");
1036 		hostapd_disable_iface(iface);
1037 		return err;
1038 	}
1039 
1040 	for (i = 0; i < iface->num_bss; i++) {
1041 		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
1042 		if (err)
1043 			num_err++;
1044 	}
1045 
1046 	if (num_err == iface->num_bss) {
1047 		wpa_printf(MSG_WARNING,
1048 			   "DFS failed to schedule CSA (%d) - trying fallback",
1049 			   err);
1050 		iface->freq = freq;
1051 		iface->conf->channel = channel;
1052 		iface->conf->secondary_channel = secondary_channel;
1053 		hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
1054 		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1055 						     oper_centr_freq_seg0_idx);
1056 		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1057 						     oper_centr_freq_seg1_idx);
1058 		if (ieee80211_freq_to_channel_ext(freq, secondary_channel,
1059 						  new_vht_oper_chwidth,
1060 						  &op_class, &chan) !=
1061 		    NUM_HOSTAPD_MODES) {
1062 			wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
1063 				   iface->conf->op_class, op_class);
1064 			iface->conf->op_class = op_class;
1065 		}
1066 
1067 		hostapd_disable_iface(iface);
1068 		hostapd_enable_iface(iface);
1069 
1070 		return 0;
1071 	}
1072 
1073 	/* Channel configuration will be updated once CSA completes and
1074 	 * ch_switch_notify event is received */
1075 	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
1076 
1077 	return 0;
1078 }
1079 
1080 
hostapd_dfs_update_background_chain(struct hostapd_iface * iface)1081 static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface)
1082 {
1083 	int sec = 0;
1084 	enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
1085 	struct hostapd_channel_data *channel;
1086 	u8 oper_centr_freq_seg0_idx = 0;
1087 	u8 oper_centr_freq_seg1_idx = 0;
1088 
1089 	/*
1090 	 * Allow selection of DFS channel in ETSI to comply with
1091 	 * uniform spreading.
1092 	 */
1093 	if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1094 		channel_type = DFS_ANY_CHANNEL;
1095 
1096 	channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
1097 					&oper_centr_freq_seg1_idx,
1098 					channel_type);
1099 	if (!channel ||
1100 	    channel->chan == iface->conf->channel ||
1101 	    channel->chan == iface->radar_background.channel)
1102 		channel = dfs_downgrade_bandwidth(iface, &sec,
1103 						  &oper_centr_freq_seg0_idx,
1104 						  &oper_centr_freq_seg1_idx,
1105 						  &channel_type);
1106 	if (!channel ||
1107 	    hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
1108 				  channel->freq, channel->chan,
1109 				  iface->conf->ieee80211n,
1110 				  iface->conf->ieee80211ac,
1111 				  iface->conf->ieee80211ax,
1112 				  iface->conf->ieee80211be,
1113 				  sec, hostapd_get_oper_chwidth(iface->conf),
1114 				  oper_centr_freq_seg0_idx,
1115 				  oper_centr_freq_seg1_idx, true)) {
1116 		wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
1117 		iface->radar_background.channel = -1;
1118 		return;
1119 	}
1120 
1121 	iface->radar_background.channel = channel->chan;
1122 	iface->radar_background.freq = channel->freq;
1123 	iface->radar_background.secondary_channel = sec;
1124 	iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
1125 	iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
1126 
1127 	wpa_printf(MSG_DEBUG,
1128 		   "%s: setting background chain to chan %d (%d MHz)",
1129 		   __func__, channel->chan, channel->freq);
1130 }
1131 
1132 
1133 static bool
hostapd_is_freq_in_current_hw_info(struct hostapd_iface * iface,int freq)1134 hostapd_is_freq_in_current_hw_info(struct hostapd_iface *iface, int freq)
1135 {
1136 	struct hostapd_channel_data *chan;
1137 
1138 	if (!iface->current_mode)
1139 		return false;
1140 
1141 	chan = hw_mode_get_channel(iface->current_mode, freq, NULL);
1142 
1143 	/* If channel data is not found for the given frequency, consider it is
1144 	 * out of the current hardware info. */
1145 	if (!chan)
1146 		return false;
1147 
1148 	return chan_in_current_hw_info(iface->current_hw_info, chan);
1149 }
1150 
1151 
1152 static bool
hostapd_dfs_is_background_event(struct hostapd_iface * iface,int freq)1153 hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
1154 {
1155 	return dfs_use_radar_background(iface) &&
1156 		iface->radar_background.channel != -1 &&
1157 		iface->radar_background.freq == freq;
1158 }
1159 
1160 
1161 static int
hostapd_dfs_start_channel_switch_background(struct hostapd_iface * iface)1162 hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
1163 {
1164 	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1165 
1166 	iface->conf->channel = iface->radar_background.channel;
1167 	iface->freq = iface->radar_background.freq;
1168 	iface->conf->secondary_channel =
1169 		iface->radar_background.secondary_channel;
1170 	hostapd_set_oper_centr_freq_seg0_idx(
1171 		iface->conf, iface->radar_background.centr_freq_seg0_idx);
1172 	hostapd_set_oper_centr_freq_seg1_idx(
1173 		iface->conf, iface->radar_background.centr_freq_seg1_idx);
1174 
1175 	hostapd_dfs_update_background_chain(iface);
1176 
1177 	return hostapd_dfs_request_channel_switch(
1178 		iface, iface->conf->channel, iface->freq,
1179 		iface->conf->secondary_channel, current_vht_oper_chwidth,
1180 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
1181 		hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
1182 }
1183 
1184 
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)1185 int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
1186 			     int ht_enabled, int chan_offset, int chan_width,
1187 			     int cf1, int cf2)
1188 {
1189 	if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1190 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1191 			DFS_EVENT_CAC_COMPLETED
1192 			"Ignoring since freq=%d info is out of own range",
1193 			freq);
1194 		return 0;
1195 	}
1196 
1197 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
1198 		"success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
1199 		success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
1200 		iface->radar_detected);
1201 
1202 	if (success) {
1203 		/* Complete iface/ap configuration */
1204 		if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
1205 			/* Complete AP configuration for the first bring up. If
1206 			 * a radar was detected in this channel, interface setup
1207 			 * will be handled in
1208 			 * 1. hostapd_event_ch_switch() if switching to a
1209 			 *    non-DFS channel
1210 			 * 2. on next CAC complete event if switching to another
1211 			 *    DFS channel.
1212 			 */
1213 			if (iface->state != HAPD_IFACE_ENABLED &&
1214 			    !iface->radar_detected)
1215 				hostapd_setup_interface_complete(iface, 0);
1216 			else
1217 				iface->cac_started = 0;
1218 		} else {
1219 			set_dfs_state(iface, freq, ht_enabled, chan_offset,
1220 				      chan_width, cf1, cf2,
1221 				      HOSTAPD_CHAN_DFS_AVAILABLE);
1222 
1223 			/*
1224 			 * Radar event from background chain for the selected
1225 			 * channel. Perform CSA, move the main chain to the
1226 			 * selected channel and configure the background chain
1227 			 * to a new DFS channel.
1228 			 */
1229 			if (hostapd_dfs_is_background_event(iface, freq)) {
1230 				iface->radar_background.cac_started = 0;
1231 				if (!iface->radar_background.temp_ch)
1232 					return 0;
1233 
1234 				iface->radar_background.temp_ch = 0;
1235 				return hostapd_dfs_start_channel_switch_background(iface);
1236 			}
1237 
1238 			/*
1239 			 * Just mark the channel available when CAC completion
1240 			 * event is received in enabled state. CAC result could
1241 			 * have been propagated from another radio having the
1242 			 * same regulatory configuration. When CAC completion is
1243 			 * received during non-HAPD_IFACE_ENABLED state, make
1244 			 * sure the configured channel is available because this
1245 			 * CAC completion event could have been propagated from
1246 			 * another radio.
1247 			 */
1248 			if (iface->state != HAPD_IFACE_ENABLED &&
1249 			    hostapd_is_dfs_chan_available(iface)) {
1250 				hostapd_setup_interface_complete(iface, 0);
1251 				iface->cac_started = 0;
1252 			}
1253 		}
1254 	} else if (hostapd_dfs_is_background_event(iface, freq)) {
1255 		iface->radar_background.cac_started = 0;
1256 		hostapd_dfs_update_background_chain(iface);
1257 	}
1258 
1259 	iface->radar_detected = false;
1260 	return 0;
1261 }
1262 
1263 
hostapd_dfs_pre_cac_expired(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1264 int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
1265 				int ht_enabled, int chan_offset, int chan_width,
1266 				int cf1, int cf2)
1267 {
1268 	if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1269 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1270 			DFS_EVENT_PRE_CAC_EXPIRED
1271 			"Ignoring since freq=%d info is out of own range",
1272 			freq);
1273 		return 0;
1274 	}
1275 
1276 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
1277 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1278 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1279 
1280 	/* Proceed only if DFS is not offloaded to the driver */
1281 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1282 		return 0;
1283 
1284 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1285 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1286 
1287 	return 0;
1288 }
1289 
1290 
1291 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,enum dfs_channel_type * channel_type)1292 dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
1293 			u8 *oper_centr_freq_seg0_idx,
1294 			u8 *oper_centr_freq_seg1_idx,
1295 			enum dfs_channel_type *channel_type)
1296 {
1297 	struct hostapd_channel_data *channel;
1298 
1299 	for (;;) {
1300 		channel = dfs_get_valid_channel(iface, secondary_channel,
1301 						oper_centr_freq_seg0_idx,
1302 						oper_centr_freq_seg1_idx,
1303 						*channel_type);
1304 		if (channel) {
1305 			wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
1306 				   channel->chan);
1307 			return channel;
1308 		}
1309 
1310 		if (*channel_type != DFS_ANY_CHANNEL) {
1311 			*channel_type = DFS_ANY_CHANNEL;
1312 		} else {
1313 			int oper_chwidth;
1314 
1315 			oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1316 			if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
1317 				break;
1318 			*channel_type = DFS_AVAILABLE;
1319 			hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
1320 		}
1321 	}
1322 
1323 	wpa_printf(MSG_INFO,
1324 		   "%s: no DFS channels left, waiting for NOP to finish",
1325 		   __func__);
1326 	return NULL;
1327 }
1328 
1329 
hostapd_dfs_start_channel_switch_cac(struct hostapd_iface * iface)1330 static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
1331 {
1332 	struct hostapd_channel_data *channel;
1333 	int secondary_channel;
1334 	u8 oper_centr_freq_seg0_idx = 0;
1335 	u8 oper_centr_freq_seg1_idx = 0;
1336 	enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
1337 	int err = 1;
1338 	u8 op_class, chan;
1339 
1340 	/* Radar detected during active CAC */
1341 	iface->cac_started = 0;
1342 	channel = dfs_get_valid_channel(iface, &secondary_channel,
1343 					&oper_centr_freq_seg0_idx,
1344 					&oper_centr_freq_seg1_idx,
1345 					channel_type);
1346 
1347 	if (!channel) {
1348 		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1349 						  &oper_centr_freq_seg0_idx,
1350 						  &oper_centr_freq_seg1_idx,
1351 						  &channel_type);
1352 		if (!channel) {
1353 			wpa_printf(MSG_ERROR, "No valid channel available");
1354 			return err;
1355 		}
1356 	}
1357 
1358 	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
1359 		   channel->chan);
1360 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
1361 		"freq=%d chan=%d sec_chan=%d", channel->freq,
1362 		channel->chan, secondary_channel);
1363 
1364 	iface->freq = channel->freq;
1365 	iface->conf->channel = channel->chan;
1366 	iface->conf->secondary_channel = secondary_channel;
1367 	hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1368 					     oper_centr_freq_seg0_idx);
1369 	hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1370 					     oper_centr_freq_seg1_idx);
1371 	if (ieee80211_freq_to_channel_ext(channel->freq, secondary_channel,
1372 					  hostapd_get_oper_chwidth(iface->conf),
1373 					  &op_class, &chan) !=
1374 	    NUM_HOSTAPD_MODES) {
1375 		wpa_printf(MSG_DEBUG, "Update op_class %d->%d",
1376 			   iface->conf->op_class, op_class);
1377 		iface->conf->op_class = op_class;
1378 	}
1379 	err = 0;
1380 
1381 	hostapd_setup_interface_complete(iface, err);
1382 	return err;
1383 }
1384 
1385 
1386 static int
hostapd_dfs_background_start_channel_switch(struct hostapd_iface * iface,int freq)1387 hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
1388 					    int freq)
1389 {
1390 	if (!dfs_use_radar_background(iface))
1391 		return -1; /* Background radar chain not supported. */
1392 
1393 	wpa_printf(MSG_DEBUG,
1394 		   "%s called (background CAC active: %s, CSA active: %s)",
1395 		   __func__, iface->radar_background.cac_started ? "yes" : "no",
1396 		   hostapd_csa_in_progress(iface) ? "yes" : "no");
1397 
1398 	/* Check if CSA in progress */
1399 	if (hostapd_csa_in_progress(iface))
1400 		return 0;
1401 
1402 	if (hostapd_dfs_is_background_event(iface, freq)) {
1403 		/*
1404 		 * Radar pattern is reported on the background chain.
1405 		 * Just select a new random channel according to the
1406 		 * regulations for monitoring.
1407 		 */
1408 		hostapd_dfs_update_background_chain(iface);
1409 		return 0;
1410 	}
1411 
1412 	/*
1413 	 * If background radar detection is supported and the radar channel
1414 	 * monitored by the background chain is available switch to it without
1415 	 * waiting for the CAC.
1416 	 */
1417 	if (iface->radar_background.channel == -1)
1418 		return -1; /* Background radar chain not available. */
1419 
1420 	if (iface->radar_background.cac_started) {
1421 		/*
1422 		 * Background channel not available yet. Perform CAC on the
1423 		 * main chain.
1424 		 */
1425 		iface->radar_background.temp_ch = 1;
1426 		return -1;
1427 	}
1428 
1429 	return hostapd_dfs_start_channel_switch_background(iface);
1430 }
1431 
1432 
hostapd_dfs_start_channel_switch(struct hostapd_iface * iface)1433 static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
1434 {
1435 	struct hostapd_channel_data *channel;
1436 	int secondary_channel;
1437 	u8 oper_centr_freq_seg0_idx;
1438 	u8 oper_centr_freq_seg1_idx;
1439 	enum dfs_channel_type channel_type = DFS_AVAILABLE;
1440 	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
1441 
1442 	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
1443 		   __func__, iface->cac_started ? "yes" : "no",
1444 		   hostapd_csa_in_progress(iface) ? "yes" : "no");
1445 
1446 	/* Check if CSA in progress */
1447 	if (hostapd_csa_in_progress(iface))
1448 		return 0;
1449 
1450 	/* Check if active CAC */
1451 	if (iface->cac_started)
1452 		return hostapd_dfs_start_channel_switch_cac(iface);
1453 
1454 	/*
1455 	 * Allow selection of DFS channel in ETSI to comply with
1456 	 * uniform spreading.
1457 	 */
1458 	if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
1459 		channel_type = DFS_ANY_CHANNEL;
1460 
1461 	/* Perform channel switch/CSA */
1462 	channel = dfs_get_valid_channel(iface, &secondary_channel,
1463 					&oper_centr_freq_seg0_idx,
1464 					&oper_centr_freq_seg1_idx,
1465 					channel_type);
1466 
1467 	if (!channel) {
1468 		/*
1469 		 * If there is no channel to switch immediately to, check if
1470 		 * there is another channel where we can switch even if it
1471 		 * requires to perform a CAC first.
1472 		 */
1473 		channel_type = DFS_ANY_CHANNEL;
1474 		channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
1475 						  &oper_centr_freq_seg0_idx,
1476 						  &oper_centr_freq_seg1_idx,
1477 						  &channel_type);
1478 		if (!channel) {
1479 			/*
1480 			 * Toggle interface state to enter DFS state
1481 			 * until NOP is finished.
1482 			 */
1483 			hostapd_disable_iface(iface);
1484 			hostapd_enable_iface(iface);
1485 			return 0;
1486 		}
1487 
1488 		if (channel_type == DFS_ANY_CHANNEL) {
1489 			iface->freq = channel->freq;
1490 			iface->conf->channel = channel->chan;
1491 			iface->conf->secondary_channel = secondary_channel;
1492 			hostapd_set_oper_centr_freq_seg0_idx(
1493 				iface->conf, oper_centr_freq_seg0_idx);
1494 			hostapd_set_oper_centr_freq_seg1_idx(
1495 				iface->conf, oper_centr_freq_seg1_idx);
1496 
1497 			hostapd_disable_iface(iface);
1498 			hostapd_enable_iface(iface);
1499 			return 0;
1500 		}
1501 	}
1502 
1503 	return hostapd_dfs_request_channel_switch(iface, channel->chan,
1504 						  channel->freq,
1505 						  secondary_channel,
1506 						  current_vht_oper_chwidth,
1507 						  oper_centr_freq_seg0_idx,
1508 						  oper_centr_freq_seg1_idx);
1509 }
1510 
1511 
hostapd_dfs_radar_detected(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1512 int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
1513 			       int ht_enabled, int chan_offset, int chan_width,
1514 			       int cf1, int cf2)
1515 {
1516 	if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1517 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1518 			DFS_EVENT_RADAR_DETECTED
1519 			"Ignoring since freq=%d info is out of own range",
1520 			freq);
1521 		return 0;
1522 	}
1523 
1524 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
1525 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1526 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1527 
1528 	iface->radar_detected = true;
1529 
1530 	/* Proceed only if DFS is not offloaded to the driver */
1531 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1532 		return 0;
1533 
1534 	if (!iface->conf->ieee80211h)
1535 		return 0;
1536 
1537 	/* mark radar frequency as invalid */
1538 	if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1539 			   cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
1540 		return 0;
1541 
1542 	if (!hostapd_dfs_is_background_event(iface, freq)) {
1543 		/* Skip if reported radar event not overlapped our channels */
1544 		if (!dfs_are_channels_overlapped(iface, freq, chan_width,
1545 						 cf1, cf2))
1546 			return 0;
1547 	}
1548 
1549 	if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
1550 		/* Radar detected while operating, switch the channel. */
1551 		return hostapd_dfs_start_channel_switch(iface);
1552 	}
1553 
1554 	return 0;
1555 }
1556 
1557 
hostapd_dfs_nop_finished(struct hostapd_iface * iface,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1558 int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
1559 			     int ht_enabled, int chan_offset, int chan_width,
1560 			     int cf1, int cf2)
1561 {
1562 	if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1563 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
1564 			DFS_EVENT_NOP_FINISHED
1565 			"Ignoring since freq=%d info is out of own range",
1566 			freq);
1567 		return 0;
1568 	}
1569 
1570 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
1571 		"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
1572 		freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
1573 
1574 	/* Proceed only if DFS is not offloaded to the driver */
1575 	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
1576 		return 0;
1577 
1578 	/* TODO add correct implementation here */
1579 	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
1580 		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
1581 
1582 	if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
1583 		/* Handle cases where all channels were initially unavailable */
1584 		hostapd_handle_dfs(iface);
1585 	} else if (dfs_use_radar_background(iface) &&
1586 		   iface->radar_background.channel == -1) {
1587 		/* Reset radar background chain if disabled */
1588 		hostapd_dfs_update_background_chain(iface);
1589 	}
1590 
1591 	return 0;
1592 }
1593 
1594 
hostapd_is_dfs_required(struct hostapd_iface * iface)1595 int hostapd_is_dfs_required(struct hostapd_iface *iface)
1596 {
1597 	int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
1598 
1599 	if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
1600 	     !iface->conf->ieee80211h) ||
1601 	    !iface->current_mode ||
1602 	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
1603 		return 0;
1604 
1605 	/* Get start (first) channel for current configuration */
1606 	start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
1607 	if (start_chan_idx == -1)
1608 		return -1;
1609 
1610 	/* Get number of used channels, depend on width */
1611 	n_chans = dfs_get_used_n_chans(iface, &n_chans1);
1612 
1613 	/* Check if any of configured channels require DFS */
1614 	res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
1615 	if (res)
1616 		return res;
1617 	if (start_chan_idx1 >= 0 && n_chans1 > 0)
1618 		res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
1619 	return res;
1620 }
1621 
1622 
hostapd_dfs_start_cac(struct hostapd_data * hapd,int freq,int ht_enabled,int chan_offset,int chan_width,int cf1,int cf2)1623 int hostapd_dfs_start_cac(struct hostapd_data *hapd, int freq,
1624 			  int ht_enabled, int chan_offset, int chan_width,
1625 			  int cf1, int cf2)
1626 {
1627 	struct hostapd_iface *iface = hapd->iface;
1628 
1629 	if (!hostapd_is_freq_in_current_hw_info(iface, freq)) {
1630 		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1631 			"Ignoring since freq=%d info is out of own range",
1632 			freq);
1633 		return 0;
1634 	}
1635 
1636 	if (hostapd_dfs_is_background_event(iface, freq)) {
1637 		iface->radar_background.cac_started = 1;
1638 	} else {
1639 		/* This is called when the driver indicates that an offloaded
1640 		 * DFS has started CAC. radar_detected might be set for previous
1641 		 * DFS channel. Clear it for this new CAC process. */
1642 		hostapd_set_state(iface, HAPD_IFACE_DFS);
1643 		iface->cac_started = 1;
1644 
1645 		/* Clear radar_detected in case it is for the previous
1646 		 * frequency. Also remove disabled link's information in RNR
1647 		 * element from other links. */
1648 		iface->radar_detected = false;
1649 		if (iface->interfaces && iface->interfaces->count > 1)
1650 			ieee802_11_set_beacons(iface);
1651 	}
1652 	/* TODO: How to check CAC time for ETSI weather channels? */
1653 	iface->dfs_cac_ms = 60000;
1654 	wpa_msg(hapd->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
1655 		"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
1656 		"seg1=%d cac_time=%ds%s",
1657 		freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
1658 		iface->dfs_cac_ms / 1000,
1659 		hostapd_dfs_is_background_event(iface, freq) ?
1660 		" (background)" : "");
1661 
1662 	os_get_reltime(&iface->dfs_cac_start);
1663 	return 0;
1664 }
1665 
1666 
1667 /*
1668  * Main DFS handler for offloaded case.
1669  * 2 - continue channel/AP setup for non-DFS channel
1670  * 1 - continue channel/AP setup for DFS channel
1671  * 0 - channel/AP setup will be continued after CAC
1672  * -1 - hit critical error
1673  */
hostapd_handle_dfs_offload(struct hostapd_iface * iface)1674 int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
1675 {
1676 	int dfs_res;
1677 
1678 	wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1679 		   __func__, iface->cac_started);
1680 
1681 	/*
1682 	 * If DFS has already been started, then we are being called from a
1683 	 * callback to continue AP/channel setup. Reset the CAC start flag and
1684 	 * return.
1685 	 */
1686 	if (iface->cac_started) {
1687 		wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
1688 			   __func__, iface->cac_started);
1689 		iface->cac_started = 0;
1690 		return 1;
1691 	}
1692 
1693 	dfs_res = hostapd_is_dfs_required(iface);
1694 	if (dfs_res > 0) {
1695 		wpa_printf(MSG_DEBUG,
1696 			   "%s: freq %d MHz requires DFS for %d chans",
1697 			   __func__, iface->freq, dfs_res);
1698 		return 0;
1699 	}
1700 
1701 	wpa_printf(MSG_DEBUG,
1702 		   "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
1703 		   __func__, iface->freq);
1704 	return 2;
1705 }
1706 
1707 
hostapd_is_dfs_overlap(struct hostapd_iface * iface,enum chan_width width,int center_freq)1708 int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
1709 			   int center_freq)
1710 {
1711 	struct hostapd_channel_data *chan;
1712 	struct hostapd_hw_modes *mode = iface->current_mode;
1713 	int half_width;
1714 	int res = 0;
1715 	int i;
1716 
1717 	if (!iface->conf->ieee80211h || !mode ||
1718 	    mode->mode != HOSTAPD_MODE_IEEE80211A)
1719 		return 0;
1720 
1721 	switch (width) {
1722 	case CHAN_WIDTH_20_NOHT:
1723 	case CHAN_WIDTH_20:
1724 		half_width = 10;
1725 		break;
1726 	case CHAN_WIDTH_40:
1727 		half_width = 20;
1728 		break;
1729 	case CHAN_WIDTH_80:
1730 	case CHAN_WIDTH_80P80:
1731 		half_width = 40;
1732 		break;
1733 	case CHAN_WIDTH_160:
1734 		half_width = 80;
1735 		break;
1736 	default:
1737 		wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
1738 			   width);
1739 		return 0;
1740 	}
1741 
1742 	for (i = 0; i < mode->num_channels; i++) {
1743 		chan = &mode->channels[i];
1744 
1745 		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
1746 			continue;
1747 
1748 		if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
1749 		    HOSTAPD_CHAN_DFS_AVAILABLE)
1750 			continue;
1751 
1752 		if (center_freq - chan->freq < half_width &&
1753 		    chan->freq - center_freq < half_width)
1754 			res++;
1755 	}
1756 
1757 	wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
1758 		   center_freq - half_width, center_freq + half_width,
1759 		   res ? "yes" : "no");
1760 
1761 	return res;
1762 }
1763