Merge KeystoneQ-ww-20190522

Change-Id: I03b64105c115f2d90fb39cb9e620350458daeed0
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..8051d5c
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,40 @@
+#############################################################################
+#
+# Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd
+#
+#############################################################################
+
+ifeq ($(CONFIG_SAMSUNG_SCSC_WIFIBT),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+LOCAL_C_INCLUDES += \
+        system/core/include/ \
+	external/libnl/include \
+        $(call include-path-for, libhardware_legacy)/hardware_legacy \
+        external/wpa_supplicant_8/src/drivers
+
+LOCAL_SRC_FILES := \
+	wifi_hal.cpp \
+	rtt.cpp \
+	common.cpp \
+	cpp_bindings.cpp \
+	gscan.cpp \
+	link_layer_stats.cpp \
+	wifi_offload.cpp \
+	roam.cpp \
+	wifi_logger.cpp \
+	wifi_nan.cpp
+
+LOCAL_MODULE := libwifi-hal-slsi
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/common.cpp b/common.cpp
new file mode 100755
index 0000000..e0de0bc
--- /dev/null
+++ b/common.cpp
@@ -0,0 +1,244 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+interface_info *getIfaceInfo(wifi_interface_handle handle)
+{
+    return (interface_info *)handle;
+}
+
+wifi_handle getWifiHandle(wifi_interface_handle handle)
+{
+    return getIfaceInfo(handle)->handle;
+}
+
+hal_info *getHalInfo(wifi_handle handle)
+{
+    return (hal_info *)handle;
+}
+
+hal_info *getHalInfo(wifi_interface_handle handle)
+{
+    return getHalInfo(getWifiHandle(handle));
+}
+
+wifi_handle getWifiHandle(hal_info *info)
+{
+    return (wifi_handle)info;
+}
+
+wifi_interface_handle getIfaceHandle(interface_info *info)
+{
+    return (wifi_interface_handle)info;
+}
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+    hal_info *info = (hal_info *)handle;
+
+    /* TODO: check for multiple handlers? */
+    pthread_mutex_lock(&info->cb_lock);
+
+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+    if (info->num_event_cb < info->alloc_event_cb) {
+        info->event_cb[info->num_event_cb].nl_cmd  = cmd;
+        info->event_cb[info->num_event_cb].vendor_id  = 0;
+        info->event_cb[info->num_event_cb].vendor_subcmd  = 0;
+        info->event_cb[info->num_event_cb].cb_func = func;
+        info->event_cb[info->num_event_cb].cb_arg  = arg;
+        /*
+        ALOGI("Successfully added event handler %p:%p for command %d at %d",
+                arg, func, cmd, info->num_event_cb);*/
+        info->num_event_cb++;
+        result = WIFI_SUCCESS;
+    }
+
+    pthread_mutex_unlock(&info->cb_lock);
+    return result;
+}
+
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+        uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+    hal_info *info = (hal_info *)handle;
+
+//ALOGD("GSCAN register handle wifi_register_vendor_handler %p", handle);
+    /* TODO: check for multiple handlers? */
+    pthread_mutex_lock(&info->cb_lock);
+    //ALOGI("Added event handler %p", info);
+
+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+    //    ALOGD("register_vendor_handler: handle = %p", handle);
+    if (info->num_event_cb < info->alloc_event_cb) {
+        info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;
+        info->event_cb[info->num_event_cb].vendor_id  = id;
+        info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;
+        info->event_cb[info->num_event_cb].cb_func = func;
+        info->event_cb[info->num_event_cb].cb_arg  = arg;
+        /*
+        ALOGI("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
+                arg, func, id, subcmd, info->num_event_cb);*/
+        info->num_event_cb++;
+        result = WIFI_SUCCESS;
+    }
+
+    pthread_mutex_unlock(&info->cb_lock);
+    return result;
+}
+
+void wifi_unregister_handler(wifi_handle handle, int cmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    if (cmd == NL80211_CMD_VENDOR) {
+        ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
+        return;
+    }
+
+    pthread_mutex_lock(&info->cb_lock);
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+        if (info->event_cb[i].nl_cmd == cmd) {
+            /*
+            ALOGI("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
+                    info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);*/
+
+            memmove(&info->event_cb[i], &info->event_cb[i+1],
+                (info->num_event_cb - i - 1) * sizeof(cb_info));
+            info->num_event_cb--;
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(&info->cb_lock);
+}
+
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    pthread_mutex_lock(&info->cb_lock);
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+
+        if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
+                && info->event_cb[i].vendor_id == id
+                && info->event_cb[i].vendor_subcmd == subcmd) {
+            /*
+            ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
+                    info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);*/
+            memmove(&info->event_cb[i], &info->event_cb[i+1],
+                (info->num_event_cb - i - 1) * sizeof(cb_info));
+            info->num_event_cb--;
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(&info->cb_lock);
+}
+
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    //ALOGD("registering command %d", id);
+
+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+    if (info->num_cmd < info->alloc_cmd) {
+        info->cmd[info->num_cmd].id   = id;
+        info->cmd[info->num_cmd].cmd  = cmd;
+        //ALOGI("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
+        info->num_cmd++;
+        result = WIFI_SUCCESS;
+    }
+
+    return result;
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+    hal_info *info = (hal_info *)handle;
+
+    //ALOGD("un-registering command %d", id);
+
+    WifiCommand *cmd = NULL;
+
+    for (int i = 0; i < info->num_cmd; i++) {
+        if (info->cmd[i].id == id) {
+            cmd = info->cmd[i].cmd;
+            memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+            info->num_cmd--;
+            //ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);
+            break;
+        }
+    }
+
+    return cmd;
+}
+
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
+{
+    hal_info *info = (hal_info *)handle;
+
+    WifiCommand *cmd = NULL;
+
+    for (int i = 0; i < info->num_cmd; i++) {
+        if (info->cmd[i].id == id) {
+            cmd = info->cmd[i].cmd;
+            break;
+        }
+    }
+
+    return cmd;
+}
+
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    for (int i = 0; i < info->num_cmd; i++) {
+        if (info->cmd[i].cmd == cmd) {
+            memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+            info->num_cmd--;
+            //ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);
+            break;
+        }
+    }
+}
+
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
+{
+	wifi_handle handle = getWifiHandle(iface);
+
+	WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+	//ALOGD("Cancel WifiCommand = %p", cmd);
+	if (cmd) {
+		cmd->cancel();
+		cmd->releaseRef();
+		return WIFI_SUCCESS;
+	}
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
diff --git a/common.h b/common.h
new file mode 100755
index 0000000..7f270a3
--- /dev/null
+++ b/common.h
@@ -0,0 +1,302 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_COMMON_H__
+#define __WIFI_HAL_COMMON_H__
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG  "WifiHAL"
+
+#include <utils/Log.h>
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define SOCKET_BUFFER_SIZE      (32768U)
+#define RECV_BUF_SIZE           (4096)
+#define DEFAULT_EVENT_CB_SIZE   (64)
+#define DEFAULT_CMD_SIZE        (64)
+#define DOT11_OUI_LEN             3
+
+typedef struct {
+	int num_bssid;
+	mac_addr bssids[MAX_BLACKLIST_BSSID];
+} wifi_bssid_params;
+
+/*
+ Vendor OUI - This is a unique identifier that identifies organization. Lets
+ code Android specific functions with Google OUI; although vendors can do more
+ with their own OUI's as well.
+ */
+
+const uint32_t GOOGLE_OUI = 0x001A11;
+/* TODO: define vendor OUI here */
+
+typedef enum {
+
+    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+    GSCAN_ATTRIBUTE_BASE_PERIOD,
+    GSCAN_ATTRIBUTE_BUCKETS_BAND,
+    GSCAN_ATTRIBUTE_BUCKET_ID,
+    GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+    GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+    GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+    GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+    GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+    GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+    GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS,
+    GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
+    GSCAN_ATTRIBUTE_REPORT_EVENTS,
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
+    GSCAN_ATTRIBUTE_NUM_CHANNELS,
+    GSCAN_ATTRIBUTE_CHANNEL_LIST,
+    GSCAN_ATTRIBUTE_SCAN_ID,
+    GSCAN_ATTRIBUTE_SCAN_FLAGS,
+    GSCAN_ATTRIBUTE_SCAN_BUCKET_BIT,
+
+    /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_SSID = 40,
+    GSCAN_ATTRIBUTE_BSSID,
+    GSCAN_ATTRIBUTE_CHANNEL,
+    GSCAN_ATTRIBUTE_RSSI,
+    GSCAN_ATTRIBUTE_TIMESTAMP,
+    GSCAN_ATTRIBUTE_RTT,
+    GSCAN_ATTRIBUTE_RTTSD,
+
+    /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
+    GSCAN_ATTRIBUTE_RSSI_LOW,
+    GSCAN_ATTRIBUTE_RSSI_HIGH,
+    GSCAN_ATTRIBUTE_HOTLIST_ELEM,
+    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+    GSCAN_ATTRIBUTE_CHANNEL_NUMBER,
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+    GSCAN_ATTRIBUTE_MIN_BREACHING,
+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+
+    GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 70,
+    GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
+    GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+
+    GSCAN_ATTRIBUTE_NUM_BSSID,
+    GSCAN_ATTRIBUTE_BLACKLIST_BSSID,
+
+    GSCAN_ATTRIBUTE_MAX
+
+} GSCAN_ATTRIBUTE;
+
+/*
+ This enum defines ranges for various commands; commands themselves
+ can be defined in respective feature headers; i.e. find gscan command
+ definitions in gscan.cpp
+ */
+
+typedef enum {
+    /* don't use 0 as a valid subcommand */
+    VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+    /* define all vendor startup commands between 0x0 and 0x0FFF */
+    VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+    VENDOR_NL80211_SUBCMD_RANGE_END   = 0x0FFF,
+
+    /* define all GScan related commands between 0x1000 and 0x10FF */
+    ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+    ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END   = 0x10FF,
+
+    /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+    ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+    ANDROID_NL80211_SUBCMD_NBD_RANGE_END   = 0x11FF,
+
+    /* define all RTT related commands between 0x1100 and 0x11FF */
+    ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+    ANDROID_NL80211_SUBCMD_RTT_RANGE_END   = 0x11FF,
+
+    ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+    ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END   = 0x12FF,
+
+    /* define all Logger related commands between 0x1400 and 0x14FF */
+    ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
+    ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END   = 0x14FF,
+
+    /* define all wifi offload related commands between 0x1400 and 0x14FF */
+    ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1400,
+    ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END   = 0x14FF,
+
+    /* Range for NAN commands */
+    ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1500,
+    ANDROID_NL80211_SUBCMD_NAN_RANGE_END   = 0x15FF,
+   /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+typedef enum {
+    SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+    SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS,
+    SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN,
+    SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN,
+    SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST,
+    SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST,
+    SLSI_NL80211_VENDOR_SUBCMD_GET_HOTLIST_RESULTS,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE,
+    SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS,
+    SLSI_NL80211_VENDOR_SUBCMD_START_KEEP_ALIVE_OFFLOAD,
+    SLSI_NL80211_VENDOR_SUBCMD_STOP_KEEP_ALIVE_OFFLOAD,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_BLACKLIST,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_EPNO_LIST,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_HS_LIST,
+    SLSI_NL80211_VENDOR_SUBCMD_RESET_HS_LIST,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_RSSI_MONITOR,
+    SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO,
+    SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO,
+    SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO,
+    SLSI_NL80211_VENDOR_SUBCMD_GET_FEATURE_SET,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_COUNTRY_CODE,
+    SLSI_NL80211_VENDOR_SUBCMD_CONFIGURE_ND_OFFLOAD,
+    SLSI_NL80211_VENDOR_SUBCMD_GET_ROAMING_CAPABILITIES,
+    SLSI_NL80211_VENDOR_SUBCMD_SET_ROAMING_STATE,
+
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_ENABLE = ANDROID_NL80211_SUBCMD_NAN_RANGE_START,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_DISABLE,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISH,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISHCANCEL,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBE,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBECANCEL,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_TXFOLLOWUP,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_CONFIG,
+    SLSI_NL80211_VENDOR_SUBCMD_NAN_CAPABILITIES,
+    SLSI_NL80211_VENDOR_SUBCMD_RTT_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+    SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_START,
+    SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_CANCEL
+} WIFI_SUB_COMMAND;
+
+typedef enum {
+    GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
+    GSCAN_EVENT_HOTLIST_RESULTS_FOUND,
+    GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
+    GSCAN_EVENT_FULL_SCAN_RESULTS,
+    GSCAN_EVENT_COMPLETE_SCAN,
+    GSCAN_EVENT_HOTLIST_RESULTS_LOST,
+    WIFI_SUBCMD_KEY_MGMT_ROAM_AUTH, /* Handled by supplicant. not in Wifi-HAL */
+    WIFI_HANGED_EVENT,
+    WIFI_EPNO_EVENT,
+    WIFI_HOTSPOT_MATCH,
+    WIFI_RSSI_REPORT_EVENT,
+    ENHANCE_LOGGER_RING_EVENT,
+    ENHANCE_LOGGER_MEM_DUMP_EVENT,
+    /* NAN events start */
+    SLSI_NAN_EVENT_RESPONSE,
+    SLSI_NAN_EVENT_PUBLISH_TERMINATED,
+    SLSI_NAN_EVENT_MATCH,
+    SLSI_NAN_EVENT_MATCH_EXPIRED,
+    SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED,
+    SLSI_NAN_EVENT_FOLLOWUP,
+    SLSI_NAN_EVENT_DISCOVERY_ENGINE,
+    SLSI_NAN_EVENT_DISABLED,
+    /* NAN events end */
+    SLSI_RTT_RESULT_EVENT,
+    SLSI_RTT_EVENT_COMPLETE
+
+} WIFI_EVENT;
+
+typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
+
+class WifiCommand;
+
+typedef struct {
+    int nl_cmd;
+    uint32_t vendor_id;
+    int vendor_subcmd;
+    nl_recvmsg_msg_cb_t cb_func;
+    void *cb_arg;
+} cb_info;
+
+typedef struct {
+    wifi_request_id id;
+    WifiCommand *cmd;
+} cmd_info;
+
+typedef struct {
+    wifi_handle handle;                             // handle to wifi data
+    char name[8+1];                                 // interface name + trailing null
+    int  id;                                        // id to use when talking to driver
+} interface_info;
+
+typedef struct {
+
+    struct nl_sock *cmd_sock;                       // command socket object
+    struct nl_sock *event_sock;                     // event socket object
+    int nl80211_family_id;                          // family id for 80211 driver
+    int cleanup_socks[2];                           // sockets used to implement wifi_cleanup
+
+    bool in_event_loop;                             // Indicates that event loop is active
+    bool clean_up;                                  // Indication to clean up the socket
+
+    wifi_internal_event_handler event_handler;      // default event handler
+    wifi_cleaned_up_handler cleaned_up_handler;     // socket cleaned up handler
+
+    cb_info *event_cb;                              // event callbacks
+    int num_event_cb;                               // number of event callbacks
+    int alloc_event_cb;                             // number of allocated callback objects
+    pthread_mutex_t cb_lock;                        // mutex for the event_cb access
+
+    cmd_info *cmd;                                  // Outstanding commands
+    int num_cmd;                                    // number of commands
+    int alloc_cmd;                                  // number of commands allocated
+
+    interface_info **interfaces;                    // array of interfaces
+    int num_interfaces;                             // number of interfaces
+
+
+    // add other details
+} hal_info;
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+            uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
+
+void wifi_unregister_handler(wifi_handle handle, int cmd);
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id);
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+
+interface_info *getIfaceInfo(wifi_interface_handle);
+wifi_handle getWifiHandle(wifi_interface_handle handle);
+hal_info *getHalInfo(wifi_handle handle);
+hal_info *getHalInfo(wifi_interface_handle handle);
+wifi_handle getWifiHandle(hal_info *info);
+wifi_interface_handle getIfaceHandle(interface_info *info);
+
+
+// some common macros
+
+#define min(x, y)       ((x) < (y) ? (x) : (y))
+#define max(x, y)       ((x) > (y) ? (x) : (y))
+
+#define NULL_CHECK_RETURN(ptr, str, ret) \
+    do { \
+        if (!(ptr)) { \
+            ALOGE("%s(): null pointer - #ptr (%s)\n", __FUNCTION__, str); \
+            return ret; \
+        } \
+    } while (0)
+#endif
+
diff --git a/cpp_bindings.cpp b/cpp_bindings.cpp
new file mode 100755
index 0000000..5ab68b1
--- /dev/null
+++ b/cpp_bindings.cpp
@@ -0,0 +1,694 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+#include <stdarg.h>
+
+#include <ctype.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+void appendFmt(char *buf, int &offset, const char *fmt, ...)
+{
+    va_list params;
+    va_start(params, fmt);
+    offset += vsprintf(buf + offset, fmt, params);
+    va_end(params);
+}
+
+#define C2S(x)  case x: return #x;
+
+static const char *cmdToString(int cmd)
+{
+	switch (cmd) {
+	C2S(NL80211_CMD_UNSPEC)
+	C2S(NL80211_CMD_GET_WIPHY)
+	C2S(NL80211_CMD_SET_WIPHY)
+	C2S(NL80211_CMD_NEW_WIPHY)
+	C2S(NL80211_CMD_DEL_WIPHY)
+	C2S(NL80211_CMD_GET_INTERFACE)
+	C2S(NL80211_CMD_SET_INTERFACE)
+	C2S(NL80211_CMD_NEW_INTERFACE)
+	C2S(NL80211_CMD_DEL_INTERFACE)
+	C2S(NL80211_CMD_GET_KEY)
+	C2S(NL80211_CMD_SET_KEY)
+	C2S(NL80211_CMD_NEW_KEY)
+	C2S(NL80211_CMD_DEL_KEY)
+	C2S(NL80211_CMD_GET_BEACON)
+	C2S(NL80211_CMD_SET_BEACON)
+	C2S(NL80211_CMD_START_AP)
+	C2S(NL80211_CMD_STOP_AP)
+	C2S(NL80211_CMD_GET_STATION)
+	C2S(NL80211_CMD_SET_STATION)
+	C2S(NL80211_CMD_NEW_STATION)
+	C2S(NL80211_CMD_DEL_STATION)
+	C2S(NL80211_CMD_GET_MPATH)
+	C2S(NL80211_CMD_SET_MPATH)
+	C2S(NL80211_CMD_NEW_MPATH)
+	C2S(NL80211_CMD_DEL_MPATH)
+	C2S(NL80211_CMD_SET_BSS)
+	C2S(NL80211_CMD_SET_REG)
+	C2S(NL80211_CMD_REQ_SET_REG)
+	C2S(NL80211_CMD_GET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MESH_CONFIG)
+	C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+	C2S(NL80211_CMD_GET_REG)
+	C2S(NL80211_CMD_GET_SCAN)
+	C2S(NL80211_CMD_TRIGGER_SCAN)
+	C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCAN_ABORTED)
+	C2S(NL80211_CMD_REG_CHANGE)
+	C2S(NL80211_CMD_AUTHENTICATE)
+	C2S(NL80211_CMD_ASSOCIATE)
+	C2S(NL80211_CMD_DEAUTHENTICATE)
+	C2S(NL80211_CMD_DISASSOCIATE)
+	C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+	C2S(NL80211_CMD_REG_BEACON_HINT)
+	C2S(NL80211_CMD_JOIN_IBSS)
+	C2S(NL80211_CMD_LEAVE_IBSS)
+	C2S(NL80211_CMD_TESTMODE)
+	C2S(NL80211_CMD_CONNECT)
+	C2S(NL80211_CMD_ROAM)
+	C2S(NL80211_CMD_DISCONNECT)
+	C2S(NL80211_CMD_SET_WIPHY_NETNS)
+	C2S(NL80211_CMD_GET_SURVEY)
+	C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+	C2S(NL80211_CMD_SET_PMKSA)
+	C2S(NL80211_CMD_DEL_PMKSA)
+	C2S(NL80211_CMD_FLUSH_PMKSA)
+	C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+	C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+	C2S(NL80211_CMD_REGISTER_FRAME)
+	C2S(NL80211_CMD_FRAME)
+	C2S(NL80211_CMD_FRAME_TX_STATUS)
+	C2S(NL80211_CMD_SET_POWER_SAVE)
+	C2S(NL80211_CMD_GET_POWER_SAVE)
+	C2S(NL80211_CMD_SET_CQM)
+	C2S(NL80211_CMD_NOTIFY_CQM)
+	C2S(NL80211_CMD_SET_CHANNEL)
+	C2S(NL80211_CMD_SET_WDS_PEER)
+	C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+	C2S(NL80211_CMD_JOIN_MESH)
+	C2S(NL80211_CMD_LEAVE_MESH)
+	C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+	C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+	C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+	C2S(NL80211_CMD_GET_WOWLAN)
+	C2S(NL80211_CMD_SET_WOWLAN)
+	C2S(NL80211_CMD_START_SCHED_SCAN)
+	C2S(NL80211_CMD_STOP_SCHED_SCAN)
+	C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+	C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+	C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+	C2S(NL80211_CMD_PMKSA_CANDIDATE)
+	C2S(NL80211_CMD_TDLS_OPER)
+	C2S(NL80211_CMD_TDLS_MGMT)
+	C2S(NL80211_CMD_UNEXPECTED_FRAME)
+	C2S(NL80211_CMD_PROBE_CLIENT)
+	C2S(NL80211_CMD_REGISTER_BEACONS)
+	C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+	C2S(NL80211_CMD_SET_NOACK_MAP)
+	C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+	C2S(NL80211_CMD_START_P2P_DEVICE)
+	C2S(NL80211_CMD_STOP_P2P_DEVICE)
+	C2S(NL80211_CMD_CONN_FAILED)
+	C2S(NL80211_CMD_SET_MCAST_RATE)
+	C2S(NL80211_CMD_SET_MAC_ACL)
+	C2S(NL80211_CMD_RADAR_DETECT)
+	C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+	C2S(NL80211_CMD_UPDATE_FT_IES)
+	C2S(NL80211_CMD_FT_EVENT)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+	C2S(NL80211_CMD_VENDOR)
+	default:
+		return "NL80211_CMD_UNKNOWN";
+	}
+}
+
+const char *attributeToString(int attribute)
+{
+    switch (attribute) {
+	C2S(NL80211_ATTR_UNSPEC)
+
+	C2S(NL80211_ATTR_WIPHY)
+	C2S(NL80211_ATTR_WIPHY_NAME)
+
+	C2S(NL80211_ATTR_IFINDEX)
+	C2S(NL80211_ATTR_IFNAME)
+	C2S(NL80211_ATTR_IFTYPE)
+
+	C2S(NL80211_ATTR_MAC)
+
+	C2S(NL80211_ATTR_KEY_DATA)
+	C2S(NL80211_ATTR_KEY_IDX)
+	C2S(NL80211_ATTR_KEY_CIPHER)
+	C2S(NL80211_ATTR_KEY_SEQ)
+	C2S(NL80211_ATTR_KEY_DEFAULT)
+
+	C2S(NL80211_ATTR_BEACON_INTERVAL)
+	C2S(NL80211_ATTR_DTIM_PERIOD)
+	C2S(NL80211_ATTR_BEACON_HEAD)
+	C2S(NL80211_ATTR_BEACON_TAIL)
+
+	C2S(NL80211_ATTR_STA_AID)
+	C2S(NL80211_ATTR_STA_FLAGS)
+	C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
+	C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
+	C2S(NL80211_ATTR_STA_VLAN)
+	C2S(NL80211_ATTR_STA_INFO)
+
+	C2S(NL80211_ATTR_WIPHY_BANDS)
+
+	C2S(NL80211_ATTR_MNTR_FLAGS)
+
+	C2S(NL80211_ATTR_MESH_ID)
+	C2S(NL80211_ATTR_STA_PLINK_ACTION)
+	C2S(NL80211_ATTR_MPATH_NEXT_HOP)
+	C2S(NL80211_ATTR_MPATH_INFO)
+
+	C2S(NL80211_ATTR_BSS_CTS_PROT)
+	C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
+	C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
+
+	C2S(NL80211_ATTR_HT_CAPABILITY)
+
+	C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
+
+	C2S(NL80211_ATTR_REG_ALPHA2)
+	C2S(NL80211_ATTR_REG_RULES)
+
+	C2S(NL80211_ATTR_MESH_CONFIG)
+
+	C2S(NL80211_ATTR_BSS_BASIC_RATES)
+
+	C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
+	C2S(NL80211_ATTR_WIPHY_FREQ)
+	C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
+
+	C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
+
+	C2S(NL80211_ATTR_MGMT_SUBTYPE)
+	C2S(NL80211_ATTR_IE)
+
+	C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
+
+	C2S(NL80211_ATTR_SCAN_FREQUENCIES)
+	C2S(NL80211_ATTR_SCAN_SSIDS)
+	C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
+	C2S(NL80211_ATTR_BSS)
+
+	C2S(NL80211_ATTR_REG_INITIATOR)
+	C2S(NL80211_ATTR_REG_TYPE)
+
+	C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
+
+	C2S(NL80211_ATTR_FRAME)
+	C2S(NL80211_ATTR_SSID)
+	C2S(NL80211_ATTR_AUTH_TYPE)
+	C2S(NL80211_ATTR_REASON_CODE)
+
+	C2S(NL80211_ATTR_KEY_TYPE)
+
+	C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
+	C2S(NL80211_ATTR_CIPHER_SUITES)
+
+	C2S(NL80211_ATTR_FREQ_BEFORE)
+	C2S(NL80211_ATTR_FREQ_AFTER)
+
+	C2S(NL80211_ATTR_FREQ_FIXED)
+
+
+	C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
+	C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
+	C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
+	C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
+
+	C2S(NL80211_ATTR_TIMED_OUT)
+
+	C2S(NL80211_ATTR_USE_MFP)
+
+	C2S(NL80211_ATTR_STA_FLAGS2)
+
+	C2S(NL80211_ATTR_CONTROL_PORT)
+
+	C2S(NL80211_ATTR_TESTDATA)
+
+	C2S(NL80211_ATTR_PRIVACY)
+
+	C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
+	C2S(NL80211_ATTR_STATUS_CODE)
+
+	C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
+	C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
+	C2S(NL80211_ATTR_WPA_VERSIONS)
+	C2S(NL80211_ATTR_AKM_SUITES)
+
+	C2S(NL80211_ATTR_REQ_IE)
+	C2S(NL80211_ATTR_RESP_IE)
+
+	C2S(NL80211_ATTR_PREV_BSSID)
+
+	C2S(NL80211_ATTR_KEY)
+	C2S(NL80211_ATTR_KEYS)
+
+	C2S(NL80211_ATTR_PID)
+
+	C2S(NL80211_ATTR_4ADDR)
+
+	C2S(NL80211_ATTR_SURVEY_INFO)
+
+	C2S(NL80211_ATTR_PMKID)
+	C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
+
+	C2S(NL80211_ATTR_DURATION)
+
+	C2S(NL80211_ATTR_COOKIE)
+
+	C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
+
+	C2S(NL80211_ATTR_TX_RATES)
+
+	C2S(NL80211_ATTR_FRAME_MATCH)
+
+	C2S(NL80211_ATTR_ACK)
+
+	C2S(NL80211_ATTR_PS_STATE)
+
+	C2S(NL80211_ATTR_CQM)
+
+	C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
+
+	C2S(NL80211_ATTR_AP_ISOLATE)
+
+	C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
+	C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
+
+	C2S(NL80211_ATTR_TX_FRAME_TYPES)
+	C2S(NL80211_ATTR_RX_FRAME_TYPES)
+	C2S(NL80211_ATTR_FRAME_TYPE)
+
+	C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+	C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
+
+	C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
+
+	C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
+	C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
+
+	C2S(NL80211_ATTR_MCAST_RATE)
+
+	C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
+
+	C2S(NL80211_ATTR_BSS_HT_OPMODE)
+
+	C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
+
+	C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
+
+	C2S(NL80211_ATTR_MESH_SETUP)
+
+	C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
+	C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
+
+	C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
+	C2S(NL80211_ATTR_STA_PLINK_STATE)
+
+	C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
+	C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
+
+	C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
+
+	C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
+	C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
+
+	C2S(NL80211_ATTR_REKEY_DATA)
+
+	C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
+	C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
+
+	C2S(NL80211_ATTR_SCAN_SUPP_RATES)
+
+	C2S(NL80211_ATTR_HIDDEN_SSID)
+
+	C2S(NL80211_ATTR_IE_PROBE_RESP)
+	C2S(NL80211_ATTR_IE_ASSOC_RESP)
+
+	C2S(NL80211_ATTR_STA_WME)
+	C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
+
+	C2S(NL80211_ATTR_ROAM_SUPPORT)
+
+	C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
+	C2S(NL80211_ATTR_MAX_MATCH_SETS)
+
+	C2S(NL80211_ATTR_PMKSA_CANDIDATE)
+
+	C2S(NL80211_ATTR_TX_NO_CCK_RATE)
+
+	C2S(NL80211_ATTR_TDLS_ACTION)
+	C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
+	C2S(NL80211_ATTR_TDLS_OPERATION)
+	C2S(NL80211_ATTR_TDLS_SUPPORT)
+	C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
+
+	C2S(NL80211_ATTR_DEVICE_AP_SME)
+
+	C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
+
+	C2S(NL80211_ATTR_FEATURE_FLAGS)
+
+	C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
+
+	C2S(NL80211_ATTR_PROBE_RESP)
+
+	C2S(NL80211_ATTR_DFS_REGION)
+
+	C2S(NL80211_ATTR_DISABLE_HT)
+	C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
+
+	C2S(NL80211_ATTR_NOACK_MAP)
+
+	C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
+
+	C2S(NL80211_ATTR_RX_SIGNAL_DBM)
+
+	C2S(NL80211_ATTR_BG_SCAN_PERIOD)
+
+	C2S(NL80211_ATTR_WDEV)
+
+	C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
+
+	C2S(NL80211_ATTR_CONN_FAILED_REASON)
+
+	C2S(NL80211_ATTR_SAE_DATA)
+
+	C2S(NL80211_ATTR_VHT_CAPABILITY)
+
+	C2S(NL80211_ATTR_SCAN_FLAGS)
+
+	C2S(NL80211_ATTR_CHANNEL_WIDTH)
+	C2S(NL80211_ATTR_CENTER_FREQ1)
+	C2S(NL80211_ATTR_CENTER_FREQ2)
+
+	C2S(NL80211_ATTR_P2P_CTWINDOW)
+	C2S(NL80211_ATTR_P2P_OPPPS)
+
+	C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
+
+	C2S(NL80211_ATTR_ACL_POLICY)
+
+	C2S(NL80211_ATTR_MAC_ADDRS)
+
+	C2S(NL80211_ATTR_MAC_ACL_MAX)
+
+	C2S(NL80211_ATTR_RADAR_EVENT)
+
+	C2S(NL80211_ATTR_EXT_CAPA)
+	C2S(NL80211_ATTR_EXT_CAPA_MASK)
+
+	C2S(NL80211_ATTR_STA_CAPABILITY)
+	C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
+
+	C2S(NL80211_ATTR_PROTOCOL_FEATURES)
+	C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
+
+	C2S(NL80211_ATTR_DISABLE_VHT)
+	C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
+
+	C2S(NL80211_ATTR_MDID)
+	C2S(NL80211_ATTR_IE_RIC)
+
+	C2S(NL80211_ATTR_CRIT_PROT_ID)
+	C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
+
+	C2S(NL80211_ATTR_PEER_AID)
+
+
+	//S(NL80211_ATTR_VENDOR_ID)
+	C2S(NL80211_ATTR_VENDOR_SUBCMD)
+	C2S(NL80211_ATTR_VENDOR_DATA)
+	C2S(NL80211_ATTR_VENDOR_EVENTS)
+
+    default:
+        return "NL80211_ATTR_UNKNOWN";
+    }
+}
+
+void WifiEvent::log() {
+    parse();
+
+    byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
+    int len = genlmsg_attrlen(mHeader, 0);
+    ALOGD("cmd = %s, len = %d", get_cmdString(), len);
+    ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
+
+    for (int i = 0; i < len; i += 16) {
+        char line[81];
+        int linelen = min(16, len - i);
+        int offset = 0;
+        appendFmt(line, offset, "%02x", data[i]);
+        for (int j = 1; j < linelen; j++) {
+            appendFmt(line, offset, " %02x", data[i+j]);
+        }
+
+        for (int j = linelen; j < 16; j++) {
+            appendFmt(line, offset, "   ");
+        }
+
+        line[23] = '-';
+
+        appendFmt(line, offset, "  ");
+
+        for (int j = 0; j < linelen; j++) {
+            if (isprint(data[i+j])) {
+                appendFmt(line, offset, "%c", data[i+j]);
+            } else {
+                appendFmt(line, offset, "-");
+            }
+        }
+
+        ALOGD("%s", line);
+    }
+
+    for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
+        if (mAttributes[i] != NULL) {
+            ALOGD("found attribute %s", attributeToString(i));
+        }
+    }
+}
+
+const char *WifiEvent::get_cmdString() {
+    return cmdToString(get_cmd());
+}
+
+
+int WifiEvent::parse() {
+    if (mHeader != NULL) {
+        return WIFI_SUCCESS;
+    }
+    mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
+    int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
+          genlmsg_attrlen(mHeader, 0), NULL);
+
+    return result;
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+    mMsg = nlmsg_alloc();
+    if (mMsg != NULL) {
+        genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
+                hdrlen, flags, cmd, /* version = */ 0);
+        return WIFI_SUCCESS;
+    } else {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+int WifiRequest::create(uint32_t id, int subcmd) {
+    int res = create(NL80211_CMD_VENDOR);
+    if (res < 0) {
+        return res;
+    }
+
+    res = put_u32(NL80211_ATTR_VENDOR_ID, id);
+    if (res < 0) {
+        return res;
+    }
+
+    res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
+    if (res < 0) {
+        return res;
+    }
+
+    if (mIface != -1) {
+        res = set_iface_id(mIface);
+    }
+
+    return res;
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+	return NL_OK;
+}
+
+int WifiCommand::requestResponse() {
+    int err = create();                 /* create the message */
+    if (err < 0) {
+        return err;
+    }
+
+    return requestResponse(mMsg);
+}
+
+int WifiCommand::requestResponse(WifiRequest& request) {
+    int err = 0;
+
+    struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+    if (!cb)
+        goto out;
+
+    err = nl_send_auto_complete(mInfo->cmd_sock, request.getMessage());    /* send message */
+    if (err < 0)
+        goto out;
+
+    err = 1;
+
+    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, response_handler, this);
+
+    while (err > 0) {                   /* wait for reply */
+        int res = nl_recvmsgs(mInfo->cmd_sock, cb);
+        if (res) {
+            ALOGE("nl80211: %s->nl_recvmsgs failed: %d", __func__, res);
+        }
+    }
+out:
+    nl_cb_put(cb);
+    return err;
+}
+
+int WifiCommand::requestEvent(int cmd) {
+
+    int res = wifi_register_handler(wifiHandle(), cmd, event_handler, this);
+    if (res < 0) {
+        return res;
+    }
+
+    res = create();                                                 /* create the message */
+    if (res < 0)
+        goto out;
+
+    res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());    /* send message */
+    if (res < 0)
+        goto out;
+
+    res = mCondition.wait();
+    if (res < 0)
+        goto out;
+
+out:
+    wifi_unregister_handler(wifiHandle(), cmd);
+    return res;
+}
+
+int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
+
+    int res = wifi_register_vendor_handler(wifiHandle(), id, subcmd, event_handler, this);
+    if (res < 0) {
+        return res;
+    }
+
+    res = create();                                                 /* create the message */
+    if (res < 0)
+        goto out;
+
+    res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());    /* send message */
+    if (res < 0)
+        goto out;
+
+    res = mCondition.wait();
+    if (res < 0)
+        goto out;
+
+out:
+    wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+    return res;
+}
+
+/* Event handlers */
+int WifiCommand::response_handler(struct nl_msg *msg, void *arg) {
+    WifiCommand *cmd = (WifiCommand *)arg;
+    WifiEvent reply(msg);
+    int res = reply.parse();
+    if (res < 0) {
+        ALOGE("Failed to parse reply message = %d", res);
+        return NL_SKIP;
+    } else {
+        // reply.log();
+        return cmd->handleResponse(reply);
+    }
+}
+
+int WifiCommand::event_handler(struct nl_msg *msg, void *arg) {
+    WifiCommand *cmd = (WifiCommand *)arg;
+    WifiEvent event(msg);
+    int res = event.parse();
+    if (res < 0) {
+        ALOGE("Failed to parse event = %d", res);
+        res = NL_SKIP;
+    } else {
+        res = cmd->handleEvent(event);
+    }
+
+    cmd->mCondition.signal();
+    return res;
+}
+
+/* Other event handlers */
+int WifiCommand::valid_handler(struct nl_msg *msg, void *arg) {
+    int *err = (int *)arg;
+    *err = 0;
+    return NL_SKIP;
+}
+
+int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
+    int *err = (int *)arg;
+    *err = 0;
+    return NL_STOP;
+}
+
+int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
+    int *ret = (int *)arg;
+    *ret = 0;
+    return NL_SKIP;
+}
+
+int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
+    int *ret = (int *)arg;
+    *ret = err->error;
+
+    /*ALOGD("error_handler received : %d", err->error);*/
+    return NL_SKIP;
+}
diff --git a/cpp_bindings.h b/cpp_bindings.h
new file mode 100755
index 0000000..d1e1e5a
--- /dev/null
+++ b/cpp_bindings.h
@@ -0,0 +1,347 @@
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "sync.h"
+
+class WifiEvent
+{
+    /* TODO: remove this when nl headers are updated */
+    static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
+private:
+    struct nl_msg *mMsg;
+    struct genlmsghdr *mHeader;
+    struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
+
+public:
+    WifiEvent(nl_msg *msg) {
+        mMsg = msg;
+        mHeader = NULL;
+        memset(mAttributes, 0, sizeof(mAttributes));
+    }
+    ~WifiEvent() {
+        /* don't destroy mMsg; it doesn't belong to us */
+    }
+
+    void log();
+
+    int parse();
+
+    genlmsghdr *header() {
+        return mHeader;
+    }
+
+    int get_cmd() {
+        return mHeader->cmd;
+    }
+
+    int get_vendor_id() {
+        return get_u32(NL80211_ATTR_VENDOR_ID);
+    }
+
+    int get_vendor_subcmd() {
+        return get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+    }
+
+    void *get_vendor_data() {
+        return get_data(NL80211_ATTR_VENDOR_DATA);
+    }
+
+    int get_vendor_data_len() {
+        return get_len(NL80211_ATTR_VENDOR_DATA);
+    }
+
+    const char *get_cmdString();
+
+    nlattr ** attributes() {
+        return mAttributes;
+    }
+
+    nlattr *get_attribute(int attribute) {
+        return mAttributes[attribute];
+    }
+
+    uint8_t get_u8(int attribute) {
+        return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;
+    }
+
+    uint16_t get_u16(int attribute) {
+        return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;
+    }
+
+    uint32_t get_u32(int attribute) {
+        return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;
+    }
+
+    uint64_t get_u64(int attribute) {
+        return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;
+    }
+
+    int get_len(int attribute) {
+        return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;
+    }
+
+    void *get_data(int attribute) {
+        return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;
+    }
+
+private:
+    WifiEvent(const WifiEvent&);        // hide copy constructor to prevent copies
+};
+
+class nl_iterator {
+    struct nlattr *pos;
+    int rem;
+public:
+    nl_iterator(struct nlattr *attr) {
+        pos = (struct nlattr *)nla_data(attr);
+        rem = nla_len(attr);
+    }
+    bool has_next() {
+        return nla_ok(pos, rem);
+    }
+    void next() {
+        pos = (struct nlattr *)nla_next(pos, &(rem));
+    }
+    struct nlattr *get() {
+        return pos;
+    }
+    uint16_t get_type() {
+        return pos->nla_type;
+    }
+    uint8_t get_u8() {
+        return nla_get_u8(pos);
+    }
+    uint16_t get_u16() {
+        return nla_get_u16(pos);
+    }
+    uint32_t get_u32() {
+        return nla_get_u32(pos);
+    }
+    uint64_t get_u64() {
+        return nla_get_u64(pos);
+    }
+    void* get_data() {
+        return nla_data(pos);
+    }
+    int get_len() {
+        return nla_len(pos);
+    }
+private:
+    nl_iterator(const nl_iterator&);    // hide copy constructor to prevent copies
+};
+
+class WifiRequest
+{
+private:
+    int mFamily;
+    int mIface;
+    struct nl_msg *mMsg;
+
+public:
+    WifiRequest(int family) {
+        mMsg = NULL;
+        mFamily = family;
+        mIface = -1;
+    }
+
+    WifiRequest(int family, int iface) {
+        mMsg = NULL;
+        mFamily = family;
+        mIface = iface;
+    }
+
+    ~WifiRequest() {
+        destroy();
+    }
+
+    void destroy() {
+        if (mMsg) {
+            nlmsg_free(mMsg);
+            mMsg = NULL;
+        }
+    }
+
+    nl_msg *getMessage() {
+        return mMsg;
+    }
+
+    /* Command assembly helpers */
+    int create(int family, uint8_t cmd, int flags, int hdrlen);
+    int create(uint8_t cmd) {
+        return create(mFamily, cmd, 0, 0);
+    }
+
+    int create(uint32_t id, int subcmd);
+
+    int put(int attribute, void *ptr, unsigned len) {
+        return nla_put(mMsg, attribute, len, ptr);
+    }
+    int put_u8(int attribute, uint8_t value) {
+        return nla_put(mMsg, attribute, sizeof(value), &value);
+    }
+    int put_u16(int attribute, uint16_t value) {
+        return nla_put(mMsg, attribute, sizeof(value), &value);
+    }
+    int put_u32(int attribute, uint32_t value) {
+        return nla_put(mMsg, attribute, sizeof(value), &value);
+    }
+    int put_u64(int attribute, uint64_t value) {
+        return nla_put(mMsg, attribute, sizeof(value), &value);
+    }
+    int put_string(int attribute, const char *value) {
+        return nla_put(mMsg, attribute, strlen(value) + 1, value);
+    }
+    int put_addr(int attribute, mac_addr value) {
+        return nla_put(mMsg, attribute, sizeof(mac_addr), value);
+    }
+
+    struct nlattr * attr_start(int attribute) {
+        return nla_nest_start(mMsg, attribute);
+    }
+    void attr_end(struct nlattr *attr) {
+        nla_nest_end(mMsg, attr);
+    }
+
+    int set_iface_id(int ifindex) {
+        return put_u32(NL80211_ATTR_IFINDEX, ifindex);
+    }
+private:
+    WifiRequest(const WifiRequest&);        // hide copy constructor to prevent copies
+
+};
+
+class WifiCommand
+{
+protected:
+    hal_info *mInfo;
+    WifiRequest mMsg;
+    Condition mCondition;
+    wifi_request_id mId;
+    interface_info *mIfaceInfo;
+    int mRefs;
+public:
+    WifiCommand(wifi_handle handle, wifi_request_id id)
+            : mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)
+    {
+        mIfaceInfo = NULL;
+        mInfo = getHalInfo(handle);
+        // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+    }
+
+    WifiCommand(wifi_interface_handle iface, wifi_request_id id)
+            : mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id), mId(id), mRefs(1)
+    {
+        mIfaceInfo = getIfaceInfo(iface);
+        mInfo = getHalInfo(iface);
+        // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+    }
+
+    virtual ~WifiCommand() {
+        // ALOGD("WifiCommand %p destroyed", this);
+    }
+
+    wifi_request_id id() {
+        return mId;
+    }
+
+    virtual void addRef() {
+        __sync_add_and_fetch(&mRefs, 1);
+        //int refs = __sync_add_and_fetch(&mRefs, 1);
+        // ALOGD("addRef: WifiCommand %p has %d references", this, refs);
+    }
+
+    virtual void releaseRef() {
+        int refs = __sync_sub_and_fetch(&mRefs, 1);
+        if (refs == 0) {
+            delete this;
+        } else {
+            // ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);
+        }
+    }
+
+    virtual int create() {
+        /* by default there is no way to cancel */
+        //ALOGD("WifiCommand %p can't be created", this);
+        return WIFI_ERROR_NOT_SUPPORTED;
+    }
+
+    virtual int cancel() {
+        /* by default there is no way to cancel */
+        return WIFI_ERROR_NOT_SUPPORTED;
+    }
+
+    int requestResponse();
+    int requestEvent(int cmd);
+    int requestVendorEvent(uint32_t id, int subcmd);
+    int requestResponse(WifiRequest& request);
+
+protected:
+    wifi_handle wifiHandle() {
+        return getWifiHandle(mInfo);
+    }
+
+    wifi_interface_handle ifaceHandle() {
+        return getIfaceHandle(mIfaceInfo);
+    }
+
+    int familyId() {
+        return mInfo->nl80211_family_id;
+    }
+
+    int ifaceId() {
+        return mIfaceInfo->id;
+    }
+
+    /* Override this method to parse reply and dig out data; save it in the object */
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGI("skipping a response");
+        return NL_SKIP;
+    }
+
+    /* Override this method to parse event and dig out data; save it in the object */
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("skipping an event");
+        return NL_SKIP;
+    }
+
+    int registerHandler(int cmd) {
+        return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);
+    }
+
+    void unregisterHandler(int cmd) {
+        wifi_unregister_handler(wifiHandle(), cmd);
+    }
+
+    int registerVendorHandler(uint32_t id, int subcmd) {
+        return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
+    }
+
+    void unregisterVendorHandler(uint32_t id, int subcmd) {
+        wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+    }
+
+private:
+    WifiCommand(const WifiCommand& );           // hide copy constructor to prevent copies
+
+    /* Event handling */
+    static int response_handler(struct nl_msg *msg, void *arg);
+
+    static int event_handler(struct nl_msg *msg, void *arg);
+
+    /* Other event handlers */
+    static int valid_handler(struct nl_msg *msg, void *arg);
+
+    static int ack_handler(struct nl_msg *msg, void *arg);
+
+    static int finish_handler(struct nl_msg *msg, void *arg);
+
+    static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
+};
+
+/* nl message processing macros (required to pass C++ type checks) */
+
+#define for_each_attr(pos, nla, rem) \
+    for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
+        nla_ok(pos, rem); \
+        pos = (nlattr *)nla_next(pos, &(rem)))
+
diff --git a/gscan.cpp b/gscan.cpp
new file mode 100755
index 0000000..89d6dd6
--- /dev/null
+++ b/gscan.cpp
@@ -0,0 +1,1350 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+    EPNO_ATTRIBUTE_MINIMUM_5G_RSSI,
+    EPNO_ATTRIBUTE_MINIMUM_2G_RSSI,
+    EPNO_ATTRIBUTE_INITIAL_SCORE_MAX,
+    EPNO_ATTRIBUTE_CUR_CONN_BONUS,
+    EPNO_ATTRIBUTE_SAME_NETWORK_BONUS,
+    EPNO_ATTRIBUTE_SECURE_BONUS,
+    EPNO_ATTRIBUTE_5G_BONUS,
+    EPNO_ATTRIBUTE_SSID_NUM,
+    EPNO_ATTRIBUTE_SSID_LIST,
+    EPNO_ATTRIBUTE_SSID,
+    EPNO_ATTRIBUTE_SSID_LEN,
+    EPNO_ATTRIBUTE_FLAGS,
+    EPNO_ATTRIBUTE_AUTH,
+    EPNO_ATTRIBUTE_MAX
+} EPNO_ATTRIBUTE;
+
+typedef enum {
+    EPNO_ATTRIBUTE_HS_PARAM_LIST,
+    EPNO_ATTRIBUTE_HS_NUM,
+    EPNO_ATTRIBUTE_HS_ID,
+    EPNO_ATTRIBUTE_HS_REALM,
+    EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS,
+    EPNO_ATTRIBUTE_HS_PLMN,
+    EPNO_ATTRIBUTE_HS_MAX
+} EPNO_HS_ATTRIBUTE;
+
+
+class GetCapabilitiesCommand : public WifiCommand
+{
+    wifi_gscan_capabilities *mCapabilities;
+public:
+    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
+        : WifiCommand(iface, 0), mCapabilities(capabitlites)
+    {
+        memset(mCapabilities, 0, sizeof(*mCapabilities));
+    }
+
+    virtual int create() {
+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES);
+        if (ret < 0) {
+            ALOGE("NL message creation failed");
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+
+        memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+
+        return NL_OK;
+    }
+};
+
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+        wifi_gscan_capabilities *capabilities)
+{
+    GetCapabilitiesCommand command(handle, capabilities);
+    return (wifi_error) command.requestResponse();
+}
+
+class GetChannelListCommand : public WifiCommand
+{
+    wifi_channel *channels;
+    int max_channels;
+    int *num_channels;
+    int band;
+public:
+    GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
+        int num_max_ch, int band)
+        : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),
+        band(band)
+    {
+        memset(channels, 0, sizeof(wifi_channel) * max_channels);
+    }
+    virtual int create() {
+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS);
+        if (ret < 0) {
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
+        if (ret < 0) {
+            return ret;
+        }
+
+        mMsg.attr_end(data);
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int num_channels_to_copy = 0;
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetChannelList response; ignoring it");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
+                num_channels_to_copy = it.get_u32();
+                /*ALOGD("Got channel list with %d channels", num_channels_to_copy);*/
+                if(num_channels_to_copy > max_channels)
+                    num_channels_to_copy = max_channels;
+                *num_channels = num_channels_to_copy;
+            } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
+                memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
+            } else {
+                ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                        it.get_type(), it.get_len());
+            }
+        }
+
+        return NL_OK;
+    }
+};
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
+        int band, int max_channels, wifi_channel *channels, int *num_channels)
+{
+    GetChannelListCommand command(handle, channels, num_channels,
+                                        max_channels, band);
+    return (wifi_error) command.requestResponse();
+}
+/////////////////////////////////////////////////////////////////////////////
+
+/* helper functions */
+
+/*
+static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
+{
+    memset(results, 0, sizeof(wifi_scan_result) * num);
+
+    int i = 0;
+    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
+
+        nlattr *sc_data = (nlattr *) it.get_data();
+        wifi_scan_result *result = results + i;
+
+        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
+            int type = it2.get_type();
+            if (type == GSCAN_ATTRIBUTE_SSID) {
+                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
+                result->ssid[it2.get_len()] = 0;
+            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
+                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
+            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
+                result->ts = it2.get_u64();
+            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
+                result->ts = it2.get_u16();
+            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
+                result->rssi = it2.get_u8();
+            } else if (type == GSCAN_ATTRIBUTE_RTT) {
+                result->rtt = it2.get_u64();
+            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
+                result->rtt_sd = it2.get_u64();
+            }
+        }
+
+    }
+
+    if (i >= num) {
+        ALOGE("Got too many results; skipping some");
+    }
+
+    return i;
+}
+*/
+
+int createFeatureRequest(WifiRequest& request, int subcmd) {
+
+    int result = request.create(GOOGLE_OUI, subcmd);
+    if (result < 0) {
+        return result;
+    }
+
+    return WIFI_SUCCESS;
+}
+
+class ScanCommand : public WifiCommand
+{
+    wifi_scan_cmd_params *mParams;
+    wifi_scan_result_handler mHandler;
+    static unsigned mGlobalFullScanBuckets;
+public:
+    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
+                wifi_scan_result_handler handler)
+        : WifiCommand(iface, id), mParams(params), mHandler(handler)
+    { }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold_percent);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS, mParams->report_threshold_num_scans);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
+        if (result < 0) {
+            return result;
+        }
+
+        for (int i = 0; i < mParams->num_buckets; i++) {
+            nlattr * bucket = request.attr_start(i);    // next bucket
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
+                    mParams->buckets[i].band);
+            if (result < 0) {
+                return result;
+            }
+
+            if (mParams->buckets[i].report_events == 0) {
+                mParams->buckets[i].report_events = REPORT_EVENTS_EACH_SCAN;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
+                    mParams->buckets[i].report_events);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+                    mParams->buckets[i].num_channels);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
+                    mParams->buckets[i].base);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+                    mParams->buckets[i].max_period);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
+                    mParams->buckets[i].step_count);
+            if (result < 0) {
+                return result;
+            }
+
+            if (mParams->buckets[i].num_channels) {
+                nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
+                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
+                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
+                    if (result < 0) {
+                        return result;
+                    }
+                }
+                request.attr_end(channels);
+            }
+
+            request.attr_end(bucket);
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int createStartRequest(WifiRequest& request) {
+        return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
+    }
+
+    int createStopRequest(WifiRequest& request) {
+        return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);
+    }
+
+    int start() {
+        ALOGD("starting Gscan");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create setup request; result = %d", result);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+
+        int nBuckets = 0;
+        for (int i = 0; i < mParams->num_buckets; i++) {
+            if (mParams->buckets[i].report_events & REPORT_EVENTS_FULL_RESULTS) {
+                nBuckets++;
+            }
+        }
+
+        if (nBuckets != 0) {
+           ALOGI("Full scan requested with nBuckets = %d", nBuckets);
+           registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+        }
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to start scan; result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+            return result;
+        }
+
+
+        return result;
+    }
+
+    virtual int cancel() {
+        ALOGD("Stopping Gscan");
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createStopRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create stop request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to stop scan; result = %d", result);
+            }
+        }
+
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        //event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        unsigned int len = event.get_vendor_data_len();
+        int event_id = event.get_vendor_subcmd();
+
+        if(event_id == GSCAN_EVENT_COMPLETE_SCAN) {
+            if (vendor_data == NULL || len != 4) {
+                ALOGE("Scan complete type not mentioned!");
+                return NL_SKIP;
+            }
+            wifi_scan_event evt_type;
+
+            evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
+            if(*mHandler.on_scan_event)
+                (*mHandler.on_scan_event)(id(), evt_type);
+        } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
+            uint32_t bucket_scanned = 0;
+            wifi_scan_result *scan_result = NULL;
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_BUCKET_BIT) {
+                    bucket_scanned = it.get_u32();
+                } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
+                    if (it.get_len() >= (int)sizeof(*scan_result))
+                        scan_result = (wifi_scan_result *)it.get_data();
+                }
+            }
+            if (scan_result) {
+                if(*mHandler.on_full_scan_result)
+                    (*mHandler.on_full_scan_result)(id(), scan_result, bucket_scanned);
+/*
+                    ALOGD("%-32s\t", scan_result->ssid);
+                    ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", scan_result->bssid[0], scan_result->bssid[1],
+                            scan_result->bssid[2], scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
+                    ALOGD("%d\t", scan_result->rssi);
+                    ALOGD("%d\t", scan_result->channel);
+                    ALOGD("%lld\t", scan_result->ts);
+                    ALOGD("%lld\t", scan_result->rtt);
+                    ALOGD("%lld\n", scan_result->rtt_sd);
+*/
+            }
+        }
+        return NL_SKIP;
+    }
+};
+
+unsigned ScanCommand::mGlobalFullScanBuckets = 0;
+
+wifi_error wifi_start_gscan(
+        wifi_request_id id,
+        wifi_interface_handle iface,
+        wifi_scan_cmd_params params,
+        wifi_scan_result_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
+    wifi_register_cmd(handle, id, cmd);
+    return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    if(id == -1) {
+        wifi_scan_result_handler handler;
+        wifi_scan_cmd_params dummy_params;
+        memset(&handler, 0, sizeof(handler));
+
+        ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+
+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+    if (cmd) {
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
+class GetScanResultsCommand : public WifiCommand {
+    wifi_cached_scan_results *mScans;
+    int mMax;
+    int *mNum;
+    int mRetrieved;
+    byte mFlush;
+    int mCompleted;
+    static const int MAX_RESULTS = 320;
+    wifi_scan_result mScanResults[MAX_RESULTS];
+    int mNextScanResult;
+public:
+    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
+            wifi_cached_scan_results *results, int max, int *num)
+        : WifiCommand(iface, -1), mScans(results), mMax(max), mNum(num),
+                mRetrieved(0), mFlush(flush), mCompleted(0)
+    {
+        memset(mScanResults,0,sizeof(mScanResults));
+        mNextScanResult = 0;
+    }
+
+    int createRequest(WifiRequest& request, int num, byte flush) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int execute() {
+        WifiRequest request(familyId(), ifaceId());
+
+        for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
+            int result = createRequest(request, (mMax - mRetrieved), mFlush);
+            if (result < 0) {
+                ALOGE("failed to create request");
+                return result;
+            }
+
+            int prev_retrieved = mRetrieved;
+
+            result = requestResponse(request);
+
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to retrieve scan results; result = %d", result);
+                return result;
+            }
+
+            if (mRetrieved == prev_retrieved || mCompleted) {
+                /* no more items left to retrieve */
+                break;
+            }
+
+            request.destroy();
+        }
+
+        ALOGE("GetScanResults read %d results", mRetrieved);
+        *mNum = mRetrieved;
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetScanResults response; ignoring it");
+            return NL_SKIP;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
+                mCompleted = it.get_u8();
+                //ALOGD("retrieved mCompleted flag : %d", mCompleted);
+            } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
+                int scan_id = 0, flags = 0, num = 0;
+                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
+                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
+                        scan_id = it2.get_u32();
+                        //ALOGD("retrieved scan_id : 0x%0x", scan_id);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
+                        flags = it2.get_u8();
+                        //ALOGD("retrieved scan_flags : 0x%0x", flags);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
+                        num = it2.get_u32();
+                        //ALOGD("retrieved num_results: %d", num);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
+                        if (mRetrieved >= mMax) {
+                            ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
+                            break;
+                        }
+                        num = it2.get_len() / sizeof(wifi_scan_result);
+                        num = min(MAX_RESULTS - mNextScanResult, num);
+                        num = min((int)MAX_AP_CACHE_PER_SCAN, num);
+                        memcpy(mScanResults + mNextScanResult, it2.get_data(),
+                                sizeof(wifi_scan_result) * num);
+                        /*
+                        wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
+                        for (int i = 0; i < num; i++) {
+                            wifi_scan_result *result = results + i;
+                            ALOGD("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x  %04d", i,
+                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
+                                result->bssid[3], result->bssid[4], result->bssid[5],
+                                result->rssi);
+                        }*/
+                        mScans[mRetrieved].scan_id = scan_id;
+                        mScans[mRetrieved].flags = flags;
+                        mScans[mRetrieved].num_results = num;
+                        //ALOGD("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
+                        memcpy(mScans[mRetrieved].results,
+                                &(mScanResults[mNextScanResult]), num * sizeof(wifi_scan_result));
+                        mNextScanResult += num;
+                        mRetrieved++;
+                    } else {
+                        ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                                it.get_type(), it.get_len());
+                    }
+                }
+            } else {
+                ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                        it.get_type(), it.get_len());
+            }
+        }
+
+        return NL_OK;
+    }
+};
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
+        int max, wifi_cached_scan_results *results, int *num) {
+    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
+    return (wifi_error)cmd->execute();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class BssidHotlistCommand : public WifiCommand
+{
+private:
+    wifi_bssid_hotlist_params mParams;
+    wifi_hotlist_ap_found_handler mHandler;
+    static const int MAX_RESULTS = 64;
+    wifi_scan_result mResults[MAX_RESULTS];
+public:
+    BssidHotlistCommand(wifi_interface_handle handle, int id,
+            wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+        : WifiCommand(handle, id), mParams(params), mHandler(handler)
+    {
+            memset(mResults, 0, sizeof(mResults));
+    }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+        for (int i = 0; i < mParams.num_bssid; i++) {
+            nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
+            if (attr2 == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+        return result;
+    }
+
+    int createTeardownRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        return result;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGE("Failed to execute hotlist setup request, result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+        /* create set hotlist message with empty hotlist */
+        WifiRequest request(familyId(), ifaceId());
+        int result = createTeardownRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        int event_id = event.get_vendor_subcmd();
+        //event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("No scan results found");
+            return NL_SKIP;
+        }
+
+
+        int num = len / sizeof(wifi_scan_result);
+        num = min(MAX_RESULTS, num);
+        memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
+
+        if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
+            ALOGD("FOUND %d hotlist APs", num);
+            if (*mHandler.on_hotlist_ap_found)
+                (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
+        } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {
+            ALOGD("LOST %d hotlist APs", num);
+            if (*mHandler.on_hotlist_ap_lost)
+                (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
+        }
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
+    wifi_register_cmd(handle, id, cmd);
+    return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+    if (cmd) {
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SignificantWifiChangeCommand : public WifiCommand
+{
+    typedef struct {
+        mac_addr bssid;                     // BSSID
+        wifi_channel channel;               // channel frequency in MHz
+        int num_rssi;                       // number of rssi samples
+        wifi_rssi rssi[8];                   // RSSI history in db
+    } wifi_significant_change_result_internal;
+
+private:
+    wifi_significant_change_params mParams;
+    wifi_significant_change_handler mHandler;
+    static const int MAX_RESULTS = 64;
+    wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
+    wifi_significant_change_result *mResults[MAX_RESULTS];
+public:
+    SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
+            wifi_significant_change_params params, wifi_significant_change_handler handler)
+        : WifiCommand(handle, id), mParams(params), mHandler(handler)
+    {
+        memset(mResultsBuffer,0,sizeof(mResultsBuffer));
+        memset(mResults,0,sizeof(mResults));
+    }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
+
+        for (int i = 0; i < mParams.num_bssid; i++) {
+
+            nlattr *attr2 = request.attr_start(i);
+            if (attr2 == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+
+        return result;
+    }
+
+    int createTeardownRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE);
+        if (result < 0) {
+            return result;
+        }
+
+        return result;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGE("failed to set significant wifi change %d", result);
+            return result;
+        }
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+        /* create set significant change monitor message with empty hotlist */
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createTeardownRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("No scan results found");
+            return NL_SKIP;
+        }
+
+        typedef struct {
+            uint16_t channel;
+            mac_addr bssid;
+            int16_t rssi_history[8];
+        } ChangeInfo;
+
+        int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
+        ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
+
+        for (int i = 0; i < num; i++) {
+            memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
+            mResultsBuffer[i].channel = ci[i].channel;
+            /* Driver sends N samples and the rest 8-N are filled 0x7FFF
+             * N = no of rssi samples to average sent in significant change request. */
+            int num_rssi = 0;
+            for (int j = 0; j < 8; j++) {
+                if (ci[i].rssi_history[j] == 0x7FFF) {
+                    num_rssi = j;
+                    break;
+                }
+                mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
+            }
+            mResultsBuffer[i].num_rssi = num_rssi;
+            mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
+        }
+
+        if (num != 0) {
+            (*mHandler.on_significant_change)(id(), num, mResults);
+        } else {
+            ALOGW("No significant change reported");
+        }
+
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+        wifi_significant_change_params params, wifi_significant_change_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
+            iface, id, params, handler);
+    wifi_register_cmd(handle, id, cmd);
+    return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+    if (cmd) {
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
+class ePNOCommand : public WifiCommand
+{
+private:
+    wifi_epno_params  *epno_params;
+    wifi_epno_handler mHandler;
+    wifi_scan_result  mResults;
+public:
+    ePNOCommand(wifi_interface_handle handle, int id,
+            wifi_epno_params *params, wifi_epno_handler handler)
+        : WifiCommand(handle, id), mHandler(handler)
+    {
+        epno_params = params;
+        memset(&mResults,0,sizeof(wifi_scan_result));
+    }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_EPNO_LIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (epno_params == NULL) {
+            result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, 0);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(data);
+            return result;
+        }
+        result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_5G_RSSI, epno_params->min5GHz_rssi);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_2G_RSSI, epno_params->min24GHz_rssi);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(EPNO_ATTRIBUTE_INITIAL_SCORE_MAX, epno_params->initial_score_max);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(EPNO_ATTRIBUTE_CUR_CONN_BONUS, epno_params->current_connection_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(EPNO_ATTRIBUTE_SAME_NETWORK_BONUS, epno_params->same_network_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(EPNO_ATTRIBUTE_SECURE_BONUS, epno_params->secure_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(EPNO_ATTRIBUTE_5G_BONUS, epno_params->band5GHz_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, epno_params->num_networks);
+        if (result < 0) {
+            return result;
+        }
+
+       ALOGI("ePNO [min5GHz_rssi:%d min24GHz_rssi:%d initial_score_max:%d current_connection_bonus:%d same_network_bonus:%d secure_bonus:%d band5GHz_bonus:%d num_networks:%d]",
+         epno_params->min5GHz_rssi,
+         epno_params->min24GHz_rssi,
+         epno_params->initial_score_max,
+         epno_params->current_connection_bonus,
+         epno_params->same_network_bonus,
+         epno_params->secure_bonus,
+         epno_params->band5GHz_bonus,
+         epno_params->num_networks);
+
+        struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_SSID_LIST);
+        for (int i = 0; i < epno_params->num_networks; i++) {
+            nlattr *attr2 = request.attr_start(i);
+            if (attr2 == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+            result = request.put_u16(EPNO_ATTRIBUTE_FLAGS, epno_params->networks[i].flags);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(EPNO_ATTRIBUTE_AUTH, epno_params->networks[i].auth_bit_field);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(EPNO_ATTRIBUTE_SSID_LEN, strlen(epno_params->networks[i].ssid));
+            if (result < 0) {
+                return result;
+            }
+            result = request.put(EPNO_ATTRIBUTE_SSID, epno_params->networks[i].ssid, strlen(epno_params->networks[i].ssid));
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("ePNO num_network=%d", epno_params ? epno_params->num_networks : 0);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Failed: ePNO setup request, result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+            return result;
+        }
+
+        if (epno_params) {
+            registerVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+        }
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+        return 0;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        // event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+
+        mResults = *(wifi_scan_result *) event.get_vendor_data();
+        if (*mHandler.on_network_found)
+            (*mHandler.on_network_found)(id(), 1, &mResults);
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_epno_list(wifi_request_id id,
+                              wifi_interface_handle iface,
+                              const wifi_epno_params *epno_params,
+                              wifi_epno_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    ePNOCommand *cmd = new ePNOCommand(iface, id, (wifi_epno_params *)epno_params, handler);
+    wifi_register_cmd(handle, id, cmd);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+    }
+    return result;
+}
+
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    wifi_epno_handler handler;
+
+    handler.on_network_found = NULL;
+    ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler);
+    wifi_register_cmd(handle, id, cmd);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+    }
+    return result;
+}
+
+class HsListCommand : public WifiCommand
+{
+    int num_hs;
+    wifi_passpoint_network *mNetworks;
+    wifi_passpoint_event_handler mHandler;
+public:
+    HsListCommand(wifi_request_id id, wifi_interface_handle iface,
+        int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler)
+        : WifiCommand(iface, id), num_hs(num), mNetworks(hs_list),
+            mHandler(handler)
+    {
+    }
+
+    HsListCommand(wifi_request_id id, wifi_interface_handle iface,
+        int num)
+        : WifiCommand(iface, id), num_hs(num), mNetworks(NULL)
+    {
+        mHandler.on_passpoint_network_found = NULL;
+    }
+
+    int createRequest(WifiRequest& request, int val) {
+        int result;
+
+        if (val) {
+            result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_HS_LIST);
+            result = request.put_u32(EPNO_ATTRIBUTE_HS_NUM, num_hs);
+            if (result < 0) {
+                return result;
+            }
+            nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+            struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_HS_PARAM_LIST);
+            for (int i = 0; i < num_hs; i++) {
+                nlattr *attr2 = request.attr_start(i);
+                if (attr2 == NULL) {
+                    return WIFI_ERROR_OUT_OF_MEMORY;
+                }
+                result = request.put_u32(EPNO_ATTRIBUTE_HS_ID, mNetworks[i].id);
+                if (result < 0) {
+                    return result;
+                }
+                result = request.put(EPNO_ATTRIBUTE_HS_REALM, mNetworks[i].realm, 256);
+                if (result < 0) {
+                    return result;
+                }
+                result = request.put(EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS, mNetworks[i].roamingConsortiumIds, 128);
+                if (result < 0) {
+                    return result;
+                }
+                result = request.put(EPNO_ATTRIBUTE_HS_PLMN, mNetworks[i].plmn, 3);
+                if (result < 0) {
+                    return result;
+                }
+                request.attr_end(attr2);
+            }
+            request.attr_end(attr);
+            request.attr_end(data);
+        }else {
+            result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_HS_LIST);
+            if (result < 0) {
+                return result;
+            }
+        }
+
+        return WIFI_SUCCESS;
+    }
+
+    int start() {
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, num_hs);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to set ANQPO networks; result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int cancel() {
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, 0);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to reset ANQPO networks;result = %d", result);
+            }
+        }
+
+        unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        unsigned int len = event.get_vendor_data_len();
+        if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
+            ALOGE("ERROR: No scan results found");
+            return NL_SKIP;
+        }
+
+        wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
+        byte *anqp = (byte *)result + offsetof(wifi_scan_result, ie_data) + result->ie_length;
+        int networkId = *(int *)anqp;
+        anqp += sizeof(int);
+        int anqp_len = *(u16 *)anqp;
+        anqp += sizeof(u16);
+
+        if(*mHandler.on_passpoint_network_found)
+            (*mHandler.on_passpoint_network_found)(id(), networkId, result, anqp_len, anqp);
+
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+        wifi_passpoint_network *networks, wifi_passpoint_event_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    HsListCommand *cmd = new HsListCommand(id, iface, num, networks, handler);
+
+    wifi_register_cmd(handle, id, cmd);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+    }
+    return result;
+}
+
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle   handle = getWifiHandle(iface);
+    wifi_error    result;
+    HsListCommand *cmd = (HsListCommand *)(wifi_get_cmd(handle, id));
+
+    if (cmd == NULL) {
+        cmd = new HsListCommand(id, iface, 0);
+        wifi_register_cmd(handle, id, cmd);
+    }
+    result = (wifi_error)cmd->cancel();
+    wifi_unregister_cmd(handle, id);
+    return result;
+}
diff --git a/link_layer_stats.cpp b/link_layer_stats.cpp
new file mode 100755
index 0000000..bfdeac8
--- /dev/null
+++ b/link_layer_stats.cpp
@@ -0,0 +1,274 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+
+    LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD = 1,
+    LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING,
+    LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK,
+    LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST,
+
+    LSTATS_ATTRIBUTE_MAX
+
+} LSTATS_ATTRIBUTE;
+
+class LinkLayerStatsCommand : public WifiCommand
+{
+    wifi_link_layer_params mParams;
+    u32 mStatsClearReqMask;
+    u32 *mStatsClearRspMask;
+    u8 mStopReq;
+    u8 *mStopRsp;
+public:
+    LinkLayerStatsCommand(wifi_interface_handle handle, wifi_link_layer_params params)
+        : WifiCommand(handle, 0), mParams(params)
+    {
+        mStatsClearReqMask = 0;
+        mStatsClearRspMask = 0;
+        mStopReq = 0 ;
+        mStopRsp = NULL;
+
+    }
+
+    LinkLayerStatsCommand(wifi_interface_handle handle,
+        u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
+        : WifiCommand(handle, 0), mStatsClearReqMask(stats_clear_req_mask), mStatsClearRspMask(stats_clear_rsp_mask),
+        mStopReq(stop_req), mStopRsp(stop_rsp)
+    {
+        memset(&mParams,0,sizeof(wifi_link_layer_params));
+    }
+
+    int createSetRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u32(LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD, mParams.mpdu_size_threshold);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING, mParams.aggressive_statistics_gathering);
+        if (result < 0) {
+            return result;
+        }
+        request.attr_end(data);
+        return result;
+    }
+
+    int createClearRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK, mStatsClearReqMask);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST, mStopReq);
+        if (result < 0) {
+            return result;
+        }
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGD("Starting Link Layer Statistics measurement (%d, %d)", mParams.mpdu_size_threshold, mParams.aggressive_statistics_gathering);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetRequest(request);
+        if (result < 0) {
+            ALOGE("failed to set Link Layer Statistics (result:%d)", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGE("failed to Set Link Layer Statistics (result:%d)", result);
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int clear() {
+        ALOGD("Clearing Link Layer Statistics (%d, %d)", mStatsClearReqMask, mStopReq);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createClearRequest(request);
+        if (result < 0) {
+            ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+
+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params)
+{
+    LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, params);
+    wifi_error result = (wifi_error)command->start();
+    if (result != WIFI_SUCCESS) {
+        ALOGE("failed to Set link layer stats (result:%d)", result);
+    }
+    return result;
+}
+
+wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
+        u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
+{
+    LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, stats_clear_req_mask, stats_clear_rsp_mask, stop_req, stop_rsp);
+    wifi_error result = (wifi_error)command->clear();
+    if (result != WIFI_SUCCESS) {
+        ALOGE("failed to Clear link layer stats (result:%d)", result);
+        *stats_clear_rsp_mask = 0;
+        *stop_rsp = 0;
+    } else {
+        *stats_clear_rsp_mask = stats_clear_req_mask;
+        *stop_rsp = stop_req;
+    }
+    return result;
+}
+
+
+class GetLinkStatsCommand : public WifiCommand
+{
+    wifi_stats_result_handler mHandler;
+    wifi_interface_handle iface;
+public:
+    GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
+        : WifiCommand(iface, 0), mHandler(handler)
+    {
+        this->iface = iface;
+    }
+
+    virtual int create() {
+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO);
+        if (ret < 0) {
+            ALOGE("Failed to create %x - %d", SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO, ret);
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+        int id = reply.get_vendor_id();
+        u8 *data = (u8 *)reply.get_vendor_data();
+        int num_radios = 0, i = 0;
+        num_radios = data[0];
+        data += sizeof(data[0]);
+
+        // assuming max peers is 16
+        wifi_iface_stat *iface_stat = (wifi_iface_stat *) malloc(sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * 16);
+        if (!iface_stat) {
+            ALOGE("Memory alloc failed for iface_stat in response handler!!!");
+            return NL_SKIP;
+        }
+
+        // max channel is 39 (14 2.4GHz and 25 5GHz)
+        wifi_radio_stat *radio_stat = (wifi_radio_stat *) malloc((num_radios * sizeof(wifi_radio_stat)) + sizeof(wifi_channel_stat) * 39);
+        wifi_radio_stat *radio_stat2;
+        radio_stat2 = radio_stat;
+        if (!radio_stat) {
+            ALOGE("Memory alloc failed for radio_stat in response handler!!!");
+            free(iface_stat);
+            return NL_SKIP;
+        }
+
+        /* Data sent from driver does not contain num_tx_levels and tx_time per level. So copy
+         * radio data in two parts - 1st part until num_tx_levels and 2nd part from rx_time.
+         * channel data is copied separately
+         */
+        int radio_data_len1,radio_data_len2;
+        radio_data_len1 = (u8 *)&(radio_stat->num_tx_levels) - (u8*)radio_stat;
+        radio_data_len2 = (u8 *)(radio_stat->channels) - (u8*)&(radio_stat->rx_time);
+
+        //kernel is 64 bit. if userspace is 64 bit, typecastting buffer works else, make corrections
+        if (sizeof(iface_stat->iface) == 8) {
+            memcpy(iface_stat, data, sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers);
+            data += sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers;
+        } else {
+            /* for 64 bit kernel ad 32 bit user space, there is 4 byte extra at the begining and another 4 byte pad after 80 bytes
+             * so remove first 4 and 81-84 bytes from NL buffer.*/
+            data += 4;
+            memcpy(iface_stat, data, 80);
+            data += 80 + 4; //for allignment skip 4 bytes
+            memcpy(((u8 *)iface_stat) + 80, data, sizeof(wifi_iface_stat) - 80);
+            data += sizeof(wifi_iface_stat) - 80;
+            memcpy(iface_stat->peer_info, data, sizeof(wifi_peer_info) * iface_stat->num_peers);
+            data += sizeof(wifi_peer_info) * iface_stat->num_peers;
+        }
+        for (i = 0; i < num_radios; i++) {
+            memcpy(radio_stat2, data, radio_data_len1);
+            data += radio_data_len1;
+            memcpy(&radio_stat2->rx_time, data, radio_data_len2);
+            data += radio_data_len2;
+            memcpy(radio_stat2->channels, data, sizeof(wifi_channel_stat)* radio_stat2->num_channels);
+            radio_stat2->num_tx_levels = 0;
+            radio_stat2->tx_time_per_levels = NULL;
+            data += sizeof(wifi_channel_stat)* radio_stat2->num_channels;
+            radio_stat2=(wifi_radio_stat *) ((u8 *)radio_stat2+ sizeof(wifi_radio_stat) +
+                        (sizeof(wifi_channel_stat) * radio_stat2->num_channels ));
+        }
+        iface_stat->iface = iface;
+        (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat);
+        free(iface_stat);
+        free(radio_stat);
+        return NL_OK;
+    }
+};
+
+wifi_error wifi_get_link_stats(wifi_request_id id,
+        wifi_interface_handle iface, wifi_stats_result_handler handler)
+{
+    GetLinkStatsCommand command(iface, handler);
+    return (wifi_error) command.requestResponse();
+}
+
+
diff --git a/roam.cpp b/roam.cpp
new file mode 100755
index 0000000..0993ec7
--- /dev/null
+++ b/roam.cpp
@@ -0,0 +1,224 @@
+#include <stdint.h>

+#include <stddef.h>

+#include <fcntl.h>

+#include <sys/socket.h>

+#include <netlink/genl/genl.h>

+#include <netlink/genl/family.h>

+#include <netlink/genl/ctrl.h>

+#include <linux/rtnetlink.h>

+#include <netpacket/packet.h>

+#include <linux/filter.h>

+#include <linux/errqueue.h>

+

+#include <linux/pkt_sched.h>

+#include <netlink/object-api.h>

+#include <netlink/netlink.h>

+#include <netlink/socket.h>

+#include <netlink/handlers.h>

+

+#include "sync.h"

+

+#define LOG_TAG  "WifiHAL"

+

+#include <utils/Log.h>

+

+#include "wifi_hal.h"

+#include "common.h"

+#include "cpp_bindings.h"

+

+#define REQUEST_ID_MAX 1000

+#define get_requestid() ((arc4random()%REQUEST_ID_MAX) + 1)

+

+enum roam_attributes {

+    SLSI_ATTR_ROAM_CAPABILITY_BLACKLIST_SIZE,

+    SLSI_ATTR_ROAM_CAPABILITY_WHITELIST_SIZE,

+    SLSI_ATTR_ROAM_STATE

+};

+

+class BssidBlacklistCommand : public WifiCommand

+{

+private:

+    wifi_bssid_params *mParams;

+public:

+    BssidBlacklistCommand(wifi_interface_handle handle, int id,

+            wifi_bssid_params *params)

+        : WifiCommand(handle, id), mParams(params)

+    { }

+     int createRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_BLACKLIST);

+        if (result < 0) {

+            return result;

+        }

+

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BSSID, mParams->num_bssid);

+        if (result < 0) {

+            return result;

+        }

+

+        for (int i = 0; i < mParams->num_bssid; i++) {

+            result = request.put_addr(GSCAN_ATTRIBUTE_BLACKLIST_BSSID, mParams->bssids[i]);

+            if (result < 0) {

+                return result;

+            }

+        }

+        request.attr_end(data);

+        return result;

+    }

+

+    int start() {

+        WifiRequest request(familyId(), ifaceId());

+        int result = createRequest(request);

+        if (result < 0) {

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result < 0) {

+            ALOGE("Failed to execute bssid blacklist request, result = %d", result);

+            return result;

+        }

+

+        return result;

+    }

+

+

+    virtual int handleResponse(WifiEvent& reply) {

+        /* Nothing to do on response! */

+        return NL_SKIP;

+    }

+};

+

+wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,

+        wifi_bssid_params params)

+{

+    BssidBlacklistCommand *cmd = new BssidBlacklistCommand(iface, id, &params);

+    wifi_error result = (wifi_error)cmd->start();

+    //release the reference of command as well

+    cmd->releaseRef();

+    return result;

+}

+

+

+class RoamingCapabilitiesCommand : public WifiCommand

+{

+private:

+    wifi_roaming_capabilities *mCaps;

+

+public:

+    RoamingCapabilitiesCommand(wifi_interface_handle handle, wifi_roaming_capabilities *caps)

+        : WifiCommand(handle, 0) {

+        mCaps = caps;

+    }

+

+    virtual int create() {

+        int ret;

+

+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_ROAMING_CAPABILITIES);

+        if (ret < 0) {

+             ALOGE("Can't create message to send to driver - %d", ret);

+             return ret;

+        }

+        return WIFI_SUCCESS;

+

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+

+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+            ALOGD("Ignore reply; cmd = %d", reply.get_cmd());

+            return NL_SKIP;

+        }

+

+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = reply.get_vendor_data_len();

+

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("vendor data in GetFeatureSetCommand missing!!");

+            return NL_SKIP;

+        }

+

+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+            switch(it.get_type()) {

+                case SLSI_ATTR_ROAM_CAPABILITY_BLACKLIST_SIZE:

+                    mCaps->max_blacklist_size = it.get_u32();

+                    break;

+                case SLSI_ATTR_ROAM_CAPABILITY_WHITELIST_SIZE:

+                    mCaps->max_whitelist_size = it.get_u32();

+                    break;

+                default :

+                    break;

+            }

+        }

+        return NL_OK;

+    }

+};

+

+wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,

+                                         wifi_roaming_capabilities *caps)

+{

+    RoamingCapabilitiesCommand cmd(handle, caps);

+    return (wifi_error) cmd.requestResponse();

+}

+

+class RoamingStateCommand : public WifiCommand

+{

+private:

+    fw_roaming_state_t mRoamingState;

+

+public:

+    RoamingStateCommand(wifi_interface_handle handle, fw_roaming_state_t roaming_state)

+        : WifiCommand(handle, 0) {

+        mRoamingState = roaming_state;

+    }

+

+    virtual int create() {

+        int ret;

+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_ROAMING_STATE);

+        if (ret < 0) {

+             ALOGE("Can't create message to send to driver - %d", ret);

+             return ret;

+        }

+

+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);

+        ret = mMsg.put_u8(SLSI_ATTR_ROAM_STATE, mRoamingState);

+        if (ret < 0) {

+            return ret;

+        }

+        mMsg.attr_end(data);

+        return WIFI_SUCCESS;

+    }

+};

+

+wifi_error wifi_enable_firmware_roaming(wifi_interface_handle handle, fw_roaming_state_t state) {

+    RoamingStateCommand cmd(handle, state);

+    wifi_error ret = (wifi_error) cmd.requestResponse();

+    return ret;

+}

+

+wifi_error wifi_configure_roaming(wifi_interface_handle iface, wifi_roaming_config *roaming_config)

+{

+    wifi_error ret;

+    int requestId;

+    wifi_bssid_params bssid_params;

+

+    if (!roaming_config) {

+        ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);

+        return WIFI_ERROR_INVALID_ARGS;

+   }

+

+    /* Generate request id randomly*/

+   requestId = get_requestid();

+   bssid_params.num_bssid = roaming_config->num_blacklist_bssid;

+

+   memcpy(bssid_params.bssids, roaming_config->blacklist_bssid,

+           (bssid_params.num_bssid * sizeof(mac_addr)));

+

+    ret = wifi_set_bssid_blacklist(requestId, iface, bssid_params);

+    if (ret != WIFI_SUCCESS) {

+        ALOGE("%s: Failed to configure blacklist bssids", __FUNCTION__);

+        return WIFI_ERROR_UNKNOWN;

+    }

+

+    return ret;

+}

diff --git a/rtt.cpp b/rtt.cpp
new file mode 100755
index 0000000..2c9114d
--- /dev/null
+++ b/rtt.cpp
@@ -0,0 +1,632 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+
+#include <string>
+#include "nl80211_copy.h"
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+using namespace std;
+
+typedef enum {
+    SLSI_RTT_ATTRIBUTE_TARGET_CNT = 0,
+    SLSI_RTT_ATTRIBUTE_TARGET_INFO,
+    SLSI_RTT_ATTRIBUTE_TARGET_MAC,
+    SLSI_RTT_ATTRIBUTE_TARGET_TYPE,
+    SLSI_RTT_ATTRIBUTE_TARGET_PEER,
+    SLSI_RTT_ATTRIBUTE_TARGET_CHAN_WIDTH,
+    SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ,
+    SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ0,
+    SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ1,
+    SLSI_RTT_ATTRIBUTE_TARGET_PERIOD,
+    SLSI_RTT_ATTRIBUTE_TARGET_NUM_BURST,
+    SLSI_RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+    SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+    SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+    SLSI_RTT_ATTRIBUTE_TARGET_LCI,
+    SLSI_RTT_ATTRIBUTE_TARGET_LCR,
+    SLSI_RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+    SLSI_RTT_ATTRIBUTE_TARGET_PREAMBLE,
+    SLSI_RTT_ATTRIBUTE_TARGET_BW,
+    SLSI_RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+    SLSI_RTT_ATTRIBUTE_RESULTS_PER_TARGET,
+    SLSI_RTT_ATTRIBUTE_RESULT_CNT,
+    SLSI_RTT_ATTRIBUTE_RESULT,
+    SLSI_RTT_ATTRIBUTE_TARGET_ID
+} SLSI_RTT_ATTRIBUTE;
+
+enum slsi_rtt_event_attributes {
+	SLSI_RTT_EVENT_ATTR_ADDR     = 0,
+	SLSI_RTT_EVENT_ATTR_BURST_NUM,
+	SLSI_RTT_EVENT_ATTR_MEASUREMENT_NUM,
+	SLSI_RTT_EVENT_ATTR_SUCCESS_NUM,
+	SLSI_RTT_EVENT_ATTR_NUM_PER_BURST_PEER,
+	SLSI_RTT_EVENT_ATTR_STATUS,
+	SLSI_RTT_EVENT_ATTR_RETRY_AFTER_DURATION,
+	SLSI_RTT_EVENT_ATTR_TYPE,
+	SLSI_RTT_EVENT_ATTR_RSSI,
+	SLSI_RTT_EVENT_ATTR_RSSI_SPREAD,
+	SLSI_RTT_EVENT_ATTR_TX_PREAMBLE,
+	SLSI_RTT_EVENT_ATTR_TX_NSS,
+	SLSI_RTT_EVENT_ATTR_TX_BW,
+	SLSI_RTT_EVENT_ATTR_TX_MCS,
+	SLSI_RTT_EVENT_ATTR_TX_RATE,
+	SLSI_RTT_EVENT_ATTR_RX_PREAMBLE,
+	SLSI_RTT_EVENT_ATTR_RX_NSS,
+	SLSI_RTT_EVENT_ATTR_RX_BW,
+	SLSI_RTT_EVENT_ATTR_RX_MCS,
+	SLSI_RTT_EVENT_ATTR_RX_RATE,
+	SLSI_RTT_EVENT_ATTR_RTT,
+	SLSI_RTT_EVENT_ATTR_RTT_SD,
+	SLSI_RTT_EVENT_ATTR_RTT_SPREAD,
+	SLSI_RTT_EVENT_ATTR_DISTANCE_MM,
+	SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM,
+	SLSI_RTT_EVENT_ATTR_DISTANCE_SPREAD_MM,
+	SLSI_RTT_EVENT_ATTR_TIMESTAMP_US,
+	SLSI_RTT_EVENT_ATTR_BURST_DURATION_MSN,
+	SLSI_RTT_EVENT_ATTR_NEGOTIATED_BURST_NUM,
+	SLSI_RTT_EVENT_ATTR_LCI,
+	SLSI_RTT_EVENT_ATTR_LCR
+};
+
+struct dot11_rm_ie {
+    u8 id;
+    u8 len;
+    u8 token;
+    u8 mode;
+    u8 type;
+} __attribute__ ((packed));
+typedef struct dot11_rm_ie dot11_rm_ie_t;
+typedef struct strmap_entry {
+    int			id;
+    string		text;
+} strmap_entry_t;
+
+static const strmap_entry_t err_info[] = {
+    {RTT_STATUS_SUCCESS, string("Success")},
+    {RTT_STATUS_FAILURE, string("Failure")},
+    {RTT_STATUS_FAIL_NO_RSP, string("No reponse")},
+    {RTT_STATUS_FAIL_INVALID_TS, string("Invalid Timestamp")},
+    {RTT_STATUS_FAIL_PROTOCOL, string("Protocol error")},
+    {RTT_STATUS_FAIL_REJECTED, string("Rejected")},
+    {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, string("not scheduled")},
+    {RTT_STATUS_FAIL_SCHEDULE,  string("schedule failed")},
+    {RTT_STATUS_FAIL_TM_TIMEOUT, string("timeout")},
+    {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, string("AP is on difference channel")},
+    {RTT_STATUS_FAIL_NO_CAPABILITY, string("no capability")},
+    {RTT_STATUS_FAIL_BUSY_TRY_LATER, string("busy and try later")},
+    {RTT_STATUS_ABORTED, string("aborted")}
+};
+/*static const string get_err_info(int status)
+{
+    int i;
+    const strmap_entry_t *p_entry;
+    int num_entries = sizeof(err_info)/ sizeof(err_info[0]);
+    * scan thru the table till end 
+    p_entry = err_info;
+    for (i = 0; i < (int) num_entries; i++)
+    {
+        if (p_entry->id == status)
+            return p_entry->text;
+        p_entry++;		* next entry 
+    }
+    return "unknown error";			* not found 
+}*/
+class RttCommand : public WifiCommand
+{
+    int rtt_id;
+    unsigned numTargetDevice;
+    int mCompleted;
+    int currentIdx;
+    int totalCnt;
+    static const int MAX_RESULTS = 1024;
+    wifi_rtt_result *rttResults[MAX_RESULTS];
+    wifi_rtt_config *rttParams;
+    wifi_rtt_event_handler rttHandler;
+public:
+    RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
+            wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+        : WifiCommand(iface, id), rtt_id(id), numTargetDevice(num_rtt_config), rttParams(rtt_config),
+        rttHandler(handler)
+    {
+        memset(rttResults, 0, sizeof(rttResults));
+        currentIdx = 0;
+        mCompleted = 0;
+        totalCnt = 0;
+    }
+
+    RttCommand(wifi_interface_handle iface, int id)
+        : WifiCommand(iface, id), rtt_id(id), rttParams(NULL)
+    {
+        rttHandler.on_rtt_results = NULL;
+        memset(rttResults, 0, sizeof(rttResults));
+        currentIdx = 0;
+        mCompleted = 0;
+        totalCnt = 0;
+        numTargetDevice = 0;
+    }
+ int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_START);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+	result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_ID, rtt_id);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_CNT, numTargetDevice);
+		ALOGI("numTargetDevice %d\n",numTargetDevice);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *rtt_config = request.attr_start(SLSI_RTT_ATTRIBUTE_TARGET_INFO);
+        for (unsigned i = 0; i < numTargetDevice; i++) {
+            nlattr *attr2 = request.attr_start(i);
+
+            result = request.put_addr(SLSI_RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
+			ALOGI("mac_addr %p\n",rttParams[i].addr);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
+			ALOGI("\trtt_type %d\n",rttParams[i].type);
+            if (result < 0) {
+                return result;
+            }
+
+	     result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
+			ALOGI("\trtt_peer %d\n",rttParams[i].peer);
+            if (result < 0) {
+                return result;
+            	}
+		result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ, rttParams[i].channel.center_freq);
+			ALOGI("\trtt_ primary channel_freq %d\n",rttParams[i].channel.center_freq);
+            if (result < 0) {
+                return result;
+            }
+		result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_WIDTH, rttParams[i].channel.width);
+			ALOGI("\trtt_channel width:%d\n",rttParams[i].channel.width);
+            if (result < 0) {
+                return result;
+            }
+		result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ0, rttParams[i].channel.center_freq0);
+			ALOGI("\trtt_channel_freq 0:%d\n",rttParams[i].channel.center_freq0);
+            if (result < 0) {
+                return result;
+            }
+		result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ1, rttParams[i].channel.center_freq1);
+			ALOGI("\trtt_channel_freq 1: %d\n",rttParams[i].channel.center_freq1);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
+			ALOGI("\tnum_burst %d\n",rttParams[i].num_burst);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+                    rttParams[i].num_frames_per_burst);
+			ALOGI("\tnum_frames_per_burst %d\n",rttParams[i].num_frames_per_burst);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+                    rttParams[i].num_retries_per_rtt_frame);
+			ALOGI("\tnum_retries_per_rtt_frame %d\n",rttParams[i].num_retries_per_rtt_frame);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+                    rttParams[i].num_retries_per_ftmr);
+			ALOGI("\tnum_retries_per_ftmr %d\n",rttParams[i].num_retries_per_ftmr);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_PERIOD,
+                    rttParams[i].burst_period);
+			ALOGI("\tburst_period %d\n",rttParams[i].burst_period);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+                    rttParams[i].burst_duration);
+			ALOGI("\tburst_duration %d\n",rttParams[i].burst_duration);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_LCI,
+                    rttParams[i].LCI_request);
+			ALOGI("\tLCI_request %d\n",rttParams[i].LCI_request);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_LCR,
+                    rttParams[i].LCR_request);
+			ALOGI("\tLCR_ request%d\n",rttParams[i].LCR_request);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_BW,
+                    rttParams[i].bw);
+			ALOGI("\tBW%d\n",rttParams[i].bw);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_PREAMBLE,
+                    rttParams[i].preamble);
+			ALOGI("\tpreamble%d\n",rttParams[i].preamble);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+	ALOGE("setup request created");
+        request.attr_end(rtt_config);
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_CANCEL);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+	 request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_ID, rtt_id);
+        request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+        for(unsigned i = 0; i < num_devices; i++) {
+            result = request.put_addr(SLSI_RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
+            if (result < 0) {
+                return result;
+            }
+        }
+        request.attr_end(data);
+        return result;
+    }
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create setup request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to configure RTT setup; result = %d", result);
+            return result;
+        }
+        registerVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+        registerVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+        return result;
+    }
+
+    virtual int cancel() {
+        ALOGD("Stopping RTT");
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createTeardownRequest(request, 0, NULL);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create stop request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to stop scan; result = %d", result);
+            }
+        }
+        ALOGE("RTT stopped");
+		/*This needs to be check */
+	  unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+        return WIFI_SUCCESS;
+    }
+
+    int cancel_specific(unsigned num_devices, mac_addr addr[]) {
+        ALOGE("Stopping RTT specific");
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createTeardownRequest(request, num_devices, addr);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create stop request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to stop RTT; result = %d", result);
+            }
+        }
+        ALOGE("Specific RTT stopped");
+	  /*This needs to be check */
+	  unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        currentIdx=0;
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int event_id = event.get_vendor_subcmd();
+        ALOGD("Got an RTT event with id:%d\n",event_id);
+        if(event_id == SLSI_RTT_EVENT_COMPLETE) {
+             ALOGD("RTT event complete\n");
+             unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+             WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
+              if (cmd)
+                  cmd->releaseRef();
+        } else if (event_id == SLSI_RTT_RESULT_EVENT) {
+             int result_cnt = 0;
+             int rtt_id = 0;
+             ALOGD("RTT result event\n");
+             for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                    if (it.get_type() == SLSI_RTT_ATTRIBUTE_RESULT_CNT) {
+                              result_cnt = it.get_u16();
+                              ALOGD("RTT results count : %d\n", result_cnt);
+                     }  else if (it.get_type() == SLSI_RTT_ATTRIBUTE_TARGET_ID) {
+                              rtt_id = it.get_u16();
+                              ALOGD("RTT target id : %d\n", rtt_id);
+                     } else if (it.get_type() == SLSI_RTT_ATTRIBUTE_RESULT) {
+                              ALOGD("RTT result attribute : %d\n", SLSI_RTT_ATTRIBUTE_RESULT);
+                              rttResults[currentIdx] =  (wifi_rtt_result *)malloc(sizeof(wifi_rtt_result));
+                               wifi_rtt_result *rtt_result = rttResults[currentIdx];
+                               if (rtt_result == NULL) {
+                                         ALOGE("failed to allocate the wifi_rtt_result\n");
+                                         unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+                                         break;
+                                }
+                               for(nl_iterator nl_nested_itr((struct nlattr *)it.get()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+                                  if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_ADDR) {
+                                         memcpy(rtt_result->addr, nl_nested_itr.get_data(), nl_nested_itr.get_len());
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_BURST_NUM) {
+                                         rtt_result->burst_num = (unsigned)nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_MEASUREMENT_NUM) {
+                                         rtt_result->measurement_number = (unsigned)nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_SUCCESS_NUM) {
+                                         rtt_result->success_number = (unsigned)nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_NUM_PER_BURST_PEER) {
+                                         rtt_result->number_per_burst_peer = (unsigned char)nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_STATUS) {
+                                         rtt_result->status = (wifi_rtt_status)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RETRY_AFTER_DURATION) {
+                                         rtt_result->retry_after_duration = (unsigned char)nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TYPE) {
+                                         rtt_result->type = (wifi_rtt_type)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RSSI) {
+                                         rtt_result->rssi = (wifi_rssi)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RSSI_SPREAD) {
+                                         rtt_result->rssi_spread= (wifi_rssi)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_PREAMBLE) {
+                                         rtt_result->tx_rate.preamble = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_NSS) {
+                                         rtt_result->tx_rate.nss = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_BW) {
+                                         rtt_result->tx_rate.bw = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_MCS) {
+                                         rtt_result->tx_rate.rateMcsIdx = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_RATE) {
+                                         rtt_result->tx_rate.bitrate = nl_nested_itr.get_u32();
+                                  }else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_PREAMBLE) {
+                                         rtt_result->rx_rate.preamble = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_NSS) {
+                                         rtt_result->rx_rate.nss = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_BW) {
+                                         rtt_result->rx_rate.bw = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_MCS) {
+                                         rtt_result->rx_rate.rateMcsIdx = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_RATE) {
+                                         rtt_result->rx_rate.bitrate = nl_nested_itr.get_u32();
+                                  }  else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT) {
+                                         rtt_result->rtt = (wifi_timespan)nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT_SD) {
+                                         rtt_result->rtt_sd = (wifi_timespan)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT_SPREAD) {
+                                         rtt_result->rtt_spread = (wifi_timespan)nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_MM) {
+                                         rtt_result->distance_mm = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM) {
+                                         rtt_result->distance_sd_mm = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_SPREAD_MM) {
+                                         rtt_result->distance_spread_mm = nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TIMESTAMP_US) {
+                                         rtt_result->ts = (wifi_timestamp)nl_nested_itr.get_u32();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_BURST_DURATION_MSN) {
+                                         rtt_result->burst_duration = nl_nested_itr.get_u16();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_NEGOTIATED_BURST_NUM) {
+                                         rtt_result->negotiated_burst_num = nl_nested_itr.get_u8();
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_LCI) {
+                                         u8 *lci_ie = (u8 *)nl_nested_itr.get_data();
+                                         rtt_result->LCI = (wifi_information_element *)malloc(sizeof(wifi_information_element) + nl_nested_itr.get_len() - 2);
+                                         rtt_result->LCI->id = lci_ie[0];
+                                         rtt_result->LCI->len =lci_ie[1];
+                                         memcpy(rtt_result->LCI->data, &lci_ie[2], nl_nested_itr.get_len() - 2);
+                                  } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_LCR) {
+                                          u8 *lcr_ie = (u8 *)nl_nested_itr.get_data();
+                                          rtt_result->LCR = (wifi_information_element *)malloc(sizeof(wifi_information_element) + nl_nested_itr.get_len() - 2);
+                                          rtt_result->LCR->id = lcr_ie[0];
+                                          rtt_result->LCR->len =lcr_ie[1];
+                                          memcpy(rtt_result->LCR->data, &lcr_ie[2], nl_nested_itr.get_len() - 2);
+                                  }
+                           }
+                           currentIdx++;
+                       }
+               }
+             (*rttHandler.on_rtt_results)(id() ,currentIdx, rttResults);
+              for (int i = 0; i < currentIdx; i++) {
+                     free(rttResults[i]);
+                     rttResults[i] = NULL;
+              }
+              currentIdx = 0;
+       }
+        ALOGE("Handled response for rtt config");
+        return NL_SKIP;
+    }
+};
+class GetRttCapabilitiesCommand : public WifiCommand
+	{
+	wifi_rtt_capabilities *mCapabilities;
+public:
+    GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
+        : WifiCommand(iface, 0), mCapabilities(capabitlites)
+    {
+        memset(mCapabilities, 0, sizeof(*mCapabilities));
+    }
+
+    virtual int create() {
+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_GET_CAPABILITIES);
+        if (ret < 0) {
+            ALOGE("NL message creation failed");
+            return ret;
+        }
+
+        return ret;
+    }
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+
+        memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+	  ALOGE("RTT capa response");
+        return NL_OK;
+    }
+};
+/*class GetRttResponderInfoCommand : public WifiCommand
+{
+    wifi_rtt_responder* mResponderInfo;
+public:
+    GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
+        : WifiCommand(iface, 0), mResponderInfo(responderInfo)
+    {
+        memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
+
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_GETAVAILCHANNEL);
+        if (ret < 0) {
+            return ret;
+        }
+
+       // return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGD("In GetRttResponderInfoCommand::handleResponse");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = reply.get_vendor_id();
+        int subcmd = reply.get_vendor_subcmd();
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+
+        ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+                sizeof(*mResponderInfo));
+
+        memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
+
+        return NL_OK;
+    }
+};*/
+
+	/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+        unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+{
+    ALOGE("Inside RTT RANGE range request");
+    wifi_handle handle = getWifiHandle(iface);
+    RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = wifi_register_cmd(handle, id, cmd);
+    if (result != WIFI_SUCCESS) {
+        cmd->releaseRef();
+        return result;
+    }
+    result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+        cmd->releaseRef();
+        return result;
+    }
+	ALOGE("wifi range request successfully executed");
+    return result;
+}
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id,  wifi_interface_handle iface,
+        unsigned num_devices, mac_addr addr[])
+{
+    if (!iface)
+             return WIFI_ERROR_UNINITIALIZED;
+    RttCommand *cmd = new RttCommand(iface, id);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    cmd->cancel_specific(num_devices, addr);
+    cmd->releaseRef();
+    return WIFI_SUCCESS;
+}
+
+/* API to get RTT capability */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
+        wifi_rtt_capabilities *capabilities)
+{
+	 ALOGE("Inside get rtt capabilities cap:%p iface:%p", capabilities, iface);
+	 if (!iface)
+             return WIFI_ERROR_UNINITIALIZED;
+	GetRttCapabilitiesCommand command(iface, capabilities);
+	return (wifi_error) command.requestResponse();
+
+}
+/* API to get the responder information */
+wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
+        wifi_rtt_responder* responderInfo)
+{
+    /*GetRttResponderInfoCommand command(iface, responderInfo);
+    return (wifi_error) command.requestResponse();*/
+    return WIFI_ERROR_NOT_SUPPORTED;
+
+}
diff --git a/sync.h b/sync.h
new file mode 100755
index 0000000..cea2ea9
--- /dev/null
+++ b/sync.h
@@ -0,0 +1,54 @@
+
+#include <pthread.h>
+
+#ifndef __WIFI_HAL_SYNC_H__
+#define __WIFI_HAL_SYNC_H__
+
+class Mutex
+{
+private:
+    pthread_mutex_t mMutex;
+public:
+    Mutex() {
+        pthread_mutex_init(&mMutex, NULL);
+    }
+    ~Mutex() {
+        pthread_mutex_destroy(&mMutex);
+    }
+    int tryLock() {
+        return pthread_mutex_trylock(&mMutex);
+    }
+    int lock() {
+        return pthread_mutex_lock(&mMutex);
+    }
+    void unlock() {
+        pthread_mutex_unlock(&mMutex);
+    }
+};
+
+class Condition
+{
+private:
+    pthread_cond_t mCondition;
+    pthread_mutex_t mMutex;
+
+public:
+    Condition() {
+        pthread_mutex_init(&mMutex, NULL);
+        pthread_cond_init(&mCondition, NULL);
+    }
+    ~Condition() {
+        pthread_cond_destroy(&mCondition);
+        pthread_mutex_destroy(&mMutex);
+    }
+
+    int wait() {
+        return pthread_cond_wait(&mCondition, &mMutex);
+    }
+
+    void signal() {
+        pthread_cond_signal(&mCondition);
+    }
+};
+
+#endif
\ No newline at end of file
diff --git a/wifi_hal.cpp b/wifi_hal.cpp
new file mode 100755
index 0000000..abcd1fd
--- /dev/null
+++ b/wifi_hal.cpp
@@ -0,0 +1,1029 @@
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/attr.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+
+#include <dirent.h>
+#include <net/if.h>
+
+#include "sync.h"
+
+#define LOG_TAG  "WifiHAL"
+
+#include <utils/Log.h>
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "roam.h"
+
+
+#define WIFI_HAL_CMD_SOCK_PORT       644
+#define WIFI_HAL_EVENT_SOCK_PORT     645
+
+#define FEATURE_SET                  0
+#define FEATURE_SET_MATRIX           1
+#define ATTR_NODFS_VALUE             3
+#define ATTR_COUNTRY_CODE            4
+
+static int internal_no_seq_check(nl_msg *msg, void *arg);
+static int internal_valid_message_handler(nl_msg *msg, void *arg);
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
+static int wifi_add_membership(wifi_handle handle, const char *group);
+static wifi_error wifi_init_interfaces(wifi_handle handle);
+
+typedef enum wifi_attr {
+    ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG,
+    ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI
+} wifi_attr_t;
+
+enum wifi_rssi_monitor_attr {
+    RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
+    RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
+    RSSI_MONITOR_ATTRIBUTE_START,
+};
+
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+                        iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface);
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
+
+/* Initialize/Cleanup */
+
+void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
+{
+    uint32_t pid = getpid() & 0x3FFFFF;
+    nl_socket_set_local_port(sock, pid + (port << 22));
+}
+
+class SetNdoffloadCommand : public WifiCommand {
+
+private:
+    u8 mEnable;
+public:
+    SetNdoffloadCommand(wifi_interface_handle handle, u8 enable)
+        : WifiCommand(handle, 0) {
+        mEnable = enable;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_CONFIGURE_ND_OFFLOAD);
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+            return WIFI_ERROR_NOT_AVAILABLE;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG, mEnable);
+        if (ret < 0) {
+        	return ret;
+        }
+	ALOGD("Driver message has been created successfully--> %d", mEnable);
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+static nl_sock * wifi_create_nl_socket(int port)
+{
+    struct nl_sock *sock = nl_socket_alloc();
+    if (sock == NULL) {
+        ALOGE("Could not create handle");
+        return NULL;
+    }
+
+    wifi_socket_set_local_port(sock, port);
+
+    if (nl_connect(sock, NETLINK_GENERIC)) {
+        ALOGE("Could not connect handle");
+        nl_socket_free(sock);
+        return NULL;
+    }
+
+    return sock;
+}
+
+
+wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
+{
+	SetNdoffloadCommand command(handle, enable);
+	int ret = command.requestResponse();
+	if (ret != WIFI_SUCCESS) {
+		if (ret == -EPERM) {           /*This is just to pass VTS test */
+			ALOGD("return value from driver--> %d",ret);
+			return WIFI_SUCCESS;
+		}
+	}
+	return (wifi_error)ret;
+}
+
+wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+                                                      u32 *version, u32 *max_len)
+{
+	/*Return success to pass VTS test.*/
+	ALOGD("Packet filter not supported");
+
+	*version = 0;
+	*max_len = 0;
+
+	return WIFI_SUCCESS;
+}
+
+/* Initialize HAL function pointer table */
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn)
+{
+    if (fn == NULL) {
+        return WIFI_ERROR_UNKNOWN;
+    }
+    fn->wifi_initialize = wifi_initialize;
+    fn->wifi_cleanup = wifi_cleanup;
+    fn->wifi_event_loop = wifi_event_loop;
+    fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
+    fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
+    fn->wifi_set_scanning_mac_oui =  wifi_set_scanning_mac_oui;
+    fn->wifi_get_ifaces = wifi_get_ifaces;
+    fn->wifi_get_iface_name = wifi_get_iface_name;
+    fn->wifi_start_gscan = wifi_start_gscan;
+    fn->wifi_stop_gscan = wifi_stop_gscan;
+    fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
+    fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
+    fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
+    fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
+    fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
+    fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
+    fn->wifi_get_valid_channels = wifi_get_valid_channels;
+    fn->wifi_rtt_range_request = wifi_rtt_range_request;
+    fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
+    fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
+    fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
+//fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet;
+    fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
+    fn->wifi_set_epno_list = wifi_set_epno_list;
+    fn->wifi_reset_epno_list = wifi_reset_epno_list;
+    fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
+    fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
+    fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
+    fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
+    fn->wifi_set_link_stats = wifi_set_link_stats;
+    fn->wifi_get_link_stats = wifi_get_link_stats;
+    fn->wifi_clear_link_stats = wifi_clear_link_stats;
+    fn->wifi_set_country_code = wifi_set_country_code;
+    fn->wifi_configure_roaming = wifi_configure_roaming;
+    fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
+    fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
+    fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
+    fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
+    fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
+    fn->wifi_start_logging = wifi_start_logging;
+    fn->wifi_set_log_handler = wifi_set_log_handler;
+    fn->wifi_set_alert_handler= wifi_set_alert_handler;
+    fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
+    fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
+    fn->wifi_get_ring_data = wifi_get_ring_data;
+    fn->wifi_get_driver_version = wifi_get_driver_version;
+    fn->wifi_get_firmware_version = wifi_get_firmware_version;
+    fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
+    fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
+    fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
+    fn->wifi_nan_enable_request = nan_enable_request;
+    fn->wifi_nan_disable_request = nan_disable_request;
+    fn->wifi_nan_publish_request = nan_publish_request;
+    fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
+    fn->wifi_nan_subscribe_request = nan_subscribe_request;
+    fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
+    fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
+    fn->wifi_nan_config_request = nan_config_request;
+    fn->wifi_nan_register_handler = nan_register_handler;
+    fn->wifi_nan_get_version = nan_get_version;
+    fn->wifi_nan_get_capabilities = nan_get_capabilities;
+    fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
+    fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
+
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_initialize(wifi_handle *handle)
+{
+    srand(getpid());
+
+    ALOGI("Initializing wifi");
+    hal_info *info = (hal_info *)malloc(sizeof(hal_info));
+    if (info == NULL) {
+        ALOGE("Could not allocate hal_info");
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    memset(info, 0, sizeof(*info));
+
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->cleanup_socks) == -1) {
+        ALOGE("Could not create cleanup sockets");
+        free(info);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
+    if (cmd_sock == NULL) {
+        ALOGE("Could not create handle");
+        free(info);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
+    if (event_sock == NULL) {
+        ALOGE("Could not create handle");
+        nl_socket_free(cmd_sock);
+        free(info);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    struct nl_cb *cb = nl_socket_get_cb(event_sock);
+    if (cb == NULL) {
+        ALOGE("Could not create handle");
+        nl_socket_free(cmd_sock);
+        nl_socket_free(event_sock);
+        free(info);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+//     ALOGI("cb->refcnt = %d", cb->cb_refcnt);
+    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info);
+    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
+    nl_cb_put(cb);
+
+    info->cmd_sock = cmd_sock;
+    info->event_sock = event_sock;
+    info->clean_up = false;
+    info->in_event_loop = false;
+
+    info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
+    info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
+    info->num_event_cb = 0;
+
+    info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
+    info->alloc_cmd = DEFAULT_CMD_SIZE;
+    info->num_cmd = 0;
+
+    info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
+    if (info->nl80211_family_id < 0) {
+        ALOGE("Could not resolve nl80211 familty id");
+        nl_socket_free(cmd_sock);
+        nl_socket_free(event_sock);
+        free(info);
+        return WIFI_ERROR_UNKNOWN;
+    }
+
+    pthread_mutex_init(&info->cb_lock, NULL);
+
+    *handle = (wifi_handle) info;
+    wifi_add_membership(*handle, "scan");
+    wifi_add_membership(*handle, "mlme");
+    wifi_add_membership(*handle, "regulatory");
+    wifi_add_membership(*handle, "vendor");
+
+    wifi_init_interfaces(*handle);
+    char intf_name_buff[10 * 10 + 4]; /* Randomly choosen max interface 10. each interface name max 9 + 1(for space) */
+    char *pos = intf_name_buff;
+    for (int i = 0; i < (info->num_interfaces < 10 ? info->num_interfaces : 10); i++) {
+        strncpy(pos, info->interfaces[i]->name, sizeof(intf_name_buff) - (pos - intf_name_buff));
+        pos += strlen(pos);
+    }
+    if (info->num_interfaces > 10) {
+        strncpy(pos, "...", 3);
+    }
+
+    ALOGD("Found %d interfaces[%s]. Initialized Wifi HAL Successfully", info->num_interfaces, intf_name_buff);
+
+    return WIFI_SUCCESS;
+}
+
+static int wifi_add_membership(wifi_handle handle, const char *group)
+{
+    hal_info *info = getHalInfo(handle);
+
+    int id = wifi_get_multicast_id(handle, "nl80211", group);
+    if (id < 0) {
+        ALOGE("Could not find group %s", group);
+        return id;
+    }
+
+    int ret = nl_socket_add_membership(info->event_sock, id);
+    if (ret < 0) {
+        ALOGE("Could not add membership to group %s", group);
+    }
+    return ret;
+}
+
+static void internal_cleaned_up_handler(wifi_handle handle)
+{
+    hal_info *info = getHalInfo(handle);
+    wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
+
+    if (info->cmd_sock != 0) {
+        close(info->cleanup_socks[0]);
+        close(info->cleanup_socks[1]);
+        nl_socket_free(info->cmd_sock);
+        nl_socket_free(info->event_sock);
+        info->cmd_sock = NULL;
+        info->event_sock = NULL;
+    }
+
+    (*cleaned_up_handler)(handle);
+    pthread_mutex_destroy(&info->cb_lock);
+    free(info);
+}
+
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
+{
+    hal_info *info = getHalInfo(handle);
+    char buf[64];
+
+    info->cleaned_up_handler = handler;
+    if (write(info->cleanup_socks[0], "Exit", 4) < 1) {
+        ALOGE("could not write to the cleanup socket");
+    } else {
+        // Listen to the response
+        // Hopefully we dont get errors or get hung up
+        // Not much can be done in that case, but assume that
+        // it has rx'ed the Exit message to exit the thread.
+        // As a fallback set the cleanup flag to TRUE
+        memset(buf, 0, sizeof(buf));
+        int result = read(info->cleanup_socks[0], buf, sizeof(buf));
+        ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result, errno);
+        if (strncmp(buf, "Done", 4) != 0) {
+            ALOGD("Rx'ed %s", buf);
+        }
+    }
+    info->clean_up = true;
+    pthread_mutex_lock(&info->cb_lock);
+
+    int bad_commands = 0;
+
+    while (info->num_cmd > bad_commands) {
+        int num_cmd = info->num_cmd;
+        cmd_info *cmdi = &(info->cmd[bad_commands]);
+        WifiCommand *cmd = cmdi->cmd;
+        if (cmd != NULL) {
+            pthread_mutex_unlock(&info->cb_lock);
+            cmd->cancel();
+            pthread_mutex_lock(&info->cb_lock);
+            /* release reference added when command is saved */
+            cmd->releaseRef();
+            if (num_cmd == info->num_cmd) {
+                bad_commands++;
+            }
+        }
+    }
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+        cb_info *cbi = &(info->event_cb[i]);
+        WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+        ALOGE("Leaked command %p", cmd);
+    }
+    pthread_mutex_unlock(&info->cb_lock);
+    internal_cleaned_up_handler(handle);
+}
+
+static int internal_pollin_handler(wifi_handle handle)
+{
+    hal_info *info = getHalInfo(handle);
+    struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
+    int res = nl_recvmsgs(info->event_sock, cb);
+    nl_cb_put(cb);
+    return res;
+}
+
+/* Run event handler */
+void wifi_event_loop(wifi_handle handle)
+{
+    hal_info *info = getHalInfo(handle);
+    if (info->in_event_loop) {
+        return;
+    } else {
+        info->in_event_loop = true;
+    }
+
+    pollfd pfd[2];
+    memset(&pfd[0], 0, sizeof(pollfd) * 2);
+
+    pfd[0].fd = nl_socket_get_fd(info->event_sock);
+    pfd[0].events = POLLIN;
+    pfd[1].fd = info->cleanup_socks[1];
+    pfd[1].events = POLLIN;
+
+    char buf[2048];
+
+    do {
+        int timeout = -1;                   /* Infinite timeout */
+        pfd[0].revents = 0;
+        pfd[1].revents = 0;
+        int result = poll(pfd, 2, timeout);
+        if (result < 0) {
+        } else if (pfd[0].revents & POLLERR) {
+            int prev_err = (int)errno;
+            int result2 = read(pfd[0].fd, buf, sizeof(buf));
+            ALOGE("Poll err:%d | Read after POLL returned %d, error no = %d", prev_err, result2, errno);
+        } else if (pfd[0].revents & POLLHUP) {
+            ALOGE("Remote side hung up");
+            break;
+        } else if (pfd[0].revents & POLLIN) {
+            internal_pollin_handler(handle);
+        } else if (pfd[1].revents & POLLIN) {
+            memset(buf, 0, sizeof(buf));
+            int result2 = read(pfd[1].fd, buf, sizeof(buf));
+            ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result2, errno);
+            if (strncmp(buf, "Exit", 4) == 0) {
+                ALOGD("Got a signal to exit!!!");
+                if (write(pfd[1].fd, "Done", 4) < 1) {
+                    ALOGE("could not write to the cleanup socket");
+                }
+                break;
+            } else {
+                ALOGD("Rx'ed %s on the cleanup socket\n", buf);
+            }
+        } else {
+            ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents);
+        }
+    } while (!info->clean_up);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int internal_no_seq_check(struct nl_msg *msg, void *arg)
+{
+    return NL_OK;
+}
+
+static int internal_valid_message_handler(nl_msg *msg, void *arg)
+{
+    wifi_handle handle = (wifi_handle)arg;
+    hal_info *info = getHalInfo(handle);
+
+    WifiEvent event(msg);
+    int res = event.parse();
+    if (res < 0) {
+        ALOGE("Failed to parse event: %d", res);
+        return NL_SKIP;
+    }
+
+    int cmd = event.get_cmd();
+    uint32_t vendor_id = 0;
+    int subcmd = 0;
+
+    if (cmd == NL80211_CMD_VENDOR) {
+        vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
+        subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+        /*
+        ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+                event.get_cmdString(), vendor_id, subcmd);*/
+    }
+
+     //ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
+     //event.log();
+
+    pthread_mutex_lock(&info->cb_lock);
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+        if (cmd == info->event_cb[i].nl_cmd) {
+            if (cmd == NL80211_CMD_VENDOR
+                && ((vendor_id != info->event_cb[i].vendor_id)
+                || (subcmd != info->event_cb[i].vendor_subcmd)))
+            {
+                /* event for a different vendor, ignore it */
+                continue;
+            }
+
+            cb_info *cbi = &(info->event_cb[i]);
+            nl_recvmsg_msg_cb_t cb_func = cbi->cb_func;
+            void *cb_arg = cbi->cb_arg;
+            WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+            if (cmd != NULL) {
+                cmd->addRef();
+            }
+
+            pthread_mutex_unlock(&info->cb_lock);
+            if (cb_func)
+                (*cb_func)(msg, cb_arg);
+            if (cmd != NULL) {
+                cmd->releaseRef();
+            }
+
+            return NL_OK;
+        }
+    }
+
+    pthread_mutex_unlock(&info->cb_lock);
+    return NL_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+class GetMulticastIdCommand : public WifiCommand
+{
+private:
+    const char *mName;
+    const char *mGroup;
+    int   mId;
+public:
+    GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
+        : WifiCommand(handle, 0)
+    {
+        mName = name;
+        mGroup = group;
+        mId = -1;
+    }
+
+    int getId() {
+        return mId;
+    }
+
+    virtual int create() {
+        int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
+        int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
+        if (ret < 0) {
+            return ret;
+        }
+        ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
+        return ret;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        struct nlattr **tb = reply.attributes();
+        struct nlattr *mcgrp = NULL;
+        int i;
+
+        if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+            ALOGE("No multicast groups found");
+            return NL_SKIP;
+        }
+
+        for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+            struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+            nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
+                nla_len(mcgrp), NULL);
+            if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
+                continue;
+            }
+
+            char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+            int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+
+            if (strncmp(grpName, mGroup, grpNameLen) != 0)
+                continue;
+
+            mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+            break;
+        }
+
+        return NL_SKIP;
+    }
+
+};
+
+class SetPnoMacAddrOuiCommand : public WifiCommand {
+
+private:
+    byte *mOui;
+    feature_set *fset;
+    feature_set *feature_matrix;
+    int *fm_size;
+    int set_size_max;
+public:
+    SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui)
+        : WifiCommand(handle, 0)
+    {
+        mOui = scan_oui;
+	fset = NULL;
+	feature_matrix = NULL;
+	fm_size = NULL;
+	set_size_max = 0;
+    }
+
+    int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) {
+        int result = request.create(GOOGLE_OUI, subcmd);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI, mOui);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to set scanning mac OUI; result = %d", result);
+        }
+
+        return result;
+    }
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+class SetNodfsCommand : public WifiCommand {
+
+private:
+    u32 mNoDfs;
+public:
+    SetNodfsCommand(wifi_interface_handle handle, u32 nodfs)
+        : WifiCommand(handle, 0) {
+        mNoDfs = nodfs;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS);
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+            return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_u32(ATTR_NODFS_VALUE, mNoDfs);
+        if (ret < 0) {
+             return ret;
+        }
+
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+class SetRSSIMonitorCommand : public WifiCommand {
+private:
+    s8 mMax_rssi;
+    s8 mMin_rssi;
+    wifi_rssi_event_handler mHandler;
+public:
+    SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle,
+                s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+        : WifiCommand(handle, id), mMax_rssi(max_rssi), mMin_rssi
+        (min_rssi), mHandler(eh)
+        {
+        }
+   int createRequest(WifiRequest& request, int enable) {
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_RSSI_MONITOR);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0));
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0));
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_START, enable);
+        if (result < 0) {
+            return result;
+        }
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, 1);
+        if (result < 0) {
+            return result;
+        }
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Failed to set RSSI Monitor, result = %d", result);
+            return result;
+        }
+        ALOGI("Successfully set RSSI monitoring");
+        registerVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
+
+        return result;
+    }
+
+    virtual int cancel() {
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, 0);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to stop RSSI monitoring = %d", result);
+            }
+        }
+        unregisterVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+   virtual int handleEvent(WifiEvent& event) {
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGI("RSSI monitor: No data");
+            return NL_SKIP;
+        }
+
+        typedef struct {
+            s8 cur_rssi;
+            mac_addr BSSID;
+        } rssi_monitor_evt;
+
+        rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data();
+
+        if (*mHandler.on_rssi_threshold_breached) {
+            (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi);
+        } else {
+            ALOGW("No RSSI monitor handler registered");
+        }
+
+        return NL_SKIP;
+    }
+
+};
+
+class SetCountryCodeCommand : public WifiCommand {
+private:
+    const char *mCountryCode;
+public:
+    SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code)
+        : WifiCommand(handle, 0) {
+        mCountryCode = country_code;
+        }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_COUNTRY_CODE);
+        if (ret < 0) {
+             ALOGE("Can't create message to send to driver - %d", ret);
+             return ret;
+        }
+
+        nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+        ret = mMsg.put_string(ATTR_COUNTRY_CODE, mCountryCode);
+        if (ret < 0) {
+            return ret;
+        }
+
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+
+    }
+};
+
+class GetFeatureSetCommand : public WifiCommand {
+
+private:
+
+    feature_set *fset;
+
+public:
+    GetFeatureSetCommand(wifi_interface_handle handle, feature_set *set)
+        : WifiCommand(handle, 0)
+    {
+        fset = set;
+    }
+
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_FEATURE_SET);
+        if (ret < 0) {
+            ALOGE("create failed - %d", ret);
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignore reply; cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("vendor data in GetFeatureSetCommand missing!!");
+            return NL_SKIP;
+        }
+
+        void *data = reply.get_vendor_data();
+        if(!fset) {
+            ALOGE("feature_set Pointer not set");
+            return NL_SKIP;
+        }
+        memcpy(fset, data, min(len, (int) sizeof(*fset)));
+        return NL_OK;
+    }
+
+};
+
+
+
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
+{
+    GetMulticastIdCommand cmd(handle, name, group);
+    int res = cmd.requestResponse();
+    if (res < 0)
+        return res;
+    else
+        return cmd.getId();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static bool is_wifi_interface(const char *name)
+{
+    if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
+        /* not a wifi interface; ignore it */
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static int get_interface(const char *name, interface_info *info)
+{
+    strcpy(info->name, name);
+    info->id = if_nametoindex(name);
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_init_interfaces(wifi_handle handle)
+{
+    hal_info *info = (hal_info *)handle;
+    struct dirent *de;
+
+    DIR *d = opendir("/sys/class/net");
+    if (d == 0)
+        return WIFI_ERROR_UNKNOWN;
+
+    int n = 0;
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.')
+            continue;
+        if (is_wifi_interface(de->d_name) ) {
+            n++;
+        }
+    }
+
+    closedir(d);
+
+    d = opendir("/sys/class/net");
+    if (d == 0)
+        return WIFI_ERROR_UNKNOWN;
+
+    info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
+
+    int i = 0;
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.')
+            continue;
+        if (is_wifi_interface(de->d_name)) {
+            interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+            if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
+                free(ifinfo);
+                continue;
+            }
+            ifinfo->handle = handle;
+            info->interfaces[i] = ifinfo;
+            i++;
+        }
+    }
+
+    closedir(d);
+
+    info->num_interfaces = n;
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
+{
+    hal_info *info = (hal_info *)handle;
+
+    *interfaces = (wifi_interface_handle *)info->interfaces;
+    *num = info->num_interfaces;
+
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
+{
+    interface_info *info = (interface_info *)handle;
+    strcpy(name, info->name);
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+       feature_set set[], int *set_size)
+{
+    return WIFI_ERROR_NOT_SUPPORTED;
+}
+
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
+{
+    SetPnoMacAddrOuiCommand command(handle, scan_oui);
+    return (wifi_error)command.start();
+
+}
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
+{
+    SetNodfsCommand command(handle, nodfs);
+    return (wifi_error) command.requestResponse();
+}
+
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+                        iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+{
+    ALOGD("Start RSSI monitor %d", id);
+    wifi_handle handle = getWifiHandle(iface);
+    SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh);
+    wifi_register_cmd(handle, id, cmd);
+
+    wifi_error result = (wifi_error)cmd->start();
+    if (result != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+    }
+    return result;
+}
+
+
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface)
+{
+    ALOGD("Stopping RSSI monitor");
+
+    if(id == -1) {
+        wifi_rssi_event_handler handler;
+        memset(&handler, 0, sizeof(handler));
+        SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
+                                                    0, 0, handler);
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+    return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
+{
+    GetFeatureSetCommand command(handle, set);
+    return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code)
+{
+    SetCountryCodeCommand command(handle, country_code);
+    return (wifi_error) command.requestResponse();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/wifi_logger.cpp b/wifi_logger.cpp
new file mode 100755
index 0000000..4ab5d74
--- /dev/null
+++ b/wifi_logger.cpp
@@ -0,0 +1,1444 @@
+#include <stdint.h>

+#include <fcntl.h>

+#include <sys/socket.h>

+#include <netlink/genl/genl.h>

+#include <netlink/genl/family.h>

+#include <netlink/genl/ctrl.h>

+#include <linux/rtnetlink.h>

+#include <netpacket/packet.h>

+#include <linux/filter.h>

+#include <linux/errqueue.h>

+

+#include <linux/pkt_sched.h>

+#include <netlink/object-api.h>

+#include <netlink/netlink.h>

+#include <netlink/socket.h>

+#include <netlink-private/object-api.h>

+#include <netlink-private/types.h>

+

+#include "nl80211_copy.h"

+#include "sync.h"

+

+#define LOG_TAG  "WifiHAL"

+

+#include <utils/Log.h>

+

+#include "wifi_hal.h"

+#include "common.h"

+#include "cpp_bindings.h"

+

+/* using namespace android; */

+

+typedef enum {

+    ENHANCE_LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,

+    ENHANCE_LOGGER_TRIGGER_FW_MEM_DUMP,

+    ENHANCE_LOGGER_GET_FW_MEM_DUMP,

+    ENHANCE_LOGGER_GET_VER,

+    ENHANCE_LOGGER_GET_RING_STATUS,

+    ENHANCE_LOGGER_GET_RING_DATA,

+    ENHANCE_LOGGER_GET_FEATURE,

+    ENHANCE_LOGGER_RESET_LOGGING,

+    ENHANCE_LOGGER_TRIGGER_DRIVER_MEM_DUMP,

+    ENHANCE_LOGGER_GET_DRIVER_MEM_DUMP,

+    ENHANCE_LOGGER_START_PKT_FATE_MONITORING,

+    ENHANCE_LOGGER_GET_TX_PKT_FATES,

+    ENHANCE_LOGGER_GET_RX_PKT_FATES,

+    ENHANCE_LOGGER_GET_WAKE_REASON_STATS,

+} DEBUG_SUB_COMMAND;

+

+typedef enum {

+    ENHANCE_LOGGER_ATTRIBUTE_DRIVER_VER,

+    ENHANCE_LOGGER_ATTRIBUTE_FW_VER,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_ID,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_NAME,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_FLAGS,

+    ENHANCE_LOGGER_ATTRIBUTE_LOG_LEVEL,

+    ENHANCE_LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,

+    ENHANCE_LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,

+    ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN,

+    ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA,

+    // LOGGER_ATTRIBUTE_FW_ERR_CODE,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_DATA,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS,

+    ENHANCE_LOGGER_ATTRIBUTE_RING_NUM,

+    ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,

+    ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,

+    ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM,

+    ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA,

+    //Attributes for data used by wake stats subcmd.

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_INVALID = 0,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_CMD_EVENT_WAKE,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_RX_DATA_WAKE,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_UNICAST_CNT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_MULTICAST_CNT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_BROADCAST_CNT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP_PKT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_PKT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RA,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NA,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NS,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP4_RX_MULTICAST_CNT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RX_MULTICAST_CNT,

+    ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_OTHER_RX_MULTICAST_CNT,

+} ENHANCE_LOGGER_ATTRIBUTE;

+

+typedef enum {

+    DEBUG_OFF = 0,

+    DEBUG_NORMAL,

+    DEBUG_VERBOSE,

+    DEBUG_VERY,

+    DEBUG_VERY_VERY,

+} ENHANCE_LOGGER_LEVEL;

+

+typedef enum {

+    GET_FW_VER,

+    GET_DRV_VER,

+    GET_RING_DATA,

+    GET_RING_STATUS,

+    GET_FEATURE,

+    START_RING_LOG,

+    GET_FW_DUMP,

+    GET_DRIVER_DUMP,

+} GetCmdType;

+

+typedef enum {

+    PACKET_MONITOR_START,

+    TX_PACKET_FATE,

+    RX_PACKET_FATE,

+} PktFateReqType;

+

+class DebugCommand : public WifiCommand

+{

+    char *mBuff = NULL;

+    int *mBuffSize = NULL;

+    u32 *mNumRings = NULL;

+    wifi_ring_buffer_status *mStatus = NULL;

+    unsigned int *mSupport = NULL;

+    u32 mVerboseLevel = 0;

+    u32 mFlags = 0;

+    u32 mMaxIntervalSec = 0;

+    u32 mMinDataSize = 0;

+    char *mRingName = NULL;

+    GetCmdType mType;

+

+public:

+

+    // constructor for get version

+    DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size,

+            GetCmdType cmdType)

+        : WifiCommand(iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType

+        (cmdType)

+    {

+        memset(mBuff, 0, *mBuffSize);

+    }

+

+    // constructor for ring data

+    DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType)

+        : WifiCommand(iface, 0), mRingName(ring_name), mType(cmdType)

+    { }

+

+    // constructor for ring status

+    DebugCommand(wifi_interface_handle iface, u32 *num_rings,

+            wifi_ring_buffer_status *status, GetCmdType cmdType)

+        : WifiCommand(iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType)

+    {

+        memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings));

+    }

+

+    // constructor for feature set

+    DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType)

+        : WifiCommand(iface, 0), mSupport(support), mType(cmdType)

+    { }

+

+    // constructor for ring params

+    DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags,

+            u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType)

+        : WifiCommand(iface, 0), mVerboseLevel(verbose_level), mFlags(flags),

+        mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size),

+        mRingName(ring_name), mType(cmdType)

+    { }

+

+    int createRingRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_START_LOGGING);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to create start ring logger request; result = %d", result);

+            return result;

+        }

+

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put log level; result = %d", result);

+            return result;

+        }

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_RING_FLAGS, mFlags);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put ring flags; result = %d", result);

+            return result;

+        }

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put log time interval; result = %d", result);

+            return result;

+        }

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put min data size; result = %d", result);

+            return result;

+        }

+        result = request.put_string(ENHANCE_LOGGER_ATTRIBUTE_RING_NAME, mRingName);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put ringbuffer name; result = %d", result);

+            return result;

+        }

+        request.attr_end(data);

+

+        return WIFI_SUCCESS;

+    }

+

+    int createRequest(WifiRequest &request) {

+        int result;

+

+        switch (mType) {

+            case GET_FW_VER:

+            {

+                result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_VER);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get fw version request; result = %d", result);

+                    return result;

+                }

+

+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+

+                // Driver expecting only attribute type, passing mbuff as data with

+                // length 0 to avoid undefined state

+                result = request.put(ENHANCE_LOGGER_ATTRIBUTE_FW_VER, mBuff, 0);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to put get fw version request; result = %d", result);

+                    return result;

+                }

+                request.attr_end(data);

+                break;

+            }

+

+            case GET_DRV_VER:

+            {

+                result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_VER);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get drv version request; result = %d", result);

+                    return result;

+                }

+

+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+

+                // Driver expecting only attribute type, passing mbuff as data with

+                // length 0 to avoid undefined state

+                result = request.put(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0);

+

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to put get drv version request; result = %d", result);

+                    return result;

+                }

+                request.attr_end(data);

+                break;

+            }

+

+            case GET_RING_DATA:

+            {

+                result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RING_DATA);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get ring data request; result = %d", result);

+                    return result;

+                }

+

+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+                result = request.put_string(ENHANCE_LOGGER_ATTRIBUTE_RING_NAME, mRingName);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to put ring data request; result = %d", result);

+                    return result;

+                }

+                request.attr_end(data);

+                break;

+            }

+

+            case GET_RING_STATUS:

+            {

+                result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RING_STATUS);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get ring status request; result = %d", result);

+                    return result;

+                }

+                break;

+            }

+

+            case GET_FEATURE:

+            {

+                result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_FEATURE);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get feature request; result = %d", result);

+                    return result;

+                }

+                break;

+            }

+

+            case START_RING_LOG:

+                result = createRingRequest(request);

+                break;

+

+            default:

+                ALOGE("Unknown Debug command");

+                result = WIFI_ERROR_UNKNOWN;

+        }

+        return result;

+    }

+

+    int start() {

+        // ALOGD("Start debug command");

+        WifiRequest request(familyId(), ifaceId());

+        int result = createRequest(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to create debug request; result = %d", result);

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to register debug response; result = %d", result);

+        }

+        return result;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        ALOGD("In DebugCommand::handleResponse");

+

+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());

+            return NL_SKIP;

+        }

+

+        switch (mType) {

+            case GET_DRV_VER:

+            case GET_FW_VER:

+            {

+                void *data = reply.get_vendor_data();

+                int len = reply.get_vendor_data_len();

+

+                ALOGD("len = %d, expected len = %d", len, *mBuffSize);

+                memcpy(mBuff, data, min(len, *mBuffSize));

+                if (*mBuffSize < len)

+                    return NL_SKIP;

+                *mBuffSize = len;

+                break;

+            }

+

+            case START_RING_LOG:

+            case GET_RING_DATA:

+                break;

+

+            case GET_RING_STATUS:

+            {

+                nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+                int len = reply.get_vendor_data_len();

+                wifi_ring_buffer_status *status(mStatus);

+

+                if (vendor_data == NULL || len == 0) {

+                    ALOGE("No Debug data found");

+                    return NL_SKIP;

+                }

+

+                nl_iterator it(vendor_data);

+                if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_NUM) {

+                    unsigned int num_rings = it.get_u32();

+                    if (*mNumRings < num_rings) {

+                        ALOGE("Not enough status buffers provided, available: %d required: %d",

+                                *mNumRings, num_rings);

+                    } else {

+                        *mNumRings = num_rings;

+                    }

+                } else {

+                    ALOGE("Unknown attribute: %d expecting %d",

+                            it.get_type(), ENHANCE_LOGGER_ATTRIBUTE_RING_NUM);

+                    return NL_SKIP;

+                }

+

+                it.next();

+                if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS) {

+                    memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status) * (*mNumRings));

+                } else {

+                    ALOGW("Ignoring invalid attribute type = %d, size = %d",

+                                it.get_type(), it.get_len());

+                }

+                break;

+            }

+

+            case GET_FEATURE:

+            {

+                void *data = reply.get_vendor_data();

+

+                ALOGD("len = %d, expected len = %lu", reply.get_vendor_data_len(), (unsigned long)sizeof(unsigned int));

+                memcpy(mSupport, data, sizeof(unsigned int));

+                break;

+            }

+

+            default:

+                ALOGW("Unknown Debug command");

+        }

+        return NL_OK;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        /* NO events! */

+        return NL_SKIP;

+    }

+};

+

+/* API to get supportable feature */

+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,

+        unsigned int *support)

+{

+    if (support) {

+        DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("Get support buffer NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

+/* API to get the status of all ring buffers supported by driver */

+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface,

+        u32 *num_rings, wifi_ring_buffer_status *status)

+{

+    if (status && num_rings) {

+        DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("Ring status buffer NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

+/* API to collect driver records */

+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name)

+{

+    DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    return result;

+}

+

+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level,

+        u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name)

+{

+    if (ring_name) {

+        DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec,

+                    min_data_size, ring_name, START_RING_LOG);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("Ring name NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

+/* API to collect a firmware version string */

+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer,

+        int buffer_size)

+{

+    if (buffer && (buffer_size > 0)) {

+        DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("FW version buffer NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

+/* API to collect a driver version string */

+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size)

+{

+    if (buffer && (buffer_size > 0)) {

+        DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("Driver version buffer NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+class SetLogHandler : public WifiCommand

+{

+    wifi_ring_buffer_data_handler mHandler;

+

+public:

+    SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler)

+        : WifiCommand(iface, id), mHandler(handler)

+    { }

+

+    int start() {

+        ALOGV("Register loghandler");

+        registerVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_RING_EVENT);

+        return WIFI_SUCCESS;

+    }

+

+    virtual int cancel() {

+        /* Send a command to driver to stop generating logging events */

+        ALOGV("Clear loghandler");

+

+        /* unregister event handler */

+        unregisterVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_RING_EVENT);

+

+        WifiRequest request(familyId(), ifaceId());

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_RESET_LOGGING);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("failed to create reset request; result = %d", result);

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("failed to request reset; result = %d", result);

+            return result;

+        }

+

+        ALOGD("Success to clear loghandler");

+        return WIFI_SUCCESS;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        char *buffer = NULL;

+        int buffer_size = 0;

+

+        // ALOGD("In SetLogHandler::handleEvent");

+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = event.get_vendor_data_len();

+        int event_id = event.get_vendor_subcmd();

+        // ALOGI("Got Logger event: %d", event_id);

+

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("No Debug data found");

+            return NL_SKIP;

+        }

+

+        if(event_id == ENHANCE_LOGGER_RING_EVENT) {

+            wifi_ring_buffer_status status;

+            memset(&status, 0, sizeof(status));

+

+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+                if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS) {

+                    memcpy(&status, it.get_data(), sizeof(status));

+                } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_DATA) {

+                    buffer_size = it.get_len();

+                    buffer = (char *)it.get_data();

+                } else {

+                    ALOGW("Ignoring invalid attribute type = %d, size = %d",

+                            it.get_type(), it.get_len());

+                }

+            }

+

+            // ALOGI("Retrieved Debug data");

+            if (mHandler.on_ring_buffer_data) {

+                (*mHandler.on_ring_buffer_data)((char *)status.name, buffer, buffer_size,

+                        &status);

+            }

+        } else {

+            ALOGE("Unknown Event");

+            return NL_SKIP;

+        }

+        return NL_OK;

+    }

+};

+

+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,

+        wifi_ring_buffer_data_handler handler)

+{

+    wifi_handle handle = getWifiHandle(iface);

+    ALOGV("Loghandler start, handle = %p", handle);

+

+    SetLogHandler *cmd = new SetLogHandler(iface, id, handler);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = wifi_register_cmd(handle, id, cmd);

+    if (result != WIFI_SUCCESS) {

+        cmd->releaseRef();

+        return result;

+    }

+    result = (wifi_error)cmd->start();

+    if (result != WIFI_SUCCESS) {

+        wifi_unregister_cmd(handle, id);

+        cmd->releaseRef();

+        return result;

+    }

+    return result;

+}

+

+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface)

+{

+    wifi_handle handle = getWifiHandle(iface);

+    ALOGV("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle);

+

+    if (id == -1) {

+        wifi_ring_buffer_data_handler handler;

+        memset(&handler, 0, sizeof(handler));

+

+        SetLogHandler *cmd = new SetLogHandler(iface, id, handler);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+    return wifi_cancel_cmd(id, iface);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+class SetAlertHandler : public WifiCommand

+{

+    wifi_alert_handler mHandler;

+    int mBuffSize;

+    char *mBuff;

+    int mErrCode;

+

+public:

+    SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler)

+        : WifiCommand(iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL),

+            mErrCode(0)

+    { }

+

+    int start() {

+        ALOGV("Start Alerting");

+        registerVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);

+        return WIFI_SUCCESS;

+    }

+

+    virtual int cancel() {

+        ALOGV("Clear alerthandler");

+

+        /* unregister alert handler */

+        unregisterVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);

+        wifi_unregister_cmd(wifiHandle(), id());

+        ALOGD("Success to clear alerthandler");

+        return WIFI_SUCCESS;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        ALOGD("In SetAlertHandler::handleResponse");

+

+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());

+            return NL_SKIP;

+        }

+

+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = reply.get_vendor_data_len();

+

+        ALOGD("len = %d", len);

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("no vendor data in memory dump response; ignoring it");

+            return NL_SKIP;

+        }

+

+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+            if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA) {

+                ALOGI("Initiating alert callback");

+                if (mHandler.on_alert) {

+                    (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode);

+                }

+                if (mBuff) {

+                    free(mBuff);

+                    mBuff = NULL;

+                }

+            }

+        }

+        return NL_OK;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        char *buffer = NULL;

+        int buffer_size = 0;

+

+

+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = event.get_vendor_data_len();

+        int event_id = event.get_vendor_subcmd();

+        ALOGI("Got event: %d", event_id);

+

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("No Debug data found");

+            return NL_SKIP;

+        }

+

+        if (event_id == ENHANCE_LOGGER_MEM_DUMP_EVENT) {

+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+                if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN) {

+                    mBuffSize = it.get_u32();

+                } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_DATA) {

+                    buffer_size = it.get_len();

+                    buffer = (char *)it.get_data();

+            /*

+                } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_ERR_CODE) {

+                    mErrCode = it.get_u32();

+            */

+                } else {

+                    ALOGW("Ignoring invalid attribute type = %d, size = %d",

+                            it.get_type(), it.get_len());

+                }

+            }

+            if (mBuffSize) {

+                ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size);

+                if (mBuff) free(mBuff);

+                mBuff = (char *)malloc(mBuffSize + buffer_size);

+                if (!mBuff) {

+                    ALOGE("Buffer allocation failed");

+                    return NL_SKIP;

+                }

+                memcpy(mBuff, buffer, buffer_size);

+

+                WifiRequest request(familyId(), ifaceId());

+                int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to create get memory dump request; result = %d", result);

+                    free(mBuff);

+                    return NL_SKIP;

+                }

+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+                result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to put get memory dump request; result = %d", result);

+                    return result;

+                }

+

+                result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA,

+                         (uint64_t)(mBuff+buffer_size));

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to put get memory dump request; result = %d", result);

+                    return result;

+                }

+

+                request.attr_end(data);

+                mBuffSize += buffer_size;

+

+                result = requestResponse(request);

+

+                if (result != WIFI_SUCCESS) {

+                    ALOGE("Failed to register get momory dump response; result = %d", result);

+                }

+            } else {

+                ALOGE("dump event missing dump length attribute");

+                return NL_SKIP;

+            }

+        }

+        return NL_OK;

+    }

+};

+

+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,

+        wifi_alert_handler handler)

+{

+    wifi_handle handle = getWifiHandle(iface);

+    ALOGV("Alerthandler start, handle = %p", handle);

+

+    SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = wifi_register_cmd(handle, id, cmd);

+    if (result != WIFI_SUCCESS) {

+        cmd->releaseRef();

+        return result;

+    }

+    result = (wifi_error)cmd->start();

+    if (result != WIFI_SUCCESS) {

+        wifi_unregister_cmd(handle, id);

+        cmd->releaseRef();

+        return result;

+    }

+    return result;

+}

+

+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface)

+{

+    wifi_handle handle = getWifiHandle(iface);

+    ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle);

+

+    if (id == -1) {

+        wifi_alert_handler handler;

+        memset(&handler, 0, sizeof(handler));

+

+        SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+    return wifi_cancel_cmd(id, iface);

+}

+

+

+class PacketFateCommand: public WifiCommand

+{

+    void *mReportBufs = NULL;

+    size_t mNoReqFates = 0;

+    size_t *mNoProvidedFates = NULL;

+    PktFateReqType mReqType;

+

+public:

+    PacketFateCommand(wifi_interface_handle handle)

+        : WifiCommand(handle, 0), mReqType(PACKET_MONITOR_START)

+    { }

+

+    PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs,

+            size_t n_requested_fates, size_t *n_provided_fates)

+        : WifiCommand(handle, 0), mReportBufs(tx_report_bufs),

+                  mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),

+                  mReqType(TX_PACKET_FATE)

+    { }

+

+    PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs,

+            size_t n_requested_fates, size_t *n_provided_fates)

+        : WifiCommand(handle, 0), mReportBufs(rx_report_bufs),

+                  mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),

+                  mReqType(RX_PACKET_FATE)

+    { }

+

+    int createRequest(WifiRequest& request) {

+        if (mReqType == TX_PACKET_FATE) {

+            ALOGD("%s Get Tx packet fate request\n", __FUNCTION__);

+            return createTxPktFateRequest(request);

+        } else if (mReqType == RX_PACKET_FATE) {

+            ALOGD("%s Get Rx packet fate request\n", __FUNCTION__);

+            return createRxPktFateRequest(request);

+        } else if (mReqType == PACKET_MONITOR_START) {

+            ALOGD("%s Monitor packet fate request\n", __FUNCTION__);

+            return createMonitorPktFateRequest(request);

+        } else {

+            ALOGE("%s Unknown packet fate request\n", __FUNCTION__);

+            return WIFI_ERROR_NOT_SUPPORTED;

+        }

+        return WIFI_SUCCESS;

+    }

+

+    int createMonitorPktFateRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_START_PKT_FATE_MONITORING);

+        if (result < 0) {

+            return result;

+        }

+

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+        request.attr_end(data);

+        return result;

+    }

+

+    int createTxPktFateRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_TX_PKT_FATES);

+        if (result < 0) {

+            return result;

+        }

+

+        memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report)));

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);

+        if (result < 0) {

+            return result;

+        }

+        result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);

+        if (result < 0) {

+            return result;

+        }

+        request.attr_end(data);

+        return result;

+    }

+

+    int createRxPktFateRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RX_PKT_FATES);

+        if (result < 0) {

+            return result;

+        }

+

+        memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report)));

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);

+        if (result < 0) {

+            return result;

+        }

+        result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);

+        if (result < 0) {

+            return result;

+        }

+        request.attr_end(data);

+        return result;

+    }

+

+    int start() {

+        ALOGD("Start get packet fate command\n");

+        WifiRequest request(familyId(), ifaceId());

+

+        int result = createRequest(request);

+        if (result < 0) {

+            ALOGE("Failed to create get pkt fate request; result = %d\n", result);

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to register get pkt fate response; result = %d\n", result);

+        }

+        return result;

+    }

+

+    int handleResponse(WifiEvent& reply) {

+        ALOGD("In GetPktFateCommand::handleResponse\n");

+

+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+            ALOGI("Ignoring reply with cmd = %d", reply.get_cmd());

+            return NL_SKIP;

+        }

+

+        int id = reply.get_vendor_id();

+        int subcmd = reply.get_vendor_subcmd();

+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = reply.get_vendor_data_len();

+

+        ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);

+

+        if (mReqType == TX_PACKET_FATE) {

+            ALOGI("Response recieved for get TX pkt fate command\n");

+        } else if (mReqType == RX_PACKET_FATE) {

+            ALOGI("Response recieved for get RX pkt fate command\n");

+        } else if (mReqType == PACKET_MONITOR_START) {

+            ALOGI("Response recieved for monitor pkt fate command\n");

+            return NL_OK;

+        } else {

+            ALOGE("Response recieved for unknown pkt fate command\n");

+            return NL_SKIP;

+        }

+

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n");

+            return NL_SKIP;

+        }

+

+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+            if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM) {

+                *mNoProvidedFates = it.get_u32();

+                ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates);

+            } else {

+                ALOGE("Ignoring invalid attribute type = %d, size = %d\n",

+                        it.get_type(), it.get_len());

+            }

+        }

+

+        return NL_OK;

+    }

+

+    int handleEvent(WifiEvent& event) {

+        /* NO events to handle here! */

+        return NL_SKIP;

+    }

+};

+

+wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle)

+{

+    PacketFateCommand *cmd = new PacketFateCommand(handle);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    return result;

+}

+

+wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle,

+        wifi_tx_report *tx_report_bufs, size_t n_requested_fates,

+        size_t *n_provided_fates)

+{

+    PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs,

+                n_requested_fates, n_provided_fates);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    memset(tx_report_bufs, 0, (n_requested_fates * sizeof(wifi_tx_report)));

+    return result;

+}

+

+wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle,

+        wifi_rx_report *rx_report_bufs, size_t n_requested_fates,

+        size_t *n_provided_fates)

+{

+    PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs,

+                n_requested_fates, n_provided_fates);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    memset(rx_report_bufs, 0, (n_requested_fates * sizeof(wifi_rx_report)));

+    return result;

+}

+

+class MemoryDumpCommand: public WifiCommand

+{

+    wifi_firmware_memory_dump_handler mHandler;

+    wifi_driver_memory_dump_callbacks mcallback;

+    int mBuffSize;

+    char *mBuff;

+    GetCmdType mType;

+

+public:

+    MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler, GetCmdType cmdtype )

+        : WifiCommand(iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL), mType(cmdtype)

+    {

+        memset(&mcallback, 0, sizeof(wifi_driver_memory_dump_callbacks));

+    }

+

+    MemoryDumpCommand(wifi_interface_handle iface, wifi_driver_memory_dump_callbacks callback, GetCmdType cmdtype)

+        : WifiCommand(iface, 0), mcallback(callback), mBuffSize(0), mBuff(NULL), mType(cmdtype)

+    {

+        memset(&mHandler, 0, sizeof(wifi_firmware_memory_dump_handler));

+    }

+

+     int createRequest(WifiRequest &request) {

+        int result;

+

+        switch (mType) {

+                case GET_FW_DUMP:

+                    {

+                        result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_TRIGGER_FW_MEM_DUMP);

+                        if (result != WIFI_SUCCESS) {

+                                 ALOGE("Failed to create trigger fw memory dump request; result = %d", result);

+                                 return result;

+                        }

+                        break;

+                    }

+                case GET_DRIVER_DUMP :

+                    {

+                        result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_TRIGGER_DRIVER_MEM_DUMP);

+                        if (result != WIFI_SUCCESS) {

+                                ALOGE("Failed to create trigger driver memory dump request; result = %d", result);

+                                return result;

+                         }

+                        break;

+                      }

+                 default:

+                         ALOGE("Unknown Debug command");

+                         result = WIFI_ERROR_UNKNOWN;

+                     }

+        return result;

+     }

+    int start() {

+        ALOGD("Start memory dump command");

+        WifiRequest request(familyId(), ifaceId());

+

+        int result = createRequest(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to create trigger memory dump request; result = %d", result);

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to register trigger memory dump response; result = %d", result);

+        }

+        return result;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        ALOGD("In MemoryDumpCommand::handleResponse");

+

+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());

+            return NL_SKIP;

+        }

+

+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        int len = reply.get_vendor_data_len();

+

+        ALOGD("len = %d", len);

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("no vendor data in memory dump response; ignoring it");

+            return NL_SKIP;

+        }

+        switch(mType) {

+            case GET_FW_DUMP:

+                 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+                     if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN) {

+                         mBuffSize = it.get_u32();

+                         if (mBuff)

+                             free(mBuff);

+                         mBuff = (char *)malloc(mBuffSize);

+                         if (!mBuff) {

+                             ALOGE("Buffer allocation failed");

+                             return NL_SKIP;

+                         }

+                         WifiRequest request(familyId(), ifaceId());

+                         int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_FW_MEM_DUMP);

+                         if (result != WIFI_SUCCESS) {

+                             ALOGE("Failed to create get fw memory dump request; result = %d", result);

+                             free(mBuff);

+                             return NL_SKIP;

+                          }

+                          nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+                          result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to put get fw memory dump request; result = %d", result);

+                              return result;

+                          }

+                          result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to put get fw memory dump request; result = %d", result);

+                              return result;

+                          }

+                          request.attr_end(data);

+                          result = requestResponse(request);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to register get fw momory dump response; result = %d", result);

+                          }

+                     } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA) {

+                          ALOGI("Initiating memory dump callback");

+                          if (mHandler.on_firmware_memory_dump) {

+                              (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize);

+                          }

+                          if (mBuff) {

+                              free(mBuff);

+                              mBuff = NULL;

+                          }

+                    } else {

+                           ALOGW("Ignoring invalid attribute type = %d, size = %d",

+                           it.get_type(), it.get_len());

+                     }

+                 }

+                 break;

+            case GET_DRIVER_DUMP :

+                 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {

+                     if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN) {

+                         mBuffSize = it.get_u32();

+                         if (mBuff)

+                             free(mBuff);

+                         mBuff = (char *)malloc(mBuffSize);

+                         if (!mBuff) {

+                             ALOGE("Buffer allocation failed");

+                             return NL_SKIP;

+                         }

+                         WifiRequest request(familyId(), ifaceId());

+                         int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_DRIVER_MEM_DUMP);

+                         if (result != WIFI_SUCCESS) {

+                             ALOGE("Failed to create get driver memory dump request; result = %d", result);

+                             free(mBuff);

+                             return NL_SKIP;

+                          }

+                          nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+                          result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN, mBuffSize);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to put get driver memory dump request; result = %d", result);

+                              return result;

+                          }

+                          result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA, (uint64_t)mBuff);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to put get driver memory dump request; result = %d", result);

+                              return result;

+                          }

+                          request.attr_end(data);

+                          result = requestResponse(request);

+                          if (result != WIFI_SUCCESS) {

+                              ALOGE("Failed to register get driver momory dump response; result = %d", result);

+                          }

+                     } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA) {

+                          ALOGI("Initiating memory dump callback");

+                          if (mcallback.on_driver_memory_dump) {

+                              (*mcallback.on_driver_memory_dump)(mBuff, mBuffSize);

+                          }

+                          if (mBuff) {

+                              free(mBuff);

+                              mBuff = NULL;

+                          }

+                    } else {

+                           ALOGW("Ignoring invalid attribute type = %d, size = %d",

+                           it.get_type(), it.get_len());

+                     }

+                 }

+                 break;

+            case GET_FW_VER:

+            case GET_DRV_VER:

+            case GET_RING_DATA:

+            case GET_RING_STATUS:

+            case GET_FEATURE:

+            case START_RING_LOG:

+            default:

+                   {

+                          ALOGW("Ignoring GetCmdType %d \n", mType);

+                   }

+            }

+        return NL_OK;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        /* NO events! */

+        return NL_SKIP;

+    }

+};

+

+/* API to collect a firmware memory dump for a given iface */

+wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface,

+        wifi_firmware_memory_dump_handler handler)

+{

+    MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler, GET_FW_DUMP);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    return result;

+}

+

+wifi_error wifi_get_driver_memory_dump(wifi_interface_handle iface,

+                                wifi_driver_memory_dump_callbacks callbacks)

+{

+    MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, callbacks, GET_DRIVER_DUMP);

+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+    wifi_error result = (wifi_error)cmd->start();

+    cmd->releaseRef();

+    return result;

+}

+class WifiLoggerCommand: public WifiCommand

+{

+     WLAN_DRIVER_WAKE_REASON_CNT *mGetWakeStats;

+

+public:

+    WifiLoggerCommand(wifi_interface_handle handle, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)

+        : WifiCommand(handle, 0), mGetWakeStats(wifi_wake_reason_cnt)

+    { }

+

+    int createRequest(WifiRequest& request) {

+        int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_WAKE_REASON_STATS);

+        if (result < 0) {

+            return result;

+        }

+

+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);

+

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ, mGetWakeStats->cmd_event_wake_cnt_sz);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put wake_cnt_sz; result = %d", result);

+            return result;

+        }

+        result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ, mGetWakeStats->driver_fw_local_wake_cnt_sz);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("Failed to put driver_fw_local_wake_cnt; result = %d", result);

+            return result;

+        }

+        request.attr_end(data);

+        return result;

+    }

+

+    int start() {

+        ALOGD("Start get wake reason stats command\n");

+        WifiRequest request(familyId(), ifaceId());

+        int result = createRequest(request);

+        if (result < 0) {

+                 ALOGE("Failed to create get wake reason stats request; result = %d\n", result);

+                 return result;

+        }

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+                ALOGE("Failed to register get wake reason stats response; result = %d\n", result);

+        }

+        return result;

+    }

+

+    int handleResponse(WifiEvent& reply) {

+         int len = 0;

+         ALOGD("In WifiLoggerCommand::handleResponse\n");

+

+         if (reply.get_cmd() != NL80211_CMD_VENDOR) {

+             ALOGI("Ignoring reply with cmd = %d", reply.get_cmd());

+             return NL_SKIP;

+        }

+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);

+        len = reply.get_vendor_data_len();

+        if (vendor_data == NULL || len == 0) {

+            ALOGE("No Debug data found");

+            return NL_SKIP;

+       }

+       nl_iterator it(vendor_data);

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_CMD_EVENT_WAKE) {

+            ALOGE("TOTAL_CMD_EVENT_WAKE not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->total_cmd_event_wake = it.get_u32();

+       it.next();

+

+       if(mGetWakeStats->total_cmd_event_wake && mGetWakeStats->cmd_event_wake_cnt) {

+            if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR) {

+                 ALOGE("CMD_EVENT_WAKE_CNT_PTR not found %d", it.get_type());

+                 return NL_SKIP;

+            }

+

+            len = it.get_len();

+            mGetWakeStats->cmd_event_wake_cnt_used = (len < mGetWakeStats->cmd_event_wake_cnt_sz) ? len : mGetWakeStats->cmd_event_wake_cnt_sz;

+            memcpy(mGetWakeStats->cmd_event_wake_cnt, it.get_data(), mGetWakeStats->cmd_event_wake_cnt_used * sizeof(int));

+       } else {

+            mGetWakeStats->cmd_event_wake_cnt_used = 0;

+       }

+

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE) {

+            ALOGE("TOTAL_DRIVER_FW_LOCAL_WAKE not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->total_driver_fw_local_wake = it.get_u32();

+       it.next();

+

+       if(mGetWakeStats->total_driver_fw_local_wake && mGetWakeStats->driver_fw_local_wake_cnt) {

+            if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR) {

+                 ALOGE("DRIVER_FW_LOCAL_WAKE_CNT_PTR not found %d", it.get_type());

+                 return NL_SKIP;

+            }

+

+            len = it.get_len();

+            mGetWakeStats->driver_fw_local_wake_cnt_used= (len < mGetWakeStats->driver_fw_local_wake_cnt_sz) ? len : mGetWakeStats->driver_fw_local_wake_cnt_sz;

+            memcpy(mGetWakeStats->driver_fw_local_wake_cnt, it.get_data(), mGetWakeStats->driver_fw_local_wake_cnt_used * sizeof(int));

+       } else {

+            mGetWakeStats->driver_fw_local_wake_cnt_used= 0;

+       }

+

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_RX_DATA_WAKE) {

+            ALOGE("TOTAL_RX_DATA_WAKE not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->total_rx_data_wake = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_UNICAST_CNT) {

+            ALOGE("RX_UNICAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_details.rx_unicast_cnt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_MULTICAST_CNT) {

+            ALOGE("RX_MULTICAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_details.rx_multicast_cnt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_BROADCAST_CNT) {

+            ALOGE("RX_BROADCAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_details.rx_broadcast_cnt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP_PKT) {

+            ALOGE("ICMP_PKT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_pkt_classification_info .icmp_pkt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_PKT) {

+            ALOGE("ICMP6_PKT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_pkt_classification_info .icmp6_pkt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RA) {

+            ALOGE("ICMP6_RA not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_pkt_classification_info .icmp6_ra = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NA) {

+            ALOGE("ICMP6_NA not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_pkt_classification_info .icmp6_na = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NS) {

+            ALOGE("ICMP6_NS not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_wake_pkt_classification_info .icmp6_ns = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP4_RX_MULTICAST_CNT) {

+            ALOGE("ICMP4_RX_MULTICAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RX_MULTICAST_CNT) {

+            ALOGE("ICMP6_RX_MULTICAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt = it.get_u32();

+       it.next();

+

+       if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_OTHER_RX_MULTICAST_CNT) {

+            ALOGE("OTHER_RX_MULTICAST_CNT not found %d", it.get_type());

+            return NL_SKIP;

+       }

+

+       mGetWakeStats->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt = it.get_u32();

+

+       return NL_OK;

+    }

+

+    int handleEvent(WifiEvent& event) {

+        /* NO events to handle here! */

+        return NL_SKIP;

+    }

+};

+

+ /* Function to get wake lock stats */

+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,

+                             WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)

+{

+    if(wifi_wake_reason_cnt) {

+        WifiLoggerCommand *cmd =  new WifiLoggerCommand(iface,wifi_wake_reason_cnt);

+        NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);

+        wifi_error result = (wifi_error)cmd->start();

+        cmd->releaseRef();

+        return result;

+    } else {

+        ALOGE("Reason cnt NULL");

+        return  WIFI_ERROR_INVALID_ARGS;

+    }

+}

+

diff --git a/wifi_nan.cpp b/wifi_nan.cpp
new file mode 100755
index 0000000..35c01ee
--- /dev/null
+++ b/wifi_nan.cpp
@@ -0,0 +1,1419 @@
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+#define SLSI_WIFI_HAL_NAN_VERSION 1
+
+#define CHECK_WIFI_STATUS_RETURN_FAIL(result, LOGSTR) \
+    if (result != WIFI_SUCCESS) {\
+        ALOGE(LOGSTR" [result:%d]", result);\
+        return result;\
+    }
+
+#define CHECK_CONFIG_PUT_8_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+    if (config) {\
+        result = request.put_u8(nan_attribute, val); \
+        if (result != WIFI_SUCCESS) {\
+            ALOGE(FAIL_STR" [result:%d]", result);\
+            return result;\
+        }\
+    }
+
+#define CHECK_CONFIG_PUT_16_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+    if (config) {\
+        result = request.put_u16(nan_attribute, val); \
+        if (result != WIFI_SUCCESS) {\
+            ALOGE(FAIL_STR" [result:%d]", result);\
+            return result;\
+        }\
+    }
+
+
+#define CHECK_CONFIG_PUT_32_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+    if (config) {\
+        result = request.put_u32(nan_attribute, val); \
+        if (result != WIFI_SUCCESS) {\
+            ALOGE(FAIL_STR" [result:%d]", result);\
+            return result;\
+        }\
+    }
+
+#define CHECK_CONFIG_PUT_RETURN_FAIL(config, valptr, len, nan_attribute, request, result, FAIL_STR) \
+    if (config) {\
+        result = request.put(nan_attribute, valptr, len); \
+        if (result != WIFI_SUCCESS) {\
+            ALOGE(FAIL_STR" [result:%d]", result);\
+            return result;\
+        }\
+    }
+
+typedef enum {
+    NAN_REQ_ATTR_MASTER_PREF,
+    NAN_REQ_ATTR_CLUSTER_LOW,
+    NAN_REQ_ATTR_CLUSTER_HIGH,
+    NAN_REQ_ATTR_HOP_COUNT_LIMIT_VAL,
+    NAN_REQ_ATTR_SID_BEACON_VAL,
+
+    NAN_REQ_ATTR_SUPPORT_2G4_VAL,
+    NAN_REQ_ATTR_SUPPORT_5G_VAL,
+
+    NAN_REQ_ATTR_RSSI_CLOSE_2G4_VAL,
+    NAN_REQ_ATTR_RSSI_MIDDLE_2G4_VAL,
+    NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL,
+    NAN_REQ_ATTR_BEACONS_2G4_VAL,
+    NAN_REQ_ATTR_SDF_2G4_VAL,
+    NAN_REQ_ATTR_CHANNEL_2G4_MHZ_VAL,
+    NAN_REQ_ATTR_RSSI_PROXIMITY_VAL,
+
+
+    NAN_REQ_ATTR_RSSI_CLOSE_5G_VAL,
+    NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL,
+    NAN_REQ_ATTR_RSSI_MIDDLE_5G_VAL,
+    NAN_REQ_ATTR_RSSI_PROXIMITY_5G_VAL,
+    NAN_REQ_ATTR_BEACON_5G_VAL,
+    NAN_REQ_ATTR_SDF_5G_VAL,
+    NAN_REQ_ATTR_CHANNEL_5G_MHZ_VAL,
+
+    NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL,
+    NAN_REQ_ATTR_OUI_VAL,
+    NAN_REQ_ATTR_MAC_ADDR_VAL,
+    NAN_REQ_ATTR_CLUSTER_VAL,
+    NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME,
+    NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD,
+    NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL,
+    NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL,
+    NAN_REQ_ATTR_CONN_CAPABILITY_PAYLOAD_TX,
+    NAN_REQ_ATTR_CONN_CAPABILITY_IBSS,
+    NAN_REQ_ATTR_CONN_CAPABILITY_WFD,
+    NAN_REQ_ATTR_CONN_CAPABILITY_WFDS,
+    NAN_REQ_ATTR_CONN_CAPABILITY_TDLS,
+    NAN_REQ_ATTR_CONN_CAPABILITY_MESH,
+    NAN_REQ_ATTR_CONN_CAPABILITY_WLAN_INFRA,
+    NAN_REQ_ATTR_DISCOVERY_ATTR_NUM_ENTRIES,
+    NAN_REQ_ATTR_DISCOVERY_ATTR_VAL,
+    NAN_REQ_ATTR_CONN_TYPE,
+    NAN_REQ_ATTR_NAN_ROLE,
+    NAN_REQ_ATTR_TRANSMIT_FREQ,
+    NAN_REQ_ATTR_AVAILABILITY_DURATION,
+    NAN_REQ_ATTR_AVAILABILITY_INTERVAL,
+    NAN_REQ_ATTR_MESH_ID_LEN,
+    NAN_REQ_ATTR_MESH_ID,
+    NAN_REQ_ATTR_INFRASTRUCTURE_SSID_LEN,
+    NAN_REQ_ATTR_INFRASTRUCTURE_SSID,
+    NAN_REQ_ATTR_FURTHER_AVAIL_NUM_ENTRIES,
+    NAN_REQ_ATTR_FURTHER_AVAIL_VAL,
+    NAN_REQ_ATTR_FURTHER_AVAIL_ENTRY_CTRL,
+    NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_CLASS,
+    NAN_REQ_ATTR_FURTHER_AVAIL_CHAN,
+    NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_MAPID,
+    NAN_REQ_ATTR_FURTHER_AVAIL_INTERVAL_BITMAP,
+    NAN_REQ_ATTR_PUBLISH_ID,
+    NAN_REQ_ATTR_PUBLISH_TTL,
+    NAN_REQ_ATTR_PUBLISH_PERIOD,
+    NAN_REQ_ATTR_PUBLISH_TYPE,
+    NAN_REQ_ATTR_PUBLISH_TX_TYPE,
+    NAN_REQ_ATTR_PUBLISH_COUNT,
+    NAN_REQ_ATTR_PUBLISH_SERVICE_NAME_LEN,
+    NAN_REQ_ATTR_PUBLISH_SERVICE_NAME,
+    NAN_REQ_ATTR_PUBLISH_MATCH_ALGO,
+    NAN_REQ_ATTR_PUBLISH_SERVICE_INFO_LEN,
+    NAN_REQ_ATTR_PUBLISH_SERVICE_INFO,
+    NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER_LEN,
+    NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER,
+    NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER_LEN,
+    NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER,
+    NAN_REQ_ATTR_PUBLISH_RSSI_THRESHOLD_FLAG,
+    NAN_REQ_ATTR_PUBLISH_CONN_MAP,
+    NAN_REQ_ATTR_PUBLISH_RECV_IND_CFG,
+    NAN_REQ_ATTR_SUBSCRIBE_ID,
+    NAN_REQ_ATTR_SUBSCRIBE_TTL,
+    NAN_REQ_ATTR_SUBSCRIBE_PERIOD,
+    NAN_REQ_ATTR_SUBSCRIBE_TYPE,
+    NAN_REQ_ATTR_SUBSCRIBE_RESP_FILTER_TYPE,
+    NAN_REQ_ATTR_SUBSCRIBE_RESP_INCLUDE,
+    NAN_REQ_ATTR_SUBSCRIBE_USE_RESP_FILTER,
+    NAN_REQ_ATTR_SUBSCRIBE_SSI_REQUIRED,
+    NAN_REQ_ATTR_SUBSCRIBE_MATCH_INDICATOR,
+    NAN_REQ_ATTR_SUBSCRIBE_COUNT,
+    NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME_LEN,
+    NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME,
+    NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO_LEN,
+    NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO,
+    NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER_LEN,
+    NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER,
+    NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER_LEN,
+    NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER,
+    NAN_REQ_ATTR_SUBSCRIBE_RSSI_THRESHOLD_FLAG,
+    NAN_REQ_ATTR_SUBSCRIBE_CONN_MAP,
+    NAN_REQ_ATTR_SUBSCRIBE_NUM_INTF_ADDR_PRESENT,
+    NAN_REQ_ATTR_SUBSCRIBE_INTF_ADDR,
+    NAN_REQ_ATTR_SUBSCRIBE_RECV_IND_CFG,
+    NAN_REQ_ATTR_FOLLOWUP_ID,
+    NAN_REQ_ATTR_FOLLOWUP_REQUESTOR_ID,
+    NAN_REQ_ATTR_FOLLOWUP_ADDR,
+    NAN_REQ_ATTR_FOLLOWUP_PRIORITY,
+    NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME_LEN,
+    NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME,
+    NAN_REQ_ATTR_FOLLOWUP_TX_WINDOW,
+    NAN_REQ_ATTR_FOLLOWUP_RECV_IND_CFG,
+} NAN_REQ_ATTRIBUTES;
+
+typedef enum {
+	NAN_REPLY_ATTR_STATUS_TYPE,
+	NAN_REPLY_ATTR_VALUE,
+	NAN_REPLY_ATTR_RESPONSE_TYPE,
+	NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE,
+	NAN_REPLY_ATTR_CAP_MAX_CONCURRENT_CLUSTER,
+	NAN_REPLY_ATTR_CAP_MAX_PUBLISHES,
+	NAN_REPLY_ATTR_CAP_MAX_SUBSCRIBES,
+	NAN_REPLY_ATTR_CAP_MAX_SERVICE_NAME_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_MATCH_FILTER_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_TOTAL_MATCH_FILTER_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_SERVICE_SPECIFIC_INFO_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_VSA_DATA_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_MESH_DATA_LEN,
+	NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES,
+	NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS,
+	NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN,
+} NAN_RESP_ATTRIBUTES;
+
+typedef enum {
+    NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID,
+    NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID,
+    NAN_EVT_ATTR_MATCH_ADDR,
+    NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO_LEN,
+    NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO,
+    NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER_LEN,
+    NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER,
+    NAN_EVT_ATTR_MATCH_MATCH_OCCURED_FLAG,
+    NAN_EVT_ATTR_MATCH_OUT_OF_RESOURCE_FLAG,
+    NAN_EVT_ATTR_MATCH_RSSI_VALUE,
+/*CONN_CAPABILITY*/
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFD_SUPPORTED,
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFDS_SUPPORTED,
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_TDLS_SUPPORTED,
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_IBSS_SUPPORTED,
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_MESH_SUPPORTED,
+    NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_WLAN_INFRA_FIELD,
+    NAN_EVT_ATTR_MATCH_NUM_RX_DISCOVERY_ATTR,
+    NAN_EVT_ATTR_MATCH_RX_DISCOVERY_ATTR,
+/*NANRECEIVEPOSTDISCOVERY DISCOVERY_ATTR,*/
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_TYPE,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_ROLE,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_DURATION,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_AVAIL_INTERVAL_BITMAP,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_MAPID,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_ADDR,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID_LEN,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_LEN,
+    NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_VAL,
+
+    NAN_EVT_ATTR_MATCH_NUM_CHANS,
+    NAN_EVT_ATTR_MATCH_FAMCHAN,
+/*FAMCHAN[32],*/
+    NAN_EVT_ATTR_MATCH_FAM_ENTRY_CONTROL,
+    NAN_EVT_ATTR_MATCH_FAM_CLASS_VAL,
+    NAN_EVT_ATTR_MATCH_FAM_CHANNEL,
+    NAN_EVT_ATTR_MATCH_FAM_MAPID,
+    NAN_EVT_ATTR_MATCH_FAM_AVAIL_INTERVAL_BITMAP,
+    NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE_LEN,
+    NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE,
+    NAN_EVT_ATTR_PUBLISH_ID,
+    NAN_EVT_ATTR_PUBLISH_REASON,
+    NAN_EVT_ATTR_SUBSCRIBE_ID,
+    NAN_EVT_ATTR_SUBSCRIBE_REASON,
+    NAN_EVT_ATTR_DISABLED_REASON,
+    NAN_EVT_ATTR_FOLLOWUP_PUBLISH_SUBSCRIBE_ID,
+    NAN_EVT_ATTR_FOLLOWUP_REQUESTOR_INSTANCE_ID,
+    NAN_EVT_ATTR_FOLLOWUP_ADDR,
+    NAN_EVT_ATTR_FOLLOWUP_DW_OR_FAW,
+    NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO_LEN,
+    NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO,
+    NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE	,
+    NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR,
+    NAN_EVT_ATTR_DISCOVERY_ENGINE_CLUSTER
+
+} NAN_EVT_ATTRIBUTES;
+
+class NanCommand : public WifiCommand {
+    static NanCallbackHandler callbackEventHandler;
+    int subscribeID[2];
+    int publishID[2];
+    int followupID[2];
+    int version;
+    NanCapabilities capabilities;
+
+    void registerNanEvents(void) {
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_PUBLISH_TERMINATED);
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH);
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH_EXPIRED);
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED);
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_FOLLOWUP);
+        registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_DISCOVERY_ENGINE);
+    }
+
+    void unregisterNanEvents(void) {
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_PUBLISH_TERMINATED);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH_EXPIRED);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_FOLLOWUP);
+        unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_DISCOVERY_ENGINE);
+    }
+
+    int processResponse(WifiEvent &reply, NanResponseMsg *response) {
+        NanCapabilities *capabilities = &response->body.nan_capabilities;
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        unsigned int val;
+
+        for(nl_iterator nl_itr(vendor_data); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_REPLY_ATTR_STATUS_TYPE:
+                response->status = NanStatusType(nl_itr.get_u32());
+                break;
+            case NAN_REPLY_ATTR_VALUE:
+                val = nl_itr.get_u32();
+                if (val) {
+                    strncpy(response->nan_error, "Lower_layer_error",NAN_ERROR_STR_LEN);
+                }
+                break;
+            case NAN_REPLY_ATTR_RESPONSE_TYPE:
+                response->response_type = NanResponseType(nl_itr.get_u32());
+                break;
+            case NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE:
+                response->body.publish_response.publish_id = nl_itr.get_u16();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_CONCURRENT_CLUSTER:
+                capabilities->max_concurrent_nan_clusters = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_PUBLISHES:
+                capabilities->max_publishes = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_SUBSCRIBES:
+                capabilities->max_subscribes = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_SERVICE_NAME_LEN:
+                capabilities->max_service_name_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_MATCH_FILTER_LEN:
+                capabilities->max_match_filter_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_TOTAL_MATCH_FILTER_LEN:
+                capabilities->max_total_match_filter_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_SERVICE_SPECIFIC_INFO_LEN:
+                capabilities->max_service_specific_info_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_VSA_DATA_LEN:
+                capabilities->max_vsa_data_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_MESH_DATA_LEN:
+                capabilities->max_mesh_data_len = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES:
+                capabilities->max_ndi_interfaces = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS:
+                capabilities->max_ndp_sessions = nl_itr.get_u32();
+                break;
+            case NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN:
+                capabilities->max_app_info_len = nl_itr.get_u32();
+                break;
+            default :
+                ALOGE("received unknown type(%d) in response", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+        this->capabilities = *capabilities;
+        return NL_OK;
+    }
+
+    int processMatchEvent(WifiEvent &event) {
+        NanMatchInd ind;
+        memset(&ind,0,sizeof(NanMatchInd));
+        int famchan_idx = 0, disc_idx = 0;
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+
+        for(nl_iterator nl_itr(vendor_data); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID:
+                ind.publish_subscribe_id = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID:
+                ind.requestor_instance_id = nl_itr.get_u32();
+                break;
+            case NAN_EVT_ATTR_MATCH_ADDR:
+                memcpy(ind.addr, nl_itr.get_data(), NAN_MAC_ADDR_LEN);
+                break;
+            case NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO_LEN:
+                ind.service_specific_info_len = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO:
+                memcpy(ind.service_specific_info, nl_itr.get_data(), ind.service_specific_info_len);
+                break;
+            case NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER_LEN:
+                ind.sdf_match_filter_len = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER:
+                memcpy(ind.sdf_match_filter, nl_itr.get_data(), ind.sdf_match_filter_len);
+                break;
+            case NAN_EVT_ATTR_MATCH_MATCH_OCCURED_FLAG:
+                ind.match_occured_flag = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_OUT_OF_RESOURCE_FLAG:
+                ind.out_of_resource_flag = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_RSSI_VALUE:
+                ind.rssi_value = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_IBSS_SUPPORTED:
+                ind.conn_capability.is_ibss_supported = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFD_SUPPORTED:
+                ind.conn_capability.is_wfd_supported = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFDS_SUPPORTED:
+                ind.conn_capability.is_wfds_supported = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_TDLS_SUPPORTED:
+                ind.conn_capability.is_tdls_supported = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_MESH_SUPPORTED:
+                ind.conn_capability.is_mesh_supported= nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_WLAN_INFRA_FIELD:
+                ind.conn_capability.wlan_infra_field = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_NUM_RX_DISCOVERY_ATTR:
+                ind.num_rx_discovery_attr = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_RX_DISCOVERY_ATTR:
+                NanReceivePostDiscovery *disc_attr;
+                disc_attr = &ind.discovery_attr[disc_idx];
+                disc_idx++;
+                for(nl_iterator nl_nested_itr((struct nlattr *)nl_itr.get_data()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+                    switch(nl_nested_itr.get_type()) {
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_TYPE:
+                        disc_attr->type = (NanConnectionType)nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_ROLE:
+                        disc_attr->role = (NanDeviceRole)nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_DURATION:
+                        disc_attr->duration = (NanAvailDuration)nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_AVAIL_INTERVAL_BITMAP:
+                        disc_attr->avail_interval_bitmap = nl_nested_itr.get_u32();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_MAPID:
+                        disc_attr->mapid = nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_ADDR:
+                        memcpy(disc_attr->addr, nl_nested_itr.get_data(), NAN_MAC_ADDR_LEN);
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID_LEN:
+                        disc_attr->mesh_id_len = nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID:
+                        memcpy(disc_attr->mesh_id, nl_nested_itr.get_data(), disc_attr->mesh_id_len);
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_LEN:
+                        disc_attr->infrastructure_ssid_len = nl_nested_itr.get_u16();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_VAL:
+                        memcpy(disc_attr->infrastructure_ssid_val, nl_nested_itr.get_data(), disc_attr->infrastructure_ssid_len);
+                        break;
+                    }
+                }
+                break;
+            case NAN_EVT_ATTR_MATCH_NUM_CHANS:
+                ind.num_chans = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_FAMCHAN:
+                NanFurtherAvailabilityChannel *famchan;
+                famchan = &ind.famchan[famchan_idx];
+                famchan_idx++;
+                for(nl_iterator nl_nested_itr((struct nlattr *)nl_itr.get_data()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+                    switch(nl_nested_itr.get_type()) {
+                    case NAN_EVT_ATTR_MATCH_FAM_ENTRY_CONTROL:
+                        famchan->entry_control = (NanAvailDuration)nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_FAM_CLASS_VAL:
+                        famchan->class_val = nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_FAM_CHANNEL:
+                        famchan->channel = nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_FAM_MAPID:
+                        famchan->mapid = nl_nested_itr.get_u8();
+                        break;
+                    case NAN_EVT_ATTR_MATCH_FAM_AVAIL_INTERVAL_BITMAP:
+                        famchan->avail_interval_bitmap = nl_nested_itr.get_u32();
+                        break;
+                    }
+                }
+                break;
+            case NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE_LEN:
+                ind.cluster_attribute_len = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE:
+                memcpy(ind.cluster_attribute, nl_itr.get_data(), ind.cluster_attribute_len);
+                break;
+            }
+        }
+
+        if (this->callbackEventHandler.EventMatch)
+            this->callbackEventHandler.EventMatch(&ind);
+        return NL_OK;
+    }
+
+    int processMatchExpiredEvent(WifiEvent &event) {
+        NanMatchExpiredInd ind;
+        memset(&ind,0,sizeof(NanMatchExpiredInd));
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID:
+                ind.publish_subscribe_id = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID:
+                ind.requestor_instance_id = nl_itr.get_u32();
+                break;
+            default :
+                ALOGE("processMatchExpiredEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+
+        if (callbackEventHandler.EventMatchExpired)
+            callbackEventHandler.EventMatchExpired(&ind);
+
+        return NL_OK;
+    }
+
+    int processPublishTerminatedEvent(WifiEvent &event) {
+        NanPublishTerminatedInd ind;
+        memset(&ind,0,sizeof(ind));
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_PUBLISH_ID:
+                ind.publish_id = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_PUBLISH_REASON:
+                ind.reason = (NanStatusType)nl_itr.get_u32();
+                break;
+            default :
+                ALOGE("processPublishTerminatedEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+
+        if (callbackEventHandler.EventPublishTerminated)
+            callbackEventHandler.EventPublishTerminated(&ind);
+
+        return NL_OK;
+
+    }
+
+    int processSubscribeTerminatedEvent(WifiEvent &event) {
+        NanSubscribeTerminatedInd ind;
+        memset(&ind,0,sizeof(ind));
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_SUBSCRIBE_ID:
+                ind.subscribe_id = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_SUBSCRIBE_REASON:
+                ind.reason = (NanStatusType)nl_itr.get_u32();
+                break;
+            default :
+                ALOGE("processSubscribeTerminatedEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+
+        if (callbackEventHandler.EventSubscribeTerminated)
+            callbackEventHandler.EventSubscribeTerminated(&ind);
+
+        return NL_OK;
+    }
+
+    int processFollowupEvent(WifiEvent &event) {
+        NanFollowupInd ind;
+        memset(&ind,0,sizeof(ind));
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_FOLLOWUP_PUBLISH_SUBSCRIBE_ID:
+                ind.publish_subscribe_id = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_FOLLOWUP_REQUESTOR_INSTANCE_ID:
+                ind.requestor_instance_id = nl_itr.get_u32();
+                break;
+            case NAN_EVT_ATTR_FOLLOWUP_ADDR:
+                memcpy(ind.addr, nl_itr.get_data(), NAN_MAC_ADDR_LEN);
+                break;
+            case NAN_EVT_ATTR_FOLLOWUP_DW_OR_FAW:
+                ind.dw_or_faw = nl_itr.get_u8();
+                break;
+            case NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO_LEN:
+                ind.service_specific_info_len = nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO:
+                memcpy(ind.service_specific_info, nl_itr.get_data(), ind.service_specific_info_len);
+                break;
+            default :
+                ALOGE("processNanDisabledEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+
+        if (callbackEventHandler.EventFollowup)
+            callbackEventHandler.EventFollowup(&ind);
+
+        return NL_OK;
+    }
+
+    int processNanDisabledEvent(WifiEvent &event) {
+        NanDisabledInd ind;
+        memset(&ind,0,sizeof(ind));
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_DISABLED_REASON:
+                ind.reason = (NanStatusType)nl_itr.get_u32();
+                break;
+            default :
+                ALOGE("processNanDisabledEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+
+        if (callbackEventHandler.EventDisabled)
+            callbackEventHandler.EventDisabled(&ind);
+
+        return NL_OK;
+    }
+
+    int processNanDiscoveryEvent(WifiEvent &event) {
+        NanDiscEngEventInd ind;
+        memset(&ind,0,sizeof(ind));
+        u8 *addr = NULL;
+
+        for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+            switch(nl_itr.get_type()) {
+            case NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE:
+                ind.event_type = (NanDiscEngEventType)nl_itr.get_u16();
+                break;
+            case NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR:
+                addr = (u8 *)nl_itr.get_data();
+                break;
+            default :
+                ALOGE("processNanDiscoveryEvent: unknown attribute(%d)", nl_itr.get_type());
+                return NL_SKIP;
+            }
+        }
+        if (addr) {
+            if (ind.event_type == NAN_EVENT_ID_DISC_MAC_ADDR)
+                memcpy(ind.data.mac_addr.addr, addr, NAN_MAC_ADDR_LEN);
+            else
+                memcpy(ind.data.cluster.addr, addr, NAN_MAC_ADDR_LEN);
+        } else {
+            ALOGE("processNanDiscoveryEvent: No Mac/cluster Address");
+        }
+
+        if (callbackEventHandler.EventDiscEngEvent)
+            callbackEventHandler.EventDiscEngEvent(&ind);
+
+        return NL_OK;
+    }
+
+public:
+    NanCommand(wifi_interface_handle iface, int id)
+        : WifiCommand(iface, id)
+    {
+        subscribeID[0] = 0;
+        subscribeID[1] = 0;
+        publishID[0] = 0;
+        publishID[1] = 0;
+        followupID[0] = 0;
+        followupID[0] = 0;
+        version = 0;
+        memset(&capabilities, 0, sizeof(capabilities));
+    }
+
+    int enable(NanEnableRequest *msg) {
+        ALOGD("Start NAN...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_ENABLE);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("enable: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+        /* Valid master pref values are 2-254 */
+        int master_pref;
+        if (msg->master_pref < 2)
+            master_pref = 2;
+        else if (msg->master_pref > 254)
+            master_pref = 254;
+        else
+            master_pref = msg->master_pref;
+        result = request.put_u8(NAN_REQ_ATTR_MASTER_PREF, master_pref);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put master_pref");
+
+        result = request.put_u16(NAN_REQ_ATTR_CLUSTER_LOW, msg->cluster_low);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put cluster_low");
+
+        result = request.put_u16(NAN_REQ_ATTR_CLUSTER_HIGH, msg->cluster_high);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put cluster_high");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_support_5g, msg->support_5g_val,
+                    NAN_REQ_ATTR_SUPPORT_5G_VAL, request, result, "enable:Failed to put support_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_sid_beacon, msg->sid_beacon_val,
+                    NAN_REQ_ATTR_SID_BEACON_VAL, request, result, "enable:Failed to put sid_beacon_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_close, msg->rssi_close_2dot4g_val,
+                    NAN_REQ_ATTR_RSSI_CLOSE_2G4_VAL, request, result, "enable:Failed to put rssi_close_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_middle, msg->rssi_middle_2dot4g_val,
+                    NAN_REQ_ATTR_RSSI_MIDDLE_2G4_VAL, request, result, "enable:Failed to put rssi_middle_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_proximity, msg->rssi_proximity_2dot4g_val,
+                    NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL, request, result, "enable:Failed to put rssi_proximity_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_limit, msg->hop_count_limit_val,
+                    NAN_REQ_ATTR_HOP_COUNT_LIMIT_VAL, request, result, "enable:Failed to put hop_count_limit_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_support, msg->support_2dot4g_val,
+                    NAN_REQ_ATTR_SUPPORT_2G4_VAL, request, result, "enable:Failed to put support_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_beacons, msg->beacon_2dot4g_val,
+                    NAN_REQ_ATTR_BEACONS_2G4_VAL, request, result, "enable:Failed to put beacon_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_sdf, msg->sdf_2dot4g_val,
+                    NAN_REQ_ATTR_SDF_2G4_VAL, request, result, "enable:Failed to put sdf_2dot4g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_beacons, msg->beacon_5g_val,
+                    NAN_REQ_ATTR_BEACON_5G_VAL, request, result, "enable:Failed to put beacon_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_sdf, msg->sdf_5g_val,
+                    NAN_REQ_ATTR_SDF_5G_VAL, request, result, "enable:Failed to put sdf_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close, msg->rssi_close_5g_val,
+                    NAN_REQ_ATTR_RSSI_CLOSE_5G_VAL, request, result, "enable:Failed to put rssi_close_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_middle, msg->rssi_middle_5g_val,
+                    NAN_REQ_ATTR_RSSI_MIDDLE_5G_VAL, request, result, "enable:Failed to put rssi_middle_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close_proximity, msg->rssi_close_proximity_5g_val,
+                    NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL, request, result, "enable:Failed to put rssi_close_proximity_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_window_size, msg->rssi_window_size_val,
+                    NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL, request, result, "enable:Failed to put rssi_window_size_val");
+
+        CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_oui, msg->oui_val,
+                    NAN_REQ_ATTR_OUI_VAL, request, result, "enable:Failed to put oui_val");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_intf_addr, msg->intf_addr_val, NAN_MAC_ADDR_LEN,
+                    NAN_REQ_ATTR_MAC_ADDR_VAL, request, result, "enable:Failed to put intf_addr_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->config_cluster_attribute_val,
+                    NAN_REQ_ATTR_CLUSTER_VAL, request, result, "enable:Failed to put config_cluster_attribute_val");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.dwell_time, sizeof(msg->scan_params_val.dwell_time),
+                    NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME, request, result, "enable:Failed to put scan_params_val.dwell_time");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.scan_period, sizeof(msg->scan_params_val.scan_period),
+                    NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD, request, result, "enable:Failed to put scan_params_val.scan_period");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_random_factor_force, msg->random_factor_force_val,
+                    NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL, request, result, "enable:Failed to put random_factor_force_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_force, msg->hop_count_force_val,
+                    NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL, request, result, "enable:Failed to put hop_count_force_val");
+
+        CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_24g_channel, msg->channel_24g_val,
+                    NAN_REQ_ATTR_CHANNEL_2G4_MHZ_VAL, request, result, "enable:Failed to put channel_24g_val");
+
+        CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_5g_channel, msg->channel_5g_val,
+                    NAN_REQ_ATTR_CHANNEL_5G_MHZ_VAL, request, result, "enable:Failed to put channel_5g_val");
+
+        request.attr_end(data);
+
+        registerNanEvents();
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to NAN; result = %d", result);
+            unregisterNanEvents();
+        } else {
+            ALOGD("Start NAN...success");
+        }
+        return result;
+    }
+
+    int disable()
+    {
+        ALOGD("Stop NAN...");
+        WifiRequest request(familyId(), ifaceId());
+
+        unregisterNanEvents();
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_DISABLE);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "disable:Failed to create WifiRequest");
+        result = requestResponse(request);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "disable:Failed to requestResponse");
+        return result;
+    }
+
+    int config(NanConfigRequest *msg) {
+        ALOGD("NAN config...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_CONFIG);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "config:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("config: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_sid_beacon, msg->sid_beacon,
+                    NAN_REQ_ATTR_SID_BEACON_VAL, request, result, "config:Failed to put sid_beacon");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_proximity, msg->rssi_proximity,
+                    NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL, request, result, "config:Failed to put rssi_proximity");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_master_pref, msg->master_pref,
+                    NAN_REQ_ATTR_MASTER_PREF, request, result, "config:Failed to put master_pref");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close_proximity, msg->rssi_close_proximity_5g_val,
+                    NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL, request, result, "config:Failed to put rssi_close_proximity_5g_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_window_size, msg->rssi_window_size_val,
+                    NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL, request, result, "config:Failed to put rssi_window_size_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->config_cluster_attribute_val,
+                    NAN_REQ_ATTR_CLUSTER_VAL, request, result, "config:Failed to put config_cluster_attribute_val");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.dwell_time, sizeof(msg->scan_params_val.dwell_time),
+                    NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME, request, result, "config:Failed to put scan_params_val.dwell_time");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.scan_period, sizeof(msg->scan_params_val.scan_period),
+                    NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD, request, result, "config:Failed to put scan_params_val.scan_period");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_random_factor_force, msg->random_factor_force_val,
+                    NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL, request, result, "config:Failed to put random_factor_force_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_force, msg->hop_count_force_val,
+                    NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL, request, result, "config:Failed to put hop_count_force_val");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.payload_transmit_flag,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_PAYLOAD_TX, request, result, "config:Failed to put payload_transmit_flag");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_wfd_supported,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_WFD, request, result, "config:Failed to put is_wfd_supported");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_wfds_supported,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_WFDS, request, result, "config:Failed to put is_wfds_supported");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_tdls_supported,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_TDLS, request, result, "config:Failed to put is_tdls_supported");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_ibss_supported,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_IBSS, request, result, "config:Failed to put is_ibss_supported");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_mesh_supported,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_MESH, request, result, "config:Failed to put is_mesh_supported");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.wlan_infra_field,
+                    NAN_REQ_ATTR_CONN_CAPABILITY_WLAN_INFRA, request, result, "config:Failed to put wlan_infra_field");
+
+        if (msg->num_config_discovery_attr) {
+            CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->num_config_discovery_attr,
+                        NAN_REQ_ATTR_DISCOVERY_ATTR_NUM_ENTRIES, request, result, "config:Failed to put msg->num_config_discovery_attr");
+            for (int i = 0; i < msg->num_config_discovery_attr; i++) {
+                nlattr *nl_disc_attribute = request.attr_start(NAN_REQ_ATTR_DISCOVERY_ATTR_VAL);
+                NanTransmitPostDiscovery *discovery_attr = &msg->discovery_attr_val[i];
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->type,
+                    NAN_REQ_ATTR_CONN_TYPE, request, result, "config:Failed to put discovery_attr->type");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->role,
+                    NAN_REQ_ATTR_NAN_ROLE, request, result, "config:Failed to put discovery_attr->role");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->transmit_freq,
+                    NAN_REQ_ATTR_TRANSMIT_FREQ, request, result, "config:Failed to put discovery_attr->transmit_freq");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->duration,
+                    NAN_REQ_ATTR_AVAILABILITY_DURATION, request, result, "config:Failed to put discovery_attr->duration");
+                CHECK_CONFIG_PUT_32_RETURN_FAIL(1, discovery_attr->avail_interval_bitmap,
+                    NAN_REQ_ATTR_AVAILABILITY_INTERVAL, request, result, "config:Failed to put discovery_attr->avail_interval_bitmap");
+                CHECK_CONFIG_PUT_RETURN_FAIL(1, discovery_attr->addr, NAN_MAC_ADDR_LEN,
+                    NAN_REQ_ATTR_MAC_ADDR_VAL, request, result, "config:Failed to put discovery_attr->addr");
+                CHECK_CONFIG_PUT_16_RETURN_FAIL(1, discovery_attr->mesh_id_len,
+                    NAN_REQ_ATTR_MESH_ID_LEN, request, result, "config:Failed to put discovery_attr->mesh_id");
+                CHECK_CONFIG_PUT_RETURN_FAIL(discovery_attr->mesh_id_len, discovery_attr->mesh_id, discovery_attr->mesh_id_len,
+                    NAN_REQ_ATTR_MESH_ID, request, result, "config:Failed to put discovery_attr->mesh_id");
+                CHECK_CONFIG_PUT_16_RETURN_FAIL(1, discovery_attr->infrastructure_ssid_len,
+                    NAN_REQ_ATTR_INFRASTRUCTURE_SSID_LEN, request, result, "config:Failed to put discovery_attr->infrastructure_ssid_val");
+                CHECK_CONFIG_PUT_RETURN_FAIL(discovery_attr->infrastructure_ssid_len, discovery_attr->infrastructure_ssid_val, discovery_attr->infrastructure_ssid_len,
+                    NAN_REQ_ATTR_INFRASTRUCTURE_SSID, request, result, "config:Failed to put discovery_attr->infrastructure_ssid_val");
+                request.attr_end(nl_disc_attribute);
+            }
+        }
+
+        if (msg->config_fam) {
+            CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->fam_val.numchans,
+                        NAN_REQ_ATTR_FURTHER_AVAIL_NUM_ENTRIES, request, result, "config:Failed to put msg->fam_val.numchans");
+            for (int i = 0; i < msg->fam_val.numchans; i++) {
+                nlattr *nl_fam_attribute = request.attr_start(NAN_REQ_ATTR_FURTHER_AVAIL_VAL);
+                NanFurtherAvailabilityChannel *further_avail_chan = &msg->fam_val.famchan[i];
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->entry_control,
+                            NAN_REQ_ATTR_FURTHER_AVAIL_ENTRY_CTRL, request, result, "config:Failed to put further_avail_chan->entry_control");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->class_val,
+                            NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_CLASS, request, result, "config:Failed to put further_avail_chan->class_val");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->channel,
+                            NAN_REQ_ATTR_FURTHER_AVAIL_CHAN, request, result, "config:Failed to put further_avail_chan->channel");
+                CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->mapid,
+                            NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_MAPID, request, result, "config:Failed to put further_avail_chan->mapid");
+                CHECK_CONFIG_PUT_32_RETURN_FAIL(1, further_avail_chan->avail_interval_bitmap,
+                            NAN_REQ_ATTR_FURTHER_AVAIL_INTERVAL_BITMAP, request, result, "config:Failed to put further_avail_chan->avail_interval_bitmap");
+                request.attr_end(nl_fam_attribute);
+            }
+        }
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to set_config; result = %d", result);
+        } else {
+            ALOGD("NAN config...success");
+        }
+        return result;
+    }
+
+    static int setCallbackHandler(NanCallbackHandler handlers) {
+        callbackEventHandler = handlers;
+        return WIFI_SUCCESS;
+    }
+
+    static int getVersion(NanVersion *version) {
+        *version = SLSI_WIFI_HAL_NAN_VERSION;
+        return WIFI_SUCCESS;
+    }
+
+    int publish(NanPublishRequest *msg) {
+        ALOGD("NAN publish...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISH);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "publish:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("publish: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->publish_id, msg->publish_id,
+                NAN_REQ_ATTR_PUBLISH_ID, request, result, "publish:Failed to put msg->publish_id");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->ttl, msg->ttl,
+                NAN_REQ_ATTR_PUBLISH_TTL, request, result, "publish:Failed to put msg->ttl");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->period,
+                NAN_REQ_ATTR_PUBLISH_PERIOD, request, result, "publish:Failed to put msg->period");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_type,
+                NAN_REQ_ATTR_PUBLISH_TYPE, request, result, "publish:Failed to put msg->publish_type");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->tx_type,
+                NAN_REQ_ATTR_PUBLISH_TX_TYPE, request, result, "publish:Failed to put msg->tx_type");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_count,
+                NAN_REQ_ATTR_PUBLISH_COUNT, request, result, "publish:Failed to put msg->publish_count");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_name_len, msg->service_name_len,
+                NAN_REQ_ATTR_PUBLISH_SERVICE_NAME_LEN, request, result, "publish:Failed to put msg->service_name_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_name_len, msg->service_name, msg->service_name_len,
+                NAN_REQ_ATTR_PUBLISH_SERVICE_NAME, request, result, "publish:Failed to put msg->service_name");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_match_indicator,
+                NAN_REQ_ATTR_PUBLISH_MATCH_ALGO, request, result, "publish:Failed to put msg->publish_match_indicator");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+                NAN_REQ_ATTR_PUBLISH_SERVICE_INFO_LEN, request, result, "publish:Failed to put msg->service_specific_info_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+                NAN_REQ_ATTR_PUBLISH_SERVICE_INFO, request, result, "publish:Failed to put msg->service_specific_info");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter_len,
+                NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER_LEN, request, result, "publish:Failed to put msg->rx_match_filter_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter, msg->rx_match_filter_len,
+                NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER, request, result, "publish:Failed to put msg->rx_match_filter");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter_len,
+                NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER_LEN, request, result, "publish:Failed to put msg->tx_match_filter_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter, msg->tx_match_filter_len,
+                NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER, request, result, "publish:Failed to put msg->tx_match_filter");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->rssi_threshold_flag,
+                NAN_REQ_ATTR_PUBLISH_RSSI_THRESHOLD_FLAG, request, result, "publish:Failed to put msg->rssi_threshold_flag");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->connmap,
+                NAN_REQ_ATTR_PUBLISH_CONN_MAP, request, result, "publish:Failed to put msg->connmap");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+                NAN_REQ_ATTR_PUBLISH_RECV_IND_CFG, request, result, "publish:Failed to put msg->recv_indication_cfg");
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to publish; result = %d", result);
+        } else {
+            ALOGD("NAN publish...success");
+        }
+        return result;
+    }
+
+    int publishCancel(NanPublishCancelRequest *msg) {
+        ALOGD("NAN publishCancel...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISHCANCEL);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "publishCancel:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("publishCancel: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->publish_id,
+                NAN_REQ_ATTR_PUBLISH_ID, request, result, "publishCancel:Failed to put msg->publish_id");
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to publishCancel; result = %d", result);
+        } else {
+            ALOGD("NAN publishCancel...success");
+        }
+        return result;
+
+    }
+
+    int subscribe(NanSubscribeRequest *msg) {
+        ALOGD("NAN subscribe...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBE);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "subscribe:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("subscribe: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->subscribe_id, msg->subscribe_id,
+                NAN_REQ_ATTR_SUBSCRIBE_ID, request, result, "subscribe:Failed to put msg->publish_id");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->ttl,
+                NAN_REQ_ATTR_SUBSCRIBE_TTL, request, result, "subscribe:Failed to put msg->ttl");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->period,
+                NAN_REQ_ATTR_SUBSCRIBE_PERIOD, request, result, "subscribe:Failed to put msg->period");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_type,
+                NAN_REQ_ATTR_SUBSCRIBE_TYPE, request, result, "subscribe:Failed to put msg->subscribe_type");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->serviceResponseFilter,
+                NAN_REQ_ATTR_SUBSCRIBE_RESP_FILTER_TYPE, request, result, "subscribe:Failed to put msg->serviceResponseFilter");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->serviceResponseInclude,
+                NAN_REQ_ATTR_SUBSCRIBE_RESP_INCLUDE, request, result, "subscribe:Failed to put msg->serviceResponseInclude");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->useServiceResponseFilter,
+                NAN_REQ_ATTR_SUBSCRIBE_USE_RESP_FILTER, request, result, "subscribe:Failed to put msg->useServiceResponseFilter");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->ssiRequiredForMatchIndication,
+                NAN_REQ_ATTR_SUBSCRIBE_SSI_REQUIRED, request, result, "subscribe:Failed to put msg->ssiRequiredForMatchIndication");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_match_indicator,
+                NAN_REQ_ATTR_SUBSCRIBE_MATCH_INDICATOR, request, result, "subscribe:Failed to put msg->subscribe_match_indicator");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_count,
+                NAN_REQ_ATTR_SUBSCRIBE_COUNT, request, result, "subscribe:Failed to put msg->subscribe_count");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_name_len, msg->service_name_len,
+                NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME_LEN, request, result, "subscribe:Failed to put msg->service_name_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_name_len, msg->service_name, msg->service_name_len,
+                NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME, request, result, "subscribe:Failed to put msg->service_name");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+                NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO_LEN, request, result, "subscribe:Failed to put msg->service_specific_info_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+                NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO, request, result, "subscribe:Failed to put msg->service_specific_info");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter_len,
+                NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER_LEN, request, result, "subscribe:Failed to put msg->rx_match_filter_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter, msg->rx_match_filter_len,
+                NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER, request, result, "subscribe:Failed to put msg->rx_match_filter");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter_len,
+                NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER_LEN, request, result, "subscribe:Failed to put msg->tx_match_filter_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter, msg->tx_match_filter_len,
+                NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER, request, result, "subscribe:Failed to put msg->tx_match_filter");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->rssi_threshold_flag,
+                NAN_REQ_ATTR_SUBSCRIBE_RSSI_THRESHOLD_FLAG, request, result, "subscribe:Failed to put msg->rssi_threshold_flag");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->connmap,
+                NAN_REQ_ATTR_SUBSCRIBE_CONN_MAP, request, result, "subscribe:Failed to put msg->connmap");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->num_intf_addr_present, msg->num_intf_addr_present,
+                NAN_REQ_ATTR_SUBSCRIBE_NUM_INTF_ADDR_PRESENT, request, result, "subscribe:Failed to put msg->num_intf_addr_present");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->num_intf_addr_present, msg->intf_addr, NAN_MAC_ADDR_LEN * msg->num_intf_addr_present,
+                NAN_REQ_ATTR_SUBSCRIBE_INTF_ADDR, request, result, "subscribe:Failed to put msg->intf_addr");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+                NAN_REQ_ATTR_SUBSCRIBE_RECV_IND_CFG, request, result, "subscribe:Failed to put msg->recv_indication_cfg");
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to subscribe; result = %d", result);
+        } else {
+            ALOGD("NAN subscribe...success");
+        }
+        return result;
+
+    }
+
+    int subscribeCancel(NanSubscribeCancelRequest *msg) {
+        ALOGD("NAN subscribeCancel...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBECANCEL);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "subscribeCancel:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("subscribeCancel: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->subscribe_id,
+                NAN_REQ_ATTR_SUBSCRIBE_ID, request, result, "subscribeCancel:Failed to put msg->subscribe_id");
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to subscribeCancel; result = %d", result);
+        } else {
+            ALOGD("NAN subscribeCancel...success");
+        }
+        return result;
+    }
+
+    int followup(NanTransmitFollowupRequest *msg) {
+        ALOGD("NAN followup...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_TXFOLLOWUP);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "followup:Failed to create WifiRequest");
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        if (!data) {
+            ALOGE("followup: request.attr_start fail");
+            return WIFI_ERROR_OUT_OF_MEMORY;
+        }
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->publish_subscribe_id,
+                NAN_REQ_ATTR_FOLLOWUP_ID, request, result, "followup:Failed to put msg->publish_subscribe_id");
+
+        CHECK_CONFIG_PUT_32_RETURN_FAIL(1, msg->requestor_instance_id,
+                NAN_REQ_ATTR_FOLLOWUP_REQUESTOR_ID, request, result, "followup:Failed to put msg->requestor_instance_id");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(1, msg->addr, NAN_MAC_ADDR_LEN,
+            NAN_REQ_ATTR_FOLLOWUP_ADDR, request, result, "followup:Failed to put msg->addr");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->priority,
+            NAN_REQ_ATTR_FOLLOWUP_PRIORITY, request, result, "followup:Failed to put msg->priority");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->dw_or_faw,
+            NAN_REQ_ATTR_FOLLOWUP_TX_WINDOW, request, result, "followup:Failed to put msg->dw_or_faw");
+
+        CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+            NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME_LEN, request, result, "followup:Failed to put msg->service_specific_info_len");
+
+        CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+            NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME, request, result, "followup:Failed to put msg->service_specific_info");
+
+        CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+            NAN_REQ_ATTR_FOLLOWUP_RECV_IND_CFG, request, result, "followup:Failed to put msg->recv_indication_cfg");
+
+        request.attr_end(data);
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to followup; result = %d", result);
+        } else {
+            ALOGD("NAN followup...success");
+        }
+        return result;
+
+    }
+
+    int getCapabilities(void) {
+        ALOGD("NAN getCapabilities...");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_CAPABILITIES);
+        CHECK_WIFI_STATUS_RETURN_FAIL(result, "getCapabilities:Failed to create WifiRequest");
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to getCapabilities; result = %d", result);
+        } else {
+            ALOGD("NAN getCapabilities...success");
+        }
+        return result;
+    }
+
+    int handleEvent(WifiEvent &event) {
+        int ret;
+        ALOGD("NAN handleEvent...");
+
+        if (event.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring event with cmd = %d", event.get_cmd());
+            return NL_SKIP;
+        }
+
+        int id = event.get_vendor_id();
+        int subcmd = event.get_vendor_subcmd();
+
+        ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+
+        switch(subcmd) {
+        case SLSI_NAN_EVENT_MATCH:
+            ret = processMatchEvent(event);
+            break;
+        case SLSI_NAN_EVENT_MATCH_EXPIRED:
+            ret = processMatchExpiredEvent(event);
+            break;
+        case SLSI_NAN_EVENT_PUBLISH_TERMINATED:
+            ret = processPublishTerminatedEvent(event);
+            break;
+        case SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED:
+            ret = processSubscribeTerminatedEvent(event);
+            break;
+        case SLSI_NAN_EVENT_FOLLOWUP:
+            ret = processFollowupEvent(event);
+            break;
+        case SLSI_NAN_EVENT_DISABLED:
+            ret = processNanDisabledEvent(event);
+            break;
+        case SLSI_NAN_EVENT_DISCOVERY_ENGINE:
+            ret = processNanDiscoveryEvent(event);
+            break;
+
+        }
+
+        return NL_OK;
+    }
+
+    int handleResponse(WifiEvent &reply) {
+        ALOGD("NAN handleResponse...");
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        NanResponseMsg response;
+        memset(&response, 0, sizeof(response));
+
+        if (processResponse(reply, &response) == NL_SKIP)
+            return NL_SKIP;
+
+        if (callbackEventHandler.NotifyResponse)
+            callbackEventHandler.NotifyResponse(id(), &response);
+        return NL_OK;
+    }
+};
+
+NanCallbackHandler NanCommand::callbackEventHandler;
+
+NanCommand *nan_get_object(transaction_id id,
+                              wifi_interface_handle iface) {
+    wifi_handle handle = getWifiHandle(iface);
+    NanCommand *nanRequest = (NanCommand *)wifi_get_cmd(handle, id);
+    if (!nanRequest) {
+        nanRequest = new NanCommand(iface, id);
+        if (!nanRequest){
+            ALOGE("Could not alloc NanCommand");
+            return NULL;
+        }
+    }
+    return nanRequest;
+}
+
+wifi_error nan_enable_request(transaction_id id,
+                              wifi_interface_handle iface,
+                              NanEnableRequest *msg) {
+    wifi_handle handle = getWifiHandle(iface);
+    wifi_error ret;
+
+    NanCommand *nanRequest = new NanCommand(iface, id);
+    if (!nanRequest) {
+        ALOGE("nan_enable_request:: Unable to create NanCommand");
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+
+    wifi_register_cmd(handle, id, nanRequest);
+    ret = (wifi_error)nanRequest->enable(msg);
+    if (ret != WIFI_SUCCESS) {
+        wifi_unregister_cmd(handle, id);
+        delete nanRequest;
+    }
+    return ret;
+}
+
+/*  Disable NAN functionality. */
+wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    wifi_error ret;
+
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    ret = (wifi_error)nanRequest->disable();
+    delete nanRequest;
+    return ret;
+}
+
+/*  Publish request to advertize a service. */
+wifi_error nan_publish_request(transaction_id id,
+                               wifi_interface_handle iface,
+                               NanPublishRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->publish(msg);
+}
+
+/*  Cancel previous publish requests. */
+wifi_error nan_publish_cancel_request(transaction_id id,
+                                      wifi_interface_handle iface,
+                                      NanPublishCancelRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->publishCancel(msg);
+}
+
+/*  Subscribe request to search for a service. */
+wifi_error nan_subscribe_request(transaction_id id,
+                                 wifi_interface_handle iface,
+                                 NanSubscribeRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->subscribe(msg);
+}
+
+/*  Cancel previous subscribe requests. */
+wifi_error nan_subscribe_cancel_request(transaction_id id,
+                                        wifi_interface_handle iface,
+                                        NanSubscribeCancelRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->subscribeCancel(msg);
+}
+
+/*  NAN transmit follow up request. */
+wifi_error nan_transmit_followup_request(transaction_id id,
+                                         wifi_interface_handle iface,
+                                         NanTransmitFollowupRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->followup(msg);
+}
+
+/* NAN configuration request. */
+wifi_error nan_config_request(transaction_id id,
+                              wifi_interface_handle iface,
+                              NanConfigRequest *msg) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->config(msg);
+}
+
+/* Register NAN callbacks. */
+wifi_error nan_register_handler(wifi_interface_handle iface,
+                                NanCallbackHandler handlers) {
+    return (wifi_error)NanCommand::setCallbackHandler(handlers);
+}
+
+/*  Get NAN HAL version. */
+wifi_error nan_get_version(wifi_handle handle,
+                           NanVersion *version) {
+    return (wifi_error)NanCommand::getVersion(version);
+}
+
+/*  Get NAN capabilities. */
+wifi_error nan_get_capabilities(transaction_id id,
+                                wifi_interface_handle iface) {
+    NanCommand *nanRequest = nan_get_object(id, iface);
+    if (!nanRequest) {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+    return (wifi_error)nanRequest->getCapabilities();
+}
+
diff --git a/wifi_offload.cpp b/wifi_offload.cpp
new file mode 100644
index 0000000..208afb8
--- /dev/null
+++ b/wifi_offload.cpp
@@ -0,0 +1,227 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/types.h>
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG  "WifiHAL[offload]"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+    MKEEP_ALIVE_ATTRIBUTE_ID,
+    MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
+    MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
+    MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
+    MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
+    MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
+} WIFI_MKEEP_ALIVE_ATTRIBUTE;
+
+typedef enum {
+    START_MKEEP_ALIVE,
+    STOP_MKEEP_ALIVE,
+} GetCmdType;
+
+///////////////////////////////////////////////////////////////////////////////
+class MKeepAliveCommand : public WifiCommand
+{
+    u8 mIndex;
+    u8 *mIpPkt;
+    u16 mIpPktLen;
+    u8 *mSrcMacAddr;
+    u8 *mDstMacAddr;
+    u32 mPeriodMsec;
+    GetCmdType mType;
+
+public:
+
+    // constructor for start sending
+    MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len,
+            u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
+        : WifiCommand(iface, 0), mIndex(index), mIpPkt(ip_packet),
+        mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
+        mPeriodMsec(period_msec), mType(cmdType)
+    { }
+
+    // constructor for stop sending
+    MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
+        : WifiCommand(iface, 0), mIndex(index), mType(cmdType)
+    {
+        mIpPkt = NULL;
+        mIpPktLen = 0;
+        mSrcMacAddr = NULL;
+        mDstMacAddr = NULL;
+        mPeriodMsec = 0;
+    }
+
+    int createRequest(WifiRequest &request) {
+        int result;
+
+        switch (mType) {
+            case START_MKEEP_ALIVE:
+            {
+                result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_START_KEEP_ALIVE_OFFLOAD);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to create start keep alive request; result = %d", result);
+                    return result;
+                }
+
+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+                result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+                if (result < 0) {
+                    ALOGE("Failed to put id request; result = %d", result);
+                    return result;
+                }
+
+                result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
+                if (result < 0) {
+                    ALOGE("Failed to put ip pkt len request; result = %d", result);
+                    return result;
+                }
+
+                result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
+                if (result < 0) {
+                    ALOGE("Failed to put ip pkt request; result = %d", result);
+                    return result;
+                }
+
+                result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
+                if (result < 0) {
+                    ALOGE("Failed to put src mac address request; result = %d", result);
+                    return result;
+                }
+
+                result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
+                if (result < 0) {
+                    ALOGE("Failed to put dst mac address request; result = %d", result);
+                    return result;
+                }
+
+                result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
+                if (result < 0) {
+                    ALOGE("Failed to put period request; result = %d", result);
+                    return result;
+                }
+
+                request.attr_end(data);
+                break;
+            }
+
+            case STOP_MKEEP_ALIVE:
+            {
+                result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_STOP_KEEP_ALIVE_OFFLOAD);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to create stop keep alive request; result = %d", result);
+                    return result;
+                }
+
+                nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+                result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+                if (result < 0) {
+                    ALOGE("Failed to put id request; result = %d", result);
+                    return result;
+                }
+
+                request.attr_end(data);
+                break;
+            }
+
+            default:
+                ALOGE("Unknown wifi keep alive command");
+                result = WIFI_ERROR_UNKNOWN;
+        }
+        return result;
+    }
+
+    int start() {
+        ALOGD("Start mkeep_alive command");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to create keep alive request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to register keep alive response; result = %d", result);
+        }
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+
+        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+            return NL_SKIP;
+        }
+
+        switch (mType) {
+            case START_MKEEP_ALIVE:
+            case STOP_MKEEP_ALIVE:
+                break;
+
+            default:
+                ALOGW("Unknown mkeep_alive command");
+        }
+        return NL_OK;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        /* NO events! */
+        return NL_SKIP;
+    }
+};
+
+
+/* API to send specified mkeep_alive packet periodically. */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
+        u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
+{
+    if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
+            && (dst_mac_addr != NULL) && (period_msec > 0)
+            && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
+        MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
+                src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
+        wifi_error result = (wifi_error)cmd->start();
+        delete cmd;
+        return result;
+    } else {
+        ALOGE("Invalid mkeep_alive parameters");
+        return  WIFI_ERROR_INVALID_ARGS;
+    }
+}
+
+/* API to stop sending mkeep_alive packet. */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
+{
+    if (index > 0 && index <= N_AVAIL_ID) {
+        MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
+        wifi_error result = (wifi_error)cmd->start();
+        delete cmd;
+        return result;
+    } else {
+        ALOGE("Invalid mkeep_alive parameters");
+        return  WIFI_ERROR_INVALID_ARGS;
+    }
+}