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