1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 /** 28 * DOC: This file has the functions related to DFS CAC. 29 */ 30 31 #include "../dfs_channel.h" 32 #include "../dfs_zero_cac.h" 33 #include "../dfs_etsi_precac.h" 34 #include "wlan_dfs_utils_api.h" 35 #include "wlan_dfs_mlme_api.h" 36 #include "../dfs_internal.h" 37 #include "../dfs_process_radar_found_ind.h" 38 39 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650)) 40 #define ADJACENT_WEATHER_RADAR_CHANNEL 5580 41 #define CH100_START_FREQ 5490 42 #define CH100 100 43 44 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout) 45 { 46 if (!dfs) 47 return -EIO; 48 49 dfs->dfs_cac_timeout_override = cac_timeout; 50 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d", 51 (cac_timeout == -1) ? "default" : "overridden", 52 cac_timeout); 53 54 return 0; 55 } 56 57 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout) 58 { 59 if (!dfs) 60 return -EIO; 61 62 (*cac_timeout) = dfs->dfs_cac_timeout_override; 63 64 return 0; 65 } 66 67 void dfs_cac_valid_reset(struct wlan_dfs *dfs, 68 uint8_t prevchan_ieee, 69 uint32_t prevchan_flags) 70 { 71 if (dfs->dfs_cac_valid_time) { 72 if ((prevchan_ieee != dfs->dfs_curchan->dfs_ch_ieee) || 73 (prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) { 74 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 75 "Cancelling timer & clearing cac_valid" 76 ); 77 qdf_timer_stop(&dfs->dfs_cac_valid_timer); 78 dfs->dfs_cac_valid = 0; 79 } 80 } 81 } 82 83 /** 84 * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer 85 * cac_valid bit will be reset in this function. 86 */ 87 static os_timer_func(dfs_cac_valid_timeout) 88 { 89 struct wlan_dfs *dfs = NULL; 90 91 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 92 dfs->dfs_cac_valid = 0; 93 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!"); 94 } 95 96 /** 97 * dfs_cac_timeout() - DFS cactimeout function. 98 * 99 * Sets dfs_cac_timer_running to 0 and dfs_cac_valid_timer. 100 */ 101 static os_timer_func(dfs_cac_timeout) 102 { 103 struct wlan_dfs *dfs = NULL; 104 105 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 106 dfs->dfs_cac_timer_running = 0; 107 108 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d", 109 dfs->dfs_curchan->dfs_ch_freq, 110 (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000)); 111 112 /* Once CAC is done, add channel to ETSI precacdone list*/ 113 if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN) 114 dfs_add_to_etsi_precac_done_list(dfs); 115 116 /* 117 * When radar is detected during a CAC we are woken up prematurely to 118 * switch to a new channel. Check the channel to decide how to act. 119 */ 120 if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) { 121 dfs_mlme_mark_dfs(dfs->dfs_pdev_obj, 122 dfs->dfs_curchan->dfs_ch_ieee, 123 dfs->dfs_curchan->dfs_ch_freq, 124 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2, 125 dfs->dfs_curchan->dfs_ch_flags); 126 dfs_debug(dfs, WLAN_DEBUG_DFS, 127 "CAC timer on channel %u (%u MHz) stopped due to radar", 128 dfs->dfs_curchan->dfs_ch_ieee, 129 dfs->dfs_curchan->dfs_ch_freq); 130 } else { 131 dfs_debug(dfs, WLAN_DEBUG_DFS, 132 "CAC timer on channel %u (%u MHz) expired; no radar detected", 133 dfs->dfs_curchan->dfs_ch_ieee, 134 dfs->dfs_curchan->dfs_ch_freq); 135 136 /* On CAC completion, set the bit 'cac_valid'. 137 * CAC will not be re-done if this bit is reset. 138 * The flag will be reset when dfs_cac_valid_timer 139 * timesout. 140 */ 141 if (dfs->dfs_cac_valid_time) { 142 dfs->dfs_cac_valid = 1; 143 qdf_timer_mod(&dfs->dfs_cac_valid_timer, 144 dfs->dfs_cac_valid_time * 1000); 145 } 146 } 147 148 /* Iterate over the nodes, processing the CAC completion event. */ 149 dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0); 150 151 /* Send a CAC timeout, VAP up event to user space */ 152 dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj); 153 154 if (dfs->dfs_defer_precac_channel_change == 1) { 155 dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj); 156 dfs->dfs_defer_precac_channel_change = 0; 157 } 158 } 159 160 void dfs_cac_timer_init(struct wlan_dfs *dfs) 161 { 162 qdf_timer_init(NULL, 163 &(dfs->dfs_cac_timer), 164 dfs_cac_timeout, 165 (void *)(dfs), 166 QDF_TIMER_TYPE_WAKE_APPS); 167 168 qdf_timer_init(NULL, 169 &(dfs->dfs_cac_valid_timer), 170 dfs_cac_valid_timeout, 171 (void *)(dfs), 172 QDF_TIMER_TYPE_WAKE_APPS); 173 } 174 175 void dfs_cac_attach(struct wlan_dfs *dfs) 176 { 177 dfs->dfs_cac_timeout_override = -1; 178 dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS; 179 dfs_cac_timer_init(dfs); 180 } 181 182 void dfs_cac_timer_reset(struct wlan_dfs *dfs) 183 { 184 qdf_timer_stop(&dfs->dfs_cac_timer); 185 dfs_get_override_cac_timeout(dfs, 186 &(dfs->dfs_cac_timeout_override)); 187 qdf_mem_zero(&dfs->dfs_cac_started_chan, 188 sizeof(dfs->dfs_cac_started_chan)); 189 190 } 191 192 void dfs_cac_timer_detach(struct wlan_dfs *dfs) 193 { 194 qdf_timer_free(&dfs->dfs_cac_timer); 195 196 qdf_timer_free(&dfs->dfs_cac_valid_timer); 197 dfs->dfs_cac_valid = 0; 198 } 199 200 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs) 201 { 202 return dfs->dfs_cac_timer_running; 203 } 204 205 void dfs_start_cac_timer(struct wlan_dfs *dfs) 206 { 207 int cac_timeout = 0; 208 struct dfs_channel *chan = dfs->dfs_curchan; 209 210 cac_timeout = dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj, 211 chan->dfs_ch_freq, 212 chan->dfs_ch_vhtop_ch_freq_seg2, 213 chan->dfs_ch_flags); 214 215 dfs->dfs_cac_started_chan = *chan; 216 217 dfs_debug(dfs, WLAN_DEBUG_DFS, 218 "chan = %d cfreq2 = %d timeout = %d sec, curr_time = %d sec", 219 chan->dfs_ch_ieee, chan->dfs_ch_vhtop_ch_freq_seg2, 220 cac_timeout, 221 qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000); 222 223 qdf_timer_mod(&dfs->dfs_cac_timer, cac_timeout * 1000); 224 dfs->dfs_cac_aborted = 0; 225 } 226 227 void dfs_cancel_cac_timer(struct wlan_dfs *dfs) 228 { 229 qdf_timer_stop(&dfs->dfs_cac_timer); 230 } 231 232 void dfs_cac_stop(struct wlan_dfs *dfs) 233 { 234 uint32_t phyerr; 235 236 dfs_get_debug_info(dfs, (void *)&phyerr); 237 dfs_debug(dfs, WLAN_DEBUG_DFS, 238 "Stopping CAC Timer %d procphyerr 0x%08x", 239 dfs->dfs_curchan->dfs_ch_freq, phyerr); 240 qdf_timer_stop(&dfs->dfs_cac_timer); 241 if (dfs->dfs_cac_timer_running) 242 dfs->dfs_cac_aborted = 1; 243 dfs->dfs_cac_timer_running = 0; 244 } 245 246 void dfs_stacac_stop(struct wlan_dfs *dfs) 247 { 248 uint32_t phyerr; 249 250 dfs_get_debug_info(dfs, (void *)&phyerr); 251 dfs_debug(dfs, WLAN_DEBUG_DFS, 252 "Stopping STA CAC Timer %d procphyerr 0x%08x", 253 dfs->dfs_curchan->dfs_ch_freq, phyerr); 254 } 255 256 bool dfs_is_subset_channel(struct wlan_dfs *dfs, 257 struct dfs_channel *old_chan, 258 struct dfs_channel *new_chan) 259 { 260 uint8_t old_subchans[NUM_CHANNELS_160MHZ]; 261 uint8_t new_subchans[NUM_CHANNELS_160MHZ]; 262 uint8_t old_n_chans; 263 uint8_t new_n_chans; 264 int i = 0, j = 0; 265 bool is_found = false; 266 267 if (WLAN_IS_CHAN_11AC_VHT160(old_chan) || 268 WLAN_IS_CHAN_11AC_VHT80_80(old_chan)) { 269 /* If primary segment is NON-DFS */ 270 if (!WLAN_IS_CHAN_DFS(old_chan)) 271 old_n_chans = dfs_get_bonding_channels(dfs, 272 old_chan, 273 SEG_ID_SECONDARY, 274 old_subchans); 275 else 276 old_n_chans = dfs_get_bonding_channels_without_seg_info( 277 old_chan, old_subchans); 278 } else { 279 old_n_chans = dfs_get_bonding_channels_without_seg_info( 280 old_chan, old_subchans); 281 } 282 283 if (WLAN_IS_CHAN_11AC_VHT160(new_chan) || 284 WLAN_IS_CHAN_11AC_VHT80_80(new_chan)) { 285 /* If primary segment is NON-DFS */ 286 if (WLAN_IS_CHAN_DFS(new_chan)) 287 new_n_chans = dfs_get_bonding_channels( 288 dfs, new_chan, SEG_ID_SECONDARY, 289 new_subchans); 290 else 291 new_n_chans = dfs_get_bonding_channels_without_seg_info( 292 new_chan, new_subchans); 293 } else { 294 new_n_chans = dfs_get_bonding_channels_without_seg_info( 295 new_chan, new_subchans); 296 } 297 298 if (new_n_chans > old_n_chans) 299 return false; 300 301 for (i = 0; i < new_n_chans; i++) { 302 is_found = false; 303 for (j = 0; j < old_n_chans; j++) { 304 if (new_subchans[i] == old_subchans[j]) { 305 is_found = true; 306 break; 307 } 308 } 309 310 /* If new_subchans[i] is not found in old_subchans, then, 311 * new_chan is not subset of old_chan. 312 */ 313 if (!is_found) 314 break; 315 } 316 317 return is_found; 318 } 319 320 bool dfs_is_curchan_subset_of_cac_started_chan(struct wlan_dfs *dfs) 321 { 322 return dfs_is_subset_channel(dfs, &dfs->dfs_cac_started_chan, 323 dfs->dfs_curchan); 324 } 325 326 void dfs_clear_cac_started_chan(struct wlan_dfs *dfs) 327 { 328 qdf_mem_zero(&dfs->dfs_cac_started_chan, 329 sizeof(dfs->dfs_cac_started_chan)); 330 } 331 332 bool dfs_check_for_cac_start(struct wlan_dfs *dfs, 333 bool *continue_current_cac) 334 { 335 if (!WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(dfs->dfs_curchan)) { 336 /* Consider a case where AP was up in a DFS channel and in CAC 337 * period (DFS-WAIT state) and the workque to initiate CAC is 338 * scheduled. At this time, real radar/spoof radar pulses from 339 * bottom-half/tasklet context are received which is given 340 * higher priority than Workque context. Due to radar, channel 341 * change happened, AP switched to non-DFS channel and curchan 342 * is non-DFS. The scheduled workque gets executed now, starts 343 * a CAC on non-DFS curchan(curchan has changed from DFS to 344 * non-DFS work queue func not aware of this !!). Though the 345 * vap state machine moves the state of the vap from DFS-WAIT 346 * to RUN state as curchan is non-DFS, the cac timer is not 347 * cancelled. CAC timer on non-DFS channel runs and it expires. 348 * So cancelling CAC here if chan is not DFS to avoid this 349 * unexpected run and expiry of CAC. 350 */ 351 dfs_cac_stop(dfs); 352 dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0); 353 354 /* Clear the old dfs cac started channel if the current channel 355 * is NON-DFS. 356 * For example: AP sets the cac started channel as 100. It does 357 * cac on channel 100 and starts beaconing. User changes the AP 358 * channel to 36 and after sometime if user changes the channel 359 * back to 100, AP does not do the CAC since user channel and 360 * cac started channel is same. 361 */ 362 dfs_clear_cac_started_chan(dfs); 363 dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC on NON-DFS chan"); 364 return false; 365 } 366 367 if (dfs->dfs_ignore_dfs || dfs->dfs_cac_valid || dfs->dfs_ignore_cac) { 368 dfs_debug(dfs, WLAN_DEBUG_DFS, 369 "Skip CAC, ignore_dfs = %d cac_valid = %d ignore_cac = %d", 370 dfs->dfs_ignore_dfs, dfs->dfs_cac_valid, 371 dfs->dfs_ignore_cac); 372 return false; 373 } 374 375 if (dfs_is_etsi_precac_done(dfs)) { 376 dfs_debug(dfs, WLAN_DEBUG_DFS, 377 "ETSI PRE-CAC alreay done on this channel %d", 378 dfs->dfs_curchan->dfs_ch_ieee); 379 return false; 380 } 381 382 /* If the channel has completed PRE-CAC then CAC can be skipped here. */ 383 if (dfs_is_precac_done(dfs, dfs->dfs_curchan)) { 384 dfs_debug(dfs, WLAN_DEBUG_DFS, 385 "PRE-CAC alreay done on this channel %d", 386 dfs->dfs_curchan->dfs_ch_ieee); 387 return false; 388 } 389 390 if (dfs_is_ap_cac_timer_running(dfs)) { 391 /* Check if we should continue the existing CAC or 392 * cancel the existing CAC. 393 * For example: - if an existing VAP(0) is already in 394 * DFS wait state (which means the radio(wifi) is 395 * running the CAC) and it is in channel A and another 396 * VAP(1) comes up in the same channel then instead of 397 * cancelling the CAC we can let the CAC continue. 398 */ 399 if (dfs_is_curchan_subset_of_cac_started_chan(dfs)) { 400 *continue_current_cac = true; 401 } else { 402 /* New CAC is needed, cancel the running CAC 403 * timer. 404 * 1) When AP is in DFS_WAIT state and it is in 405 * channel A and user restarts the AP vap in 406 * channel B, then cancel the running CAC in 407 * channel A and start new CAC in channel B. 408 * 409 * 2) When AP detects the RADAR during CAC in 410 * channel A, it cancels the running CAC and 411 * tries to find channel B with the reduced 412 * bandwidth with of channel A. 413 * In this case, since the CAC is aborted by 414 * the RADAR, AP should start the CAC again. 415 */ 416 dfs_cancel_cac_timer(dfs); 417 } 418 } else { /* CAC timer is not running. */ 419 if (dfs_is_curchan_subset_of_cac_started_chan(dfs)) { 420 /* AP bandwidth reduce case: 421 * When AP detects the RADAR in in-service monitoring 422 * mode in channel A, it cancels the running CAC and 423 * tries to find the channel B with the reduced 424 * bandwidth of channel A. 425 * If the new channel B is subset of the channel A 426 * then AP skips the CAC. 427 */ 428 if (!dfs->dfs_cac_aborted) { 429 dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC"); 430 return false; 431 } 432 } 433 } 434 435 return true; 436 } 437