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