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