1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2002-2006, Atheros Communications Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: This file contains the dfs_attach() and dfs_detach() functions as well 20 * as the dfs_control() function which is used to process ioctls related to DFS. 21 * For Linux/Mac, "radartool" is the command line tool that can be used to call 22 * various ioctls to set and get radar detection thresholds. 23 */ 24 25 #include "../dfs_zero_cac.h" 26 #include "wlan_dfs_lmac_api.h" 27 #include "wlan_dfs_mlme_api.h" 28 #include "wlan_dfs_tgt_api.h" 29 #include "../dfs_internal.h" 30 #include "../dfs_filter_init.h" 31 #include "../dfs_full_offload.h" 32 #include "wlan_dfs_utils_api.h" 33 34 /** 35 * dfs_testtimer_task() - Sends CSA in the current channel. 36 * 37 * When the user sets usenol to 0 and inject the RADAR, AP does not mark the 38 * channel as RADAR and does not add the channel to NOL. It sends the CSA in 39 * the current channel. 40 */ 41 static os_timer_func(dfs_testtimer_task) 42 { 43 struct wlan_dfs *dfs = NULL; 44 45 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 46 dfs->wlan_dfstest = 0; 47 48 /* 49 * Flip the channel back to the original channel. 50 * Make sure this is done properly with a CSA. 51 */ 52 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "go back to channel %d", 53 dfs->wlan_dfstest_ieeechan); 54 dfs_mlme_start_csa(dfs->dfs_pdev_obj, 55 dfs->wlan_dfstest_ieeechan, 56 dfs->dfs_curchan->dfs_ch_freq, 57 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2, 58 dfs->dfs_curchan->dfs_ch_flags); 59 } 60 61 int dfs_get_debug_info(struct wlan_dfs *dfs, void *data) 62 { 63 if (data) 64 *(uint32_t *)data = dfs->dfs_proc_phyerr; 65 66 return (int)dfs->dfs_proc_phyerr; 67 } 68 69 void dfs_main_task_testtimer_init(struct wlan_dfs *dfs) 70 { 71 qdf_timer_init(NULL, 72 &(dfs->wlan_dfstesttimer), 73 dfs_testtimer_task, (void *)dfs, 74 QDF_TIMER_TYPE_WAKE_APPS); 75 } 76 77 int dfs_create_object(struct wlan_dfs **dfs) 78 { 79 *dfs = (struct wlan_dfs *)qdf_mem_malloc(sizeof(**dfs)); 80 if (!(*dfs)) { 81 dfs_alert(*dfs, WLAN_DEBUG_DFS_ALWAYS, "wlan_dfs allocation failed"); 82 return 1; 83 } 84 85 qdf_mem_zero(*dfs, sizeof(**dfs)); 86 87 (*dfs)->dfs_curchan = (struct dfs_channel *)qdf_mem_malloc( 88 sizeof(struct dfs_channel)); 89 90 if (!((*dfs)->dfs_curchan)) { 91 dfs_alert(*dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_curchan allocation failed"); 92 return 1; 93 } 94 95 return 0; 96 } 97 98 int dfs_attach(struct wlan_dfs *dfs) 99 { 100 int ret; 101 102 if (!dfs->dfs_is_offload_enabled) { 103 ret = dfs_main_attach(dfs); 104 105 /* 106 * For full offload we have a wmi handler registered to process 107 * a radar event from firmware in the event of a radar detect. 108 * So, init of timer, dfs_task is not required for 109 * full-offload. dfs_task timer is called in 110 * dfs_main_timer_init within dfs_main_attach for 111 * partial-offload in the event of radar detect. 112 */ 113 if (ret) { 114 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_main_attach failed"); 115 return ret; 116 } 117 } 118 dfs_cac_attach(dfs); 119 dfs_zero_cac_attach(dfs); 120 dfs_nol_attach(dfs); 121 122 /* 123 * Init of timer ,dfs_testtimer_task is required by both partial 124 * and full offload, indicating test mode timer initialization for both. 125 */ 126 dfs_main_task_testtimer_init(dfs); 127 return 0; 128 } 129 130 void dfs_stop(struct wlan_dfs *dfs) 131 { 132 dfs_nol_timer_cleanup(dfs); 133 dfs_nol_workqueue_cleanup(dfs); 134 dfs_clear_nolhistory(dfs); 135 } 136 137 void dfs_reset(struct wlan_dfs *dfs) 138 { 139 if (!dfs) { 140 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 141 return; 142 } 143 144 dfs_cac_timer_reset(dfs); 145 dfs_zero_cac_reset(dfs); 146 if (!dfs->dfs_is_offload_enabled) { 147 dfs_main_timer_reset(dfs); 148 dfs->dfs_event_log_count = 0; 149 } 150 } 151 152 void dfs_detach(struct wlan_dfs *dfs) 153 { 154 if (!dfs->dfs_is_offload_enabled) 155 dfs_main_detach(dfs); 156 dfs_zero_cac_detach(dfs); 157 dfs_nol_detach(dfs); 158 } 159 160 void dfs_destroy_object(struct wlan_dfs *dfs) 161 { 162 qdf_mem_free(dfs->dfs_curchan); 163 qdf_mem_free(dfs); 164 } 165 166 int dfs_control(struct wlan_dfs *dfs, 167 u_int id, 168 void *indata, 169 uint32_t insize, 170 void *outdata, 171 uint32_t *outsize) 172 { 173 struct wlan_dfs_phyerr_param peout; 174 struct dfs_ioctl_params *dfsparams; 175 int error = 0; 176 uint32_t val = 0; 177 struct dfsreq_nolinfo *nol; 178 uint32_t *data = NULL; 179 int i; 180 struct dfs_emulate_bang_radar_test_cmd dfs_unit_test; 181 182 qdf_mem_zero(&dfs_unit_test, sizeof(dfs_unit_test)); 183 184 if (!dfs) { 185 dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 186 goto bad; 187 } 188 189 switch (id) { 190 case DFS_SET_THRESH: 191 if (insize < sizeof(struct dfs_ioctl_params) || !indata) { 192 dfs_debug(dfs, WLAN_DEBUG_DFS1, 193 "insize = %d, expected = %zu bytes, indata = %pK", 194 insize, 195 sizeof(struct dfs_ioctl_params), 196 indata); 197 error = -EINVAL; 198 break; 199 } 200 dfsparams = (struct dfs_ioctl_params *)indata; 201 if (!dfs_set_thresholds(dfs, DFS_PARAM_FIRPWR, 202 dfsparams->dfs_firpwr)) 203 error = -EINVAL; 204 if (!dfs_set_thresholds(dfs, DFS_PARAM_RRSSI, 205 dfsparams->dfs_rrssi)) 206 error = -EINVAL; 207 if (!dfs_set_thresholds(dfs, DFS_PARAM_HEIGHT, 208 dfsparams->dfs_height)) 209 error = -EINVAL; 210 if (!dfs_set_thresholds(dfs, DFS_PARAM_PRSSI, 211 dfsparams->dfs_prssi)) 212 error = -EINVAL; 213 if (!dfs_set_thresholds(dfs, DFS_PARAM_INBAND, 214 dfsparams->dfs_inband)) 215 error = -EINVAL; 216 217 /* 5413 speicfic. */ 218 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELPWR, 219 dfsparams->dfs_relpwr)) 220 error = -EINVAL; 221 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELSTEP, 222 dfsparams->dfs_relstep)) 223 error = -EINVAL; 224 if (!dfs_set_thresholds(dfs, DFS_PARAM_MAXLEN, 225 dfsparams->dfs_maxlen)) 226 error = -EINVAL; 227 break; 228 case DFS_GET_THRESH: 229 if (!outdata || !outsize || 230 *outsize < sizeof(struct dfs_ioctl_params)) { 231 error = -EINVAL; 232 break; 233 } 234 *outsize = sizeof(struct dfs_ioctl_params); 235 dfsparams = (struct dfs_ioctl_params *) outdata; 236 237 /* Fetch the DFS thresholds using the internal representation */ 238 (void) dfs_get_thresholds(dfs, &peout); 239 240 /* Convert them to the dfs IOCTL representation. */ 241 wlan_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); 242 break; 243 case DFS_RADARDETECTS: 244 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 245 error = -EINVAL; 246 break; 247 } 248 *outsize = sizeof(uint32_t); 249 *((uint32_t *)outdata) = dfs->wlan_dfs_stats.num_radar_detects; 250 break; 251 case DFS_DISABLE_DETECT: 252 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; 253 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 254 dfs->dfs_ignore_dfs = 1; 255 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 256 "enable detects, ignore_dfs %d", 257 dfs->dfs_ignore_dfs ? 1:0); 258 break; 259 case DFS_ENABLE_DETECT: 260 dfs->dfs_proc_phyerr |= DFS_RADAR_EN; 261 dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN; 262 dfs->dfs_ignore_dfs = 0; 263 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS 264 , "enable detects, ignore_dfs %d", 265 dfs->dfs_ignore_dfs ? 1:0); 266 break; 267 case DFS_DISABLE_FFT: 268 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 269 "TODO disable FFT val=0x%x", val); 270 break; 271 case DFS_ENABLE_FFT: 272 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 273 "TODO enable FFT val=0x%x", val); 274 break; 275 case DFS_SET_DEBUG_LEVEL: 276 if (insize < sizeof(uint32_t) || !indata) { 277 error = -EINVAL; 278 break; 279 } 280 dfs->dfs_debug_mask = *(uint32_t *)indata; 281 282 /* Do not allow user to set the ALWAYS/MAX bit. 283 * It will be used internally by dfs print macro(s) 284 * to print messages when dfs is NULL. 285 */ 286 dfs->dfs_debug_mask &= ~(WLAN_DEBUG_DFS_ALWAYS); 287 288 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 289 "debug level now = 0x%x", dfs->dfs_debug_mask); 290 if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS3) { 291 /* Enable debug Radar Event */ 292 dfs->dfs_event_log_on = 1; 293 } else if ((utils_get_dfsdomain(dfs->dfs_pdev_obj) == 294 DFS_FCC_DOMAIN) && 295 lmac_is_host_dfs_check_support_enabled(dfs->dfs_pdev_obj)) { 296 dfs->dfs_event_log_on = 1; 297 } else { 298 dfs->dfs_event_log_on = 0; 299 } 300 break; 301 case DFS_SET_FALSE_RSSI_THRES: 302 if (insize < sizeof(uint32_t) || !indata) { 303 error = -EINVAL; 304 break; 305 } 306 dfs->wlan_dfs_false_rssi_thres = *(uint32_t *)indata; 307 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 308 "false RSSI threshold now = 0x%x", 309 dfs->wlan_dfs_false_rssi_thres); 310 break; 311 case DFS_SET_PEAK_MAG: 312 if (insize < sizeof(uint32_t) || !indata) { 313 error = -EINVAL; 314 break; 315 } 316 dfs->wlan_dfs_peak_mag = *(uint32_t *)indata; 317 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 318 "peak_mag now = 0x%x", 319 dfs->wlan_dfs_peak_mag); 320 break; 321 case DFS_GET_CAC_VALID_TIME: 322 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 323 error = -EINVAL; 324 break; 325 } 326 *outsize = sizeof(uint32_t); 327 *((uint32_t *)outdata) = dfs->dfs_cac_valid_time; 328 break; 329 case DFS_SET_CAC_VALID_TIME: 330 if (insize < sizeof(uint32_t) || !indata) { 331 error = -EINVAL; 332 break; 333 } 334 dfs->dfs_cac_valid_time = *(uint32_t *)indata; 335 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 336 "dfs timeout = %d", dfs->dfs_cac_valid_time); 337 break; 338 case DFS_IGNORE_CAC: 339 if (insize < sizeof(uint32_t) || !indata) { 340 error = -EINVAL; 341 break; 342 } 343 344 if (*(uint32_t *)indata) 345 dfs->dfs_ignore_cac = 1; 346 else 347 dfs->dfs_ignore_cac = 0; 348 349 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 350 "ignore cac = 0x%x", dfs->dfs_ignore_cac); 351 break; 352 case DFS_SET_NOL_TIMEOUT: 353 if (insize < sizeof(uint32_t) || !indata) { 354 error = -EINVAL; 355 break; 356 } 357 if (*(int *)indata) 358 dfs->wlan_dfs_nol_timeout = *(int *)indata; 359 else 360 dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; 361 362 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "nol timeout = %d sec", 363 dfs->wlan_dfs_nol_timeout); 364 break; 365 case DFS_MUTE_TIME: 366 if (insize < sizeof(uint32_t) || !indata) { 367 error = -EINVAL; 368 break; 369 } 370 data = (uint32_t *) indata; 371 dfs->wlan_dfstesttime = *data; 372 dfs->wlan_dfstesttime *= (1000); /* convert sec into ms */ 373 break; 374 case DFS_GET_USENOL: 375 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 376 error = -EINVAL; 377 break; 378 } 379 *outsize = sizeof(uint32_t); 380 *((uint32_t *)outdata) = dfs->dfs_use_nol; 381 382 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 383 "#Phyerr=%d, #false detect=%d, #queued=%d", 384 dfs->dfs_phyerr_count, 385 dfs->dfs_phyerr_reject_count, 386 dfs->dfs_phyerr_queued_count); 387 388 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 389 "dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d", 390 dfs->dfs_phyerr_freq_min, 391 dfs->dfs_phyerr_freq_max); 392 393 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 394 "Total radar events detected=%d, entries in the radar queue follows:", 395 dfs->dfs_event_log_count); 396 397 for (i = 0; (i < DFS_EVENT_LOG_SIZE) && 398 (i < dfs->dfs_event_log_count); i++) { 399 #define FREQ_OFFSET1 ((int)dfs->radar_log[i].freq_offset_khz / 1000) 400 #define FREQ_OFFSET2 ((int)abs(dfs->radar_log[i].freq_offset_khz) % 1000) 401 dfs_debug(dfs, WLAN_DEBUG_DFS, 402 "ts=%llu diff_ts=%u rssi=%u dur=%u, is_chirp=%d, seg_id=%d, sidx=%d, freq_offset=%d.%dMHz, peak_mag=%d, total_gain=%d, mb_gain=%d, relpwr_db=%d, delta_diff=%d, delta_peak=%d, psidx_diff=%d\n", 403 dfs->radar_log[i].ts, 404 dfs->radar_log[i].diff_ts, 405 dfs->radar_log[i].rssi, 406 dfs->radar_log[i].dur, 407 dfs->radar_log[i].is_chirp, 408 dfs->radar_log[i].seg_id, 409 dfs->radar_log[i].sidx, 410 FREQ_OFFSET1, 411 FREQ_OFFSET2, 412 dfs->radar_log[i].peak_mag, 413 dfs->radar_log[i].total_gain, 414 dfs->radar_log[i].mb_gain, 415 dfs->radar_log[i].relpwr_db, 416 dfs->radar_log[i].delta_diff, 417 dfs->radar_log[i].delta_peak, 418 dfs->radar_log[i].psidx_diff); 419 } 420 dfs->dfs_event_log_count = 0; 421 dfs->dfs_phyerr_count = 0; 422 dfs->dfs_phyerr_reject_count = 0; 423 dfs->dfs_phyerr_queued_count = 0; 424 dfs->dfs_phyerr_freq_min = 0x7fffffff; 425 dfs->dfs_phyerr_freq_max = 0; 426 break; 427 case DFS_SET_USENOL: 428 if (insize < sizeof(uint32_t) || !indata) { 429 error = -EINVAL; 430 break; 431 } 432 dfs->dfs_use_nol = *(uint32_t *)indata; 433 break; 434 case DFS_GET_NOL: 435 if (!outdata || !outsize || 436 *outsize < sizeof(struct dfsreq_nolinfo)) { 437 error = -EINVAL; 438 break; 439 } 440 *outsize = sizeof(struct dfsreq_nolinfo); 441 nol = (struct dfsreq_nolinfo *)outdata; 442 DFS_GET_NOL_LOCKED(dfs, 443 (struct dfsreq_nolelem *)nol->dfs_nol, 444 &nol->dfs_ch_nchans); 445 DFS_PRINT_NOL_LOCKED(dfs); 446 break; 447 case DFS_SET_NOL: 448 if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { 449 error = -EINVAL; 450 break; 451 } 452 nol = (struct dfsreq_nolinfo *) indata; 453 dfs_set_nol(dfs, 454 (struct dfsreq_nolelem *)nol->dfs_nol, 455 nol->dfs_ch_nchans); 456 break; 457 case DFS_SHOW_NOL: 458 DFS_PRINT_NOL_LOCKED(dfs); 459 break; 460 case DFS_SHOW_NOLHISTORY: 461 dfs_print_nolhistory(dfs); 462 break; 463 case DFS_BANGRADAR: 464 if (dfs->dfs_is_offload_enabled) { 465 error = dfs_fill_emulate_bang_radar_test(dfs, 466 SEG_ID_PRIMARY, 467 &dfs_unit_test); 468 } else { 469 dfs->dfs_bangradar = 1; 470 error = dfs_start_host_based_bangradar(dfs); 471 } 472 break; 473 case DFS_SHOW_PRECAC_LISTS: 474 dfs_print_precaclists(dfs); 475 break; 476 case DFS_RESET_PRECAC_LISTS: 477 dfs_reset_precac_lists(dfs); 478 break; 479 case DFS_SECOND_SEGMENT_BANGRADAR: 480 if (dfs->dfs_is_offload_enabled) { 481 error = dfs_fill_emulate_bang_radar_test(dfs, 482 SEG_ID_SECONDARY, 483 &dfs_unit_test); 484 } else { 485 dfs->dfs_second_segment_bangradar = 1; 486 error = dfs_start_host_based_bangradar(dfs); 487 } 488 break; 489 default: 490 error = -EINVAL; 491 } 492 493 bad: 494 return error; 495 } 496 497 void dfs_set_current_channel(struct wlan_dfs *dfs, 498 uint16_t dfs_ch_freq, 499 uint64_t dfs_ch_flags, 500 uint16_t dfs_ch_flagext, 501 uint8_t dfs_ch_ieee, 502 uint8_t dfs_ch_vhtop_ch_freq_seg1, 503 uint8_t dfs_ch_vhtop_ch_freq_seg2) 504 { 505 if (!dfs) { 506 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 507 return; 508 } 509 510 dfs->dfs_curchan->dfs_ch_freq = dfs_ch_freq; 511 dfs->dfs_curchan->dfs_ch_flags = dfs_ch_flags; 512 dfs->dfs_curchan->dfs_ch_flagext = dfs_ch_flagext; 513 dfs->dfs_curchan->dfs_ch_ieee = dfs_ch_ieee; 514 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_ch_vhtop_ch_freq_seg1; 515 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_ch_vhtop_ch_freq_seg2; 516 } 517 518 void dfs_update_cur_chan_flags(struct wlan_dfs *dfs, 519 uint64_t flags, 520 uint16_t flagext) 521 { 522 dfs->dfs_curchan->dfs_ch_flags = flags; 523 dfs->dfs_curchan->dfs_ch_flagext = flagext; 524 } 525