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 39 #define LOGGER_MEMDUMP_FILENAME "/proc/debug/fwdump" 40 #define LOGGER_MEMDUMP_CHUNKSIZE (4 * 1024) 41 42 char power_events_ring_name[] = "power_events_rb"; 43 char connectivity_events_ring_name[] = "connectivity_events_rb"; 44 char pkt_stats_ring_name[] = "pkt_stats_rb"; 45 char driver_prints_ring_name[] = "driver_prints_rb"; 46 char firmware_prints_ring_name[] = "firmware_prints_rb"; 47 48 static int get_ring_id(hal_info *info, char *ring_name) 49 { 50 int rb_id; 51 52 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) { 53 if (is_rb_name_match(&info->rb_infos[rb_id], ring_name)) { 54 return rb_id; 55 } 56 } 57 return -1; 58 } 59 60 //Implementation of the functions exposed in wifi_logger.h 61 62 /* Function to intiate logging */ 63 wifi_error wifi_start_logging(wifi_interface_handle iface, 64 u32 verbose_level, u32 flags, 65 u32 max_interval_sec, u32 min_data_size, 66 char *buffer_name) 67 { 68 int requestId, ret = 0; 69 WifiLoggerCommand *wifiLoggerCommand = NULL; 70 struct nlattr *nlData; 71 interface_info *ifaceInfo = getIfaceInfo(iface); 72 wifi_handle wifiHandle = getWifiHandle(iface); 73 hal_info *info = getHalInfo(wifiHandle); 74 int ring_id = 0; 75 76 /* 77 * No request id from caller, so generate one and pass it on to the driver. 78 * Generate one randomly. 79 */ 80 requestId = rand(); 81 82 if (buffer_name == NULL) { 83 ALOGE("%s: Invalid Ring Name. \n", __FUNCTION__); 84 return WIFI_ERROR_UNKNOWN; 85 } 86 87 ring_id = get_ring_id(info, buffer_name); 88 if (ring_id < 0) { 89 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__); 90 return WIFI_ERROR_UNKNOWN; 91 } 92 93 if ((ring_id == POWER_EVENTS_RB_ID) || 94 (ring_id == PKT_STATS_RB_ID)) { 95 wifiLoggerCommand = new WifiLoggerCommand( 96 wifiHandle, 97 requestId, 98 OUI_QCA, 99 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START); 100 101 if (wifiLoggerCommand == NULL) { 102 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 103 return WIFI_ERROR_UNKNOWN; 104 } 105 /* Create the NL message. */ 106 ret = wifiLoggerCommand->create(); 107 108 if (ret < 0) 109 goto cleanup; 110 111 /* Set the interface Id of the message. */ 112 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 113 114 if (ret < 0) 115 goto cleanup; 116 117 /* Add the vendor specific attributes for the NL command. */ 118 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 119 120 if (!nlData) 121 goto cleanup; 122 123 if (wifiLoggerCommand->put_u32( 124 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID, ring_id)) 125 { 126 goto cleanup; 127 } 128 if (wifiLoggerCommand->put_u32( 129 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL, 130 verbose_level)) 131 { 132 goto cleanup; 133 } 134 if (wifiLoggerCommand->put_u32( 135 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS, 136 flags)) 137 { 138 goto cleanup; 139 } 140 141 wifiLoggerCommand->attr_end(nlData); 142 143 /* Send the msg and wait for a response. */ 144 ret = wifiLoggerCommand->requestResponse(); 145 if (ret) { 146 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 147 } 148 149 } 150 ALOGI("%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 if (wifiLoggerCommand) 155 delete wifiLoggerCommand; 156 return (wifi_error)ret; 157 158 } 159 160 /* Function to get each ring related info */ 161 wifi_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:%d 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 190 void 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 199 void send_alert(hal_info *info, int reason_code) 200 { 201 //TODO check locking 202 if (info->on_alert) { 203 info->on_alert(0, NULL, 0, reason_code); 204 } 205 } 206 207 void WifiLoggerCommand::setFeatureSet(u32 *support) { 208 mSupportedSet = support; 209 } 210 211 /* Function to get the supported feature set for logging.*/ 212 wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface, 213 u32 *support) 214 { 215 216 int requestId, ret = 0; 217 WifiLoggerCommand *wifiLoggerCommand; 218 struct nlattr *nlData; 219 interface_info *ifaceInfo = getIfaceInfo(iface); 220 wifi_handle wifiHandle = getWifiHandle(iface); 221 hal_info *info = getHalInfo(wifiHandle); 222 223 /* No request id from caller, so generate one and pass it on to the driver. 224 * Generate one randomly. 225 */ 226 requestId = rand(); 227 228 wifiLoggerCommand = new WifiLoggerCommand( 229 wifiHandle, 230 requestId, 231 OUI_QCA, 232 QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET); 233 234 if (wifiLoggerCommand == NULL) { 235 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 236 return WIFI_ERROR_UNKNOWN; 237 } 238 /* Create the NL message. */ 239 ret = wifiLoggerCommand->create(); 240 241 if (ret < 0) 242 goto cleanup; 243 244 /* Set the interface Id of the message. */ 245 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 246 247 if (ret < 0) 248 goto cleanup; 249 250 /* Add the vendor specific attributes for the NL command. */ 251 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 252 253 if (!nlData) 254 goto cleanup; 255 256 if (wifiLoggerCommand->put_u32( 257 QCA_WLAN_VENDOR_ATTR_FEATURE_SET, requestId)) 258 { 259 goto cleanup; 260 } 261 wifiLoggerCommand->attr_end(nlData); 262 263 wifiLoggerCommand->setFeatureSet(support); 264 265 /* Send the msg and wait for a response. */ 266 ret = wifiLoggerCommand->requestResponse(); 267 if (ret) { 268 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 269 } 270 271 cleanup: 272 delete wifiLoggerCommand; 273 return (wifi_error)ret; 274 } 275 276 /* Function to get the data in each ring for the given ring ID.*/ 277 wifi_error wifi_get_ring_data(wifi_interface_handle iface, 278 char *ring_name) 279 { 280 281 int requestId, ret = 0; 282 WifiLoggerCommand *wifiLoggerCommand; 283 struct nlattr *nlData; 284 interface_info *ifaceInfo = getIfaceInfo(iface); 285 wifi_handle wifiHandle = getWifiHandle(iface); 286 hal_info *info = getHalInfo(wifiHandle); 287 int ring_id = 0; 288 289 ring_id = get_ring_id(info, ring_name); 290 if (ring_id < 0) { 291 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__); 292 return WIFI_ERROR_UNKNOWN; 293 } 294 295 requestId = rand(); 296 297 wifiLoggerCommand = new WifiLoggerCommand( 298 wifiHandle, 299 requestId, 300 OUI_QCA, 301 QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA); 302 if (wifiLoggerCommand == NULL) { 303 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 304 return WIFI_ERROR_UNKNOWN; 305 } 306 /* Create the NL message. */ 307 ret = wifiLoggerCommand->create(); 308 309 if (ret < 0) 310 goto cleanup; 311 312 /* Set the interface Id of the message. */ 313 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 314 315 if (ret < 0) 316 goto cleanup; 317 318 /* Add the vendor specific attributes for the NL command. */ 319 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 320 321 if (!nlData) 322 goto cleanup; 323 324 if (wifiLoggerCommand->put_u32( 325 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID, ring_id)) 326 { 327 goto cleanup; 328 } 329 wifiLoggerCommand->attr_end(nlData); 330 331 //TBD Is there requestResponse here 332 /* Send the msg and wait for a response. */ 333 ret = wifiLoggerCommand->requestResponse(); 334 if (ret) { 335 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 336 } 337 338 cleanup: 339 delete wifiLoggerCommand; 340 return (wifi_error)ret; 341 } 342 343 void WifiLoggerCommand::setVersionInfo(char *buffer, int buffer_size) { 344 mVersion = buffer; 345 mVersionLen = buffer_size; 346 } 347 348 /* Function to send enable request to the wifi driver.*/ 349 wifi_error wifi_get_firmware_version(wifi_interface_handle iface, 350 char *buffer, int buffer_size) 351 { 352 int requestId, ret = 0; 353 WifiLoggerCommand *wifiLoggerCommand; 354 struct nlattr *nlData; 355 interface_info *ifaceInfo = getIfaceInfo(iface); 356 wifi_handle wifiHandle = getWifiHandle(iface); 357 hal_info *info = getHalInfo(wifiHandle); 358 359 /* No request id from caller, so generate one and pass it on to the driver. 360 * Generate one randomly. 361 */ 362 requestId = rand(); 363 364 wifiLoggerCommand = new WifiLoggerCommand( 365 wifiHandle, 366 requestId, 367 OUI_QCA, 368 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO); 369 if (wifiLoggerCommand == NULL) { 370 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 371 return WIFI_ERROR_UNKNOWN; 372 } 373 /* Create the NL message. */ 374 ret = wifiLoggerCommand->create(); 375 376 if (ret < 0) 377 goto cleanup; 378 379 /* Set the interface Id of the message. */ 380 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 381 382 if (ret < 0) 383 goto cleanup; 384 385 /* Add the vendor specific attributes for the NL command. */ 386 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 387 388 if (!nlData) 389 goto cleanup; 390 391 if (wifiLoggerCommand->put_u32( 392 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION, requestId)) 393 { 394 goto cleanup; 395 } 396 wifiLoggerCommand->attr_end(nlData); 397 398 wifiLoggerCommand->setVersionInfo(buffer, buffer_size); 399 400 /* Send the msg and wait for a response. */ 401 ret = wifiLoggerCommand->requestResponse(); 402 if (ret) { 403 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 404 } 405 cleanup: 406 delete wifiLoggerCommand; 407 return (wifi_error)ret; 408 409 } 410 411 /* Function to get wlan driver version.*/ 412 wifi_error wifi_get_driver_version(wifi_interface_handle iface, 413 char *buffer, int buffer_size) 414 { 415 416 int requestId, ret = 0; 417 WifiLoggerCommand *wifiLoggerCommand; 418 struct nlattr *nlData; 419 interface_info *ifaceInfo = getIfaceInfo(iface); 420 wifi_handle wifiHandle = getWifiHandle(iface); 421 hal_info *info = getHalInfo(wifiHandle); 422 423 /* No request id from caller, so generate one and pass it on to the driver. 424 * Generate one randomly. 425 */ 426 requestId = rand(); 427 428 wifiLoggerCommand = new WifiLoggerCommand( 429 wifiHandle, 430 requestId, 431 OUI_QCA, 432 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO); 433 if (wifiLoggerCommand == NULL) { 434 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 435 return WIFI_ERROR_UNKNOWN; 436 } 437 /* Create the NL message. */ 438 ret = wifiLoggerCommand->create(); 439 440 if (ret < 0) 441 goto cleanup; 442 443 /* Set the interface Id of the message. */ 444 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 445 446 if (ret < 0) 447 goto cleanup; 448 449 /* Add the vendor specific attributes for the NL command. */ 450 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 451 452 if (!nlData) 453 goto cleanup; 454 455 if (wifiLoggerCommand->put_u32( 456 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION, requestId)) 457 { 458 goto cleanup; 459 } 460 wifiLoggerCommand->attr_end(nlData); 461 462 wifiLoggerCommand->setVersionInfo(buffer, buffer_size); 463 464 /* Send the msg and wait for a response. */ 465 ret = wifiLoggerCommand->requestResponse(); 466 if (ret) { 467 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 468 } 469 cleanup: 470 delete wifiLoggerCommand; 471 return (wifi_error)ret; 472 } 473 474 475 /* Function to get the Firmware memory dump. */ 476 wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface, 477 wifi_firmware_memory_dump_handler handler) 478 { 479 int requestId, ret = 0; 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 /* No request id from caller, so generate one and pass it on to the driver. 487 * Generate one randomly. 488 */ 489 requestId = rand(); 490 491 wifiLoggerCommand = new WifiLoggerCommand( 492 wifiHandle, 493 requestId, 494 OUI_QCA, 495 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP); 496 if (wifiLoggerCommand == NULL) { 497 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__); 498 return WIFI_ERROR_UNKNOWN; 499 } 500 /* Create the NL message. */ 501 ret = wifiLoggerCommand->create(); 502 503 if (ret < 0) 504 goto cleanup; 505 506 /* Set the interface Id of the message. */ 507 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name); 508 509 if (ret < 0) 510 goto cleanup; 511 512 /* Add the vendor specific attributes for the NL command. */ 513 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA); 514 515 if (!nlData) 516 goto cleanup; 517 518 wifiLoggerCommand->attr_end(nlData); 519 520 /* copy the callback into callback handler */ 521 WifiLoggerCallbackHandler callbackHandler; 522 memset(&callbackHandler, 0, sizeof(callbackHandler)); 523 callbackHandler.on_firmware_memory_dump = \ 524 handler.on_firmware_memory_dump; 525 526 ret = wifiLoggerCommand->setCallbackHandler(callbackHandler); 527 if (ret < 0) 528 goto cleanup; 529 530 /* Send the msg and wait for the memory dump event */ 531 wifiLoggerCommand->waitForRsp(true); 532 ret = wifiLoggerCommand->requestEvent(); 533 if (ret) { 534 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret); 535 } 536 537 cleanup: 538 delete wifiLoggerCommand; 539 return (wifi_error)ret; 540 } 541 542 wifi_error wifi_set_log_handler(wifi_request_id id, 543 wifi_interface_handle iface, 544 wifi_ring_buffer_data_handler handler) 545 { 546 wifi_handle wifiHandle = getWifiHandle(iface); 547 hal_info *info = getHalInfo(wifiHandle); 548 549 info->on_ring_buffer_data = handler.on_ring_buffer_data; 550 if (handler.on_ring_buffer_data == NULL) { 551 ALOGE("Input handler is NULL"); 552 return WIFI_ERROR_UNKNOWN; 553 } 554 return WIFI_SUCCESS; 555 } 556 557 wifi_error wifi_reset_log_handler(wifi_request_id id, 558 wifi_interface_handle iface) 559 { 560 wifi_handle wifiHandle = getWifiHandle(iface); 561 hal_info *info = getHalInfo(wifiHandle); 562 563 /* Some locking needs to be introduced here */ 564 info->on_ring_buffer_data = NULL; 565 return WIFI_SUCCESS; 566 } 567 568 wifi_error wifi_set_alert_handler(wifi_request_id id, 569 wifi_interface_handle iface, 570 wifi_alert_handler handler) 571 { 572 wifi_handle wifiHandle = getWifiHandle(iface); 573 hal_info *info = getHalInfo(wifiHandle); 574 575 if (handler.on_alert) { 576 ALOGE("Input handler is NULL"); 577 return WIFI_ERROR_UNKNOWN; 578 } 579 //TODO check locking 580 info->on_alert = handler.on_alert; 581 return WIFI_SUCCESS; 582 } 583 584 wifi_error wifi_reset_alert_handler(wifi_request_id id, 585 wifi_interface_handle iface) 586 { 587 wifi_handle wifiHandle = getWifiHandle(iface); 588 hal_info *info = getHalInfo(wifiHandle); 589 590 /* Some locking needs to be introduced here */ 591 info->on_alert = NULL; 592 return WIFI_SUCCESS; 593 } 594 595 WifiLoggerCommand::WifiLoggerCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd) 596 : WifiVendorCommand(handle, id, vendor_id, subcmd) 597 { 598 ALOGV("WifiLoggerCommand %p constructed", this); 599 mVersion = NULL; 600 mVersionLen = 0; 601 mRequestId = id; 602 memset(&mHandler, 0,sizeof(mHandler)); 603 mWaitforRsp = false; 604 mMoreData = false; 605 mSupportedSet = NULL; 606 } 607 608 WifiLoggerCommand::~WifiLoggerCommand() 609 { 610 ALOGD("WifiLoggerCommand %p destructor", this); 611 unregisterVendorHandler(mVendor_id, mSubcmd); 612 } 613 614 /* This function implements creation of Vendor command */ 615 int WifiLoggerCommand::create() { 616 int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0); 617 if (ret < 0) { 618 return ret; 619 } 620 621 /* Insert the oui in the msg */ 622 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id); 623 if (ret < 0) 624 goto out; 625 /* Insert the subcmd in the msg */ 626 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd); 627 if (ret < 0) 628 goto out; 629 630 ALOGI("%s: mVendor_id = %d, Subcmd = %d.", 631 __FUNCTION__, mVendor_id, mSubcmd); 632 633 out: 634 return ret; 635 } 636 637 void rb_timerhandler(hal_info *info) 638 { 639 struct timeval now; 640 int rb_id; 641 642 gettimeofday(&now,NULL); 643 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) { 644 rb_check_for_timeout(&info->rb_infos[rb_id], &now); 645 } 646 } 647 648 wifi_error wifi_logger_ring_buffers_init(hal_info *info) 649 { 650 wifi_error ret; 651 652 ret = rb_init(info, &info->rb_infos[POWER_EVENTS_RB_ID], 653 POWER_EVENTS_RB_ID, 654 POWER_EVENTS_RB_BUF_SIZE, 655 POWER_EVENTS_NUM_BUFS, 656 power_events_ring_name); 657 if (ret != WIFI_SUCCESS) { 658 ALOGE("Failed to initialize power events ring buffer"); 659 goto cleanup; 660 } 661 662 ret = rb_init(info, &info->rb_infos[CONNECTIVITY_EVENTS_RB_ID], 663 CONNECTIVITY_EVENTS_RB_ID, 664 CONNECTIVITY_EVENTS_RB_BUF_SIZE, 665 CONNECTIVITY_EVENTS_NUM_BUFS, 666 connectivity_events_ring_name); 667 if (ret != WIFI_SUCCESS) { 668 ALOGE("Failed to initialize connectivity events ring buffer"); 669 goto cleanup; 670 } 671 672 ret = rb_init(info, &info->rb_infos[PKT_STATS_RB_ID], 673 PKT_STATS_RB_ID, 674 PKT_STATS_RB_BUF_SIZE, 675 PKT_STATS_NUM_BUFS, 676 pkt_stats_ring_name); 677 if (ret != WIFI_SUCCESS) { 678 ALOGE("Failed to initialize per packet stats ring buffer"); 679 goto cleanup; 680 } 681 682 ret = rb_init(info, &info->rb_infos[DRIVER_PRINTS_RB_ID], 683 DRIVER_PRINTS_RB_ID, 684 DRIVER_PRINTS_RB_BUF_SIZE, 685 DRIVER_PRINTS_NUM_BUFS, 686 driver_prints_ring_name); 687 if (ret != WIFI_SUCCESS) { 688 ALOGE("Failed to initialize driver prints ring buffer"); 689 goto cleanup; 690 } 691 692 ret = rb_init(info, &info->rb_infos[FIRMWARE_PRINTS_RB_ID], 693 FIRMWARE_PRINTS_RB_ID, 694 FIRMWARE_PRINTS_RB_BUF_SIZE, 695 FIRMWARE_PRINTS_NUM_BUFS, 696 firmware_prints_ring_name); 697 if (ret != WIFI_SUCCESS) { 698 ALOGE("Failed to initialize firmware prints ring buffer"); 699 goto cleanup; 700 } 701 702 return ret; 703 704 cleanup: 705 wifi_logger_ring_buffers_deinit(info); 706 return ret; 707 } 708 709 void wifi_logger_ring_buffers_deinit(hal_info *info) 710 { 711 int i; 712 713 for (i = 0; i < NUM_RING_BUFS; i++) { 714 rb_deinit(&info->rb_infos[i]); 715 } 716 } 717 718 719 /* Callback handlers registered for nl message send */ 720 static int error_handler_wifi_logger(struct sockaddr_nl *nla, 721 struct nlmsgerr *err, 722 void *arg) 723 { 724 struct sockaddr_nl *tmp; 725 int *ret = (int *)arg; 726 tmp = nla; 727 *ret = err->error; 728 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret))); 729 return NL_STOP; 730 } 731 732 /* Callback handlers registered for nl message send */ 733 static int ack_handler_wifi_logger(struct nl_msg *msg, void *arg) 734 { 735 int *ret = (int *)arg; 736 struct nl_msg * a; 737 738 ALOGE("%s: called", __FUNCTION__); 739 a = msg; 740 *ret = 0; 741 return NL_STOP; 742 } 743 744 /* Callback handlers registered for nl message send */ 745 static int finish_handler_wifi_logger(struct nl_msg *msg, void *arg) 746 { 747 int *ret = (int *)arg; 748 struct nl_msg * a; 749 750 ALOGE("%s: called", __FUNCTION__); 751 a = msg; 752 *ret = 0; 753 return NL_SKIP; 754 } 755 756 int WifiLoggerCommand::requestEvent() 757 { 758 int res = -1; 759 struct nl_cb *cb; 760 761 ALOGD("%s: Entry.", __FUNCTION__); 762 763 cb = nl_cb_alloc(NL_CB_DEFAULT); 764 if (!cb) { 765 ALOGE("%s: Callback allocation failed",__FUNCTION__); 766 res = -1; 767 goto out; 768 } 769 770 /* Send message */ 771 res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); 772 if (res < 0) 773 goto out; 774 res = 1; 775 776 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_logger, &res); 777 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_logger, &res); 778 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_logger, &res); 779 780 /* Err is populated as part of finish_handler. */ 781 while (res > 0){ 782 nl_recvmsgs(mInfo->cmd_sock, cb); 783 } 784 785 ALOGD("%s: Msg sent, res=%d, mWaitForRsp=%d", __FUNCTION__, res, mWaitforRsp); 786 /* Only wait for the asynchronous event if HDD returns success, res=0 */ 787 if (!res && (mWaitforRsp == true)) { 788 struct timespec abstime; 789 abstime.tv_sec = 4; 790 abstime.tv_nsec = 0; 791 res = mCondition.wait(abstime); 792 if (res == ETIMEDOUT) 793 { 794 ALOGE("%s: Time out happened.", __FUNCTION__); 795 } 796 ALOGD("%s: Command invoked return value:%d, mWaitForRsp=%d", 797 __FUNCTION__, res, mWaitforRsp); 798 } 799 out: 800 /* Cleanup the mMsg */ 801 mMsg.destroy(); 802 return res; 803 } 804 805 int WifiLoggerCommand::requestResponse() 806 { 807 return WifiCommand::requestResponse(mMsg); 808 } 809 810 int WifiLoggerCommand::handleResponse(WifiEvent &reply) { 811 ALOGD("Received a WifiLogger response message from Driver"); 812 u32 status; 813 int ret = WIFI_SUCCESS; 814 int i = 0; 815 int len = 0, version; 816 char version_type[20]; 817 WifiVendorCommand::handleResponse(reply); 818 819 switch(mSubcmd) 820 { 821 case QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: 822 { 823 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; 824 825 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, 826 (struct nlattr *)mVendorData, mDataLen, NULL); 827 828 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { 829 len = nla_len(tb_vendor[ 830 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]); 831 memcpy(version_type, "Driver", strlen("Driver")); 832 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION; 833 } else if ( 834 tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { 835 len = nla_len( 836 tb_vendor[ 837 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]); 838 memcpy(version_type, "Firmware", strlen("Firmware")); 839 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION; 840 } 841 if (len && mVersion && mVersionLen) { 842 memset(mVersion, 0, mVersionLen); 843 /* if len is greater than the incoming length then 844 accommodate 1 lesser than mVersionLen to have the 845 string terminated with '\0' */ 846 len = (len > mVersionLen)? (mVersionLen - 1) : len; 847 memcpy(mVersion, nla_data(tb_vendor[version]), len); 848 ALOGD("%s: WLAN version len : %d", __FUNCTION__, len); 849 ALOGD("%s: WLAN %s version : %s ", __FUNCTION__, 850 version_type, mVersion); 851 } 852 } 853 break; 854 case QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: 855 { 856 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX + 1]; 857 858 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX, 859 (struct nlattr *)mVendorData, mDataLen, NULL); 860 861 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET]) { 862 *mSupportedSet = 863 nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET]); 864 ALOGD("%s: Supported Feature Set : val 0x%x", 865 __FUNCTION__, *mSupportedSet); 866 } 867 } 868 break; 869 default : 870 ALOGE("%s: Wrong Wifi Logger subcmd response received %d", 871 __FUNCTION__, mSubcmd); 872 } 873 874 return NL_SKIP; 875 } 876 877 /* This function will be the main handler for incoming (from driver) 878 * WIFI_LOGGER_SUBCMD. 879 * Calls the appropriate callback handler after parsing the vendor data. 880 */ 881 int WifiLoggerCommand::handleEvent(WifiEvent &event) 882 { 883 unsigned i = 0; 884 u32 status; 885 int ret = WIFI_SUCCESS; 886 char* memBuffer = NULL; 887 FILE* memDumpFilePtr = NULL; 888 889 WifiVendorCommand::handleEvent(event); 890 891 struct nlattr *tbVendor[ 892 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX + 1]; 893 nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX, 894 (struct nlattr *)mVendorData, 895 mDataLen, NULL); 896 897 switch(mSubcmd) 898 { 899 case QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP: 900 { 901 int id = 0; 902 u32 memDumpSize = 0; 903 int numRecordsRead = 0; 904 u32 remaining = 0; 905 char* buffer = NULL; 906 907 if (!tbVendor[ 908 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_REQUEST_ID]) { 909 ALOGE("%s: LOGGER_RESULTS_REQUEST_ID not" 910 "found, continuing...", __func__); 911 } 912 else { 913 id = nla_get_u32(tbVendor[ 914 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_REQUEST_ID] 915 ); 916 ALOGI("%s: Event has Req. ID:%d, ours:%d", 917 __func__, id, mRequestId); 918 } 919 920 if (!tbVendor[ 921 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE]) { 922 ALOGE("%s: LOGGER_RESULTS_MEMDUMP_SIZE not" 923 "found", __func__); 924 break; 925 } 926 927 memDumpSize = nla_get_u32( 928 tbVendor[QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE] 929 ); 930 931 /* Allocate the memory indicated in memDumpSize */ 932 memBuffer = (char*) malloc(sizeof(char) * memDumpSize); 933 if (memBuffer == NULL) { 934 ALOGE("%s: No Memory for allocating Buffer ", 935 "size of %d", __func__, memDumpSize); 936 break; 937 } 938 memset(memBuffer, 0, sizeof(char) * memDumpSize); 939 940 ALOGI("%s: Memory Dump size: %u", __func__, 941 memDumpSize); 942 943 /* Open the proc or debugfs filesystem */ 944 memDumpFilePtr = fopen(LOGGER_MEMDUMP_FILENAME, "r"); 945 if (memDumpFilePtr == NULL) { 946 ALOGE("Failed to open %s file", LOGGER_MEMDUMP_FILENAME); 947 break; 948 } 949 950 /* Read the memDumpSize value at once */ 951 numRecordsRead = fread(memBuffer, 1, memDumpSize, 952 memDumpFilePtr); 953 if (numRecordsRead <= 0 || 954 numRecordsRead != (int) memDumpSize) { 955 ALOGE("%s: Read %d failed for reading at once.", 956 __func__, numRecordsRead); 957 /* Lets try to read in chunks */ 958 rewind(memDumpFilePtr); 959 remaining = memDumpSize; 960 buffer = memBuffer; 961 while (remaining) { 962 u32 readSize = 0; 963 if (remaining >= LOGGER_MEMDUMP_CHUNKSIZE) { 964 readSize = LOGGER_MEMDUMP_CHUNKSIZE; 965 } 966 else { 967 readSize = remaining; 968 } 969 numRecordsRead = fread(buffer, 1, 970 readSize, memDumpFilePtr); 971 if (numRecordsRead) { 972 remaining -= readSize; 973 buffer += readSize; 974 ALOGI("%s: Read successful for size:%u " 975 "remaining:%u", __func__, readSize, 976 remaining); 977 } 978 else { 979 ALOGE("%s: Chunk read failed for size:%u", 980 __func__, readSize); 981 break; 982 } 983 } 984 } 985 986 /* After successful read, call the callback handler*/ 987 if (mHandler.on_firmware_memory_dump) { 988 mHandler.on_firmware_memory_dump(memBuffer, 989 memDumpSize); 990 991 } 992 } 993 break; 994 995 default: 996 /* Error case should not happen print log */ 997 ALOGE("%s: Wrong subcmd received %d", __func__, mSubcmd); 998 break; 999 } 1000 1001 cleanup: 1002 /* free the allocated memory */ 1003 if (memBuffer) { 1004 free(memBuffer); 1005 } 1006 return NL_SKIP; 1007 } 1008 1009 int WifiLoggerCommand::setCallbackHandler(WifiLoggerCallbackHandler nHandler) 1010 { 1011 int res = 0; 1012 mHandler = nHandler; 1013 res = registerVendorHandler(mVendor_id, mSubcmd); 1014 if (res != 0) { 1015 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u", 1016 __FUNCTION__, mVendor_id, mSubcmd); 1017 } 1018 return res; 1019 } 1020 1021 void WifiLoggerCommand::unregisterHandler(u32 subCmd) 1022 { 1023 unregisterVendorHandler(mVendor_id, subCmd); 1024 } 1025 1026 int WifiLoggerCommand::timed_wait(u16 wait_time) 1027 { 1028 struct timespec absTime; 1029 int res; 1030 absTime.tv_sec = wait_time; 1031 absTime.tv_nsec = 0; 1032 return mCondition.wait(absTime); 1033 } 1034 1035 void WifiLoggerCommand::waitForRsp(bool wait) 1036 { 1037 mWaitforRsp = wait; 1038 } 1039 1040