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