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