1 /*
2  * Copyright (c) 2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 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: Target interface file for pkt_capture component to
22  * Implement api's which shall be used by pkt_capture component
23  * in target_if internally.
24  */
25 
26 #include <target_if_pkt_capture.h>
27 #include <wlan_pkt_capture_tgt_api.h>
28 #include <wmi_unified_api.h>
29 #include <target_if.h>
30 #include <init_deinit_lmac.h>
31 #include <wlan_pkt_capture_api.h>
32 
33 /**
34  * target_if_set_packet_capture_mode() - set packet capture mode
35  * @psoc: pointer to psoc object
36  * @vdev_id: vdev id
37  * @mode: mode to set
38  *
39  * Return: QDF_STATUS
40  */
41 static QDF_STATUS
target_if_set_packet_capture_mode(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum pkt_capture_mode mode)42 target_if_set_packet_capture_mode(struct wlan_objmgr_psoc *psoc,
43 				  uint8_t vdev_id,
44 				  enum pkt_capture_mode mode)
45 {
46 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
47 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
48 	struct vdev_set_params param;
49 
50 	if (!wmi_handle) {
51 		target_if_err("Invalid wmi handle");
52 		return QDF_STATUS_E_INVAL;
53 	}
54 
55 	target_if_debug("psoc:%pK, vdev_id:%d mode:%d",
56 			psoc, vdev_id, mode);
57 
58 	param.vdev_id = vdev_id;
59 	param.param_id = wmi_vdev_param_packet_capture_mode;
60 	param.param_value = (uint32_t)mode;
61 
62 	status = wmi_unified_vdev_set_param_send(wmi_handle, &param);
63 	if (QDF_IS_STATUS_SUCCESS(status))
64 		ucfg_pkt_capture_set_pktcap_mode(psoc, mode);
65 	else
66 		pkt_capture_err("failed to set packet capture mode");
67 
68 	return status;
69 }
70 
71 #ifdef WLAN_FEATURE_PKT_CAPTURE_V2
72 /**
73  * target_if_set_packet_capture_config() - set packet capture config
74  * @psoc: pointer to psoc object
75  * @vdev_id: vdev id
76  * @config_value: config value
77  *
78  * Return: QDF_STATUS
79  */
80 static QDF_STATUS
target_if_set_packet_capture_config(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum pkt_capture_config config_value)81 target_if_set_packet_capture_config
82 			(struct wlan_objmgr_psoc *psoc,
83 			 uint8_t vdev_id,
84 			 enum pkt_capture_config config_value)
85 {
86 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
87 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
88 	struct wlan_objmgr_vdev *vdev;
89 	struct vdev_set_params param;
90 
91 	if (!wmi_handle) {
92 		target_if_err("Invalid wmi handle");
93 		return QDF_STATUS_E_INVAL;
94 	}
95 
96 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
97 						    WLAN_PKT_CAPTURE_ID);
98 	if (!vdev) {
99 		pkt_capture_err("vdev is NULL");
100 		return QDF_STATUS_E_INVAL;
101 	}
102 
103 	target_if_debug("psoc:%pK, vdev_id:%d config_value:%d",
104 			psoc, vdev_id, config_value);
105 
106 	param.vdev_id = vdev_id;
107 	param.param_id = wmi_vdev_param_smart_monitor_config;
108 	param.param_value = (uint32_t)config_value;
109 
110 	status = wmi_unified_vdev_set_param_send(wmi_handle, &param);
111 	if (QDF_IS_STATUS_SUCCESS(status))
112 		ucfg_pkt_capture_set_pktcap_config(vdev, config_value);
113 	else
114 		pkt_capture_err("failed to set packet capture config");
115 
116 	wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID);
117 	return status;
118 }
119 #else
120 static QDF_STATUS
target_if_set_packet_capture_config(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum pkt_capture_config config_value)121 target_if_set_packet_capture_config
122 			(struct wlan_objmgr_psoc *psoc,
123 			 uint8_t vdev_id,
124 			 enum pkt_capture_config config_value)
125 {
126 	return QDF_STATUS_SUCCESS;
127 }
128 #endif
129 
130 /**
131  * target_if_set_packet_capture_beacon_interval() - set packet capture beacon
132  * interval
133  * @psoc: pointer to psoc object
134  * @vdev_id: vdev id
135  * @nth_value: Beacon report period
136  *
137  * Return: QDF_STATUS
138  */
139 static QDF_STATUS
target_if_set_packet_capture_beacon_interval(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint32_t nth_value)140 target_if_set_packet_capture_beacon_interval
141 			(struct wlan_objmgr_psoc *psoc,
142 			 uint8_t vdev_id,
143 			 uint32_t nth_value)
144 {
145 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
146 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
147 	struct vdev_set_params param;
148 
149 	if (!wmi_handle) {
150 		target_if_err("Invalid wmi handle");
151 		return QDF_STATUS_E_INVAL;
152 	}
153 
154 	target_if_debug("psoc:%pK, vdev_id:%d nth_value:%d",
155 			psoc, vdev_id, nth_value);
156 
157 	param.vdev_id = vdev_id;
158 	param.param_id = wmi_vdev_param_nth_beacon_to_host;
159 	param.param_value = nth_value;
160 
161 	status = wmi_unified_vdev_set_param_send(wmi_handle, &param);
162 	if (QDF_IS_STATUS_ERROR(status))
163 		pkt_capture_err("failed to set beacon interval");
164 
165 	return status;
166 }
167 
168 /**
169  * target_if_mgmt_offload_data_event_handler() - offload event handler
170  * @handle: scn handle
171  * @data: mgmt data
172  * @data_len: data length
173  *
174  * Process management offload frame.
175  *
176  * Return: 0 for success or error code
177  */
178 static int
target_if_mgmt_offload_data_event_handler(void * handle,uint8_t * data,uint32_t data_len)179 target_if_mgmt_offload_data_event_handler(void *handle, uint8_t *data,
180 					  uint32_t data_len)
181 {
182 	static uint8_t limit_prints_invalid_len = RATE_LIMIT - 1;
183 	struct mgmt_offload_event_params params;
184 	struct wmi_unified *wmi_handle;
185 	struct wlan_objmgr_psoc *psoc;
186 	struct wlan_objmgr_pdev *pdev;
187 	QDF_STATUS status;
188 	qdf_nbuf_t wbuf;
189 
190 	psoc = target_if_get_psoc_from_scn_hdl(handle);
191 	if (!psoc) {
192 		pkt_capture_err("psoc is NULL");
193 		return -EINVAL;
194 	}
195 
196 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
197 	if (!wmi_handle) {
198 		target_if_err("Invalid WMI handle");
199 		return -EINVAL;
200 	}
201 
202 	pdev = target_if_get_pdev_from_scn_hdl(handle);
203 	if (!pdev) {
204 		pkt_capture_err("pdev is NULL");
205 		return -EINVAL;
206 	}
207 
208 	if (!(wlan_pkt_capture_is_tx_mgmt_enable(pdev)))
209 		return -EINVAL;
210 
211 	status = wmi_unified_extract_vdev_mgmt_offload_event(wmi_handle, data,
212 							     &params);
213 	if (QDF_IS_STATUS_ERROR(status)) {
214 		pkt_capture_err("Extract mgmt offload event failed");
215 		return -EINVAL;
216 	}
217 
218 	if (!params.buf) {
219 		pkt_capture_err("Mgmt offload buf is NULL");
220 		return -EINVAL;
221 	}
222 
223 	if (params.buf_len < sizeof(struct ieee80211_hdr_3addr) ||
224 	    params.buf_len > data_len) {
225 		limit_prints_invalid_len++;
226 		if (limit_prints_invalid_len == RATE_LIMIT) {
227 			pkt_capture_debug(
228 			"Invalid mgmt packet, data_len %u, params.buf_len %u",
229 			data_len, params.buf_len);
230 			limit_prints_invalid_len = 0;
231 		}
232 		return -EINVAL;
233 	}
234 
235 	wbuf = qdf_nbuf_alloc(NULL,
236 			      roundup(params.buf_len + RESERVE_BYTES, 4),
237 			      RESERVE_BYTES, 4, false);
238 	if (!wbuf) {
239 		pkt_capture_err("Failed to allocate wbuf for mgmt pkt len(%u)",
240 				params.buf_len);
241 		return -ENOMEM;
242 	}
243 
244 	qdf_nbuf_put_tail(wbuf, params.buf_len);
245 	qdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL);
246 	qdf_mem_copy(qdf_nbuf_data(wbuf), params.buf, params.buf_len);
247 
248 	status = params.tx_status;
249 	if (QDF_STATUS_SUCCESS !=
250 		ucfg_pkt_capture_process_mgmt_tx_data(pdev, &params,
251 						      wbuf, status))
252 		qdf_nbuf_free(wbuf);
253 
254 	return 0;
255 }
256 
257 /**
258  * target_if_register_mgmt_data_offload_event() - Register mgmt data offload
259  * event handler
260  * @psoc: wlan psoc object
261  *
262  * Return: QDF_STATUS
263  */
264 static QDF_STATUS
target_if_register_mgmt_data_offload_event(struct wlan_objmgr_psoc * psoc)265 target_if_register_mgmt_data_offload_event(struct wlan_objmgr_psoc *psoc)
266 {
267 	wmi_unified_t wmi_handle;
268 
269 	PKT_CAPTURE_ENTER();
270 
271 	if (!psoc) {
272 		pkt_capture_err("psoc got NULL");
273 		return QDF_STATUS_E_FAILURE;
274 	}
275 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
276 
277 	if (!wmi_handle) {
278 		pkt_capture_err("wmi_handle is NULL");
279 		return QDF_STATUS_E_FAILURE;
280 	}
281 
282 	if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) &&
283 	    wmi_service_enabled(wmi_handle,
284 				wmi_service_packet_capture_support)) {
285 		QDF_STATUS status;
286 
287 		status = wmi_unified_register_event_handler(
288 				wmi_handle,
289 				wmi_mgmt_offload_data_event_id,
290 				target_if_mgmt_offload_data_event_handler,
291 				WMI_RX_WORK_CTX);
292 		if (QDF_IS_STATUS_ERROR(status)) {
293 			pkt_capture_err("Failed to register MGMT offload handler");
294 			return QDF_STATUS_E_FAILURE;
295 		}
296 	}
297 
298 	PKT_CAPTURE_EXIT();
299 
300 	return QDF_STATUS_SUCCESS;
301 }
302 
303 /**
304  * target_if_unregister_mgmt_data_offload_event() - Unregister mgmt data offload
305  * event handler
306  * @psoc: wlan psoc object
307  *
308  * Return: QDF_STATUS
309  */
310 static QDF_STATUS
target_if_unregister_mgmt_data_offload_event(struct wlan_objmgr_psoc * psoc)311 target_if_unregister_mgmt_data_offload_event(struct wlan_objmgr_psoc *psoc)
312 {
313 	wmi_unified_t wmi_handle;
314 	QDF_STATUS status;
315 
316 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
317 	if (!wmi_handle) {
318 		pkt_capture_err("Invalid wmi handle");
319 		return QDF_STATUS_E_INVAL;
320 	}
321 
322 	status = wmi_unified_unregister_event(wmi_handle,
323 					      wmi_mgmt_offload_data_event_id);
324 	if (status)
325 		pkt_capture_err("unregister mgmt data offload event cb failed");
326 
327 	return status;
328 }
329 
330 #ifdef WLAN_FEATURE_PKT_CAPTURE_V2
331 static int
target_if_smart_monitor_event_handler(void * handle,uint8_t * data,uint32_t len)332 target_if_smart_monitor_event_handler(void *handle, uint8_t *data,
333 				      uint32_t len)
334 {
335 	struct smu_event_params params;
336 	struct wmi_unified *wmi_handle;
337 	struct wlan_objmgr_psoc *psoc;
338 	QDF_STATUS status;
339 
340 	psoc = target_if_get_psoc_from_scn_hdl(handle);
341 	if (!psoc) {
342 		pkt_capture_err("psoc is NULL");
343 		return -EINVAL;
344 	}
345 
346 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
347 	if (!wmi_handle) {
348 		target_if_err("Invalid WMI handle");
349 		return -EINVAL;
350 	}
351 
352 	if (!(ucfg_pkt_capture_get_pktcap_mode(psoc) &
353 	      PKT_CAPTURE_MODE_MGMT_ONLY))
354 		return -EINVAL;
355 
356 	status = wmi_unified_extract_smart_monitor_event(wmi_handle, data,
357 							 &params);
358 	if (QDF_IS_STATUS_ERROR(status)) {
359 		pkt_capture_err("Extract smart monitor event failed");
360 		return -EINVAL;
361 	}
362 
363 	tgt_pkt_capture_smu_event(psoc, &params);
364 	return 0;
365 }
366 
367 /**
368  * target_if_register_smart_monitor_event() - Register smu event
369  * @psoc: wlan psoc object
370  *
371  * Return: QDF_STATUS
372  */
373 static QDF_STATUS
target_if_register_smart_monitor_event(struct wlan_objmgr_psoc * psoc)374 target_if_register_smart_monitor_event(struct wlan_objmgr_psoc *psoc)
375 {
376 	wmi_unified_t wmi_handle;
377 
378 	if (!psoc) {
379 		pkt_capture_err("psoc got NULL");
380 		return QDF_STATUS_E_FAILURE;
381 	}
382 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
383 
384 	if (!wmi_handle) {
385 		pkt_capture_err("wmi_handle is NULL");
386 		return QDF_STATUS_E_FAILURE;
387 	}
388 
389 	if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) &&
390 	    wmi_service_enabled(wmi_handle,
391 				wmi_service_packet_capture_support)) {
392 		uint8_t status;
393 
394 		status = wmi_unified_register_event_handler(
395 				wmi_handle,
396 				wmi_vdev_smart_monitor_event_id,
397 				target_if_smart_monitor_event_handler,
398 				WMI_RX_WORK_CTX);
399 		if (status) {
400 			pkt_capture_err("Failed to register smart monitor handler");
401 			return QDF_STATUS_E_FAILURE;
402 		}
403 	}
404 
405 	return QDF_STATUS_SUCCESS;
406 }
407 
408 /**
409  * target_if_unregister_smart_monitor_event() - Unregister smu event
410  * @psoc: wlan psoc object
411  *
412  * Return: QDF_STATUS
413  */
414 static QDF_STATUS
target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc * psoc)415 target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc *psoc)
416 {
417 	wmi_unified_t wmi_handle;
418 	QDF_STATUS status;
419 
420 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
421 	if (!wmi_handle) {
422 		pkt_capture_err("Invalid wmi handle");
423 		return QDF_STATUS_E_INVAL;
424 	}
425 
426 	status = wmi_unified_unregister_event(wmi_handle,
427 					      wmi_vdev_smart_monitor_event_id);
428 	if (status)
429 		pkt_capture_err("unregister smart monitor event handler failed");
430 
431 	return status;
432 }
433 #else
434 static QDF_STATUS
target_if_register_smart_monitor_event(struct wlan_objmgr_psoc * psoc)435 target_if_register_smart_monitor_event(struct wlan_objmgr_psoc *psoc)
436 {
437 	return QDF_STATUS_SUCCESS;
438 }
439 
440 static QDF_STATUS
target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc * psoc)441 target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc *psoc)
442 {
443 	return QDF_STATUS_SUCCESS;
444 }
445 #endif
446 void
target_if_pkt_capture_register_rx_ops(struct wlan_pkt_capture_rx_ops * rx_ops)447 target_if_pkt_capture_register_rx_ops(struct wlan_pkt_capture_rx_ops *rx_ops)
448 {
449 	if (!rx_ops) {
450 		target_if_err("packet capture rx_ops is null");
451 		return;
452 	}
453 
454 	rx_ops->pkt_capture_register_ev_handlers =
455 				target_if_register_mgmt_data_offload_event;
456 
457 	rx_ops->pkt_capture_unregister_ev_handlers =
458 				target_if_unregister_mgmt_data_offload_event;
459 
460 	rx_ops->pkt_capture_register_smart_monitor_event =
461 				target_if_register_smart_monitor_event;
462 
463 	rx_ops->pkt_capture_unregister_smart_monitor_event =
464 				target_if_unregister_smart_monitor_event;
465 }
466 
467 void
target_if_pkt_capture_register_tx_ops(struct wlan_pkt_capture_tx_ops * tx_ops)468 target_if_pkt_capture_register_tx_ops(struct wlan_pkt_capture_tx_ops *tx_ops)
469 {
470 	if (!tx_ops) {
471 		target_if_err("packet capture tx_ops is null");
472 		return;
473 	}
474 
475 	tx_ops->pkt_capture_send_mode = target_if_set_packet_capture_mode;
476 	tx_ops->pkt_capture_send_config = target_if_set_packet_capture_config;
477 	tx_ops->pkt_capture_send_beacon_interval =
478 				target_if_set_packet_capture_beacon_interval;
479 }
480