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