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, ¶m);
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, ¶m);
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, ¶m);
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 ¶ms);
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, ¶ms,
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 ¶ms);
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, ¶ms);
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