xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/dispatcher/src/wlan_scan_tgt_api.c (revision dd4dc88b837a295134aa9869114a2efee0f4894b)
1 /*
2  * Copyright (c) 2017-2019 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 
273 	bcn = qdf_mem_malloc_atomic(sizeof(*bcn));
274 	if (!bcn) {
275 		status = QDF_STATUS_E_NOMEM;
276 		goto free;
277 	}
278 	bcn->rx_data =
279 		qdf_mem_malloc_atomic(sizeof(*rx_param));
280 	if (!bcn->rx_data) {
281 		status = QDF_STATUS_E_NOMEM;
282 		goto free;
283 	}
284 
285 	if (frm_type == MGMT_PROBE_RESP)
286 		bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP;
287 	else
288 		bcn->frm_type = MGMT_SUBTYPE_BEACON;
289 
290 	/* Check if the beacon/probe frame can be posted in the scan queue */
291 	status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size);
292 	if (!QDF_IS_STATUS_SUCCESS(status) ||
293 	    scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) {
294 		scm_debug_rl("Dropping beacon/probe frame, queue size %d",
295 			     scan_queue_size);
296 		status = QDF_STATUS_E_FAILURE;
297 		goto free;
298 	}
299 
300 	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID);
301 	if (QDF_IS_STATUS_ERROR(status)) {
302 		scm_info("unable to get reference");
303 		goto free;
304 	}
305 
306 	bcn->psoc = psoc;
307 	bcn->buf = buf;
308 	qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param));
309 
310 	msg.bodyptr = bcn;
311 	msg.callback = scm_handle_bcn_probe;
312 	msg.flush_callback = scm_bcn_probe_flush_callback;
313 
314 	status = scheduler_post_message(QDF_MODULE_ID_SCAN,
315 					QDF_MODULE_ID_SCAN,
316 					QDF_MODULE_ID_SCAN, &msg);
317 
318 	if (QDF_IS_STATUS_SUCCESS(status))
319 		return status;
320 
321 	wlan_objmgr_psoc_release_ref(psoc, WLAN_SCAN_ID);
322 
323 free:
324 	if (bcn && bcn->rx_data)
325 		qdf_mem_free(bcn->rx_data);
326 	if (bcn)
327 		qdf_mem_free(bcn);
328 	if (buf)
329 		qdf_nbuf_free(buf);
330 
331 	return status;
332 }
333 
334 QDF_STATUS
335 tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc,
336 		uint32_t max_active_scans)
337 {
338 	struct scan_default_params *scan_params = NULL;
339 
340 	if (!psoc) {
341 		scm_err("null psoc");
342 		return QDF_STATUS_E_NULL_VALUE;
343 	}
344 
345 	scan_params = wlan_scan_psoc_get_def_params(psoc);
346 	if (!scan_params) {
347 		scm_err("wlan_scan_psoc_get_def_params returned NULL");
348 		return QDF_STATUS_E_NULL_VALUE;
349 	}
350 
351 	scan_params->max_active_scans_allowed = max_active_scans;
352 
353 	return QDF_STATUS_SUCCESS;
354 }
355