SSB-8693 slsi hal library code for GSCAN

slsi hal library code
see http://12.36.211.73:8089/#/c/108073/


SCSC-Bug-Id: SSB-8693

Change-Id: Ib1826f3f6f6da7e0b961b0f02130780fc31865fc
Signed-off-by: j.sangaru <j.sangaru@samsung.com>
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..4bd17fa
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,29 @@
+#############################################################################
+#
+# Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd
+#
+#############################################################################
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+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
+
+LOCAL_MODULE := libwifi-hal-slsi
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/common.cpp b/common.cpp
new file mode 100755
index 0000000..c35f3fe
--- /dev/null
+++ b/common.cpp
@@ -0,0 +1,214 @@
+

+#include <stdlib.h>

+#include <linux/pkt_sched.h>

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

+#include <netlink/handlers.h>

+#include <linux/types.h>

+

+#include "wifi_hal.h"

+#include "common.h"

+

+interface_info *getIfaceInfo(wifi_interface_handle handle)

+{

+    return (interface_info *)handle;

+}

+

+wifi_handle getWifiHandle(wifi_interface_handle handle)

+{

+    return getIfaceInfo(handle)->handle;

+}

+

+hal_info *getHalInfo(wifi_handle handle)

+{

+    return (hal_info *)handle;

+}

+

+hal_info *getHalInfo(wifi_interface_handle handle)

+{

+    return getHalInfo(getWifiHandle(handle));

+}

+

+wifi_handle getWifiHandle(hal_info *info)

+{

+    return (wifi_handle)info;

+}

+

+wifi_interface_handle getIfaceHandle(interface_info *info)

+{

+    return (wifi_interface_handle)info;

+}

+

+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)

+{

+    hal_info *info = (hal_info *)handle;

+

+    /* TODO: check for multiple handlers? */

+    pthread_mutex_lock(&info->cb_lock);

+

+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;

+

+    if (info->num_event_cb < info->alloc_event_cb) {

+        info->event_cb[info->num_event_cb].nl_cmd  = cmd;

+        info->event_cb[info->num_event_cb].vendor_id  = 0;

+        info->event_cb[info->num_event_cb].vendor_subcmd  = 0;

+        info->event_cb[info->num_event_cb].cb_func = func;

+        info->event_cb[info->num_event_cb].cb_arg  = arg;

+        ALOGI("Successfully added event handler %p:%p for command %d at %d",

+                arg, func, cmd, info->num_event_cb);

+        info->num_event_cb++;

+        result = WIFI_SUCCESS;

+    }

+

+    pthread_mutex_unlock(&info->cb_lock);

+    return result;

+}

+

+wifi_error wifi_register_vendor_handler(wifi_handle handle,

+        uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)

+{

+    hal_info *info = (hal_info *)handle;

+

+//ALOGD("GSCAN register handle wifi_register_vendor_handler %p", handle);

+    /* TODO: check for multiple handlers? */

+    pthread_mutex_lock(&info->cb_lock);

+        ALOGI("Added event handler %p", info);

+

+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;

+

+	//    ALOGD("register_vendor_handler: handle = %p", handle);

+    if (info->num_event_cb < info->alloc_event_cb) {

+        info->event_cb[info->num_event_cb].nl_cmd  = NL80211_CMD_VENDOR;

+        info->event_cb[info->num_event_cb].vendor_id  = id;

+        info->event_cb[info->num_event_cb].vendor_subcmd  = subcmd;

+        info->event_cb[info->num_event_cb].cb_func = func;

+        info->event_cb[info->num_event_cb].cb_arg  = arg;

+        ALOGI("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",

+                arg, func, id, subcmd, info->num_event_cb);

+        info->num_event_cb++;

+        result = WIFI_SUCCESS;

+    }

+

+    pthread_mutex_unlock(&info->cb_lock);

+    return result;

+}

+

+void wifi_unregister_handler(wifi_handle handle, int cmd)

+{

+    hal_info *info = (hal_info *)handle;

+

+    if (cmd == NL80211_CMD_VENDOR) {

+        ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");

+        return;

+    }

+

+    pthread_mutex_lock(&info->cb_lock);

+

+    for (int i = 0; i < info->num_event_cb; i++) {

+        if (info->event_cb[i].nl_cmd == cmd) {

+            ALOGI("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",

+                    info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);

+

+            memmove(&info->event_cb[i], &info->event_cb[i+1],

+                (info->num_event_cb - i - 1) * sizeof(cb_info));

+            info->num_event_cb--;

+            break;

+        }

+    }

+

+    pthread_mutex_unlock(&info->cb_lock);

+}

+

+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)

+{

+    hal_info *info = (hal_info *)handle;

+

+    pthread_mutex_lock(&info->cb_lock);

+

+    for (int i = 0; i < info->num_event_cb; i++) {

+

+        if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR

+                && info->event_cb[i].vendor_id == id

+                && info->event_cb[i].vendor_subcmd == subcmd) {

+            ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",

+                    info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);

+            memmove(&info->event_cb[i], &info->event_cb[i+1],

+                (info->num_event_cb - i - 1) * sizeof(cb_info));

+            info->num_event_cb--;

+            break;

+        }

+    }

+

+    pthread_mutex_unlock(&info->cb_lock);

+}

+

+

+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)

+{

+    hal_info *info = (hal_info *)handle;

+

+    ALOGD("registering command %d", id);

+

+    wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;

+

+    if (info->num_cmd < info->alloc_cmd) {

+        info->cmd[info->num_cmd].id   = id;

+        info->cmd[info->num_cmd].cmd  = cmd;

+        ALOGI("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);

+        info->num_cmd++;

+        result = WIFI_SUCCESS;

+    }

+

+    return result;

+}

+

+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)

+{

+    hal_info *info = (hal_info *)handle;

+

+    ALOGD("un-registering command %d", id);

+

+    WifiCommand *cmd = NULL;

+

+    for (int i = 0; i < info->num_cmd; i++) {

+        if (info->cmd[i].id == id) {

+            cmd = info->cmd[i].cmd;

+            memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));

+            info->num_cmd--;

+            ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);

+            break;

+        }

+    }

+

+    return cmd;

+}

+

+WifiCommand *wifi_get_cmd(wifi_handle handle, int id)

+{

+    hal_info *info = (hal_info *)handle;

+

+    WifiCommand *cmd = NULL;

+

+    for (int i = 0; i < info->num_cmd; i++) {

+        if (info->cmd[i].id == id) {

+            cmd = info->cmd[i].cmd;

+            break;

+        }

+    }

+

+    return cmd;

+}

+

+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)

+{

+    hal_info *info = (hal_info *)handle;

+

+    for (int i = 0; i < info->num_cmd; i++) {

+        if (info->cmd[i].cmd == cmd) {

+            int id = info->cmd[i].id;

+            memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));

+            info->num_cmd--;

+            ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);

+            break;

+        }

+    }

+}

diff --git a/common.h b/common.h
new file mode 100755
index 0000000..5cfa92a
--- /dev/null
+++ b/common.h
@@ -0,0 +1,163 @@
+

+#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

+

+/*

+ 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,

+

+    /* This is reserved for future usage */

+

+} ANDROID_VENDOR_SUB_COMMAND;

+

+typedef enum {

+    SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,

+    SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS,

+    SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN,

+    SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN,

+    SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS,

+    SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST,

+    SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST,

+    SLSI_NL80211_VENDOR_SUBCMD_GET_HOTLIST_RESULTS,

+    SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE,

+    SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE,

+    SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI,

+    SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS

+} WIFI_SUB_COMMAND;

+

+typedef enum {

+    GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,

+    GSCAN_EVENT_HOTLIST_RESULTS_FOUND,

+    GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,

+    GSCAN_EVENT_FULL_SCAN_RESULTS,

+    GSCAN_EVENT_COMPLETE_SCAN,

+    GSCAN_EVENT_HOTLIST_RESULTS_LOST

+} WIFI_EVENT;

+

+typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);

+

+class WifiCommand;

+

+typedef struct {

+    int nl_cmd;

+    uint32_t vendor_id;

+    int vendor_subcmd;

+    nl_recvmsg_msg_cb_t cb_func;

+    void *cb_arg;

+} cb_info;

+

+typedef struct {

+    wifi_request_id id;

+    WifiCommand *cmd;

+} cmd_info;

+

+typedef struct {

+    wifi_handle handle;                             // handle to wifi data

+    char name[8+1];                                 // interface name + trailing null

+    int  id;                                        // id to use when talking to driver

+} interface_info;

+

+typedef struct {

+

+    struct nl_sock *cmd_sock;                       // command socket object

+    struct nl_sock *event_sock;                     // event socket object

+    int nl80211_family_id;                          // family id for 80211 driver

+

+    bool in_event_loop;                             // Indicates that event loop is active

+    bool clean_up;                                  // Indication to clean up the socket

+

+    wifi_internal_event_handler event_handler;      // default event handler

+    wifi_cleaned_up_handler cleaned_up_handler;     // socket cleaned up handler

+

+    cb_info *event_cb;                              // event callbacks

+    int num_event_cb;                               // number of event callbacks

+    int alloc_event_cb;                             // number of allocated callback objects

+    pthread_mutex_t cb_lock;                        // mutex for the event_cb access

+

+    cmd_info *cmd;                                  // Outstanding commands

+    int num_cmd;                                    // number of commands

+    int alloc_cmd;                                  // number of commands allocated

+

+    interface_info **interfaces;                    // array of interfaces

+    int num_interfaces;                             // number of interfaces

+

+

+    // add other details

+} hal_info;

+

+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);

+wifi_error wifi_register_vendor_handler(wifi_handle handle,

+            uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);

+

+void wifi_unregister_handler(wifi_handle handle, int cmd);

+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);

+

+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);

+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);

+WifiCommand *wifi_get_cmd(wifi_handle handle, int id);

+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);

+

+interface_info *getIfaceInfo(wifi_interface_handle);

+wifi_handle getWifiHandle(wifi_interface_handle handle);

+hal_info *getHalInfo(wifi_handle handle);

+hal_info *getHalInfo(wifi_interface_handle handle);

+wifi_handle getWifiHandle(hal_info *info);

+wifi_interface_handle getIfaceHandle(interface_info *info);

+

+

+// some common macros

+

+#define min(x, y)       ((x) < (y) ? (x) : (y))

+#define max(x, y)       ((x) > (y) ? (x) : (y))

+

+#endif

+

diff --git a/cpp_bindings.cpp b/cpp_bindings.cpp
new file mode 100755
index 0000000..bcfebca
--- /dev/null
+++ b/cpp_bindings.cpp
@@ -0,0 +1,706 @@
+

+#include <stdint.h>

+#include <fcntl.h>

+#include <sys/socket.h>

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

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

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

+#include <linux/rtnetlink.h>

+#include <netpacket/packet.h>

+#include <linux/filter.h>

+#include <linux/errqueue.h>

+

+#include <linux/pkt_sched.h>

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

+#include <netlink/netlink.h>

+#include <netlink/socket.h>

+#include <netlink/handlers.h>

+#include <stdarg.h>

+

+#include <ctype.h>

+

+#include "wifi_hal.h"

+#include "common.h"

+#include "cpp_bindings.h"

+

+void appendFmt(char *buf, int &offset, const char *fmt, ...)

+{

+    va_list params;

+    va_start(params, fmt);

+    offset += vsprintf(buf + offset, fmt, params);

+    va_end(params);

+}

+

+#define C2S(x)  case x: return #x;

+

+static const char *cmdToString(int cmd)

+{

+	switch (cmd) {

+	C2S(NL80211_CMD_UNSPEC)

+	C2S(NL80211_CMD_GET_WIPHY)

+	C2S(NL80211_CMD_SET_WIPHY)

+	C2S(NL80211_CMD_NEW_WIPHY)

+	C2S(NL80211_CMD_DEL_WIPHY)

+	C2S(NL80211_CMD_GET_INTERFACE)

+	C2S(NL80211_CMD_SET_INTERFACE)

+	C2S(NL80211_CMD_NEW_INTERFACE)

+	C2S(NL80211_CMD_DEL_INTERFACE)

+	C2S(NL80211_CMD_GET_KEY)

+	C2S(NL80211_CMD_SET_KEY)

+	C2S(NL80211_CMD_NEW_KEY)

+	C2S(NL80211_CMD_DEL_KEY)

+	C2S(NL80211_CMD_GET_BEACON)

+	C2S(NL80211_CMD_SET_BEACON)

+	C2S(NL80211_CMD_START_AP)

+	C2S(NL80211_CMD_STOP_AP)

+	C2S(NL80211_CMD_GET_STATION)

+	C2S(NL80211_CMD_SET_STATION)

+	C2S(NL80211_CMD_NEW_STATION)

+	C2S(NL80211_CMD_DEL_STATION)

+	C2S(NL80211_CMD_GET_MPATH)

+	C2S(NL80211_CMD_SET_MPATH)

+	C2S(NL80211_CMD_NEW_MPATH)

+	C2S(NL80211_CMD_DEL_MPATH)

+	C2S(NL80211_CMD_SET_BSS)

+	C2S(NL80211_CMD_SET_REG)

+	C2S(NL80211_CMD_REQ_SET_REG)

+	C2S(NL80211_CMD_GET_MESH_CONFIG)

+	C2S(NL80211_CMD_SET_MESH_CONFIG)

+	C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)

+	C2S(NL80211_CMD_GET_REG)

+	C2S(NL80211_CMD_GET_SCAN)

+	C2S(NL80211_CMD_TRIGGER_SCAN)

+	C2S(NL80211_CMD_NEW_SCAN_RESULTS)

+	C2S(NL80211_CMD_SCAN_ABORTED)

+	C2S(NL80211_CMD_REG_CHANGE)

+	C2S(NL80211_CMD_AUTHENTICATE)

+	C2S(NL80211_CMD_ASSOCIATE)

+	C2S(NL80211_CMD_DEAUTHENTICATE)

+	C2S(NL80211_CMD_DISASSOCIATE)

+	C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)

+	C2S(NL80211_CMD_REG_BEACON_HINT)

+	C2S(NL80211_CMD_JOIN_IBSS)

+	C2S(NL80211_CMD_LEAVE_IBSS)

+	C2S(NL80211_CMD_TESTMODE)

+	C2S(NL80211_CMD_CONNECT)

+	C2S(NL80211_CMD_ROAM)

+	C2S(NL80211_CMD_DISCONNECT)

+	C2S(NL80211_CMD_SET_WIPHY_NETNS)

+	C2S(NL80211_CMD_GET_SURVEY)

+	C2S(NL80211_CMD_NEW_SURVEY_RESULTS)

+	C2S(NL80211_CMD_SET_PMKSA)

+	C2S(NL80211_CMD_DEL_PMKSA)

+	C2S(NL80211_CMD_FLUSH_PMKSA)

+	C2S(NL80211_CMD_REMAIN_ON_CHANNEL)

+	C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)

+	C2S(NL80211_CMD_SET_TX_BITRATE_MASK)

+	C2S(NL80211_CMD_REGISTER_FRAME)

+	C2S(NL80211_CMD_FRAME)

+	C2S(NL80211_CMD_FRAME_TX_STATUS)

+	C2S(NL80211_CMD_SET_POWER_SAVE)

+	C2S(NL80211_CMD_GET_POWER_SAVE)

+	C2S(NL80211_CMD_SET_CQM)

+	C2S(NL80211_CMD_NOTIFY_CQM)

+	C2S(NL80211_CMD_SET_CHANNEL)

+	C2S(NL80211_CMD_SET_WDS_PEER)

+	C2S(NL80211_CMD_FRAME_WAIT_CANCEL)

+	C2S(NL80211_CMD_JOIN_MESH)

+	C2S(NL80211_CMD_LEAVE_MESH)

+	C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)

+	C2S(NL80211_CMD_UNPROT_DISASSOCIATE)

+	C2S(NL80211_CMD_NEW_PEER_CANDIDATE)

+	C2S(NL80211_CMD_GET_WOWLAN)

+	C2S(NL80211_CMD_SET_WOWLAN)

+	C2S(NL80211_CMD_START_SCHED_SCAN)

+	C2S(NL80211_CMD_STOP_SCHED_SCAN)

+	C2S(NL80211_CMD_SCHED_SCAN_RESULTS)

+	C2S(NL80211_CMD_SCHED_SCAN_STOPPED)

+	C2S(NL80211_CMD_SET_REKEY_OFFLOAD)

+	C2S(NL80211_CMD_PMKSA_CANDIDATE)

+	C2S(NL80211_CMD_TDLS_OPER)

+	C2S(NL80211_CMD_TDLS_MGMT)

+	C2S(NL80211_CMD_UNEXPECTED_FRAME)

+	C2S(NL80211_CMD_PROBE_CLIENT)

+	C2S(NL80211_CMD_REGISTER_BEACONS)

+	C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)

+	C2S(NL80211_CMD_SET_NOACK_MAP)

+	C2S(NL80211_CMD_CH_SWITCH_NOTIFY)

+	C2S(NL80211_CMD_START_P2P_DEVICE)

+	C2S(NL80211_CMD_STOP_P2P_DEVICE)

+	C2S(NL80211_CMD_CONN_FAILED)

+	C2S(NL80211_CMD_SET_MCAST_RATE)

+	C2S(NL80211_CMD_SET_MAC_ACL)

+	C2S(NL80211_CMD_RADAR_DETECT)

+	C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)

+	C2S(NL80211_CMD_UPDATE_FT_IES)

+	C2S(NL80211_CMD_FT_EVENT)

+	C2S(NL80211_CMD_CRIT_PROTOCOL_START)

+	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)

+	C2S(NL80211_CMD_VENDOR)

+	default:

+		return "NL80211_CMD_UNKNOWN";

+	}

+}

+

+const char *attributeToString(int attribute)

+{

+    switch (attribute) {

+	C2S(NL80211_ATTR_UNSPEC)

+

+	C2S(NL80211_ATTR_WIPHY)

+	C2S(NL80211_ATTR_WIPHY_NAME)

+

+	C2S(NL80211_ATTR_IFINDEX)

+	C2S(NL80211_ATTR_IFNAME)

+	C2S(NL80211_ATTR_IFTYPE)

+

+	C2S(NL80211_ATTR_MAC)

+

+	C2S(NL80211_ATTR_KEY_DATA)

+	C2S(NL80211_ATTR_KEY_IDX)

+	C2S(NL80211_ATTR_KEY_CIPHER)

+	C2S(NL80211_ATTR_KEY_SEQ)

+	C2S(NL80211_ATTR_KEY_DEFAULT)

+

+	C2S(NL80211_ATTR_BEACON_INTERVAL)

+	C2S(NL80211_ATTR_DTIM_PERIOD)

+	C2S(NL80211_ATTR_BEACON_HEAD)

+	C2S(NL80211_ATTR_BEACON_TAIL)

+

+	C2S(NL80211_ATTR_STA_AID)

+	C2S(NL80211_ATTR_STA_FLAGS)

+	C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)

+	C2S(NL80211_ATTR_STA_SUPPORTED_RATES)

+	C2S(NL80211_ATTR_STA_VLAN)

+	C2S(NL80211_ATTR_STA_INFO)

+

+	C2S(NL80211_ATTR_WIPHY_BANDS)

+

+	C2S(NL80211_ATTR_MNTR_FLAGS)

+

+	C2S(NL80211_ATTR_MESH_ID)

+	C2S(NL80211_ATTR_STA_PLINK_ACTION)

+	C2S(NL80211_ATTR_MPATH_NEXT_HOP)

+	C2S(NL80211_ATTR_MPATH_INFO)

+

+	C2S(NL80211_ATTR_BSS_CTS_PROT)

+	C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)

+	C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)

+

+	C2S(NL80211_ATTR_HT_CAPABILITY)

+

+	C2S(NL80211_ATTR_SUPPORTED_IFTYPES)

+

+	C2S(NL80211_ATTR_REG_ALPHA2)

+	C2S(NL80211_ATTR_REG_RULES)

+

+	C2S(NL80211_ATTR_MESH_CONFIG)

+

+	C2S(NL80211_ATTR_BSS_BASIC_RATES)

+

+	C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)

+	C2S(NL80211_ATTR_WIPHY_FREQ)

+	C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)

+

+	C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)

+

+	C2S(NL80211_ATTR_MGMT_SUBTYPE)

+	C2S(NL80211_ATTR_IE)

+

+	C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)

+

+	C2S(NL80211_ATTR_SCAN_FREQUENCIES)

+	C2S(NL80211_ATTR_SCAN_SSIDS)

+	C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */

+	C2S(NL80211_ATTR_BSS)

+

+	C2S(NL80211_ATTR_REG_INITIATOR)

+	C2S(NL80211_ATTR_REG_TYPE)

+

+	C2S(NL80211_ATTR_SUPPORTED_COMMANDS)

+

+	C2S(NL80211_ATTR_FRAME)

+	C2S(NL80211_ATTR_SSID)

+	C2S(NL80211_ATTR_AUTH_TYPE)

+	C2S(NL80211_ATTR_REASON_CODE)

+

+	C2S(NL80211_ATTR_KEY_TYPE)

+

+	C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)

+	C2S(NL80211_ATTR_CIPHER_SUITES)

+

+	C2S(NL80211_ATTR_FREQ_BEFORE)

+	C2S(NL80211_ATTR_FREQ_AFTER)

+

+	C2S(NL80211_ATTR_FREQ_FIXED)

+

+

+	C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)

+	C2S(NL80211_ATTR_WIPHY_RETRY_LONG)

+	C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)

+	C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)

+

+	C2S(NL80211_ATTR_TIMED_OUT)

+

+	C2S(NL80211_ATTR_USE_MFP)

+

+	C2S(NL80211_ATTR_STA_FLAGS2)

+

+	C2S(NL80211_ATTR_CONTROL_PORT)

+

+	C2S(NL80211_ATTR_TESTDATA)

+

+	C2S(NL80211_ATTR_PRIVACY)

+

+	C2S(NL80211_ATTR_DISCONNECTED_BY_AP)

+	C2S(NL80211_ATTR_STATUS_CODE)

+

+	C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)

+	C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)

+	C2S(NL80211_ATTR_WPA_VERSIONS)

+	C2S(NL80211_ATTR_AKM_SUITES)

+

+	C2S(NL80211_ATTR_REQ_IE)

+	C2S(NL80211_ATTR_RESP_IE)

+

+	C2S(NL80211_ATTR_PREV_BSSID)

+

+	C2S(NL80211_ATTR_KEY)

+	C2S(NL80211_ATTR_KEYS)

+

+	C2S(NL80211_ATTR_PID)

+

+	C2S(NL80211_ATTR_4ADDR)

+

+	C2S(NL80211_ATTR_SURVEY_INFO)

+

+	C2S(NL80211_ATTR_PMKID)

+	C2S(NL80211_ATTR_MAX_NUM_PMKIDS)

+

+	C2S(NL80211_ATTR_DURATION)

+

+	C2S(NL80211_ATTR_COOKIE)

+

+	C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)

+

+	C2S(NL80211_ATTR_TX_RATES)

+

+	C2S(NL80211_ATTR_FRAME_MATCH)

+

+	C2S(NL80211_ATTR_ACK)

+

+	C2S(NL80211_ATTR_PS_STATE)

+

+	C2S(NL80211_ATTR_CQM)

+

+	C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)

+

+	C2S(NL80211_ATTR_AP_ISOLATE)

+

+	C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)

+	C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)

+

+	C2S(NL80211_ATTR_TX_FRAME_TYPES)

+	C2S(NL80211_ATTR_RX_FRAME_TYPES)

+	C2S(NL80211_ATTR_FRAME_TYPE)

+

+	C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)

+	C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)

+

+	C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)

+

+	C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)

+	C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)

+

+	C2S(NL80211_ATTR_MCAST_RATE)

+

+	C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)

+

+	C2S(NL80211_ATTR_BSS_HT_OPMODE)

+

+	C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)

+

+	C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)

+

+	C2S(NL80211_ATTR_MESH_SETUP)

+

+	C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)

+	C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)

+

+	C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)

+	C2S(NL80211_ATTR_STA_PLINK_STATE)

+

+	C2S(NL80211_ATTR_WOWLAN_TRIGGERS)

+	C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)

+

+	C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)

+

+	C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)

+	C2S(NL80211_ATTR_SOFTWARE_IFTYPES)

+

+	C2S(NL80211_ATTR_REKEY_DATA)

+

+	C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)

+	C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)

+

+	C2S(NL80211_ATTR_SCAN_SUPP_RATES)

+

+	C2S(NL80211_ATTR_HIDDEN_SSID)

+

+	C2S(NL80211_ATTR_IE_PROBE_RESP)

+	C2S(NL80211_ATTR_IE_ASSOC_RESP)

+

+	C2S(NL80211_ATTR_STA_WME)

+	C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)

+

+	C2S(NL80211_ATTR_ROAM_SUPPORT)

+

+	C2S(NL80211_ATTR_SCHED_SCAN_MATCH)

+	C2S(NL80211_ATTR_MAX_MATCH_SETS)

+

+	C2S(NL80211_ATTR_PMKSA_CANDIDATE)

+

+	C2S(NL80211_ATTR_TX_NO_CCK_RATE)

+

+	C2S(NL80211_ATTR_TDLS_ACTION)

+	C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)

+	C2S(NL80211_ATTR_TDLS_OPERATION)

+	C2S(NL80211_ATTR_TDLS_SUPPORT)

+	C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)

+

+	C2S(NL80211_ATTR_DEVICE_AP_SME)

+

+	C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)

+

+	C2S(NL80211_ATTR_FEATURE_FLAGS)

+

+	C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)

+

+	C2S(NL80211_ATTR_PROBE_RESP)

+

+	C2S(NL80211_ATTR_DFS_REGION)

+

+	C2S(NL80211_ATTR_DISABLE_HT)

+	C2S(NL80211_ATTR_HT_CAPABILITY_MASK)

+

+	C2S(NL80211_ATTR_NOACK_MAP)

+

+	C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)

+

+	C2S(NL80211_ATTR_RX_SIGNAL_DBM)

+

+	C2S(NL80211_ATTR_BG_SCAN_PERIOD)

+

+	C2S(NL80211_ATTR_WDEV)

+

+	C2S(NL80211_ATTR_USER_REG_HINT_TYPE)

+

+	C2S(NL80211_ATTR_CONN_FAILED_REASON)

+

+	C2S(NL80211_ATTR_SAE_DATA)

+

+	C2S(NL80211_ATTR_VHT_CAPABILITY)

+

+	C2S(NL80211_ATTR_SCAN_FLAGS)

+

+	C2S(NL80211_ATTR_CHANNEL_WIDTH)

+	C2S(NL80211_ATTR_CENTER_FREQ1)

+	C2S(NL80211_ATTR_CENTER_FREQ2)

+

+	C2S(NL80211_ATTR_P2P_CTWINDOW)

+	C2S(NL80211_ATTR_P2P_OPPPS)

+

+	C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)

+

+	C2S(NL80211_ATTR_ACL_POLICY)

+

+	C2S(NL80211_ATTR_MAC_ADDRS)

+

+	C2S(NL80211_ATTR_MAC_ACL_MAX)

+

+	C2S(NL80211_ATTR_RADAR_EVENT)

+

+	C2S(NL80211_ATTR_EXT_CAPA)

+	C2S(NL80211_ATTR_EXT_CAPA_MASK)

+

+	C2S(NL80211_ATTR_STA_CAPABILITY)

+	C2S(NL80211_ATTR_STA_EXT_CAPABILITY)

+

+	C2S(NL80211_ATTR_PROTOCOL_FEATURES)

+	C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)

+

+	C2S(NL80211_ATTR_DISABLE_VHT)

+	C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)

+

+	C2S(NL80211_ATTR_MDID)

+	C2S(NL80211_ATTR_IE_RIC)

+

+	C2S(NL80211_ATTR_CRIT_PROT_ID)

+	C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)

+

+	C2S(NL80211_ATTR_PEER_AID)

+

+

+	//S(NL80211_ATTR_VENDOR_ID)

+	C2S(NL80211_ATTR_VENDOR_SUBCMD)

+	C2S(NL80211_ATTR_VENDOR_DATA)

+	C2S(NL80211_ATTR_VENDOR_EVENTS)

+

+    default:

+        return "NL80211_ATTR_UNKNOWN";

+    }

+}

+

+void WifiEvent::log() {

+    parse();

+

+    byte *data = (byte *)genlmsg_attrdata(mHeader, 0);

+    int len = genlmsg_attrlen(mHeader, 0);

+    ALOGD("cmd = %s, len = %d", get_cmdString(), len);

+    ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());

+

+    for (int i = 0; i < len; i += 16) {

+        char line[81];

+        int linelen = min(16, len - i);

+        int offset = 0;

+        appendFmt(line, offset, "%02x", data[i]);

+        for (int j = 1; j < linelen; j++) {

+            appendFmt(line, offset, " %02x", data[i+j]);

+        }

+

+        for (int j = linelen; j < 16; j++) {

+            appendFmt(line, offset, "   ");

+        }

+

+        line[23] = '-';

+

+        appendFmt(line, offset, "  ");

+

+        for (int j = 0; j < linelen; j++) {

+            if (isprint(data[i+j])) {

+                appendFmt(line, offset, "%c", data[i+j]);

+            } else {

+                appendFmt(line, offset, "-");

+            }

+        }

+

+        ALOGD("%s", line);

+    }

+

+    for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {

+        if (mAttributes[i] != NULL) {

+            ALOGD("found attribute %s", attributeToString(i));

+        }

+    }

+

+    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) {

+    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/cpp_bindings.h b/cpp_bindings.h
new file mode 100755
index 0000000..65f0f4e
--- /dev/null
+++ b/cpp_bindings.h
@@ -0,0 +1,346 @@
+

+#include "wifi_hal.h"

+#include "common.h"

+#include "sync.h"

+

+class WifiEvent

+{

+    /* TODO: remove this when nl headers are updated */

+    static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;

+private:

+    struct nl_msg *mMsg;

+    struct genlmsghdr *mHeader;

+    struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];

+

+public:

+    WifiEvent(nl_msg *msg) {

+        mMsg = msg;

+        mHeader = NULL;

+        memset(mAttributes, 0, sizeof(mAttributes));

+    }

+    ~WifiEvent() {

+        /* don't destroy mMsg; it doesn't belong to us */

+    }

+

+    void log();

+

+    int parse();

+

+    genlmsghdr *header() {

+        return mHeader;

+    }

+

+    int get_cmd() {

+        return mHeader->cmd;

+    }

+

+    int get_vendor_id() {

+        return get_u32(NL80211_ATTR_VENDOR_ID);

+    }

+

+    int get_vendor_subcmd() {

+        return get_u32(NL80211_ATTR_VENDOR_SUBCMD);

+    }

+

+    void *get_vendor_data() {

+        return get_data(NL80211_ATTR_VENDOR_DATA);

+    }

+

+    int get_vendor_data_len() {

+        return get_len(NL80211_ATTR_VENDOR_DATA);

+    }

+

+    const char *get_cmdString();

+

+    nlattr ** attributes() {

+        return mAttributes;

+    }

+

+    nlattr *get_attribute(int attribute) {

+        return mAttributes[attribute];

+    }

+

+    uint8_t get_u8(int attribute) {

+        return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;

+    }

+

+    uint16_t get_u16(int attribute) {

+        return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;

+    }

+

+    uint32_t get_u32(int attribute) {

+        return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;

+    }

+

+    uint64_t get_u64(int attribute) {

+        return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;

+    }

+

+    int get_len(int attribute) {

+        return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;

+    }

+

+    void *get_data(int attribute) {

+        return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;

+    }

+

+private:

+    WifiEvent(const WifiEvent&);        // hide copy constructor to prevent copies

+};

+

+class nl_iterator {

+    struct nlattr *pos;

+    int rem;

+public:

+    nl_iterator(struct nlattr *attr) {

+        pos = (struct nlattr *)nla_data(attr);

+        rem = nla_len(attr);

+    }

+    bool has_next() {

+        return nla_ok(pos, rem);

+    }

+    void next() {

+        pos = (struct nlattr *)nla_next(pos, &(rem));

+    }

+    struct nlattr *get() {

+        return pos;

+    }

+    uint16_t get_type() {

+        return pos->nla_type;

+    }

+    uint8_t get_u8() {

+        return nla_get_u8(pos);

+    }

+    uint16_t get_u16() {

+        return nla_get_u16(pos);

+    }

+    uint32_t get_u32() {

+        return nla_get_u32(pos);

+    }

+    uint64_t get_u64() {

+        return nla_get_u64(pos);

+    }

+    void* get_data() {

+        return nla_data(pos);

+    }

+    int get_len() {

+        return nla_len(pos);

+    }

+private:

+    nl_iterator(const nl_iterator&);    // hide copy constructor to prevent copies

+};

+

+class WifiRequest

+{

+private:

+    int mFamily;

+    int mIface;

+    struct nl_msg *mMsg;

+

+public:

+    WifiRequest(int family) {

+        mMsg = NULL;

+        mFamily = family;

+        mIface = -1;

+    }

+

+    WifiRequest(int family, int iface) {

+        mMsg = NULL;

+        mFamily = family;

+        mIface = iface;

+    }

+

+    ~WifiRequest() {

+        destroy();

+    }

+

+    void destroy() {

+        if (mMsg) {

+            nlmsg_free(mMsg);

+            mMsg = NULL;

+        }

+    }

+

+    nl_msg *getMessage() {

+        return mMsg;

+    }

+

+    /* Command assembly helpers */

+    int create(int family, uint8_t cmd, int flags, int hdrlen);

+    int create(uint8_t cmd) {

+        return create(mFamily, cmd, 0, 0);

+    }

+

+    int create(uint32_t id, int subcmd);

+

+    int put(int attribute, void *ptr, unsigned len) {

+        return nla_put(mMsg, attribute, len, ptr);

+    }

+    int put_u8(int attribute, uint8_t value) {

+        return nla_put(mMsg, attribute, sizeof(value), &value);

+    }

+    int put_u16(int attribute, uint16_t value) {

+        return nla_put(mMsg, attribute, sizeof(value), &value);

+    }

+    int put_u32(int attribute, uint32_t value) {

+        return nla_put(mMsg, attribute, sizeof(value), &value);

+    }

+    int put_u64(int attribute, uint64_t value) {

+        return nla_put(mMsg, attribute, sizeof(value), &value);

+    }

+    int put_string(int attribute, const char *value) {

+        return nla_put(mMsg, attribute, strlen(value) + 1, value);

+    }

+    int put_addr(int attribute, mac_addr value) {

+        return nla_put(mMsg, attribute, sizeof(mac_addr), value);

+    }

+

+    struct nlattr * attr_start(int attribute) {

+        return nla_nest_start(mMsg, attribute);

+    }

+    void attr_end(struct nlattr *attr) {

+        nla_nest_end(mMsg, attr);

+    }

+

+    int set_iface_id(int ifindex) {

+        return put_u32(NL80211_ATTR_IFINDEX, ifindex);

+    }

+private:

+    WifiRequest(const WifiRequest&);        // hide copy constructor to prevent copies

+

+};

+

+class WifiCommand

+{

+protected:

+    hal_info *mInfo;

+    WifiRequest mMsg;

+    Condition mCondition;

+    wifi_request_id mId;

+    interface_info *mIfaceInfo;

+    int mRefs;

+public:

+    WifiCommand(wifi_handle handle, wifi_request_id id)

+            : mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)

+    {

+        mIfaceInfo = NULL;

+        mInfo = getHalInfo(handle);

+        // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);

+    }

+

+    WifiCommand(wifi_interface_handle iface, wifi_request_id id)

+            : mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id), mId(id), mRefs(1)

+    {

+        mIfaceInfo = getIfaceInfo(iface);

+        mInfo = getHalInfo(iface);

+        // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);

+    }

+

+    virtual ~WifiCommand() {

+        // ALOGD("WifiCommand %p destroyed", this);

+    }

+

+    wifi_request_id id() {

+        return mId;

+    }

+

+    virtual void addRef() {

+        int refs = __sync_add_and_fetch(&mRefs, 1);

+        // ALOGD("addRef: WifiCommand %p has %d references", this, refs);

+    }

+

+    virtual void releaseRef() {

+        int refs = __sync_sub_and_fetch(&mRefs, 1);

+        if (refs == 0) {

+            delete this;

+        } else {

+            // ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);

+        }

+    }

+

+    virtual int create() {

+        /* by default there is no way to cancel */

+        ALOGD("WifiCommand %p can't be created", this);

+        return WIFI_ERROR_NOT_SUPPORTED;

+    }

+

+    virtual int cancel() {

+        /* by default there is no way to cancel */

+        return WIFI_ERROR_NOT_SUPPORTED;

+    }

+

+    int requestResponse();

+    int requestEvent(int cmd);

+    int requestVendorEvent(uint32_t id, int subcmd);

+    int requestResponse(WifiRequest& request);

+

+protected:

+    wifi_handle wifiHandle() {

+        return getWifiHandle(mInfo);

+    }

+

+    wifi_interface_handle ifaceHandle() {

+        return getIfaceHandle(mIfaceInfo);

+    }

+

+    int familyId() {

+        return mInfo->nl80211_family_id;

+    }

+

+    int ifaceId() {

+        return mIfaceInfo->id;

+    }

+

+    /* Override this method to parse reply and dig out data; save it in the object */

+    virtual int handleResponse(WifiEvent& reply) {

+        ALOGI("skipping a response");

+        return NL_SKIP;

+    }

+

+    /* Override this method to parse event and dig out data; save it in the object */

+    virtual int handleEvent(WifiEvent& event) {

+        ALOGI("skipping an event");

+        return NL_SKIP;

+    }

+

+    int registerHandler(int cmd) {

+        return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);

+    }

+

+    void unregisterHandler(int cmd) {

+        wifi_unregister_handler(wifiHandle(), cmd);

+    }

+

+    int registerVendorHandler(uint32_t id, int subcmd) {

+        return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);

+    }

+

+    void unregisterVendorHandler(uint32_t id, int subcmd) {

+        wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);

+    }

+

+private:

+    WifiCommand(const WifiCommand& );           // hide copy constructor to prevent copies

+

+    /* Event handling */

+    static int response_handler(struct nl_msg *msg, void *arg);

+

+    static int event_handler(struct nl_msg *msg, void *arg);

+

+    /* Other event handlers */

+    static int valid_handler(struct nl_msg *msg, void *arg);

+

+    static int ack_handler(struct nl_msg *msg, void *arg);

+

+    static int finish_handler(struct nl_msg *msg, void *arg);

+

+    static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);

+};

+

+/* nl message processing macros (required to pass C++ type checks) */

+

+#define for_each_attr(pos, nla, rem) \

+    for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \

+        nla_ok(pos, rem); \

+        pos = (nlattr *)nla_next(pos, &(rem)))

+

diff --git a/gscan.cpp b/gscan.cpp
new file mode 100755
index 0000000..4c6eccc
--- /dev/null
+++ b/gscan.cpp
@@ -0,0 +1,1096 @@
+

+#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"

+

+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_DWELL_TIME,

+    GSCAN_ATTRIBUTE_SCAN_TYPE,

+    GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,

+

+    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,

+    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */

+    GSCAN_ENABLE_FULL_SCAN_RESULTS,

+    GSCAN_ATTRIBUTE_REPORT_EVENTS,

+

+    /* remaining reserved for additional attributes */

+    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,

+    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */

+    GSCAN_ATTRIBUTE_NUM_CHANNELS,

+    GSCAN_ATTRIBUTE_CHANNEL_LIST,

+

+    /* remaining reserved for additional attributes */

+

+    GSCAN_ATTRIBUTE_SSID = 40,

+    GSCAN_ATTRIBUTE_BSSID,

+    GSCAN_ATTRIBUTE_CHANNEL,

+    GSCAN_ATTRIBUTE_RSSI,

+    GSCAN_ATTRIBUTE_TIMESTAMP,

+    GSCAN_ATTRIBUTE_RTT,

+    GSCAN_ATTRIBUTE_RTTSD,

+

+    /* remaining reserved for additional attributes */

+

+    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,

+    GSCAN_ATTRIBUTE_RSSI_LOW,

+    GSCAN_ATTRIBUTE_RSSI_HIGH,

+    GSCAN_ATTRIBUTE_HOTLIST_ELEM,

+    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,

+    GSCAN_ATTRIBUTE_CHANNEL_NUMBER,

+

+    /* remaining reserved for additional attributes */

+    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,

+    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,

+    GSCAN_ATTRIBUTE_MIN_BREACHING,

+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,

+

+    GSCAN_ATTRIBUTE_MAX

+

+} GSCAN_ATTRIBUTE;

+

+

+class GetCapabilitiesCommand : public WifiCommand

+{

+    wifi_gscan_capabilities *mCapabilities;

+public:

+    GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)

+        : WifiCommand(iface, 0), mCapabilities(capabitlites)

+    {

+        memset(mCapabilities, 0, sizeof(*mCapabilities));

+    }

+

+    virtual int create() {

+        ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);

+

+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES);

+        if (ret < 0) {

+	    ALOGD("NL message creation failed");

+            return ret;

+        }

+

+        return ret;

+    }

+

+protected:

+    virtual int handleResponse(WifiEvent& reply) {

+

+        ALOGD("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();

+

+        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;

+    }

+};

+

+

+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,

+        wifi_gscan_capabilities *capabilities)

+{

+    GetCapabilitiesCommand command(handle, capabilities);

+    return (wifi_error) command.requestResponse();

+}

+

+class GetChannelListCommand : public WifiCommand

+{

+    wifi_channel *channels;

+    int max_channels;

+    int *num_channels;

+    int band;

+public:

+    GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,

+        int num_max_ch, int band)

+        : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),

+        band(band)

+    {

+        memset(channels, 0, sizeof(wifi_channel) * max_channels);

+    }

+    virtual int create() {

+        ALOGD("Creating message to get channel list; iface = %d", mIfaceInfo->id);

+

+        int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS);

+        if (ret < 0) {

+            return ret;

+        }

+

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

+        ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);

+        if (ret < 0) {

+            return ret;

+        }

+

+        mMsg.attr_end(data);

+

+        return ret;

+    }

+

+protected:

+    virtual int handleResponse(WifiEvent& reply) {

+

+        ALOGD("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();

+

+        ALOGD("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();

+                ALOGD("Got channel list with %d channels", num_channels_to_copy);

+                if(num_channels_to_copy > max_channels)

+                    num_channels_to_copy = max_channels;

+                *num_channels = num_channels_to_copy;

+            } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {

+                memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);

+            } else {

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

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

+            }

+        }

+

+        return NL_OK;

+    }

+};

+

+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,

+        int band, int max_channels, wifi_channel *channels, int *num_channels)

+{

+    GetChannelListCommand command(handle, channels, num_channels,

+                                        max_channels, band);

+    return (wifi_error) command.requestResponse();

+}

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

+

+/* helper functions */

+

+static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)

+{

+    memset(results, 0, sizeof(wifi_scan_result) * num);

+

+    int i = 0;

+    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {

+

+        int index = it.get_type();

+        ALOGD("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 result = request.create(GOOGLE_OUI, subcmd);

+    if (result < 0) {

+        return result;

+    }

+

+    return WIFI_SUCCESS;

+}

+

+class ScanCommand : public WifiCommand

+{

+    wifi_scan_cmd_params *mParams;

+    wifi_scan_result_handler mHandler;

+    static unsigned mGlobalFullScanBuckets;

+    bool mLocalFullScanBuckets;

+public:

+    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,

+                wifi_scan_result_handler handler)

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

+          mLocalFullScanBuckets(0)

+    { }

+

+    int createSetupRequest(WifiRequest& request) {

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

+        if (result < 0) {

+            return result;

+        }

+

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

+        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);

+        if (result < 0) {

+            return result;

+        }

+

+	result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);

+        if (result < 0) {

+            return result;

+        }

+

+        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold);

+        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_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);

+                for (int j = 0; j < mParams->buckets[i].num_channels; j++) {

+                    result = request.put_u32(j, mParams->buckets[i].channels[j].channel);

+                    if (result < 0) {

+                        return result;

+                    }

+                }

+                request.attr_end(channels);

+            }

+

+            request.attr_end(bucket);

+        }

+

+        request.attr_end(data);

+        return WIFI_SUCCESS;

+    }

+

+    int createStartRequest(WifiRequest& request) {

+        return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);

+    }

+

+    int createStopRequest(WifiRequest& request) {

+        return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);

+    }

+

+    int enableFullScanResultsIfRequired() {

+        /* temporary workaround till we have full support for per bucket scans */

+

+        ALOGI("enabling full scan results if needed");

+        int nBuckets = 0;

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

+            if (mParams->buckets[i].report_events == 2) {

+                nBuckets++;

+            }

+        }

+

+        if (mGlobalFullScanBuckets == 0 && nBuckets != 0) {

+            

+           ALOGI("full scan results were requested ");

+           ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);

+		    mLocalFullScanBuckets = nBuckets;

+        mGlobalFullScanBuckets += nBuckets;

+		registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);

+

+        } else {

+            ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);

+

+        }

+

+        return WIFI_SUCCESS;       

+    }

+    int disableFullScanResultsIfRequired() {

+        /* temporary workaround till we have full support for per bucket scans */

+

+        if (mLocalFullScanBuckets == 0) {

+            return WIFI_SUCCESS;

+        }

+

+        mGlobalFullScanBuckets -= mLocalFullScanBuckets;

+        if (mGlobalFullScanBuckets == 0) {

+            

+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);

+        }

+

+        return WIFI_SUCCESS;

+    }

+    int start() {

+        ALOGD(" sending scan req to driver");

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

+        int result = createSetupRequest(request);

+        if (result != WIFI_SUCCESS) {

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

+            return result;

+        }

+        ALOGD("Starting scan");

+

+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);

+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);

+        result = enableFullScanResultsIfRequired();

+		if ( result == WIFI_SUCCESS)

+		{

+		   

+		}

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("failed to start scan; result = %d", result);

+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);

+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);

+            return result;

+        }

+

+      

+        return result;

+    }

+

+    virtual int cancel() {

+        ALOGD("Stopping 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);

+        disableFullScanResultsIfRequired();

+

+        return WIFI_SUCCESS;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        /* Nothing to do on response! */

+        return NL_SKIP;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        ALOGD("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) {

+            if (vendor_data == NULL || len != 4) {

+                ALOGD("Scan complete type not mentioned!");

+                return NL_SKIP;

+            }

+            wifi_scan_event evt_type;

+

+            evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);

+            ALOGD("Scan complete: Received event type %d", evt_type);

+            if(*mHandler.on_scan_event)

+                (*mHandler.on_scan_event)(evt_type, evt_type);

+        } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {

+	    if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {

+	        ALOGD("No scan results found");

+	        return NL_SKIP;

+	    }

+	    wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();

+

+	    if(*mHandler.on_full_scan_result)

+	        (*mHandler.on_full_scan_result)(id(), result);

+

+	    ALOGD("%-32s\t", result->ssid);

+

+	    ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],

+	            result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);

+

+	    ALOGD("%d\t", result->rssi);

+	    ALOGD("%d\t", result->channel);

+	    ALOGD("%lld\t", result->ts);

+	    ALOGD("%lld\t", result->rtt);

+	    ALOGD("%lld\n", result->rtt_sd);

+        } else {

+

+            if (vendor_data == NULL || len != 4) {

+                ALOGD("No scan results found");

+                return NL_SKIP;

+            }

+

+            int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);

+            ALOGD("Found %d scan results", num);

+            if(*mHandler.on_scan_results_available)

+                (*mHandler.on_scan_results_available)(id(), num);

+        }

+        return NL_SKIP;

+    }

+};

+

+unsigned ScanCommand::mGlobalFullScanBuckets = 0;

+

+wifi_error wifi_start_gscan(

+        wifi_request_id id,

+        wifi_interface_handle iface,

+        wifi_scan_cmd_params params,

+        wifi_scan_result_handler handler)

+{

+    wifi_handle handle = getWifiHandle(iface);

+

+    ALOGD("Starting GScan, halHandle = %p", handle);

+

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

+    wifi_register_cmd(handle, id, cmd);

+    return (wifi_error)cmd->start();

+}

+

+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)

+{

+    ALOGD("Stopping GScan");

+    wifi_handle handle = getWifiHandle(iface);

+

+    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);

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+

+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);

+    if (cmd) {

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+    return WIFI_ERROR_INVALID_ARGS;

+}

+

+class GetScanResultsCommand : public WifiCommand {

+    wifi_scan_result *mResults;

+    int mMax;

+    int *mNum;

+    int mRetrieved;

+    byte mFlush;

+    int mCompleted;

+public:

+    GetScanResultsCommand(wifi_interface_handle iface, byte flush,

+            wifi_scan_result *results, int max, int *num)

+        : WifiCommand(iface, -1), mResults(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, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);

+        if (result < 0) {

+            return result;

+        }

+

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

+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);

+        if (result < 0) {

+            return result;

+        }

+

+        request.attr_end(data);

+        return WIFI_SUCCESS;

+    }

+

+    int execute() {

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

+        ALOGD("retrieving %d scan results", mMax);

+

+        for (int i = 0; i < 10 && mRetrieved < mMax; i++) {

+            int result = createRequest(request, (mMax - mRetrieved), mFlush);

+            if (result < 0) {

+                ALOGE("failed to create request");

+                return result;

+            }

+

+            int prev_retrieved = mRetrieved;

+

+            result = requestResponse(request);

+

+            if (result != WIFI_SUCCESS) {

+                ALOGE("failed to retrieve scan results; result = %d", result);

+                return result;

+            }

+

+            if (mRetrieved == prev_retrieved || mCompleted) {

+                /* no more items left to retrieve */

+                break;

+            }

+

+            request.destroy();

+        }

+

+        ALOGE("GetScanResults read %d results", mRetrieved);

+        *mNum = mRetrieved;

+        return WIFI_SUCCESS;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        ALOGD("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();

+

+        ALOGD("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();

+                ALOGD("retrieved mCompleted flag : %d", mCompleted);

+            } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {

+                for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {

+                    int num = 0;

+                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {

+                        num = it2.get_len() / sizeof(wifi_scan_result);

+                        num = min(*mNum - mRetrieved, num);

+                        memcpy(mResults + mRetrieved, it2.get_data(),

+                                sizeof(wifi_scan_result) * num);

+                        ALOGD("Retrieved %d scan results", num);

+                        wifi_scan_result *results = (wifi_scan_result *)it2.get_data();

+                        for (int i = 0; i < num; i++) {

+                            wifi_scan_result *result = results + i;

+                            ALOGD("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x  %04d", i,

+                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],

+                                result->bssid[3], result->bssid[4], result->bssid[5],

+                                result->rssi);

+                        }

+                        mRetrieved += num;

+                    } else {

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

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

+                    }

+                }

+            } else {

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

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

+            }

+        }

+

+        return NL_OK;

+    }

+};

+

+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,

+        int max, wifi_scan_result *results, int *num) {

+

+    ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);

+

+    GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);

+    return (wifi_error)cmd->execute();

+}

+

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

+

+class BssidHotlistCommand : public WifiCommand

+{

+private:

+    wifi_bssid_hotlist_params mParams;

+    wifi_hotlist_ap_found_handler mHandler;

+    static const int MAX_RESULTS = 64;

+    wifi_scan_result mResults[MAX_RESULTS];

+public:

+    BssidHotlistCommand(wifi_interface_handle handle, int id,

+            wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)

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

+    { }

+

+    int createSetupRequest(WifiRequest& request) {

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

+        if (result < 0) {

+            return result;

+        }

+

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

+

+        result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);

+        if (result < 0) {

+            return result;

+        }

+

+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);

+        for (int i = 0; i < mParams.num_ap; 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;

+            }

+            result = request.put_u8(GSCAN_ATTRIBUTE_CHANNEL_NUMBER, mParams.ap[i].channel);

+            if (result < 0) {

+                return result;

+            }

+            request.attr_end(attr2);

+        }

+

+        request.attr_end(attr);

+        request.attr_end(data);

+        return result;

+    }

+

+    int createTeardownRequest(WifiRequest& request) {

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

+        if (result < 0) {

+            return result;

+        }

+

+        return result;

+    }

+

+    int start() {

+        ALOGD("Executing hotlist setup request, num = %d", mParams.num_ap);

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

+        int result = createSetupRequest(request);

+        if (result < 0) {

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result < 0) {

+            ALOGD("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;

+        }

+

+        ALOGD("Successfully set %d APs in the hotlist", mParams.num_ap);

+        result = createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);

+        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;

+        }

+

+        ALOGD("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;

+        }

+

+        ALOGD("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) {

+        ALOGD("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) {

+            ALOGD("No scan results found");

+            return NL_SKIP;

+        }

+

+        memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);

+

+        int num = len / sizeof(wifi_scan_result);

+        num = min(MAX_RESULTS, num);

+        memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));

+

+        if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {

+            ALOGD("FOUND %d hotlist APs", num);

+            if (*mHandler.on_hotlist_ap_found)

+                (*mHandler.on_hotlist_ap_found)(id(), num, mResults);

+        } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {

+            ALOGD("LOST %d hotlist APs", num);

+            if (*mHandler.on_hotlist_ap_lost)

+                (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);

+        }

+        return NL_SKIP;

+    }

+};

+

+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,

+        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)

+{

+    wifi_handle handle = getWifiHandle(iface);

+

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

+    wifi_register_cmd(handle, id, cmd);

+    return (wifi_error)cmd->start();

+}

+

+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)

+{

+    wifi_handle handle = getWifiHandle(iface);

+

+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);

+    if (cmd) {

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+    return WIFI_ERROR_INVALID_ARGS;

+}

+

+

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

+

+class SignificantWifiChangeCommand : public WifiCommand

+{

+    typedef struct {

+        mac_addr bssid;                     // BSSID

+        wifi_channel channel;               // channel frequency in MHz

+        int num_rssi;                       // number of rssi samples

+        wifi_rssi rssi[8];                   // RSSI history in db

+    } wifi_significant_change_result_internal;

+

+private:

+    wifi_significant_change_params mParams;

+    wifi_significant_change_handler mHandler;

+    static const int MAX_RESULTS = 64;

+    wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];

+    wifi_significant_change_result *mResults[MAX_RESULTS];

+public:

+    SignificantWifiChangeCommand(wifi_interface_handle handle, int id,

+            wifi_significant_change_params params, wifi_significant_change_handler handler)

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

+    { }

+

+    int createSetupRequest(WifiRequest& request) {

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

+        if (result < 0) {

+            return result;

+        }

+

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

+

+        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);

+        if (result < 0) {

+            return result;

+        }

+        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);

+        if (result < 0) {

+            return result;

+        }

+        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);

+        if (result < 0) {

+            return result;

+        }

+

+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);

+

+        for (int i = 0; i < mParams.num_ap; i++) {

+

+            nlattr *attr2 = request.attr_start(i);

+            if (attr2 == NULL) {

+                return WIFI_ERROR_OUT_OF_MEMORY;

+            }

+            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);

+            if (result < 0) {

+                return result;

+            }

+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);

+            if (result < 0) {

+                return result;

+            }

+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);

+            if (result < 0) {

+                return result;

+            }

+            request.attr_end(attr2);

+        }

+

+        request.attr_end(attr);

+        request.attr_end(data);

+

+        return result;

+    }

+

+    int createTeardownRequest(WifiRequest& request) {

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

+        if (result < 0) {

+            return result;

+        }

+

+        return result;

+    }

+

+    int start() {

+        ALOGD("Set significant wifi change");

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

+

+        int result = createSetupRequest(request);

+        if (result < 0) {

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result < 0) {

+            ALOGD("failed to set significant wifi change %d", result);

+            return result;

+        }

+

+        result = createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);

+        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;

+        }

+

+        ALOGD("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;

+        }

+

+        ALOGD("successfully reset significant wifi change");

+        return result;

+    }

+

+    virtual int handleResponse(WifiEvent& reply) {

+        /* Nothing to do on response! */

+        return NL_SKIP;

+    }

+

+    virtual int handleEvent(WifiEvent& event) {

+        ALOGD("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) {

+            ALOGD("No scan results found");

+            return NL_SKIP;

+        }

+

+        typedef struct {

+            uint16_t channel;

+            mac_addr bssid;

+            s16 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]));

+        }

+

+        ALOGD("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);

+    wifi_register_cmd(handle, id, cmd);

+    return (wifi_error)cmd->start();

+}

+

+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)

+{

+    wifi_handle handle = getWifiHandle(iface);

+

+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);

+    if (cmd) {

+        cmd->cancel();

+        cmd->releaseRef();

+        return WIFI_SUCCESS;

+    }

+

+    return WIFI_ERROR_INVALID_ARGS;

+}

diff --git a/link_layer_stats.cpp b/link_layer_stats.cpp
new file mode 100755
index 0000000..87406a8
--- /dev/null
+++ b/link_layer_stats.cpp
@@ -0,0 +1,31 @@
+#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"

+wifi_error wifi_get_link_stats(wifi_request_id id,

+        wifi_interface_handle iface, wifi_stats_result_handler handler)

+{

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

diff --git a/rtt.cpp b/rtt.cpp
new file mode 100755
index 0000000..ef92ae5
--- /dev/null
+++ b/rtt.cpp
@@ -0,0 +1,52 @@
+#include <stdint.h>

+#include <fcntl.h>

+#include <sys/socket.h>

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

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

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

+#include <linux/rtnetlink.h>

+#include <netpacket/packet.h>

+#include <linux/filter.h>

+#include <linux/errqueue.h>

+

+#include <linux/pkt_sched.h>

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

+#include <netlink/netlink.h>

+#include <netlink/socket.h>

+#include <netlink-types.h>

+

+#include "nl80211_copy.h"

+

+#include "sync.h"

+

+#define LOG_TAG  "WifiHAL"

+

+#include <utils/Log.h>

+

+#include "wifi_hal.h"

+#include "common.h"

+#include "cpp_bindings.h"

+/* 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)

+{

+    

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

+

+/* 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[])

+{

+

+

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

+

+/* API to get RTT capability */

+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,

+        wifi_rtt_capabilities *capabilities)

+{

+

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

diff --git a/sync.h b/sync.h
new file mode 100755
index 0000000..1dc0841
--- /dev/null
+++ b/sync.h
@@ -0,0 +1,54 @@
+

+#include <pthread.h>

+

+#ifndef __WIFI_HAL_SYNC_H__

+#define __WIFI_HAL_SYNC_H__

+

+class Mutex

+{

+private:

+    pthread_mutex_t mMutex;

+public:

+    Mutex() {

+        pthread_mutex_init(&mMutex, NULL);

+    }

+    ~Mutex() {

+        pthread_mutex_destroy(&mMutex);

+    }

+    int tryLock() {

+        return pthread_mutex_trylock(&mMutex);

+    }

+    int lock() {

+        return pthread_mutex_lock(&mMutex);

+    }

+    void unlock() {

+        pthread_mutex_unlock(&mMutex);

+    }

+};

+

+class Condition

+{

+private:

+    pthread_cond_t mCondition;

+    pthread_mutex_t mMutex;

+

+public:

+    Condition() {

+        pthread_mutex_init(&mMutex, NULL);

+        pthread_cond_init(&mCondition, NULL);

+    }

+    ~Condition() {

+        pthread_cond_destroy(&mCondition);

+        pthread_mutex_destroy(&mMutex);

+    }

+

+    int wait() {

+        return pthread_cond_wait(&mCondition, &mMutex);

+    }

+

+    void signal() {

+        pthread_cond_signal(&mCondition);

+    }

+};

+

+#endif
\ No newline at end of file
diff --git a/wifi_hal.cpp b/wifi_hal.cpp
new file mode 100755
index 0000000..ad7cf79
--- /dev/null
+++ b/wifi_hal.cpp
@@ -0,0 +1,639 @@
+#include <errno.h>

+#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/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"

+

+

+#define WIFI_HAL_CMD_SOCK_PORT       644

+#define WIFI_HAL_EVENT_SOCK_PORT     645

+

+#define FEATURE_SET                  0

+#define FEATURE_SET_MATRIX           1

+#define ATTR_NODFS_VALUE             3

+

+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);

+

+typedef enum wifi_attr {

+    ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,

+    ANDR_WIFI_ATTRIBUTE_FEATURE_SET,

+    ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI

+} wifi_attr_t;

+

+/* 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;

+}

+

+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");

+    struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);

+    if (cmd_sock == NULL) {

+        ALOGE("Could not create handle");

+        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);

+        return WIFI_ERROR_UNKNOWN;

+    }

+

+    struct nl_cb *cb = nl_socket_get_cb(event_sock);

+    if (cb == NULL) {

+        ALOGE("Could not create handle");

+        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;

+	    ALOGD("wifi_initialize, handle = %p\n", handle);

+	    ALOGD("wifi_initialize, *handle = %p\n", *handle);

+		ALOGD("wifi_initialize, info = %p\n", info);

+		ALOGD("wifi_initialize, *info = %pn", *info);

+    wifi_add_membership(*handle, "scan");

+    wifi_add_membership(*handle, "mlme");

+    wifi_add_membership(*handle, "regulatory");

+    wifi_add_membership(*handle, "vendor");

+

+    wifi_init_interfaces(*handle);

+     ALOGD("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) {

+        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);

+    info->cleaned_up_handler = handler;

+    info->clean_up = true;

+

+    ALOGI("Wifi cleanup completed");

+}

+

+static int internal_pollin_handler(wifi_handle handle)

+{

+    hal_info *info = getHalInfo(handle);

+		ALOGI("even_loop info = %p", info);

+    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);

+	ALOGI("even_loop info = %p", info);

+	ALOGI("even_loop info = %p", handle);

+    if (info->in_event_loop) {

+        return;

+    } else {

+        info->in_event_loop = true;

+    }

+

+    pollfd pfd;

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

+

+    pfd.fd = nl_socket_get_fd(info->event_sock);

+    pfd.events = POLLIN;

+

+    /* TODO: Add support for timeouts */

+

+    do {

+        int timeout = -1;                   /* Infinite timeout */

+        pfd.revents = 0;

+         ALOGI("Polling socket");

+        int result = poll(&pfd, 1, -1);

+        if (result < 0) {

+            ALOGE("Error polling socket");

+        } else if (pfd.revents & POLLERR) {

+            ALOGE("POLL Error; error no = %d", errno);

+            char buf[2048];

+            int result2 = read(pfd.fd, buf, sizeof(buf));

+            ALOGE("Read after POLL returned %d, error no = %d", result2, errno);

+        } else if (pfd.revents & POLLHUP) {

+            ALOGE("Remote side hung up");

+            break;

+        } else if (pfd.revents & POLLIN) {

+             ALOGI("Found some events!!!");

+            internal_pollin_handler(handle);

+        } else {

+            ALOGE("Unknown event - %0x", pfd.revents);

+        }

+    } while (!info->clean_up);

+

+

+    ALOGI("Cleaning up");

+    internal_cleaned_up_handler(handle);

+}

+

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

+

+static int internal_no_seq_check(struct nl_msg *msg, void *arg)

+{

+    return NL_OK;

+}

+

+static int internal_valid_message_handler(nl_msg *msg, void *arg)

+{

+    wifi_handle handle = (wifi_handle)arg;

+    hal_info *info = getHalInfo(handle);

+   ALOGI("even_loop info = %p", handle);

+   ALOGD("internal_valid_message_handler, info = %p", info);

+

+    WifiEvent event(msg);

+    int res = event.parse();

+    if (res < 0) {

+        ALOGE("Failed to parse event: %d", res);

+        return NL_SKIP;

+    }

+

+    int cmd = event.get_cmd();

+    uint32_t vendor_id = 0;

+    int subcmd = 0;

+

+    if (cmd == NL80211_CMD_VENDOR) {

+        vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);

+        subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);

+        ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",

+                event.get_cmdString(), vendor_id, subcmd);

+    } else {

+         ALOGI("event received %s", event.get_cmdString());

+    }

+

+     //ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);

+     //event.log();

+

+    bool dispatched = false;

+

+    pthread_mutex_lock(&info->cb_lock);

+    

+    ALOGI("Number of events %d", info->num_event_cb);

+

+    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);

+

+            (*cb_func)(msg, cb_arg);

+            if (cmd != NULL) {

+                cmd->releaseRef();

+            }

+

+            return NL_OK;

+        }

+    }

+

+    pthread_mutex_unlock(&info->cb_lock);

+    return NL_OK;

+}

+

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

+

+class GetMulticastIdCommand : public WifiCommand

+{

+private:

+    const char *mName;

+    const char *mGroup;

+    int   mId;

+public:

+    GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)

+        : WifiCommand(handle, 0)

+    {

+        mName = name;

+        mGroup = group;

+        mId = -1;

+    }

+

+    int getId() {

+        return mId;

+    }

+

+    virtual int create() {

+        int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");

+        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) {

+

+         ALOGE("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]) {

+            ALOGE("No multicast groups found");

+            return NL_SKIP;

+        } else {

+             ALOGE("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));

+        }

+

+        for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {

+

+             ALOGE("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]);

+

+             ALOGE("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(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, SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI, mOui);

+        if (result != WIFI_SUCCESS) {

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

+            return result;

+        }

+

+        result = requestResponse(request);

+        if (result != WIFI_SUCCESS) {

+            ALOGE("failed to set scanning mac OUI; result = %d", result);

+        }

+

+        return result;

+    }

+protected:

+    virtual int handleResponse(WifiEvent& reply) {

+         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(handle, 0) {

+        mNoDfs = nodfs;

+    }

+    virtual int create() {

+        int ret;

+

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

+        if (ret < 0) {

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

+            return ret;

+        }

+

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

+        ret = mMsg.put_u32(ATTR_NODFS_VALUE, mNoDfs);

+        if (ret < 0) {

+             return ret;

+        }

+

+        mMsg.attr_end(data);

+        return WIFI_SUCCESS;

+    }

+};

+

+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;

+	ALOGD("wifi_init_interfaces, info = %p", info);

+

+    struct dirent *de;

+

+    DIR *d = opendir("/sys/class/net");

+    if (d == 0)

+        return WIFI_ERROR_UNKNOWN;

+

+    int n = 0;

+    while ((de = readdir(d))) {

+        if (de->d_name[0] == '.')

+            continue;

+        if (is_wifi_interface(de->d_name) ) {

+            n++;

+        }

+    }

+

+    closedir(d);

+

+    d = opendir("/sys/class/net");

+    if (d == 0)

+        return WIFI_ERROR_UNKNOWN;

+

+    info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);

+

+    int i = 0;

+    while ((de = readdir(d))) {

+        if (de->d_name[0] == '.')

+            continue;

+        if (is_wifi_interface(de->d_name)) {

+            interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));

+            if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {

+                free(ifinfo);

+                continue;

+            }

+            ifinfo->handle = handle;

+            info->interfaces[i] = ifinfo;

+            i++;

+        }

+    }

+

+    closedir(d);

+

+    info->num_interfaces = n;

+    return WIFI_SUCCESS;

+}

+

+wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)

+{

+    hal_info *info = (hal_info *)handle;

+

+    *interfaces = (wifi_interface_handle *)info->interfaces;

+    *num = info->num_interfaces;

+

+    return WIFI_SUCCESS;

+}

+

+wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)

+{

+    interface_info *info = (interface_info *)handle;

+    strcpy(name, info->name);

+    return WIFI_SUCCESS;

+}

+

+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)

+{

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

+

+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,

+       feature_set set[], int *set_size)

+{

+    return WIFI_ERROR_NOT_SUPPORTED;

+}

+

+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)

+{

+    SetPnoMacAddrOuiCommand command(handle, scan_oui);

+    return (wifi_error)command.start();

+

+}

+

+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)

+{

+    SetNodfsCommand command(handle, nodfs);

+    return (wifi_error) command.requestResponse();

+}

+

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