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