Moving Wifi HAL to hardware
Vinit Deshapnde [Tue, 8 Apr 2014 22:36:03 +0000 (15:36 -0700)]
This change moves all Wifi HAL headers to libhardware_legacy; and moves
hal implementation under hardware/<vendor>/wlan. This way different
vendors will be able to tailor implementation to their drivers.

Change-Id: I55789bb6788ab694f4896aa36d76f7887b32dad6

bcmdhd/wifi_hal/Android.mk [new file with mode: 0644]
bcmdhd/wifi_hal/common.cpp [new file with mode: 0644]
bcmdhd/wifi_hal/common.h [new file with mode: 0644]
bcmdhd/wifi_hal/cpp_bindings.cpp [new file with mode: 0644]
bcmdhd/wifi_hal/cpp_bindings.h [new file with mode: 0644]
bcmdhd/wifi_hal/gscan.cpp [new file with mode: 0644]
bcmdhd/wifi_hal/sync.h [new file with mode: 0644]
bcmdhd/wifi_hal/wifi_hal.cpp [new file with mode: 0644]

diff --git a/bcmdhd/wifi_hal/Android.mk b/bcmdhd/wifi_hal/Android.mk
new file mode 100644 (file)
index 0000000..9a3caa9
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_REQUIRED_MODULES :=
+
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
+LOCAL_CPPFLAGS += -Wno-conversion-null
+
+LOCAL_C_INCLUDES += \
+       external/libnl-headers \
+       $(call include-path-for, libhardware_legacy)/hardware_legacy \
+
+LOCAL_SRC_FILES := \
+       wifi_hal.cpp \
+       common.cpp \
+       cpp_bindings.cpp \
+       gscan.cpp 
+
+LOCAL_MODULE := libwifi-hal-bcm
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/bcmdhd/wifi_hal/common.cpp b/bcmdhd/wifi_hal/common.cpp
new file mode 100644 (file)
index 0000000..5e09b6e
--- /dev/null
@@ -0,0 +1,168 @@
+
+#include <stdlib.h>
+#include <netlink-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? */
+
+    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;
+        info->num_event_cb++;
+        ALOGI("Successfully added event handler %p for command %d", func, cmd);
+        return WIFI_SUCCESS;
+    } else {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+        uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+    hal_info *info = (hal_info *)handle;
+
+    /* TODO: check for multiple handlers? */
+
+    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;
+        info->num_event_cb++;
+        ALOGI("Added event handler %p for vendor 0x%0x and subcmd 0x%0x", func, id, subcmd);
+        return WIFI_SUCCESS;
+    } else {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+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");
+    }
+
+    for (int i = 0; i < info->num_event_cb; i++) {
+        if (info->event_cb[i].nl_cmd == cmd) {
+            memmove(&info->event_cb[i], &info->event_cb[i+1],
+                (info->num_event_cb - i) * sizeof(cb_info));
+            info->num_event_cb--;
+            ALOGI("Successfully removed event handler for command %d", cmd);
+            return;
+        }
+    }
+}
+
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    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) {
+
+            memmove(&info->event_cb[i], &info->event_cb[i+1],
+                (info->num_event_cb - i) * sizeof(cb_info));
+            info->num_event_cb--;
+            ALOGI("Successfully removed event handler for vendor 0x%0x", id);
+            return;
+        }
+    }
+}
+
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
+{
+    hal_info *info = (hal_info *)handle;
+
+    ALOGD("registering command %d", id);
+
+    if (info->num_cmd < info->alloc_cmd) {
+        info->cmd[info->num_cmd].id   = id;
+        info->cmd[info->num_cmd].cmd  = cmd;
+        info->num_cmd++;
+        ALOGI("Successfully added command %d: %p", id, cmd);
+        return WIFI_SUCCESS;
+    } else {
+        return WIFI_ERROR_OUT_OF_MEMORY;
+    }
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+    hal_info *info = (hal_info *)handle;
+
+    ALOGD("un-registering command %d", id);
+
+    for (int i = 0; i < info->num_cmd; i++) {
+        if (info->cmd[i].id == id) {
+            WifiCommand *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", id, cmd);
+            return cmd;
+        }
+    }
+
+    return NULL;
+}
+
+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", id, cmd);
+            return;
+        }
+    }
+}
+
diff --git a/bcmdhd/wifi_hal/common.h b/bcmdhd/wifi_hal/common.h
new file mode 100644 (file)
index 0000000..88062cf
--- /dev/null
@@ -0,0 +1,131 @@
+
+#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"
+
+#define SOCKET_BUFFER_SIZE      (32768U)
+#define RECV_BUF_SIZE           (4096)
+#define DEFAULT_EVENT_CB_SIZE   (64)
+#define DEFAULT_CMD_SIZE        (64)
+
+/*
+ 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,
+
+    /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+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
+
+    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);
+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/bcmdhd/wifi_hal/cpp_bindings.cpp b/bcmdhd/wifi_hal/cpp_bindings.cpp
new file mode 100644 (file)
index 0000000..6f70259
--- /dev/null
@@ -0,0 +1,731 @@
+
+#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 <ctype.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+void appendFmt(char *buf, int &offset, const char *fmt, ...)
+{
+    va_list params;
+    va_start(params, fmt);
+    offset += vsprintf(buf + offset, fmt, params);
+    va_end(params);
+}
+
+#define C2S(x)  case x: return #x;
+
+static const char *cmdToString(int cmd)
+{
+       switch (cmd) {
+       C2S(NL80211_CMD_UNSPEC)
+       C2S(NL80211_CMD_GET_WIPHY)
+       C2S(NL80211_CMD_SET_WIPHY)
+       C2S(NL80211_CMD_NEW_WIPHY)
+       C2S(NL80211_CMD_DEL_WIPHY)
+       C2S(NL80211_CMD_GET_INTERFACE)
+       C2S(NL80211_CMD_SET_INTERFACE)
+       C2S(NL80211_CMD_NEW_INTERFACE)
+       C2S(NL80211_CMD_DEL_INTERFACE)
+       C2S(NL80211_CMD_GET_KEY)
+       C2S(NL80211_CMD_SET_KEY)
+       C2S(NL80211_CMD_NEW_KEY)
+       C2S(NL80211_CMD_DEL_KEY)
+       C2S(NL80211_CMD_GET_BEACON)
+       C2S(NL80211_CMD_SET_BEACON)
+       C2S(NL80211_CMD_START_AP)
+       C2S(NL80211_CMD_STOP_AP)
+       C2S(NL80211_CMD_GET_STATION)
+       C2S(NL80211_CMD_SET_STATION)
+       C2S(NL80211_CMD_NEW_STATION)
+       C2S(NL80211_CMD_DEL_STATION)
+       C2S(NL80211_CMD_GET_MPATH)
+       C2S(NL80211_CMD_SET_MPATH)
+       C2S(NL80211_CMD_NEW_MPATH)
+       C2S(NL80211_CMD_DEL_MPATH)
+       C2S(NL80211_CMD_SET_BSS)
+       C2S(NL80211_CMD_SET_REG)
+       C2S(NL80211_CMD_REQ_SET_REG)
+       C2S(NL80211_CMD_GET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MESH_CONFIG)
+       C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+       C2S(NL80211_CMD_GET_REG)
+       C2S(NL80211_CMD_GET_SCAN)
+       C2S(NL80211_CMD_TRIGGER_SCAN)
+       C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCAN_ABORTED)
+       C2S(NL80211_CMD_REG_CHANGE)
+       C2S(NL80211_CMD_AUTHENTICATE)
+       C2S(NL80211_CMD_ASSOCIATE)
+       C2S(NL80211_CMD_DEAUTHENTICATE)
+       C2S(NL80211_CMD_DISASSOCIATE)
+       C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+       C2S(NL80211_CMD_REG_BEACON_HINT)
+       C2S(NL80211_CMD_JOIN_IBSS)
+       C2S(NL80211_CMD_LEAVE_IBSS)
+       C2S(NL80211_CMD_TESTMODE)
+       C2S(NL80211_CMD_CONNECT)
+       C2S(NL80211_CMD_ROAM)
+       C2S(NL80211_CMD_DISCONNECT)
+       C2S(NL80211_CMD_SET_WIPHY_NETNS)
+       C2S(NL80211_CMD_GET_SURVEY)
+       C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+       C2S(NL80211_CMD_SET_PMKSA)
+       C2S(NL80211_CMD_DEL_PMKSA)
+       C2S(NL80211_CMD_FLUSH_PMKSA)
+       C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+       C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+       C2S(NL80211_CMD_REGISTER_FRAME)
+       C2S(NL80211_CMD_FRAME)
+       C2S(NL80211_CMD_FRAME_TX_STATUS)
+       C2S(NL80211_CMD_SET_POWER_SAVE)
+       C2S(NL80211_CMD_GET_POWER_SAVE)
+       C2S(NL80211_CMD_SET_CQM)
+       C2S(NL80211_CMD_NOTIFY_CQM)
+       C2S(NL80211_CMD_SET_CHANNEL)
+       C2S(NL80211_CMD_SET_WDS_PEER)
+       C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+       C2S(NL80211_CMD_JOIN_MESH)
+       C2S(NL80211_CMD_LEAVE_MESH)
+       C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+       C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+       C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+       C2S(NL80211_CMD_GET_WOWLAN)
+       C2S(NL80211_CMD_SET_WOWLAN)
+       C2S(NL80211_CMD_START_SCHED_SCAN)
+       C2S(NL80211_CMD_STOP_SCHED_SCAN)
+       C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+       C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+       C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+       C2S(NL80211_CMD_PMKSA_CANDIDATE)
+       C2S(NL80211_CMD_TDLS_OPER)
+       C2S(NL80211_CMD_TDLS_MGMT)
+       C2S(NL80211_CMD_UNEXPECTED_FRAME)
+       C2S(NL80211_CMD_PROBE_CLIENT)
+       C2S(NL80211_CMD_REGISTER_BEACONS)
+       C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+       C2S(NL80211_CMD_SET_NOACK_MAP)
+       C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+       C2S(NL80211_CMD_START_P2P_DEVICE)
+       C2S(NL80211_CMD_STOP_P2P_DEVICE)
+       C2S(NL80211_CMD_CONN_FAILED)
+       C2S(NL80211_CMD_SET_MCAST_RATE)
+       C2S(NL80211_CMD_SET_MAC_ACL)
+       C2S(NL80211_CMD_RADAR_DETECT)
+       C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+       C2S(NL80211_CMD_UPDATE_FT_IES)
+       C2S(NL80211_CMD_FT_EVENT)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+       C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+       C2S(NL80211_CMD_GET_COALESCE)
+       C2S(NL80211_CMD_SET_COALESCE)
+       C2S(NL80211_CMD_CHANNEL_SWITCH)
+       C2S(NL80211_CMD_VENDOR)
+       C2S(NL80211_CMD_SET_QOS_MAP)
+       default:
+               return "NL80211_CMD_UNKNOWN";
+       }
+}
+
+const char *attributeToString(int attribute)
+{
+    switch (attribute) {
+       C2S(NL80211_ATTR_UNSPEC)
+
+       C2S(NL80211_ATTR_WIPHY)
+       C2S(NL80211_ATTR_WIPHY_NAME)
+
+       C2S(NL80211_ATTR_IFINDEX)
+       C2S(NL80211_ATTR_IFNAME)
+       C2S(NL80211_ATTR_IFTYPE)
+
+       C2S(NL80211_ATTR_MAC)
+
+       C2S(NL80211_ATTR_KEY_DATA)
+       C2S(NL80211_ATTR_KEY_IDX)
+       C2S(NL80211_ATTR_KEY_CIPHER)
+       C2S(NL80211_ATTR_KEY_SEQ)
+       C2S(NL80211_ATTR_KEY_DEFAULT)
+
+       C2S(NL80211_ATTR_BEACON_INTERVAL)
+       C2S(NL80211_ATTR_DTIM_PERIOD)
+       C2S(NL80211_ATTR_BEACON_HEAD)
+       C2S(NL80211_ATTR_BEACON_TAIL)
+
+       C2S(NL80211_ATTR_STA_AID)
+       C2S(NL80211_ATTR_STA_FLAGS)
+       C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
+       C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
+       C2S(NL80211_ATTR_STA_VLAN)
+       C2S(NL80211_ATTR_STA_INFO)
+
+       C2S(NL80211_ATTR_WIPHY_BANDS)
+
+       C2S(NL80211_ATTR_MNTR_FLAGS)
+
+       C2S(NL80211_ATTR_MESH_ID)
+       C2S(NL80211_ATTR_STA_PLINK_ACTION)
+       C2S(NL80211_ATTR_MPATH_NEXT_HOP)
+       C2S(NL80211_ATTR_MPATH_INFO)
+
+       C2S(NL80211_ATTR_BSS_CTS_PROT)
+       C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
+       C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
+
+       C2S(NL80211_ATTR_HT_CAPABILITY)
+
+       C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
+
+       C2S(NL80211_ATTR_REG_ALPHA2)
+       C2S(NL80211_ATTR_REG_RULES)
+
+       C2S(NL80211_ATTR_MESH_CONFIG)
+
+       C2S(NL80211_ATTR_BSS_BASIC_RATES)
+
+       C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
+       C2S(NL80211_ATTR_WIPHY_FREQ)
+       C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
+
+       C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
+
+       C2S(NL80211_ATTR_MGMT_SUBTYPE)
+       C2S(NL80211_ATTR_IE)
+
+       C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
+
+       C2S(NL80211_ATTR_SCAN_FREQUENCIES)
+       C2S(NL80211_ATTR_SCAN_SSIDS)
+       C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
+       C2S(NL80211_ATTR_BSS)
+
+       C2S(NL80211_ATTR_REG_INITIATOR)
+       C2S(NL80211_ATTR_REG_TYPE)
+
+       C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
+
+       C2S(NL80211_ATTR_FRAME)
+       C2S(NL80211_ATTR_SSID)
+       C2S(NL80211_ATTR_AUTH_TYPE)
+       C2S(NL80211_ATTR_REASON_CODE)
+
+       C2S(NL80211_ATTR_KEY_TYPE)
+
+       C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
+       C2S(NL80211_ATTR_CIPHER_SUITES)
+
+       C2S(NL80211_ATTR_FREQ_BEFORE)
+       C2S(NL80211_ATTR_FREQ_AFTER)
+
+       C2S(NL80211_ATTR_FREQ_FIXED)
+
+
+       C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
+       C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
+       C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
+       C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
+
+       C2S(NL80211_ATTR_TIMED_OUT)
+
+       C2S(NL80211_ATTR_USE_MFP)
+
+       C2S(NL80211_ATTR_STA_FLAGS2)
+
+       C2S(NL80211_ATTR_CONTROL_PORT)
+
+       C2S(NL80211_ATTR_TESTDATA)
+
+       C2S(NL80211_ATTR_PRIVACY)
+
+       C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
+       C2S(NL80211_ATTR_STATUS_CODE)
+
+       C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
+       C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
+       C2S(NL80211_ATTR_WPA_VERSIONS)
+       C2S(NL80211_ATTR_AKM_SUITES)
+
+       C2S(NL80211_ATTR_REQ_IE)
+       C2S(NL80211_ATTR_RESP_IE)
+
+       C2S(NL80211_ATTR_PREV_BSSID)
+
+       C2S(NL80211_ATTR_KEY)
+       C2S(NL80211_ATTR_KEYS)
+
+       C2S(NL80211_ATTR_PID)
+
+       C2S(NL80211_ATTR_4ADDR)
+
+       C2S(NL80211_ATTR_SURVEY_INFO)
+
+       C2S(NL80211_ATTR_PMKID)
+       C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
+
+       C2S(NL80211_ATTR_DURATION)
+
+       C2S(NL80211_ATTR_COOKIE)
+
+       C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
+
+       C2S(NL80211_ATTR_TX_RATES)
+
+       C2S(NL80211_ATTR_FRAME_MATCH)
+
+       C2S(NL80211_ATTR_ACK)
+
+       C2S(NL80211_ATTR_PS_STATE)
+
+       C2S(NL80211_ATTR_CQM)
+
+       C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
+
+       C2S(NL80211_ATTR_AP_ISOLATE)
+
+       C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
+       C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
+
+       C2S(NL80211_ATTR_TX_FRAME_TYPES)
+       C2S(NL80211_ATTR_RX_FRAME_TYPES)
+       C2S(NL80211_ATTR_FRAME_TYPE)
+
+       C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+       C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
+
+       C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
+
+       C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
+       C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
+
+       C2S(NL80211_ATTR_MCAST_RATE)
+
+       C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
+
+       C2S(NL80211_ATTR_BSS_HT_OPMODE)
+
+       C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
+
+       C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
+
+       C2S(NL80211_ATTR_MESH_SETUP)
+
+       C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
+       C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
+
+       C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
+       C2S(NL80211_ATTR_STA_PLINK_STATE)
+
+       C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
+       C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
+
+       C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
+
+       C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
+       C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
+
+       C2S(NL80211_ATTR_REKEY_DATA)
+
+       C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
+       C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
+
+       C2S(NL80211_ATTR_SCAN_SUPP_RATES)
+
+       C2S(NL80211_ATTR_HIDDEN_SSID)
+
+       C2S(NL80211_ATTR_IE_PROBE_RESP)
+       C2S(NL80211_ATTR_IE_ASSOC_RESP)
+
+       C2S(NL80211_ATTR_STA_WME)
+       C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
+
+       C2S(NL80211_ATTR_ROAM_SUPPORT)
+
+       C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
+       C2S(NL80211_ATTR_MAX_MATCH_SETS)
+
+       C2S(NL80211_ATTR_PMKSA_CANDIDATE)
+
+       C2S(NL80211_ATTR_TX_NO_CCK_RATE)
+
+       C2S(NL80211_ATTR_TDLS_ACTION)
+       C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
+       C2S(NL80211_ATTR_TDLS_OPERATION)
+       C2S(NL80211_ATTR_TDLS_SUPPORT)
+       C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
+
+       C2S(NL80211_ATTR_DEVICE_AP_SME)
+
+       C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
+
+       C2S(NL80211_ATTR_FEATURE_FLAGS)
+
+       C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
+
+       C2S(NL80211_ATTR_PROBE_RESP)
+
+       C2S(NL80211_ATTR_DFS_REGION)
+
+       C2S(NL80211_ATTR_DISABLE_HT)
+       C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
+
+       C2S(NL80211_ATTR_NOACK_MAP)
+
+       C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
+
+       C2S(NL80211_ATTR_RX_SIGNAL_DBM)
+
+       C2S(NL80211_ATTR_BG_SCAN_PERIOD)
+
+       C2S(NL80211_ATTR_WDEV)
+
+       C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
+
+       C2S(NL80211_ATTR_CONN_FAILED_REASON)
+
+       C2S(NL80211_ATTR_SAE_DATA)
+
+       C2S(NL80211_ATTR_VHT_CAPABILITY)
+
+       C2S(NL80211_ATTR_SCAN_FLAGS)
+
+       C2S(NL80211_ATTR_CHANNEL_WIDTH)
+       C2S(NL80211_ATTR_CENTER_FREQ1)
+       C2S(NL80211_ATTR_CENTER_FREQ2)
+
+       C2S(NL80211_ATTR_P2P_CTWINDOW)
+       C2S(NL80211_ATTR_P2P_OPPPS)
+
+       C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
+
+       C2S(NL80211_ATTR_ACL_POLICY)
+
+       C2S(NL80211_ATTR_MAC_ADDRS)
+
+       C2S(NL80211_ATTR_MAC_ACL_MAX)
+
+       C2S(NL80211_ATTR_RADAR_EVENT)
+
+       C2S(NL80211_ATTR_EXT_CAPA)
+       C2S(NL80211_ATTR_EXT_CAPA_MASK)
+
+       C2S(NL80211_ATTR_STA_CAPABILITY)
+       C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
+
+       C2S(NL80211_ATTR_PROTOCOL_FEATURES)
+       C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
+
+       C2S(NL80211_ATTR_DISABLE_VHT)
+       C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
+
+       C2S(NL80211_ATTR_MDID)
+       C2S(NL80211_ATTR_IE_RIC)
+
+       C2S(NL80211_ATTR_CRIT_PROT_ID)
+       C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
+
+       C2S(NL80211_ATTR_PEER_AID)
+
+       C2S(NL80211_ATTR_COALESCE_RULE)
+
+       C2S(NL80211_ATTR_CH_SWITCH_COUNT)
+       C2S(NL80211_ATTR_CH_SWITCH_BLOCK_TX)
+       C2S(NL80211_ATTR_CSA_IES)
+       C2S(NL80211_ATTR_CSA_C_OFF_BEACON)
+       C2S(NL80211_ATTR_CSA_C_OFF_PRESP)
+
+       C2S(NL80211_ATTR_RXMGMT_FLAGS)
+
+       C2S(NL80211_ATTR_STA_SUPPORTED_CHANNELS)
+
+       C2S(NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES)
+
+       C2S(NL80211_ATTR_HANDLE_DFS)
+
+       C2S(NL80211_ATTR_SUPPORT_5_MHZ)
+       C2S(NL80211_ATTR_SUPPORT_10_MHZ)
+
+       C2S(NL80211_ATTR_OPMODE_NOTIF)
+
+       C2S(NL80211_ATTR_VENDOR_ID)
+       C2S(NL80211_ATTR_VENDOR_SUBCMD)
+       C2S(NL80211_ATTR_VENDOR_DATA)
+       C2S(NL80211_ATTR_VENDOR_EVENTS)
+
+       C2S(NL80211_ATTR_QOS_MAP)
+    default:
+        return "NL80211_ATTR_UNKNOWN";
+    }
+}
+
+void WifiEvent::log() {
+    parse();
+
+    byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
+    int len = genlmsg_attrlen(mHeader, 0);
+    ALOGD("cmd = %s, len = %d", get_cmdString(), len);
+    ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
+
+    for (int i = 0; i < len; i += 16) {
+        char line[81];
+        int linelen = min(16, len - i);
+        int offset = 0;
+        appendFmt(line, offset, "%02x", data[i]);
+        for (int j = 1; j < linelen; j++) {
+            appendFmt(line, offset, " %02x", data[i+j]);
+        }
+
+        for (int j = linelen; j < 16; j++) {
+            appendFmt(line, offset, "   ");
+        }
+
+        line[23] = '-';
+
+        appendFmt(line, offset, "  ");
+
+        for (int j = 0; j < linelen; j++) {
+            if (isprint(data[i+j])) {
+                appendFmt(line, offset, "%c", data[i+j]);
+            } else {
+                appendFmt(line, offset, "-");
+            }
+        }
+
+        ALOGD("%s", line);
+    }
+
+    for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
+        if (mAttributes[i] != NULL) {
+            ALOGD("found attribute %s", attributeToString(i));
+        }
+    }
+
+    ALOGD("-- End of message --");
+}
+
+const char *WifiEvent::get_cmdString() {
+    return cmdToString(get_cmd());
+}
+
+
+int WifiEvent::parse() {
+    if (mHeader != NULL) {
+        return WIFI_SUCCESS;
+    }
+    mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
+    int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
+          genlmsg_attrlen(mHeader, 0), NULL);
+
+    // ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
+    return result;
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+    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/bcmdhd/wifi_hal/cpp_bindings.h b/bcmdhd/wifi_hal/cpp_bindings.h
new file mode 100644 (file)
index 0000000..7a29caf
--- /dev/null
@@ -0,0 +1,328 @@
+
+#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_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;
+public:
+    WifiCommand(wifi_handle handle, wifi_request_id id)
+            : mMsg(getHalInfo(handle)->nl80211_family_id), mId(id)
+    {
+        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)
+    {
+        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 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/bcmdhd/wifi_hal/gscan.cpp b/bcmdhd/wifi_hal/gscan.cpp
new file mode 100644 (file)
index 0000000..39cbce4
--- /dev/null
@@ -0,0 +1,990 @@
+
+#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"
+
+typedef enum {
+    BRCM_RESERVED1,
+    BRCM_RESERVED2,
+    GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
+    GSCAN_EVENT_HOTLIST_RESULTS,
+    GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
+
+} GSCAN_EVENT;
+
+typedef enum {
+
+    GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+
+    GSCAN_SUBCMD_SET_CONFIG,                            /* 0x1001 */
+
+    GSCAN_SUBCMD_SET_SCAN_CONFIG,                       /* 0x1002 */
+    GSCAN_SUBCMD_ENABLE_GSCAN,                          /* 0x1003 */
+    GSCAN_SUBCMD_GET_SCAN_RESULTS,                      /* 0x1004 */
+    GSCAN_SUBCMD_SCAN_RESULTS,                          /* 0x1005 */
+
+    GSCAN_SUBCMD_SET_HOTLIST,                           /* 0x1006 */
+
+    GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,         /* 0x1007 */
+
+    /* Add more sub commands here */
+
+    GSCAN_SUBCMD_MAX                                    /* 0x1008 */
+
+} GSCAN_SUB_COMMAND;
+
+typedef enum {
+
+    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+    GSCAN_ATTRIBUTE_BASE_PERIOD,
+    GSCAN_ATTRIBUTE_BUCKETS,
+    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_ENABLE_FEATURE = 20,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,              /* indicates no more results */
+    GSCAN_ATTRIBUTE_FLUSH_FEATURE,                      /* Flush all the configs */
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
+    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
+    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
+    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
+
+    /* 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,
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+    GSCAN_ATTRIBUTE_MIN_BREACHING,
+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
+
+    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, GSCAN_SUBCMD_GET_CAPABILITIES);
+        if (ret < 0) {
+            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();
+
+        ALOGD("Id = %0x, subcmd = %d", id, subcmd);
+
+        void *data = reply.get_vendor_data();
+        int len = reply.get_vendor_data_len();
+
+        if (len == sizeof(*mCapabilities)) {
+            ALOGE("Invalid reply length");
+            memcpy(mCapabilities, data, len);
+        } else {
+            ALOGE("Invalid reply length: %d", len);
+        }
+
+        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();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+/* helper functions */
+
+static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
+{
+    memset(results, 0, sizeof(wifi_scan_result) * num);
+
+    int i = 0;
+    for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
+
+        int index = it.get_type();
+        ALOGI("retrieved scan result %d", index);
+        nlattr *sc_data = (nlattr *) it.get_data();
+        wifi_scan_result *result = results + i;
+
+        for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
+            int type = it2.get_type();
+            if (type == GSCAN_ATTRIBUTE_SSID) {
+                strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
+                result->ssid[it2.get_len()] = 0;
+            } else if (type == GSCAN_ATTRIBUTE_BSSID) {
+                memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
+            } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
+                result->ts = it2.get_u64();
+            } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
+                result->ts = it2.get_u16();
+            } else if (type == GSCAN_ATTRIBUTE_RSSI) {
+                result->rssi = it2.get_u8();
+            } else if (type == GSCAN_ATTRIBUTE_RTT) {
+                result->rtt = it2.get_u64();
+            } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
+                result->rtt_sd = it2.get_u64();
+            }
+        }
+
+    }
+
+    if (i >= num) {
+        ALOGE("Got too many results; skipping some");
+    }
+
+    return i;
+}
+
+int createFeatureRequest(WifiRequest& request, int subcmd, int enable) {
+
+    int result = request.create(GOOGLE_OUI, subcmd);
+    if (result < 0) {
+        return result;
+    }
+
+    nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+    result = request.put_u32(GSCAN_ATTRIBUTE_ENABLE_FEATURE, enable);
+    if (result < 0) {
+        return result;
+    }
+
+    request.attr_end(data);
+    return WIFI_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class ScanCommand : public WifiCommand
+{
+    wifi_scan_cmd_params *mParams;
+    wifi_scan_result_handler mHandler;
+public:
+    ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
+                wifi_scan_result_handler handler)
+        : WifiCommand(iface, id), mParams(params), mHandler(handler)
+    { }
+
+    int createSetupRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
+        if (result < 0) {
+            return result;
+        }
+
+        for (int i = 0; i < mParams->num_buckets; i++) {
+            nlattr * bucket = request.attr_start(i);    // next bucket
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+                    mParams->buckets[i].num_channels);
+            if (result < 0) {
+                return result;
+            }
+
+            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 createScanConfigRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SCAN_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, 3);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int createStartRequest(WifiRequest& request) {
+        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+    }
+
+    int createStopRequest(WifiRequest& request) {
+        return createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 0);
+    }
+
+    int start() {
+        ALOGD("Setting configuration");
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create setup request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to configure setup; result = %d", result);
+            return result;
+        }
+
+        request.destroy();
+
+        result = createScanConfigRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create scan config request; result = %d", result);
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to configure scan; result = %d", result);
+            return result;
+        }
+
+        ALOGD("Starting scan");
+
+        result = createStartRequest(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to create start request; result = %d", result);
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+
+        result = requestResponse(request);
+        if (result != WIFI_SUCCESS) {
+            ALOGE("failed to start scan; result = %d", result);
+            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_SCAN_RESULTS_AVAILABLE);
+        return WIFI_SUCCESS;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Got a scan results event");
+
+        event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len != 4) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+        int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
+        ALOGI("Found %d scan results", num);
+        (*mHandler.on_scan_results_available)(id(), num);
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_start_gscan(
+        wifi_request_id id,
+        wifi_interface_handle iface,
+        wifi_scan_cmd_params params,
+        wifi_scan_result_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    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);
+
+    WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+    if (cmd) {
+        cmd->cancel();
+        delete cmd;
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class GetScanResultsCommand : public WifiCommand {
+    wifi_scan_result *mResults;
+    int *mNum;
+    int mRetrieved;
+    byte mFlush;
+    int mCompleted;
+public:
+    GetScanResultsCommand(wifi_interface_handle iface, byte flush,
+            wifi_scan_result *results, int *num)
+        : WifiCommand(iface, -1), mResults(results), mNum(num),
+                mRetrieved(0), mFlush(flush), mCompleted(0)
+    { }
+
+    int createRequest(WifiRequest& request, int num, byte flush) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_GET_SCAN_RESULTS);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
+        if (result < 0) {
+            return result;
+        }
+
+        result = request.put_u8(GSCAN_ATTRIBUTE_FLUSH_RESULTS, flush);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return WIFI_SUCCESS;
+    }
+
+    int execute() {
+        WifiRequest request(familyId(), ifaceId());
+        ALOGI("retrieving %d scan results", *mNum);
+
+        for (int i = 0; i < 10 && mRetrieved < *mNum; i++) {
+            int result = createRequest(request, (*mNum - 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();
+                ALOGI("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 scan_id = 0, flags = 0, num = 0;
+                    if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
+                        scan_id = it.get_u32();
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
+                        flags = it.get_u8();
+                    } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
+                        num = it2.get_u32();
+                    } else 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);
+                        ALOGI("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;
+                            ALOGI("%02d  %-32s  %02x:%02x:%02x:%02x:%02x:%02x", i,
+                                result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
+                                result->bssid[3], result->bssid[4], result->bssid[5]);
+                        }
+                        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,
+        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, 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, GSCAN_SUBCMD_SET_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+        for (int i = 0; i < mParams.num; 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.bssids[i].bssid);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+        return result;
+    }
+
+    int createTeardownRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_HOTLIST_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+        request.attr_end(attr);
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("Executing hotlist setup request, num = %d", mParams.num);
+        WifiRequest request(familyId(), ifaceId());
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("Failed to execute hotlist setup request, result = %d", result);
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
+            return result;
+        }
+
+        ALOGI("Successfully set %d APs in the hotlist", mParams.num);
+        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
+
+        result = requestResponse(request);
+        if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
+            return result;
+        }
+
+        ALOGI("successfully restarted the scan");
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS);
+
+        /* create set hotlist message with empty hotlist */
+        WifiRequest request(familyId(), ifaceId());
+        int result = createTeardownRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            return result;
+        }
+
+        ALOGI("Successfully reset APs in current hotlist");
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Got a hotlist ap found event");
+
+        event.log();
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+        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));
+        ALOGI("Retrieved %d hot APs", num);
+
+        (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
+        return NL_SKIP;
+    }
+};
+
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+        wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+{
+    wifi_handle handle = getWifiHandle(iface);
+
+    BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
+    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();
+        delete cmd;
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SignificantWifiChangeCommand : public WifiCommand
+{
+private:
+    wifi_significant_change_params mParams;
+    wifi_significant_change_handler mHandler;
+    static const int MAX_RESULTS = 64;
+    wifi_scan_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, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+        if (result < 0) {
+            return result;
+        }
+        result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
+        if (result < 0) {
+            return result;
+        }
+
+        struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
+
+        for (int i = 0; i < mParams.num; i++) {
+
+            nlattr *attr2 = request.attr_start(i);
+            if (attr2 == NULL) {
+                return WIFI_ERROR_OUT_OF_MEMORY;
+            }
+            result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.bssids[i].bssid);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.bssids[i].high);
+            if (result < 0) {
+                return result;
+            }
+            result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.bssids[i].low);
+            if (result < 0) {
+                return result;
+            }
+            request.attr_end(attr2);
+        }
+
+        request.attr_end(attr);
+        request.attr_end(data);
+
+        return result;
+    }
+
+    int createTeardownRequest(WifiRequest& request) {
+        int result = request.create(GOOGLE_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG);
+        if (result < 0) {
+            return result;
+        }
+
+        nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+        result = request.put_u16(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        request.attr_end(data);
+        return result;
+    }
+
+    int start() {
+        ALOGI("Set significant wifi change config");
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createSetupRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        WifiEvent e(request.getMessage());
+        e.log();
+
+        result = requestResponse(request);
+        if (result < 0) {
+            ALOGI("failed to set significant wifi change config %d", result);
+            return result;
+        }
+
+        ALOGI("successfully set significant wifi change config");
+
+        result = createFeatureRequest(request, GSCAN_SUBCMD_ENABLE_GSCAN, 1);
+        if (result < 0) {
+            return result;
+        }
+
+        registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+        result = requestResponse(request);
+        if (result < 0) {
+            unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+            return result;
+        }
+
+        ALOGI("successfully restarted the scan");
+        return result;
+    }
+
+    virtual int cancel() {
+        /* unregister event handler */
+        unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+        /* create set significant change monitor message with empty hotlist */
+        WifiRequest request(familyId(), ifaceId());
+
+        int result = createTeardownRequest(request);
+        if (result < 0) {
+            return result;
+        }
+
+        result = requestResponse(request);
+        if (result < 0) {
+            return result;
+        }
+
+        ALOGI("successfully reset significant wifi change config");
+        return result;
+    }
+
+    virtual int handleResponse(WifiEvent& reply) {
+        /* Nothing to do on response! */
+        return NL_SKIP;
+    }
+
+    virtual int handleEvent(WifiEvent& event) {
+        ALOGI("Got a significant wifi change event");
+
+        nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+        int len = event.get_vendor_data_len();
+
+        if (vendor_data == NULL || len == 0) {
+            ALOGI("No scan results found");
+            return NL_SKIP;
+        }
+
+        typedef struct {
+            uint16_t flags;
+            uint16_t channel;
+            mac_addr bssid;
+            byte 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(mResults[i].bssid, ci[i].bssid, sizeof(mac_addr));
+            mResults[i].rssi = ci[i].rssi_history[7];
+            mResults[i].channel = ci[i].channel;
+        }
+
+        ALOGI("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();
+        delete cmd;
+        return WIFI_SUCCESS;
+    }
+
+    return WIFI_ERROR_INVALID_ARGS;
+}
diff --git a/bcmdhd/wifi_hal/sync.h b/bcmdhd/wifi_hal/sync.h
new file mode 100644 (file)
index 0000000..cea2ea9
--- /dev/null
@@ -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/bcmdhd/wifi_hal/wifi_hal.cpp b/bcmdhd/wifi_hal/wifi_hal.cpp
new file mode 100644 (file)
index 0000000..7d31b38
--- /dev/null
@@ -0,0 +1,506 @@
+
+#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 <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"
+
+/*
+ BUGBUG: normally, libnl allocates ports for all connections it makes; but
+ being a static library, it doesn't really know how many other netlink connections
+ are made by the same process, if connections come from different shared libraries.
+ These port assignments exist to solve that problem - temporarily. We need to fix
+ libnl to try and allocate ports across the entire process.
+ */
+
+#define WIFI_HAL_CMD_SOCK_PORT       644
+#define WIFI_HAL_EVENT_SOCK_PORT     645
+
+static void internal_event_handler(wifi_handle handle, int events);
+static int internal_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);
+
+/* Initialize/Cleanup */
+
+void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
+{
+       uint32_t pid = getpid() & 0x3FFFFF;
+
+       if (port == 0) {
+               sock->s_flags &= ~NL_OWN_PORT;
+       } else {
+               sock->s_flags |= NL_OWN_PORT;
+       }
+
+       sock->s_local.nl_pid = 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_nl *addr_nl = &(sock->s_local);
+    /* ALOGI("socket address is %d:%d:%d:%d",
+        addr_nl->nl_family, addr_nl->nl_pad, addr_nl->nl_pid, addr_nl->nl_groups); */
+
+    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_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;
+    }
+
+    *handle = (wifi_handle) info;
+
+    wifi_add_membership(*handle, "scan");
+    wifi_add_membership(*handle, "mlme");
+    wifi_add_membership(*handle, "regulatory");
+    wifi_add_membership(*handle, "vendor");
+
+    wifi_init_interfaces(*handle);
+    // ALOGI("Found %d interfaces", info->num_interfaces);
+
+    ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR);
+    return WIFI_SUCCESS;
+}
+
+static int wifi_add_membership(wifi_handle handle, const char *group)
+{
+    hal_info *info = getHalInfo(handle);
+
+    int id = wifi_get_multicast_id(handle, "nl80211", group);
+    if (id < 0) {
+        ALOGE("Could not find group %s", group);
+        return id;
+    }
+
+    int ret = nl_socket_add_membership(info->event_sock, id);
+    if (ret < 0) {
+        ALOGE("Could not add membership to group %s", group);
+    }
+
+    // ALOGI("Successfully added membership for group %s", group);
+    return ret;
+}
+
+static void internal_cleaned_up_handler(wifi_handle handle)
+{
+    hal_info *info = getHalInfo(handle);
+    wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
+
+    if (info->cmd_sock != 0) {
+        nl_socket_free(info->cmd_sock);
+        nl_socket_free(info->event_sock);
+        info->cmd_sock = NULL;
+        info->event_sock = NULL;
+    }
+
+    (*cleaned_up_handler)(handle);
+    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);
+    struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
+    int res = nl_recvmsgs(info->event_sock, cb);
+    nl_cb_put(cb);
+    return res;
+}
+
+static void internal_event_handler(wifi_handle handle, int events)
+{
+    if (events & POLLERR) {
+        ALOGE("Error reading from socket");
+    } else if (events & POLLHUP) {
+        ALOGE("Remote side hung up");
+    } else if (events & POLLIN) {
+        ALOGI("Found some events!!!");
+        internal_pollin_handler(handle);
+    } else {
+        ALOGE("Unknown event - %0x", events);
+    }
+}
+
+/* Run event handler */
+void wifi_event_loop(wifi_handle handle)
+{
+    hal_info *info = getHalInfo(handle);
+    if (info->in_event_loop) {
+        return;
+    } else {
+        info->in_event_loop = true;
+    }
+
+    pollfd pfd;
+    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 & (POLLIN | POLLHUP | POLLERR)) {
+            internal_event_handler(handle, pfd.revents);
+        }
+    } while (!info->clean_up);
+
+
+    ALOGI("Cleaning up");
+    internal_cleaned_up_handler(handle);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int internal_valid_message_handler(nl_msg *msg, void *arg)
+{
+    wifi_handle handle = (wifi_handle)arg;
+    hal_info *info = getHalInfo(handle);
+
+    WifiEvent event(msg);
+    int res = event.parse();
+    if (res < 0) {
+        ALOGE("Failed to parse event: %d", res);
+        return NL_SKIP;
+    }
+
+    int cmd = event.get_cmd();
+    uint32_t vendor_id = 0;
+    int subcmd = 0;
+
+    if (cmd == NL80211_CMD_VENDOR) {
+        vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
+        subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+        ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+                event.get_cmdString(), vendor_id, subcmd);
+    } 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;
+    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]);
+            (*(cbi->cb_func))(msg, cbi->cb_arg);
+            dispatched = true;
+        }
+    }
+
+    if (!dispatched) {
+        ALOGI("event ignored!!");
+    }
+
+    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) {
+
+        // ALOGI("handling reponse in %s", __func__);
+
+        struct nlattr **tb = reply.attributes();
+        struct genlmsghdr *gnlh = reply.header();
+        struct nlattr *mcgrp = NULL;
+        int i;
+
+        if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+            ALOGI("No multicast groups found");
+            return NL_SKIP;
+        } else {
+            // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
+        }
+
+        for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+            // ALOGI("Processing group");
+            struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+            nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
+                nla_len(mcgrp), NULL);
+            if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
+                continue;
+            }
+
+            char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+            int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+
+            // ALOGI("Found group name %s", grpName);
+
+            if (strncmp(grpName, mGroup, grpNameLen) != 0)
+                continue;
+
+            mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+            break;
+        }
+
+        return NL_SKIP;
+    }
+
+};
+
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
+{
+    GetMulticastIdCommand cmd(handle, name, group);
+    int res = cmd.requestResponse();
+    if (res < 0)
+        return res;
+    else
+        return cmd.getId();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static bool is_wifi_interface(const char *name)
+{
+    if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
+        /* not a wifi interface; ignore it */
+        return false;
+    } else {
+        return true;
+    }
+}
+
+static int get_interface(const char *name, interface_info *info)
+{
+    strcpy(info->name, name);
+    info->id = if_nametoindex(name);
+    // ALOGI("found an interface : %s, id = %d", name, info->id);
+    return WIFI_SUCCESS;
+}
+
+wifi_error wifi_init_interfaces(wifi_handle handle)
+{
+    hal_info *info = (hal_info *)handle;
+
+    struct dirent *de;
+
+    DIR *d = opendir("/sys/class/net");
+    if (d == 0)
+        return WIFI_ERROR_UNKNOWN;
+
+    int n = 0;
+    while ((de = readdir(d))) {
+        if (de->d_name[0] == '.')
+            continue;
+        if (is_wifi_interface(de->d_name) ) {
+            n++;
+        }
+    }
+
+    closedir(d);
+
+    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;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+