xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/dispatcher/src/wlan_scan_tgt_api.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
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