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