wifi_logger.cpp revision 1dc3032cbec4d3d4f67fcc0a1dffb6a1dee8a1b7
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                /* BUG: 1. should not be passing pointer to data, 2. should not assume pointer is 32 bits
622                result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_DATA,
623                        (uint32_t)(mBuff+buffer_size));
624                if (result != WIFI_SUCCESS) {
625                    ALOGE("Failed to put get memory dump request; result = %d", result);
626                    return result;
627                }
628                */
629                request.attr_end(data);
630                mBuffSize += buffer_size;
631
632                result = requestResponse(request);
633
634                if (result != WIFI_SUCCESS) {
635                    ALOGE("Failed to register get momory dump response; result = %d", result);
636                }
637            } else {
638                ALOGE("dump event missing dump length attribute");
639                return NL_SKIP;
640            }
641        }
642        return NL_OK;
643    }
644};
645
646wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
647        wifi_alert_handler handler)
648{
649    wifi_handle handle = getWifiHandle(iface);
650    SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
651    ALOGI("Alert start, handle = %p", handle);
652
653    wifi_register_cmd(handle, id, cmd);
654    return (wifi_error)cmd->start();
655}
656
657
658///////////////////////////////////////////////////////////////////////////////
659class MemoryDumpCommand: public WifiCommand
660{
661    wifi_firmware_memory_dump_handler mHandler;
662    int mBuffSize;
663    char *mBuff;
664
665public:
666    MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler)
667        : WifiCommand(iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL)
668    { }
669
670    int start() {
671        ALOGD("Start memory dump command");
672        WifiRequest request(familyId(), ifaceId());
673
674        int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP);
675        if (result != WIFI_SUCCESS) {
676            ALOGE("Failed to create trigger fw memory dump request; result = %d", result);
677            return result;
678        }
679
680        result = requestResponse(request);
681        if (result != WIFI_SUCCESS) {
682            ALOGE("Failed to register trigger memory dump response; result = %d", result);
683        }
684        return result;
685    }
686
687    virtual int handleResponse(WifiEvent& reply) {
688        ALOGD("In MemoryDumpCommand::handleResponse");
689
690        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
691            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
692            return NL_SKIP;
693        }
694
695        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
696        int len = reply.get_vendor_data_len();
697
698        ALOGD("len = %d", len);
699        if (vendor_data == NULL || len == 0) {
700            ALOGE("no vendor data in memory dump response; ignoring it");
701            return NL_SKIP;
702        }
703
704        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
705            if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
706                mBuffSize = it.get_u32();
707
708                if (mBuff)
709                    free(mBuff);
710                mBuff = (char *)malloc(mBuffSize);
711                if (!mBuff) {
712                    ALOGE("Buffer allocation failed");
713                    return NL_SKIP;
714                }
715                WifiRequest request(familyId(), ifaceId());
716                int result = request.create(GOOGLE_OUI, LOGGER_GET_MEM_DUMP);
717                if (result != WIFI_SUCCESS) {
718                    ALOGE("Failed to create get memory dump request; result = %d", result);
719                    free(mBuff);
720                    return NL_SKIP;
721                }
722
723                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
724                result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);
725                if (result != WIFI_SUCCESS) {
726                    ALOGE("Failed to put get memory dump request; result = %d", result);
727                    return result;
728                }
729                /* BUG: 1. should not be passing pointer to data, 2. should not assume pointer is 32 bits
730                result = request.put_u32(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint32_t)mBuff);
731                if (result != WIFI_SUCCESS) {
732                    ALOGE("Failed to put get memory dump request; result = %d", result);
733                    return result;
734                }
735                */
736                request.attr_end(data);
737
738                result = requestResponse(request);
739                if (result != WIFI_SUCCESS) {
740                    ALOGE("Failed to register get momory dump response; result = %d", result);
741                }
742            } else if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_DATA) {
743                ALOGI("Initiating memory dump callback");
744                if (mHandler.on_firmware_memory_dump) {
745                    (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize);
746                }
747                if (mBuff) {
748                    free(mBuff);
749                    mBuff = NULL;
750                }
751            } else {
752                ALOGW("Ignoring invalid attribute type = %d, size = %d",
753                        it.get_type(), it.get_len());
754            }
755        }
756        return NL_OK;
757    }
758
759    virtual int handleEvent(WifiEvent& event) {
760        /* NO events! */
761        return NL_SKIP;
762    }
763};
764
765/* API to collect a firmware memory dump for a given iface */
766wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface,
767        wifi_firmware_memory_dump_handler handler)
768{
769    MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler);
770    return (wifi_error)cmd->start();
771}
772
773