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