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