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