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 scan_ops = wlan_psoc_get_scan_txops(psoc); 81 /* invoke wmi_unified_pno_start_cmd() */ 82 QDF_ASSERT(scan_ops->pno_start); 83 if (scan_ops->pno_start) 84 return scan_ops->pno_start(psoc, req); 85 86 return QDF_STATUS_SUCCESS; 87 } 88 89 QDF_STATUS tgt_scan_pno_stop(struct wlan_objmgr_vdev *vdev, 90 uint8_t vdev_id) 91 { 92 struct wlan_lmac_if_scan_tx_ops *scan_ops; 93 struct wlan_objmgr_psoc *psoc; 94 95 psoc = wlan_vdev_get_psoc(vdev); 96 97 scan_ops = wlan_psoc_get_scan_txops(psoc); 98 /* invoke wmi_unified_pno_stop_cmd() */ 99 QDF_ASSERT(scan_ops->pno_stop); 100 if (scan_ops->pno_stop) 101 return scan_ops->pno_stop(psoc, vdev_id); 102 103 return QDF_STATUS_SUCCESS; 104 } 105 #endif 106 107 QDF_STATUS 108 tgt_scan_start(struct scan_start_request *req) 109 { 110 struct wlan_lmac_if_scan_tx_ops *scan_ops; 111 struct wlan_objmgr_psoc *psoc; 112 struct wlan_objmgr_pdev *pdev; 113 struct wlan_objmgr_vdev *vdev = req->vdev; 114 115 psoc = wlan_vdev_get_psoc(vdev); 116 pdev = wlan_vdev_get_pdev(vdev); 117 118 scan_ops = wlan_psoc_get_scan_txops(psoc); 119 /* invoke wmi_unified_scan_start_cmd_send() */ 120 QDF_ASSERT(scan_ops->scan_start); 121 if (scan_ops->scan_start) 122 return scan_ops->scan_start(pdev, req); 123 else 124 return QDF_STATUS_SUCCESS; 125 } 126 127 128 QDF_STATUS 129 tgt_scan_cancel(struct scan_cancel_request *req) 130 { 131 struct wlan_lmac_if_scan_tx_ops *scan_ops; 132 struct wlan_objmgr_psoc *psoc; 133 struct wlan_objmgr_pdev *pdev; 134 struct wlan_objmgr_vdev *vdev = req->vdev; 135 136 psoc = wlan_vdev_get_psoc(vdev); 137 pdev = wlan_vdev_get_pdev(vdev); 138 139 scan_ops = wlan_psoc_get_scan_txops(psoc); 140 /* invoke wmi_unified_scan_stop_cmd_send() */ 141 QDF_ASSERT(scan_ops->scan_cancel); 142 if (scan_ops->scan_cancel) 143 return scan_ops->scan_cancel(pdev, &req->cancel_req); 144 else 145 return QDF_STATUS_SUCCESS; 146 } 147 148 QDF_STATUS 149 tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc) 150 { 151 struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; 152 153 scan_ops = wlan_psoc_get_scan_txops(psoc); 154 /* invoke wmi_unified_register_event_handler() 155 * since event id, handler function and context is 156 * already known to offload lmac, passing NULL as argument. 157 * DA can pass necessary arguments by clubing then into 158 * some structure. 159 */ 160 QDF_ASSERT(scan_ops->scan_reg_ev_handler); 161 if (scan_ops->scan_reg_ev_handler) 162 return scan_ops->scan_reg_ev_handler(psoc, NULL); 163 else 164 return QDF_STATUS_SUCCESS; 165 } 166 167 QDF_STATUS 168 tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) 169 { 170 struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL; 171 172 scan_ops = wlan_psoc_get_scan_txops(psoc); 173 /* invoke wmi_unified_register_event_handler() 174 * since event id, handler function and context is 175 * already known to offload lmac, passing NULL as argument. 176 * DA can pass necessary arguments by clubing then into 177 * some structure. 178 */ 179 QDF_ASSERT(scan_ops->scan_unreg_ev_handler); 180 if (scan_ops->scan_unreg_ev_handler) 181 return scan_ops->scan_unreg_ev_handler(psoc, NULL); 182 else 183 return QDF_STATUS_SUCCESS; 184 } 185 186 QDF_STATUS 187 tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc, 188 struct scan_event_info *event_info) 189 { 190 struct scheduler_msg msg = {0}; 191 struct scan_event *event = &event_info->event; 192 uint8_t vdev_id = event->vdev_id; 193 QDF_STATUS status; 194 195 if (!psoc || !event_info) { 196 scm_err("psoc: 0x%pK, event_info: 0x%pK", psoc, event_info); 197 return QDF_STATUS_E_NULL_VALUE; 198 } 199 scm_info("vdev: %d, type: %d, reason: %d, freq: %d, req: %d, scanid: %d", 200 vdev_id, event->type, event->reason, event->chan_freq, 201 event->requester, event->scan_id); 202 203 event_info->vdev = 204 wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 205 vdev_id, WLAN_SCAN_ID); 206 if (!event_info->vdev) { 207 scm_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc); 208 return QDF_STATUS_E_INVAL; 209 } 210 msg.bodyptr = event_info; 211 msg.callback = scm_scan_event_handler; 212 msg.flush_callback = scm_scan_event_flush_callback; 213 214 status = scheduler_post_msg(QDF_MODULE_ID_SCAN, &msg); 215 if (QDF_IS_STATUS_ERROR(status)) { 216 wlan_objmgr_vdev_release_ref(event_info->vdev, WLAN_SCAN_ID); 217 } 218 219 return status; 220 } 221 222 QDF_STATUS tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc *psoc, 223 struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, 224 struct mgmt_rx_event_params *rx_param, 225 enum mgmt_frame_type frm_type) 226 { 227 struct scheduler_msg msg = {0}; 228 struct scan_bcn_probe_event *bcn; 229 QDF_STATUS status; 230 231 if ((frm_type != MGMT_PROBE_RESP) && 232 (frm_type != MGMT_BEACON)) { 233 scm_err("frame is not beacon or probe resp"); 234 qdf_nbuf_free(buf); 235 return QDF_STATUS_E_INVAL; 236 } 237 bcn = qdf_mem_malloc(sizeof(*bcn)); 238 239 if (!bcn) { 240 scm_err("Failed to allocate memory for bcn"); 241 qdf_nbuf_free(buf); 242 return QDF_STATUS_E_NOMEM; 243 } 244 bcn->rx_data = 245 qdf_mem_malloc(sizeof(*rx_param)); 246 if (!bcn->rx_data) { 247 scm_err("Failed to allocate memory for rx_data"); 248 qdf_mem_free(bcn); 249 qdf_nbuf_free(buf); 250 return QDF_STATUS_E_NOMEM; 251 } 252 253 if (frm_type == MGMT_PROBE_RESP) 254 bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP; 255 else 256 bcn->frm_type = MGMT_SUBTYPE_BEACON; 257 258 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID); 259 if (QDF_IS_STATUS_ERROR(status)) { 260 scm_info("unable to get reference"); 261 qdf_mem_free(bcn->rx_data); 262 qdf_mem_free(bcn); 263 qdf_nbuf_free(buf); 264 return status; 265 } 266 267 bcn->psoc = psoc; 268 bcn->buf = buf; 269 qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param)); 270 271 msg.bodyptr = bcn; 272 msg.callback = scm_handle_bcn_probe; 273 msg.flush_callback = scm_bcn_probe_flush_callback; 274 275 status = scheduler_post_msg(QDF_MODULE_ID_SCAN, &msg); 276 277 if (!QDF_IS_STATUS_SUCCESS(status)) { 278 wlan_objmgr_psoc_release_ref(psoc, WLAN_SCAN_ID); 279 scm_err("failed to post to QDF_MODULE_ID_SCAN"); 280 qdf_mem_free(bcn->rx_data); 281 qdf_mem_free(bcn); 282 qdf_nbuf_free(buf); 283 } 284 285 return status; 286 } 287 288 QDF_STATUS 289 tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc, 290 uint32_t max_active_scans) 291 { 292 struct scan_default_params *scan_params = NULL; 293 294 if (!psoc) { 295 scm_err("null psoc"); 296 return QDF_STATUS_E_NULL_VALUE; 297 } 298 299 scan_params = wlan_scan_psoc_get_def_params(psoc); 300 if (!scan_params) { 301 scm_err("wlan_scan_psoc_get_def_params returned NULL"); 302 return QDF_STATUS_E_NULL_VALUE; 303 } 304 305 scan_params->max_active_scans_allowed = max_active_scans; 306 307 return QDF_STATUS_SUCCESS; 308 } 309