1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * DOC: contains scan south bound interface definitions
22  */
23 
24 #include <wlan_cmn.h>
25 #include <qdf_list.h>
26 #include "../../core/src/wlan_scan_main.h"
27 #include <wlan_scan_utils_api.h>
28 #include <wlan_scan_ucfg_api.h>
29 #include <wlan_scan_tgt_api.h>
30 #include <wlan_objmgr_cmn.h>
31 #include <wlan_lmac_if_def.h>
32 #include <wlan_objmgr_psoc_obj.h>
33 #include <wlan_objmgr_pdev_obj.h>
34 #include <wlan_objmgr_vdev_obj.h>
35 #include <../../core/src/wlan_scan_manager.h>
36 
37 static inline struct wlan_lmac_if_scan_tx_ops *
wlan_psoc_get_scan_txops(struct wlan_objmgr_psoc * psoc)38 wlan_psoc_get_scan_txops(struct wlan_objmgr_psoc *psoc)
39 {
40 	struct wlan_lmac_if_tx_ops *tx_ops;
41 
42 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
43 	if (!tx_ops) {
44 		scm_err("tx_ops is NULL");
45 		return NULL;
46 	}
47 
48 	return &tx_ops->scan;
49 }
50 
51 static inline struct wlan_lmac_if_scan_tx_ops *
wlan_vdev_get_scan_txops(struct wlan_objmgr_vdev * vdev)52 wlan_vdev_get_scan_txops(struct wlan_objmgr_vdev *vdev)
53 {
54 	struct wlan_objmgr_psoc *psoc = NULL;
55 
56 	psoc = wlan_vdev_get_psoc(vdev);
57 	if (!psoc) {
58 		scm_err("NULL psoc");
59 		return NULL;
60 	}
61 
62 	return wlan_psoc_get_scan_txops(psoc);
63 }
64 
65 static inline struct wlan_lmac_if_scan_rx_ops *
wlan_vdev_get_scan_rxops(struct wlan_objmgr_vdev * vdev)66 wlan_vdev_get_scan_rxops(struct wlan_objmgr_vdev *vdev)
67 {
68 	struct wlan_objmgr_psoc *psoc = NULL;
69 	struct wlan_lmac_if_rx_ops *rx_ops;
70 
71 	psoc = wlan_vdev_get_psoc(vdev);
72 	if (!psoc) {
73 		scm_err("NULL psoc");
74 		return NULL;
75 	}
76 
77 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
78 	if (!rx_ops) {
79 		scm_err("rx_ops is NULL");
80 		return NULL;
81 	}
82 
83 	return &rx_ops->scan;
84 }
85 
86 #ifdef FEATURE_WLAN_SCAN_PNO
87 
tgt_scan_pno_start(struct wlan_objmgr_vdev * vdev,struct pno_scan_req_params * req)88 QDF_STATUS tgt_scan_pno_start(struct wlan_objmgr_vdev *vdev,
89 	struct pno_scan_req_params *req)
90 {
91 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
92 	struct wlan_objmgr_psoc *psoc;
93 
94 	psoc = wlan_vdev_get_psoc(vdev);
95 
96 	if (!psoc) {
97 		scm_err("NULL PSOC");
98 		return QDF_STATUS_E_FAILURE;
99 	}
100 	scan_ops = wlan_psoc_get_scan_txops(psoc);
101 	if (!scan_ops) {
102 		scm_err("NULL scan_ops");
103 		return QDF_STATUS_E_FAILURE;
104 	}
105 	/* invoke wmi_unified_pno_start_cmd() */
106 	QDF_ASSERT(scan_ops->pno_start);
107 	if (scan_ops->pno_start)
108 		return scan_ops->pno_start(psoc, req);
109 
110 	return QDF_STATUS_SUCCESS;
111 }
112 
tgt_scan_pno_stop(struct wlan_objmgr_vdev * vdev,uint8_t vdev_id)113 QDF_STATUS tgt_scan_pno_stop(struct wlan_objmgr_vdev *vdev,
114 	uint8_t vdev_id)
115 {
116 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
117 	struct wlan_objmgr_psoc *psoc;
118 
119 	psoc = wlan_vdev_get_psoc(vdev);
120 
121 	if (!psoc) {
122 		scm_err("NULL PSOC");
123 		return QDF_STATUS_E_FAILURE;
124 	}
125 	scan_ops = wlan_psoc_get_scan_txops(psoc);
126 	if (!scan_ops) {
127 		scm_err("NULL scan_ops");
128 		return QDF_STATUS_E_FAILURE;
129 	}
130 	/* invoke wmi_unified_pno_stop_cmd() */
131 	QDF_ASSERT(scan_ops->pno_stop);
132 	if (scan_ops->pno_stop)
133 		return scan_ops->pno_stop(psoc, vdev_id);
134 
135 	return QDF_STATUS_SUCCESS;
136 }
137 #endif
138 
tgt_scan_obss_disable(struct wlan_objmgr_vdev * vdev)139 QDF_STATUS tgt_scan_obss_disable(struct wlan_objmgr_vdev *vdev)
140 {
141 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
142 	struct wlan_objmgr_psoc *psoc;
143 	uint8_t vdev_id;
144 
145 	psoc = wlan_vdev_get_psoc(vdev);
146 
147 	if (!psoc) {
148 		scm_err("NULL PSOC");
149 		return QDF_STATUS_E_FAILURE;
150 	}
151 	scan_ops = wlan_psoc_get_scan_txops(psoc);
152 	if (!scan_ops) {
153 		scm_err("NULL scan_ops");
154 		return QDF_STATUS_E_FAILURE;
155 	}
156 
157 	vdev_id = wlan_vdev_get_id(vdev);
158 
159 	/* invoke wmi_unified_obss_disable_cmd() */
160 	QDF_ASSERT(scan_ops->obss_disable);
161 	if (scan_ops->obss_disable)
162 		return scan_ops->obss_disable(psoc, vdev_id);
163 
164 	return QDF_STATUS_SUCCESS;
165 }
166 
167 QDF_STATUS
tgt_scan_start(struct scan_start_request * req)168 tgt_scan_start(struct scan_start_request *req)
169 {
170 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
171 	struct wlan_objmgr_psoc *psoc;
172 	struct wlan_objmgr_pdev *pdev;
173 	struct wlan_objmgr_vdev *vdev = req->vdev;
174 
175 	if (!vdev) {
176 		scm_err("vdev is NULL");
177 		return QDF_STATUS_E_NULL_VALUE;
178 	}
179 
180 	psoc = wlan_vdev_get_psoc(vdev);
181 	pdev = wlan_vdev_get_pdev(vdev);
182 	if (!psoc || !pdev) {
183 		scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev);
184 		return QDF_STATUS_E_NULL_VALUE;
185 	}
186 
187 	scan_ops = wlan_psoc_get_scan_txops(psoc);
188 	if (!scan_ops) {
189 		scm_err("NULL scan_ops");
190 		return QDF_STATUS_E_NULL_VALUE;
191 	}
192 
193 	/* invoke wmi_unified_scan_start_cmd_send() */
194 	QDF_ASSERT(scan_ops->scan_start);
195 	if (scan_ops->scan_start)
196 		return scan_ops->scan_start(pdev, req);
197 	else
198 		return QDF_STATUS_SUCCESS;
199 }
200 
201 
202 QDF_STATUS
tgt_scan_cancel(struct scan_cancel_request * req)203 tgt_scan_cancel(struct scan_cancel_request *req)
204 {
205 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
206 	struct wlan_objmgr_psoc *psoc;
207 	struct wlan_objmgr_pdev *pdev;
208 	struct wlan_objmgr_vdev *vdev = req->vdev;
209 
210 	if (!vdev) {
211 		scm_err("vdev is NULL");
212 		return QDF_STATUS_E_NULL_VALUE;
213 	}
214 	psoc = wlan_vdev_get_psoc(vdev);
215 	pdev = wlan_vdev_get_pdev(vdev);
216 	if (!psoc || !pdev) {
217 		scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev);
218 		return QDF_STATUS_E_NULL_VALUE;
219 	}
220 	scan_ops = wlan_psoc_get_scan_txops(psoc);
221 	if (!scan_ops) {
222 		scm_err("NULL scan_ops");
223 		return QDF_STATUS_E_NULL_VALUE;
224 	}
225 
226 	/* invoke wmi_unified_scan_stop_cmd_send() */
227 	QDF_ASSERT(scan_ops->scan_cancel);
228 	if (scan_ops->scan_cancel)
229 		return scan_ops->scan_cancel(pdev, &req->cancel_req);
230 	else
231 		return QDF_STATUS_SUCCESS;
232 }
233 
234 QDF_STATUS
tgt_scan_register_ev_handler(struct wlan_objmgr_psoc * psoc)235 tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc)
236 {
237 	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
238 
239 	scan_ops = wlan_psoc_get_scan_txops(psoc);
240 	if (!scan_ops) {
241 		scm_err("NULL scan_ops");
242 		return QDF_STATUS_E_FAILURE;
243 	}
244 
245 	/* invoke wmi_unified_register_event_handler()
246 	 * since event id, handler function and context is
247 	 * already known to offload lmac, passing NULL as argument.
248 	 * DA can pass necessary arguments by clubing then into
249 	 * some structure.
250 	 */
251 	QDF_ASSERT(scan_ops->scan_reg_ev_handler);
252 	if (scan_ops->scan_reg_ev_handler)
253 		return scan_ops->scan_reg_ev_handler(psoc, NULL);
254 	else
255 		return QDF_STATUS_SUCCESS;
256 }
257 
258 QDF_STATUS
tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc * psoc)259 tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc)
260 {
261 	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
262 
263 	scan_ops = wlan_psoc_get_scan_txops(psoc);
264 	if (!scan_ops) {
265 		scm_err("NULL scan_ops");
266 		return QDF_STATUS_E_FAILURE;
267 	}
268 
269 	/* invoke wmi_unified_register_event_handler()
270 	 * since event id, handler function and context is
271 	 * already known to offload lmac, passing NULL as argument.
272 	 * DA can pass necessary arguments by clubing then into
273 	 * some structure.
274 	 */
275 	QDF_ASSERT(scan_ops->scan_unreg_ev_handler);
276 	if (scan_ops->scan_unreg_ev_handler)
277 		return scan_ops->scan_unreg_ev_handler(psoc, NULL);
278 	else
279 		return QDF_STATUS_SUCCESS;
280 }
281 
282 QDF_STATUS
tgt_scan_event_handler(struct wlan_objmgr_psoc * psoc,struct scan_event_info * event_info)283 tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc,
284 		struct scan_event_info *event_info)
285 {
286 	struct scheduler_msg msg = {0};
287 	struct scan_event *event = &event_info->event;
288 	uint8_t vdev_id = event->vdev_id;
289 	QDF_STATUS status;
290 
291 	if (!psoc || !event_info) {
292 		scm_err("psoc: 0x%pK, event_info: 0x%pK", psoc, event_info);
293 		return QDF_STATUS_E_NULL_VALUE;
294 	}
295 
296 	event_info->vdev =
297 		wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
298 				vdev_id, WLAN_SCAN_ID);
299 	if (!event_info->vdev) {
300 		scm_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc);
301 		return QDF_STATUS_E_INVAL;
302 	}
303 	msg.bodyptr = event_info;
304 	msg.callback = scm_scan_event_handler;
305 	msg.flush_callback = scm_scan_event_flush_callback;
306 
307 	status = scheduler_post_message(QDF_MODULE_ID_SCAN,
308 					QDF_MODULE_ID_SCAN,
309 					QDF_MODULE_ID_SCAN, &msg);
310 	if (QDF_IS_STATUS_ERROR(status)) {
311 		wlan_objmgr_vdev_release_ref(event_info->vdev, WLAN_SCAN_ID);
312 	}
313 
314 	return status;
315 }
316 
tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_peer * peer,qdf_nbuf_t buf,struct mgmt_rx_event_params * rx_param,enum mgmt_frame_type frm_type)317 QDF_STATUS tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc *psoc,
318 	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
319 	struct mgmt_rx_event_params *rx_param,
320 	enum mgmt_frame_type frm_type)
321 {
322 	struct scheduler_msg msg = {0};
323 	struct scan_bcn_probe_event *bcn = NULL;
324 	QDF_STATUS status;
325 	uint32_t scan_queue_size = 0;
326 
327 	if ((frm_type != MGMT_PROBE_RESP) &&
328 	    (frm_type != MGMT_BEACON)) {
329 		scm_err("frame is not beacon or probe resp");
330 		status = QDF_STATUS_E_INVAL;
331 		goto free;
332 	}
333 
334 	bcn = qdf_mem_malloc_atomic(sizeof(*bcn));
335 	if (!bcn) {
336 		status = QDF_STATUS_E_NOMEM;
337 		goto free;
338 	}
339 	bcn->rx_data =
340 		qdf_mem_malloc_atomic(sizeof(*rx_param));
341 	if (!bcn->rx_data) {
342 		status = QDF_STATUS_E_NOMEM;
343 		goto free;
344 	}
345 
346 	if (frm_type == MGMT_PROBE_RESP)
347 		bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP;
348 	else
349 		bcn->frm_type = MGMT_SUBTYPE_BEACON;
350 
351 	/* Check if the beacon/probe frame can be posted in the scan queue */
352 	status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size);
353 	if (!QDF_IS_STATUS_SUCCESS(status) ||
354 	    scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) {
355 		scm_debug_rl("Dropping beacon/probe frame, queue size %d",
356 			     scan_queue_size);
357 		status = QDF_STATUS_E_FAILURE;
358 		goto free;
359 	}
360 
361 	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID);
362 	if (QDF_IS_STATUS_ERROR(status)) {
363 		scm_info("unable to get reference");
364 		goto free;
365 	}
366 
367 	bcn->psoc = psoc;
368 	bcn->buf = buf;
369 	bcn->save_rnr_info = false;
370 	qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param));
371 
372 	msg.bodyptr = bcn;
373 	msg.callback = scm_handle_bcn_probe;
374 	msg.flush_callback = scm_bcn_probe_flush_callback;
375 
376 	status = scheduler_post_message(QDF_MODULE_ID_SCAN,
377 					QDF_MODULE_ID_SCAN,
378 					QDF_MODULE_ID_SCAN, &msg);
379 
380 	if (QDF_IS_STATUS_SUCCESS(status))
381 		return status;
382 
383 	wlan_objmgr_psoc_release_ref(psoc, WLAN_SCAN_ID);
384 
385 free:
386 	if (bcn && bcn->rx_data)
387 		qdf_mem_free(bcn->rx_data);
388 	if (bcn)
389 		qdf_mem_free(bcn);
390 	if (buf)
391 		qdf_nbuf_free(buf);
392 
393 	return status;
394 }
395 
396 QDF_STATUS
tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc * psoc,uint32_t max_active_scans)397 tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc,
398 		uint32_t max_active_scans)
399 {
400 	struct scan_default_params *scan_params = NULL;
401 
402 	if (!psoc) {
403 		scm_err("null psoc");
404 		return QDF_STATUS_E_NULL_VALUE;
405 	}
406 
407 	scan_params = wlan_scan_psoc_get_def_params(psoc);
408 	if (!scan_params) {
409 		scm_err("wlan_scan_psoc_get_def_params returned NULL");
410 		return QDF_STATUS_E_NULL_VALUE;
411 	}
412 
413 	scan_params->max_active_scans_allowed = max_active_scans;
414 
415 	return QDF_STATUS_SUCCESS;
416 }
417