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 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 initilization 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 } 149 150 void dfs_detach(struct wlan_dfs *dfs) 151 { 152 if (!dfs->dfs_is_offload_enabled) 153 dfs_main_detach(dfs); 154 dfs_zero_cac_detach(dfs); 155 dfs_nol_detach(dfs); 156 } 157 158 void dfs_destroy_object(struct wlan_dfs *dfs) 159 { 160 qdf_mem_free(dfs->dfs_curchan); 161 qdf_mem_free(dfs); 162 } 163 164 int dfs_control(struct wlan_dfs *dfs, 165 u_int id, 166 void *indata, 167 uint32_t insize, 168 void *outdata, 169 uint32_t *outsize) 170 { 171 struct wlan_dfs_phyerr_param peout; 172 struct dfs_ioctl_params *dfsparams; 173 int error = 0; 174 uint32_t val = 0; 175 struct dfsreq_nolinfo *nol; 176 uint32_t *data = NULL; 177 int i; 178 struct dfs_emulate_bang_radar_test_cmd dfs_unit_test; 179 180 qdf_mem_zero(&dfs_unit_test, sizeof(dfs_unit_test)); 181 182 if (!dfs) { 183 dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 184 goto bad; 185 } 186 187 switch (id) { 188 case DFS_SET_THRESH: 189 if (insize < sizeof(struct dfs_ioctl_params) || !indata) { 190 dfs_debug(dfs, WLAN_DEBUG_DFS1, 191 "insize = %d, expected = %zu bytes, indata = %pK", 192 insize, 193 sizeof(struct dfs_ioctl_params), 194 indata); 195 error = -EINVAL; 196 break; 197 } 198 dfsparams = (struct dfs_ioctl_params *)indata; 199 if (!dfs_set_thresholds(dfs, DFS_PARAM_FIRPWR, 200 dfsparams->dfs_firpwr)) 201 error = -EINVAL; 202 if (!dfs_set_thresholds(dfs, DFS_PARAM_RRSSI, 203 dfsparams->dfs_rrssi)) 204 error = -EINVAL; 205 if (!dfs_set_thresholds(dfs, DFS_PARAM_HEIGHT, 206 dfsparams->dfs_height)) 207 error = -EINVAL; 208 if (!dfs_set_thresholds(dfs, DFS_PARAM_PRSSI, 209 dfsparams->dfs_prssi)) 210 error = -EINVAL; 211 if (!dfs_set_thresholds(dfs, DFS_PARAM_INBAND, 212 dfsparams->dfs_inband)) 213 error = -EINVAL; 214 215 /* 5413 speicfic. */ 216 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELPWR, 217 dfsparams->dfs_relpwr)) 218 error = -EINVAL; 219 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELSTEP, 220 dfsparams->dfs_relstep)) 221 error = -EINVAL; 222 if (!dfs_set_thresholds(dfs, DFS_PARAM_MAXLEN, 223 dfsparams->dfs_maxlen)) 224 error = -EINVAL; 225 break; 226 case DFS_GET_THRESH: 227 if (!outdata || !outsize || 228 *outsize < sizeof(struct dfs_ioctl_params)) { 229 error = -EINVAL; 230 break; 231 } 232 *outsize = sizeof(struct dfs_ioctl_params); 233 dfsparams = (struct dfs_ioctl_params *) outdata; 234 235 /* Fetch the DFS thresholds using the internal representation */ 236 (void) dfs_get_thresholds(dfs, &peout); 237 238 /* Convert them to the dfs IOCTL representation. */ 239 wlan_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); 240 break; 241 case DFS_RADARDETECTS: 242 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 243 error = -EINVAL; 244 break; 245 } 246 *outsize = sizeof(uint32_t); 247 *((uint32_t *)outdata) = dfs->wlan_dfs_stats.num_radar_detects; 248 break; 249 case DFS_DISABLE_DETECT: 250 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; 251 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 252 dfs->dfs_ignore_dfs = 1; 253 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 254 "enable detects, ignore_dfs %d", 255 dfs->dfs_ignore_dfs ? 1:0); 256 break; 257 case DFS_ENABLE_DETECT: 258 dfs->dfs_proc_phyerr |= DFS_RADAR_EN; 259 dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN; 260 dfs->dfs_ignore_dfs = 0; 261 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS 262 , "enable detects, ignore_dfs %d", 263 dfs->dfs_ignore_dfs ? 1:0); 264 break; 265 case DFS_DISABLE_FFT: 266 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 267 "TODO disable FFT val=0x%x", val); 268 break; 269 case DFS_ENABLE_FFT: 270 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 271 "TODO enable FFT val=0x%x", val); 272 break; 273 case DFS_SET_DEBUG_LEVEL: 274 if (insize < sizeof(uint32_t) || !indata) { 275 error = -EINVAL; 276 break; 277 } 278 dfs->dfs_debug_mask = *(uint32_t *)indata; 279 280 /* Do not allow user to set the ALWAYS/MAX bit. 281 * It will be used internally by dfs print macro(s) 282 * to print messages when dfs is NULL. 283 */ 284 dfs->dfs_debug_mask &= ~(WLAN_DEBUG_DFS_ALWAYS); 285 286 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 287 "debug level now = 0x%x", dfs->dfs_debug_mask); 288 if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS3) { 289 /* Enable debug Radar Event */ 290 dfs->dfs_event_log_on = 1; 291 } else { 292 dfs->dfs_event_log_on = 0; 293 } 294 break; 295 case DFS_SET_FALSE_RSSI_THRES: 296 if (insize < sizeof(uint32_t) || !indata) { 297 error = -EINVAL; 298 break; 299 } 300 dfs->wlan_dfs_false_rssi_thres = *(uint32_t *)indata; 301 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 302 "false RSSI threshold now = 0x%x", 303 dfs->wlan_dfs_false_rssi_thres); 304 break; 305 case DFS_SET_PEAK_MAG: 306 if (insize < sizeof(uint32_t) || !indata) { 307 error = -EINVAL; 308 break; 309 } 310 dfs->wlan_dfs_peak_mag = *(uint32_t *)indata; 311 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 312 "peak_mag now = 0x%x", 313 dfs->wlan_dfs_peak_mag); 314 break; 315 case DFS_GET_CAC_VALID_TIME: 316 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 317 error = -EINVAL; 318 break; 319 } 320 *outsize = sizeof(uint32_t); 321 *((uint32_t *)outdata) = dfs->dfs_cac_valid_time; 322 break; 323 case DFS_SET_CAC_VALID_TIME: 324 if (insize < sizeof(uint32_t) || !indata) { 325 error = -EINVAL; 326 break; 327 } 328 dfs->dfs_cac_valid_time = *(uint32_t *)indata; 329 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 330 "dfs timeout = %d", dfs->dfs_cac_valid_time); 331 break; 332 case DFS_IGNORE_CAC: 333 if (insize < sizeof(uint32_t) || !indata) { 334 error = -EINVAL; 335 break; 336 } 337 338 if (*(uint32_t *)indata) 339 dfs->dfs_ignore_cac = 1; 340 else 341 dfs->dfs_ignore_cac = 0; 342 343 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 344 "ignore cac = 0x%x", dfs->dfs_ignore_cac); 345 break; 346 case DFS_SET_NOL_TIMEOUT: 347 if (insize < sizeof(uint32_t) || !indata) { 348 error = -EINVAL; 349 break; 350 } 351 if (*(int *)indata) 352 dfs->wlan_dfs_nol_timeout = *(int *)indata; 353 else 354 dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; 355 356 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "nol timeout = %d sec", 357 dfs->wlan_dfs_nol_timeout); 358 break; 359 case DFS_MUTE_TIME: 360 if (insize < sizeof(uint32_t) || !indata) { 361 error = -EINVAL; 362 break; 363 } 364 data = (uint32_t *) indata; 365 dfs->wlan_dfstesttime = *data; 366 dfs->wlan_dfstesttime *= (1000); /* convert sec into ms */ 367 break; 368 case DFS_GET_USENOL: 369 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 370 error = -EINVAL; 371 break; 372 } 373 *outsize = sizeof(uint32_t); 374 *((uint32_t *)outdata) = dfs->dfs_use_nol; 375 376 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 377 "#Phyerr=%d, #false detect=%d, #queued=%d", 378 dfs->dfs_phyerr_count, 379 dfs->dfs_phyerr_reject_count, 380 dfs->dfs_phyerr_queued_count); 381 382 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 383 "dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d", 384 dfs->dfs_phyerr_freq_min, 385 dfs->dfs_phyerr_freq_max); 386 387 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 388 "Total radar events detected=%d, entries in the radar queue follows:", 389 dfs->dfs_event_log_count); 390 391 for (i = 0; (i < DFS_EVENT_LOG_SIZE) && 392 (i < dfs->dfs_event_log_count); i++) { 393 #define FREQ_OFFSET1 ((int)dfs->radar_log[i].freq_offset_khz / 1000) 394 #define FREQ_OFFSET2 ((int)abs(dfs->radar_log[i].freq_offset_khz) % 1000) 395 dfs_debug(dfs, WLAN_DEBUG_DFS, 396 "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\n", 397 dfs->radar_log[i].ts, 398 dfs->radar_log[i].diff_ts, 399 dfs->radar_log[i].rssi, 400 dfs->radar_log[i].dur, 401 dfs->radar_log[i].is_chirp, 402 dfs->radar_log[i].seg_id, 403 dfs->radar_log[i].sidx, 404 FREQ_OFFSET1, 405 FREQ_OFFSET2, 406 dfs->radar_log[i].peak_mag, 407 dfs->radar_log[i].total_gain, 408 dfs->radar_log[i].mb_gain, 409 dfs->radar_log[i].relpwr_db, 410 dfs->radar_log[i].delta_diff, 411 dfs->radar_log[i].delta_peak); 412 } 413 dfs->dfs_event_log_count = 0; 414 dfs->dfs_phyerr_count = 0; 415 dfs->dfs_phyerr_reject_count = 0; 416 dfs->dfs_phyerr_queued_count = 0; 417 dfs->dfs_phyerr_freq_min = 0x7fffffff; 418 dfs->dfs_phyerr_freq_max = 0; 419 break; 420 case DFS_SET_USENOL: 421 if (insize < sizeof(uint32_t) || !indata) { 422 error = -EINVAL; 423 break; 424 } 425 dfs->dfs_use_nol = *(uint32_t *)indata; 426 break; 427 case DFS_GET_NOL: 428 if (!outdata || !outsize || 429 *outsize < sizeof(struct dfsreq_nolinfo)) { 430 error = -EINVAL; 431 break; 432 } 433 *outsize = sizeof(struct dfsreq_nolinfo); 434 nol = (struct dfsreq_nolinfo *)outdata; 435 DFS_GET_NOL_LOCKED(dfs, 436 (struct dfsreq_nolelem *)nol->dfs_nol, 437 &nol->dfs_ch_nchans); 438 DFS_PRINT_NOL_LOCKED(dfs); 439 break; 440 case DFS_SET_NOL: 441 if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { 442 error = -EINVAL; 443 break; 444 } 445 nol = (struct dfsreq_nolinfo *) indata; 446 dfs_set_nol(dfs, 447 (struct dfsreq_nolelem *)nol->dfs_nol, 448 nol->dfs_ch_nchans); 449 break; 450 case DFS_SHOW_NOL: 451 DFS_PRINT_NOL_LOCKED(dfs); 452 break; 453 case DFS_SHOW_NOLHISTORY: 454 dfs_print_nolhistory(dfs); 455 break; 456 case DFS_BANGRADAR: 457 if (dfs->dfs_is_offload_enabled) { 458 error = dfs_fill_emulate_bang_radar_test(dfs, 459 SEG_ID_PRIMARY, 460 &dfs_unit_test); 461 } else { 462 dfs->dfs_bangradar = 1; 463 error = dfs_start_host_based_bangradar(dfs); 464 } 465 break; 466 case DFS_SHOW_PRECAC_LISTS: 467 dfs_print_precaclists(dfs); 468 break; 469 case DFS_RESET_PRECAC_LISTS: 470 dfs_reset_precac_lists(dfs); 471 break; 472 case DFS_SECOND_SEGMENT_BANGRADAR: 473 if (dfs->dfs_is_offload_enabled) { 474 error = dfs_fill_emulate_bang_radar_test(dfs, 475 SEG_ID_SECONDARY, 476 &dfs_unit_test); 477 } else { 478 dfs->dfs_second_segment_bangradar = 1; 479 error = dfs_start_host_based_bangradar(dfs); 480 } 481 break; 482 default: 483 error = -EINVAL; 484 } 485 486 bad: 487 return error; 488 } 489 490 void dfs_set_current_channel(struct wlan_dfs *dfs, 491 uint16_t dfs_ch_freq, 492 uint64_t dfs_ch_flags, 493 uint16_t dfs_ch_flagext, 494 uint8_t dfs_ch_ieee, 495 uint8_t dfs_ch_vhtop_ch_freq_seg1, 496 uint8_t dfs_ch_vhtop_ch_freq_seg2) 497 { 498 if (!dfs) { 499 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 500 return; 501 } 502 503 dfs->dfs_curchan->dfs_ch_freq = dfs_ch_freq; 504 dfs->dfs_curchan->dfs_ch_flags = dfs_ch_flags; 505 dfs->dfs_curchan->dfs_ch_flagext = dfs_ch_flagext; 506 dfs->dfs_curchan->dfs_ch_ieee = dfs_ch_ieee; 507 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_ch_vhtop_ch_freq_seg1; 508 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_ch_vhtop_ch_freq_seg2; 509 } 510 511 void dfs_update_cur_chan_flags(struct wlan_dfs *dfs, 512 uint64_t flags, 513 uint16_t flagext) 514 { 515 dfs->dfs_curchan->dfs_ch_flags = flags; 516 dfs->dfs_curchan->dfs_ch_flagext = flagext; 517 } 518