1 /* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Changes from Qualcomm Innovation Center are provided under the following license:
29 *
30 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted (subject to the limitations in the
34 * disclaimer below) provided that the following conditions are met:
35 *
36 * * Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 *
39 * * Redistributions in binary form must reproduce the above
40 * copyright notice, this list of conditions and the following
41 * disclaimer in the documentation and/or other materials provided
42 * with the distribution.
43 *
44 * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
45 * contributors may be used to endorse or promote products derived
46 * from this software without specific prior written permission.
47 *
48 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
49 * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
50 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
51 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
54 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
56 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
58 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
59 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
60 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 */
62
63 #include "sync.h"
64
65 #include <hardware_legacy/wifi_hal.h>
66 #include "common.h"
67 #include "cpp_bindings.h"
68 #include <errno.h>
69 #include <utils/Log.h>
70 #include "wifiloggercmd.h"
71 #include "rb_wrapper.h"
72 #include <stdlib.h>
73
74 #define LOGGER_MEMDUMP_FILENAME "/proc/debug/fwdump"
75 #define DRIVER_MEMDUMP_FILENAME "/proc/debugdriver/driverdump"
76 #define LOGGER_MEMDUMP_CHUNKSIZE (4 * 1024)
77 #define DRIVER_MEMDUMP_MAX_FILESIZE (16 * 1024)
78
79 char power_events_ring_name[] = "power_events_rb";
80 char connectivity_events_ring_name[] = "connectivity_events_rb";
81 char pkt_stats_ring_name[] = "pkt_stats_rb";
82 char driver_prints_ring_name[] = "driver_prints_rb";
83 char firmware_prints_ring_name[] = "firmware_prints_rb";
84
get_ring_id(hal_info * info,char * ring_name)85 static int get_ring_id(hal_info *info, char *ring_name)
86 {
87 int rb_id;
88
89 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
90 if (is_rb_name_match(&info->rb_infos[rb_id], ring_name)) {
91 return rb_id;
92 }
93 }
94 return -1;
95 }
96
97 //Implementation of the functions exposed in wifi_logger.h
98
99 /* Function to intiate logging */
wifi_start_logging(wifi_interface_handle iface,u32 verbose_level,u32 flags,u32 max_interval_sec,u32 min_data_size,char * buffer_name)100 wifi_error wifi_start_logging(wifi_interface_handle iface,
101 u32 verbose_level, u32 flags,
102 u32 max_interval_sec, u32 min_data_size,
103 char *buffer_name)
104 {
105 int requestId;
106 wifi_error ret;
107 WifiLoggerCommand *wifiLoggerCommand = NULL;
108 struct nlattr *nlData;
109 interface_info *ifaceInfo = getIfaceInfo(iface);
110 wifi_handle wifiHandle = getWifiHandle(iface);
111 hal_info *info = getHalInfo(wifiHandle);
112 int ring_id = 0;
113
114 /* Check Supported logger capability */
115 if (!(info->supported_logger_feature_set & LOGGER_RING_BUFFER)) {
116 ALOGE("%s: Ring buffer logging feature not supported %x", __FUNCTION__,
117 info->supported_logger_feature_set);
118 return WIFI_ERROR_NOT_SUPPORTED;
119 }
120 /*
121 * No request id from caller, so generate one and pass it on to the driver.
122 * Generate one randomly.
123 */
124 requestId = get_requestid();
125
126 if (buffer_name == NULL) {
127 ALOGE("%s: Invalid Ring Name. \n", __FUNCTION__);
128 return WIFI_ERROR_UNKNOWN;
129 }
130
131 ring_id = get_ring_id(info, buffer_name);
132 if (ring_id < 0) {
133 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__);
134 return WIFI_ERROR_UNKNOWN;
135 }
136
137 wifiLoggerCommand = new WifiLoggerCommand(
138 wifiHandle,
139 requestId,
140 OUI_QCA,
141 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START);
142
143 if (wifiLoggerCommand == NULL) {
144 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
145 return WIFI_ERROR_UNKNOWN;
146 }
147 /* Create the NL message. */
148 ret = wifiLoggerCommand->create();
149 if (ret != WIFI_SUCCESS)
150 goto cleanup;
151
152 /* Set the interface Id of the message. */
153 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
154 if (ret != WIFI_SUCCESS)
155 goto cleanup;
156
157 /* Add the vendor specific attributes for the NL command. */
158 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
159 if (!nlData){
160 ret = WIFI_ERROR_UNKNOWN;
161 goto cleanup;
162 }
163
164 ret = wifiLoggerCommand->put_u32(QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID,
165 ring_id);
166 if (ret != WIFI_SUCCESS)
167 goto cleanup;
168
169 ret = wifiLoggerCommand->put_u32(
170 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL,
171 verbose_level);
172 if (ret != WIFI_SUCCESS)
173 goto cleanup;
174
175 ret = wifiLoggerCommand->put_u32(QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS,
176 flags);
177 if (ret != WIFI_SUCCESS)
178 goto cleanup;
179
180 wifiLoggerCommand->attr_end(nlData);
181
182 /* Send the msg and wait for a response. */
183 ret = wifiLoggerCommand->requestResponse();
184 if (ret != WIFI_SUCCESS)
185 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
186
187 ALOGV("%s: Logging Started for %s. with verboselevel %d",
188 __FUNCTION__, buffer_name,verbose_level);
189 rb_start_logging(&info->rb_infos[ring_id], verbose_level,
190 flags, max_interval_sec, min_data_size);
191 cleanup:
192 delete wifiLoggerCommand;
193 return ret;
194 }
195
196 /* Function to get each ring related info */
wifi_get_ring_buffers_status(wifi_interface_handle iface,u32 * num_buffers,wifi_ring_buffer_status * status)197 wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface,
198 u32 *num_buffers,
199 wifi_ring_buffer_status *status)
200 {
201 wifi_handle wifiHandle = getWifiHandle(iface);
202 hal_info *info = getHalInfo(wifiHandle);
203 wifi_ring_buffer_status *rbs;
204 struct rb_info *rb_info;
205 int rb_id;
206
207 /* Check Supported logger capability */
208 if (!(info->supported_logger_feature_set & LOGGER_RING_BUFFER)) {
209 ALOGE("%s: Ring buffer logging feature not supported %x", __FUNCTION__,
210 info->supported_logger_feature_set);
211 return WIFI_ERROR_NOT_SUPPORTED;
212 }
213
214 if ((*num_buffers) < NUM_RING_BUFS) {
215 ALOGE("%s: Input num_buffers:%u cannot be accommodated, "
216 "Total ring buffer num:%d", __FUNCTION__, *num_buffers,
217 NUM_RING_BUFS);
218 *num_buffers = 0;
219 return WIFI_ERROR_OUT_OF_MEMORY;
220 }
221 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
222 rb_info = &info->rb_infos[rb_id];
223 rbs = status + rb_id;
224
225 get_rb_status(rb_info, rbs);
226 }
227 *num_buffers = NUM_RING_BUFS;
228 return WIFI_SUCCESS;
229 }
230
push_out_all_ring_buffers(hal_info * info)231 void push_out_all_ring_buffers(hal_info *info)
232 {
233 int rb_id;
234
235 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
236 push_out_rb_data(&info->rb_infos[rb_id]);
237 }
238 }
239
send_alert(hal_info * info,int reason_code)240 void send_alert(hal_info *info, int reason_code)
241 {
242 wifi_alert_handler handler;
243 char alert_msg[20] = "Fatal Event";
244 pthread_mutex_lock(&info->ah_lock);
245 handler.on_alert = info->on_alert;
246 pthread_mutex_unlock(&info->ah_lock);
247
248 if (handler.on_alert) {
249 handler.on_alert(0, alert_msg, strlen(alert_msg), reason_code);
250 }
251 }
252
setFeatureSet(u32 * support)253 void WifiLoggerCommand::setFeatureSet(u32 *support) {
254 mSupportedSet = support;
255 }
256
257 /* Function to get the supported feature set for logging.*/
wifi_get_logger_supported_feature_set(wifi_interface_handle iface,u32 * support)258 wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
259 u32 *support)
260 {
261 int requestId;
262 wifi_error ret;
263 WifiLoggerCommand *wifiLoggerCommand;
264 struct nlattr *nlData;
265 interface_info *ifaceInfo = getIfaceInfo(iface);
266 wifi_handle wifiHandle = getWifiHandle(iface);
267
268 /* No request id from caller, so generate one and pass it on to the driver.
269 * Generate one randomly.
270 */
271 requestId = get_requestid();
272
273 wifiLoggerCommand = new WifiLoggerCommand(
274 wifiHandle,
275 requestId,
276 OUI_QCA,
277 QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET);
278
279 if (wifiLoggerCommand == NULL) {
280 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
281 return WIFI_ERROR_UNKNOWN;
282 }
283 /* Create the NL message. */
284 ret = wifiLoggerCommand->create();
285 if (ret != WIFI_SUCCESS)
286 goto cleanup;
287
288 /* Set the interface Id of the message. */
289 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
290 if (ret != WIFI_SUCCESS)
291 goto cleanup;
292
293 /* Add the vendor specific attributes for the NL command. */
294 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
295 if (!nlData){
296 ret = WIFI_ERROR_UNKNOWN;
297 goto cleanup;
298 }
299
300 ret = wifiLoggerCommand->put_u32(QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED,
301 requestId);
302 if (ret != WIFI_SUCCESS)
303 goto cleanup;
304
305 wifiLoggerCommand->attr_end(nlData);
306
307 wifiLoggerCommand->setFeatureSet(support);
308
309 /* Send the msg and wait for a response. */
310 ret = wifiLoggerCommand->requestResponse();
311 if (ret != WIFI_SUCCESS)
312 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
313
314 cleanup:
315 delete wifiLoggerCommand;
316 return ret;
317 }
318
319 /* Function to get the data in each ring for the given ring ID.*/
wifi_get_ring_data(wifi_interface_handle iface,char * ring_name)320 wifi_error wifi_get_ring_data(wifi_interface_handle iface,
321 char *ring_name)
322 {
323 int requestId;
324 wifi_error ret;
325 WifiLoggerCommand *wifiLoggerCommand;
326 struct nlattr *nlData;
327 interface_info *ifaceInfo = getIfaceInfo(iface);
328 wifi_handle wifiHandle = getWifiHandle(iface);
329 hal_info *info = getHalInfo(wifiHandle);
330 int ring_id = 0;
331
332 /* Check Supported logger capability */
333 if (!(info->supported_logger_feature_set & LOGGER_RING_BUFFER)) {
334 ALOGE("%s: Ring buffer logging feature not supported %x", __FUNCTION__,
335 info->supported_logger_feature_set);
336 return WIFI_ERROR_NOT_SUPPORTED;
337 }
338
339 ring_id = get_ring_id(info, ring_name);
340 if (ring_id < 0) {
341 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__);
342 return WIFI_ERROR_UNKNOWN;
343 }
344
345 requestId = get_requestid();
346
347 wifiLoggerCommand = new WifiLoggerCommand(
348 wifiHandle,
349 requestId,
350 OUI_QCA,
351 QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA);
352 if (wifiLoggerCommand == NULL) {
353 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
354 return WIFI_ERROR_UNKNOWN;
355 }
356 /* Create the NL message. */
357 ret = wifiLoggerCommand->create();
358 if (ret != WIFI_SUCCESS)
359 goto cleanup;
360
361 /* Set the interface Id of the message. */
362 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
363 if (ret != WIFI_SUCCESS)
364 goto cleanup;
365
366 /* Add the vendor specific attributes for the NL command. */
367 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
368 if (!nlData){
369 ret = WIFI_ERROR_UNKNOWN;
370 goto cleanup;
371 }
372
373 if (wifiLoggerCommand->put_u32(
374 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID, ring_id))
375 {
376 ret = WIFI_ERROR_UNKNOWN;
377 goto cleanup;
378 }
379 wifiLoggerCommand->attr_end(nlData);
380
381 /* Send the msg and wait for a response. */
382 ret = wifiLoggerCommand->requestResponse();
383 if (ret != WIFI_SUCCESS)
384 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
385
386 cleanup:
387 delete wifiLoggerCommand;
388 return ret;
389 }
390
setVersionInfo(char * buffer,int buffer_size)391 void WifiLoggerCommand::setVersionInfo(char *buffer, int buffer_size) {
392 mVersion = buffer;
393 mVersionLen = buffer_size;
394 }
395
396 /* Function to send enable request to the wifi driver.*/
wifi_get_firmware_version(wifi_interface_handle iface,char * buffer,int buffer_size)397 wifi_error wifi_get_firmware_version(wifi_interface_handle iface,
398 char *buffer, int buffer_size)
399 {
400 int requestId;
401 wifi_error ret;
402 WifiLoggerCommand *wifiLoggerCommand;
403 struct nlattr *nlData;
404 interface_info *ifaceInfo = getIfaceInfo(iface);
405 wifi_handle wifiHandle = getWifiHandle(iface);
406
407 /* No request id from caller, so generate one and pass it on to the driver.
408 * Generate one randomly.
409 */
410 requestId = get_requestid_u8();
411
412 wifiLoggerCommand = new WifiLoggerCommand(
413 wifiHandle,
414 requestId,
415 OUI_QCA,
416 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO);
417 if (wifiLoggerCommand == NULL) {
418 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
419 return WIFI_ERROR_UNKNOWN;
420 }
421 /* Create the NL message. */
422 ret = wifiLoggerCommand->create();
423 if (ret != WIFI_SUCCESS)
424 goto cleanup;
425
426 /* Set the interface Id of the message. */
427 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
428 if (ret != WIFI_SUCCESS)
429 goto cleanup;
430
431 /* Add the vendor specific attributes for the NL command. */
432 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
433 if (!nlData)
434 goto cleanup;
435
436 ret = wifiLoggerCommand->put_u8(
437 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION, requestId);
438 if (ret != WIFI_SUCCESS)
439 goto cleanup;
440
441 wifiLoggerCommand->attr_end(nlData);
442
443 wifiLoggerCommand->setVersionInfo(buffer, buffer_size);
444
445 /* Send the msg and wait for a response. */
446 ret = wifiLoggerCommand->requestResponse();
447 if (ret != WIFI_SUCCESS)
448 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
449
450 cleanup:
451 delete wifiLoggerCommand;
452 return ret;
453
454 }
455
456 /* Function to get wlan driver version.*/
wifi_get_driver_version(wifi_interface_handle iface,char * buffer,int buffer_size)457 wifi_error wifi_get_driver_version(wifi_interface_handle iface,
458 char *buffer, int buffer_size)
459 {
460
461 int requestId;
462 wifi_error ret;
463 WifiLoggerCommand *wifiLoggerCommand;
464 struct nlattr *nlData;
465 interface_info *ifaceInfo = getIfaceInfo(iface);
466 wifi_handle wifiHandle = getWifiHandle(iface);
467
468 /* No request id from caller, so generate one and pass it on to the driver.
469 * Generate one randomly.
470 */
471 requestId = get_requestid_u8();
472
473 wifiLoggerCommand = new WifiLoggerCommand(
474 wifiHandle,
475 requestId,
476 OUI_QCA,
477 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO);
478 if (wifiLoggerCommand == NULL) {
479 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
480 return WIFI_ERROR_UNKNOWN;
481 }
482 /* Create the NL message. */
483 ret = wifiLoggerCommand->create();
484 if (ret != WIFI_SUCCESS)
485 goto cleanup;
486
487 /* Set the interface Id of the message. */
488 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
489 if (ret != WIFI_SUCCESS)
490 goto cleanup;
491
492 /* Add the vendor specific attributes for the NL command. */
493 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
494 if (!nlData){
495 ret = WIFI_ERROR_UNKNOWN;
496 goto cleanup;
497 }
498
499 ret = wifiLoggerCommand->put_u8(
500 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION, requestId);
501 if (ret != WIFI_SUCCESS)
502 goto cleanup;
503
504 wifiLoggerCommand->attr_end(nlData);
505
506 wifiLoggerCommand->setVersionInfo(buffer, buffer_size);
507
508 /* Send the msg and wait for a response. */
509 ret = wifiLoggerCommand->requestResponse();
510 if (ret != WIFI_SUCCESS)
511 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
512
513 cleanup:
514 delete wifiLoggerCommand;
515 return ret;
516 }
517
518
519 /* Function to get the Firmware memory dump. */
wifi_get_firmware_memory_dump(wifi_interface_handle iface,wifi_firmware_memory_dump_handler handler)520 wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
521 wifi_firmware_memory_dump_handler handler)
522 {
523 wifi_error ret;
524 int requestId;
525 WifiLoggerCommand *wifiLoggerCommand;
526 struct nlattr *nlData;
527 interface_info *ifaceInfo = getIfaceInfo(iface);
528 wifi_handle wifiHandle = getWifiHandle(iface);
529 hal_info *info = getHalInfo(wifiHandle);
530
531 /* Check Supported logger capability */
532 if (!(info->supported_logger_feature_set &
533 WIFI_LOGGER_MEMORY_DUMP_SUPPORTED)) {
534 ALOGE("%s: Firmware memory dump logging feature not supported %x",
535 __FUNCTION__, info->supported_logger_feature_set);
536 return WIFI_ERROR_NOT_SUPPORTED;
537 }
538
539 /* No request id from caller, so generate one and pass it on to the driver.
540 * Generate one randomly.
541 */
542 requestId = get_requestid();
543
544 wifiLoggerCommand = new WifiLoggerCommand(
545 wifiHandle,
546 requestId,
547 OUI_QCA,
548 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP);
549 if (wifiLoggerCommand == NULL) {
550 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
551 return WIFI_ERROR_UNKNOWN;
552 }
553 /* Create the NL message. */
554 ret = wifiLoggerCommand->create();
555
556 if (ret != WIFI_SUCCESS)
557 goto cleanup;
558
559 /* Set the interface Id of the message. */
560 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
561
562 if (ret != WIFI_SUCCESS)
563 goto cleanup;
564
565 /* Add the vendor specific attributes for the NL command. */
566 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
567 if (!nlData){
568 ret = WIFI_ERROR_UNKNOWN;
569 goto cleanup;
570 }
571
572 wifiLoggerCommand->attr_end(nlData);
573
574 /* copy the callback into callback handler */
575 WifiLoggerCallbackHandler callbackHandler;
576 memset(&callbackHandler, 0, sizeof(callbackHandler));
577 callbackHandler.on_firmware_memory_dump = \
578 handler.on_firmware_memory_dump;
579
580 ret = wifiLoggerCommand->setCallbackHandler(callbackHandler);
581 if (ret != WIFI_SUCCESS)
582 goto cleanup;
583
584 /* Send the msg and wait for the memory dump response */
585 ret = wifiLoggerCommand->requestResponse();
586 if (ret != WIFI_SUCCESS)
587 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
588
589 cleanup:
590 delete wifiLoggerCommand;
591 return ret;
592 }
593
wifi_set_log_handler(wifi_request_id id,wifi_interface_handle iface,wifi_ring_buffer_data_handler handler)594 wifi_error wifi_set_log_handler(wifi_request_id id,
595 wifi_interface_handle iface,
596 wifi_ring_buffer_data_handler handler)
597 {
598 wifi_handle wifiHandle = getWifiHandle(iface);
599 hal_info *info = getHalInfo(wifiHandle);
600
601 pthread_mutex_lock(&info->lh_lock);
602 info->on_ring_buffer_data = handler.on_ring_buffer_data;
603 pthread_mutex_unlock(&info->lh_lock);
604 if (handler.on_ring_buffer_data == NULL) {
605 ALOGE("Set log handler is NULL");
606 return WIFI_ERROR_UNKNOWN;
607 }
608 return WIFI_SUCCESS;
609 }
610
wifi_reset_log_handler(wifi_request_id id,wifi_interface_handle iface)611 wifi_error wifi_reset_log_handler(wifi_request_id id,
612 wifi_interface_handle iface)
613 {
614 wifi_handle wifiHandle = getWifiHandle(iface);
615 hal_info *info = getHalInfo(wifiHandle);
616
617 pthread_mutex_lock(&info->lh_lock);
618 info->on_ring_buffer_data = NULL;
619 pthread_mutex_unlock(&info->lh_lock);
620 return WIFI_SUCCESS;
621 }
622
wifi_set_alert_handler(wifi_request_id id,wifi_interface_handle iface,wifi_alert_handler handler)623 wifi_error wifi_set_alert_handler(wifi_request_id id,
624 wifi_interface_handle iface,
625 wifi_alert_handler handler)
626 {
627 wifi_handle wifiHandle = getWifiHandle(iface);
628 hal_info *info = getHalInfo(wifiHandle);
629
630 if (handler.on_alert == NULL) {
631 ALOGE("Set alert handler is NULL");
632 return WIFI_ERROR_UNKNOWN;
633 }
634 pthread_mutex_lock(&info->ah_lock);
635 info->on_alert = handler.on_alert;
636 pthread_mutex_unlock(&info->ah_lock);
637 return WIFI_SUCCESS;
638 }
639
wifi_reset_alert_handler(wifi_request_id id,wifi_interface_handle iface)640 wifi_error wifi_reset_alert_handler(wifi_request_id id,
641 wifi_interface_handle iface)
642 {
643 wifi_handle wifiHandle = getWifiHandle(iface);
644 hal_info *info = getHalInfo(wifiHandle);
645
646 pthread_mutex_lock(&info->ah_lock);
647 info->on_alert = NULL;
648 pthread_mutex_unlock(&info->ah_lock);
649 return WIFI_SUCCESS;
650 }
651
652
653 /**
654 API to start packet fate monitoring.
655 - Once stared, monitoring should remain active until HAL is unloaded.
656 - When HAL is unloaded, all packet fate buffers should be cleared.
657 */
wifi_start_pkt_fate_monitoring(wifi_interface_handle iface)658 wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle iface)
659 {
660 wifi_handle wifiHandle = getWifiHandle(iface);
661 hal_info *info = getHalInfo(wifiHandle);
662
663 /* Check Supported logger capability */
664 if (!(info->supported_logger_feature_set &
665 WIFI_LOGGER_PACKET_FATE_SUPPORTED)) {
666 ALOGE("%s: packet fate logging feature not supported %x",
667 __FUNCTION__, info->supported_logger_feature_set);
668 return WIFI_ERROR_NOT_SUPPORTED;
669 }
670
671 if (info->fate_monitoring_enabled == true) {
672 ALOGV("Packet monitoring is already enabled");
673 return WIFI_SUCCESS;
674 }
675
676 info->pkt_fate_stats = (packet_fate_monitor_info *) malloc (
677 sizeof(packet_fate_monitor_info));
678 if (info->pkt_fate_stats == NULL) {
679 ALOGE("Failed to allocate memory for : %zu bytes",
680 sizeof(packet_fate_monitor_info));
681 return WIFI_ERROR_OUT_OF_MEMORY;
682 }
683 memset(info->pkt_fate_stats, 0, sizeof(packet_fate_monitor_info));
684
685 pthread_mutex_lock(&info->pkt_fate_stats_lock);
686 info->fate_monitoring_enabled = true;
687 pthread_mutex_unlock(&info->pkt_fate_stats_lock);
688
689 return WIFI_SUCCESS;
690 }
691
692
693 /**
694 API to retrieve fates of outbound packets.
695 - HAL implementation should fill |tx_report_bufs| with fates of
696 _first_ min(n_requested_fates, actual packets) frames
697 transmitted for the most recent association. The fate reports
698 should follow the same order as their respective packets.
699 - Packets reported by firmware, but not recognized by driver
700 should be included. However, the ordering of the corresponding
701 reports is at the discretion of HAL implementation.
702 - Framework may call this API multiple times for the same association.
703 - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
704 - Framework will allocate and free the referenced storage.
705 */
wifi_get_tx_pkt_fates(wifi_interface_handle iface,wifi_tx_report * tx_report_bufs,size_t n_requested_fates,size_t * n_provided_fates)706 wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle iface,
707 wifi_tx_report *tx_report_bufs,
708 size_t n_requested_fates,
709 size_t *n_provided_fates)
710 {
711 wifi_handle wifiHandle = getWifiHandle(iface);
712 hal_info *info = getHalInfo(wifiHandle);
713 wifi_tx_report_i *tx_fate_stats;
714 size_t i;
715
716 if (info->fate_monitoring_enabled != true) {
717 ALOGE("Packet monitoring is not yet triggered");
718 return WIFI_ERROR_UNINITIALIZED;
719 }
720 pthread_mutex_lock(&info->pkt_fate_stats_lock);
721
722 tx_fate_stats = &info->pkt_fate_stats->tx_fate_stats[0];
723
724 *n_provided_fates = min(n_requested_fates,
725 info->pkt_fate_stats->n_tx_stats_collected);
726
727 for (i=0; i < *n_provided_fates; i++) {
728 memcpy(tx_report_bufs[i].md5_prefix,
729 tx_fate_stats[i].md5_prefix, MD5_PREFIX_LEN);
730 tx_report_bufs[i].fate = tx_fate_stats[i].fate;
731 tx_report_bufs[i].frame_inf.payload_type =
732 tx_fate_stats[i].frame_inf.payload_type;
733 tx_report_bufs[i].frame_inf.driver_timestamp_usec =
734 tx_fate_stats[i].frame_inf.driver_timestamp_usec;
735 tx_report_bufs[i].frame_inf.firmware_timestamp_usec =
736 tx_fate_stats[i].frame_inf.firmware_timestamp_usec;
737 tx_report_bufs[i].frame_inf.frame_len =
738 tx_fate_stats[i].frame_inf.frame_len;
739
740 if (tx_report_bufs[i].frame_inf.payload_type == FRAME_TYPE_ETHERNET_II)
741 memcpy(tx_report_bufs[i].frame_inf.frame_content.ethernet_ii_bytes,
742 tx_fate_stats[i].frame_inf.frame_content,
743 min(tx_fate_stats[i].frame_inf.frame_len,
744 MAX_FRAME_LEN_ETHERNET));
745 else if (tx_report_bufs[i].frame_inf.payload_type ==
746 FRAME_TYPE_80211_MGMT)
747 memcpy(
748 tx_report_bufs[i].frame_inf.frame_content.ieee_80211_mgmt_bytes,
749 tx_fate_stats[i].frame_inf.frame_content,
750 min(tx_fate_stats[i].frame_inf.frame_len,
751 MAX_FRAME_LEN_80211_MGMT));
752 else
753 /* Currently framework is interested only two types(
754 * FRAME_TYPE_ETHERNET_II and FRAME_TYPE_80211_MGMT) of packets, so
755 * ignore the all other types of packets received from driver */
756 ALOGI("Unknown format packet");
757 }
758 pthread_mutex_unlock(&info->pkt_fate_stats_lock);
759
760 return WIFI_SUCCESS;
761 }
762
763 /**
764 API to retrieve fates of inbound packets.
765 - HAL implementation should fill |rx_report_bufs| with fates of
766 _first_ min(n_requested_fates, actual packets) frames
767 received for the most recent association. The fate reports
768 should follow the same order as their respective packets.
769 - Packets reported by firmware, but not recognized by driver
770 should be included. However, the ordering of the corresponding
771 reports is at the discretion of HAL implementation.
772 - Framework may call this API multiple times for the same association.
773 - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
774 - Framework will allocate and free the referenced storage.
775 */
wifi_get_rx_pkt_fates(wifi_interface_handle iface,wifi_rx_report * rx_report_bufs,size_t n_requested_fates,size_t * n_provided_fates)776 wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle iface,
777 wifi_rx_report *rx_report_bufs,
778 size_t n_requested_fates,
779 size_t *n_provided_fates)
780 {
781 wifi_handle wifiHandle = getWifiHandle(iface);
782 hal_info *info = getHalInfo(wifiHandle);
783 wifi_rx_report_i *rx_fate_stats;
784 size_t i;
785
786 if (info->fate_monitoring_enabled != true) {
787 ALOGE("Packet monitoring is not yet triggered");
788 return WIFI_ERROR_UNINITIALIZED;
789 }
790 pthread_mutex_lock(&info->pkt_fate_stats_lock);
791
792 rx_fate_stats = &info->pkt_fate_stats->rx_fate_stats[0];
793
794 *n_provided_fates = min(n_requested_fates,
795 info->pkt_fate_stats->n_rx_stats_collected);
796
797 for (i=0; i < *n_provided_fates; i++) {
798 memcpy(rx_report_bufs[i].md5_prefix,
799 rx_fate_stats[i].md5_prefix, MD5_PREFIX_LEN);
800 rx_report_bufs[i].fate = rx_fate_stats[i].fate;
801 rx_report_bufs[i].frame_inf.payload_type =
802 rx_fate_stats[i].frame_inf.payload_type;
803 rx_report_bufs[i].frame_inf.driver_timestamp_usec =
804 rx_fate_stats[i].frame_inf.driver_timestamp_usec;
805 rx_report_bufs[i].frame_inf.firmware_timestamp_usec =
806 rx_fate_stats[i].frame_inf.firmware_timestamp_usec;
807 rx_report_bufs[i].frame_inf.frame_len =
808 rx_fate_stats[i].frame_inf.frame_len;
809
810 if (rx_report_bufs[i].frame_inf.payload_type == FRAME_TYPE_ETHERNET_II)
811 memcpy(rx_report_bufs[i].frame_inf.frame_content.ethernet_ii_bytes,
812 rx_fate_stats[i].frame_inf.frame_content,
813 min(rx_fate_stats[i].frame_inf.frame_len,
814 MAX_FRAME_LEN_ETHERNET));
815 else if (rx_report_bufs[i].frame_inf.payload_type ==
816 FRAME_TYPE_80211_MGMT)
817 memcpy(
818 rx_report_bufs[i].frame_inf.frame_content.ieee_80211_mgmt_bytes,
819 rx_fate_stats[i].frame_inf.frame_content,
820 min(rx_fate_stats[i].frame_inf.frame_len,
821 MAX_FRAME_LEN_80211_MGMT));
822 else
823 /* Currently framework is interested only two types(
824 * FRAME_TYPE_ETHERNET_II and FRAME_TYPE_80211_MGMT) of packets, so
825 * ignore the all other types of packets received from driver */
826 ALOGI("Unknown format packet");
827 }
828 pthread_mutex_unlock(&info->pkt_fate_stats_lock);
829
830 return WIFI_SUCCESS;
831 }
832
WifiLoggerCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)833 WifiLoggerCommand::WifiLoggerCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
834 : WifiVendorCommand(handle, id, vendor_id, subcmd)
835 {
836 mVersion = NULL;
837 mVersionLen = 0;
838 mRequestId = id;
839 memset(&mHandler, 0,sizeof(mHandler));
840 mWaitforRsp = false;
841 mMoreData = false;
842 mSupportedSet = NULL;
843 }
844
~WifiLoggerCommand()845 WifiLoggerCommand::~WifiLoggerCommand()
846 {
847 unregisterVendorHandler(mVendor_id, mSubcmd);
848 }
849
850 /* This function implements creation of Vendor command */
create()851 wifi_error WifiLoggerCommand::create() {
852 wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
853 if (ret != WIFI_SUCCESS)
854 return ret;
855
856 /* Insert the oui in the msg */
857 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
858 if (ret != WIFI_SUCCESS)
859 goto out;
860 /* Insert the subcmd in the msg */
861 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
862 if (ret != WIFI_SUCCESS)
863 goto out;
864
865 ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
866 __FUNCTION__, mVendor_id, mSubcmd);
867
868 out:
869 return ret;
870 }
871
rb_timerhandler(hal_info * info)872 void rb_timerhandler(hal_info *info)
873 {
874 struct timeval now;
875 int rb_id;
876
877 gettimeofday(&now,NULL);
878 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
879 rb_check_for_timeout(&info->rb_infos[rb_id], &now);
880 }
881 }
882
wifi_logger_ring_buffers_init(hal_info * info)883 wifi_error wifi_logger_ring_buffers_init(hal_info *info)
884 {
885 wifi_error ret;
886
887 /* Check Supported logger capability */
888 if (!(info->supported_logger_feature_set & LOGGER_RING_BUFFER)) {
889 ALOGE("%s: Ring buffer logging feature not supported %x", __FUNCTION__,
890 info->supported_logger_feature_set);
891 return WIFI_ERROR_NOT_SUPPORTED;
892 }
893
894 ret = rb_init(info, &info->rb_infos[POWER_EVENTS_RB_ID],
895 POWER_EVENTS_RB_ID,
896 POWER_EVENTS_RB_BUF_SIZE,
897 POWER_EVENTS_NUM_BUFS,
898 power_events_ring_name);
899 if (ret != WIFI_SUCCESS) {
900 ALOGE("Failed to initialize power events ring buffer");
901 goto cleanup;
902 }
903
904 ret = rb_init(info, &info->rb_infos[CONNECTIVITY_EVENTS_RB_ID],
905 CONNECTIVITY_EVENTS_RB_ID,
906 CONNECTIVITY_EVENTS_RB_BUF_SIZE,
907 CONNECTIVITY_EVENTS_NUM_BUFS,
908 connectivity_events_ring_name);
909 if (ret != WIFI_SUCCESS) {
910 ALOGE("Failed to initialize connectivity events ring buffer");
911 goto cleanup;
912 }
913
914 ret = rb_init(info, &info->rb_infos[PKT_STATS_RB_ID],
915 PKT_STATS_RB_ID,
916 PKT_STATS_RB_BUF_SIZE,
917 PKT_STATS_NUM_BUFS,
918 pkt_stats_ring_name);
919 if (ret != WIFI_SUCCESS) {
920 ALOGE("Failed to initialize per packet stats ring buffer");
921 goto cleanup;
922 }
923
924 ret = rb_init(info, &info->rb_infos[DRIVER_PRINTS_RB_ID],
925 DRIVER_PRINTS_RB_ID,
926 DRIVER_PRINTS_RB_BUF_SIZE,
927 DRIVER_PRINTS_NUM_BUFS,
928 driver_prints_ring_name);
929 if (ret != WIFI_SUCCESS) {
930 ALOGE("Failed to initialize driver prints ring buffer");
931 goto cleanup;
932 }
933
934 ret = rb_init(info, &info->rb_infos[FIRMWARE_PRINTS_RB_ID],
935 FIRMWARE_PRINTS_RB_ID,
936 FIRMWARE_PRINTS_RB_BUF_SIZE,
937 FIRMWARE_PRINTS_NUM_BUFS,
938 firmware_prints_ring_name);
939 if (ret != WIFI_SUCCESS) {
940 ALOGE("Failed to initialize firmware prints ring buffer");
941 goto cleanup;
942 }
943
944 pthread_mutex_init(&info->lh_lock, NULL);
945 pthread_mutex_init(&info->ah_lock, NULL);
946
947 return ret;
948
949 cleanup:
950 wifi_logger_ring_buffers_deinit(info);
951 return ret;
952 }
953
wifi_logger_ring_buffers_deinit(hal_info * info)954 void wifi_logger_ring_buffers_deinit(hal_info *info)
955 {
956 int i;
957
958 if (!(info->supported_logger_feature_set & LOGGER_RING_BUFFER))
959 return;
960
961 for (i = 0; i < NUM_RING_BUFS; i++) {
962 rb_deinit(&info->rb_infos[i]);
963 }
964 pthread_mutex_destroy(&info->lh_lock);
965 pthread_mutex_destroy(&info->ah_lock);
966 }
967
968
969 /* Callback handlers registered for nl message send */
error_handler_wifi_logger(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)970 static int error_handler_wifi_logger(struct sockaddr_nl *nla,
971 struct nlmsgerr *err,
972 void *arg)
973 {
974 struct sockaddr_nl *tmp;
975 int *ret = (int *)arg;
976 tmp = nla;
977 *ret = err->error;
978 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
979 return NL_STOP;
980 }
981
982 /* Callback handlers registered for nl message send */
ack_handler_wifi_logger(struct nl_msg * msg,void * arg)983 static int ack_handler_wifi_logger(struct nl_msg *msg, void *arg)
984 {
985 int *ret = (int *)arg;
986 struct nl_msg * a;
987
988 a = msg;
989 *ret = 0;
990 return NL_STOP;
991 }
992
993 /* Callback handlers registered for nl message send */
finish_handler_wifi_logger(struct nl_msg * msg,void * arg)994 static int finish_handler_wifi_logger(struct nl_msg *msg, void *arg)
995 {
996 int *ret = (int *)arg;
997 struct nl_msg * a;
998
999 a = msg;
1000 *ret = 0;
1001 return NL_SKIP;
1002 }
1003
requestEvent()1004 wifi_error WifiLoggerCommand::requestEvent()
1005 {
1006 int status;
1007 wifi_error res = WIFI_SUCCESS;
1008 struct nl_cb *cb = NULL;
1009
1010 cb = nl_cb_alloc(NL_CB_DEFAULT);
1011 if (!cb) {
1012 ALOGE("%s: Callback allocation failed",__FUNCTION__);
1013 res = WIFI_ERROR_OUT_OF_MEMORY;
1014 goto out;
1015 }
1016
1017 /* Send message */
1018 status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
1019 if (status < 0) {
1020 res = mapKernelErrortoWifiHalError(status);
1021 goto out;
1022 }
1023
1024 status = 1;
1025
1026 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_logger, &status);
1027 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_logger, &status);
1028 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_logger, &status);
1029
1030 /* Err is populated as part of finish_handler. */
1031 while (status > 0){
1032 nl_recvmsgs(mInfo->cmd_sock, cb);
1033 }
1034
1035 ALOGV("%s: Msg sent, status=%d, mWaitForRsp=%d", __FUNCTION__, status, mWaitforRsp);
1036 /* Only wait for the asynchronous event if HDD returns success, res=0 */
1037 if (!status && (mWaitforRsp == true)) {
1038 struct timespec abstime;
1039 abstime.tv_sec = 4;
1040 abstime.tv_nsec = 0;
1041 res = mCondition.wait(abstime);
1042 if (res == WIFI_ERROR_TIMED_OUT)
1043 ALOGE("%s: Time out happened.", __FUNCTION__);
1044
1045 ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
1046 __FUNCTION__, res, mWaitforRsp);
1047 }
1048 out:
1049 nl_cb_put(cb);
1050 /* Cleanup the mMsg */
1051 mMsg.destroy();
1052 return res;
1053 }
1054
requestResponse()1055 wifi_error WifiLoggerCommand::requestResponse()
1056 {
1057 return WifiCommand::requestResponse(mMsg);
1058 }
1059
handleResponse(WifiEvent & reply)1060 int WifiLoggerCommand::handleResponse(WifiEvent &reply) {
1061 int len = 0, version;
1062 char version_type[20];
1063 char* memBuffer = NULL;
1064 FILE* memDumpFilePtr = NULL;
1065 WifiVendorCommand::handleResponse(reply);
1066
1067 memset(version_type, 0, 20);
1068 switch(mSubcmd)
1069 {
1070 case QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO:
1071 {
1072 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1];
1073
1074 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX,
1075 (struct nlattr *)mVendorData, mDataLen, NULL);
1076
1077 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) {
1078 len = nla_len(tb_vendor[
1079 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]);
1080 memcpy(version_type, "Driver", strlen("Driver"));
1081 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION;
1082 } else if (
1083 tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) {
1084 len = nla_len(
1085 tb_vendor[
1086 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]);
1087 memcpy(version_type, "Firmware", strlen("Firmware"));
1088 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION;
1089 }
1090 if (len && mVersion && mVersionLen) {
1091 memset(mVersion, 0, mVersionLen);
1092 /* if len is greater than the incoming length then
1093 accommodate 1 lesser than mVersionLen to have the
1094 string terminated with '\0' */
1095 len = (len > mVersionLen)? (mVersionLen - 1) : len;
1096 memcpy(mVersion, nla_data(tb_vendor[version]), len);
1097 ALOGV("%s: WLAN %s version : %s ", __FUNCTION__,
1098 version_type, mVersion);
1099 }
1100 }
1101 break;
1102 case QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET:
1103 {
1104 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LOGGER_MAX + 1];
1105
1106 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LOGGER_MAX,
1107 (struct nlattr *)mVendorData, mDataLen, NULL);
1108
1109 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED]) {
1110 *mSupportedSet =
1111 nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED]);
1112 #ifdef QC_HAL_DEBUG
1113 ALOGV("%s: Supported Feature Set : val 0x%x",
1114 __FUNCTION__, *mSupportedSet);
1115 #endif
1116 }
1117 }
1118 break;
1119
1120 case QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP:
1121 {
1122 u32 memDumpSize = 0;
1123 int numRecordsRead = 0;
1124 u32 remaining = 0;
1125 char* buffer = NULL;
1126 struct nlattr *tbVendor[
1127 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX + 1];
1128
1129 nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX,
1130 (struct nlattr *)mVendorData,
1131 mDataLen, NULL);
1132
1133 if (!tbVendor[
1134 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE]) {
1135 ALOGE("%s: LOGGER_RESULTS_MEMDUMP_SIZE not"
1136 "found", __FUNCTION__);
1137 break;
1138 }
1139
1140 memDumpSize = nla_get_u32(
1141 tbVendor[QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE]
1142 );
1143
1144 /* Allocate the memory indicated in memDumpSize */
1145 memBuffer = (char*) malloc(sizeof(char) * memDumpSize);
1146 if (memBuffer == NULL) {
1147 ALOGE("%s: No Memory for allocating Buffer size of %d",
1148 __func__, memDumpSize);
1149 break;
1150 }
1151 memset(memBuffer, 0, sizeof(char) * memDumpSize);
1152
1153 ALOGI("%s: Memory Dump size: %u", __func__,
1154 memDumpSize);
1155
1156 /* Open the proc or debugfs filesystem */
1157 memDumpFilePtr = fopen(LOGGER_MEMDUMP_FILENAME, "r");
1158 if (memDumpFilePtr == NULL) {
1159 ALOGE("Failed to open %s file", LOGGER_MEMDUMP_FILENAME);
1160 break;
1161 }
1162
1163 /* Read the memDumpSize value at once */
1164 numRecordsRead = fread(memBuffer, 1, memDumpSize,
1165 memDumpFilePtr);
1166 if (numRecordsRead <= 0 ||
1167 numRecordsRead != (int) memDumpSize) {
1168 ALOGE("%s: Read %d failed for reading at once.",
1169 __func__, numRecordsRead);
1170 /* Lets try to read in chunks */
1171 rewind(memDumpFilePtr);
1172 remaining = memDumpSize;
1173 buffer = memBuffer;
1174 while (remaining) {
1175 u32 readSize = 0;
1176 if (remaining >= LOGGER_MEMDUMP_CHUNKSIZE) {
1177 readSize = LOGGER_MEMDUMP_CHUNKSIZE;
1178 }
1179 else {
1180 readSize = remaining;
1181 }
1182 numRecordsRead = fread(buffer, 1,
1183 readSize, memDumpFilePtr);
1184 if (numRecordsRead) {
1185 remaining -= readSize;
1186 buffer += readSize;
1187 ALOGV("%s: Read successful for size:%u "
1188 "remaining:%u", __func__, readSize,
1189 remaining);
1190 }
1191 else {
1192 ALOGE("%s: Chunk read failed for size:%u",
1193 __func__, readSize);
1194 break;
1195 }
1196 }
1197 }
1198
1199 /* After successful read, call the callback handler*/
1200 if (mHandler.on_firmware_memory_dump) {
1201 mHandler.on_firmware_memory_dump(memBuffer,
1202 memDumpSize);
1203
1204 }
1205 }
1206 break;
1207 case QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS:
1208 {
1209 struct nlattr *tbVendor[QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX+1];
1210
1211 /* parse and extract wake reason stats */
1212 nla_parse(tbVendor, QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX,
1213 (struct nlattr *)mVendorData,
1214 mDataLen, NULL);
1215
1216 mGetWakeStats->cmd_event_wake_cnt_used = 0;
1217
1218 mGetWakeStats->driver_fw_local_wake_cnt_used = 0;
1219
1220 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE]) {
1221 ALOGE("%s: TOTAL_RX_DATA_WAKE not found", __FUNCTION__);
1222 break;
1223 }
1224 mGetWakeStats->total_rx_data_wake = nla_get_u32(tbVendor[
1225 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE]);
1226
1227 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT]) {
1228 ALOGE("%s: RX_UNICAST_CNT not found", __FUNCTION__);
1229 break;
1230 }
1231 mGetWakeStats->rx_wake_details.rx_unicast_cnt = nla_get_u32(
1232 tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT]);
1233
1234 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT]) {
1235 ALOGE("%s: RX_MULTICAST_CNT not found", __FUNCTION__);
1236 break;
1237 }
1238 mGetWakeStats->rx_wake_details.rx_multicast_cnt = nla_get_u32(
1239 tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT]);
1240
1241 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT]) {
1242 ALOGE("%s: RX_BROADCAST_CNT not found", __FUNCTION__);
1243 break;
1244 }
1245 mGetWakeStats->rx_wake_details.rx_broadcast_cnt = nla_get_u32(
1246 tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT]);
1247
1248 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT]) {
1249 ALOGE("%s: ICMP_PKT not found", __FUNCTION__);
1250 break;
1251 }
1252 mGetWakeStats->rx_wake_pkt_classification_info.icmp_pkt =
1253 nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT]);
1254
1255 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT]) {
1256 ALOGE("%s: ICMP6_PKT not found", __FUNCTION__);
1257 break;
1258 }
1259 mGetWakeStats->rx_wake_pkt_classification_info.icmp6_pkt =
1260 nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT]);
1261
1262 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA]) {
1263 ALOGE("%s: ICMP6_RA not found", __FUNCTION__);
1264 break;
1265 }
1266 mGetWakeStats->rx_wake_pkt_classification_info.icmp6_ra =
1267 nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA]);
1268
1269 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA]) {
1270 ALOGE("%s: ICMP6_NA not found", __FUNCTION__);
1271 break;
1272 }
1273 mGetWakeStats->rx_wake_pkt_classification_info.icmp6_na =
1274 nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA]);
1275
1276 if (!tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS]) {
1277 ALOGE("%s: ICMP6_NS not found", __FUNCTION__);
1278 break;
1279 }
1280 mGetWakeStats->rx_wake_pkt_classification_info.icmp6_ns =
1281 nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS]);
1282
1283 if (!tbVendor[
1284 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT]) {
1285 ALOGE("%s: ICMP4_RX_MULTICAST_CNT not found", __FUNCTION__);
1286 break;
1287 }
1288 mGetWakeStats->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt =
1289 nla_get_u32(tbVendor[
1290 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT]);
1291
1292 if (!tbVendor[
1293 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT]) {
1294 ALOGE("%s: ICMP6_RX_MULTICAST_CNT not found", __FUNCTION__);
1295 break;
1296 }
1297 mGetWakeStats->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt =
1298 nla_get_u32(tbVendor[
1299 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT]);
1300
1301 if (!tbVendor[
1302 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_OTHER_RX_MULTICAST_CNT]) {
1303 ALOGE("%s: OTHER_RX_MULTICAST_CNT not found", __FUNCTION__);
1304 break;
1305 }
1306 mGetWakeStats->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt =
1307 nla_get_u32(tbVendor[
1308 QCA_WLAN_VENDOR_ATTR_WAKE_STATS_OTHER_RX_MULTICAST_CNT]);
1309
1310 }
1311 break;
1312
1313 default :
1314 ALOGE("%s: Wrong Wifi Logger subcmd response received %d",
1315 __FUNCTION__, mSubcmd);
1316 }
1317
1318 /* free the allocated memory */
1319 if (memBuffer) {
1320 free(memBuffer);
1321 }
1322 if (memDumpFilePtr) {
1323 fclose(memDumpFilePtr);
1324 }
1325 return NL_SKIP;
1326 }
1327
1328 /* This function will be the main handler for incoming (from driver)
1329 * WIFI_LOGGER_SUBCMD.
1330 * Calls the appropriate callback handler after parsing the vendor data.
1331 */
handleEvent(WifiEvent & event)1332 int WifiLoggerCommand::handleEvent(WifiEvent &event)
1333 {
1334 WifiVendorCommand::handleEvent(event);
1335
1336 switch(mSubcmd)
1337 {
1338 default:
1339 /* Error case should not happen print log */
1340 ALOGE("%s: Wrong subcmd received %d", __func__, mSubcmd);
1341 break;
1342 }
1343
1344 return NL_SKIP;
1345 }
1346
setCallbackHandler(WifiLoggerCallbackHandler nHandler)1347 wifi_error WifiLoggerCommand::setCallbackHandler(WifiLoggerCallbackHandler nHandler)
1348 {
1349 wifi_error res;
1350 mHandler = nHandler;
1351 res = registerVendorHandler(mVendor_id, mSubcmd);
1352 if (res != WIFI_SUCCESS) {
1353 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
1354 __FUNCTION__, mVendor_id, mSubcmd);
1355 }
1356 return res;
1357 }
1358
unregisterHandler(u32 subCmd)1359 void WifiLoggerCommand::unregisterHandler(u32 subCmd)
1360 {
1361 unregisterVendorHandler(mVendor_id, subCmd);
1362 }
1363
timed_wait(u16 wait_time)1364 wifi_error WifiLoggerCommand::timed_wait(u16 wait_time)
1365 {
1366 struct timespec absTime;
1367 absTime.tv_sec = wait_time;
1368 absTime.tv_nsec = 0;
1369 return mCondition.wait(absTime);
1370 }
1371
waitForRsp(bool wait)1372 void WifiLoggerCommand::waitForRsp(bool wait)
1373 {
1374 mWaitforRsp = wait;
1375 }
1376
1377 /* Function to get Driver memory dump */
wifi_get_driver_memory_dump(wifi_interface_handle iface,wifi_driver_memory_dump_callbacks callback)1378 wifi_error wifi_get_driver_memory_dump(wifi_interface_handle iface,
1379 wifi_driver_memory_dump_callbacks callback)
1380 {
1381 FILE *fp;
1382 size_t fileSize, remaining, readSize;
1383 size_t numRecordsRead;
1384 char *memBuffer = NULL, *buffer = NULL;
1385 wifi_handle wifiHandle = getWifiHandle(iface);
1386 hal_info *info = getHalInfo(wifiHandle);
1387
1388 /* Check Supported logger capability */
1389 if (!(info->supported_logger_feature_set &
1390 WIFI_LOGGER_DRIVER_DUMP_SUPPORTED)) {
1391 ALOGE("%s: Driver memory dump logging feature not supported %x",
1392 __FUNCTION__, info->supported_logger_feature_set);
1393 return WIFI_ERROR_NOT_SUPPORTED;
1394 }
1395 /* Open File */
1396 fp = fopen(DRIVER_MEMDUMP_FILENAME, "r");
1397 if (fp == NULL) {
1398 ALOGE("Failed to open %s file", DRIVER_MEMDUMP_FILENAME);
1399 return WIFI_ERROR_UNKNOWN;
1400 }
1401
1402 memBuffer = (char *) malloc(DRIVER_MEMDUMP_MAX_FILESIZE);
1403 if (memBuffer == NULL) {
1404 ALOGE("%s: malloc failed for size %d", __FUNCTION__,
1405 DRIVER_MEMDUMP_MAX_FILESIZE);
1406 fclose(fp);
1407 return WIFI_ERROR_OUT_OF_MEMORY;
1408 }
1409
1410 /* Read the DRIVER_MEMDUMP_MAX_FILESIZE value at once */
1411 numRecordsRead = fread(memBuffer, 1, DRIVER_MEMDUMP_MAX_FILESIZE, fp);
1412 if (feof(fp))
1413 fileSize = numRecordsRead;
1414 else if (numRecordsRead == DRIVER_MEMDUMP_MAX_FILESIZE) {
1415 ALOGE("%s: Reading only first %zu bytes from file", __FUNCTION__,
1416 numRecordsRead);
1417 fileSize = numRecordsRead;
1418 } else {
1419 ALOGE("%s: Read failed for reading at once, ret: %zu. Trying to read in"
1420 "chunks", __FUNCTION__, numRecordsRead);
1421 /* Lets try to read in chunks */
1422 rewind(fp);
1423 remaining = DRIVER_MEMDUMP_MAX_FILESIZE;
1424 buffer = memBuffer;
1425 fileSize = 0;
1426 while (remaining) {
1427 readSize = 0;
1428 if (remaining >= LOGGER_MEMDUMP_CHUNKSIZE)
1429 readSize = LOGGER_MEMDUMP_CHUNKSIZE;
1430 else
1431 readSize = remaining;
1432
1433 numRecordsRead = fread(buffer, 1, readSize, fp);
1434 fileSize += numRecordsRead;
1435 if (feof(fp))
1436 break;
1437 else if (numRecordsRead == readSize) {
1438 remaining -= readSize;
1439 buffer += readSize;
1440 ALOGV("%s: Read successful for size:%zu remaining:%zu",
1441 __FUNCTION__, readSize, remaining);
1442 } else {
1443 ALOGE("%s: Chunk read failed for size:%zu", __FUNCTION__,
1444 readSize);
1445 free(memBuffer);
1446 memBuffer = NULL;
1447 fclose(fp);
1448 return WIFI_ERROR_UNKNOWN;
1449 }
1450 }
1451 }
1452 ALOGV("%s filename: %s fileSize: %zu", __FUNCTION__, DRIVER_MEMDUMP_FILENAME,
1453 fileSize);
1454 /* After successful read, call the callback function*/
1455 callback.on_driver_memory_dump(memBuffer, fileSize);
1456
1457 /* free the allocated memory */
1458 free(memBuffer);
1459 fclose(fp);
1460 return WIFI_SUCCESS;
1461 }
1462
1463 /* Function to get wake lock stats */
wifi_get_wake_reason_stats(wifi_interface_handle iface,WLAN_DRIVER_WAKE_REASON_CNT * wifi_wake_reason_cnt)1464 wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,
1465 WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
1466 {
1467 int requestId;
1468 wifi_error ret;
1469 WifiLoggerCommand *wifiLoggerCommand;
1470 interface_info *ifaceInfo = getIfaceInfo(iface);
1471 wifi_handle wifiHandle = getWifiHandle(iface);
1472 hal_info *info = getHalInfo(wifiHandle);
1473
1474 /* Check Supported logger capability */
1475 if (!(info->supported_logger_feature_set &
1476 WIFI_LOGGER_WAKE_LOCK_SUPPORTED)) {
1477 ALOGE("%s: Wake lock logging feature not supported %x",
1478 __FUNCTION__, info->supported_logger_feature_set);
1479 return WIFI_ERROR_NOT_SUPPORTED;
1480 }
1481
1482 /* No request id from caller, so generate one and pass it on to the driver.
1483 * Generate it randomly.
1484 */
1485 requestId = get_requestid();
1486
1487 if (!wifi_wake_reason_cnt) {
1488 ALOGE("%s: Invalid buffer provided. Exit.",
1489 __FUNCTION__);
1490 return WIFI_ERROR_INVALID_ARGS;
1491 }
1492
1493 wifiLoggerCommand = new WifiLoggerCommand(
1494 wifiHandle,
1495 requestId,
1496 OUI_QCA,
1497 QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS);
1498 if (wifiLoggerCommand == NULL) {
1499 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
1500 return WIFI_ERROR_UNKNOWN;
1501 }
1502
1503 /* Create the NL message. */
1504 ret = wifiLoggerCommand->create();
1505 if (ret != WIFI_SUCCESS)
1506 goto cleanup;
1507
1508 /* Set the interface Id of the message. */
1509 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
1510 if (ret != WIFI_SUCCESS)
1511 goto cleanup;
1512
1513 wifiLoggerCommand->getWakeStatsRspParams(wifi_wake_reason_cnt);
1514
1515 /* Send the msg and wait for a response. */
1516 ret = wifiLoggerCommand->requestResponse();
1517 if (ret != WIFI_SUCCESS)
1518 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
1519
1520 cleanup:
1521 delete wifiLoggerCommand;
1522 return ret;
1523 }
1524
getWakeStatsRspParams(WLAN_DRIVER_WAKE_REASON_CNT * wifi_wake_reason_cnt)1525 void WifiLoggerCommand::getWakeStatsRspParams(
1526 WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
1527 {
1528 mGetWakeStats = wifi_wake_reason_cnt;
1529 }
1530