xref: /wlan-dirver/qca-wifi-host-cmn/umac/scan/dispatcher/src/wlan_scan_tgt_api.c (revision a86b23ee68a2491aede2e03991f3fb37046f4e41)
1 /*
2  * Copyright (c) 2017-2020 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
139 tgt_scan_start(struct scan_start_request *req)
140 {
141 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
142 	struct wlan_objmgr_psoc *psoc;
143 	struct wlan_objmgr_pdev *pdev;
144 	struct wlan_objmgr_vdev *vdev = req->vdev;
145 
146 	if (!vdev) {
147 		scm_err("vdev is NULL");
148 		return QDF_STATUS_E_NULL_VALUE;
149 	}
150 
151 	psoc = wlan_vdev_get_psoc(vdev);
152 	pdev = wlan_vdev_get_pdev(vdev);
153 	if (!psoc || !pdev) {
154 		scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev);
155 		return QDF_STATUS_E_NULL_VALUE;
156 	}
157 
158 	scan_ops = wlan_psoc_get_scan_txops(psoc);
159 	if (!scan_ops) {
160 		scm_err("NULL scan_ops");
161 		return QDF_STATUS_E_NULL_VALUE;
162 	}
163 
164 	/* invoke wmi_unified_scan_start_cmd_send() */
165 	QDF_ASSERT(scan_ops->scan_start);
166 	if (scan_ops->scan_start)
167 		return scan_ops->scan_start(pdev, req);
168 	else
169 		return QDF_STATUS_SUCCESS;
170 }
171 
172 
173 QDF_STATUS
174 tgt_scan_cancel(struct scan_cancel_request *req)
175 {
176 	struct wlan_lmac_if_scan_tx_ops *scan_ops;
177 	struct wlan_objmgr_psoc *psoc;
178 	struct wlan_objmgr_pdev *pdev;
179 	struct wlan_objmgr_vdev *vdev = req->vdev;
180 
181 	if (!vdev) {
182 		scm_err("vdev is NULL");
183 		return QDF_STATUS_E_NULL_VALUE;
184 	}
185 	psoc = wlan_vdev_get_psoc(vdev);
186 	pdev = wlan_vdev_get_pdev(vdev);
187 	if (!psoc || !pdev) {
188 		scm_err("psoc: 0x%pK or pdev: 0x%pK is NULL", psoc, pdev);
189 		return QDF_STATUS_E_NULL_VALUE;
190 	}
191 	scan_ops = wlan_psoc_get_scan_txops(psoc);
192 	if (!scan_ops) {
193 		scm_err("NULL scan_ops");
194 		return QDF_STATUS_E_NULL_VALUE;
195 	}
196 
197 	/* invoke wmi_unified_scan_stop_cmd_send() */
198 	QDF_ASSERT(scan_ops->scan_cancel);
199 	if (scan_ops->scan_cancel)
200 		return scan_ops->scan_cancel(pdev, &req->cancel_req);
201 	else
202 		return QDF_STATUS_SUCCESS;
203 }
204 
205 QDF_STATUS
206 tgt_scan_register_ev_handler(struct wlan_objmgr_psoc *psoc)
207 {
208 	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
209 
210 	scan_ops = wlan_psoc_get_scan_txops(psoc);
211 	if (!scan_ops) {
212 		scm_err("NULL scan_ops");
213 		return QDF_STATUS_E_FAILURE;
214 	}
215 
216 	/* invoke wmi_unified_register_event_handler()
217 	 * since event id, handler function and context is
218 	 * already known to offload lmac, passing NULL as argument.
219 	 * DA can pass necessary arguments by clubing then into
220 	 * some structure.
221 	 */
222 	QDF_ASSERT(scan_ops->scan_reg_ev_handler);
223 	if (scan_ops->scan_reg_ev_handler)
224 		return scan_ops->scan_reg_ev_handler(psoc, NULL);
225 	else
226 		return QDF_STATUS_SUCCESS;
227 }
228 
229 QDF_STATUS
230 tgt_scan_unregister_ev_handler(struct wlan_objmgr_psoc *psoc)
231 {
232 	struct wlan_lmac_if_scan_tx_ops *scan_ops = NULL;
233 
234 	scan_ops = wlan_psoc_get_scan_txops(psoc);
235 	if (!scan_ops) {
236 		scm_err("NULL scan_ops");
237 		return QDF_STATUS_E_FAILURE;
238 	}
239 
240 	/* invoke wmi_unified_register_event_handler()
241 	 * since event id, handler function and context is
242 	 * already known to offload lmac, passing NULL as argument.
243 	 * DA can pass necessary arguments by clubing then into
244 	 * some structure.
245 	 */
246 	QDF_ASSERT(scan_ops->scan_unreg_ev_handler);
247 	if (scan_ops->scan_unreg_ev_handler)
248 		return scan_ops->scan_unreg_ev_handler(psoc, NULL);
249 	else
250 		return QDF_STATUS_SUCCESS;
251 }
252 
253 QDF_STATUS
254 tgt_scan_event_handler(struct wlan_objmgr_psoc *psoc,
255 		struct scan_event_info *event_info)
256 {
257 	struct scheduler_msg msg = {0};
258 	struct scan_event *event = &event_info->event;
259 	uint8_t vdev_id = event->vdev_id;
260 	QDF_STATUS status;
261 
262 	if (!psoc || !event_info) {
263 		scm_err("psoc: 0x%pK, event_info: 0x%pK", psoc, event_info);
264 		return QDF_STATUS_E_NULL_VALUE;
265 	}
266 
267 	event_info->vdev =
268 		wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
269 				vdev_id, WLAN_SCAN_ID);
270 	if (!event_info->vdev) {
271 		scm_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc);
272 		return QDF_STATUS_E_INVAL;
273 	}
274 	msg.bodyptr = event_info;
275 	msg.callback = scm_scan_event_handler;
276 	msg.flush_callback = scm_scan_event_flush_callback;
277 
278 	status = scheduler_post_message(QDF_MODULE_ID_SCAN,
279 					QDF_MODULE_ID_SCAN,
280 					QDF_MODULE_ID_SCAN, &msg);
281 	if (QDF_IS_STATUS_ERROR(status)) {
282 		wlan_objmgr_vdev_release_ref(event_info->vdev, WLAN_SCAN_ID);
283 	}
284 
285 	return status;
286 }
287 
288 QDF_STATUS tgt_scan_bcn_probe_rx_callback(struct wlan_objmgr_psoc *psoc,
289 	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
290 	struct mgmt_rx_event_params *rx_param,
291 	enum mgmt_frame_type frm_type)
292 {
293 	struct scheduler_msg msg = {0};
294 	struct scan_bcn_probe_event *bcn = NULL;
295 	QDF_STATUS status;
296 	uint32_t scan_queue_size = 0;
297 
298 	if ((frm_type != MGMT_PROBE_RESP) &&
299 	    (frm_type != MGMT_BEACON)) {
300 		scm_err("frame is not beacon or probe resp");
301 		status = QDF_STATUS_E_INVAL;
302 		goto free;
303 	}
304 
305 	bcn = qdf_mem_malloc_atomic(sizeof(*bcn));
306 	if (!bcn) {
307 		status = QDF_STATUS_E_NOMEM;
308 		goto free;
309 	}
310 	bcn->rx_data =
311 		qdf_mem_malloc_atomic(sizeof(*rx_param));
312 	if (!bcn->rx_data) {
313 		status = QDF_STATUS_E_NOMEM;
314 		goto free;
315 	}
316 
317 	if (frm_type == MGMT_PROBE_RESP)
318 		bcn->frm_type = MGMT_SUBTYPE_PROBE_RESP;
319 	else
320 		bcn->frm_type = MGMT_SUBTYPE_BEACON;
321 
322 	/* Check if the beacon/probe frame can be posted in the scan queue */
323 	status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size);
324 	if (!QDF_IS_STATUS_SUCCESS(status) ||
325 	    scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) {
326 		scm_debug_rl("Dropping beacon/probe frame, queue size %d",
327 			     scan_queue_size);
328 		status = QDF_STATUS_E_FAILURE;
329 		goto free;
330 	}
331 
332 	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_SCAN_ID);
333 	if (QDF_IS_STATUS_ERROR(status)) {
334 		scm_info("unable to get reference");
335 		goto free;
336 	}
337 
338 	bcn->psoc = psoc;
339 	bcn->buf = buf;
340 	qdf_mem_copy(bcn->rx_data, rx_param, sizeof(*rx_param));
341 
342 	msg.bodyptr = bcn;
343 	msg.callback = scm_handle_bcn_probe;
344 	msg.flush_callback = scm_bcn_probe_flush_callback;
345 
346 	status = scheduler_post_message(QDF_MODULE_ID_SCAN,
347 					QDF_MODULE_ID_SCAN,
348 					QDF_MODULE_ID_SCAN, &msg);
349 
350 	if (QDF_IS_STATUS_SUCCESS(status))
351 		return status;
352 
353 	wlan_objmgr_psoc_release_ref(psoc, WLAN_SCAN_ID);
354 
355 free:
356 	if (bcn && bcn->rx_data)
357 		qdf_mem_free(bcn->rx_data);
358 	if (bcn)
359 		qdf_mem_free(bcn);
360 	if (buf)
361 		qdf_nbuf_free(buf);
362 
363 	return status;
364 }
365 
366 QDF_STATUS
367 tgt_scan_set_max_active_scans(struct wlan_objmgr_psoc *psoc,
368 		uint32_t max_active_scans)
369 {
370 	struct scan_default_params *scan_params = NULL;
371 
372 	if (!psoc) {
373 		scm_err("null psoc");
374 		return QDF_STATUS_E_NULL_VALUE;
375 	}
376 
377 	scan_params = wlan_scan_psoc_get_def_params(psoc);
378 	if (!scan_params) {
379 		scm_err("wlan_scan_psoc_get_def_params returned NULL");
380 		return QDF_STATUS_E_NULL_VALUE;
381 	}
382 
383 	scan_params->max_active_scans_allowed = max_active_scans;
384 
385 	return QDF_STATUS_SUCCESS;
386 }
387