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