wifi_logger.cpp revision bedc792622bd9ef90c30e4d8c5efa194f1010d2e
1#include <stdint.h> 2#include <fcntl.h> 3#include <sys/socket.h> 4#include <netlink/genl/genl.h> 5#include <netlink/genl/family.h> 6#include <netlink/genl/ctrl.h> 7#include <linux/rtnetlink.h> 8#include <netpacket/packet.h> 9#include <linux/filter.h> 10#include <linux/errqueue.h> 11 12#include <linux/pkt_sched.h> 13#include <netlink/object-api.h> 14#include <netlink/netlink.h> 15#include <netlink/socket.h> 16#include <netlink-types.h> 17 18#include "nl80211_copy.h" 19#include "sync.h" 20 21#define LOG_TAG "WifiHAL" 22 23#include <utils/Log.h> 24 25#include "wifi_hal.h" 26#include "common.h" 27#include "cpp_bindings.h" 28 29using namespace android; 30 31typedef enum { 32 LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START, 33 LOGGER_TRIGGER_MEM_DUMP, 34 LOGGER_GET_MEM_DUMP, 35 LOGGER_GET_VER, 36 LOGGER_GET_RING_STATUS, 37 LOGGER_GET_RING_DATA, 38 LOGGER_GET_FEATURE, 39 LOGGER_RESET_LOGGING, 40} DEBUG_SUB_COMMAND; 41 42typedef enum { 43 LOGGER_ATTRIBUTE_DRIVER_VER, 44 LOGGER_ATTRIBUTE_FW_VER, 45 LOGGER_ATTRIBUTE_RING_ID, 46 LOGGER_ATTRIBUTE_RING_NAME, 47 LOGGER_ATTRIBUTE_RING_FLAGS, 48 LOGGER_ATTRIBUTE_LOG_LEVEL, 49 LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, 50 LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, 51 LOGGER_ATTRIBUTE_FW_DUMP_LEN, 52 LOGGER_ATTRIBUTE_FW_DUMP_DATA, 53 // LOGGER_ATTRIBUTE_FW_ERR_CODE, 54 LOGGER_ATTRIBUTE_RING_DATA, 55 LOGGER_ATTRIBUTE_RING_STATUS, 56 LOGGER_ATTRIBUTE_RING_NUM, 57} LOGGER_ATTRIBUTE; 58 59typedef enum { 60 DEBUG_OFF = 0, 61 DEBUG_NORMAL, 62 DEBUG_VERBOSE, 63 DEBUG_VERY, 64 DEBUG_VERY_VERY, 65} LOGGER_LEVEL; 66 67typedef enum { 68 GET_FW_VER, 69 GET_DRV_VER, 70 GET_RING_DATA, 71 GET_RING_STATUS, 72 GET_FEATURE, 73 START_RING_LOG, 74} GetCmdType; 75 76 77/////////////////////////////////////////////////////////////////////////////// 78class DebugCommand : public WifiCommand 79{ 80 char *mBuff; 81 int *mBuffSize; 82 u32 *mNumRings; 83 wifi_ring_buffer_status *mStatus; 84 unsigned int *mSupport; 85 u32 mVerboseLevel; 86 u32 mFlags; 87 u32 mMaxIntervalSec; 88 u32 mMinDataSize; 89 char *mRingName; 90 GetCmdType mType; 91 92public: 93 94 // constructor for get version 95 DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size, 96 GetCmdType cmdType) 97 : WifiCommand(iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType(cmdType) 98 { 99 memset(mBuff, 0, *mBuffSize); 100 } 101 102 // constructor for ring data 103 DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType) 104 : WifiCommand(iface, 0), mRingName(ring_name), mType(cmdType) 105 { } 106 107 // constructor for ring status 108 DebugCommand(wifi_interface_handle iface, u32 *num_rings, 109 wifi_ring_buffer_status *status, GetCmdType cmdType) 110 : WifiCommand(iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType) 111 { 112 memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings)); 113 } 114 115 // constructor for feature set 116 DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType) 117 : WifiCommand(iface, 0), mSupport(support), mType(cmdType) 118 { } 119 120 // constructor for ring params 121 DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags, 122 u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType) 123 : WifiCommand(iface, 0), mVerboseLevel(verbose_level), mFlags(flags), 124 mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size), 125 mRingName(ring_name), mType(cmdType) 126 { } 127 128 int createRingRequest(WifiRequest& request) { 129 int result = request.create(GOOGLE_OUI, LOGGER_START_LOGGING); 130 if (result != WIFI_SUCCESS) { 131 ALOGE("Failed to create start ring logger request; result = %d", result); 132 return result; 133 } 134 135 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 136 137 result = request.put_u32(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel); 138 if (result != WIFI_SUCCESS) { 139 ALOGE("Failed to put log level; result = %d", result); 140 return result; 141 } 142 result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags); 143 if (result != WIFI_SUCCESS) { 144 ALOGE("Failed to put ring flags; result = %d", result); 145 return result; 146 } 147 result = request.put_u32(LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec); 148 if (result != WIFI_SUCCESS) { 149 ALOGE("Failed to put log time interval; result = %d", result); 150 return result; 151 } 152 result = request.put_u32(LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize); 153 if (result != WIFI_SUCCESS) { 154 ALOGE("Failed to put min data size; result = %d", result); 155 return result; 156 } 157 result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); 158 if (result != WIFI_SUCCESS) { 159 ALOGE("Failed to put ringbuffer name; result = %d", result); 160 return result; 161 } 162 request.attr_end(data); 163 164 return WIFI_SUCCESS; 165 } 166 167 int createRequest(WifiRequest &request) { 168 int result; 169 170 switch (mType) { 171 case GET_FW_VER: 172 { 173 result = request.create(GOOGLE_OUI, LOGGER_GET_VER); 174 if (result != WIFI_SUCCESS) { 175 ALOGE("Failed to create get fw version request; result = %d", result); 176 return result; 177 } 178 179 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 180 181 // Driver expecting only attribute type, passing mbuff as data with 182 // length 0 to avoid undefined state 183 result = request.put(LOGGER_ATTRIBUTE_FW_VER, mBuff, 0); 184 if (result != WIFI_SUCCESS) { 185 ALOGE("Failed to put get fw version request; result = %d", result); 186 return result; 187 } 188 request.attr_end(data); 189 break; 190 } 191 192 case GET_DRV_VER: 193 { 194 result = request.create(GOOGLE_OUI, LOGGER_GET_VER); 195 if (result != WIFI_SUCCESS) { 196 ALOGE("Failed to create get drv version request; result = %d", result); 197 return result; 198 } 199 200 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 201 202 // Driver expecting only attribute type, passing mbuff as data with 203 // length 0 to avoid undefined state 204 result = request.put(LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0); 205 206 if (result != WIFI_SUCCESS) { 207 ALOGE("Failed to put get drv version request; result = %d", result); 208 return result; 209 } 210 request.attr_end(data); 211 break; 212 } 213 214 case GET_RING_DATA: 215 { 216 result = request.create(GOOGLE_OUI, LOGGER_GET_RING_DATA); 217 if (result != WIFI_SUCCESS) { 218 ALOGE("Failed to create get ring data request; result = %d", result); 219 return result; 220 } 221 222 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 223 result = request.put_string(LOGGER_ATTRIBUTE_RING_NAME, mRingName); 224 if (result != WIFI_SUCCESS) { 225 ALOGE("Failed to put ring data request; result = %d", result); 226 return result; 227 } 228 request.attr_end(data); 229 break; 230 } 231 232 case GET_RING_STATUS: 233 { 234 result = request.create(GOOGLE_OUI, LOGGER_GET_RING_STATUS); 235 if (result != WIFI_SUCCESS) { 236 ALOGE("Failed to create get ring status request; result = %d", result); 237 return result; 238 } 239 break; 240 } 241 242 case GET_FEATURE: 243 { 244 result = request.create(GOOGLE_OUI, LOGGER_GET_FEATURE); 245 if (result != WIFI_SUCCESS) { 246 ALOGE("Failed to create get feature request; result = %d", result); 247 return result; 248 } 249 break; 250 } 251 252 case START_RING_LOG: 253 result = createRingRequest(request); 254 break; 255 256 default: 257 ALOGE("Unknown Debug command"); 258 result = WIFI_ERROR_UNKNOWN; 259 } 260 return result; 261 } 262 263 int start() { 264 // ALOGD("Start debug command"); 265 WifiRequest request(familyId(), ifaceId()); 266 int result = createRequest(request); 267 if (result != WIFI_SUCCESS) { 268 ALOGE("Failed to create debug request; result = %d", result); 269 return result; 270 } 271 272 result = requestResponse(request); 273 if (result != WIFI_SUCCESS) { 274 ALOGE("Failed to register debug response; result = %d", result); 275 } 276 return result; 277 } 278 279 virtual int handleResponse(WifiEvent& reply) { 280 ALOGD("In DebugCommand::handleResponse"); 281 282 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 283 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 284 return NL_SKIP; 285 } 286 287 switch (mType) { 288 case GET_DRV_VER: 289 case GET_FW_VER: 290 { 291 void *data = reply.get_vendor_data(); 292 int len = reply.get_vendor_data_len(); 293 294 ALOGD("len = %d, expected len = %d", len, *mBuffSize); 295 memcpy(mBuff, data, min(len, *mBuffSize)); 296 if (*mBuffSize < len) 297 return NL_SKIP; 298 *mBuffSize = len; 299 break; 300 } 301 302 case START_RING_LOG: 303 case GET_RING_DATA: 304 break; 305 306 case GET_RING_STATUS: 307 { 308 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 309 int len = reply.get_vendor_data_len(); 310 wifi_ring_buffer_status *status(mStatus); 311 312 if (vendor_data == NULL || len == 0) { 313 ALOGE("No Debug data found"); 314 return NL_SKIP; 315 } 316 317 nl_iterator it(vendor_data); 318 if (it.get_type() == LOGGER_ATTRIBUTE_RING_NUM) { 319 unsigned int num_rings = it.get_u32(); 320 if (*mNumRings < num_rings) { 321 ALOGE("Not enough status buffers provided, available: %d required: %d", 322 *mNumRings, num_rings); 323 } else { 324 *mNumRings = num_rings; 325 } 326 } else { 327 ALOGE("Unknown attribute: %d expecting %d", 328 it.get_type(), LOGGER_ATTRIBUTE_RING_NUM); 329 return NL_SKIP; 330 } 331 332 it.next(); 333 for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) { 334 if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { 335 memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status)); 336 i++; 337 status++; 338 } else { 339 ALOGW("Ignoring invalid attribute type = %d, size = %d", 340 it.get_type(), it.get_len()); 341 } 342 } 343 break; 344 } 345 346 case GET_FEATURE: 347 { 348 void *data = reply.get_vendor_data(); 349 int len = reply.get_vendor_data_len(); 350 351 ALOGD("len = %d, expected len = %d", len, sizeof(unsigned int)); 352 memcpy(mSupport, data, sizeof(unsigned int)); 353 break; 354 } 355 356 default: 357 ALOGW("Unknown Debug command"); 358 } 359 return NL_OK; 360 } 361 362 virtual int handleEvent(WifiEvent& event) { 363 /* NO events! */ 364 return NL_SKIP; 365 } 366}; 367 368/* API to collect a firmware version string */ 369wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, 370 int buffer_size) 371{ 372 if (buffer && (buffer_size > 0)) { 373 DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER); 374 return (wifi_error)cmd->start(); 375 } else { 376 ALOGE("FW version buffer NULL"); 377 return WIFI_ERROR_INVALID_ARGS; 378 } 379} 380 381/* API to collect a driver version string */ 382wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size) 383{ 384 if (buffer && (buffer_size > 0)) { 385 DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER); 386 return (wifi_error)cmd->start(); 387 } else { 388 ALOGE("Driver version buffer NULL"); 389 return WIFI_ERROR_INVALID_ARGS; 390 } 391} 392 393/* API to collect driver records */ 394wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name) 395{ 396 DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA); 397 return (wifi_error)cmd->start(); 398} 399 400/* API to get the status of all ring buffers supported by driver */ 401wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, 402 u32 *num_rings, wifi_ring_buffer_status *status) 403{ 404 if (status && num_rings) { 405 DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS); 406 return (wifi_error)cmd->start(); 407 } else { 408 ALOGE("Ring status buffer NULL"); 409 return WIFI_ERROR_INVALID_ARGS; 410 } 411} 412 413/* API to get supportable feature */ 414wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface, 415 unsigned int *support) 416{ 417 if (support) { 418 DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE); 419 return (wifi_error)cmd->start(); 420 } else { 421 ALOGE("Get support buffer NULL"); 422 return WIFI_ERROR_INVALID_ARGS; 423 } 424} 425 426wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, 427 u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name) 428{ 429 if (ring_name) { 430 DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, 431 max_interval_sec, min_data_size, ring_name, START_RING_LOG); 432 return (wifi_error)cmd->start(); 433 } else { 434 ALOGE("Ring name NULL"); 435 return WIFI_ERROR_INVALID_ARGS; 436 } 437} 438 439 440/////////////////////////////////////////////////////////////////////////////// 441class SetLogHandler : public WifiCommand 442{ 443 wifi_ring_buffer_data_handler mHandler; 444 445public: 446 SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler) 447 : WifiCommand(iface, id), mHandler(handler) 448 { } 449 SetLogHandler(wifi_interface_handle iface, int id) 450 : WifiCommand(iface, id) 451 { } 452 453 int start() { 454 ALOGD("Register log handler"); 455 registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); 456 return WIFI_SUCCESS; 457 } 458 459 virtual int cancel() { 460 /* Send a command to driver to stop generating logging events */ 461 ALOGD("Reset event handler"); 462 463 WifiRequest request(familyId(), ifaceId()); 464 int result = request.create(GOOGLE_OUI, LOGGER_RESET_LOGGING); 465 466 if (result != WIFI_SUCCESS) { 467 ALOGE("failed to create reset request; result = %d", result); 468 return result; 469 } 470 471 result = requestResponse(request); 472 if (result != WIFI_SUCCESS) { 473 ALOGE("failed to request reset; result = %d", result); 474 return result; 475 } 476 477 /* unregister event handler */ 478 unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT); 479 ALOGD("Success to reset event handler"); 480 return WIFI_SUCCESS; 481 } 482 483 virtual int handleEvent(WifiEvent& event) { 484 char *buffer = NULL; 485 int buffer_size = 0; 486 487 // ALOGD("In SetLogHandler::handleEvent"); 488 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 489 int len = event.get_vendor_data_len(); 490 int event_id = event.get_vendor_subcmd(); 491 // ALOGI("Got Logger event: %d", event_id); 492 493 if (vendor_data == NULL || len == 0) { 494 ALOGE("No Debug data found"); 495 return NL_SKIP; 496 } 497 498 if(event_id == GOOGLE_DEBUG_RING_EVENT) { 499 wifi_ring_buffer_status status; 500 memset(&status, 0, sizeof(status)); 501 502 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 503 if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) { 504 memcpy(&status, it.get_data(), sizeof(status)); 505 } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { 506 buffer_size = it.get_len(); 507 buffer = (char *)it.get_data(); 508 } else { 509 ALOGW("Ignoring invalid attribute type = %d, size = %d", 510 it.get_type(), it.get_len()); 511 } 512 } 513 514 // ALOGI("Retrieved Debug data"); 515 if (mHandler.on_ring_buffer_data) { 516 (*mHandler.on_ring_buffer_data)((char *)status.name, buffer, buffer_size, 517 &status); 518 } 519 } else { 520 ALOGE("Unknown Event"); 521 return NL_SKIP; 522 } 523 return NL_OK; 524 } 525}; 526 527wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface, 528 wifi_ring_buffer_data_handler handler) 529{ 530 wifi_handle handle = getWifiHandle(iface); 531 SetLogHandler *cmd = new SetLogHandler(iface, id, handler); 532 533 ALOGI("Logger start, handle = %p", handle); 534 if (cmd) { 535 wifi_register_cmd(handle, id, cmd); 536 return (wifi_error)cmd->start(); 537 } else { 538 ALOGD("Out of memory"); 539 return WIFI_ERROR_OUT_OF_MEMORY; 540 } 541} 542 543wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface) 544{ 545 wifi_handle handle = getWifiHandle(iface); 546 SetLogHandler *cmd = new SetLogHandler(iface, id); 547 548 ALOGI("Logger reset, handle = %p", handle); 549 if (cmd) { 550 cmd->cancel(); 551 cmd->releaseRef(); 552 return WIFI_SUCCESS; 553 } 554 return WIFI_ERROR_INVALID_ARGS; 555} 556 557/////////////////////////////////////////////////////////////////////////////// 558class SetAlertHandler : public WifiCommand 559{ 560 wifi_alert_handler mHandler; 561 int mBuffSize; 562 char *mBuff; 563 int mErrCode; 564 565public: 566 SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler) 567 : WifiCommand(iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL), mErrCode(0) 568 { } 569 570 int start() { 571 ALOGD("Start Alerting"); 572 registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT); 573 return WIFI_SUCCESS; 574 } 575 576 virtual int handleResponse(WifiEvent& reply) { 577 ALOGD("In SetAlertHandler::handleResponse"); 578 579 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 580 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 581 return NL_SKIP; 582 } 583 584 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 585 int len = reply.get_vendor_data_len(); 586 587 ALOGD("len = %d", len); 588 if (vendor_data == NULL || len == 0) { 589 ALOGE("no vendor data in memory dump response; ignoring it"); 590 return NL_SKIP; 591 } 592 593 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 594 if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { 595 ALOGI("Initiating alert callback"); 596 if (mHandler.on_alert) { 597 (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode); 598 } 599 if (mBuff) { 600 free(mBuff); 601 mBuff = NULL; 602 } 603 } 604 } 605 return NL_OK; 606 } 607 608 virtual int handleEvent(WifiEvent& event) { 609 wifi_ring_buffer_id ring_id; 610 char *buffer = NULL; 611 int buffer_size = 0; 612 613 614 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); 615 int len = event.get_vendor_data_len(); 616 int event_id = event.get_vendor_subcmd(); 617 ALOGI("Got event: %d", event_id); 618 619 if (vendor_data == NULL || len == 0) { 620 ALOGE("No Debug data found"); 621 return NL_SKIP; 622 } 623 624 if (event_id == GOOGLE_DEBUG_MEM_DUMP_EVENT) { 625 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 626 if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { 627 mBuffSize = it.get_u32(); 628 } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) { 629 buffer_size = it.get_len(); 630 buffer = (char *)it.get_data(); 631 /* 632 } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_ERR_CODE) { 633 mErrCode = it.get_u32(); 634 */ 635 } else { 636 ALOGW("Ignoring invalid attribute type = %d, size = %d", 637 it.get_type(), it.get_len()); 638 } 639 } 640 if (mBuffSize) { 641 ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size); 642 if (mBuff) free(mBuff); 643 mBuff = (char *)malloc(mBuffSize + buffer_size); 644 if (!mBuff) { 645 ALOGE("Buffer allocation failed"); 646 return NL_SKIP; 647 } 648 memcpy(mBuff, buffer, buffer_size); 649 650 WifiRequest request(familyId(), ifaceId()); 651 int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); 652 if (result != WIFI_SUCCESS) { 653 ALOGE("Failed to create get memory dump request; result = %d", result); 654 free(mBuff); 655 return NL_SKIP; 656 } 657 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 658 result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); 659 if (result != WIFI_SUCCESS) { 660 ALOGE("Failed to put get memory dump request; result = %d", result); 661 return result; 662 } 663 664 result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, 665 (uint64_t)(mBuff+buffer_size)); 666 if (result != WIFI_SUCCESS) { 667 ALOGE("Failed to put get memory dump request; result = %d", result); 668 return result; 669 } 670 671 request.attr_end(data); 672 mBuffSize += buffer_size; 673 674 result = requestResponse(request); 675 676 if (result != WIFI_SUCCESS) { 677 ALOGE("Failed to register get momory dump response; result = %d", result); 678 } 679 } else { 680 ALOGE("dump event missing dump length attribute"); 681 return NL_SKIP; 682 } 683 } 684 return NL_OK; 685 } 686}; 687 688wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface, 689 wifi_alert_handler handler) 690{ 691 wifi_handle handle = getWifiHandle(iface); 692 SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler); 693 ALOGI("Alert start, handle = %p", handle); 694 695 wifi_register_cmd(handle, id, cmd); 696 return (wifi_error)cmd->start(); 697} 698 699 700/////////////////////////////////////////////////////////////////////////////// 701class MemoryDumpCommand: public WifiCommand 702{ 703 wifi_firmware_memory_dump_handler mHandler; 704 int mBuffSize; 705 char *mBuff; 706 707public: 708 MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler) 709 : WifiCommand(iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL) 710 { } 711 712 int start() { 713 ALOGD("Start memory dump command"); 714 WifiRequest request(familyId(), ifaceId()); 715 716 int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP); 717 if (result != WIFI_SUCCESS) { 718 ALOGE("Failed to create trigger fw memory dump request; result = %d", result); 719 return result; 720 } 721 722 result = requestResponse(request); 723 if (result != WIFI_SUCCESS) { 724 ALOGE("Failed to register trigger memory dump response; result = %d", result); 725 } 726 return result; 727 } 728 729 virtual int handleResponse(WifiEvent& reply) { 730 ALOGD("In MemoryDumpCommand::handleResponse"); 731 732 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 733 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 734 return NL_SKIP; 735 } 736 737 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 738 int len = reply.get_vendor_data_len(); 739 740 ALOGD("len = %d", len); 741 if (vendor_data == NULL || len == 0) { 742 ALOGE("no vendor data in memory dump response; ignoring it"); 743 return NL_SKIP; 744 } 745 746 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 747 if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) { 748 mBuffSize = it.get_u32(); 749 750 if (mBuff) 751 free(mBuff); 752 mBuff = (char *)malloc(mBuffSize); 753 if (!mBuff) { 754 ALOGE("Buffer allocation failed"); 755 return NL_SKIP; 756 } 757 WifiRequest request(familyId(), ifaceId()); 758 int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP); 759 if (result != WIFI_SUCCESS) { 760 ALOGE("Failed to create get memory dump request; result = %d", result); 761 free(mBuff); 762 return NL_SKIP; 763 } 764 765 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 766 result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize); 767 if (result != WIFI_SUCCESS) { 768 ALOGE("Failed to put get memory dump request; result = %d", result); 769 return result; 770 } 771 772 result = request.put_u64(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff); 773 if (result != WIFI_SUCCESS) { 774 ALOGE("Failed to put get memory dump request; result = %d", result); 775 return result; 776 } 777 request.attr_end(data); 778 779 result = requestResponse(request); 780 if (result != WIFI_SUCCESS) { 781 ALOGE("Failed to register get momory dump response; result = %d", result); 782 } 783 } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) { 784 ALOGI("Initiating memory dump callback"); 785 if (mHandler.on_firmware_memory_dump) { 786 (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize); 787 } 788 if (mBuff) { 789 free(mBuff); 790 mBuff = NULL; 791 } 792 } else { 793 ALOGW("Ignoring invalid attribute type = %d, size = %d", 794 it.get_type(), it.get_len()); 795 } 796 } 797 return NL_OK; 798 } 799 800 virtual int handleEvent(WifiEvent& event) { 801 /* NO events! */ 802 return NL_SKIP; 803 } 804}; 805 806/* API to collect a firmware memory dump for a given iface */ 807wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface, 808 wifi_firmware_memory_dump_handler handler) 809{ 810 MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler); 811 return (wifi_error)cmd->start(); 812} 813 814