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