1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * DOC: contains scan south bound interface definitions 22 */ 23 24 #include <wlan_cmn.h> 25 #include <qdf_list.h> 26 #include "../../core/src/wlan_scan_main.h" 27 #include <wlan_scan_utils_api.h> 28 #include <wlan_scan_ucfg_api.h> 29 #include <wlan_scan_tgt_api.h> 30 #include <wlan_objmgr_cmn.h> 31 #include <wlan_lmac_if_def.h> 32 #include <wlan_objmgr_psoc_obj.h> 33 #include <wlan_objmgr_pdev_obj.h> 34 #include <wlan_objmgr_vdev_obj.h> 35 #include <../../core/src/wlan_scan_manager.h> 36 37 static inline struct wlan_lmac_if_scan_tx_ops * 38 wlan_psoc_get_scan_txops(struct wlan_objmgr_psoc *psoc) 39 { 40 struct wlan_lmac_if_tx_ops *tx_ops; 41 42 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 43 if (!tx_ops) { 44 scm_err("tx_ops is NULL"); 45 return NULL; 46 } 47 48 return &tx_ops->scan; 49 } 50 51 static inline struct wlan_lmac_if_scan_tx_ops * 52 wlan_vdev_get_scan_txops(struct wlan_objmgr_vdev *vdev) 53 { 54 struct wlan_objmgr_psoc *psoc = NULL; 55 56 psoc = wlan_vdev_get_psoc(vdev); 57 if (!psoc) { 58 scm_err("NULL psoc"); 59 return NULL; 60 } 61 62 return wlan_psoc_get_scan_txops(psoc); 63 } 64 65 static inline struct wlan_lmac_if_scan_rx_ops * 66 wlan_vdev_get_scan_rxops(struct wlan_objmgr_vdev *vdev) 67 { 68 struct wlan_objmgr_psoc *psoc = NULL; 69 struct wlan_lmac_if_rx_ops *rx_ops; 70 71 psoc = wlan_vdev_get_psoc(vdev); 72 if (!psoc) { 73 scm_err("NULL psoc"); 74 return NULL; 75 } 76 77 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 78 if (!rx_ops) { 79 scm_err("rx_ops is NULL"); 80 return NULL; 81 } 82 83 return &rx_ops->scan; 84 } 85 86 #ifdef FEATURE_WLAN_SCAN_PNO 87 88 QDF_STATUS tgt_scan_pno_start(struct wlan_objmgr_vdev *vdev, 89 struct pno_scan_req_params *req) 90 { 91 struct wlan_lmac_if_scan_tx_ops *scan_ops; 92 struct wlan_objmgr_psoc *psoc; 93 94 psoc = wlan_vdev_get_psoc(vdev); 95 96 if (!psoc) { 97 scm_err("NULL PSOC"); 98 return QDF_STATUS_E_FAILURE; 99 } 100 scan_ops = wlan_psoc_get_scan_txops(psoc); 101 if (!scan_ops) { 102 scm_err("NULL scan_ops"); 103 return QDF_STATUS_E_FAILURE; 104 } 105 /* invoke wmi_unified_pno_start_cmd() */ 106 QDF_ASSERT(scan_ops->pno_start); 107 if (scan_ops->pno_start) 108 return scan_ops->pno_start(psoc, req); 109 110 return QDF_STATUS_SUCCESS; 111 } 112 113 QDF_STATUS tgt_scan_pno_stop(struct wlan_objmgr_vdev *vdev, 114 uint8_t vdev_id) 115 { 116 struct wlan_lmac_if_scan_tx_ops *scan_ops; 117 struct wlan_objmgr_psoc *psoc; 118 119 psoc = wlan_vdev_get_psoc(vdev); 120 121 if (!psoc) { 122 scm_err("NULL PSOC"); 123 return QDF_STATUS_E_FAILURE; 124 } 125 scan_ops = wlan_psoc_get_scan_txops(psoc); 126 if (!scan_ops) { 127 scm_err("NULL scan_ops"); 128 return QDF_STATUS_E_FAILURE; 129 } 130 /* invoke wmi_unified_pno_stop_cmd() */ 131 QDF_ASSERT(scan_ops->pno_stop); 132 if (scan_ops->pno_stop) 133 return scan_ops->pno_stop(psoc, vdev_id); 134 135 return QDF_STATUS_SUCCESS; 136 } 137 #endif 138 139 QDF_STATUS tgt_scan_obss_disable(struct wlan_objmgr_vdev *vdev) 140 { 141 struct wlan_lmac_if_scan_tx_ops *scan_ops; 142 struct wlan_objmgr_psoc *psoc; 143 uint8_t vdev_id; 144 145 psoc = wlan_vdev_get_psoc(vdev); 146 147 if (!psoc) { 148 scm_err("NULL PSOC"); 149 return QDF_STATUS_E_FAILURE; 150 } 151 scan_ops = wlan_psoc_get_scan_txops(psoc); 152 if (!scan_ops) { 153 scm_err("NULL scan_ops"); 154 return QDF_STATUS_E_FAILURE; 155 } 156 157 vdev_id = wlan_vdev_get_id(vdev); 158 159 /* invoke wmi_unified_obss_disable_cmd() */ 160 QDF_ASSERT(scan_ops->obss_disable); 161 if (scan_ops->obss_disable) 162 return scan_ops->obss_disable(psoc, vdev_id); 163 164 return QDF_STATUS_SUCCESS; 165 } 166 167 QDF_STATUS 168 tgt_scan_start(struct scan_start_request *req) 169 { 170 struct wlan_lmac_if_scan_tx_ops *scan_ops; 171 struct wlan_objmgr_psoc *psoc; 172 struct wlan_objmgr_pdev *pdev; 173 struct wlan_objmgr_vdev *vdev = req->vdev; 174 175 if (!vdev) { 176 scm_err("vdev is NULL"); 177 return QDF_STATUS_E_NULL_VALUE; 178 } 179 180 psoc = wlan_vdev_get_psoc(vdev); 181 pdev = wlan_vdev_get_pdev(vdev); 182 if (!psoc || !pdev) { 183 scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev); 184 return QDF_STATUS_E_NULL_VALUE; 185 } 186 187 scan_ops = wlan_psoc_get_scan_txops(psoc); 188 if (!scan_ops) { 189 scm_err("NULL scan_ops"); 190 return QDF_STATUS_E_NULL_VALUE; 191 } 192 193 /* invoke wmi_unified_scan_start_cmd_send() */ 194 QDF_ASSERT(scan_ops->scan_start); 195 if (scan_ops->scan_start) 196 return scan_ops->scan_start(pdev, req); 197 else 198 return QDF_STATUS_SUCCESS; 199 } 200 201 202 QDF_STATUS 203 tgt_scan_cancel(struct scan_cancel_request *req) 204 { 205 struct wlan_lmac_if_scan_tx_ops *scan_ops; 206 struct wlan_objmgr_psoc *psoc; 207 struct wlan_objmgr_pdev *pdev; 208 struct wlan_objmgr_vdev *vdev = req->vdev; 209 210 if (!vdev) { 211 scm_err("vdev is NULL"); 212 return QDF_STATUS_E_NULL_VALUE; 213 } 214 psoc = wlan_vdev_get_psoc(vdev); 215 pdev = wlan_vdev_get_pdev(vdev); 216 if (!psoc || !pdev) { 217 scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev); 218 return QDF_STATUS_E_NULL_VALUE; 219 } 220 scan_ops = wlan_psoc_get_scan_txops(psoc); 221 if (!scan_ops) { 222 scm_err("NULL scan_ops"); 223 return QDF_STATUS_E_NULL_VALUE; 224 } 225 226 /* invoke wmi_unified_scan_stop_cmd_send() */ 227 QDF_ASSERT(scan_ops->scan_cancel); 228 if (scan_ops->scan_cancel) 229 return scan_ops->scan_cancel(pdev, &req->cancel_req); 230 else 231 return QDF_STATUS_SUCCESS; 232 } 233 234 QDF_STATUS 235 tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc) 236 { 237 struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; 238 239 scan_ops = wlan_psoc_get_scan_txops(psoc); 240 if (!scan_ops) { 241 scm_err("NULL scan_ops"); 242 return QDF_STATUS_E_FAILURE; 243 } 244 245 /* invoke wmi_unified_register_event_handler() 246 * since event id, handler function and context is 247 * already known to offload lmac, passing NULL as argument. 248 * DA can pass necessary arguments by clubing then into 249 * some structure. 250 */ 251 QDF_ASSERT(scan_ops->scan_reg_ev_handler); 252 if (scan_ops->scan_reg_ev_handler) 253 return scan_ops->scan_reg_ev_handler(psoc, NULL); 254 else 255 return QDF_STATUS_SUCCESS; 256 } 257 258 QDF_STATUS 259 tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) 260 { 261 struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; 262 263 scan_ops = wlan_psoc_get_scan_txops(psoc); 264 if (!scan_ops) { 265 scm_err("NULL scan_ops"); 266 return QDF_STATUS_E_FAILURE; 267 } 268 269 /* invoke wmi_unified_register_event_handler() 270 * since event id, handler function and context is 271 * already known to offload lmac, passing NULL as argument. 272 * DA can pass necessary arguments by clubing then into 273 * some structure. 274 */ 275 QDF_ASSERT(scan_ops->scan_unreg_ev_handler); 276 if (scan_ops->scan_unreg_ev_handler) 277 return scan_ops->scan_unreg_ev_handler(psoc, NULL); 278 else 279 return QDF_STATUS_SUCCESS; 280 } 281 282 QDF_STATUS 283 tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc, 284 struct scan_event_info *event_info) 285 { 286 struct scheduler_msg msg = {0}; 287 struct scan_event *event = &event_info->event; 288 uint8_t vdev_id = event->vdev_id; 289 QDF_STATUS status; 290 291 if (!psoc || !event_info) { 292 scm_err("psoc: 0x%pK, event_info: 0x%pK", psoc, event_info); 293 return QDF_STATUS_E_NULL_VALUE; 294 } 295 296 event_info->vdev = 297 wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 298 vdev_id, WLAN_SCAN_ID); 299 if (!event_info->vdev) { 300 scm_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc); 301 return QDF_STATUS_E_INVAL; 302 } 303 msg.bodyptr = event_info; 304 msg.callback = scm_scan_event_handler; 305 msg.flush_callback = scm_scan_event_flush_callback; 306 307 status = scheduler_post_message(QDF_MODULE_ID_SCAN, 308 QDF_MODULE_ID_SCAN, 309 QDF_MODULE_ID_SCAN, &msg); 310 if (QDF_IS_STATUS_ERROR(status)) { 311 wlan_objmgr_vdev_release_ref(event_info->vdev, WLAN_SCAN_ID); 312 } 313 314 return status; 315 } 316 317 QDF_STATUS tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc *psoc, 318 struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, 319 struct mgmt_rx_event_params *rx_param, 320 enum mgmt_frame_type frm_type) 321 { 322 struct scheduler_msg msg = {0}; 323 struct scan_bcn_probe_event *bcn = NULL; 324 QDF_STATUS status; 325 uint32_t scan_queue_size = 0; 326 327 if ((frm_type != MGMT_PROBE_RESP) && 328 (frm_type != MGMT_BEACON)) { 329 scm_err("frame is not beacon or probe resp"); 330 status = QDF_STATUS_E_INVAL; 331 goto free; 332 } 333 334 bcn = qdf_mem_malloc_atomic(sizeof(*bcn)); 335 if (!bcn) { 336 status = QDF_STATUS_E_NOMEM; 337 goto free; 338 } 339 bcn->rx_data = 340 qdf_mem_malloc_atomic(sizeof(*rx_param)); 341 if (!bcn->rx_data) { 342 status = QDF_STATUS_E_NOMEM; 343 goto free; 344 } 345 346 if (frm_type == MGMT_PROBE_RESP) 347 bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP; 348 else 349 bcn->frm_type = MGMT_SUBTYPE_BEACON; 350 351 /* Check if the beacon/probe frame can be posted in the scan queue */ 352 status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size); 353 if (!QDF_IS_STATUS_SUCCESS(status) || 354 scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) { 355 scm_debug_rl("Dropping beacon/probe frame, queue size %d", 356 scan_queue_size); 357 status = QDF_STATUS_E_FAILURE; 358 goto free; 359 } 360 361 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID); 362 if (QDF_IS_STATUS_ERROR(status)) { 363 scm_info("unable to get reference"); 364 goto free; 365 } 366 367 bcn->psoc = psoc; 368 bcn->buf = buf; 369 bcn->save_rnr_info = false; 370 qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param)); 371 372 msg.bodyptr = bcn; 373 msg.callback = scm_handle_bcn_probe; 374 msg.flush_callback = scm_bcn_probe_flush_callback; 375 376 status = scheduler_post_message(QDF_MODULE_ID_SCAN, 377 QDF_MODULE_ID_SCAN, 378 QDF_MODULE_ID_SCAN, &msg); 379 380 if (QDF_IS_STATUS_SUCCESS(status)) 381 return status; 382 383 wlan_objmgr_psoc_release_ref(psoc, WLAN_SCAN_ID); 384 385 free: 386 if (bcn && bcn->rx_data) 387 qdf_mem_free(bcn->rx_data); 388 if (bcn) 389 qdf_mem_free(bcn); 390 if (buf) 391 qdf_nbuf_free(buf); 392 393 return status; 394 } 395 396 QDF_STATUS 397 tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc, 398 uint32_t max_active_scans) 399 { 400 struct scan_default_params *scan_params = NULL; 401 402 if (!psoc) { 403 scm_err("null psoc"); 404 return QDF_STATUS_E_NULL_VALUE; 405 } 406 407 scan_params = wlan_scan_psoc_get_def_params(psoc); 408 if (!scan_params) { 409 scm_err("wlan_scan_psoc_get_def_params returned NULL"); 410 return QDF_STATUS_E_NULL_VALUE; 411 } 412 413 scan_params->max_active_scans_allowed = max_active_scans; 414 415 return QDF_STATUS_SUCCESS; 416 } 417