add libwifi-hal-rtk support
authorAlex Zhao <zzc@rock-chips.com>
Mon, 22 Jan 2018 06:40:56 +0000 (14:40 +0800)
committerAlex Zhao <zzc@rock-chips.com>
Mon, 22 Jan 2018 06:40:56 +0000 (14:40 +0800)
Change-Id: I96eed731578f876ca81e7017e379bac7f28acd8e
Signed-off-by: Alex Zhao <zzc@rock-chips.com>
12 files changed:
wlan/wifi_hal/Android.mk [new file with mode: 0644]
wlan/wifi_hal/common.cpp [new file with mode: 0644]
wlan/wifi_hal/common.h [new file with mode: 0644]
wlan/wifi_hal/cpp_bindings.cpp [new file with mode: 0644]
wlan/wifi_hal/cpp_bindings.h [new file with mode: 0644]
wlan/wifi_hal/gscan.cpp [new file with mode: 0644]
wlan/wifi_hal/link_layer_stats.cpp [new file with mode: 0644]
wlan/wifi_hal/rtt.cpp [new file with mode: 0644]
wlan/wifi_hal/sync.h [new file with mode: 0644]
wlan/wifi_hal/wifi_hal.cpp [new file with mode: 0644]
wlan/wifi_hal/wifi_logger.cpp [new file with mode: 0644]
wlan/wifi_hal/wifi_offload.cpp [new file with mode: 0644]

diff --git a/wlan/wifi_hal/Android.mk b/wlan/wifi_hal/Android.mk
new file mode 100644 (file)
index 0000000..fc8267e
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := \
+    -Wall \
+    -Werror \
+    -Wno-format \
+    -Wno-reorder \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -Wno-unused-private-field \
+    -Wno-unused-variable \
+
+LOCAL_C_INCLUDES += \
+       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_logger.cpp \
+       wifi_offload.cpp
+
+LOCAL_MODULE := libwifi-hal-rtk
+LOCAL_PROPRIETARY_MODULE := true
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/wlan/wifi_hal/common.cpp b/wlan/wifi_hal/common.cpp
new file mode 100644 (file)
index 0000000..45fbfb0
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+        ALOGV("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;
+
+    /* 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  = 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;
+        ALOGV("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) {
+            ALOGV("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) {
+            ALOGV("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;
+
+    ALOGV("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;
+        ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
+        info->num_cmd++;
+        result = WIFI_SUCCESS;
+    } else {
+        ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
+                id, cmd, info->num_cmd, info->alloc_cmd);
+    }
+
+    return result;
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+    hal_info *info = (hal_info *)handle;
+
+    ALOGV("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 - 1) * sizeof(cmd_info));
+            info->num_cmd--;
+            ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
+            break;
+        }
+    }
+
+    if (!cmd) {
+        ALOGI("Failed to remove command %d: %p", id, cmd);
+    }
+
+    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) {
+            int id = info->cmd[i].id;
+            memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
+            info->num_cmd--;
+            ALOGV("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);
+    ALOGV("Cancel WifiCommand = %p", cmd);
+    if (cmd) {
+        cmd->cancel();
+        cmd->releaseRef();
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
diff --git a/wlan/wifi_hal/common.h b/wlan/wifi_hal/common.h
new file mode 100644 (file)
index 0000000..a8d60b7
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_COMMON_H__
+#define __WIFI_HAL_COMMON_H__
+
+#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
+#define DOT11_MAX_SSID_LEN        32
+
+#define MAX_PROBE_RESP_IE_LEN      2048
+/*
+ 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 */
+
+
+/*
+ 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 0x1600 and 0x16FF */
+    ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
+    ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END   = 0x16FF,
+
+    /* define all NAN related commands between 0x1700 and 0x17FF */
+    ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700,
+    ANDROID_NL80211_SUBCMD_NAN_RANGE_END   = 0x17FF,
+
+    /* define all Android Packet Filter related commands between 0x1800 and 0x18FF */
+    ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800,
+    ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END   = 0x18FF,
+
+    /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+typedef enum {
+
+    GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+
+    GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
+
+    GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
+    GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
+    GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
+    GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
+
+    GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
+
+    GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
+    GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,              /* 0x1008 */
+    GSCAN_SUBCMD_GET_CHANNEL_LIST,                       /* 0x1009 */
+
+    WIFI_SUBCMD_GET_FEATURE_SET,                         /* 0x100A */
+    WIFI_SUBCMD_GET_FEATURE_SET_MATRIX,                  /* 0x100B */
+    WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI,                  /* 0x100C */
+    WIFI_SUBCMD_NODFS_SET,                               /* 0x100D */
+    WIFI_SUBCMD_SET_COUNTRY_CODE,                             /* 0x100E */
+    /* Add more sub commands here */
+    GSCAN_SUBCMD_SET_EPNO_SSID,                          /* 0x100F */
+
+    WIFI_SUBCMD_SET_SSID_WHITE_LIST,                    /* 0x1010 */
+    WIFI_SUBCMD_SET_ROAM_PARAMS,                        /* 0x1011 */
+    WIFI_SUBCMD_ENABLE_LAZY_ROAM,                       /* 0x1012 */
+    WIFI_SUBCMD_SET_BSSID_PREF,                         /* 0x1013 */
+    WIFI_SUBCMD_SET_BSSID_BLACKLIST,                     /* 0x1014 */
+
+    GSCAN_SUBCMD_ANQPO_CONFIG,                          /* 0x1015 */
+    WIFI_SUBCMD_SET_RSSI_MONITOR,                       /* 0x1016 */
+    WIFI_SUBCMD_CONFIG_ND_OFFLOAD,                      /* 0x1017 */
+    /* Add more sub commands here */
+
+    GSCAN_SUBCMD_MAX,
+
+    APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
+    APF_SUBCMD_SET_FILTER,
+} WIFI_SUB_COMMAND;
+
+typedef enum {
+    RTK_RESERVED1,
+    RTK_RESERVED2,
+    GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
+    GSCAN_EVENT_HOTLIST_RESULTS_FOUND,
+    GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
+    GSCAN_EVENT_FULL_SCAN_RESULTS,
+    RTT_EVENT_COMPLETE,
+    GSCAN_EVENT_COMPLETE_SCAN,
+    GSCAN_EVENT_HOTLIST_RESULTS_LOST,
+    GSCAN_EVENT_EPNO_EVENT,
+    GOOGLE_DEBUG_RING_EVENT,
+    GOOGLE_DEBUG_MEM_DUMP_EVENT,
+    GSCAN_EVENT_ANQPO_HOTSPOT_MATCH,
+    GOOGLE_RSSI_MONITOR_EVENT
+} 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[IFNAMSIZ+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 exit since cleanup has started
+
+    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;
+
+#define PNO_SSID_FOUND  0x1
+#define PNO_SSID_LOST    0x2
+
+typedef struct wifi_pno_result {
+    unsigned char ssid[DOT11_MAX_SSID_LEN];
+    unsigned char ssid_len;
+    signed char rssi;
+    u16 channel;
+    u16 flags;
+    mac_addr  bssid;
+} wifi_pno_result_t;
+
+typedef struct wifi_gscan_result {
+    u64 ts;                           // Time of discovery
+    u8 ssid[DOT11_MAX_SSID_LEN+1];    // null terminated
+    mac_addr bssid;                   // BSSID
+    u32 channel;                      // channel frequency in MHz
+    s32 rssi;                         // in db
+    u64 rtt;                          // in nanoseconds
+    u64 rtt_sd;                       // standard deviation in rtt
+    u16 beacon_period;                // units are Kusec
+    u16 capability;                   // Capability information
+    u32 pad;
+} wifi_gscan_result_t;
+
+typedef struct wifi_gscan_full_result {
+    wifi_gscan_result_t fixed;
+    u32 scan_ch_bucket;              // scan chbucket bitmask
+    u32 ie_length;                   // byte length of Information Elements
+    u8  ie_data[1];                  // IE data to follow
+} wifi_gscan_full_result_t;
+
+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);
+
+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);
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+
+// 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/wlan/wifi_hal/cpp_bindings.cpp b/wlan/wifi_hal/cpp_bindings.cpp
new file mode 100644 (file)
index 0000000..65d10b6
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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 <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_GET_COALESCE)
+       C2S(NL80211_CMD_SET_COALESCE)
+       C2S(NL80211_CMD_CHANNEL_SWITCH)
+       C2S(NL80211_CMD_VENDOR)
+       C2S(NL80211_CMD_SET_QOS_MAP)
+       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)
+
+       C2S(NL80211_ATTR_COALESCE_RULE)
+
+       C2S(NL80211_ATTR_CH_SWITCH_COUNT)
+       C2S(NL80211_ATTR_CH_SWITCH_BLOCK_TX)
+       C2S(NL80211_ATTR_CSA_IES)
+       C2S(NL80211_ATTR_CSA_C_OFF_BEACON)
+       C2S(NL80211_ATTR_CSA_C_OFF_PRESP)
+
+       C2S(NL80211_ATTR_RXMGMT_FLAGS)
+
+       C2S(NL80211_ATTR_STA_SUPPORTED_CHANNELS)
+
+       C2S(NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES)
+
+       C2S(NL80211_ATTR_HANDLE_DFS)
+
+       C2S(NL80211_ATTR_SUPPORT_5_MHZ)
+       C2S(NL80211_ATTR_SUPPORT_10_MHZ)
+
+       C2S(NL80211_ATTR_OPMODE_NOTIF)
+
+       C2S(NL80211_ATTR_VENDOR_ID)
+       C2S(NL80211_ATTR_VENDOR_SUBCMD)
+       C2S(NL80211_ATTR_VENDOR_DATA)
+       C2S(NL80211_ATTR_VENDOR_EVENTS)
+
+       C2S(NL80211_ATTR_QOS_MAP)
+    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));
+        }
+    }
+
+    ALOGD("-- End of message --");
+}
+
+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);
+
+    // ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
+    return result;
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+
+    destroy();
+
+    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) {
+
+    ALOGD("requesting event %d", 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;
+
+    ALOGD("waiting for response %d", cmd);
+
+    res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());    /* send message */
+    if (res < 0)
+        goto out;
+
+    ALOGD("waiting for event %d", cmd);
+    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) {
+    // ALOGD("response_handler called");
+    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) {
+    // ALOGD("valid_handler called");
+    int *err = (int *)arg;
+    *err = 0;
+    return NL_SKIP;
+}
+
+int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
+    // ALOGD("ack_handler called");
+    int *err = (int *)arg;
+    *err = 0;
+    return NL_STOP;
+}
+
+int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
+    // ALOGD("finish_handler called");
+    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/wlan/wifi_hal/cpp_bindings.h b/wlan/wifi_hal/cpp_bindings.h
new file mode 100644 (file)
index 0000000..3cde258
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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:
+    const char *mType;
+    hal_info *mInfo;
+    WifiRequest mMsg;
+    Condition mCondition;
+    wifi_request_id mId;
+    interface_info *mIfaceInfo;
+    int mRefs;
+public:
+    WifiCommand(const char *type, wifi_handle handle, wifi_request_id id)
+            : mType(type), 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(const char *type, wifi_interface_handle iface, wifi_request_id id)
+            : mType(type), 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;
+    }
+
+    const char *getType() {
+        return mType;
+    }
+
+    virtual void addRef() {
+        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/wlan/wifi_hal/gscan.cpp b/wlan/wifi_hal/gscan.cpp
new file mode 100644 (file)
index 0000000..d33ac93
--- /dev/null
@@ -0,0 +1,1856 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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"
+
+#define LOG_TAG  "WifiHAL"
+//#define LOG_NDEBUG 0         //uncomment to enable verbose logging
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+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_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
+    GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
+    GSCAN_ENABLE_FULL_SCAN_RESULTS,
+    GSCAN_ATTRIBUTE_REPORT_EVENTS,
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
+    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
+    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
+    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
+    GSCAN_ATTRIBUTE_NUM_CHANNELS,
+    GSCAN_ATTRIBUTE_CHANNEL_LIST,
+    GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK,
+    /* 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_HOTLIST_BSSID_COUNT,
+
+    /* 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_SIGNIFICANT_CHANGE_FLUSH,
+
+    /* EPNO */
+    GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70,
+    GSCAN_ATTRIBUTE_EPNO_SSID,
+    GSCAN_ATTRIBUTE_EPNO_SSID_LEN,
+    GSCAN_ATTRIBUTE_EPNO_RSSI,
+    GSCAN_ATTRIBUTE_EPNO_FLAGS,
+    GSCAN_ATTRIBUTE_EPNO_AUTH,
+    GSCAN_ATTRIBUTE_EPNO_SSID_NUM,
+    GSCAN_ATTRIBUTE_EPNO_FLUSH,
+
+    /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_WHITELIST_SSID = 80,
+    GSCAN_ATTRIBUTE_NUM_WL_SSID,
+    GSCAN_ATTRIBUTE_WL_SSID_LEN,
+    GSCAN_ATTRIBUTE_WL_SSID_FLUSH,
+    GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM,
+    GSCAN_ATTRIBUTE_NUM_BSSID,
+    GSCAN_ATTRIBUTE_BSSID_PREF_LIST,
+    GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH,
+    GSCAN_ATTRIBUTE_BSSID_PREF,
+    GSCAN_ATTRIBUTE_RSSI_MODIFIER,
+
+    /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90,
+    GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD,
+    GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR,
+    GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR,
+    GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST,
+    GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS,
+    GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER,
+    GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE,
+
+    /* BSSID blacklist */
+    GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100,
+    GSCAN_ATTRIBUTE_BLACKLIST_BSSID,
+
+    /* ANQPO */
+    GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110,
+    GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE,
+    GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID,
+    GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM,
+    GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID,
+    GSCAN_ATTRIBUTE_ANQPO_HS_PLMN,
+
+    /* Adaptive scan attributes */
+    GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120,
+    GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+
+    /* ePNO cfg */
+    GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR = 130,
+    GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR,
+    GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX,
+    GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS,
+    GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS,
+    GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS,
+    GSCAN_ATTRIBUTE_EPNO_5G_BONUS,
+
+    GSCAN_ATTRIBUTE_MAX
+
+} GSCAN_ATTRIBUTE;
+
+
+// helper methods
+wifi_error wifi_enable_full_scan_results(wifi_request_id id, wifi_interface_handle iface,
+         wifi_scan_result_handler handler);
+wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface);
+int wifi_handle_full_scan_event(wifi_request_id id, WifiEvent& event,
+         wifi_scan_result_handler handler);
+void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from);
+
+
+void convert_to_hal_result(wifi_scan_result *to, wifi_gscan_result_t *from)
+{
+    to->ts = from->ts;
+    to->channel = from->channel;
+    to->rssi = from->rssi;
+    to->rtt = from->rtt;
+    to->rtt_sd = from->rtt_sd;
+    to->beacon_period = from->beacon_period;
+    to->capability = from->capability;
+    memcpy(to->ssid, from->ssid, (DOT11_MAX_SSID_LEN+1));
+    memcpy(&to->bssid, &from->bssid, sizeof(mac_addr));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class GetCapabilitiesCommand : public WifiCommand
+{
+    wifi_gscan_capabilities *mCapabilities;
+public:
+    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
+        : WifiCommand("GetGscanCapabilitiesCommand", iface, 0), mCapabilities(capabitlites)
+    {
+        memset(mCapabilities, 0, sizeof(*mCapabilities));
+    }
+
+    virtual int create() {
+        ALOGV("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CAPABILITIES);
+        if (ret < 0) {
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGV("In GetCapabilities::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();
+
+        ALOGV("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+                    sizeof(*mCapabilities));
+
+        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("GetChannelListCommand", 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() {
+        ALOGV("Creating message to get channel list; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_CHANNEL_LIST);
+        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) {
+
+        ALOGV("In GetChannelList::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();
+        int num_channels_to_copy = 0;
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, 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();
+                ALOGI("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)
+{
+#if 0
+    GetChannelListCommand command(handle, channels, num_channels,
+                                        max_channels, band);
+    return (wifi_error) command.requestResponse();
+#endif
+       *num_channels = 12;
+       return WIFI_SUCCESS;
+}
+/////////////////////////////////////////////////////////////////////////////
+
+/* 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++) {
+
+        int index = it.get_type();
+        ALOGI("retrieved scan result %d", index);
+        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 enable) {
+
+    int result = request.create(GOOGLE_OUI, subcmd);
+    if (result < 0) {
+        return result;
+    }
+
+    nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+    result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
+    if (result < 0) {
+        return result;
+    }
+
+    request.attr_end(data);
+    return WIFI_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+class FullScanResultsCommand : public WifiCommand
+{
+    int *mParams;
+    wifi_scan_result_handler mHandler;
+public:
+    FullScanResultsCommand(wifi_interface_handle iface, int id, int *params,
+                wifi_scan_result_handler handler)
+        : WifiCommand("FullScanResultsCommand", iface, id), mParams(params), mHandler(handler)
+    { }
+
+    int createRequest(WifiRequest& request, int subcmd, int enable) {
+        int result = request.create(GOOGLE_OUI, subcmd);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ENABLE_FULL_SCAN_RESULTS, enable);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+
+    }
+
+    int start() {
+        ALOGV("Enabling Full scan results");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 1);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to enable full scan results; result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+            return result;
+        }
+
+        return result;
+    }
+
+    virtual int cancel() {
+        ALOGV("Disabling Full scan results");
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, 0);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create request; result = %d", result);
+        } else {
+            result = requestResponse(request);
+            if (result != WIFI_SUCCESS) {
+                ALOGE("failed to disable full scan results;result = %d", result);
+            }
+        }
+
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+         ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGV("Full scan results:  Got an event");
+        return wifi_handle_full_scan_event(id(), event, mHandler);
+    }
+
+};
+/////////////////////////////////////////////////////////////////////////////
+
+class ScanCommand : public WifiCommand
+{
+    wifi_scan_cmd_params *mParams;
+    wifi_scan_result_handler mHandler;
+public:
+    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
+                wifi_scan_result_handler handler)
+        : WifiCommand("ScanCommand", iface, id), mParams(params), mHandler(handler)
+    { }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
+        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_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;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
+                    mParams->buckets[i].step_count);
+            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_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;
+            }
+
+            if (mParams->buckets[i].num_channels) {
+                nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
+                ALOGV(" channels: ");
+                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
+                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
+                    ALOGV(" %u", 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 createScanConfigRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        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;
+        }
+
+        int num_scans = mParams->report_threshold_num_scans;
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, num_scans);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int createStartRequest(WifiRequest& request) {
+        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+    }
+
+    int createStopRequest(WifiRequest& request) {
+        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
+    }
+
+    int start() {
+        ALOGV("GSCAN 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 setup; result = %d", result);
+            return result;
+        }
+
+        request.destroy();
+
+        result = createScanConfigRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create scan config request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to configure scan; result = %d", result);
+            return result;
+        }
+
+        ALOGV(" ....starting scan");
+
+        result = createStartRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create start request; result = %d", result);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+        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);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+            return result;
+        }
+        return result;
+    }
+
+    virtual int cancel() {
+        ALOGV("Stopping scan");
+
+        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) {
+        ALOGV("Got a scan results event");
+        //event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+        int event_id = event.get_vendor_subcmd();
+
+        if ((event_id == GSCAN_EVENT_COMPLETE_SCAN) ||
+            (event_id == GSCAN_EVENT_SCAN_RESULTS_AVAILABLE)) {
+            if (vendor_data == NULL || len != 4) {
+                ALOGI("Bad event data!");
+                return NL_SKIP;
+            }
+            wifi_scan_event evt_type;
+            evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
+            ALOGV("Received event type %d", evt_type);
+            if(*mHandler.on_scan_event)
+                (*mHandler.on_scan_event)(id(), evt_type);
+        } else if (event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
+            wifi_handle_full_scan_event(id(), event, mHandler);
+        }
+        return NL_SKIP;
+    }
+};
+
+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);
+
+    ALOGV("Starting GScan, halHandle = %p", handle);
+
+    ScanCommand *cmd = new ScanCommand(iface, id, &params, 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_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    ALOGV("Stopping GScan, wifi_request_id = %d, halHandle = %p", id, handle);
+
+    if (id == -1) {
+        wifi_scan_result_handler handler;
+        wifi_scan_cmd_params dummy_params;
+        wifi_handle handle = getWifiHandle(iface);
+        memset(&handler, 0, sizeof(handler));
+
+        ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, 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);
+}
+
+wifi_error wifi_enable_full_scan_results(
+        wifi_request_id id,
+        wifi_interface_handle iface,
+        wifi_scan_result_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+    int params_dummy;
+
+    ALOGV("Enabling full scan results, halHandle = %p", handle);
+
+    FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, id, &params_dummy, 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;
+}
+
+int wifi_handle_full_scan_event(
+        wifi_request_id id,
+        WifiEvent& event,
+        wifi_scan_result_handler handler)
+{
+    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_gscan_full_result_t)) {
+        ALOGI("Full scan results: No scan results found");
+        return NL_SKIP;
+    }
+
+    wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data();
+    /* To protect against corrupted data, put a ceiling */
+    int ie_len = min(MAX_PROBE_RESP_IE_LEN, drv_res->ie_length);
+    wifi_scan_result *full_scan_result;
+    wifi_gscan_result_t *fixed = &drv_res->fixed;
+
+    if ((ie_len + offsetof(wifi_gscan_full_result_t, ie_data)) > len) {
+        ALOGE("BAD event data, len %d ie_len %d fixed length %d!\n", len,
+            ie_len, offsetof(wifi_gscan_full_result_t, ie_data));
+        return NL_SKIP;
+    }
+    full_scan_result = (wifi_scan_result *) malloc((ie_len + offsetof(wifi_scan_result, ie_data)));
+    if (!full_scan_result) {
+        ALOGE("Full scan results: Can't malloc!\n");
+        return NL_SKIP;
+    }
+    convert_to_hal_result(full_scan_result, fixed);
+    full_scan_result->ie_length = ie_len;
+    memcpy(full_scan_result->ie_data, drv_res->ie_data, ie_len);
+    if(handler.on_full_scan_result)
+        handler.on_full_scan_result(id, full_scan_result, drv_res->scan_ch_bucket);
+
+    ALOGV("Full scan result: %-32s %02x:%02x:%02x:%02x:%02x:%02x %d %d %lld %lld %lld %x %d\n",
+        fixed->ssid, fixed->bssid[0], fixed->bssid[1], fixed->bssid[2], fixed->bssid[3],
+        fixed->bssid[4], fixed->bssid[5], fixed->rssi, fixed->channel, fixed->ts,
+        fixed->rtt, fixed->rtt_sd, drv_res->scan_ch_bucket, drv_res->ie_length);
+    free(full_scan_result);
+    return NL_SKIP;
+}
+
+
+wifi_error wifi_disable_full_scan_results(wifi_request_id id, wifi_interface_handle iface)
+{
+    ALOGV("Disabling full scan results");
+    wifi_handle handle = getWifiHandle(iface);
+
+    if(id == -1) {
+        wifi_scan_result_handler handler;
+        wifi_handle handle = getWifiHandle(iface);
+        int params_dummy;
+
+        memset(&handler, 0, sizeof(handler));
+        FullScanResultsCommand *cmd = new FullScanResultsCommand(iface, 0, &params_dummy, 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 GetScanResultsCommand : public WifiCommand {
+    wifi_cached_scan_results *mScans;
+    int mMax;
+    int *mNum;
+    int mRetrieved;
+    byte mFlush;
+    int mCompleted;
+public:
+    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
+            wifi_cached_scan_results *results, int max, int *num)
+        : WifiCommand("GetScanResultsCommand", iface, -1), mScans(results), mMax(max), mNum(num),
+                mRetrieved(0), mFlush(flush), mCompleted(0)
+    { }
+
+    int createRequest(WifiRequest& request, int num, byte flush) {
+        int result = request.create(GOOGLE_OUI, GSCAN_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;
+        }
+
+        result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int execute() {
+        WifiRequest request(familyId(), ifaceId());
+        ALOGV("retrieving %d scan results", mMax);
+
+        for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
+            int num_to_retrieve = mMax - mRetrieved;
+            // ALOGI("retrieving %d scan results in one shot", num_to_retrieve);
+            int result = createRequest(request, num_to_retrieve, 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();
+        }
+
+        ALOGV("GetScanResults read %d results", mRetrieved);
+        *mNum = mRetrieved;
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        ALOGV("In GetScanResultsCommand::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();
+
+        ALOGV("Id = %0x, subcmd = %d", id, subcmd);
+
+        /*
+        if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
+            ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
+            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();
+                ALOGV("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, scan_ch_bucket_mask = 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();
+                        ALOGV("retrieved scan_id : 0x%0x", scan_id);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
+                        flags = it2.get_u8();
+                        ALOGV("retrieved scan_flags : 0x%0x", flags);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
+                        num = it2.get_u32();
+                        ALOGV("retrieved num_results: %d", num);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK) {
+                        scan_ch_bucket_mask = it2.get_u32();
+                        ALOGD("retrieved scan_ch_bucket_mask: %x", scan_ch_bucket_mask);
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS && num) {
+                        if (mRetrieved >= mMax) {
+                            ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
+                            break;
+                        }
+                        num = min(num, (int)(it2.get_len()/sizeof(wifi_gscan_result)));
+                        num = min(num, (int)MAX_AP_CACHE_PER_SCAN);
+                        ALOGV("Copying %d scan results", num);
+                        wifi_gscan_result_t *results = (wifi_gscan_result_t *)it2.get_data();
+                        wifi_scan_result *mScanResults = mScans[mRetrieved].results;
+
+                        for (int i = 0; i < num; i++) {
+                            wifi_gscan_result_t *result = &results[i];
+                            convert_to_hal_result(&mScanResults[i], result);
+                            mScanResults[i].ie_length = 0;
+                            ALOGV("%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;
+                        mScans[mRetrieved].buckets_scanned = scan_ch_bucket_mask;
+                        ALOGV("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
+                        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());
+            }
+        }
+        ALOGV("GetScanResults read %d results", mRetrieved);
+        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) {
+    ALOGV("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
+
+    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error err = (wifi_error)cmd->execute();
+    cmd->releaseRef();
+    return err;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+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("BssidHotlistCommand", handle, id), mParams(params), mHandler(handler)
+    { }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT, mParams.num_bssid);
+        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, GSCAN_SUBCMD_SET_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+        request.attr_end(attr);
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("Executing hotlist setup request, num = %d", mParams.num_bssid);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("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;
+        }
+
+        ALOGI("Successfully set %d APs in the hotlist ", mParams.num_bssid);
+        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+
+        result = requestResponse(request);
+        if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+            return result;
+        }
+
+        ALOGI("successfully restarted the scan");
+        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;
+        }
+
+        ALOGI("Successfully reset APs in current hotlist");
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Hotlist AP 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) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
+
+        int num = len / sizeof(wifi_gscan_result_t);
+        wifi_gscan_result_t *inp = (wifi_gscan_result_t *)event.get_vendor_data();
+        num = min(MAX_RESULTS, num);
+        for (int i = 0; i < num; i++, inp++) {
+            convert_to_hal_result(&(mResults[i]), inp);
+        }
+
+        if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
+            ALOGI("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) {
+            ALOGI("LOST %d hotlist APs", num);
+            if (*mHandler.on_hotlist_ap_lost)
+                (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
+        }
+        return NL_SKIP;
+    }
+};
+
+class ePNOCommand : public WifiCommand
+{
+private:
+    wifi_epno_params epno_params;
+    wifi_epno_handler mHandler;
+    wifi_scan_result mResults[MAX_EPNO_NETWORKS];
+public:
+    ePNOCommand(wifi_interface_handle handle, int id,
+            const wifi_epno_params *params, wifi_epno_handler handler)
+        : WifiCommand("ePNOCommand", handle, id), mHandler(handler)
+    {
+        if (params != NULL) {
+            memcpy(&epno_params, params, sizeof(wifi_epno_params));
+        } else {
+            memset(&epno_params, 0, sizeof(wifi_epno_params));
+        }
+    }
+    int createSetupRequest(WifiRequest& request) {
+        if (epno_params.num_networks > MAX_EPNO_NETWORKS) {
+            ALOGE("wrong epno num_networks:%d", epno_params.num_networks);
+            return WIFI_ERROR_INVALID_ARGS;
+        }
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_EPNO_SSID);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR,
+                            (u8)epno_params.min5GHz_rssi);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR,
+                            (u8)epno_params.min24GHz_rssi);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX,
+                            epno_params.initial_score_max);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS,
+                            epno_params.current_connection_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS,
+                            epno_params.same_network_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS,
+                            epno_params.secure_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_EPNO_5G_BONUS,
+                            epno_params.band5GHz_bonus);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_SSID_NUM,
+                        epno_params.num_networks);
+        if (result < 0) {
+            return result;
+        }
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_EPNO_SSID_LIST);
+        wifi_epno_network *ssid_list = epno_params.networks;
+        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(GSCAN_ATTRIBUTE_EPNO_SSID, ssid_list[i].ssid, DOT11_MAX_SSID_LEN);
+            ALOGI("PNO network: SSID %s flags %x auth %x", ssid_list[i].ssid,
+                ssid_list[i].flags,
+                ssid_list[i].auth_bit_field);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_SSID_LEN, strlen(ssid_list[i].ssid));
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_FLAGS, ssid_list[i].flags);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_EPNO_AUTH, ssid_list[i].auth_bit_field);
+            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, GSCAN_SUBCMD_SET_EPNO_SSID);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_EPNO_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("Executing ePNO setup request, num = %d", epno_params.num_networks);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Failed to execute ePNO setup request, result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+            return result;
+        }
+
+        ALOGI("Successfully set %d SSIDs for ePNO", epno_params.num_networks);
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+        ALOGI("successfully restarted the scan");
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_EPNO_EVENT);
+        /* 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;
+        }
+
+        ALOGI("Successfully reset APs in current hotlist");
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("ePNO 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) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_EPNO_NETWORKS);
+
+        unsigned int num = len / sizeof(wifi_pno_result_t);
+        unsigned int i;
+        num = min(MAX_EPNO_NETWORKS, num);
+        wifi_pno_result_t *res = (wifi_pno_result_t *) event.get_vendor_data();
+        for (i = 0; i < num; i++) {
+            if (res[i].flags == PNO_SSID_FOUND) {
+                memcpy(mResults[i].ssid, res[i].ssid, res[i].ssid_len);
+                memcpy(mResults[i].bssid, res[i].bssid, sizeof(mac_addr));
+
+                mResults[i].ssid[res[i].ssid_len] = '\0';
+                mResults[i].channel = res[i].channel;
+                mResults[i].rssi = res[i].rssi;
+            }
+        }
+        if (*mHandler.on_network_found)
+            (*mHandler.on_network_found)(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);
+    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_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
+{
+    return wifi_cancel_cmd(id, iface);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+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("SignificantWifiChangeCommand", handle, id), mParams(params),
+            mHandler(handler)
+    { }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+        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;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_NUM_BSSID, mParams.num_bssid);
+        if (result < 0) {
+            return result;
+        }
+        if (mParams.num_bssid != 0) {
+            nlattr* attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
+            if (attr == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+
+            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, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("Set significant wifi change config");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("failed to set significant wifi change config %d", result);
+            return result;
+        }
+
+        ALOGI("successfully set significant wifi change config");
+
+        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+        result = requestResponse(request);
+        if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+            return result;
+        }
+
+        ALOGI("successfully restarted the scan");
+        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;
+        }
+
+        ALOGI("successfully reset significant wifi change config");
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGV("Got a significant wifi change 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("No scan results found");
+            return NL_SKIP;
+        }
+
+        typedef struct {
+            uint16_t flags;
+            uint16_t channel;
+            mac_addr bssid;
+            s8 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;
+            mResultsBuffer[i].num_rssi = 8;
+            for (int j = 0; j < mResultsBuffer[i].num_rssi; j++)
+                mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
+            mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
+        }
+
+        ALOGV("Retrieved %d scan results", num);
+
+        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);
+    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_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+    return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
+{
+    if (id == -1) {
+        wifi_epno_handler handler;
+        wifi_handle handle = getWifiHandle(iface);
+
+        memset(&handler, 0, sizeof(handler));
+        ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, 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);
+}
+
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+        const wifi_epno_params *params, wifi_epno_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    ePNOCommand *cmd = new ePNOCommand(iface, id, params, 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;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+class AnqpoConfigureCommand : public WifiCommand
+{
+    int num_hs;
+    wifi_passpoint_network *mNetworks;
+    wifi_passpoint_event_handler mHandler;
+    wifi_scan_result *mResult;
+public:
+    AnqpoConfigureCommand(wifi_request_id id, wifi_interface_handle iface,
+        int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler)
+        : WifiCommand("AnqpoConfigureCommand", iface, id), num_hs(num), mNetworks(hs_list),
+            mHandler(handler)
+    {
+        mResult = NULL;
+    }
+
+    int createRequest(WifiRequest& request, int val) {
+
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_ANQPO_CONFIG);
+        result = request.put_u32(GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE, num_hs);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_ANQPO_HS_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(GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID, mNetworks[i].id);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM, mNetworks[i].realm, 256);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID,
+                         mNetworks[i].roamingConsortiumIds, 128);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put(GSCAN_ATTRIBUTE_ANQPO_HS_PLMN, mNetworks[i].plmn, 3);
+            if (result < 0) {
+                return result;
+            }
+
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+
+        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, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to set ANQPO networks; result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_ANQPO_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, GSCAN_EVENT_ANQPO_HOTSPOT_MATCH);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+         ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        typedef struct {
+            u16 channel;        /* channel of GAS protocol */
+            u8  dialog_token;   /* GAS dialog token */
+            u8  fragment_id;    /* fragment id */
+            u16 status_code;    /* status code on GAS completion */
+            u16 data_len;       /* length of data to follow */
+            u8  data[1];        /* variable length specified by data_len */
+        } wifi_anqp_gas_resp;
+
+        ALOGI("ANQPO hotspot matched 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)) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+        mResult = (wifi_scan_result *)malloc(sizeof(wifi_scan_result));
+        if (!mResult) {
+            return NL_SKIP;
+        }
+        wifi_gscan_full_result_t *drv_res = (wifi_gscan_full_result_t *)event.get_vendor_data();
+        wifi_gscan_result_t *fixed = &drv_res->fixed;
+        convert_to_hal_result(mResult, fixed);
+
+        byte *anqp = (byte *)drv_res + offsetof(wifi_gscan_full_result_t, ie_data) + drv_res->ie_length;
+        wifi_anqp_gas_resp *gas = (wifi_anqp_gas_resp *)anqp;
+        int anqp_len = offsetof(wifi_anqp_gas_resp, data) + gas->data_len;
+        int networkId = *(int *)((byte *)anqp + anqp_len);
+
+        ALOGI("%-32s\t", mResult->ssid);
+
+        ALOGI("%02x:%02x:%02x:%02x:%02x:%02x ", mResult->bssid[0], mResult->bssid[1],
+                mResult->bssid[2], mResult->bssid[3], mResult->bssid[4], mResult->bssid[5]);
+
+        ALOGI("%d\t", mResult->rssi);
+        ALOGI("%d\t", mResult->channel);
+        ALOGI("%lld\t", mResult->ts);
+        ALOGI("%lld\t", mResult->rtt);
+        ALOGI("%lld\n", mResult->rtt_sd);
+
+        if(*mHandler.on_passpoint_network_found)
+            (*mHandler.on_passpoint_network_found)(id(), networkId, mResult, anqp_len, anqp);
+        free(mResult);
+        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);
+
+    AnqpoConfigureCommand *cmd = new AnqpoConfigureCommand(id, iface, num, networks, 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_passpoint_list(wifi_request_id id, wifi_interface_handle iface)
+{
+    return wifi_cancel_cmd(id, iface);
+}
diff --git a/wlan/wifi_hal/link_layer_stats.cpp b/wlan/wifi_hal/link_layer_stats.cpp
new file mode 100644 (file)
index 0000000..31e43e6
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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"
+
+#define LOG_TAG  "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+/* Internal radio statistics structure in the driver */
+typedef struct {
+       wifi_radio radio;
+       uint32_t on_time;
+       uint32_t tx_time;
+       uint32_t rx_time;
+       uint32_t on_time_scan;
+       uint32_t on_time_nbd;
+       uint32_t on_time_gscan;
+       uint32_t on_time_roam_scan;
+       uint32_t on_time_pno_scan;
+       uint32_t on_time_hs20;
+       uint32_t num_channels;
+       wifi_channel_stat channels[];
+} wifi_radio_stat_internal;
+
+enum {
+    LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
+       LSTATS_SUBCMD_SET_INFO,
+       LSTATS_SUBCMD_CLEAR_INFO,
+};
+
+class GetLinkStatsCommand : public WifiCommand
+{
+    wifi_stats_result_handler mHandler;
+public:
+    GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
+        : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
+    { }
+
+    virtual int create() {
+        // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
+        if (ret < 0) {
+            ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        // ALOGI("In GetLinkStatsCommand::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();
+
+        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+        wifi_radio_stat *radio_stat = (wifi_radio_stat *)data;
+               ALOGE("radio: = %d", radio_stat->radio);
+        ALOGE("on_time: = %u ms", radio_stat->on_time);
+        ALOGE("tx_time: = %u ms", radio_stat->tx_time);
+               ALOGE("num_tx_levels: = %u", radio_stat->num_tx_levels);
+               radio_stat->tx_time_per_levels = (u32*)((char*)data + sizeof(wifi_radio_stat) + sizeof(wifi_iface_stat));
+               ALOGE("tx_time_per_levels: = %u ms", radio_stat->tx_time_per_levels[0]);
+        ALOGE("rx_time: = %u ms", radio_stat->rx_time);
+        ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan);
+        ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd);
+        ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan);
+        ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan);
+        ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20);
+        if (!radio_stat) {
+            ALOGE("Invalid stats pointer received");
+            return NL_SKIP;
+        }
+        if (radio_stat->num_channels > 11) {
+            ALOGE("Incorrect number of channels = %d", radio_stat->num_channels);
+            // dump data before num_channels
+            ALOGE("radio: = %d", radio_stat->radio);
+            ALOGE("on_time: = %u ms", radio_stat->on_time);
+            ALOGE("tx_time: = %u ms", radio_stat->tx_time);
+            ALOGE("rx_time: = %u ms", radio_stat->rx_time);
+            ALOGE("on_time_scan: = %u ms", radio_stat->on_time_scan);
+            ALOGE("on_time_nbd: = %u ms", radio_stat->on_time_nbd);
+            ALOGE("on_time_gscan: = %u ms", radio_stat->on_time_gscan);
+            ALOGE("on_time_pno_scan: = %u ms", radio_stat->on_time_pno_scan);
+            ALOGE("on_time_hs20: = %u ms", radio_stat->on_time_hs20);
+            free(radio_stat);
+            return NL_SKIP;
+        }
+               wifi_iface_stat *iface_stat = NULL;
+               iface_stat = (wifi_iface_stat *)((char* )data + sizeof(wifi_radio_stat));
+
+               if(*mHandler.on_link_stats_results == NULL) {
+                       ALOGE("*mHandler.on_link_stats_results is NULL");
+               } else {
+               (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
+               }
+        //free(radio_stat);
+        return NL_OK;
+    }
+
+};
+
+class SetLinkStatsCommand : public WifiCommand
+{
+    wifi_stats_result_handler mHandler;
+public:
+    SetLinkStatsCommand(wifi_interface_handle iface)
+        : WifiCommand("SetLinkStatsCommand", iface, 0)
+    { }
+
+    virtual int create() {
+        // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_SET_INFO);
+        if (ret < 0) {
+            ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_SET_INFO, ret);
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        // ALOGI("In GetLinkStatsCommand::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();
+
+        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+         return NL_OK;
+    }
+
+};
+
+class ClearLinkStatsCommand : public WifiCommand
+{
+    wifi_stats_result_handler mHandler;
+public:
+    ClearLinkStatsCommand(wifi_interface_handle iface)
+        : WifiCommand("ClearLinkStatsCommand", iface, 0)
+    { }
+
+    virtual int create() {
+        // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_CLEAR_INFO);
+        if (ret < 0) {
+            ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_CLEAR_INFO, ret);
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        // ALOGI("In GetLinkStatsCommand::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();
+
+        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+         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();
+}
+
+wifi_error wifi_set_link_stats(
+        wifi_interface_handle iface, wifi_link_layer_params params)
+{
+    
+       SetLinkStatsCommand command(iface);
+    return (wifi_error) command.requestResponse();
+    //return WIFI_SUCCESS;
+}
+
+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)
+{
+    
+       ClearLinkStatsCommand command(iface);
+    return (wifi_error) command.requestResponse();
+    //return WIFI_SUCCESS;
+}
diff --git a/wlan/wifi_hal/rtt.cpp b/wlan/wifi_hal/rtt.cpp
new file mode 100644 (file)
index 0000000..048f339
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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 <utils/String8.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+using namespace android;
+#define RTT_RESULT_SIZE (sizeof(wifi_rtt_result));
+typedef enum {
+
+    RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+    RTT_SUBCMD_CANCEL_CONFIG,
+    RTT_SUBCMD_GETCAPABILITY,
+    RTT_SUBCMD_GETAVAILCHANNEL,
+    RTT_SUBCMD_SET_RESPONDER,
+    RTT_SUBCMD_CANCEL_RESPONDER,
+} RTT_SUB_COMMAND;
+
+typedef enum {
+    RTT_ATTRIBUTE_TARGET_CNT = 0,
+    RTT_ATTRIBUTE_TARGET_INFO,
+    RTT_ATTRIBUTE_TARGET_MAC,
+    RTT_ATTRIBUTE_TARGET_TYPE,
+    RTT_ATTRIBUTE_TARGET_PEER,
+    RTT_ATTRIBUTE_TARGET_CHAN,
+    RTT_ATTRIBUTE_TARGET_PERIOD,
+    RTT_ATTRIBUTE_TARGET_NUM_BURST,
+    RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+    RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+    RTT_ATTRIBUTE_TARGET_LCI,
+    RTT_ATTRIBUTE_TARGET_LCR,
+    RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+    RTT_ATTRIBUTE_TARGET_PREAMBLE,
+    RTT_ATTRIBUTE_TARGET_BW,
+    RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+    RTT_ATTRIBUTE_RESULTS_PER_TARGET,
+    RTT_ATTRIBUTE_RESULT_CNT,
+    RTT_ATTRIBUTE_RESULT
+} RTT_ATTRIBUTE;
+typedef struct strmap_entry {
+    int                        id;
+    String8            text;
+} strmap_entry_t;
+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;
+#define DOT11_HDR_LEN 2
+#define DOT11_RM_IE_LEN       5
+#define DOT11_MNG_MEASURE_REQUEST_ID           38      /* 11H MeasurementRequest */
+#define DOT11_MEASURE_TYPE_LCI         8   /* d11 measurement LCI type */
+#define DOT11_MEASURE_TYPE_CIVICLOC    11  /* d11 measurement location civic */
+
+static const strmap_entry_t err_info[] = {
+    {RTT_STATUS_SUCCESS, String8("Success")},
+    {RTT_STATUS_FAILURE, String8("Failure")},
+    {RTT_STATUS_FAIL_NO_RSP, String8("No reponse")},
+    {RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")},
+    {RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")},
+    {RTT_STATUS_FAIL_REJECTED, String8("Rejected")},
+    {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")},
+    {RTT_STATUS_FAIL_SCHEDULE,  String8("schedule failed")},
+    {RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")},
+    {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")},
+    {RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")},
+    {RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")},
+    {RTT_STATUS_ABORTED, String8("aborted")}
+};
+
+    static const char*
+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 GetRttCapabilitiesCommand : public WifiCommand
+{
+    wifi_rtt_capabilities *mCapabilities;
+public:
+    GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
+        : WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites)
+    {
+        memset(mCapabilities, 0, sizeof(*mCapabilities));
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY);
+        if (ret < 0) {
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGD("In GetRttCapabilitiesCommand::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(*mCapabilities));
+
+        memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+
+        return NL_OK;
+    }
+};
+
+
+class GetRttResponderInfoCommand : public WifiCommand
+{
+    wifi_rtt_responder* mResponderInfo;
+public:
+    GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
+        : WifiCommand("GetRttResponderInfoCommand", 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, RTT_SUBCMD_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;
+    }
+};
+
+
+class EnableResponderCommand : public WifiCommand
+{
+    wifi_channel_info  mChannelInfo;
+    wifi_rtt_responder* mResponderInfo;
+    unsigned m_max_duration_sec;
+public:
+    EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
+            unsigned max_duration_seconds, wifi_rtt_responder *responderInfo)
+            : WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint),
+            m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo)
+    {
+        memset(mResponderInfo, 0, sizeof(*mResponderInfo));
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER);
+        if (ret < 0) {
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGD("In EnableResponderCommand::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;
+    }
+};
+
+
+class CancelResponderCommand : public WifiCommand
+{
+
+public:
+    CancelResponderCommand(wifi_interface_handle iface, int id)
+        : WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/
+    {
+
+    }
+
+    virtual int create() {
+        ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id);
+
+        int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER);
+        if (ret < 0) {
+            return ret;
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+};
+
+
+class RttCommand : public WifiCommand
+{
+    unsigned numRttParams;
+    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("RttCommand", iface, id), numRttParams(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("RttCommand", iface, id)
+    {
+        currentIdx = 0;
+        mCompleted = 0;
+        totalCnt = 0;
+        numRttParams = 0;
+    }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
+        if (result < 0) {
+            return result;
+        }
+        nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
+        for (unsigned i = 0; i < numRttParams; i++) {
+            nlattr *attr2 = request.attr_start(i);
+            if (attr2 == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+
+            result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
+                    sizeof(wifi_channel_info));
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+                    rttParams[i].num_frames_per_burst);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+                    rttParams[i].num_retries_per_rtt_frame);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+                    rttParams[i].num_retries_per_ftmr);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD,
+                    rttParams[i].burst_period);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+                    rttParams[i].burst_duration);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI,
+                    rttParams[i].LCI_request);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR,
+                    rttParams[i].LCR_request);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW,
+                    rttParams[i].bw);
+            if (result < 0) {
+                return result;
+            }
+
+            result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE,
+                    rttParams[i].preamble);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        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, RTT_SUBCMD_CANCEL_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+        for(unsigned i = 0; i < num_devices; i++) {
+            result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
+            if (result < 0) {
+                return result;
+            }
+        }
+        request.attr_end(data);
+        return result;
+    }
+    int start() {
+        ALOGD("Setting RTT configuration");
+        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, RTT_EVENT_COMPLETE);
+        ALOGI("Successfully started RTT operation");
+        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);
+            }
+        }
+
+        unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+        return WIFI_SUCCESS;
+    }
+
+    int cancel_specific(unsigned num_devices, mac_addr addr[]) {
+        ALOGE("Stopping RTT");
+
+        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);
+            }
+        }
+
+        unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Got an RTT 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("No rtt results found");
+        }
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
+                mCompleted = it.get_u32();
+                ALOGI("retrieved completed flag : %d\n", mCompleted);
+            } else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) {
+                int result_cnt = 0;
+                mac_addr bssid;
+                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
+                    if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) {
+                        memcpy(bssid, it2.get_data(), sizeof(mac_addr));
+                        ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
+                                bssid[0],
+                                bssid[1],
+                                bssid[2],
+                                bssid[3],
+                                bssid[4],
+                                bssid[5]);
+                    } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) {
+                        result_cnt = it2.get_u32();
+                        ALOGI("retrieved result_cnt : %d\n", result_cnt);
+                    } else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) {
+                        int result_len = it2.get_len();
+                        rttResults[currentIdx] =  (wifi_rtt_result *)malloc(it2.get_len());
+                        wifi_rtt_result *rtt_result = rttResults[currentIdx];
+                        if (rtt_result == NULL) {
+                            mCompleted = 1;
+                            ALOGE("failed to allocate the wifi_rtt_result\n");
+                            break;
+                        }
+                        memcpy(rtt_result, it2.get_data(), it2.get_len());
+                        result_len -= sizeof(wifi_rtt_result);
+                        if (result_len > 0) {
+                            result_len -= sizeof(wifi_rtt_result);
+                            dot11_rm_ie_t *ele_1;
+                            dot11_rm_ie_t *ele_2;
+                            /* The result has LCI or LCR element */
+                            ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
+                            if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) {
+                                if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
+                                    rtt_result->LCI = (wifi_information_element *)ele_1;
+                                    result_len -= (ele_1->len + DOT11_HDR_LEN);
+                                    /* get a next rm ie */
+                                    if (result_len > 0) {
+                                        ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
+                                        if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
+                                                (ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
+                                            rtt_result->LCR = (wifi_information_element *)ele_2;
+                                        }
+                                    }
+                                } else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){
+                                    rtt_result->LCR = (wifi_information_element *)ele_1;
+                                    result_len -= (ele_1->len + DOT11_HDR_LEN);
+                                    /* get a next rm ie */
+                                    if (result_len > 0) {
+                                        ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
+                                        if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
+                                                (ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
+                                            rtt_result->LCI = (wifi_information_element *)ele_2;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        totalCnt++;
+                        ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n"
+                                "\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n"
+                                "\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n"
+                                "\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n",
+                                rtt_result->burst_num, rtt_result->measurement_number,
+                                rtt_result->success_number, rtt_result->number_per_burst_peer,
+                                get_err_info(rtt_result->status), rtt_result->retry_after_duration,
+                                rtt_result->rssi, rtt_result->rx_rate.bitrate * 100,
+                                rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10,
+                                rtt_result->burst_duration, rtt_result->negotiated_burst_num);
+                        currentIdx++;
+                    }
+                }
+            }
+
+        }
+        if (mCompleted) {
+            unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
+            (*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
+            for (int i = 0; i < currentIdx; i++) {
+                free(rttResults[i]);
+                rttResults[i] = NULL;
+            }
+            totalCnt = currentIdx = 0;
+            WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
+            if (cmd)
+                cmd->releaseRef();
+        }
+        return NL_SKIP;
+    }
+};
+
+
+/* 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)
+{
+    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;
+    }
+    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[])
+{
+    wifi_handle handle = getWifiHandle(iface);
+    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)
+{
+    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();
+
+}
+
+/**
+ * Enable RTT responder mode.
+ * channel_hint - hint of the channel information where RTT responder should be enabled on.
+ * max_duration_seconds - timeout of responder mode.
+ * wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported.
+ */
+wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
+                                wifi_channel_info channel_hint, unsigned max_duration_seconds,
+                                wifi_rtt_responder* responderInfo)
+{
+    EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo);
+    return (wifi_error) command.requestResponse();
+}
+
+/**
+ * Disable RTT responder mode.
+ */
+wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface)
+{
+    CancelResponderCommand command(iface, id);
+    return (wifi_error) command.requestResponse();
+}
+
diff --git a/wlan/wifi_hal/sync.h b/wlan/wifi_hal/sync.h
new file mode 100644 (file)
index 0000000..aaae325
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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/wlan/wifi_hal/wifi_hal.cpp b/wlan/wifi_hal/wifi_hal.cpp
new file mode 100644 (file)
index 0000000..cfc5e23
--- /dev/null
@@ -0,0 +1,1349 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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 <errno.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 "rtt.h"
+/*
+ BUGBUG: normally, libnl allocates ports for all connections it makes; but
+ being a static library, it doesn't really know how many other netlink connections
+ are made by the same process, if connections come from different shared libraries.
+ These port assignments exist to solve that problem - temporarily. We need to fix
+ libnl to try and allocate ports across the entire process.
+ */
+
+#define WIFI_HAL_CMD_SOCK_PORT       644
+#define WIFI_HAL_EVENT_SOCK_PORT     645
+
+static void internal_event_handler(wifi_handle handle, int events);
+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);
+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);
+static wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
+                            const u8 *program, u32 len);
+static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+                u32 *version, u32 *max_len);
+static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface, u8 enable);
+static wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,
+                                WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
+
+typedef enum wifi_attr {
+    ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
+    ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
+    ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
+    ANDR_WIFI_ATTRIBUTE_NODFS_SET,
+    ANDR_WIFI_ATTRIBUTE_COUNTRY,
+    ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE
+    // Add more attribute here
+} wifi_attr_t;
+
+enum wifi_rssi_monitor_attr {
+    RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
+    RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
+    RSSI_MONITOR_ATTRIBUTE_START,
+};
+
+enum wifi_apf_attr {
+    APF_ATTRIBUTE_VERSION,
+    APF_ATTRIBUTE_MAX_LEN,
+    APF_ATTRIBUTE_PROGRAM,
+    APF_ATTRIBUTE_PROGRAM_LEN
+};
+
+enum apf_request_type {
+    GET_APF_CAPABILITIES,
+    SET_APF_PROGRAM
+};
+
+/* 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));
+}
+
+static nl_sock * wifi_create_nl_socket(int port)
+{
+    // ALOGI("Creating socket");
+    struct nl_sock *sock = nl_socket_alloc();
+    if (sock == NULL) {
+        ALOGE("Could not create handle");
+        return NULL;
+    }
+
+    wifi_socket_set_local_port(sock, port);
+
+    struct sockaddr *addr = NULL;
+    // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl));
+
+    // ALOGI("Connecting socket");
+    if (nl_connect(sock, NETLINK_GENERIC)) {
+        ALOGE("Could not connect handle");
+        nl_socket_free(sock);
+        return NULL;
+    }
+
+    // ALOGI("Making socket nonblocking");
+    /*
+    if (nl_socket_set_nonblocking(sock)) {
+        ALOGE("Could make socket non-blocking");
+        nl_socket_free(sock);
+        return NULL;
+    }
+    */
+
+    return sock;
+}
+
+/*initialize function pointer table with Realtek HAL API*/
+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_link_stats = wifi_get_link_stats;
+    fn->wifi_set_link_stats = wifi_set_link_stats;
+    fn->wifi_clear_link_stats = wifi_clear_link_stats;
+    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_rtt_get_responder_info = wifi_rtt_get_responder_info;
+    fn->wifi_enable_responder = wifi_enable_responder;
+    fn->wifi_disable_responder = wifi_disable_responder;
+    fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
+    fn->wifi_start_logging = wifi_start_logging;
+    fn->wifi_set_epno_list = wifi_set_epno_list;
+    fn->wifi_reset_epno_list = wifi_reset_epno_list;
+    fn->wifi_set_country_code = wifi_set_country_code;
+    fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
+    fn->wifi_set_log_handler = wifi_set_log_handler;
+    fn->wifi_reset_log_handler = wifi_reset_log_handler;
+    fn->wifi_set_alert_handler = wifi_set_alert_handler;
+    fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
+    fn->wifi_get_firmware_version = wifi_get_firmware_version;
+    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_start_rssi_monitoring = wifi_start_rssi_monitoring;
+    fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
+    fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
+    fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet;
+    fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
+    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_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
+    fn->wifi_set_packet_filter = wifi_set_packet_filter;
+       fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
+    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));
+
+    ALOGI("Creating socket");
+    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;
+
+    if (wifi_init_interfaces(*handle) != WIFI_SUCCESS) {
+        ALOGE("No wifi interface found");
+        nl_socket_free(cmd_sock);
+        nl_socket_free(event_sock);
+        pthread_mutex_destroy(&info->cb_lock);
+        free(info);
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    if ((wifi_add_membership(*handle, "scan") < 0) ||
+        (wifi_add_membership(*handle, "mlme")  < 0) ||
+        (wifi_add_membership(*handle, "regulatory") < 0) ||
+        (wifi_add_membership(*handle, "vendor") < 0)) {
+        ALOGE("Add membership failed");
+        nl_socket_free(cmd_sock);
+        nl_socket_free(event_sock);
+        pthread_mutex_destroy(&info->cb_lock);
+        free(info);
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    // ALOGI("Found %d interfaces", info->num_interfaces);
+
+    ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR);
+    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);
+    }
+
+    // ALOGI("Successfully added membership for 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);
+
+    ALOGI("Internal cleanup completed");
+}
+
+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 (TEMP_FAILURE_RETRY(write(info->cleanup_socks[0], "Exit", 4)) < 1) {
+        // As a fallback set the cleanup flag to TRUE
+        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));
+        ssize_t result = TEMP_FAILURE_RETRY(read(info->cleanup_socks[0], buf, sizeof(buf)));
+        ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__,
+               result, errno, strerror(errno));
+        if (strncmp(buf, "Done", 4) == 0) {
+            ALOGE("Event processing terminated");
+        } else {
+            ALOGD("Rx'ed %s", buf);
+        }
+    }
+    info->clean_up = true;
+    pthread_mutex_lock(&info->cb_lock);
+
+    int bad_commands = 0;
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+        cb_info *cbi = &(info->event_cb[i]);
+        WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+        ALOGI("Command left in event_cb %p:%s", cmd, (cmd ? cmd->getType(): ""));
+    }
+
+    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) {
+            ALOGI("Cancelling command %p:%s", cmd, cmd->getType());
+            pthread_mutex_unlock(&info->cb_lock);
+            cmd->cancel();
+            pthread_mutex_lock(&info->cb_lock);
+            if (num_cmd == info->num_cmd) {
+                ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): ""));
+                bad_commands++;
+            }
+            /* release reference added when command is saved */
+            cmd->releaseRef();
+        }
+    }
+
+    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);
+    // ALOGD("nl_recvmsgs returned %d", res);
+    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];
+    /* TODO: Add support for timeouts */
+
+    do {
+        int timeout = -1;                   /* Infinite timeout */
+        pfd[0].revents = 0;
+        pfd[1].revents = 0;
+        // ALOGI("Polling socket");
+        int result = TEMP_FAILURE_RETRY(poll(pfd, 2, timeout));
+        if (result < 0) {
+            // ALOGE("Error polling socket");
+        } else if (pfd[0].revents & POLLERR) {
+            ALOGE("POLL Error; error no = %d (%s)", errno, strerror(errno));
+            ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf)));
+            ALOGE("Read after POLL returned %zd, error no = %d (%s)", result2,
+                  errno, strerror(errno));
+        } else if (pfd[0].revents & POLLHUP) {
+            ALOGE("Remote side hung up");
+            break;
+        } else if (pfd[0].revents & POLLIN) {
+            // ALOGI("Found some events!!!");
+            internal_pollin_handler(handle);
+        } else if (pfd[1].revents & POLLIN) {
+            memset(buf, 0, sizeof(buf));
+            ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[1].fd, buf, sizeof(buf)));
+            ALOGE("%s: Read after POLL returned %zd, error no = %d (%s)", __FUNCTION__,
+                   result2, errno, strerror(errno));
+            if (strncmp(buf, "Exit", 4) == 0) {
+                ALOGD("Got a signal to exit!!!");
+                if (TEMP_FAILURE_RETRY(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);
+    ALOGI("Exit %s", __FUNCTION__);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+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)
+{
+    // ALOGI("got an event");
+
+    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);
+        ALOGV("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+                event.get_cmdString(), vendor_id, subcmd);
+    } else {
+        // ALOGV("event received %s", event.get_cmdString());
+    }
+
+    // ALOGV("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
+    // event.log();
+
+    bool dispatched = false;
+
+    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("GetMulticastIdCommand", handle, 0)
+    {
+        mName = name;
+        mGroup = group;
+        mId = -1;
+    }
+
+    int getId() {
+        return mId;
+    }
+
+    virtual int create() {
+        int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
+        // ALOGI("ctrl family = %d", nlctrlFamily);
+        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) {
+
+        // ALOGI("handling reponse in %s", __func__);
+
+        struct nlattr **tb = reply.attributes();
+        struct genlmsghdr *gnlh = reply.header();
+        struct nlattr *mcgrp = NULL;
+        int i;
+
+        if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+            ALOGI("No multicast groups found");
+            return NL_SKIP;
+        } else {
+            // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
+        }
+
+        for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+            // ALOGI("Processing group");
+            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]);
+
+            // ALOGI("Found group name %s", grpName);
+
+            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("SetPnoMacAddrOuiCommand", handle, 0)
+    {
+        mOui = scan_oui;
+    }
+
+    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() {
+        ALOGD("Sending mac address OUI");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_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) {
+         ALOGD("Request complete!");
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+};
+
+class SetNodfsCommand : public WifiCommand {
+
+private:
+    u32 mNoDfs;
+public:
+    SetNodfsCommand(wifi_interface_handle handle, u32 nodfs)
+        : WifiCommand("SetNodfsCommand", handle, 0) {
+        mNoDfs = nodfs;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_NODFS_SET);
+        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(ANDR_WIFI_ATTRIBUTE_NODFS_SET, mNoDfs);
+        if (ret < 0) {
+             return ret;
+        }
+
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+class SetCountryCodeCommand : public WifiCommand {
+private:
+    const char *mCountryCode;
+public:
+    SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code)
+        : WifiCommand("SetCountryCodeCommand", handle, 0) {
+        mCountryCode = country_code;
+        }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_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(ANDR_WIFI_ATTRIBUTE_COUNTRY, mCountryCode);
+        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("SetRSSIMonitorCommand", handle, id), mMax_rssi(max_rssi), mMin_rssi
+        (min_rssi), mHandler(eh)
+        {
+        }
+   int createRequest(WifiRequest& request, int enable) {
+        int result = request.create(GOOGLE_OUI, WIFI_SUBCMD_SET_RSSI_MONITOR);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0));
+        if (result < 0) {
+            return result;
+        }
+        ALOGD("create request");
+        result = request.put_u32(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0));
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u32(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, GOOGLE_RSSI_MONITOR_EVENT);
+
+
+        if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GOOGLE_RSSI_MONITOR_EVENT);
+            return result;
+        }
+        ALOGI("Done!");
+        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, GOOGLE_RSSI_MONITOR_EVENT);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+   virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Got a RSSI monitor 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;
+        }
+        /* driver<->HAL event structure */
+        #define RSSI_MONITOR_EVT_VERSION   1
+        typedef struct {
+            u8 version;
+            s8 cur_rssi;
+            mac_addr BSSID;
+        } rssi_monitor_evt;
+
+        rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data();
+
+        if (data->version != RSSI_MONITOR_EVT_VERSION) {
+            ALOGI("Event version mismatch %d, expected %d", data->version, RSSI_MONITOR_EVT_VERSION);
+            return NL_SKIP;
+        }
+
+        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 AndroidPktFilterCommand : public WifiCommand {
+    private:
+        const u8* mProgram;
+        u32 mProgramLen;
+        u32* mVersion;
+        u32* mMaxLen;
+        int mReqType;
+    public:
+        AndroidPktFilterCommand(wifi_interface_handle handle,
+                u32* version, u32* max_len)
+            : WifiCommand("AndroidPktFilterCommand", handle, 0),
+                    mVersion(version), mMaxLen(max_len),
+                    mReqType(GET_APF_CAPABILITIES)
+        {
+        }
+
+        AndroidPktFilterCommand(wifi_interface_handle handle,
+                const u8* program, u32 len)
+            : WifiCommand("AndroidPktFilterCommand", handle, 0),
+                    mProgram(program), mProgramLen(len),
+                    mReqType(SET_APF_PROGRAM)
+        {
+        }
+
+    int createRequest(WifiRequest& request) {
+        if (mReqType == SET_APF_PROGRAM) {
+            ALOGI("\n%s: APF set program request\n", __FUNCTION__);
+            return createSetPktFilterRequest(request);
+        } else if (mReqType == GET_APF_CAPABILITIES) {
+            ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__);
+            return createGetPktFilterCapabilitesRequest(request);
+        } else {
+            ALOGE("\n%s Unknown APF request\n", __FUNCTION__);
+            return WIFI_ERROR_NOT_SUPPORTED;
+        }
+        return WIFI_SUCCESS;
+    }
+
+    int createSetPktFilterRequest(WifiRequest& request) {
+        u8 *program = new u8[mProgramLen];
+        NULL_CHECK_RETURN(program, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+        int result = request.create(GOOGLE_OUI, APF_SUBCMD_SET_FILTER);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(APF_ATTRIBUTE_PROGRAM_LEN, mProgramLen);
+        if (result < 0) {
+            return result;
+        }
+        memcpy(program, mProgram, mProgramLen);
+        result = request.put(APF_ATTRIBUTE_PROGRAM, program, mProgramLen);
+        if (result < 0) {
+            return result;
+        }
+        request.attr_end(data);
+        delete[] program;
+        return result;
+    }
+
+    int createGetPktFilterCapabilitesRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, APF_SUBCMD_GET_CAPABILITIES);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        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) {
+            ALOGI("Request Response failed for APF, result = %d", result);
+            return result;
+        }
+        ALOGI("Done!");
+        return result;
+    }
+
+    int cancel() {
+        return WIFI_SUCCESS;
+    }
+
+    int handleResponse(WifiEvent& reply) {
+        ALOGD("In SetAPFCommand::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();
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in SetAPFCommand response; ignoring it");
+            return NL_SKIP;
+        }
+        if( mReqType == SET_APF_PROGRAM) {
+            ALOGD("Response recieved for set packet filter command\n");
+        } else if (mReqType == GET_APF_CAPABILITIES) {
+            *mVersion = 0;
+            *mMaxLen = 0;
+            ALOGD("Response recieved for get packet filter capabilities command\n");
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == APF_ATTRIBUTE_VERSION) {
+                    *mVersion = it.get_u32();
+                    ALOGI("APF version is %d\n", *mVersion);
+                } else if (it.get_type() == APF_ATTRIBUTE_MAX_LEN) {
+                    *mMaxLen = it.get_u32();
+                    ALOGI("APF max len is %d\n", *mMaxLen);
+                } else {
+                    ALOGE("Ignoring invalid attribute type = %d, size = %d",
+                            it.get_type(), it.get_len());
+                }
+            }
+        }
+        return NL_OK;
+    }
+
+    int handleEvent(WifiEvent& event) {
+        /* No Event to recieve for APF commands */
+        return NL_SKIP;
+    }
+};
+
+class SetNdoffloadCommand : public WifiCommand {
+
+private:
+    u8 mEnable;
+public:
+    SetNdoffloadCommand(wifi_interface_handle handle, u8 enable)
+        : WifiCommand("SetNdoffloadCommand", handle, 0) {
+        mEnable = enable;
+    }
+    virtual int create() {
+        int ret;
+
+        ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_CONFIG_ND_OFFLOAD);
+        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(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE, mEnable);
+        if (ret < 0) {
+             return ret;
+        }
+
+        mMsg.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+};
+
+class GetFeatureSetCommand : public WifiCommand {
+
+private:
+    int feature_type;
+    feature_set *fset;
+    feature_set *feature_matrix;
+    int *fm_size;
+    int set_size_max;
+public:
+    GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set,
+         feature_set set_matrix[], int *size, int max_size)
+        : WifiCommand("GetFeatureSetCommand", handle, 0)
+    {
+        feature_type = feature;
+        fset = set;
+        feature_matrix = set_matrix;
+        fm_size = size;
+        set_size_max = max_size;
+    }
+
+    virtual int create() {
+        int ret;
+
+        if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+            ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET);
+        } else if (feature_type == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) {
+            ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX);
+        } else {
+            ALOGE("Unknown feature type %d", feature_type);
+            return -1;
+        }
+
+        if (ret < 0) {
+            ALOGE("Can't create message to send to driver - %d", ret);
+        }
+
+        return ret;
+    }
+
+protected:
+    virtual int handleResponse(WifiEvent& reply) {
+
+        ALOGV("In GetFeatureSetCommand::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();
+
+        nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = reply.get_vendor_data_len();
+
+        ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+        if (vendor_data == NULL || len == 0) {
+            ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it");
+            return NL_SKIP;
+        }
+        if(feature_type == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+            void *data = reply.get_vendor_data();
+            if(!fset) {
+                ALOGE("Buffers pointers not set");
+                return NL_SKIP;
+            }
+            memcpy(fset, data, min(len, (int) sizeof(*fset)));
+        } else {
+            int num_features_set = 0;
+            int i = 0;
+
+            if(!feature_matrix || !fm_size) {
+                ALOGE("Buffers pointers not set");
+                return NL_SKIP;
+            }
+
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) {
+                    num_features_set = it.get_u32();
+                    ALOGV("Got feature list with %d concurrent sets", num_features_set);
+                    if(set_size_max && (num_features_set > set_size_max))
+                        num_features_set = set_size_max;
+                    *fm_size = num_features_set;
+                } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) &&
+                             i < num_features_set) {
+                    feature_matrix[i] = it.get_u32();
+                    i++;
+                } else {
+                    ALOGW("Ignoring invalid attribute type = %d, size = %d",
+                            it.get_type(), it.get_len());
+                }
+            }
+
+        }
+        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);
+    // ALOGI("found an interface : %s, id = %d", name, info->id);
+    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);
+
+    if (n == 0)
+        return WIFI_ERROR_NOT_AVAILABLE;
+
+    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_supported_feature_set(wifi_interface_handle handle, feature_set *set)
+{
+    GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, set, NULL, NULL, 1);
+    return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+       feature_set set[], int *set_size)
+{
+    GetFeatureSetCommand command(handle, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, NULL,
+            set, set_size, set_size_max);
+    return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
+{
+#if 0
+    SetPnoMacAddrOuiCommand command(handle, scan_oui);
+    return (wifi_error)command.start();
+#endif
+       return WIFI_SUCCESS;
+
+}
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
+{
+    SetNodfsCommand command(handle, nodfs);
+    return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code)
+{
+#if 0
+    SetCountryCodeCommand command(handle, country_code);
+    return (wifi_error) command.requestResponse();
+#endif
+       return WIFI_SUCCESS ;
+}
+
+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);
+    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;
+}
+
+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;
+        s8 max_rssi = 0, min_rssi = 0;
+        wifi_handle handle = getWifiHandle(iface);
+        memset(&handler, 0, sizeof(handler));
+        SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
+                                                    max_rssi, min_rssi, 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);
+}
+
+static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+        u32 *version, u32 *max_len)
+{
+#if 0
+    ALOGD("Getting APF capabilities, halHandle = %p\n", handle);
+    AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, version, max_len);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    if (result == WIFI_SUCCESS) {
+        ALOGD("Getting APF capability, version = %d, max_len = %d\n", *version, *max_len);
+    }
+    cmd->releaseRef();
+    return result;
+#endif
+       return WIFI_SUCCESS;
+}
+
+static wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
+        const u8 *program, u32 len)
+{
+    ALOGD("Setting APF program, halHandle = %p\n", handle);
+    AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, program, len);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    cmd->releaseRef();
+    return result;
+}
+
+static wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
+{
+#if 0
+    SetNdoffloadCommand command(handle, enable);
+    return (wifi_error) command.requestResponse();
+#endif
+       return WIFI_SUCCESS;
+}
+
+static wifi_error wifi_get_wake_reason_stats (wifi_interface_handle handle,
+                                WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt) {
+                                
+       return WIFI_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/wlan/wifi_hal/wifi_logger.cpp b/wlan/wifi_hal/wifi_logger.cpp
new file mode 100644 (file)
index 0000000..d53a010
--- /dev/null
@@ -0,0 +1,1148 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string>
+#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 <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+    LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
+    LOGGER_TRIGGER_MEM_DUMP,
+    LOGGER_GET_MEM_DUMP,
+    LOGGER_GET_VER,
+    LOGGER_GET_RING_STATUS,
+    LOGGER_GET_RING_DATA,
+    LOGGER_GET_FEATURE,
+    LOGGER_RESET_LOGGING,
+    LOGGER_TRIGGER_DRIVER_MEM_DUMP,
+    LOGGER_GET_DRIVER_MEM_DUMP,
+    LOGGER_START_PKT_FATE_MONITORING,
+    LOGGER_GET_TX_PKT_FATES,
+    LOGGER_GET_RX_PKT_FATES,
+} DEBUG_SUB_COMMAND;
+
+typedef enum {
+    LOGGER_ATTRIBUTE_DRIVER_VER,
+    LOGGER_ATTRIBUTE_FW_VER,
+    LOGGER_ATTRIBUTE_RING_ID,
+    LOGGER_ATTRIBUTE_RING_NAME,
+    LOGGER_ATTRIBUTE_RING_FLAGS,
+    LOGGER_ATTRIBUTE_LOG_LEVEL,
+    LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
+    LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
+    LOGGER_ATTRIBUTE_FW_DUMP_LEN,
+    LOGGER_ATTRIBUTE_FW_DUMP_DATA,
+    // LOGGER_ATTRIBUTE_FW_ERR_CODE,
+    LOGGER_ATTRIBUTE_RING_DATA,
+    LOGGER_ATTRIBUTE_RING_STATUS,
+    LOGGER_ATTRIBUTE_RING_NUM,
+    LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
+    LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
+    LOGGER_ATTRIBUTE_PKT_FATE_NUM,
+    LOGGER_ATTRIBUTE_PKT_FATE_DATA,
+} LOGGER_ATTRIBUTE;
+
+typedef enum {
+    DEBUG_OFF = 0,
+    DEBUG_NORMAL,
+    DEBUG_VERBOSE,
+    DEBUG_VERY,
+    DEBUG_VERY_VERY,
+} LOGGER_LEVEL;
+
+typedef enum {
+    GET_FW_VER,
+    GET_DRV_VER,
+    GET_RING_DATA,
+    GET_RING_STATUS,
+    GET_FEATURE,
+    START_RING_LOG,
+} GetCmdType;
+
+typedef enum {
+    PACKET_MONITOR_START,
+    TX_PACKET_FATE,
+    RX_PACKET_FATE,
+} PktFateReqType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+class DebugCommand : public WifiCommand
+{
+    char *mBuff;
+    int *mBuffSize;
+    u32 *mNumRings;
+    wifi_ring_buffer_status *mStatus;
+    unsigned int *mSupport;
+    u32 mVerboseLevel;
+    u32 mFlags;
+    u32 mMaxIntervalSec;
+    u32 mMinDataSize;
+    char *mRingName;
+    GetCmdType mType;
+
+public:
+
+    // constructor for get version
+    DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size,
+            GetCmdType cmdType)
+        : WifiCommand("DebugCommand", 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("DebugCommand", 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("DebugCommand", 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("DebugCommand", 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("DebugCommand", 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, 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(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put log level; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to put ring flags; result = %d", result);
+            return result;
+        }
+        result = request.put_u32(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(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(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, 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(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, 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(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, 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(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, 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, 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() == 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(), LOGGER_ATTRIBUTE_RING_NUM);
+                    return NL_SKIP;
+                }
+
+                it.next();
+                for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) {
+                    if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
+                        memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status));
+                        i++;
+                        status++;
+                    } 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();
+                int len = reply.get_vendor_data_len();
+
+                ALOGD("len = %d, expected len = %d", len, 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 collect a firmware version string */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer,
+        int buffer_size)
+{
+#if 0
+    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;
+    }
+#endif
+       std::string pFirmwareVer = "RTK_FIRMWARE";
+       memcpy(buffer, pFirmwareVer.c_str(), pFirmwareVer.length()+1);
+       return WIFI_SUCCESS;
+}
+
+/* API to collect a driver version string */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size)
+{
+#if 0
+    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;
+    }
+#endif
+       std::string pDriverVer = "RTK_DRIVER";
+       memcpy(buffer, pDriverVer.c_str(), pDriverVer.length()+1);
+       return WIFI_SUCCESS;
+}
+
+/* API to collect driver records */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name)
+{
+#if 0
+    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;
+#endif
+       return WIFI_SUCCESS;
+}
+
+/* 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 0
+    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;
+    }
+#endif
+       wifi_ring_buffer_status* pLocalstatus = NULL;
+       std::string from = "RTK_RING";
+       memcpy(status->name, from.c_str(), strlen(from.c_str())+1);
+       *num_rings = 1;
+       
+       return  WIFI_SUCCESS;
+}
+
+/* API to get supportable feature */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+        unsigned int *support)
+{
+    if (support) {
+               wifi_error result = WIFI_SUCCESS;
+               #if 0
+        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();
+               #endif
+               *support = WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
+               
+        return result;
+    } else {
+        ALOGE("Get support buffer NULL");
+        return  WIFI_ERROR_INVALID_ARGS;
+    }
+}
+
+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 0
+    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;
+    }
+#endif
+       return WIFI_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+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("SetLogHandler", iface, id), mHandler(handler)
+    { }
+
+    int start() {
+        ALOGV("Register loghandler");
+        registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_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, GOOGLE_DEBUG_RING_EVENT);
+
+        WifiRequest request(familyId(), ifaceId());
+        int result = request.create(GOOGLE_OUI, 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 == GOOGLE_DEBUG_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() == LOGGER_ATTRIBUTE_RING_STATUS) {
+                    memcpy(&status, it.get_data(), sizeof(status));
+                } else if (it.get_type() == 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("SetAlertHandler", iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL),
+            mErrCode(0)
+    { }
+
+    int start() {
+        ALOGV("Start Alerting");
+        registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int cancel() {
+        ALOGV("Clear alerthandler");
+
+        /* unregister alert handler */
+        unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_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() == 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) {
+        wifi_ring_buffer_id ring_id;
+        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 == GOOGLE_DEBUG_MEM_DUMP_EVENT) {
+            for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+                if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
+                    mBuffSize = it.get_u32();
+                } else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) {
+                    buffer_size = it.get_len();
+                    buffer = (char *)it.get_data();
+            /*
+                } else if (it.get_type() == 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, LOGGER_GET_MEM_DUMP);
+                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(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(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 MemoryDumpCommand: public WifiCommand
+{
+    wifi_firmware_memory_dump_handler mHandler;
+    int mBuffSize;
+    char *mBuff;
+
+public:
+    MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler)
+        : WifiCommand("MemoryDumpCommand", iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL)
+    { }
+
+    int start() {
+        ALOGD("Start memory dump command");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("Failed to create trigger fw 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;
+        }
+
+        for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+            if (it.get_type() == 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, LOGGER_GET_MEM_DUMP);
+                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(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(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to put get memory dump request; result = %d", result);
+                    return result;
+                }
+                request.attr_end(data);
+
+                result = requestResponse(request);
+                if (result != WIFI_SUCCESS) {
+                    ALOGE("Failed to register get momory dump response; result = %d", result);
+                }
+            } else if (it.get_type() == 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());
+            }
+        }
+        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)
+{
+#if 0
+    MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler);
+    NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+    wifi_error result = (wifi_error)cmd->start();
+    cmd->releaseRef();
+    return result;
+#endif
+       return WIFI_SUCCESS;
+}
+
+class PacketFateCommand: public WifiCommand
+{
+    void *mReportBufs;
+    size_t mNoReqFates;
+    size_t *mNoProvidedFates;
+    PktFateReqType mReqType;
+
+public:
+    PacketFateCommand(wifi_interface_handle handle)
+        : WifiCommand("PacketFateCommand", 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("PacketFateCommand", 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("PacketFateCommand", 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, 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, 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(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u64(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, 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(LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u64(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() == LOGGER_ATTRIBUTE_PKT_FATE_NUM) {
+                *mNoProvidedFates = it.get_u32();
+                ALOGI("No: of pkt fates provided is %d\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)
+{
+#if 0
+    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;
+#endif
+       return WIFI_SUCCESS;
+}
+
+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)
+{
+#if 0
+    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();
+    return result;
+#endif
+       return WIFI_SUCCESS;
+}
+
+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)
+{
+#if 0
+    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();
+    return result;
+#endif
+       return WIFI_SUCCESS;
+}
diff --git a/wlan/wifi_hal/wifi_offload.cpp b/wlan/wifi_hal/wifi_offload.cpp
new file mode 100644 (file)
index 0000000..397b792
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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 <log/log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+    WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
+    WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
+} WIFI_OFFLOAD_SUB_COMMAND;
+
+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("MKeepAliveCommand", 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("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
+    { }
+
+    int createRequest(WifiRequest &request) {
+        int result;
+
+        switch (mType) {
+            case START_MKEEP_ALIVE:
+            {
+                result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
+                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, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
+                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) {
+        ALOGD("In MKeepAliveCommand::handleResponse");
+
+        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);
+        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("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);
+        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("Invalid mkeep_alive parameters");
+        return  WIFI_ERROR_INVALID_ARGS;
+    }
+}