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