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