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 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 */ 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 */ 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 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 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 215 void WifiLoggerCommand::setFeatureSet(u32 *support) { 216 mSupportedSet = support; 217 } 218 219 /* Function to get the supported feature set for logging.*/ 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.*/ 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 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.*/ 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.*/ 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. */ 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 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 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 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 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 */ 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 */ 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 */ 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 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 797 WifiLoggerCommand::~WifiLoggerCommand() 798 { 799 unregisterVendorHandler(mVendor_id, mSubcmd); 800 } 801 802 /* This function implements creation of Vendor command */ 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 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 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 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 */ 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 */ 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 */ 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 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 1005 wifi_error WifiLoggerCommand::requestResponse() 1006 { 1007 return WifiCommand::requestResponse(mMsg); 1008 } 1009 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 */ 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 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 1363 void WifiLoggerCommand::unregisterHandler(u32 subCmd) 1364 { 1365 unregisterVendorHandler(mVendor_id, subCmd); 1366 } 1367 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 1376 void WifiLoggerCommand::waitForRsp(bool wait) 1377 { 1378 mWaitforRsp = wait; 1379 } 1380 1381 /* Function to get Driver memory dump */ 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 */ 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 1549 void WifiLoggerCommand::getWakeStatsRspParams( 1550 WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) 1551 { 1552 mGetWakeStats = wifi_wake_reason_cnt; 1553 } 1554