1 /* 2 * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * DOC: This file contains all SCAN component's APIs 21 */ 22 23 #include "cfg_ucfg_api.h" 24 #include "wlan_scan_api.h" 25 #include "../../core/src/wlan_scan_manager.h" 26 27 void wlan_scan_cfg_get_passive_dwelltime(struct wlan_objmgr_psoc *psoc, 28 uint32_t *dwell_time) 29 { 30 struct wlan_scan_obj *scan_obj; 31 32 scan_obj = wlan_psoc_get_scan_obj(psoc); 33 if (!scan_obj) 34 return; 35 *dwell_time = scan_obj->scan_def.passive_dwell; 36 } 37 38 void wlan_scan_cfg_set_passive_dwelltime(struct wlan_objmgr_psoc *psoc, 39 uint32_t dwell_time) 40 { 41 struct wlan_scan_obj *scan_obj; 42 43 scan_obj = wlan_psoc_get_scan_obj(psoc); 44 if (!scan_obj) 45 return; 46 scan_obj->scan_def.passive_dwell = dwell_time; 47 } 48 49 void wlan_scan_cfg_get_active_dwelltime(struct wlan_objmgr_psoc *psoc, 50 uint32_t *dwell_time) 51 { 52 struct wlan_scan_obj *scan_obj; 53 54 scan_obj = wlan_psoc_get_scan_obj(psoc); 55 if (!scan_obj) 56 return; 57 *dwell_time = scan_obj->scan_def.active_dwell; 58 } 59 60 void wlan_scan_cfg_set_active_dwelltime(struct wlan_objmgr_psoc *psoc, 61 uint32_t dwell_time) 62 { 63 struct wlan_scan_obj *scan_obj; 64 65 scan_obj = wlan_psoc_get_scan_obj(psoc); 66 if (!scan_obj) 67 return; 68 scan_obj->scan_def.active_dwell = dwell_time; 69 } 70 71 void wlan_scan_cfg_get_active_2g_dwelltime(struct wlan_objmgr_psoc *psoc, 72 uint32_t *dwell_time) 73 { 74 struct wlan_scan_obj *scan_obj; 75 76 scan_obj = wlan_psoc_get_scan_obj(psoc); 77 if (!scan_obj) 78 return; 79 80 *dwell_time = scan_obj->scan_def.active_dwell_2g; 81 } 82 83 void wlan_scan_cfg_set_active_2g_dwelltime(struct wlan_objmgr_psoc *psoc, 84 uint32_t dwell_time) 85 { 86 struct wlan_scan_obj *scan_obj; 87 88 scan_obj = wlan_psoc_get_scan_obj(psoc); 89 if (!scan_obj) 90 return; 91 scan_obj->scan_def.active_dwell_2g = dwell_time; 92 } 93 94 #ifdef CONFIG_BAND_6GHZ 95 QDF_STATUS wlan_scan_cfg_get_active_6g_dwelltime(struct wlan_objmgr_psoc *psoc, 96 uint32_t *dwell_time) 97 { 98 struct wlan_scan_obj *scan_obj; 99 100 scan_obj = wlan_psoc_get_scan_obj(psoc); 101 if (!scan_obj) 102 return QDF_STATUS_E_INVAL; 103 104 *dwell_time = scan_obj->scan_def.active_dwell_6g; 105 106 return QDF_STATUS_SUCCESS; 107 } 108 109 QDF_STATUS wlan_scan_cfg_set_active_6g_dwelltime(struct wlan_objmgr_psoc *psoc, 110 uint32_t dwell_time) 111 { 112 struct wlan_scan_obj *scan_obj; 113 114 scan_obj = wlan_psoc_get_scan_obj(psoc); 115 if (!scan_obj) 116 return QDF_STATUS_E_INVAL; 117 118 scan_obj->scan_def.active_dwell_6g = dwell_time; 119 120 return QDF_STATUS_SUCCESS; 121 } 122 123 QDF_STATUS wlan_scan_cfg_get_passive_6g_dwelltime(struct wlan_objmgr_psoc *psoc, 124 uint32_t *dwell_time) 125 { 126 struct wlan_scan_obj *scan_obj; 127 128 scan_obj = wlan_psoc_get_scan_obj(psoc); 129 if (!scan_obj) 130 return QDF_STATUS_E_INVAL; 131 132 *dwell_time = scan_obj->scan_def.passive_dwell_6g; 133 134 return QDF_STATUS_SUCCESS; 135 } 136 137 QDF_STATUS wlan_scan_cfg_set_passive_6g_dwelltime(struct wlan_objmgr_psoc *psoc, 138 uint32_t dwell_time) 139 { 140 struct wlan_scan_obj *scan_obj; 141 142 scan_obj = wlan_psoc_get_scan_obj(psoc); 143 if (!scan_obj) 144 return QDF_STATUS_E_INVAL; 145 146 scan_obj->scan_def.passive_dwell_6g = dwell_time; 147 148 return QDF_STATUS_SUCCESS; 149 } 150 #endif 151 152 void wlan_scan_cfg_get_conc_active_dwelltime(struct wlan_objmgr_psoc *psoc, 153 uint32_t *dwell_time) 154 { 155 struct wlan_scan_obj *scan_obj; 156 157 scan_obj = wlan_psoc_get_scan_obj(psoc); 158 if (!scan_obj) 159 return; 160 161 *dwell_time = scan_obj->scan_def.conc_active_dwell; 162 } 163 164 void wlan_scan_cfg_set_conc_active_dwelltime(struct wlan_objmgr_psoc *psoc, 165 uint32_t dwell_time) 166 { 167 struct wlan_scan_obj *scan_obj; 168 169 scan_obj = wlan_psoc_get_scan_obj(psoc); 170 if (!scan_obj) 171 return; 172 173 scan_obj->scan_def.conc_active_dwell = dwell_time; 174 } 175 176 void wlan_scan_cfg_get_conc_passive_dwelltime(struct wlan_objmgr_psoc *psoc, 177 uint32_t *dwell_time) 178 { 179 struct wlan_scan_obj *scan_obj; 180 181 scan_obj = wlan_psoc_get_scan_obj(psoc); 182 if (!scan_obj) 183 return; 184 185 *dwell_time = scan_obj->scan_def.conc_passive_dwell; 186 } 187 188 void wlan_scan_cfg_set_conc_passive_dwelltime(struct wlan_objmgr_psoc *psoc, 189 uint32_t dwell_time) 190 { 191 struct wlan_scan_obj *scan_obj; 192 193 scan_obj = wlan_psoc_get_scan_obj(psoc); 194 if (!scan_obj) 195 return; 196 197 scan_obj->scan_def.conc_passive_dwell = dwell_time; 198 } 199 200 void 201 wlan_scan_cfg_get_dfs_chan_scan_allowed(struct wlan_objmgr_psoc *psoc, 202 bool *enable_dfs_scan) 203 { 204 struct wlan_scan_obj *scan_obj; 205 206 scan_obj = wlan_psoc_get_scan_obj(psoc); 207 if (!scan_obj) 208 return; 209 210 *enable_dfs_scan = scan_obj->scan_def.allow_dfs_chan_in_scan; 211 } 212 213 void 214 wlan_scan_cfg_set_dfs_chan_scan_allowed(struct wlan_objmgr_psoc *psoc, 215 bool enable_dfs_scan) 216 { 217 struct wlan_scan_obj *scan_obj; 218 219 scan_obj = wlan_psoc_get_scan_obj(psoc); 220 if (!scan_obj) 221 return; 222 223 scan_obj->scan_def.allow_dfs_chan_in_scan = enable_dfs_scan; 224 } 225 226 bool wlan_scan_cfg_honour_nl_scan_policy_flags(struct wlan_objmgr_psoc *psoc) 227 { 228 struct wlan_scan_obj *scan_obj; 229 230 scan_obj = wlan_psoc_get_scan_obj(psoc); 231 if (!scan_obj) 232 return false; 233 234 return scan_obj->scan_def.honour_nl_scan_policy_flags; 235 } 236 237 void wlan_scan_cfg_get_conc_max_resttime(struct wlan_objmgr_psoc *psoc, 238 uint32_t *rest_time) 239 { 240 struct wlan_scan_obj *scan_obj; 241 242 scan_obj = wlan_psoc_get_scan_obj(psoc); 243 if (!scan_obj) 244 return; 245 246 *rest_time = scan_obj->scan_def.conc_max_rest_time; 247 } 248 249 void wlan_scan_cfg_get_conc_min_resttime(struct wlan_objmgr_psoc *psoc, 250 uint32_t *rest_time) 251 { 252 struct wlan_scan_obj *scan_obj; 253 254 scan_obj = wlan_psoc_get_scan_obj(psoc); 255 if (!scan_obj) 256 return; 257 258 *rest_time = scan_obj->scan_def.conc_min_rest_time; 259 } 260 261 bool wlan_scan_is_snr_monitor_enabled(struct wlan_objmgr_psoc *psoc) 262 { 263 struct wlan_scan_obj *scan_obj; 264 265 scan_obj = wlan_psoc_get_scan_obj(psoc); 266 if (!scan_obj) 267 return cfg_default(CFG_ENABLE_SNR_MONITORING); 268 269 return scan_obj->scan_def.scan_f_chan_stat_evnt; 270 } 271 272 QDF_STATUS 273 wlan_scan_process_bcn_probe_rx_sync(struct wlan_objmgr_psoc *psoc, 274 qdf_nbuf_t buf, 275 struct mgmt_rx_event_params *rx_param, 276 enum mgmt_frame_type frm_type) 277 { 278 struct scan_bcn_probe_event *bcn = NULL; 279 QDF_STATUS status; 280 281 if ((frm_type != MGMT_PROBE_RESP) && 282 (frm_type != MGMT_BEACON)) { 283 scm_err("frame is not beacon or probe resp"); 284 status = QDF_STATUS_E_INVAL; 285 goto free; 286 } 287 288 bcn = qdf_mem_malloc_atomic(sizeof(*bcn)); 289 if (!bcn) { 290 status = QDF_STATUS_E_NOMEM; 291 goto free; 292 } 293 bcn->rx_data = 294 qdf_mem_malloc_atomic(sizeof(*rx_param)); 295 if (!bcn->rx_data) { 296 status = QDF_STATUS_E_NOMEM; 297 goto free; 298 } 299 300 if (frm_type == MGMT_PROBE_RESP) 301 bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP; 302 else 303 bcn->frm_type = MGMT_SUBTYPE_BEACON; 304 305 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID); 306 if (QDF_IS_STATUS_ERROR(status)) { 307 scm_info("unable to get reference"); 308 goto free; 309 } 310 311 bcn->psoc = psoc; 312 bcn->buf = buf; 313 qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param)); 314 315 return __scm_handle_bcn_probe(bcn); 316 free: 317 if (bcn && bcn->rx_data) 318 qdf_mem_free(bcn->rx_data); 319 if (bcn) 320 qdf_mem_free(bcn); 321 if (buf) 322 qdf_nbuf_free(buf); 323 324 return status; 325 } 326 327 qdf_time_t wlan_scan_get_aging_time(struct wlan_objmgr_psoc *psoc) 328 { 329 struct wlan_scan_obj *scan_obj; 330 331 scan_obj = wlan_psoc_get_scan_obj(psoc); 332 if (!scan_obj) 333 return cfg_default(CFG_SCAN_AGING_TIME) * 1000; 334 335 return scan_obj->scan_def.scan_cache_aging_time; 336 } 337 338 QDF_STATUS wlan_scan_start(struct scan_start_request *req) 339 { 340 struct scheduler_msg msg = {0}; 341 QDF_STATUS status; 342 343 if (!req || !req->vdev) { 344 scm_err("req or vdev within req is NULL"); 345 if (req) 346 scm_scan_free_scan_request_mem(req); 347 return QDF_STATUS_E_NULL_VALUE; 348 } 349 350 if (!scm_is_scan_allowed(req->vdev)) { 351 scm_err_rl("scan disabled, rejecting the scan req"); 352 scm_scan_free_scan_request_mem(req); 353 return QDF_STATUS_E_AGAIN; 354 } 355 356 /* 357 * Try to get vdev reference. Return if reference could 358 * not be taken. Reference will be released once scan 359 * request handling completes along with free of @req. 360 */ 361 status = wlan_objmgr_vdev_try_get_ref(req->vdev, WLAN_SCAN_ID); 362 if (QDF_IS_STATUS_ERROR(status)) { 363 scm_info("unable to get reference"); 364 scm_scan_free_scan_request_mem(req); 365 return status; 366 } 367 368 msg.bodyptr = req; 369 msg.callback = scm_scan_start_req; 370 msg.flush_callback = scm_scan_start_flush_callback; 371 372 status = scheduler_post_message(QDF_MODULE_ID_OS_IF, 373 QDF_MODULE_ID_SCAN, 374 QDF_MODULE_ID_OS_IF, &msg); 375 if (QDF_IS_STATUS_ERROR(status)) { 376 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 377 scm_scan_free_scan_request_mem(req); 378 } 379 380 return status; 381 } 382 383 QDF_STATUS wlan_scan_cancel(struct scan_cancel_request *req) 384 { 385 struct scheduler_msg msg = {0}; 386 QDF_STATUS status; 387 388 if (!req || !req->vdev) { 389 scm_err("req or vdev within req is NULL"); 390 if (req) 391 qdf_mem_free(req); 392 return QDF_STATUS_E_NULL_VALUE; 393 } 394 395 status = wlan_objmgr_vdev_try_get_ref(req->vdev, WLAN_SCAN_ID); 396 if (QDF_IS_STATUS_ERROR(status)) { 397 scm_info("Failed to get vdev ref; status:%d", status); 398 goto req_free; 399 } 400 401 msg.bodyptr = req; 402 msg.callback = scm_scan_cancel_req; 403 msg.flush_callback = scm_scan_cancel_flush_callback; 404 405 status = scheduler_post_message(QDF_MODULE_ID_OS_IF, 406 QDF_MODULE_ID_SCAN, 407 QDF_MODULE_ID_OS_IF, &msg); 408 if (QDF_IS_STATUS_ERROR(status)) 409 goto vdev_put; 410 411 return QDF_STATUS_SUCCESS; 412 413 vdev_put: 414 wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); 415 416 req_free: 417 qdf_mem_free(req); 418 419 return status; 420 } 421 422 wlan_scan_id 423 wlan_scan_get_scan_id(struct wlan_objmgr_psoc *psoc) 424 { 425 wlan_scan_id id; 426 struct wlan_scan_obj *scan; 427 428 if (!psoc) { 429 QDF_ASSERT(0); 430 scm_err("null psoc"); 431 return 0; 432 } 433 434 scan = wlan_psoc_get_scan_obj(psoc); 435 if (!scan) { 436 scm_err("scan object null"); 437 return 0; 438 } 439 440 id = qdf_atomic_inc_return(&scan->scan_ids); 441 id = id & WLAN_SCAN_ID_MASK; 442 /* Mark this scan request as triggered by host 443 * by setting WLAN_HOST_SCAN_REQ_ID_PREFIX flag. 444 */ 445 id = id | WLAN_HOST_SCAN_REQ_ID_PREFIX; 446 scm_debug("scan_id: 0x%x", id); 447 448 return id; 449 } 450 451 QDF_STATUS 452 wlan_scan_init_default_params(struct wlan_objmgr_vdev *vdev, 453 struct scan_start_request *req) 454 { 455 struct scan_default_params *def; 456 457 if (!vdev | !req) { 458 scm_err("vdev: 0x%pK, req: 0x%pK", vdev, req); 459 return QDF_STATUS_E_INVAL; 460 } 461 def = wlan_vdev_get_def_scan_params(vdev); 462 if (!def) { 463 scm_err("wlan_vdev_get_def_scan_params returned NULL"); 464 return QDF_STATUS_E_NULL_VALUE; 465 } 466 467 /* Zero out everything and explicitly set fields as required */ 468 qdf_mem_zero(req, sizeof(*req)); 469 470 req->vdev = vdev; 471 req->scan_req.vdev_id = wlan_vdev_get_id(vdev); 472 req->scan_req.scan_type = SCAN_TYPE_DEFAULT; 473 req->scan_req.scan_priority = def->scan_priority; 474 req->scan_req.dwell_time_active = def->active_dwell; 475 req->scan_req.dwell_time_active_2g = def->active_dwell_2g; 476 req->scan_req.dwell_time_active_6g = def->active_dwell_6g; 477 req->scan_req.dwell_time_passive_6g = def->passive_dwell_6g; 478 req->scan_req.dwell_time_passive = def->passive_dwell; 479 req->scan_req.min_rest_time = def->min_rest_time; 480 req->scan_req.max_rest_time = def->max_rest_time; 481 req->scan_req.repeat_probe_time = def->repeat_probe_time; 482 req->scan_req.probe_spacing_time = def->probe_spacing_time; 483 req->scan_req.idle_time = def->idle_time; 484 req->scan_req.max_scan_time = def->max_scan_time; 485 req->scan_req.probe_delay = def->probe_delay; 486 req->scan_req.burst_duration = def->burst_duration; 487 req->scan_req.n_probes = def->num_probes; 488 req->scan_req.adaptive_dwell_time_mode = 489 def->adaptive_dwell_time_mode; 490 req->scan_req.scan_flags = def->scan_flags; 491 req->scan_req.scan_events = def->scan_events; 492 req->scan_req.scan_random.randomize = def->enable_mac_spoofing; 493 494 return QDF_STATUS_SUCCESS; 495 } 496 497 wlan_scan_requester 498 wlan_scan_register_requester(struct wlan_objmgr_psoc *psoc, 499 uint8_t *name, 500 scan_event_handler event_cb, 501 void *arg) 502 { 503 int i, j; 504 struct wlan_scan_obj *scan; 505 struct scan_requester_info *requesters; 506 wlan_scan_requester requester = {0}; 507 508 if (!psoc) { 509 scm_err("null psoc"); 510 return 0; 511 } 512 scan = wlan_psoc_get_scan_obj(psoc); 513 if (!scan) 514 return 0; 515 516 requesters = scan->requesters; 517 qdf_spin_lock_bh(&scan->lock); 518 for (i = 0; i < WLAN_MAX_REQUESTORS; ++i) { 519 if (requesters[i].requester == 0) { 520 requesters[i].requester = 521 WLAN_SCAN_REQUESTER_ID_PREFIX | i; 522 j = 0; 523 while (name[j] && (j < (WLAN_MAX_MODULE_NAME - 1))) { 524 requesters[i].module[j] = name[j]; 525 ++j; 526 } 527 requesters[i].module[j] = 0; 528 requesters[i].ev_handler.func = event_cb; 529 requesters[i].ev_handler.arg = arg; 530 requester = requesters[i].requester; 531 break; 532 } 533 } 534 qdf_spin_unlock_bh(&scan->lock); 535 scm_debug("module: %s, event_cb: 0x%pK, arg: 0x%pK, reqid: %d", 536 name, event_cb, arg, requester); 537 538 return requester; 539 } 540 541 void 542 wlan_scan_unregister_requester(struct wlan_objmgr_psoc *psoc, 543 wlan_scan_requester requester) 544 { 545 int idx; 546 struct wlan_scan_obj *scan; 547 struct scan_requester_info *requesters; 548 549 idx = requester & WLAN_SCAN_REQUESTER_ID_PREFIX; 550 if (idx != WLAN_SCAN_REQUESTER_ID_PREFIX) { 551 scm_err("prefix didn't match for requester id %d", requester); 552 return; 553 } 554 555 idx = requester & WLAN_SCAN_REQUESTER_ID_MASK; 556 if (idx >= WLAN_MAX_REQUESTORS) { 557 scm_err("requester id %d greater than max value", requester); 558 return; 559 } 560 561 if (!psoc) { 562 scm_err("null psoc"); 563 return; 564 } 565 scan = wlan_psoc_get_scan_obj(psoc); 566 if (!scan) 567 return; 568 requesters = scan->requesters; 569 scm_debug("reqid: %d", requester); 570 571 qdf_spin_lock_bh(&scan->lock); 572 requesters[idx].requester = 0; 573 requesters[idx].module[0] = 0; 574 requesters[idx].ev_handler.func = NULL; 575 requesters[idx].ev_handler.arg = NULL; 576 qdf_spin_unlock_bh(&scan->lock); 577 } 578 579