Merge KeystoneQ-ww-20190522
Change-Id: I03b64105c115f2d90fb39cb9e620350458daeed0
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..8051d5c
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,40 @@
+#############################################################################
+#
+# Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd
+#
+#############################################################################
+
+ifeq ($(CONFIG_SAMSUNG_SCSC_WIFIBT),true)
+
+LOCAL_PATH := $(call my-dir)
+
+# Make the HAL library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Wno-unused-parameter
+
+LOCAL_C_INCLUDES += \
+ system/core/include/ \
+ external/libnl/include \
+ $(call include-path-for, libhardware_legacy)/hardware_legacy \
+ external/wpa_supplicant_8/src/drivers
+
+LOCAL_SRC_FILES := \
+ wifi_hal.cpp \
+ rtt.cpp \
+ common.cpp \
+ cpp_bindings.cpp \
+ gscan.cpp \
+ link_layer_stats.cpp \
+ wifi_offload.cpp \
+ roam.cpp \
+ wifi_logger.cpp \
+ wifi_nan.cpp
+
+LOCAL_MODULE := libwifi-hal-slsi
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif
diff --git a/common.cpp b/common.cpp
new file mode 100755
index 0000000..e0de0bc
--- /dev/null
+++ b/common.cpp
@@ -0,0 +1,244 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+interface_info *getIfaceInfo(wifi_interface_handle handle)
+{
+ return (interface_info *)handle;
+}
+
+wifi_handle getWifiHandle(wifi_interface_handle handle)
+{
+ return getIfaceInfo(handle)->handle;
+}
+
+hal_info *getHalInfo(wifi_handle handle)
+{
+ return (hal_info *)handle;
+}
+
+hal_info *getHalInfo(wifi_interface_handle handle)
+{
+ return getHalInfo(getWifiHandle(handle));
+}
+
+wifi_handle getWifiHandle(hal_info *info)
+{
+ return (wifi_handle)info;
+}
+
+wifi_interface_handle getIfaceHandle(interface_info *info)
+{
+ return (wifi_interface_handle)info;
+}
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+ /* TODO: check for multiple handlers? */
+ pthread_mutex_lock(&info->cb_lock);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ info->event_cb[info->num_event_cb].nl_cmd = cmd;
+ info->event_cb[info->num_event_cb].vendor_id = 0;
+ info->event_cb[info->num_event_cb].vendor_subcmd = 0;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ /*
+ ALOGI("Successfully added event handler %p:%p for command %d at %d",
+ arg, func, cmd, info->num_event_cb);*/
+ info->num_event_cb++;
+ result = WIFI_SUCCESS;
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return result;
+}
+
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+//ALOGD("GSCAN register handle wifi_register_vendor_handler %p", handle);
+ /* TODO: check for multiple handlers? */
+ pthread_mutex_lock(&info->cb_lock);
+ //ALOGI("Added event handler %p", info);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ // ALOGD("register_vendor_handler: handle = %p", handle);
+ if (info->num_event_cb < info->alloc_event_cb) {
+ info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
+ info->event_cb[info->num_event_cb].vendor_id = id;
+ info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ /*
+ ALOGI("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
+ arg, func, id, subcmd, info->num_event_cb);*/
+ info->num_event_cb++;
+ result = WIFI_SUCCESS;
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return result;
+}
+
+void wifi_unregister_handler(wifi_handle handle, int cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
+ return;
+ }
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (info->event_cb[i].nl_cmd == cmd) {
+ /*
+ ALOGI("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
+ info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);*/
+
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i - 1) * sizeof(cb_info));
+ info->num_event_cb--;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+
+ if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
+ && info->event_cb[i].vendor_id == id
+ && info->event_cb[i].vendor_subcmd == subcmd) {
+ /*
+ ALOGI("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
+ info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);*/
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i - 1) * sizeof(cb_info));
+ info->num_event_cb--;
+ break;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+}
+
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ //ALOGD("registering command %d", id);
+
+ wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
+
+ if (info->num_cmd < info->alloc_cmd) {
+ info->cmd[info->num_cmd].id = id;
+ info->cmd[info->num_cmd].cmd = cmd;
+ //ALOGI("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
+ info->num_cmd++;
+ result = WIFI_SUCCESS;
+ }
+
+ return result;
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+ hal_info *info = (hal_info *)handle;
+
+ //ALOGD("un-registering command %d", id);
+
+ WifiCommand *cmd = NULL;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].id == id) {
+ cmd = info->cmd[i].cmd;
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+ info->num_cmd--;
+ //ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);
+ break;
+ }
+ }
+
+ return cmd;
+}
+
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
+{
+ hal_info *info = (hal_info *)handle;
+
+ WifiCommand *cmd = NULL;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].id == id) {
+ cmd = info->cmd[i].cmd;
+ break;
+ }
+ }
+
+ return cmd;
+}
+
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].cmd == cmd) {
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+ info->num_cmd--;
+ //ALOGI("Successfully removed command %d: %p from %d", id, cmd, i);
+ break;
+ }
+ }
+}
+
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ //ALOGD("Cancel WifiCommand = %p", cmd);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
diff --git a/common.h b/common.h
new file mode 100755
index 0000000..7f270a3
--- /dev/null
+++ b/common.h
@@ -0,0 +1,302 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_COMMON_H__
+#define __WIFI_HAL_COMMON_H__
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define SOCKET_BUFFER_SIZE (32768U)
+#define RECV_BUF_SIZE (4096)
+#define DEFAULT_EVENT_CB_SIZE (64)
+#define DEFAULT_CMD_SIZE (64)
+#define DOT11_OUI_LEN 3
+
+typedef struct {
+ int num_bssid;
+ mac_addr bssids[MAX_BLACKLIST_BSSID];
+} wifi_bssid_params;
+
+/*
+ Vendor OUI - This is a unique identifier that identifies organization. Lets
+ code Android specific functions with Google OUI; although vendors can do more
+ with their own OUI's as well.
+ */
+
+const uint32_t GOOGLE_OUI = 0x001A11;
+/* TODO: define vendor OUI here */
+
+typedef enum {
+
+ GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+ GSCAN_ATTRIBUTE_BASE_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ GSCAN_ATTRIBUTE_BUCKET_ID,
+ GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+ GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+ GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS,
+ GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+ GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
+ GSCAN_ATTRIBUTE_REPORT_EVENTS,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
+ GSCAN_ATTRIBUTE_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_CHANNEL_LIST,
+ GSCAN_ATTRIBUTE_SCAN_ID,
+ GSCAN_ATTRIBUTE_SCAN_FLAGS,
+ GSCAN_ATTRIBUTE_SCAN_BUCKET_BIT,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_SSID = 40,
+ GSCAN_ATTRIBUTE_BSSID,
+ GSCAN_ATTRIBUTE_CHANNEL,
+ GSCAN_ATTRIBUTE_RSSI,
+ GSCAN_ATTRIBUTE_TIMESTAMP,
+ GSCAN_ATTRIBUTE_RTT,
+ GSCAN_ATTRIBUTE_RTTSD,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
+ GSCAN_ATTRIBUTE_RSSI_LOW,
+ GSCAN_ATTRIBUTE_RSSI_HIGH,
+ GSCAN_ATTRIBUTE_HOTLIST_ELEM,
+ GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+ GSCAN_ATTRIBUTE_CHANNEL_NUMBER,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+ GSCAN_ATTRIBUTE_MIN_BREACHING,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+
+ GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 70,
+ GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
+ GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+
+ GSCAN_ATTRIBUTE_NUM_BSSID,
+ GSCAN_ATTRIBUTE_BLACKLIST_BSSID,
+
+ GSCAN_ATTRIBUTE_MAX
+
+} GSCAN_ATTRIBUTE;
+
+/*
+ This enum defines ranges for various commands; commands themselves
+ can be defined in respective feature headers; i.e. find gscan command
+ definitions in gscan.cpp
+ */
+
+typedef enum {
+ /* don't use 0 as a valid subcommand */
+ VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+ /* define all vendor startup commands between 0x0 and 0x0FFF */
+ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
+
+ /* define all GScan related commands between 0x1000 and 0x10FF */
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
+
+ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
+
+ /* define all RTT related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
+
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
+
+ /* define all Logger related commands between 0x1400 and 0x14FF */
+ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
+ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF,
+
+ /* define all wifi offload related commands between 0x1400 and 0x14FF */
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1400,
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x14FF,
+
+ /* Range for NAN commands */
+ ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1500,
+ ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x15FF,
+ /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+typedef enum {
+ SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+ SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS,
+ SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN,
+ SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN,
+ SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST,
+ SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST,
+ SLSI_NL80211_VENDOR_SUBCMD_GET_HOTLIST_RESULTS,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE,
+ SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS,
+ SLSI_NL80211_VENDOR_SUBCMD_START_KEEP_ALIVE_OFFLOAD,
+ SLSI_NL80211_VENDOR_SUBCMD_STOP_KEEP_ALIVE_OFFLOAD,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_BLACKLIST,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_EPNO_LIST,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_HS_LIST,
+ SLSI_NL80211_VENDOR_SUBCMD_RESET_HS_LIST,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_RSSI_MONITOR,
+ SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO,
+ SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO,
+ SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO,
+ SLSI_NL80211_VENDOR_SUBCMD_GET_FEATURE_SET,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_COUNTRY_CODE,
+ SLSI_NL80211_VENDOR_SUBCMD_CONFIGURE_ND_OFFLOAD,
+ SLSI_NL80211_VENDOR_SUBCMD_GET_ROAMING_CAPABILITIES,
+ SLSI_NL80211_VENDOR_SUBCMD_SET_ROAMING_STATE,
+
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_ENABLE = ANDROID_NL80211_SUBCMD_NAN_RANGE_START,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_DISABLE,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISH,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISHCANCEL,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBE,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBECANCEL,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_TXFOLLOWUP,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_CONFIG,
+ SLSI_NL80211_VENDOR_SUBCMD_NAN_CAPABILITIES,
+ SLSI_NL80211_VENDOR_SUBCMD_RTT_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+ SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_START,
+ SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_CANCEL
+} WIFI_SUB_COMMAND;
+
+typedef enum {
+ GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
+ GSCAN_EVENT_HOTLIST_RESULTS_FOUND,
+ GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
+ GSCAN_EVENT_FULL_SCAN_RESULTS,
+ GSCAN_EVENT_COMPLETE_SCAN,
+ GSCAN_EVENT_HOTLIST_RESULTS_LOST,
+ WIFI_SUBCMD_KEY_MGMT_ROAM_AUTH, /* Handled by supplicant. not in Wifi-HAL */
+ WIFI_HANGED_EVENT,
+ WIFI_EPNO_EVENT,
+ WIFI_HOTSPOT_MATCH,
+ WIFI_RSSI_REPORT_EVENT,
+ ENHANCE_LOGGER_RING_EVENT,
+ ENHANCE_LOGGER_MEM_DUMP_EVENT,
+ /* NAN events start */
+ SLSI_NAN_EVENT_RESPONSE,
+ SLSI_NAN_EVENT_PUBLISH_TERMINATED,
+ SLSI_NAN_EVENT_MATCH,
+ SLSI_NAN_EVENT_MATCH_EXPIRED,
+ SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED,
+ SLSI_NAN_EVENT_FOLLOWUP,
+ SLSI_NAN_EVENT_DISCOVERY_ENGINE,
+ SLSI_NAN_EVENT_DISABLED,
+ /* NAN events end */
+ SLSI_RTT_RESULT_EVENT,
+ SLSI_RTT_EVENT_COMPLETE
+
+} WIFI_EVENT;
+
+typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
+
+class WifiCommand;
+
+typedef struct {
+ int nl_cmd;
+ uint32_t vendor_id;
+ int vendor_subcmd;
+ nl_recvmsg_msg_cb_t cb_func;
+ void *cb_arg;
+} cb_info;
+
+typedef struct {
+ wifi_request_id id;
+ WifiCommand *cmd;
+} cmd_info;
+
+typedef struct {
+ wifi_handle handle; // handle to wifi data
+ char name[8+1]; // interface name + trailing null
+ int id; // id to use when talking to driver
+} interface_info;
+
+typedef struct {
+
+ struct nl_sock *cmd_sock; // command socket object
+ struct nl_sock *event_sock; // event socket object
+ int nl80211_family_id; // family id for 80211 driver
+ int cleanup_socks[2]; // sockets used to implement wifi_cleanup
+
+ bool in_event_loop; // Indicates that event loop is active
+ bool clean_up; // Indication to clean up the socket
+
+ wifi_internal_event_handler event_handler; // default event handler
+ wifi_cleaned_up_handler cleaned_up_handler; // socket cleaned up handler
+
+ cb_info *event_cb; // event callbacks
+ int num_event_cb; // number of event callbacks
+ int alloc_event_cb; // number of allocated callback objects
+ pthread_mutex_t cb_lock; // mutex for the event_cb access
+
+ cmd_info *cmd; // Outstanding commands
+ int num_cmd; // number of commands
+ int alloc_cmd; // number of commands allocated
+
+ interface_info **interfaces; // array of interfaces
+ int num_interfaces; // number of interfaces
+
+
+ // add other details
+} hal_info;
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
+
+void wifi_unregister_handler(wifi_handle handle, int cmd);
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);
+WifiCommand *wifi_get_cmd(wifi_handle handle, int id);
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);
+wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
+
+interface_info *getIfaceInfo(wifi_interface_handle);
+wifi_handle getWifiHandle(wifi_interface_handle handle);
+hal_info *getHalInfo(wifi_handle handle);
+hal_info *getHalInfo(wifi_interface_handle handle);
+wifi_handle getWifiHandle(hal_info *info);
+wifi_interface_handle getIfaceHandle(interface_info *info);
+
+
+// some common macros
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+#define NULL_CHECK_RETURN(ptr, str, ret) \
+ do { \
+ if (!(ptr)) { \
+ ALOGE("%s(): null pointer - #ptr (%s)\n", __FUNCTION__, str); \
+ return ret; \
+ } \
+ } while (0)
+#endif
+
diff --git a/cpp_bindings.cpp b/cpp_bindings.cpp
new file mode 100755
index 0000000..5ab68b1
--- /dev/null
+++ b/cpp_bindings.cpp
@@ -0,0 +1,694 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+#include <stdarg.h>
+
+#include <ctype.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+void appendFmt(char *buf, int &offset, const char *fmt, ...)
+{
+ va_list params;
+ va_start(params, fmt);
+ offset += vsprintf(buf + offset, fmt, params);
+ va_end(params);
+}
+
+#define C2S(x) case x: return #x;
+
+static const char *cmdToString(int cmd)
+{
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ C2S(NL80211_CMD_VENDOR)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+}
+
+const char *attributeToString(int attribute)
+{
+ switch (attribute) {
+ C2S(NL80211_ATTR_UNSPEC)
+
+ C2S(NL80211_ATTR_WIPHY)
+ C2S(NL80211_ATTR_WIPHY_NAME)
+
+ C2S(NL80211_ATTR_IFINDEX)
+ C2S(NL80211_ATTR_IFNAME)
+ C2S(NL80211_ATTR_IFTYPE)
+
+ C2S(NL80211_ATTR_MAC)
+
+ C2S(NL80211_ATTR_KEY_DATA)
+ C2S(NL80211_ATTR_KEY_IDX)
+ C2S(NL80211_ATTR_KEY_CIPHER)
+ C2S(NL80211_ATTR_KEY_SEQ)
+ C2S(NL80211_ATTR_KEY_DEFAULT)
+
+ C2S(NL80211_ATTR_BEACON_INTERVAL)
+ C2S(NL80211_ATTR_DTIM_PERIOD)
+ C2S(NL80211_ATTR_BEACON_HEAD)
+ C2S(NL80211_ATTR_BEACON_TAIL)
+
+ C2S(NL80211_ATTR_STA_AID)
+ C2S(NL80211_ATTR_STA_FLAGS)
+ C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
+ C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
+ C2S(NL80211_ATTR_STA_VLAN)
+ C2S(NL80211_ATTR_STA_INFO)
+
+ C2S(NL80211_ATTR_WIPHY_BANDS)
+
+ C2S(NL80211_ATTR_MNTR_FLAGS)
+
+ C2S(NL80211_ATTR_MESH_ID)
+ C2S(NL80211_ATTR_STA_PLINK_ACTION)
+ C2S(NL80211_ATTR_MPATH_NEXT_HOP)
+ C2S(NL80211_ATTR_MPATH_INFO)
+
+ C2S(NL80211_ATTR_BSS_CTS_PROT)
+ C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
+ C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
+
+ C2S(NL80211_ATTR_HT_CAPABILITY)
+
+ C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
+
+ C2S(NL80211_ATTR_REG_ALPHA2)
+ C2S(NL80211_ATTR_REG_RULES)
+
+ C2S(NL80211_ATTR_MESH_CONFIG)
+
+ C2S(NL80211_ATTR_BSS_BASIC_RATES)
+
+ C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
+ C2S(NL80211_ATTR_WIPHY_FREQ)
+ C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
+
+ C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
+
+ C2S(NL80211_ATTR_MGMT_SUBTYPE)
+ C2S(NL80211_ATTR_IE)
+
+ C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
+
+ C2S(NL80211_ATTR_SCAN_FREQUENCIES)
+ C2S(NL80211_ATTR_SCAN_SSIDS)
+ C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
+ C2S(NL80211_ATTR_BSS)
+
+ C2S(NL80211_ATTR_REG_INITIATOR)
+ C2S(NL80211_ATTR_REG_TYPE)
+
+ C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
+
+ C2S(NL80211_ATTR_FRAME)
+ C2S(NL80211_ATTR_SSID)
+ C2S(NL80211_ATTR_AUTH_TYPE)
+ C2S(NL80211_ATTR_REASON_CODE)
+
+ C2S(NL80211_ATTR_KEY_TYPE)
+
+ C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
+ C2S(NL80211_ATTR_CIPHER_SUITES)
+
+ C2S(NL80211_ATTR_FREQ_BEFORE)
+ C2S(NL80211_ATTR_FREQ_AFTER)
+
+ C2S(NL80211_ATTR_FREQ_FIXED)
+
+
+ C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
+ C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
+ C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
+ C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
+
+ C2S(NL80211_ATTR_TIMED_OUT)
+
+ C2S(NL80211_ATTR_USE_MFP)
+
+ C2S(NL80211_ATTR_STA_FLAGS2)
+
+ C2S(NL80211_ATTR_CONTROL_PORT)
+
+ C2S(NL80211_ATTR_TESTDATA)
+
+ C2S(NL80211_ATTR_PRIVACY)
+
+ C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
+ C2S(NL80211_ATTR_STATUS_CODE)
+
+ C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
+ C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
+ C2S(NL80211_ATTR_WPA_VERSIONS)
+ C2S(NL80211_ATTR_AKM_SUITES)
+
+ C2S(NL80211_ATTR_REQ_IE)
+ C2S(NL80211_ATTR_RESP_IE)
+
+ C2S(NL80211_ATTR_PREV_BSSID)
+
+ C2S(NL80211_ATTR_KEY)
+ C2S(NL80211_ATTR_KEYS)
+
+ C2S(NL80211_ATTR_PID)
+
+ C2S(NL80211_ATTR_4ADDR)
+
+ C2S(NL80211_ATTR_SURVEY_INFO)
+
+ C2S(NL80211_ATTR_PMKID)
+ C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
+
+ C2S(NL80211_ATTR_DURATION)
+
+ C2S(NL80211_ATTR_COOKIE)
+
+ C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
+
+ C2S(NL80211_ATTR_TX_RATES)
+
+ C2S(NL80211_ATTR_FRAME_MATCH)
+
+ C2S(NL80211_ATTR_ACK)
+
+ C2S(NL80211_ATTR_PS_STATE)
+
+ C2S(NL80211_ATTR_CQM)
+
+ C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
+
+ C2S(NL80211_ATTR_AP_ISOLATE)
+
+ C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
+ C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
+
+ C2S(NL80211_ATTR_TX_FRAME_TYPES)
+ C2S(NL80211_ATTR_RX_FRAME_TYPES)
+ C2S(NL80211_ATTR_FRAME_TYPE)
+
+ C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
+
+ C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
+
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
+
+ C2S(NL80211_ATTR_MCAST_RATE)
+
+ C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
+
+ C2S(NL80211_ATTR_BSS_HT_OPMODE)
+
+ C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
+
+ C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
+
+ C2S(NL80211_ATTR_MESH_SETUP)
+
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
+ C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
+
+ C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
+ C2S(NL80211_ATTR_STA_PLINK_STATE)
+
+ C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
+ C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
+
+ C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
+
+ C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
+ C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
+
+ C2S(NL80211_ATTR_REKEY_DATA)
+
+ C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
+ C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
+
+ C2S(NL80211_ATTR_SCAN_SUPP_RATES)
+
+ C2S(NL80211_ATTR_HIDDEN_SSID)
+
+ C2S(NL80211_ATTR_IE_PROBE_RESP)
+ C2S(NL80211_ATTR_IE_ASSOC_RESP)
+
+ C2S(NL80211_ATTR_STA_WME)
+ C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
+
+ C2S(NL80211_ATTR_ROAM_SUPPORT)
+
+ C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
+ C2S(NL80211_ATTR_MAX_MATCH_SETS)
+
+ C2S(NL80211_ATTR_PMKSA_CANDIDATE)
+
+ C2S(NL80211_ATTR_TX_NO_CCK_RATE)
+
+ C2S(NL80211_ATTR_TDLS_ACTION)
+ C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
+ C2S(NL80211_ATTR_TDLS_OPERATION)
+ C2S(NL80211_ATTR_TDLS_SUPPORT)
+ C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
+
+ C2S(NL80211_ATTR_DEVICE_AP_SME)
+
+ C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
+
+ C2S(NL80211_ATTR_FEATURE_FLAGS)
+
+ C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
+
+ C2S(NL80211_ATTR_PROBE_RESP)
+
+ C2S(NL80211_ATTR_DFS_REGION)
+
+ C2S(NL80211_ATTR_DISABLE_HT)
+ C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
+
+ C2S(NL80211_ATTR_NOACK_MAP)
+
+ C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
+
+ C2S(NL80211_ATTR_RX_SIGNAL_DBM)
+
+ C2S(NL80211_ATTR_BG_SCAN_PERIOD)
+
+ C2S(NL80211_ATTR_WDEV)
+
+ C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
+
+ C2S(NL80211_ATTR_CONN_FAILED_REASON)
+
+ C2S(NL80211_ATTR_SAE_DATA)
+
+ C2S(NL80211_ATTR_VHT_CAPABILITY)
+
+ C2S(NL80211_ATTR_SCAN_FLAGS)
+
+ C2S(NL80211_ATTR_CHANNEL_WIDTH)
+ C2S(NL80211_ATTR_CENTER_FREQ1)
+ C2S(NL80211_ATTR_CENTER_FREQ2)
+
+ C2S(NL80211_ATTR_P2P_CTWINDOW)
+ C2S(NL80211_ATTR_P2P_OPPPS)
+
+ C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
+
+ C2S(NL80211_ATTR_ACL_POLICY)
+
+ C2S(NL80211_ATTR_MAC_ADDRS)
+
+ C2S(NL80211_ATTR_MAC_ACL_MAX)
+
+ C2S(NL80211_ATTR_RADAR_EVENT)
+
+ C2S(NL80211_ATTR_EXT_CAPA)
+ C2S(NL80211_ATTR_EXT_CAPA_MASK)
+
+ C2S(NL80211_ATTR_STA_CAPABILITY)
+ C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
+
+ C2S(NL80211_ATTR_PROTOCOL_FEATURES)
+ C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
+
+ C2S(NL80211_ATTR_DISABLE_VHT)
+ C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
+
+ C2S(NL80211_ATTR_MDID)
+ C2S(NL80211_ATTR_IE_RIC)
+
+ C2S(NL80211_ATTR_CRIT_PROT_ID)
+ C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
+
+ C2S(NL80211_ATTR_PEER_AID)
+
+
+ //S(NL80211_ATTR_VENDOR_ID)
+ C2S(NL80211_ATTR_VENDOR_SUBCMD)
+ C2S(NL80211_ATTR_VENDOR_DATA)
+ C2S(NL80211_ATTR_VENDOR_EVENTS)
+
+ default:
+ return "NL80211_ATTR_UNKNOWN";
+ }
+}
+
+void WifiEvent::log() {
+ parse();
+
+ byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
+ int len = genlmsg_attrlen(mHeader, 0);
+ ALOGD("cmd = %s, len = %d", get_cmdString(), len);
+ ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
+
+ for (int i = 0; i < len; i += 16) {
+ char line[81];
+ int linelen = min(16, len - i);
+ int offset = 0;
+ appendFmt(line, offset, "%02x", data[i]);
+ for (int j = 1; j < linelen; j++) {
+ appendFmt(line, offset, " %02x", data[i+j]);
+ }
+
+ for (int j = linelen; j < 16; j++) {
+ appendFmt(line, offset, " ");
+ }
+
+ line[23] = '-';
+
+ appendFmt(line, offset, " ");
+
+ for (int j = 0; j < linelen; j++) {
+ if (isprint(data[i+j])) {
+ appendFmt(line, offset, "%c", data[i+j]);
+ } else {
+ appendFmt(line, offset, "-");
+ }
+ }
+
+ ALOGD("%s", line);
+ }
+
+ for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
+ if (mAttributes[i] != NULL) {
+ ALOGD("found attribute %s", attributeToString(i));
+ }
+ }
+}
+
+const char *WifiEvent::get_cmdString() {
+ return cmdToString(get_cmd());
+}
+
+
+int WifiEvent::parse() {
+ if (mHeader != NULL) {
+ return WIFI_SUCCESS;
+ }
+ mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
+ int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
+ genlmsg_attrlen(mHeader, 0), NULL);
+
+ return result;
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+ mMsg = nlmsg_alloc();
+ if (mMsg != NULL) {
+ genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
+ hdrlen, flags, cmd, /* version = */ 0);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+int WifiRequest::create(uint32_t id, int subcmd) {
+ int res = create(NL80211_CMD_VENDOR);
+ if (res < 0) {
+ return res;
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_ID, id);
+ if (res < 0) {
+ return res;
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
+ if (res < 0) {
+ return res;
+ }
+
+ if (mIface != -1) {
+ res = set_iface_id(mIface);
+ }
+
+ return res;
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+int WifiCommand::requestResponse() {
+ int err = create(); /* create the message */
+ if (err < 0) {
+ return err;
+ }
+
+ return requestResponse(mMsg);
+}
+
+int WifiCommand::requestResponse(WifiRequest& request) {
+ int err = 0;
+
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(mInfo->cmd_sock, request.getMessage()); /* send message */
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, response_handler, this);
+
+ while (err > 0) { /* wait for reply */
+ int res = nl_recvmsgs(mInfo->cmd_sock, cb);
+ if (res) {
+ ALOGE("nl80211: %s->nl_recvmsgs failed: %d", __func__, res);
+ }
+ }
+out:
+ nl_cb_put(cb);
+ return err;
+}
+
+int WifiCommand::requestEvent(int cmd) {
+
+ int res = wifi_register_handler(wifiHandle(), cmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_handler(wifiHandle(), cmd);
+ return res;
+}
+
+int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
+
+ int res = wifi_register_vendor_handler(wifiHandle(), id, subcmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+ return res;
+}
+
+/* Event handlers */
+int WifiCommand::response_handler(struct nl_msg *msg, void *arg) {
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent reply(msg);
+ int res = reply.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse reply message = %d", res);
+ return NL_SKIP;
+ } else {
+ // reply.log();
+ return cmd->handleResponse(reply);
+ }
+}
+
+int WifiCommand::event_handler(struct nl_msg *msg, void *arg) {
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse event = %d", res);
+ res = NL_SKIP;
+ } else {
+ res = cmd->handleEvent(event);
+ }
+
+ cmd->mCondition.signal();
+ return res;
+}
+
+/* Other event handlers */
+int WifiCommand::valid_handler(struct nl_msg *msg, void *arg) {
+ int *err = (int *)arg;
+ *err = 0;
+ return NL_SKIP;
+}
+
+int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
+ int *err = (int *)arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
+ int *ret = (int *)arg;
+ *ret = err->error;
+
+ /*ALOGD("error_handler received : %d", err->error);*/
+ return NL_SKIP;
+}
diff --git a/cpp_bindings.h b/cpp_bindings.h
new file mode 100755
index 0000000..d1e1e5a
--- /dev/null
+++ b/cpp_bindings.h
@@ -0,0 +1,347 @@
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "sync.h"
+
+class WifiEvent
+{
+ /* TODO: remove this when nl headers are updated */
+ static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
+private:
+ struct nl_msg *mMsg;
+ struct genlmsghdr *mHeader;
+ struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
+
+public:
+ WifiEvent(nl_msg *msg) {
+ mMsg = msg;
+ mHeader = NULL;
+ memset(mAttributes, 0, sizeof(mAttributes));
+ }
+ ~WifiEvent() {
+ /* don't destroy mMsg; it doesn't belong to us */
+ }
+
+ void log();
+
+ int parse();
+
+ genlmsghdr *header() {
+ return mHeader;
+ }
+
+ int get_cmd() {
+ return mHeader->cmd;
+ }
+
+ int get_vendor_id() {
+ return get_u32(NL80211_ATTR_VENDOR_ID);
+ }
+
+ int get_vendor_subcmd() {
+ return get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ }
+
+ void *get_vendor_data() {
+ return get_data(NL80211_ATTR_VENDOR_DATA);
+ }
+
+ int get_vendor_data_len() {
+ return get_len(NL80211_ATTR_VENDOR_DATA);
+ }
+
+ const char *get_cmdString();
+
+ nlattr ** attributes() {
+ return mAttributes;
+ }
+
+ nlattr *get_attribute(int attribute) {
+ return mAttributes[attribute];
+ }
+
+ uint8_t get_u8(int attribute) {
+ return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;
+ }
+
+ uint16_t get_u16(int attribute) {
+ return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;
+ }
+
+ uint32_t get_u32(int attribute) {
+ return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;
+ }
+
+ uint64_t get_u64(int attribute) {
+ return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;
+ }
+
+ int get_len(int attribute) {
+ return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;
+ }
+
+ void *get_data(int attribute) {
+ return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;
+ }
+
+private:
+ WifiEvent(const WifiEvent&); // hide copy constructor to prevent copies
+};
+
+class nl_iterator {
+ struct nlattr *pos;
+ int rem;
+public:
+ nl_iterator(struct nlattr *attr) {
+ pos = (struct nlattr *)nla_data(attr);
+ rem = nla_len(attr);
+ }
+ bool has_next() {
+ return nla_ok(pos, rem);
+ }
+ void next() {
+ pos = (struct nlattr *)nla_next(pos, &(rem));
+ }
+ struct nlattr *get() {
+ return pos;
+ }
+ uint16_t get_type() {
+ return pos->nla_type;
+ }
+ uint8_t get_u8() {
+ return nla_get_u8(pos);
+ }
+ uint16_t get_u16() {
+ return nla_get_u16(pos);
+ }
+ uint32_t get_u32() {
+ return nla_get_u32(pos);
+ }
+ uint64_t get_u64() {
+ return nla_get_u64(pos);
+ }
+ void* get_data() {
+ return nla_data(pos);
+ }
+ int get_len() {
+ return nla_len(pos);
+ }
+private:
+ nl_iterator(const nl_iterator&); // hide copy constructor to prevent copies
+};
+
+class WifiRequest
+{
+private:
+ int mFamily;
+ int mIface;
+ struct nl_msg *mMsg;
+
+public:
+ WifiRequest(int family) {
+ mMsg = NULL;
+ mFamily = family;
+ mIface = -1;
+ }
+
+ WifiRequest(int family, int iface) {
+ mMsg = NULL;
+ mFamily = family;
+ mIface = iface;
+ }
+
+ ~WifiRequest() {
+ destroy();
+ }
+
+ void destroy() {
+ if (mMsg) {
+ nlmsg_free(mMsg);
+ mMsg = NULL;
+ }
+ }
+
+ nl_msg *getMessage() {
+ return mMsg;
+ }
+
+ /* Command assembly helpers */
+ int create(int family, uint8_t cmd, int flags, int hdrlen);
+ int create(uint8_t cmd) {
+ return create(mFamily, cmd, 0, 0);
+ }
+
+ int create(uint32_t id, int subcmd);
+
+ int put(int attribute, void *ptr, unsigned len) {
+ return nla_put(mMsg, attribute, len, ptr);
+ }
+ int put_u8(int attribute, uint8_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u16(int attribute, uint16_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u32(int attribute, uint32_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u64(int attribute, uint64_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_string(int attribute, const char *value) {
+ return nla_put(mMsg, attribute, strlen(value) + 1, value);
+ }
+ int put_addr(int attribute, mac_addr value) {
+ return nla_put(mMsg, attribute, sizeof(mac_addr), value);
+ }
+
+ struct nlattr * attr_start(int attribute) {
+ return nla_nest_start(mMsg, attribute);
+ }
+ void attr_end(struct nlattr *attr) {
+ nla_nest_end(mMsg, attr);
+ }
+
+ int set_iface_id(int ifindex) {
+ return put_u32(NL80211_ATTR_IFINDEX, ifindex);
+ }
+private:
+ WifiRequest(const WifiRequest&); // hide copy constructor to prevent copies
+
+};
+
+class WifiCommand
+{
+protected:
+ hal_info *mInfo;
+ WifiRequest mMsg;
+ Condition mCondition;
+ wifi_request_id mId;
+ interface_info *mIfaceInfo;
+ int mRefs;
+public:
+ WifiCommand(wifi_handle handle, wifi_request_id id)
+ : mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)
+ {
+ mIfaceInfo = NULL;
+ mInfo = getHalInfo(handle);
+ // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+ }
+
+ WifiCommand(wifi_interface_handle iface, wifi_request_id id)
+ : mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id), mId(id), mRefs(1)
+ {
+ mIfaceInfo = getIfaceInfo(iface);
+ mInfo = getHalInfo(iface);
+ // ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
+ }
+
+ virtual ~WifiCommand() {
+ // ALOGD("WifiCommand %p destroyed", this);
+ }
+
+ wifi_request_id id() {
+ return mId;
+ }
+
+ virtual void addRef() {
+ __sync_add_and_fetch(&mRefs, 1);
+ //int refs = __sync_add_and_fetch(&mRefs, 1);
+ // ALOGD("addRef: WifiCommand %p has %d references", this, refs);
+ }
+
+ virtual void releaseRef() {
+ int refs = __sync_sub_and_fetch(&mRefs, 1);
+ if (refs == 0) {
+ delete this;
+ } else {
+ // ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);
+ }
+ }
+
+ virtual int create() {
+ /* by default there is no way to cancel */
+ //ALOGD("WifiCommand %p can't be created", this);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ virtual int cancel() {
+ /* by default there is no way to cancel */
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ int requestResponse();
+ int requestEvent(int cmd);
+ int requestVendorEvent(uint32_t id, int subcmd);
+ int requestResponse(WifiRequest& request);
+
+protected:
+ wifi_handle wifiHandle() {
+ return getWifiHandle(mInfo);
+ }
+
+ wifi_interface_handle ifaceHandle() {
+ return getIfaceHandle(mIfaceInfo);
+ }
+
+ int familyId() {
+ return mInfo->nl80211_family_id;
+ }
+
+ int ifaceId() {
+ return mIfaceInfo->id;
+ }
+
+ /* Override this method to parse reply and dig out data; save it in the object */
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGI("skipping a response");
+ return NL_SKIP;
+ }
+
+ /* Override this method to parse event and dig out data; save it in the object */
+ virtual int handleEvent(WifiEvent& event) {
+ ALOGI("skipping an event");
+ return NL_SKIP;
+ }
+
+ int registerHandler(int cmd) {
+ return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);
+ }
+
+ void unregisterHandler(int cmd) {
+ wifi_unregister_handler(wifiHandle(), cmd);
+ }
+
+ int registerVendorHandler(uint32_t id, int subcmd) {
+ return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
+ }
+
+ void unregisterVendorHandler(uint32_t id, int subcmd) {
+ wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
+ }
+
+private:
+ WifiCommand(const WifiCommand& ); // hide copy constructor to prevent copies
+
+ /* Event handling */
+ static int response_handler(struct nl_msg *msg, void *arg);
+
+ static int event_handler(struct nl_msg *msg, void *arg);
+
+ /* Other event handlers */
+ static int valid_handler(struct nl_msg *msg, void *arg);
+
+ static int ack_handler(struct nl_msg *msg, void *arg);
+
+ static int finish_handler(struct nl_msg *msg, void *arg);
+
+ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
+};
+
+/* nl message processing macros (required to pass C++ type checks) */
+
+#define for_each_attr(pos, nla, rem) \
+ for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
+ nla_ok(pos, rem); \
+ pos = (nlattr *)nla_next(pos, &(rem)))
+
diff --git a/gscan.cpp b/gscan.cpp
new file mode 100755
index 0000000..89d6dd6
--- /dev/null
+++ b/gscan.cpp
@@ -0,0 +1,1350 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+ EPNO_ATTRIBUTE_MINIMUM_5G_RSSI,
+ EPNO_ATTRIBUTE_MINIMUM_2G_RSSI,
+ EPNO_ATTRIBUTE_INITIAL_SCORE_MAX,
+ EPNO_ATTRIBUTE_CUR_CONN_BONUS,
+ EPNO_ATTRIBUTE_SAME_NETWORK_BONUS,
+ EPNO_ATTRIBUTE_SECURE_BONUS,
+ EPNO_ATTRIBUTE_5G_BONUS,
+ EPNO_ATTRIBUTE_SSID_NUM,
+ EPNO_ATTRIBUTE_SSID_LIST,
+ EPNO_ATTRIBUTE_SSID,
+ EPNO_ATTRIBUTE_SSID_LEN,
+ EPNO_ATTRIBUTE_FLAGS,
+ EPNO_ATTRIBUTE_AUTH,
+ EPNO_ATTRIBUTE_MAX
+} EPNO_ATTRIBUTE;
+
+typedef enum {
+ EPNO_ATTRIBUTE_HS_PARAM_LIST,
+ EPNO_ATTRIBUTE_HS_NUM,
+ EPNO_ATTRIBUTE_HS_ID,
+ EPNO_ATTRIBUTE_HS_REALM,
+ EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS,
+ EPNO_ATTRIBUTE_HS_PLMN,
+ EPNO_ATTRIBUTE_HS_MAX
+} EPNO_HS_ATTRIBUTE;
+
+
+class GetCapabilitiesCommand : public WifiCommand
+{
+ wifi_gscan_capabilities *mCapabilities;
+public:
+ GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
+ : WifiCommand(iface, 0), mCapabilities(capabitlites)
+ {
+ memset(mCapabilities, 0, sizeof(*mCapabilities));
+ }
+
+ virtual int create() {
+ int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES);
+ if (ret < 0) {
+ ALOGE("NL message creation failed");
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+
+ return NL_OK;
+ }
+};
+
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+ wifi_gscan_capabilities *capabilities)
+{
+ GetCapabilitiesCommand command(handle, capabilities);
+ return (wifi_error) command.requestResponse();
+}
+
+class GetChannelListCommand : public WifiCommand
+{
+ wifi_channel *channels;
+ int max_channels;
+ int *num_channels;
+ int band;
+public:
+ GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
+ int num_max_ch, int band)
+ : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),
+ band(band)
+ {
+ memset(channels, 0, sizeof(wifi_channel) * max_channels);
+ }
+ virtual int create() {
+ int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int num_channels_to_copy = 0;
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetChannelList response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
+ num_channels_to_copy = it.get_u32();
+ /*ALOGD("Got channel list with %d channels", num_channels_to_copy);*/
+ if(num_channels_to_copy > max_channels)
+ num_channels_to_copy = max_channels;
+ *num_channels = num_channels_to_copy;
+ } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
+ memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
+ int band, int max_channels, wifi_channel *channels, int *num_channels)
+{
+ GetChannelListCommand command(handle, channels, num_channels,
+ max_channels, band);
+ return (wifi_error) command.requestResponse();
+}
+/////////////////////////////////////////////////////////////////////////////
+
+/* helper functions */
+
+/*
+static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
+{
+ memset(results, 0, sizeof(wifi_scan_result) * num);
+
+ int i = 0;
+ for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
+
+ nlattr *sc_data = (nlattr *) it.get_data();
+ wifi_scan_result *result = results + i;
+
+ for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
+ int type = it2.get_type();
+ if (type == GSCAN_ATTRIBUTE_SSID) {
+ strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
+ result->ssid[it2.get_len()] = 0;
+ } else if (type == GSCAN_ATTRIBUTE_BSSID) {
+ memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
+ } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
+ result->ts = it2.get_u64();
+ } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
+ result->ts = it2.get_u16();
+ } else if (type == GSCAN_ATTRIBUTE_RSSI) {
+ result->rssi = it2.get_u8();
+ } else if (type == GSCAN_ATTRIBUTE_RTT) {
+ result->rtt = it2.get_u64();
+ } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
+ result->rtt_sd = it2.get_u64();
+ }
+ }
+
+ }
+
+ if (i >= num) {
+ ALOGE("Got too many results; skipping some");
+ }
+
+ return i;
+}
+*/
+
+int createFeatureRequest(WifiRequest& request, int subcmd) {
+
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ return WIFI_SUCCESS;
+}
+
+class ScanCommand : public WifiCommand
+{
+ wifi_scan_cmd_params *mParams;
+ wifi_scan_result_handler mHandler;
+ static unsigned mGlobalFullScanBuckets;
+public:
+ ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
+ wifi_scan_result_handler handler)
+ : WifiCommand(iface, id), mParams(params), mHandler(handler)
+ { }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold_percent);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS, mParams->report_threshold_num_scans);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
+ if (result < 0) {
+ return result;
+ }
+
+ for (int i = 0; i < mParams->num_buckets; i++) {
+ nlattr * bucket = request.attr_start(i); // next bucket
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ mParams->buckets[i].band);
+ if (result < 0) {
+ return result;
+ }
+
+ if (mParams->buckets[i].report_events == 0) {
+ mParams->buckets[i].report_events = REPORT_EVENTS_EACH_SCAN;
+ }
+ result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
+ mParams->buckets[i].report_events);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ mParams->buckets[i].num_channels);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
+ mParams->buckets[i].base);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+ mParams->buckets[i].max_period);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
+ mParams->buckets[i].step_count);
+ if (result < 0) {
+ return result;
+ }
+
+ if (mParams->buckets[i].num_channels) {
+ nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
+ for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
+ result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
+ if (result < 0) {
+ return result;
+ }
+ }
+ request.attr_end(channels);
+ }
+
+ request.attr_end(bucket);
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createStartRequest(WifiRequest& request) {
+ return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
+ }
+
+ int createStopRequest(WifiRequest& request) {
+ return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);
+ }
+
+ int start() {
+ ALOGD("starting Gscan");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create setup request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+
+ int nBuckets = 0;
+ for (int i = 0; i < mParams->num_buckets; i++) {
+ if (mParams->buckets[i].report_events & REPORT_EVENTS_FULL_RESULTS) {
+ nBuckets++;
+ }
+ }
+
+ if (nBuckets != 0) {
+ ALOGI("Full scan requested with nBuckets = %d", nBuckets);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+ }
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to start scan; result = %d", result);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+ return result;
+ }
+
+
+ return result;
+ }
+
+ virtual int cancel() {
+ ALOGD("Stopping Gscan");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createStopRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop scan; result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
+
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ //event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ unsigned int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+
+ if(event_id == GSCAN_EVENT_COMPLETE_SCAN) {
+ if (vendor_data == NULL || len != 4) {
+ ALOGE("Scan complete type not mentioned!");
+ return NL_SKIP;
+ }
+ wifi_scan_event evt_type;
+
+ evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
+ if(*mHandler.on_scan_event)
+ (*mHandler.on_scan_event)(id(), evt_type);
+ } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
+ uint32_t bucket_scanned = 0;
+ wifi_scan_result *scan_result = NULL;
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_BUCKET_BIT) {
+ bucket_scanned = it.get_u32();
+ } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
+ if (it.get_len() >= (int)sizeof(*scan_result))
+ scan_result = (wifi_scan_result *)it.get_data();
+ }
+ }
+ if (scan_result) {
+ if(*mHandler.on_full_scan_result)
+ (*mHandler.on_full_scan_result)(id(), scan_result, bucket_scanned);
+/*
+ ALOGD("%-32s\t", scan_result->ssid);
+ ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", scan_result->bssid[0], scan_result->bssid[1],
+ scan_result->bssid[2], scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
+ ALOGD("%d\t", scan_result->rssi);
+ ALOGD("%d\t", scan_result->channel);
+ ALOGD("%lld\t", scan_result->ts);
+ ALOGD("%lld\t", scan_result->rtt);
+ ALOGD("%lld\n", scan_result->rtt_sd);
+*/
+ }
+ }
+ return NL_SKIP;
+ }
+};
+
+unsigned ScanCommand::mGlobalFullScanBuckets = 0;
+
+wifi_error wifi_start_gscan(
+ wifi_request_id id,
+ wifi_interface_handle iface,
+ wifi_scan_cmd_params params,
+ wifi_scan_result_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ ScanCommand *cmd = new ScanCommand(iface, id, ¶ms, handler);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ if(id == -1) {
+ wifi_scan_result_handler handler;
+ wifi_scan_cmd_params dummy_params;
+ memset(&handler, 0, sizeof(handler));
+
+ ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+class GetScanResultsCommand : public WifiCommand {
+ wifi_cached_scan_results *mScans;
+ int mMax;
+ int *mNum;
+ int mRetrieved;
+ byte mFlush;
+ int mCompleted;
+ static const int MAX_RESULTS = 320;
+ wifi_scan_result mScanResults[MAX_RESULTS];
+ int mNextScanResult;
+public:
+ GetScanResultsCommand(wifi_interface_handle iface, byte flush,
+ wifi_cached_scan_results *results, int max, int *num)
+ : WifiCommand(iface, -1), mScans(results), mMax(max), mNum(num),
+ mRetrieved(0), mFlush(flush), mCompleted(0)
+ {
+ memset(mScanResults,0,sizeof(mScanResults));
+ mNextScanResult = 0;
+ }
+
+ int createRequest(WifiRequest& request, int num, byte flush) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int execute() {
+ WifiRequest request(familyId(), ifaceId());
+
+ for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
+ int result = createRequest(request, (mMax - mRetrieved), mFlush);
+ if (result < 0) {
+ ALOGE("failed to create request");
+ return result;
+ }
+
+ int prev_retrieved = mRetrieved;
+
+ result = requestResponse(request);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to retrieve scan results; result = %d", result);
+ return result;
+ }
+
+ if (mRetrieved == prev_retrieved || mCompleted) {
+ /* no more items left to retrieve */
+ break;
+ }
+
+ request.destroy();
+ }
+
+ ALOGE("GetScanResults read %d results", mRetrieved);
+ *mNum = mRetrieved;
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetScanResults response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
+ mCompleted = it.get_u8();
+ //ALOGD("retrieved mCompleted flag : %d", mCompleted);
+ } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
+ int scan_id = 0, flags = 0, num = 0;
+ for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
+ if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
+ scan_id = it2.get_u32();
+ //ALOGD("retrieved scan_id : 0x%0x", scan_id);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
+ flags = it2.get_u8();
+ //ALOGD("retrieved scan_flags : 0x%0x", flags);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
+ num = it2.get_u32();
+ //ALOGD("retrieved num_results: %d", num);
+ } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
+ if (mRetrieved >= mMax) {
+ ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
+ break;
+ }
+ num = it2.get_len() / sizeof(wifi_scan_result);
+ num = min(MAX_RESULTS - mNextScanResult, num);
+ num = min((int)MAX_AP_CACHE_PER_SCAN, num);
+ memcpy(mScanResults + mNextScanResult, it2.get_data(),
+ sizeof(wifi_scan_result) * num);
+ /*
+ wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
+ for (int i = 0; i < num; i++) {
+ wifi_scan_result *result = results + i;
+ ALOGD("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i,
+ result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
+ result->bssid[3], result->bssid[4], result->bssid[5],
+ result->rssi);
+ }*/
+ mScans[mRetrieved].scan_id = scan_id;
+ mScans[mRetrieved].flags = flags;
+ mScans[mRetrieved].num_results = num;
+ //ALOGD("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
+ memcpy(mScans[mRetrieved].results,
+ &(mScanResults[mNextScanResult]), num * sizeof(wifi_scan_result));
+ mNextScanResult += num;
+ mRetrieved++;
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
+ int max, wifi_cached_scan_results *results, int *num) {
+ GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
+ return (wifi_error)cmd->execute();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+class BssidHotlistCommand : public WifiCommand
+{
+private:
+ wifi_bssid_hotlist_params mParams;
+ wifi_hotlist_ap_found_handler mHandler;
+ static const int MAX_RESULTS = 64;
+ wifi_scan_result mResults[MAX_RESULTS];
+public:
+ BssidHotlistCommand(wifi_interface_handle handle, int id,
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+ : WifiCommand(handle, id), mParams(params), mHandler(handler)
+ {
+ memset(mResults, 0, sizeof(mResults));
+ }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+ if (result < 0) {
+ return result;
+ }
+
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+ for (int i = 0; i < mParams.num_bssid; i++) {
+ nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createTeardownRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("Failed to execute hotlist setup request, result = %d", result);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
+ /* create set hotlist message with empty hotlist */
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ int event_id = event.get_vendor_subcmd();
+ //event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No scan results found");
+ return NL_SKIP;
+ }
+
+
+ int num = len / sizeof(wifi_scan_result);
+ num = min(MAX_RESULTS, num);
+ memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
+
+ if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
+ ALOGD("FOUND %d hotlist APs", num);
+ if (*mHandler.on_hotlist_ap_found)
+ (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
+ } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {
+ ALOGD("LOST %d hotlist APs", num);
+ if (*mHandler.on_hotlist_ap_lost)
+ (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
+ }
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SignificantWifiChangeCommand : public WifiCommand
+{
+ typedef struct {
+ mac_addr bssid; // BSSID
+ wifi_channel channel; // channel frequency in MHz
+ int num_rssi; // number of rssi samples
+ wifi_rssi rssi[8]; // RSSI history in db
+ } wifi_significant_change_result_internal;
+
+private:
+ wifi_significant_change_params mParams;
+ wifi_significant_change_handler mHandler;
+ static const int MAX_RESULTS = 64;
+ wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
+ wifi_significant_change_result *mResults[MAX_RESULTS];
+public:
+ SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
+ wifi_significant_change_params params, wifi_significant_change_handler handler)
+ : WifiCommand(handle, id), mParams(params), mHandler(handler)
+ {
+ memset(mResultsBuffer,0,sizeof(mResultsBuffer));
+ memset(mResults,0,sizeof(mResults));
+ }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
+ if (result < 0) {
+ return result;
+ }
+
+ struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
+
+ for (int i = 0; i < mParams.num_bssid; i++) {
+
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ request.attr_end(data);
+
+ return result;
+ }
+
+ int createTeardownRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE);
+ if (result < 0) {
+ return result;
+ }
+
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("failed to set significant wifi change %d", result);
+ return result;
+ }
+ registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
+
+ /* create set significant change monitor message with empty hotlist */
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createTeardownRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No scan results found");
+ return NL_SKIP;
+ }
+
+ typedef struct {
+ uint16_t channel;
+ mac_addr bssid;
+ int16_t rssi_history[8];
+ } ChangeInfo;
+
+ int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
+ ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
+
+ for (int i = 0; i < num; i++) {
+ memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
+ mResultsBuffer[i].channel = ci[i].channel;
+ /* Driver sends N samples and the rest 8-N are filled 0x7FFF
+ * N = no of rssi samples to average sent in significant change request. */
+ int num_rssi = 0;
+ for (int j = 0; j < 8; j++) {
+ if (ci[i].rssi_history[j] == 0x7FFF) {
+ num_rssi = j;
+ break;
+ }
+ mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
+ }
+ mResultsBuffer[i].num_rssi = num_rssi;
+ mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
+ }
+
+ if (num != 0) {
+ (*mHandler.on_significant_change)(id(), num, mResults);
+ } else {
+ ALOGW("No significant change reported");
+ }
+
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_significant_change_params params, wifi_significant_change_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
+ iface, id, params, handler);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+class ePNOCommand : public WifiCommand
+{
+private:
+ wifi_epno_params *epno_params;
+ wifi_epno_handler mHandler;
+ wifi_scan_result mResults;
+public:
+ ePNOCommand(wifi_interface_handle handle, int id,
+ wifi_epno_params *params, wifi_epno_handler handler)
+ : WifiCommand(handle, id), mHandler(handler)
+ {
+ epno_params = params;
+ memset(&mResults,0,sizeof(wifi_scan_result));
+ }
+
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_EPNO_LIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (epno_params == NULL) {
+ result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, 0);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+ result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_5G_RSSI, epno_params->min5GHz_rssi);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_2G_RSSI, epno_params->min24GHz_rssi);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(EPNO_ATTRIBUTE_INITIAL_SCORE_MAX, epno_params->initial_score_max);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_CUR_CONN_BONUS, epno_params->current_connection_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_SAME_NETWORK_BONUS, epno_params->same_network_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_SECURE_BONUS, epno_params->secure_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_5G_BONUS, epno_params->band5GHz_bonus);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, epno_params->num_networks);
+ if (result < 0) {
+ return result;
+ }
+
+ ALOGI("ePNO [min5GHz_rssi:%d min24GHz_rssi:%d initial_score_max:%d current_connection_bonus:%d same_network_bonus:%d secure_bonus:%d band5GHz_bonus:%d num_networks:%d]",
+ epno_params->min5GHz_rssi,
+ epno_params->min24GHz_rssi,
+ epno_params->initial_score_max,
+ epno_params->current_connection_bonus,
+ epno_params->same_network_bonus,
+ epno_params->secure_bonus,
+ epno_params->band5GHz_bonus,
+ epno_params->num_networks);
+
+ struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_SSID_LIST);
+ for (int i = 0; i < epno_params->num_networks; i++) {
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_u16(EPNO_ATTRIBUTE_FLAGS, epno_params->networks[i].flags);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_AUTH, epno_params->networks[i].auth_bit_field);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(EPNO_ATTRIBUTE_SSID_LEN, strlen(epno_params->networks[i].ssid));
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(EPNO_ATTRIBUTE_SSID, epno_params->networks[i].ssid, strlen(epno_params->networks[i].ssid));
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+
+ request.attr_end(attr);
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGI("ePNO num_network=%d", epno_params ? epno_params->num_networks : 0);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Failed: ePNO setup request, result = %d", result);
+ unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+ return result;
+ }
+
+ if (epno_params) {
+ registerVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+ }
+ return result;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
+ return 0;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ // event.log();
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("No scan results found");
+ return NL_SKIP;
+ }
+
+
+ mResults = *(wifi_scan_result *) event.get_vendor_data();
+ if (*mHandler.on_network_found)
+ (*mHandler.on_network_found)(id(), 1, &mResults);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_epno_list(wifi_request_id id,
+ wifi_interface_handle iface,
+ const wifi_epno_params *epno_params,
+ wifi_epno_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ePNOCommand *cmd = new ePNOCommand(iface, id, (wifi_epno_params *)epno_params, handler);
+ wifi_register_cmd(handle, id, cmd);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ }
+ return result;
+}
+
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ wifi_epno_handler handler;
+
+ handler.on_network_found = NULL;
+ ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler);
+ wifi_register_cmd(handle, id, cmd);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ }
+ return result;
+}
+
+class HsListCommand : public WifiCommand
+{
+ int num_hs;
+ wifi_passpoint_network *mNetworks;
+ wifi_passpoint_event_handler mHandler;
+public:
+ HsListCommand(wifi_request_id id, wifi_interface_handle iface,
+ int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler)
+ : WifiCommand(iface, id), num_hs(num), mNetworks(hs_list),
+ mHandler(handler)
+ {
+ }
+
+ HsListCommand(wifi_request_id id, wifi_interface_handle iface,
+ int num)
+ : WifiCommand(iface, id), num_hs(num), mNetworks(NULL)
+ {
+ mHandler.on_passpoint_network_found = NULL;
+ }
+
+ int createRequest(WifiRequest& request, int val) {
+ int result;
+
+ if (val) {
+ result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_HS_LIST);
+ result = request.put_u32(EPNO_ATTRIBUTE_HS_NUM, num_hs);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_HS_PARAM_LIST);
+ for (int i = 0; i < num_hs; i++) {
+ nlattr *attr2 = request.attr_start(i);
+ if (attr2 == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ result = request.put_u32(EPNO_ATTRIBUTE_HS_ID, mNetworks[i].id);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(EPNO_ATTRIBUTE_HS_REALM, mNetworks[i].realm, 256);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS, mNetworks[i].roamingConsortiumIds, 128);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put(EPNO_ATTRIBUTE_HS_PLMN, mNetworks[i].plmn, 3);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+ request.attr_end(attr);
+ request.attr_end(data);
+ }else {
+ result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_HS_LIST);
+ if (result < 0) {
+ return result;
+ }
+ }
+
+ return WIFI_SUCCESS;
+ }
+
+ int start() {
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, num_hs);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ registerVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to set ANQPO networks; result = %d", result);
+ unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int cancel() {
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to reset ANQPO networks;result = %d", result);
+ }
+ }
+
+ unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ unsigned int len = event.get_vendor_data_len();
+ if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
+ ALOGE("ERROR: No scan results found");
+ return NL_SKIP;
+ }
+
+ wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
+ byte *anqp = (byte *)result + offsetof(wifi_scan_result, ie_data) + result->ie_length;
+ int networkId = *(int *)anqp;
+ anqp += sizeof(int);
+ int anqp_len = *(u16 *)anqp;
+ anqp += sizeof(u16);
+
+ if(*mHandler.on_passpoint_network_found)
+ (*mHandler.on_passpoint_network_found)(id(), networkId, result, anqp_len, anqp);
+
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+ wifi_passpoint_network *networks, wifi_passpoint_event_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ HsListCommand *cmd = new HsListCommand(id, iface, num, networks, handler);
+
+ wifi_register_cmd(handle, id, cmd);
+ wifi_error result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ }
+ return result;
+}
+
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ wifi_error result;
+ HsListCommand *cmd = (HsListCommand *)(wifi_get_cmd(handle, id));
+
+ if (cmd == NULL) {
+ cmd = new HsListCommand(id, iface, 0);
+ wifi_register_cmd(handle, id, cmd);
+ }
+ result = (wifi_error)cmd->cancel();
+ wifi_unregister_cmd(handle, id);
+ return result;
+}
diff --git a/link_layer_stats.cpp b/link_layer_stats.cpp
new file mode 100755
index 0000000..bfdeac8
--- /dev/null
+++ b/link_layer_stats.cpp
@@ -0,0 +1,274 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+
+ LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD = 1,
+ LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING,
+ LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK,
+ LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST,
+
+ LSTATS_ATTRIBUTE_MAX
+
+} LSTATS_ATTRIBUTE;
+
+class LinkLayerStatsCommand : public WifiCommand
+{
+ wifi_link_layer_params mParams;
+ u32 mStatsClearReqMask;
+ u32 *mStatsClearRspMask;
+ u8 mStopReq;
+ u8 *mStopRsp;
+public:
+ LinkLayerStatsCommand(wifi_interface_handle handle, wifi_link_layer_params params)
+ : WifiCommand(handle, 0), mParams(params)
+ {
+ mStatsClearReqMask = 0;
+ mStatsClearRspMask = 0;
+ mStopReq = 0 ;
+ mStopRsp = NULL;
+
+ }
+
+ LinkLayerStatsCommand(wifi_interface_handle handle,
+ u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
+ : WifiCommand(handle, 0), mStatsClearReqMask(stats_clear_req_mask), mStatsClearRspMask(stats_clear_rsp_mask),
+ mStopReq(stop_req), mStopRsp(stop_rsp)
+ {
+ memset(&mParams,0,sizeof(wifi_link_layer_params));
+ }
+
+ int createSetRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD, mParams.mpdu_size_threshold);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING, mParams.aggressive_statistics_gathering);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int createClearRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK, mStatsClearReqMask);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST, mStopReq);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGD("Starting Link Layer Statistics measurement (%d, %d)", mParams.mpdu_size_threshold, mParams.aggressive_statistics_gathering);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetRequest(request);
+ if (result < 0) {
+ ALOGE("failed to set Link Layer Statistics (result:%d)", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("failed to Set Link Layer Statistics (result:%d)", result);
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int clear() {
+ ALOGD("Clearing Link Layer Statistics (%d, %d)", mStatsClearReqMask, mStopReq);
+ WifiRequest request(familyId(), ifaceId());
+ int result = createClearRequest(request);
+ if (result < 0) {
+ ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
+ return result;
+ }
+
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+
+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params)
+{
+ LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, params);
+ wifi_error result = (wifi_error)command->start();
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to Set link layer stats (result:%d)", result);
+ }
+ return result;
+}
+
+wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
+ u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
+{
+ LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, stats_clear_req_mask, stats_clear_rsp_mask, stop_req, stop_rsp);
+ wifi_error result = (wifi_error)command->clear();
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to Clear link layer stats (result:%d)", result);
+ *stats_clear_rsp_mask = 0;
+ *stop_rsp = 0;
+ } else {
+ *stats_clear_rsp_mask = stats_clear_req_mask;
+ *stop_rsp = stop_req;
+ }
+ return result;
+}
+
+
+class GetLinkStatsCommand : public WifiCommand
+{
+ wifi_stats_result_handler mHandler;
+ wifi_interface_handle iface;
+public:
+ GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
+ : WifiCommand(iface, 0), mHandler(handler)
+ {
+ this->iface = iface;
+ }
+
+ virtual int create() {
+ int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO);
+ if (ret < 0) {
+ ALOGE("Failed to create %x - %d", SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO, ret);
+ return ret;
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+ int id = reply.get_vendor_id();
+ u8 *data = (u8 *)reply.get_vendor_data();
+ int num_radios = 0, i = 0;
+ num_radios = data[0];
+ data += sizeof(data[0]);
+
+ // assuming max peers is 16
+ wifi_iface_stat *iface_stat = (wifi_iface_stat *) malloc(sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * 16);
+ if (!iface_stat) {
+ ALOGE("Memory alloc failed for iface_stat in response handler!!!");
+ return NL_SKIP;
+ }
+
+ // max channel is 39 (14 2.4GHz and 25 5GHz)
+ wifi_radio_stat *radio_stat = (wifi_radio_stat *) malloc((num_radios * sizeof(wifi_radio_stat)) + sizeof(wifi_channel_stat) * 39);
+ wifi_radio_stat *radio_stat2;
+ radio_stat2 = radio_stat;
+ if (!radio_stat) {
+ ALOGE("Memory alloc failed for radio_stat in response handler!!!");
+ free(iface_stat);
+ return NL_SKIP;
+ }
+
+ /* Data sent from driver does not contain num_tx_levels and tx_time per level. So copy
+ * radio data in two parts - 1st part until num_tx_levels and 2nd part from rx_time.
+ * channel data is copied separately
+ */
+ int radio_data_len1,radio_data_len2;
+ radio_data_len1 = (u8 *)&(radio_stat->num_tx_levels) - (u8*)radio_stat;
+ radio_data_len2 = (u8 *)(radio_stat->channels) - (u8*)&(radio_stat->rx_time);
+
+ //kernel is 64 bit. if userspace is 64 bit, typecastting buffer works else, make corrections
+ if (sizeof(iface_stat->iface) == 8) {
+ memcpy(iface_stat, data, sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers);
+ data += sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers;
+ } else {
+ /* for 64 bit kernel ad 32 bit user space, there is 4 byte extra at the begining and another 4 byte pad after 80 bytes
+ * so remove first 4 and 81-84 bytes from NL buffer.*/
+ data += 4;
+ memcpy(iface_stat, data, 80);
+ data += 80 + 4; //for allignment skip 4 bytes
+ memcpy(((u8 *)iface_stat) + 80, data, sizeof(wifi_iface_stat) - 80);
+ data += sizeof(wifi_iface_stat) - 80;
+ memcpy(iface_stat->peer_info, data, sizeof(wifi_peer_info) * iface_stat->num_peers);
+ data += sizeof(wifi_peer_info) * iface_stat->num_peers;
+ }
+ for (i = 0; i < num_radios; i++) {
+ memcpy(radio_stat2, data, radio_data_len1);
+ data += radio_data_len1;
+ memcpy(&radio_stat2->rx_time, data, radio_data_len2);
+ data += radio_data_len2;
+ memcpy(radio_stat2->channels, data, sizeof(wifi_channel_stat)* radio_stat2->num_channels);
+ radio_stat2->num_tx_levels = 0;
+ radio_stat2->tx_time_per_levels = NULL;
+ data += sizeof(wifi_channel_stat)* radio_stat2->num_channels;
+ radio_stat2=(wifi_radio_stat *) ((u8 *)radio_stat2+ sizeof(wifi_radio_stat) +
+ (sizeof(wifi_channel_stat) * radio_stat2->num_channels ));
+ }
+ iface_stat->iface = iface;
+ (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat);
+ free(iface_stat);
+ free(radio_stat);
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_link_stats(wifi_request_id id,
+ wifi_interface_handle iface, wifi_stats_result_handler handler)
+{
+ GetLinkStatsCommand command(iface, handler);
+ return (wifi_error) command.requestResponse();
+}
+
+
diff --git a/roam.cpp b/roam.cpp
new file mode 100755
index 0000000..0993ec7
--- /dev/null
+++ b/roam.cpp
@@ -0,0 +1,224 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+#define REQUEST_ID_MAX 1000
+#define get_requestid() ((arc4random()%REQUEST_ID_MAX) + 1)
+
+enum roam_attributes {
+ SLSI_ATTR_ROAM_CAPABILITY_BLACKLIST_SIZE,
+ SLSI_ATTR_ROAM_CAPABILITY_WHITELIST_SIZE,
+ SLSI_ATTR_ROAM_STATE
+};
+
+class BssidBlacklistCommand : public WifiCommand
+{
+private:
+ wifi_bssid_params *mParams;
+public:
+ BssidBlacklistCommand(wifi_interface_handle handle, int id,
+ wifi_bssid_params *params)
+ : WifiCommand(handle, id), mParams(params)
+ { }
+ int createRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_BLACKLIST);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BSSID, mParams->num_bssid);
+ if (result < 0) {
+ return result;
+ }
+
+ for (int i = 0; i < mParams->num_bssid; i++) {
+ result = request.put_addr(GSCAN_ATTRIBUTE_BLACKLIST_BSSID, mParams->bssids[i]);
+ if (result < 0) {
+ return result;
+ }
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGE("Failed to execute bssid blacklist request, result = %d", result);
+ return result;
+ }
+
+ return result;
+ }
+
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_params params)
+{
+ BssidBlacklistCommand *cmd = new BssidBlacklistCommand(iface, id, ¶ms);
+ wifi_error result = (wifi_error)cmd->start();
+ //release the reference of command as well
+ cmd->releaseRef();
+ return result;
+}
+
+
+class RoamingCapabilitiesCommand : public WifiCommand
+{
+private:
+ wifi_roaming_capabilities *mCaps;
+
+public:
+ RoamingCapabilitiesCommand(wifi_interface_handle handle, wifi_roaming_capabilities *caps)
+ : WifiCommand(handle, 0) {
+ mCaps = caps;
+ }
+
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_ROAMING_CAPABILITIES);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+ return WIFI_SUCCESS;
+
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignore reply; cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("vendor data in GetFeatureSetCommand missing!!");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ switch(it.get_type()) {
+ case SLSI_ATTR_ROAM_CAPABILITY_BLACKLIST_SIZE:
+ mCaps->max_blacklist_size = it.get_u32();
+ break;
+ case SLSI_ATTR_ROAM_CAPABILITY_WHITELIST_SIZE:
+ mCaps->max_whitelist_size = it.get_u32();
+ break;
+ default :
+ break;
+ }
+ }
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,
+ wifi_roaming_capabilities *caps)
+{
+ RoamingCapabilitiesCommand cmd(handle, caps);
+ return (wifi_error) cmd.requestResponse();
+}
+
+class RoamingStateCommand : public WifiCommand
+{
+private:
+ fw_roaming_state_t mRoamingState;
+
+public:
+ RoamingStateCommand(wifi_interface_handle handle, fw_roaming_state_t roaming_state)
+ : WifiCommand(handle, 0) {
+ mRoamingState = roaming_state;
+ }
+
+ virtual int create() {
+ int ret;
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_ROAMING_STATE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(SLSI_ATTR_ROAM_STATE, mRoamingState);
+ if (ret < 0) {
+ return ret;
+ }
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+wifi_error wifi_enable_firmware_roaming(wifi_interface_handle handle, fw_roaming_state_t state) {
+ RoamingStateCommand cmd(handle, state);
+ wifi_error ret = (wifi_error) cmd.requestResponse();
+ return ret;
+}
+
+wifi_error wifi_configure_roaming(wifi_interface_handle iface, wifi_roaming_config *roaming_config)
+{
+ wifi_error ret;
+ int requestId;
+ wifi_bssid_params bssid_params;
+
+ if (!roaming_config) {
+ ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+
+ /* Generate request id randomly*/
+ requestId = get_requestid();
+ bssid_params.num_bssid = roaming_config->num_blacklist_bssid;
+
+ memcpy(bssid_params.bssids, roaming_config->blacklist_bssid,
+ (bssid_params.num_bssid * sizeof(mac_addr)));
+
+ ret = wifi_set_bssid_blacklist(requestId, iface, bssid_params);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Failed to configure blacklist bssids", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ return ret;
+}
diff --git a/rtt.cpp b/rtt.cpp
new file mode 100755
index 0000000..2c9114d
--- /dev/null
+++ b/rtt.cpp
@@ -0,0 +1,632 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+
+#include <string>
+#include "nl80211_copy.h"
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+using namespace std;
+
+typedef enum {
+ SLSI_RTT_ATTRIBUTE_TARGET_CNT = 0,
+ SLSI_RTT_ATTRIBUTE_TARGET_INFO,
+ SLSI_RTT_ATTRIBUTE_TARGET_MAC,
+ SLSI_RTT_ATTRIBUTE_TARGET_TYPE,
+ SLSI_RTT_ATTRIBUTE_TARGET_PEER,
+ SLSI_RTT_ATTRIBUTE_TARGET_CHAN_WIDTH,
+ SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ,
+ SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ0,
+ SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ1,
+ SLSI_RTT_ATTRIBUTE_TARGET_PERIOD,
+ SLSI_RTT_ATTRIBUTE_TARGET_NUM_BURST,
+ SLSI_RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+ SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+ SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+ SLSI_RTT_ATTRIBUTE_TARGET_LCI,
+ SLSI_RTT_ATTRIBUTE_TARGET_LCR,
+ SLSI_RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+ SLSI_RTT_ATTRIBUTE_TARGET_PREAMBLE,
+ SLSI_RTT_ATTRIBUTE_TARGET_BW,
+ SLSI_RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+ SLSI_RTT_ATTRIBUTE_RESULTS_PER_TARGET,
+ SLSI_RTT_ATTRIBUTE_RESULT_CNT,
+ SLSI_RTT_ATTRIBUTE_RESULT,
+ SLSI_RTT_ATTRIBUTE_TARGET_ID
+} SLSI_RTT_ATTRIBUTE;
+
+enum slsi_rtt_event_attributes {
+ SLSI_RTT_EVENT_ATTR_ADDR = 0,
+ SLSI_RTT_EVENT_ATTR_BURST_NUM,
+ SLSI_RTT_EVENT_ATTR_MEASUREMENT_NUM,
+ SLSI_RTT_EVENT_ATTR_SUCCESS_NUM,
+ SLSI_RTT_EVENT_ATTR_NUM_PER_BURST_PEER,
+ SLSI_RTT_EVENT_ATTR_STATUS,
+ SLSI_RTT_EVENT_ATTR_RETRY_AFTER_DURATION,
+ SLSI_RTT_EVENT_ATTR_TYPE,
+ SLSI_RTT_EVENT_ATTR_RSSI,
+ SLSI_RTT_EVENT_ATTR_RSSI_SPREAD,
+ SLSI_RTT_EVENT_ATTR_TX_PREAMBLE,
+ SLSI_RTT_EVENT_ATTR_TX_NSS,
+ SLSI_RTT_EVENT_ATTR_TX_BW,
+ SLSI_RTT_EVENT_ATTR_TX_MCS,
+ SLSI_RTT_EVENT_ATTR_TX_RATE,
+ SLSI_RTT_EVENT_ATTR_RX_PREAMBLE,
+ SLSI_RTT_EVENT_ATTR_RX_NSS,
+ SLSI_RTT_EVENT_ATTR_RX_BW,
+ SLSI_RTT_EVENT_ATTR_RX_MCS,
+ SLSI_RTT_EVENT_ATTR_RX_RATE,
+ SLSI_RTT_EVENT_ATTR_RTT,
+ SLSI_RTT_EVENT_ATTR_RTT_SD,
+ SLSI_RTT_EVENT_ATTR_RTT_SPREAD,
+ SLSI_RTT_EVENT_ATTR_DISTANCE_MM,
+ SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM,
+ SLSI_RTT_EVENT_ATTR_DISTANCE_SPREAD_MM,
+ SLSI_RTT_EVENT_ATTR_TIMESTAMP_US,
+ SLSI_RTT_EVENT_ATTR_BURST_DURATION_MSN,
+ SLSI_RTT_EVENT_ATTR_NEGOTIATED_BURST_NUM,
+ SLSI_RTT_EVENT_ATTR_LCI,
+ SLSI_RTT_EVENT_ATTR_LCR
+};
+
+struct dot11_rm_ie {
+ u8 id;
+ u8 len;
+ u8 token;
+ u8 mode;
+ u8 type;
+} __attribute__ ((packed));
+typedef struct dot11_rm_ie dot11_rm_ie_t;
+typedef struct strmap_entry {
+ int id;
+ string text;
+} strmap_entry_t;
+
+static const strmap_entry_t err_info[] = {
+ {RTT_STATUS_SUCCESS, string("Success")},
+ {RTT_STATUS_FAILURE, string("Failure")},
+ {RTT_STATUS_FAIL_NO_RSP, string("No reponse")},
+ {RTT_STATUS_FAIL_INVALID_TS, string("Invalid Timestamp")},
+ {RTT_STATUS_FAIL_PROTOCOL, string("Protocol error")},
+ {RTT_STATUS_FAIL_REJECTED, string("Rejected")},
+ {RTT_STATUS_FAIL_NOT_SCHEDULED_YET, string("not scheduled")},
+ {RTT_STATUS_FAIL_SCHEDULE, string("schedule failed")},
+ {RTT_STATUS_FAIL_TM_TIMEOUT, string("timeout")},
+ {RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, string("AP is on difference channel")},
+ {RTT_STATUS_FAIL_NO_CAPABILITY, string("no capability")},
+ {RTT_STATUS_FAIL_BUSY_TRY_LATER, string("busy and try later")},
+ {RTT_STATUS_ABORTED, string("aborted")}
+};
+/*static const string get_err_info(int status)
+{
+ int i;
+ const strmap_entry_t *p_entry;
+ int num_entries = sizeof(err_info)/ sizeof(err_info[0]);
+ * scan thru the table till end
+ p_entry = err_info;
+ for (i = 0; i < (int) num_entries; i++)
+ {
+ if (p_entry->id == status)
+ return p_entry->text;
+ p_entry++; * next entry
+ }
+ return "unknown error"; * not found
+}*/
+class RttCommand : public WifiCommand
+{
+ int rtt_id;
+ unsigned numTargetDevice;
+ int mCompleted;
+ int currentIdx;
+ int totalCnt;
+ static const int MAX_RESULTS = 1024;
+ wifi_rtt_result *rttResults[MAX_RESULTS];
+ wifi_rtt_config *rttParams;
+ wifi_rtt_event_handler rttHandler;
+public:
+ RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
+ wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+ : WifiCommand(iface, id), rtt_id(id), numTargetDevice(num_rtt_config), rttParams(rtt_config),
+ rttHandler(handler)
+ {
+ memset(rttResults, 0, sizeof(rttResults));
+ currentIdx = 0;
+ mCompleted = 0;
+ totalCnt = 0;
+ }
+
+ RttCommand(wifi_interface_handle iface, int id)
+ : WifiCommand(iface, id), rtt_id(id), rttParams(NULL)
+ {
+ rttHandler.on_rtt_results = NULL;
+ memset(rttResults, 0, sizeof(rttResults));
+ currentIdx = 0;
+ mCompleted = 0;
+ totalCnt = 0;
+ numTargetDevice = 0;
+ }
+ int createSetupRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_START);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_ID, rtt_id);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_CNT, numTargetDevice);
+ ALOGI("numTargetDevice %d\n",numTargetDevice);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *rtt_config = request.attr_start(SLSI_RTT_ATTRIBUTE_TARGET_INFO);
+ for (unsigned i = 0; i < numTargetDevice; i++) {
+ nlattr *attr2 = request.attr_start(i);
+
+ result = request.put_addr(SLSI_RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
+ ALOGI("mac_addr %p\n",rttParams[i].addr);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
+ ALOGI("\trtt_type %d\n",rttParams[i].type);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
+ ALOGI("\trtt_peer %d\n",rttParams[i].peer);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ, rttParams[i].channel.center_freq);
+ ALOGI("\trtt_ primary channel_freq %d\n",rttParams[i].channel.center_freq);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_WIDTH, rttParams[i].channel.width);
+ ALOGI("\trtt_channel width:%d\n",rttParams[i].channel.width);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ0, rttParams[i].channel.center_freq0);
+ ALOGI("\trtt_channel_freq 0:%d\n",rttParams[i].channel.center_freq0);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CHAN_FREQ1, rttParams[i].channel.center_freq1);
+ ALOGI("\trtt_channel_freq 1: %d\n",rttParams[i].channel.center_freq1);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
+ ALOGI("\tnum_burst %d\n",rttParams[i].num_burst);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+ rttParams[i].num_frames_per_burst);
+ ALOGI("\tnum_frames_per_burst %d\n",rttParams[i].num_frames_per_burst);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+ rttParams[i].num_retries_per_rtt_frame);
+ ALOGI("\tnum_retries_per_rtt_frame %d\n",rttParams[i].num_retries_per_rtt_frame);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+ rttParams[i].num_retries_per_ftmr);
+ ALOGI("\tnum_retries_per_ftmr %d\n",rttParams[i].num_retries_per_ftmr);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_PERIOD,
+ rttParams[i].burst_period);
+ ALOGI("\tburst_period %d\n",rttParams[i].burst_period);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(SLSI_RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+ rttParams[i].burst_duration);
+ ALOGI("\tburst_duration %d\n",rttParams[i].burst_duration);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_LCI,
+ rttParams[i].LCI_request);
+ ALOGI("\tLCI_request %d\n",rttParams[i].LCI_request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_LCR,
+ rttParams[i].LCR_request);
+ ALOGI("\tLCR_ request%d\n",rttParams[i].LCR_request);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_BW,
+ rttParams[i].bw);
+ ALOGI("\tBW%d\n",rttParams[i].bw);
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_PREAMBLE,
+ rttParams[i].preamble);
+ ALOGI("\tpreamble%d\n",rttParams[i].preamble);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(attr2);
+ }
+ ALOGE("setup request created");
+ request.attr_end(rtt_config);
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+
+ int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_RANGE_CANCEL);
+ if (result < 0) {
+ return result;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_ID, rtt_id);
+ request.put_u16(SLSI_RTT_ATTRIBUTE_TARGET_CNT, num_devices);
+ for(unsigned i = 0; i < num_devices; i++) {
+ result = request.put_addr(SLSI_RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
+ if (result < 0) {
+ return result;
+ }
+ }
+ request.attr_end(data);
+ return result;
+ }
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createSetupRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create setup request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to configure RTT setup; result = %d", result);
+ return result;
+ }
+ registerVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+ registerVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+ return result;
+ }
+
+ virtual int cancel() {
+ ALOGD("Stopping RTT");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request, 0, NULL);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop scan; result = %d", result);
+ }
+ }
+ ALOGE("RTT stopped");
+ /*This needs to be check */
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+ return WIFI_SUCCESS;
+ }
+
+ int cancel_specific(unsigned num_devices, mac_addr addr[]) {
+ ALOGE("Stopping RTT specific");
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createTeardownRequest(request, num_devices, addr);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create stop request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop RTT; result = %d", result);
+ }
+ }
+ ALOGE("Specific RTT stopped");
+ /*This needs to be check */
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_EVENT_COMPLETE);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ currentIdx=0;
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int event_id = event.get_vendor_subcmd();
+ ALOGD("Got an RTT event with id:%d\n",event_id);
+ if(event_id == SLSI_RTT_EVENT_COMPLETE) {
+ ALOGD("RTT event complete\n");
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+ WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
+ if (cmd)
+ cmd->releaseRef();
+ } else if (event_id == SLSI_RTT_RESULT_EVENT) {
+ int result_cnt = 0;
+ int rtt_id = 0;
+ ALOGD("RTT result event\n");
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == SLSI_RTT_ATTRIBUTE_RESULT_CNT) {
+ result_cnt = it.get_u16();
+ ALOGD("RTT results count : %d\n", result_cnt);
+ } else if (it.get_type() == SLSI_RTT_ATTRIBUTE_TARGET_ID) {
+ rtt_id = it.get_u16();
+ ALOGD("RTT target id : %d\n", rtt_id);
+ } else if (it.get_type() == SLSI_RTT_ATTRIBUTE_RESULT) {
+ ALOGD("RTT result attribute : %d\n", SLSI_RTT_ATTRIBUTE_RESULT);
+ rttResults[currentIdx] = (wifi_rtt_result *)malloc(sizeof(wifi_rtt_result));
+ wifi_rtt_result *rtt_result = rttResults[currentIdx];
+ if (rtt_result == NULL) {
+ ALOGE("failed to allocate the wifi_rtt_result\n");
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_RTT_RESULT_EVENT);
+ break;
+ }
+ for(nl_iterator nl_nested_itr((struct nlattr *)it.get()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+ if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_ADDR) {
+ memcpy(rtt_result->addr, nl_nested_itr.get_data(), nl_nested_itr.get_len());
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_BURST_NUM) {
+ rtt_result->burst_num = (unsigned)nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_MEASUREMENT_NUM) {
+ rtt_result->measurement_number = (unsigned)nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_SUCCESS_NUM) {
+ rtt_result->success_number = (unsigned)nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_NUM_PER_BURST_PEER) {
+ rtt_result->number_per_burst_peer = (unsigned char)nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_STATUS) {
+ rtt_result->status = (wifi_rtt_status)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RETRY_AFTER_DURATION) {
+ rtt_result->retry_after_duration = (unsigned char)nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TYPE) {
+ rtt_result->type = (wifi_rtt_type)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RSSI) {
+ rtt_result->rssi = (wifi_rssi)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RSSI_SPREAD) {
+ rtt_result->rssi_spread= (wifi_rssi)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_PREAMBLE) {
+ rtt_result->tx_rate.preamble = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_NSS) {
+ rtt_result->tx_rate.nss = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_BW) {
+ rtt_result->tx_rate.bw = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_MCS) {
+ rtt_result->tx_rate.rateMcsIdx = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TX_RATE) {
+ rtt_result->tx_rate.bitrate = nl_nested_itr.get_u32();
+ }else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_PREAMBLE) {
+ rtt_result->rx_rate.preamble = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_NSS) {
+ rtt_result->rx_rate.nss = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_BW) {
+ rtt_result->rx_rate.bw = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_MCS) {
+ rtt_result->rx_rate.rateMcsIdx = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RX_RATE) {
+ rtt_result->rx_rate.bitrate = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT) {
+ rtt_result->rtt = (wifi_timespan)nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT_SD) {
+ rtt_result->rtt_sd = (wifi_timespan)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_RTT_SPREAD) {
+ rtt_result->rtt_spread = (wifi_timespan)nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_MM) {
+ rtt_result->distance_mm = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_SD_MM) {
+ rtt_result->distance_sd_mm = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_DISTANCE_SPREAD_MM) {
+ rtt_result->distance_spread_mm = nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_TIMESTAMP_US) {
+ rtt_result->ts = (wifi_timestamp)nl_nested_itr.get_u32();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_BURST_DURATION_MSN) {
+ rtt_result->burst_duration = nl_nested_itr.get_u16();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_NEGOTIATED_BURST_NUM) {
+ rtt_result->negotiated_burst_num = nl_nested_itr.get_u8();
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_LCI) {
+ u8 *lci_ie = (u8 *)nl_nested_itr.get_data();
+ rtt_result->LCI = (wifi_information_element *)malloc(sizeof(wifi_information_element) + nl_nested_itr.get_len() - 2);
+ rtt_result->LCI->id = lci_ie[0];
+ rtt_result->LCI->len =lci_ie[1];
+ memcpy(rtt_result->LCI->data, &lci_ie[2], nl_nested_itr.get_len() - 2);
+ } else if (nl_nested_itr.get_type() == SLSI_RTT_EVENT_ATTR_LCR) {
+ u8 *lcr_ie = (u8 *)nl_nested_itr.get_data();
+ rtt_result->LCR = (wifi_information_element *)malloc(sizeof(wifi_information_element) + nl_nested_itr.get_len() - 2);
+ rtt_result->LCR->id = lcr_ie[0];
+ rtt_result->LCR->len =lcr_ie[1];
+ memcpy(rtt_result->LCR->data, &lcr_ie[2], nl_nested_itr.get_len() - 2);
+ }
+ }
+ currentIdx++;
+ }
+ }
+ (*rttHandler.on_rtt_results)(id() ,currentIdx, rttResults);
+ for (int i = 0; i < currentIdx; i++) {
+ free(rttResults[i]);
+ rttResults[i] = NULL;
+ }
+ currentIdx = 0;
+ }
+ ALOGE("Handled response for rtt config");
+ return NL_SKIP;
+ }
+};
+class GetRttCapabilitiesCommand : public WifiCommand
+ {
+ wifi_rtt_capabilities *mCapabilities;
+public:
+ GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
+ : WifiCommand(iface, 0), mCapabilities(capabitlites)
+ {
+ memset(mCapabilities, 0, sizeof(*mCapabilities));
+ }
+
+ virtual int create() {
+ int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_GET_CAPABILITIES);
+ if (ret < 0) {
+ ALOGE("NL message creation failed");
+ return ret;
+ }
+
+ return ret;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
+ ALOGE("RTT capa response");
+ return NL_OK;
+ }
+};
+/*class GetRttResponderInfoCommand : public WifiCommand
+{
+ wifi_rtt_responder* mResponderInfo;
+public:
+ GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
+ : WifiCommand(iface, 0), mResponderInfo(responderInfo)
+ {
+ memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
+
+ }
+
+ virtual int create() {
+ ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
+
+ int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RTT_GETAVAILCHANNEL);
+ if (ret < 0) {
+ return ret;
+ }
+
+ // return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ ALOGD("In GetRttResponderInfoCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
+ sizeof(*mResponderInfo));
+
+ memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
+
+ return NL_OK;
+ }
+};*/
+
+ /* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
+{
+ ALOGE("Inside RTT RANGE range request");
+ wifi_handle handle = getWifiHandle(iface);
+ RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ ALOGE("wifi range request successfully executed");
+ return result;
+}
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_devices, mac_addr addr[])
+{
+ if (!iface)
+ return WIFI_ERROR_UNINITIALIZED;
+ RttCommand *cmd = new RttCommand(iface, id);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel_specific(num_devices, addr);
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+}
+
+/* API to get RTT capability */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
+ wifi_rtt_capabilities *capabilities)
+{
+ ALOGE("Inside get rtt capabilities cap:%p iface:%p", capabilities, iface);
+ if (!iface)
+ return WIFI_ERROR_UNINITIALIZED;
+ GetRttCapabilitiesCommand command(iface, capabilities);
+ return (wifi_error) command.requestResponse();
+
+}
+/* API to get the responder information */
+wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
+ wifi_rtt_responder* responderInfo)
+{
+ /*GetRttResponderInfoCommand command(iface, responderInfo);
+ return (wifi_error) command.requestResponse();*/
+ return WIFI_ERROR_NOT_SUPPORTED;
+
+}
diff --git a/sync.h b/sync.h
new file mode 100755
index 0000000..cea2ea9
--- /dev/null
+++ b/sync.h
@@ -0,0 +1,54 @@
+
+#include <pthread.h>
+
+#ifndef __WIFI_HAL_SYNC_H__
+#define __WIFI_HAL_SYNC_H__
+
+class Mutex
+{
+private:
+ pthread_mutex_t mMutex;
+public:
+ Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+ ~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+ }
+ int tryLock() {
+ return pthread_mutex_trylock(&mMutex);
+ }
+ int lock() {
+ return pthread_mutex_lock(&mMutex);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&mMutex);
+ }
+};
+
+class Condition
+{
+private:
+ pthread_cond_t mCondition;
+ pthread_mutex_t mMutex;
+
+public:
+ Condition() {
+ pthread_mutex_init(&mMutex, NULL);
+ pthread_cond_init(&mCondition, NULL);
+ }
+ ~Condition() {
+ pthread_cond_destroy(&mCondition);
+ pthread_mutex_destroy(&mMutex);
+ }
+
+ int wait() {
+ return pthread_cond_wait(&mCondition, &mMutex);
+ }
+
+ void signal() {
+ pthread_cond_signal(&mCondition);
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/wifi_hal.cpp b/wifi_hal.cpp
new file mode 100755
index 0000000..abcd1fd
--- /dev/null
+++ b/wifi_hal.cpp
@@ -0,0 +1,1029 @@
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/attr.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+
+#include <dirent.h>
+#include <net/if.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "roam.h"
+
+
+#define WIFI_HAL_CMD_SOCK_PORT 644
+#define WIFI_HAL_EVENT_SOCK_PORT 645
+
+#define FEATURE_SET 0
+#define FEATURE_SET_MATRIX 1
+#define ATTR_NODFS_VALUE 3
+#define ATTR_COUNTRY_CODE 4
+
+static int internal_no_seq_check(nl_msg *msg, void *arg);
+static int internal_valid_message_handler(nl_msg *msg, void *arg);
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
+static int wifi_add_membership(wifi_handle handle, const char *group);
+static wifi_error wifi_init_interfaces(wifi_handle handle);
+
+typedef enum wifi_attr {
+ ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG,
+ ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI
+} wifi_attr_t;
+
+enum wifi_rssi_monitor_attr {
+ RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
+ RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
+ RSSI_MONITOR_ATTRIBUTE_START,
+};
+
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+ iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface);
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
+
+/* Initialize/Cleanup */
+
+void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
+{
+ uint32_t pid = getpid() & 0x3FFFFF;
+ nl_socket_set_local_port(sock, pid + (port << 22));
+}
+
+class SetNdoffloadCommand : public WifiCommand {
+
+private:
+ u8 mEnable;
+public:
+ SetNdoffloadCommand(wifi_interface_handle handle, u8 enable)
+ : WifiCommand(handle, 0) {
+ mEnable = enable;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_CONFIGURE_ND_OFFLOAD);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG, mEnable);
+ if (ret < 0) {
+ return ret;
+ }
+ ALOGD("Driver message has been created successfully--> %d", mEnable);
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+static nl_sock * wifi_create_nl_socket(int port)
+{
+ struct nl_sock *sock = nl_socket_alloc();
+ if (sock == NULL) {
+ ALOGE("Could not create handle");
+ return NULL;
+ }
+
+ wifi_socket_set_local_port(sock, port);
+
+ if (nl_connect(sock, NETLINK_GENERIC)) {
+ ALOGE("Could not connect handle");
+ nl_socket_free(sock);
+ return NULL;
+ }
+
+ return sock;
+}
+
+
+wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
+{
+ SetNdoffloadCommand command(handle, enable);
+ int ret = command.requestResponse();
+ if (ret != WIFI_SUCCESS) {
+ if (ret == -EPERM) { /*This is just to pass VTS test */
+ ALOGD("return value from driver--> %d",ret);
+ return WIFI_SUCCESS;
+ }
+ }
+ return (wifi_error)ret;
+}
+
+wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
+ u32 *version, u32 *max_len)
+{
+ /*Return success to pass VTS test.*/
+ ALOGD("Packet filter not supported");
+
+ *version = 0;
+ *max_len = 0;
+
+ return WIFI_SUCCESS;
+}
+
+/* Initialize HAL function pointer table */
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn)
+{
+ if (fn == NULL) {
+ return WIFI_ERROR_UNKNOWN;
+ }
+ fn->wifi_initialize = wifi_initialize;
+ fn->wifi_cleanup = wifi_cleanup;
+ fn->wifi_event_loop = wifi_event_loop;
+ fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
+ fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
+ fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui;
+ fn->wifi_get_ifaces = wifi_get_ifaces;
+ fn->wifi_get_iface_name = wifi_get_iface_name;
+ fn->wifi_start_gscan = wifi_start_gscan;
+ fn->wifi_stop_gscan = wifi_stop_gscan;
+ fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
+ fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
+ fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
+ fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
+ fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
+ fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
+ fn->wifi_get_valid_channels = wifi_get_valid_channels;
+ fn->wifi_rtt_range_request = wifi_rtt_range_request;
+ fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
+ fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
+ fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
+//fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet;
+ fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
+ fn->wifi_set_epno_list = wifi_set_epno_list;
+ fn->wifi_reset_epno_list = wifi_reset_epno_list;
+ fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
+ fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
+ fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
+ fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
+ fn->wifi_set_link_stats = wifi_set_link_stats;
+ fn->wifi_get_link_stats = wifi_get_link_stats;
+ fn->wifi_clear_link_stats = wifi_clear_link_stats;
+ fn->wifi_set_country_code = wifi_set_country_code;
+ fn->wifi_configure_roaming = wifi_configure_roaming;
+ fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
+ fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
+ fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
+ fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
+ fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
+ fn->wifi_start_logging = wifi_start_logging;
+ fn->wifi_set_log_handler = wifi_set_log_handler;
+ fn->wifi_set_alert_handler= wifi_set_alert_handler;
+ fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
+ fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
+ fn->wifi_get_ring_data = wifi_get_ring_data;
+ fn->wifi_get_driver_version = wifi_get_driver_version;
+ fn->wifi_get_firmware_version = wifi_get_firmware_version;
+ fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
+ fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
+ fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
+ fn->wifi_nan_enable_request = nan_enable_request;
+ fn->wifi_nan_disable_request = nan_disable_request;
+ fn->wifi_nan_publish_request = nan_publish_request;
+ fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
+ fn->wifi_nan_subscribe_request = nan_subscribe_request;
+ fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
+ fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
+ fn->wifi_nan_config_request = nan_config_request;
+ fn->wifi_nan_register_handler = nan_register_handler;
+ fn->wifi_nan_get_version = nan_get_version;
+ fn->wifi_nan_get_capabilities = nan_get_capabilities;
+ fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
+ fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
+
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_initialize(wifi_handle *handle)
+{
+ srand(getpid());
+
+ ALOGI("Initializing wifi");
+ hal_info *info = (hal_info *)malloc(sizeof(hal_info));
+ if (info == NULL) {
+ ALOGE("Could not allocate hal_info");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->cleanup_socks) == -1) {
+ ALOGE("Could not create cleanup sockets");
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
+ if (cmd_sock == NULL) {
+ ALOGE("Could not create handle");
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
+ if (event_sock == NULL) {
+ ALOGE("Could not create handle");
+ nl_socket_free(cmd_sock);
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_cb *cb = nl_socket_get_cb(event_sock);
+ if (cb == NULL) {
+ ALOGE("Could not create handle");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+// ALOGI("cb->refcnt = %d", cb->cb_refcnt);
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
+ nl_cb_put(cb);
+
+ info->cmd_sock = cmd_sock;
+ info->event_sock = event_sock;
+ info->clean_up = false;
+ info->in_event_loop = false;
+
+ info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
+ info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
+ info->num_event_cb = 0;
+
+ info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
+ info->alloc_cmd = DEFAULT_CMD_SIZE;
+ info->num_cmd = 0;
+
+ info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
+ if (info->nl80211_family_id < 0) {
+ ALOGE("Could not resolve nl80211 familty id");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ pthread_mutex_init(&info->cb_lock, NULL);
+
+ *handle = (wifi_handle) info;
+ wifi_add_membership(*handle, "scan");
+ wifi_add_membership(*handle, "mlme");
+ wifi_add_membership(*handle, "regulatory");
+ wifi_add_membership(*handle, "vendor");
+
+ wifi_init_interfaces(*handle);
+ char intf_name_buff[10 * 10 + 4]; /* Randomly choosen max interface 10. each interface name max 9 + 1(for space) */
+ char *pos = intf_name_buff;
+ for (int i = 0; i < (info->num_interfaces < 10 ? info->num_interfaces : 10); i++) {
+ strncpy(pos, info->interfaces[i]->name, sizeof(intf_name_buff) - (pos - intf_name_buff));
+ pos += strlen(pos);
+ }
+ if (info->num_interfaces > 10) {
+ strncpy(pos, "...", 3);
+ }
+
+ ALOGD("Found %d interfaces[%s]. Initialized Wifi HAL Successfully", info->num_interfaces, intf_name_buff);
+
+ return WIFI_SUCCESS;
+}
+
+static int wifi_add_membership(wifi_handle handle, const char *group)
+{
+ hal_info *info = getHalInfo(handle);
+
+ int id = wifi_get_multicast_id(handle, "nl80211", group);
+ if (id < 0) {
+ ALOGE("Could not find group %s", group);
+ return id;
+ }
+
+ int ret = nl_socket_add_membership(info->event_sock, id);
+ if (ret < 0) {
+ ALOGE("Could not add membership to group %s", group);
+ }
+ return ret;
+}
+
+static void internal_cleaned_up_handler(wifi_handle handle)
+{
+ hal_info *info = getHalInfo(handle);
+ wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
+
+ if (info->cmd_sock != 0) {
+ close(info->cleanup_socks[0]);
+ close(info->cleanup_socks[1]);
+ nl_socket_free(info->cmd_sock);
+ nl_socket_free(info->event_sock);
+ info->cmd_sock = NULL;
+ info->event_sock = NULL;
+ }
+
+ (*cleaned_up_handler)(handle);
+ pthread_mutex_destroy(&info->cb_lock);
+ free(info);
+}
+
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
+{
+ hal_info *info = getHalInfo(handle);
+ char buf[64];
+
+ info->cleaned_up_handler = handler;
+ if (write(info->cleanup_socks[0], "Exit", 4) < 1) {
+ ALOGE("could not write to the cleanup socket");
+ } else {
+ // Listen to the response
+ // Hopefully we dont get errors or get hung up
+ // Not much can be done in that case, but assume that
+ // it has rx'ed the Exit message to exit the thread.
+ // As a fallback set the cleanup flag to TRUE
+ memset(buf, 0, sizeof(buf));
+ int result = read(info->cleanup_socks[0], buf, sizeof(buf));
+ ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result, errno);
+ if (strncmp(buf, "Done", 4) != 0) {
+ ALOGD("Rx'ed %s", buf);
+ }
+ }
+ info->clean_up = true;
+ pthread_mutex_lock(&info->cb_lock);
+
+ int bad_commands = 0;
+
+ while (info->num_cmd > bad_commands) {
+ int num_cmd = info->num_cmd;
+ cmd_info *cmdi = &(info->cmd[bad_commands]);
+ WifiCommand *cmd = cmdi->cmd;
+ if (cmd != NULL) {
+ pthread_mutex_unlock(&info->cb_lock);
+ cmd->cancel();
+ pthread_mutex_lock(&info->cb_lock);
+ /* release reference added when command is saved */
+ cmd->releaseRef();
+ if (num_cmd == info->num_cmd) {
+ bad_commands++;
+ }
+ }
+ }
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ cb_info *cbi = &(info->event_cb[i]);
+ WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+ ALOGE("Leaked command %p", cmd);
+ }
+ pthread_mutex_unlock(&info->cb_lock);
+ internal_cleaned_up_handler(handle);
+}
+
+static int internal_pollin_handler(wifi_handle handle)
+{
+ hal_info *info = getHalInfo(handle);
+ struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
+ int res = nl_recvmsgs(info->event_sock, cb);
+ nl_cb_put(cb);
+ return res;
+}
+
+/* Run event handler */
+void wifi_event_loop(wifi_handle handle)
+{
+ hal_info *info = getHalInfo(handle);
+ if (info->in_event_loop) {
+ return;
+ } else {
+ info->in_event_loop = true;
+ }
+
+ pollfd pfd[2];
+ memset(&pfd[0], 0, sizeof(pollfd) * 2);
+
+ pfd[0].fd = nl_socket_get_fd(info->event_sock);
+ pfd[0].events = POLLIN;
+ pfd[1].fd = info->cleanup_socks[1];
+ pfd[1].events = POLLIN;
+
+ char buf[2048];
+
+ do {
+ int timeout = -1; /* Infinite timeout */
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
+ int result = poll(pfd, 2, timeout);
+ if (result < 0) {
+ } else if (pfd[0].revents & POLLERR) {
+ int prev_err = (int)errno;
+ int result2 = read(pfd[0].fd, buf, sizeof(buf));
+ ALOGE("Poll err:%d | Read after POLL returned %d, error no = %d", prev_err, result2, errno);
+ } else if (pfd[0].revents & POLLHUP) {
+ ALOGE("Remote side hung up");
+ break;
+ } else if (pfd[0].revents & POLLIN) {
+ internal_pollin_handler(handle);
+ } else if (pfd[1].revents & POLLIN) {
+ memset(buf, 0, sizeof(buf));
+ int result2 = read(pfd[1].fd, buf, sizeof(buf));
+ ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result2, errno);
+ if (strncmp(buf, "Exit", 4) == 0) {
+ ALOGD("Got a signal to exit!!!");
+ if (write(pfd[1].fd, "Done", 4) < 1) {
+ ALOGE("could not write to the cleanup socket");
+ }
+ break;
+ } else {
+ ALOGD("Rx'ed %s on the cleanup socket\n", buf);
+ }
+ } else {
+ ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents);
+ }
+ } while (!info->clean_up);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int internal_no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+static int internal_valid_message_handler(nl_msg *msg, void *arg)
+{
+ wifi_handle handle = (wifi_handle)arg;
+ hal_info *info = getHalInfo(handle);
+
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse event: %d", res);
+ return NL_SKIP;
+ }
+
+ int cmd = event.get_cmd();
+ uint32_t vendor_id = 0;
+ int subcmd = 0;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
+ subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ /*
+ ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+ event.get_cmdString(), vendor_id, subcmd);*/
+ }
+
+ //ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
+ //event.log();
+
+ pthread_mutex_lock(&info->cb_lock);
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (cmd == info->event_cb[i].nl_cmd) {
+ if (cmd == NL80211_CMD_VENDOR
+ && ((vendor_id != info->event_cb[i].vendor_id)
+ || (subcmd != info->event_cb[i].vendor_subcmd)))
+ {
+ /* event for a different vendor, ignore it */
+ continue;
+ }
+
+ cb_info *cbi = &(info->event_cb[i]);
+ nl_recvmsg_msg_cb_t cb_func = cbi->cb_func;
+ void *cb_arg = cbi->cb_arg;
+ WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
+ if (cmd != NULL) {
+ cmd->addRef();
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ if (cb_func)
+ (*cb_func)(msg, cb_arg);
+ if (cmd != NULL) {
+ cmd->releaseRef();
+ }
+
+ return NL_OK;
+ }
+ }
+
+ pthread_mutex_unlock(&info->cb_lock);
+ return NL_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+class GetMulticastIdCommand : public WifiCommand
+{
+private:
+ const char *mName;
+ const char *mGroup;
+ int mId;
+public:
+ GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
+ : WifiCommand(handle, 0)
+ {
+ mName = name;
+ mGroup = group;
+ mId = -1;
+ }
+
+ int getId() {
+ return mId;
+ }
+
+ virtual int create() {
+ int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
+ int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
+ return ret;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ struct nlattr **tb = reply.attributes();
+ struct nlattr *mcgrp = NULL;
+ int i;
+
+ if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+ ALOGE("No multicast groups found");
+ return NL_SKIP;
+ }
+
+ for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
+ continue;
+ }
+
+ char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+ int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+
+ if (strncmp(grpName, mGroup, grpNameLen) != 0)
+ continue;
+
+ mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ }
+
+ return NL_SKIP;
+ }
+
+};
+
+class SetPnoMacAddrOuiCommand : public WifiCommand {
+
+private:
+ byte *mOui;
+ feature_set *fset;
+ feature_set *feature_matrix;
+ int *fm_size;
+ int set_size_max;
+public:
+ SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui)
+ : WifiCommand(handle, 0)
+ {
+ mOui = scan_oui;
+ fset = NULL;
+ feature_matrix = NULL;
+ fm_size = NULL;
+ set_size_max = 0;
+ }
+
+ int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) {
+ int result = request.create(GOOGLE_OUI, subcmd);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN);
+ if (result < 0) {
+ return result;
+ }
+
+ request.attr_end(data);
+ return WIFI_SUCCESS;
+
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI, mOui);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to set scanning mac OUI; result = %d", result);
+ }
+
+ return result;
+ }
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+};
+
+class SetNodfsCommand : public WifiCommand {
+
+private:
+ u32 mNoDfs;
+public:
+ SetNodfsCommand(wifi_interface_handle handle, u32 nodfs)
+ : WifiCommand(handle, 0) {
+ mNoDfs = nodfs;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_u32(ATTR_NODFS_VALUE, mNoDfs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+ }
+};
+
+class SetRSSIMonitorCommand : public WifiCommand {
+private:
+ s8 mMax_rssi;
+ s8 mMin_rssi;
+ wifi_rssi_event_handler mHandler;
+public:
+ SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle,
+ s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+ : WifiCommand(handle, id), mMax_rssi(max_rssi), mMin_rssi
+ (min_rssi), mHandler(eh)
+ {
+ }
+ int createRequest(WifiRequest& request, int enable) {
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_RSSI_MONITOR);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0));
+ if (result < 0) {
+ return result;
+ }
+
+ result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0));
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_START, enable);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 1);
+ if (result < 0) {
+ return result;
+ }
+ result = requestResponse(request);
+ if (result < 0) {
+ ALOGI("Failed to set RSSI Monitor, result = %d", result);
+ return result;
+ }
+ ALOGI("Successfully set RSSI monitoring");
+ registerVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
+
+ return result;
+ }
+
+ virtual int cancel() {
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create request; result = %d", result);
+ } else {
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to stop RSSI monitoring = %d", result);
+ }
+ }
+ unregisterVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGI("RSSI monitor: No data");
+ return NL_SKIP;
+ }
+
+ typedef struct {
+ s8 cur_rssi;
+ mac_addr BSSID;
+ } rssi_monitor_evt;
+
+ rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data();
+
+ if (*mHandler.on_rssi_threshold_breached) {
+ (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi);
+ } else {
+ ALOGW("No RSSI monitor handler registered");
+ }
+
+ return NL_SKIP;
+ }
+
+};
+
+class SetCountryCodeCommand : public WifiCommand {
+private:
+ const char *mCountryCode;
+public:
+ SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code)
+ : WifiCommand(handle, 0) {
+ mCountryCode = country_code;
+ }
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_COUNTRY_CODE);
+ if (ret < 0) {
+ ALOGE("Can't create message to send to driver - %d", ret);
+ return ret;
+ }
+
+ nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
+ ret = mMsg.put_string(ATTR_COUNTRY_CODE, mCountryCode);
+ if (ret < 0) {
+ return ret;
+ }
+
+ mMsg.attr_end(data);
+ return WIFI_SUCCESS;
+
+ }
+};
+
+class GetFeatureSetCommand : public WifiCommand {
+
+private:
+
+ feature_set *fset;
+
+public:
+ GetFeatureSetCommand(wifi_interface_handle handle, feature_set *set)
+ : WifiCommand(handle, 0)
+ {
+ fset = set;
+ }
+
+ virtual int create() {
+ int ret;
+
+ ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_FEATURE_SET);
+ if (ret < 0) {
+ ALOGE("create failed - %d", ret);
+ }
+
+ return ret;
+ }
+
+protected:
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignore reply; cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("vendor data in GetFeatureSetCommand missing!!");
+ return NL_SKIP;
+ }
+
+ void *data = reply.get_vendor_data();
+ if(!fset) {
+ ALOGE("feature_set Pointer not set");
+ return NL_SKIP;
+ }
+ memcpy(fset, data, min(len, (int) sizeof(*fset)));
+ return NL_OK;
+ }
+
+};
+
+
+
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
+{
+ GetMulticastIdCommand cmd(handle, name, group);
+ int res = cmd.requestResponse();
+ if (res < 0)
+ return res;
+ else
+ return cmd.getId();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static bool is_wifi_interface(const char *name)
+{
+ if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
+ /* not a wifi interface; ignore it */
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static int get_interface(const char *name, interface_info *info)
+{
+ strcpy(info->name, name);
+ info->id = if_nametoindex(name);
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_init_interfaces(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+ struct dirent *de;
+
+ DIR *d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ int n = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name) ) {
+ n++;
+ }
+ }
+
+ closedir(d);
+
+ d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
+
+ int i = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name)) {
+ interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+ if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
+ free(ifinfo);
+ continue;
+ }
+ ifinfo->handle = handle;
+ info->interfaces[i] = ifinfo;
+ i++;
+ }
+ }
+
+ closedir(d);
+
+ info->num_interfaces = n;
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
+{
+ hal_info *info = (hal_info *)handle;
+
+ *interfaces = (wifi_interface_handle *)info->interfaces;
+ *num = info->num_interfaces;
+
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
+{
+ interface_info *info = (interface_info *)handle;
+ strcpy(name, info->name);
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+ feature_set set[], int *set_size)
+{
+ return WIFI_ERROR_NOT_SUPPORTED;
+}
+
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
+{
+ SetPnoMacAddrOuiCommand command(handle, scan_oui);
+ return (wifi_error)command.start();
+
+}
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
+{
+ SetNodfsCommand command(handle, nodfs);
+ return (wifi_error) command.requestResponse();
+}
+
+static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
+ iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
+{
+ ALOGD("Start RSSI monitor %d", id);
+ wifi_handle handle = getWifiHandle(iface);
+ SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh);
+ wifi_register_cmd(handle, id, cmd);
+
+ wifi_error result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ }
+ return result;
+}
+
+
+static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface)
+{
+ ALOGD("Stopping RSSI monitor");
+
+ if(id == -1) {
+ wifi_rssi_event_handler handler;
+ memset(&handler, 0, sizeof(handler));
+ SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
+ 0, 0, handler);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+ return wifi_cancel_cmd(id, iface);
+}
+
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
+{
+ GetFeatureSetCommand command(handle, set);
+ return (wifi_error) command.requestResponse();
+}
+
+wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code)
+{
+ SetCountryCodeCommand command(handle, country_code);
+ return (wifi_error) command.requestResponse();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/wifi_logger.cpp b/wifi_logger.cpp
new file mode 100755
index 0000000..4ab5d74
--- /dev/null
+++ b/wifi_logger.cpp
@@ -0,0 +1,1444 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+/* using namespace android; */
+
+typedef enum {
+ ENHANCE_LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
+ ENHANCE_LOGGER_TRIGGER_FW_MEM_DUMP,
+ ENHANCE_LOGGER_GET_FW_MEM_DUMP,
+ ENHANCE_LOGGER_GET_VER,
+ ENHANCE_LOGGER_GET_RING_STATUS,
+ ENHANCE_LOGGER_GET_RING_DATA,
+ ENHANCE_LOGGER_GET_FEATURE,
+ ENHANCE_LOGGER_RESET_LOGGING,
+ ENHANCE_LOGGER_TRIGGER_DRIVER_MEM_DUMP,
+ ENHANCE_LOGGER_GET_DRIVER_MEM_DUMP,
+ ENHANCE_LOGGER_START_PKT_FATE_MONITORING,
+ ENHANCE_LOGGER_GET_TX_PKT_FATES,
+ ENHANCE_LOGGER_GET_RX_PKT_FATES,
+ ENHANCE_LOGGER_GET_WAKE_REASON_STATS,
+} DEBUG_SUB_COMMAND;
+
+typedef enum {
+ ENHANCE_LOGGER_ATTRIBUTE_DRIVER_VER,
+ ENHANCE_LOGGER_ATTRIBUTE_FW_VER,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_ID,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_NAME,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_FLAGS,
+ ENHANCE_LOGGER_ATTRIBUTE_LOG_LEVEL,
+ ENHANCE_LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
+ ENHANCE_LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
+ ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN,
+ ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA,
+ // LOGGER_ATTRIBUTE_FW_ERR_CODE,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_DATA,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS,
+ ENHANCE_LOGGER_ATTRIBUTE_RING_NUM,
+ ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
+ ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
+ ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM,
+ ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA,
+ //Attributes for data used by wake stats subcmd.
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_INVALID = 0,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_CMD_EVENT_WAKE,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_RX_DATA_WAKE,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_UNICAST_CNT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_MULTICAST_CNT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_BROADCAST_CNT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP_PKT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_PKT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RA,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NA,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NS,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP4_RX_MULTICAST_CNT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RX_MULTICAST_CNT,
+ ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_OTHER_RX_MULTICAST_CNT,
+} ENHANCE_LOGGER_ATTRIBUTE;
+
+typedef enum {
+ DEBUG_OFF = 0,
+ DEBUG_NORMAL,
+ DEBUG_VERBOSE,
+ DEBUG_VERY,
+ DEBUG_VERY_VERY,
+} ENHANCE_LOGGER_LEVEL;
+
+typedef enum {
+ GET_FW_VER,
+ GET_DRV_VER,
+ GET_RING_DATA,
+ GET_RING_STATUS,
+ GET_FEATURE,
+ START_RING_LOG,
+ GET_FW_DUMP,
+ GET_DRIVER_DUMP,
+} GetCmdType;
+
+typedef enum {
+ PACKET_MONITOR_START,
+ TX_PACKET_FATE,
+ RX_PACKET_FATE,
+} PktFateReqType;
+
+class DebugCommand : public WifiCommand
+{
+ char *mBuff = NULL;
+ int *mBuffSize = NULL;
+ u32 *mNumRings = NULL;
+ wifi_ring_buffer_status *mStatus = NULL;
+ unsigned int *mSupport = NULL;
+ u32 mVerboseLevel = 0;
+ u32 mFlags = 0;
+ u32 mMaxIntervalSec = 0;
+ u32 mMinDataSize = 0;
+ char *mRingName = NULL;
+ GetCmdType mType;
+
+public:
+
+ // constructor for get version
+ DebugCommand(wifi_interface_handle iface, char *buffer, int *buffer_size,
+ GetCmdType cmdType)
+ : WifiCommand(iface, 0), mBuff(buffer), mBuffSize(buffer_size), mType
+ (cmdType)
+ {
+ memset(mBuff, 0, *mBuffSize);
+ }
+
+ // constructor for ring data
+ DebugCommand(wifi_interface_handle iface, char *ring_name, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mRingName(ring_name), mType(cmdType)
+ { }
+
+ // constructor for ring status
+ DebugCommand(wifi_interface_handle iface, u32 *num_rings,
+ wifi_ring_buffer_status *status, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mNumRings(num_rings), mStatus(status), mType(cmdType)
+ {
+ memset(mStatus, 0, sizeof(wifi_ring_buffer_status) * (*mNumRings));
+ }
+
+ // constructor for feature set
+ DebugCommand(wifi_interface_handle iface, unsigned int *support, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mSupport(support), mType(cmdType)
+ { }
+
+ // constructor for ring params
+ DebugCommand(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+ u32 max_interval_sec, u32 min_data_size, char *ring_name, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mVerboseLevel(verbose_level), mFlags(flags),
+ mMaxIntervalSec(max_interval_sec), mMinDataSize(min_data_size),
+ mRingName(ring_name), mType(cmdType)
+ { }
+
+ int createRingRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_START_LOGGING);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create start ring logger request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put log level; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_RING_FLAGS, mFlags);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ring flags; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_TIME_INTVAL, mMaxIntervalSec);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put log time interval; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE, mMinDataSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put min data size; result = %d", result);
+ return result;
+ }
+ result = request.put_string(ENHANCE_LOGGER_ATTRIBUTE_RING_NAME, mRingName);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ringbuffer name; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+
+ return WIFI_SUCCESS;
+ }
+
+ int createRequest(WifiRequest &request) {
+ int result;
+
+ switch (mType) {
+ case GET_FW_VER:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_VER);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get fw version request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ // Driver expecting only attribute type, passing mbuff as data with
+ // length 0 to avoid undefined state
+ result = request.put(ENHANCE_LOGGER_ATTRIBUTE_FW_VER, mBuff, 0);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get fw version request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_DRV_VER:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_VER);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get drv version request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ // Driver expecting only attribute type, passing mbuff as data with
+ // length 0 to avoid undefined state
+ result = request.put(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_VER, mBuff, 0);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get drv version request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_RING_DATA:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RING_DATA);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get ring data request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_string(ENHANCE_LOGGER_ATTRIBUTE_RING_NAME, mRingName);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put ring data request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ break;
+ }
+
+ case GET_RING_STATUS:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RING_STATUS);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get ring status request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+
+ case GET_FEATURE:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_FEATURE);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get feature request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+
+ case START_RING_LOG:
+ result = createRingRequest(request);
+ break;
+
+ default:
+ ALOGE("Unknown Debug command");
+ result = WIFI_ERROR_UNKNOWN;
+ }
+ return result;
+ }
+
+ int start() {
+ // ALOGD("Start debug command");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create debug request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register debug response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In DebugCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ switch (mType) {
+ case GET_DRV_VER:
+ case GET_FW_VER:
+ {
+ void *data = reply.get_vendor_data();
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d, expected len = %d", len, *mBuffSize);
+ memcpy(mBuff, data, min(len, *mBuffSize));
+ if (*mBuffSize < len)
+ return NL_SKIP;
+ *mBuffSize = len;
+ break;
+ }
+
+ case START_RING_LOG:
+ case GET_RING_DATA:
+ break;
+
+ case GET_RING_STATUS:
+ {
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+ wifi_ring_buffer_status *status(mStatus);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ nl_iterator it(vendor_data);
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_NUM) {
+ unsigned int num_rings = it.get_u32();
+ if (*mNumRings < num_rings) {
+ ALOGE("Not enough status buffers provided, available: %d required: %d",
+ *mNumRings, num_rings);
+ } else {
+ *mNumRings = num_rings;
+ }
+ } else {
+ ALOGE("Unknown attribute: %d expecting %d",
+ it.get_type(), ENHANCE_LOGGER_ATTRIBUTE_RING_NUM);
+ return NL_SKIP;
+ }
+
+ it.next();
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS) {
+ memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status) * (*mNumRings));
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ break;
+ }
+
+ case GET_FEATURE:
+ {
+ void *data = reply.get_vendor_data();
+
+ ALOGD("len = %d, expected len = %lu", reply.get_vendor_data_len(), (unsigned long)sizeof(unsigned int));
+ memcpy(mSupport, data, sizeof(unsigned int));
+ break;
+ }
+
+ default:
+ ALOGW("Unknown Debug command");
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+/* API to get supportable feature */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+ unsigned int *support)
+{
+ if (support) {
+ DebugCommand *cmd = new DebugCommand(iface, support, GET_FEATURE);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Get support buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to get the status of all ring buffers supported by driver */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface,
+ u32 *num_rings, wifi_ring_buffer_status *status)
+{
+ if (status && num_rings) {
+ DebugCommand *cmd = new DebugCommand(iface, num_rings, status, GET_RING_STATUS);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Ring status buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to collect driver records */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name)
+{
+ DebugCommand *cmd = new DebugCommand(iface, ring_name, GET_RING_DATA);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level,
+ u32 flags, u32 max_interval_sec, u32 min_data_size, char *ring_name)
+{
+ if (ring_name) {
+ DebugCommand *cmd = new DebugCommand(iface, verbose_level, flags, max_interval_sec,
+ min_data_size, ring_name, START_RING_LOG);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Ring name NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to collect a firmware version string */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer,
+ int buffer_size)
+{
+ if (buffer && (buffer_size > 0)) {
+ DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_FW_VER);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("FW version buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to collect a driver version string */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size)
+{
+ if (buffer && (buffer_size > 0)) {
+ DebugCommand *cmd = new DebugCommand(iface, buffer, &buffer_size, GET_DRV_VER);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Driver version buffer NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+class SetLogHandler : public WifiCommand
+{
+ wifi_ring_buffer_data_handler mHandler;
+
+public:
+ SetLogHandler(wifi_interface_handle iface, int id, wifi_ring_buffer_data_handler handler)
+ : WifiCommand(iface, id), mHandler(handler)
+ { }
+
+ int start() {
+ ALOGV("Register loghandler");
+ registerVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_RING_EVENT);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int cancel() {
+ /* Send a command to driver to stop generating logging events */
+ ALOGV("Clear loghandler");
+
+ /* unregister event handler */
+ unregisterVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_RING_EVENT);
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_RESET_LOGGING);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to create reset request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to request reset; result = %d", result);
+ return result;
+ }
+
+ ALOGD("Success to clear loghandler");
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ char *buffer = NULL;
+ int buffer_size = 0;
+
+ // ALOGD("In SetLogHandler::handleEvent");
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ // ALOGI("Got Logger event: %d", event_id);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ if(event_id == ENHANCE_LOGGER_RING_EVENT) {
+ wifi_ring_buffer_status status;
+ memset(&status, 0, sizeof(status));
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_STATUS) {
+ memcpy(&status, it.get_data(), sizeof(status));
+ } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_DATA) {
+ buffer_size = it.get_len();
+ buffer = (char *)it.get_data();
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ // ALOGI("Retrieved Debug data");
+ if (mHandler.on_ring_buffer_data) {
+ (*mHandler.on_ring_buffer_data)((char *)status.name, buffer, buffer_size,
+ &status);
+ }
+ } else {
+ ALOGE("Unknown Event");
+ return NL_SKIP;
+ }
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Loghandler start, handle = %p", handle);
+
+ SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Loghandler reset, wifi_request_id = %d, handle = %p", id, handle);
+
+ if (id == -1) {
+ wifi_ring_buffer_data_handler handler;
+ memset(&handler, 0, sizeof(handler));
+
+ SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_cancel_cmd(id, iface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+class SetAlertHandler : public WifiCommand
+{
+ wifi_alert_handler mHandler;
+ int mBuffSize;
+ char *mBuff;
+ int mErrCode;
+
+public:
+ SetAlertHandler(wifi_interface_handle iface, int id, wifi_alert_handler handler)
+ : WifiCommand(iface, id), mHandler(handler), mBuffSize(0), mBuff(NULL),
+ mErrCode(0)
+ { }
+
+ int start() {
+ ALOGV("Start Alerting");
+ registerVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int cancel() {
+ ALOGV("Clear alerthandler");
+
+ /* unregister alert handler */
+ unregisterVendorHandler(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);
+ wifi_unregister_cmd(wifiHandle(), id());
+ ALOGD("Success to clear alerthandler");
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In SetAlertHandler::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d", len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in memory dump response; ignoring it");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA) {
+ ALOGI("Initiating alert callback");
+ if (mHandler.on_alert) {
+ (*mHandler.on_alert)(id(), mBuff, mBuffSize, mErrCode);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ char *buffer = NULL;
+ int buffer_size = 0;
+
+
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = event.get_vendor_data_len();
+ int event_id = event.get_vendor_subcmd();
+ ALOGI("Got event: %d", event_id);
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+
+ if (event_id == ENHANCE_LOGGER_MEM_DUMP_EVENT) {
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
+ mBuffSize = it.get_u32();
+ } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_RING_DATA) {
+ buffer_size = it.get_len();
+ buffer = (char *)it.get_data();
+ /*
+ } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_ERR_CODE) {
+ mErrCode = it.get_u32();
+ */
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ if (mBuffSize) {
+ ALOGD("dump size: %d meta data size: %d", mBuffSize, buffer_size);
+ if (mBuff) free(mBuff);
+ mBuff = (char *)malloc(mBuffSize + buffer_size);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ memcpy(mBuff, buffer, buffer_size);
+
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_MEM_DUMP_EVENT);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get memory dump request; result = %d", result);
+ free(mBuff);
+ return NL_SKIP;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA,
+ (uint64_t)(mBuff+buffer_size));
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get memory dump request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ mBuffSize += buffer_size;
+
+ result = requestResponse(request);
+
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get momory dump response; result = %d", result);
+ }
+ } else {
+ ALOGE("dump event missing dump length attribute");
+ return NL_SKIP;
+ }
+ }
+ return NL_OK;
+ }
+};
+
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Alerthandler start, handle = %p", handle);
+
+ SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = wifi_register_cmd(handle, id, cmd);
+ if (result != WIFI_SUCCESS) {
+ cmd->releaseRef();
+ return result;
+ }
+ result = (wifi_error)cmd->start();
+ if (result != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ cmd->releaseRef();
+ return result;
+ }
+ return result;
+}
+
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ wifi_handle handle = getWifiHandle(iface);
+ ALOGV("Alerthandler reset, wifi_request_id = %d, handle = %p", id, handle);
+
+ if (id == -1) {
+ wifi_alert_handler handler;
+ memset(&handler, 0, sizeof(handler));
+
+ SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ cmd->cancel();
+ cmd->releaseRef();
+ return WIFI_SUCCESS;
+ }
+
+ return wifi_cancel_cmd(id, iface);
+}
+
+
+class PacketFateCommand: public WifiCommand
+{
+ void *mReportBufs = NULL;
+ size_t mNoReqFates = 0;
+ size_t *mNoProvidedFates = NULL;
+ PktFateReqType mReqType;
+
+public:
+ PacketFateCommand(wifi_interface_handle handle)
+ : WifiCommand(handle, 0), mReqType(PACKET_MONITOR_START)
+ { }
+
+ PacketFateCommand(wifi_interface_handle handle, wifi_tx_report *tx_report_bufs,
+ size_t n_requested_fates, size_t *n_provided_fates)
+ : WifiCommand(handle, 0), mReportBufs(tx_report_bufs),
+ mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),
+ mReqType(TX_PACKET_FATE)
+ { }
+
+ PacketFateCommand(wifi_interface_handle handle, wifi_rx_report *rx_report_bufs,
+ size_t n_requested_fates, size_t *n_provided_fates)
+ : WifiCommand(handle, 0), mReportBufs(rx_report_bufs),
+ mNoReqFates(n_requested_fates), mNoProvidedFates(n_provided_fates),
+ mReqType(RX_PACKET_FATE)
+ { }
+
+ int createRequest(WifiRequest& request) {
+ if (mReqType == TX_PACKET_FATE) {
+ ALOGD("%s Get Tx packet fate request\n", __FUNCTION__);
+ return createTxPktFateRequest(request);
+ } else if (mReqType == RX_PACKET_FATE) {
+ ALOGD("%s Get Rx packet fate request\n", __FUNCTION__);
+ return createRxPktFateRequest(request);
+ } else if (mReqType == PACKET_MONITOR_START) {
+ ALOGD("%s Monitor packet fate request\n", __FUNCTION__);
+ return createMonitorPktFateRequest(request);
+ } else {
+ ALOGE("%s Unknown packet fate request\n", __FUNCTION__);
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+ return WIFI_SUCCESS;
+ }
+
+ int createMonitorPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_START_PKT_FATE_MONITORING);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ request.attr_end(data);
+ return result;
+ }
+
+ int createTxPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_TX_PKT_FATES);
+ if (result < 0) {
+ return result;
+ }
+
+ memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_tx_report)));
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int createRxPktFateRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_RX_PKT_FATES);
+ if (result < 0) {
+ return result;
+ }
+
+ memset(mReportBufs, 0, (mNoReqFates * sizeof(wifi_rx_report)));
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM, mNoReqFates);
+ if (result < 0) {
+ return result;
+ }
+ result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_DATA, (uint64_t)mReportBufs);
+ if (result < 0) {
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start get packet fate command\n");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createRequest(request);
+ if (result < 0) {
+ ALOGE("Failed to create get pkt fate request; result = %d\n", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get pkt fate response; result = %d\n", result);
+ }
+ return result;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ ALOGD("In GetPktFateCommand::handleResponse\n");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGI("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = reply.get_vendor_id();
+ int subcmd = reply.get_vendor_subcmd();
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGI("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
+
+ if (mReqType == TX_PACKET_FATE) {
+ ALOGI("Response recieved for get TX pkt fate command\n");
+ } else if (mReqType == RX_PACKET_FATE) {
+ ALOGI("Response recieved for get RX pkt fate command\n");
+ } else if (mReqType == PACKET_MONITOR_START) {
+ ALOGI("Response recieved for monitor pkt fate command\n");
+ return NL_OK;
+ } else {
+ ALOGE("Response recieved for unknown pkt fate command\n");
+ return NL_SKIP;
+ }
+
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetPktFateCommand response; ignoring it\n");
+ return NL_SKIP;
+ }
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_PKT_FATE_NUM) {
+ *mNoProvidedFates = it.get_u32();
+ ALOGI("No: of pkt fates provided is %zu\n", *mNoProvidedFates);
+ } else {
+ ALOGE("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* NO events to handle here! */
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle,
+ wifi_tx_report *tx_report_bufs, size_t n_requested_fates,
+ size_t *n_provided_fates)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle, tx_report_bufs,
+ n_requested_fates, n_provided_fates);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ memset(tx_report_bufs, 0, (n_requested_fates * sizeof(wifi_tx_report)));
+ return result;
+}
+
+wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle,
+ wifi_rx_report *rx_report_bufs, size_t n_requested_fates,
+ size_t *n_provided_fates)
+{
+ PacketFateCommand *cmd = new PacketFateCommand(handle, rx_report_bufs,
+ n_requested_fates, n_provided_fates);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ memset(rx_report_bufs, 0, (n_requested_fates * sizeof(wifi_rx_report)));
+ return result;
+}
+
+class MemoryDumpCommand: public WifiCommand
+{
+ wifi_firmware_memory_dump_handler mHandler;
+ wifi_driver_memory_dump_callbacks mcallback;
+ int mBuffSize;
+ char *mBuff;
+ GetCmdType mType;
+
+public:
+ MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler, GetCmdType cmdtype )
+ : WifiCommand(iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL), mType(cmdtype)
+ {
+ memset(&mcallback, 0, sizeof(wifi_driver_memory_dump_callbacks));
+ }
+
+ MemoryDumpCommand(wifi_interface_handle iface, wifi_driver_memory_dump_callbacks callback, GetCmdType cmdtype)
+ : WifiCommand(iface, 0), mcallback(callback), mBuffSize(0), mBuff(NULL), mType(cmdtype)
+ {
+ memset(&mHandler, 0, sizeof(wifi_firmware_memory_dump_handler));
+ }
+
+ int createRequest(WifiRequest &request) {
+ int result;
+
+ switch (mType) {
+ case GET_FW_DUMP:
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_TRIGGER_FW_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create trigger fw memory dump request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+ case GET_DRIVER_DUMP :
+ {
+ result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_TRIGGER_DRIVER_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create trigger driver memory dump request; result = %d", result);
+ return result;
+ }
+ break;
+ }
+ default:
+ ALOGE("Unknown Debug command");
+ result = WIFI_ERROR_UNKNOWN;
+ }
+ return result;
+ }
+ int start() {
+ ALOGD("Start memory dump command");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create trigger memory dump request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register trigger memory dump response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+ ALOGD("In MemoryDumpCommand::handleResponse");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ int len = reply.get_vendor_data_len();
+
+ ALOGD("len = %d", len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in memory dump response; ignoring it");
+ return NL_SKIP;
+ }
+ switch(mType) {
+ case GET_FW_DUMP:
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
+ mBuffSize = it.get_u32();
+ if (mBuff)
+ free(mBuff);
+ mBuff = (char *)malloc(mBuffSize);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_FW_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get fw memory dump request; result = %d", result);
+ free(mBuff);
+ return NL_SKIP;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_LEN, mBuffSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get fw memory dump request; result = %d", result);
+ return result;
+ }
+ result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get fw memory dump request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get fw momory dump response; result = %d", result);
+ }
+ } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_FW_DUMP_DATA) {
+ ALOGI("Initiating memory dump callback");
+ if (mHandler.on_firmware_memory_dump) {
+ (*mHandler.on_firmware_memory_dump)(mBuff, mBuffSize);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ break;
+ case GET_DRIVER_DUMP :
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN) {
+ mBuffSize = it.get_u32();
+ if (mBuff)
+ free(mBuff);
+ mBuff = (char *)malloc(mBuffSize);
+ if (!mBuff) {
+ ALOGE("Buffer allocation failed");
+ return NL_SKIP;
+ }
+ WifiRequest request(familyId(), ifaceId());
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_DRIVER_MEM_DUMP);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create get driver memory dump request; result = %d", result);
+ free(mBuff);
+ return NL_SKIP;
+ }
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN, mBuffSize);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get driver memory dump request; result = %d", result);
+ return result;
+ }
+ result = request.put_u64(ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA, (uint64_t)mBuff);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put get driver memory dump request; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get driver momory dump response; result = %d", result);
+ }
+ } else if (it.get_type() == ENHANCE_LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA) {
+ ALOGI("Initiating memory dump callback");
+ if (mcallback.on_driver_memory_dump) {
+ (*mcallback.on_driver_memory_dump)(mBuff, mBuffSize);
+ }
+ if (mBuff) {
+ free(mBuff);
+ mBuff = NULL;
+ }
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d",
+ it.get_type(), it.get_len());
+ }
+ }
+ break;
+ case GET_FW_VER:
+ case GET_DRV_VER:
+ case GET_RING_DATA:
+ case GET_RING_STATUS:
+ case GET_FEATURE:
+ case START_RING_LOG:
+ default:
+ {
+ ALOGW("Ignoring GetCmdType %d \n", mType);
+ }
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+/* API to collect a firmware memory dump for a given iface */
+wifi_error wifi_get_firmware_memory_dump( wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler)
+{
+ MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, handler, GET_FW_DUMP);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+
+wifi_error wifi_get_driver_memory_dump(wifi_interface_handle iface,
+ wifi_driver_memory_dump_callbacks callbacks)
+{
+ MemoryDumpCommand *cmd = new MemoryDumpCommand(iface, callbacks, GET_DRIVER_DUMP);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+}
+class WifiLoggerCommand: public WifiCommand
+{
+ WLAN_DRIVER_WAKE_REASON_CNT *mGetWakeStats;
+
+public:
+ WifiLoggerCommand(wifi_interface_handle handle, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
+ : WifiCommand(handle, 0), mGetWakeStats(wifi_wake_reason_cnt)
+ { }
+
+ int createRequest(WifiRequest& request) {
+ int result = request.create(GOOGLE_OUI, ENHANCE_LOGGER_GET_WAKE_REASON_STATS);
+ if (result < 0) {
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ, mGetWakeStats->cmd_event_wake_cnt_sz);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put wake_cnt_sz; result = %d", result);
+ return result;
+ }
+ result = request.put_u32(ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ, mGetWakeStats->driver_fw_local_wake_cnt_sz);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to put driver_fw_local_wake_cnt; result = %d", result);
+ return result;
+ }
+ request.attr_end(data);
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start get wake reason stats command\n");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result < 0) {
+ ALOGE("Failed to create get wake reason stats request; result = %d\n", result);
+ return result;
+ }
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register get wake reason stats response; result = %d\n", result);
+ }
+ return result;
+ }
+
+ int handleResponse(WifiEvent& reply) {
+ int len = 0;
+ ALOGD("In WifiLoggerCommand::handleResponse\n");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGI("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ len = reply.get_vendor_data_len();
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("No Debug data found");
+ return NL_SKIP;
+ }
+ nl_iterator it(vendor_data);
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_CMD_EVENT_WAKE) {
+ ALOGE("TOTAL_CMD_EVENT_WAKE not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->total_cmd_event_wake = it.get_u32();
+ it.next();
+
+ if(mGetWakeStats->total_cmd_event_wake && mGetWakeStats->cmd_event_wake_cnt) {
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR) {
+ ALOGE("CMD_EVENT_WAKE_CNT_PTR not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ len = it.get_len();
+ mGetWakeStats->cmd_event_wake_cnt_used = (len < mGetWakeStats->cmd_event_wake_cnt_sz) ? len : mGetWakeStats->cmd_event_wake_cnt_sz;
+ memcpy(mGetWakeStats->cmd_event_wake_cnt, it.get_data(), mGetWakeStats->cmd_event_wake_cnt_used * sizeof(int));
+ } else {
+ mGetWakeStats->cmd_event_wake_cnt_used = 0;
+ }
+
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE) {
+ ALOGE("TOTAL_DRIVER_FW_LOCAL_WAKE not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->total_driver_fw_local_wake = it.get_u32();
+ it.next();
+
+ if(mGetWakeStats->total_driver_fw_local_wake && mGetWakeStats->driver_fw_local_wake_cnt) {
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR) {
+ ALOGE("DRIVER_FW_LOCAL_WAKE_CNT_PTR not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ len = it.get_len();
+ mGetWakeStats->driver_fw_local_wake_cnt_used= (len < mGetWakeStats->driver_fw_local_wake_cnt_sz) ? len : mGetWakeStats->driver_fw_local_wake_cnt_sz;
+ memcpy(mGetWakeStats->driver_fw_local_wake_cnt, it.get_data(), mGetWakeStats->driver_fw_local_wake_cnt_used * sizeof(int));
+ } else {
+ mGetWakeStats->driver_fw_local_wake_cnt_used= 0;
+ }
+
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_TOTAL_RX_DATA_WAKE) {
+ ALOGE("TOTAL_RX_DATA_WAKE not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->total_rx_data_wake = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_UNICAST_CNT) {
+ ALOGE("RX_UNICAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_details.rx_unicast_cnt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_MULTICAST_CNT) {
+ ALOGE("RX_MULTICAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_details.rx_multicast_cnt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_RX_BROADCAST_CNT) {
+ ALOGE("RX_BROADCAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_details.rx_broadcast_cnt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP_PKT) {
+ ALOGE("ICMP_PKT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_pkt_classification_info .icmp_pkt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_PKT) {
+ ALOGE("ICMP6_PKT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_pkt_classification_info .icmp6_pkt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RA) {
+ ALOGE("ICMP6_RA not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_pkt_classification_info .icmp6_ra = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NA) {
+ ALOGE("ICMP6_NA not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_pkt_classification_info .icmp6_na = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_NS) {
+ ALOGE("ICMP6_NS not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_wake_pkt_classification_info .icmp6_ns = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP4_RX_MULTICAST_CNT) {
+ ALOGE("ICMP4_RX_MULTICAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_ICMP6_RX_MULTICAST_CNT) {
+ ALOGE("ICMP6_RX_MULTICAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt = it.get_u32();
+ it.next();
+
+ if (it.get_type() != ENHANCE_LOGGER_ATTRIBUTE_WAKE_STATS_OTHER_RX_MULTICAST_CNT) {
+ ALOGE("OTHER_RX_MULTICAST_CNT not found %d", it.get_type());
+ return NL_SKIP;
+ }
+
+ mGetWakeStats->rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt = it.get_u32();
+
+ return NL_OK;
+ }
+
+ int handleEvent(WifiEvent& event) {
+ /* NO events to handle here! */
+ return NL_SKIP;
+ }
+};
+
+ /* Function to get wake lock stats */
+wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,
+ WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt)
+{
+ if(wifi_wake_reason_cnt) {
+ WifiLoggerCommand *cmd = new WifiLoggerCommand(iface,wifi_wake_reason_cnt);
+ NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
+ wifi_error result = (wifi_error)cmd->start();
+ cmd->releaseRef();
+ return result;
+ } else {
+ ALOGE("Reason cnt NULL");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
diff --git a/wifi_nan.cpp b/wifi_nan.cpp
new file mode 100755
index 0000000..35c01ee
--- /dev/null
+++ b/wifi_nan.cpp
@@ -0,0 +1,1419 @@
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/handlers.h>
+
+#include "sync.h"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+#define SLSI_WIFI_HAL_NAN_VERSION 1
+
+#define CHECK_WIFI_STATUS_RETURN_FAIL(result, LOGSTR) \
+ if (result != WIFI_SUCCESS) {\
+ ALOGE(LOGSTR" [result:%d]", result);\
+ return result;\
+ }
+
+#define CHECK_CONFIG_PUT_8_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+ if (config) {\
+ result = request.put_u8(nan_attribute, val); \
+ if (result != WIFI_SUCCESS) {\
+ ALOGE(FAIL_STR" [result:%d]", result);\
+ return result;\
+ }\
+ }
+
+#define CHECK_CONFIG_PUT_16_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+ if (config) {\
+ result = request.put_u16(nan_attribute, val); \
+ if (result != WIFI_SUCCESS) {\
+ ALOGE(FAIL_STR" [result:%d]", result);\
+ return result;\
+ }\
+ }
+
+
+#define CHECK_CONFIG_PUT_32_RETURN_FAIL(config, val, nan_attribute, request, result, FAIL_STR) \
+ if (config) {\
+ result = request.put_u32(nan_attribute, val); \
+ if (result != WIFI_SUCCESS) {\
+ ALOGE(FAIL_STR" [result:%d]", result);\
+ return result;\
+ }\
+ }
+
+#define CHECK_CONFIG_PUT_RETURN_FAIL(config, valptr, len, nan_attribute, request, result, FAIL_STR) \
+ if (config) {\
+ result = request.put(nan_attribute, valptr, len); \
+ if (result != WIFI_SUCCESS) {\
+ ALOGE(FAIL_STR" [result:%d]", result);\
+ return result;\
+ }\
+ }
+
+typedef enum {
+ NAN_REQ_ATTR_MASTER_PREF,
+ NAN_REQ_ATTR_CLUSTER_LOW,
+ NAN_REQ_ATTR_CLUSTER_HIGH,
+ NAN_REQ_ATTR_HOP_COUNT_LIMIT_VAL,
+ NAN_REQ_ATTR_SID_BEACON_VAL,
+
+ NAN_REQ_ATTR_SUPPORT_2G4_VAL,
+ NAN_REQ_ATTR_SUPPORT_5G_VAL,
+
+ NAN_REQ_ATTR_RSSI_CLOSE_2G4_VAL,
+ NAN_REQ_ATTR_RSSI_MIDDLE_2G4_VAL,
+ NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL,
+ NAN_REQ_ATTR_BEACONS_2G4_VAL,
+ NAN_REQ_ATTR_SDF_2G4_VAL,
+ NAN_REQ_ATTR_CHANNEL_2G4_MHZ_VAL,
+ NAN_REQ_ATTR_RSSI_PROXIMITY_VAL,
+
+
+ NAN_REQ_ATTR_RSSI_CLOSE_5G_VAL,
+ NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL,
+ NAN_REQ_ATTR_RSSI_MIDDLE_5G_VAL,
+ NAN_REQ_ATTR_RSSI_PROXIMITY_5G_VAL,
+ NAN_REQ_ATTR_BEACON_5G_VAL,
+ NAN_REQ_ATTR_SDF_5G_VAL,
+ NAN_REQ_ATTR_CHANNEL_5G_MHZ_VAL,
+
+ NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL,
+ NAN_REQ_ATTR_OUI_VAL,
+ NAN_REQ_ATTR_MAC_ADDR_VAL,
+ NAN_REQ_ATTR_CLUSTER_VAL,
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME,
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD,
+ NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL,
+ NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL,
+ NAN_REQ_ATTR_CONN_CAPABILITY_PAYLOAD_TX,
+ NAN_REQ_ATTR_CONN_CAPABILITY_IBSS,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WFD,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WFDS,
+ NAN_REQ_ATTR_CONN_CAPABILITY_TDLS,
+ NAN_REQ_ATTR_CONN_CAPABILITY_MESH,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WLAN_INFRA,
+ NAN_REQ_ATTR_DISCOVERY_ATTR_NUM_ENTRIES,
+ NAN_REQ_ATTR_DISCOVERY_ATTR_VAL,
+ NAN_REQ_ATTR_CONN_TYPE,
+ NAN_REQ_ATTR_NAN_ROLE,
+ NAN_REQ_ATTR_TRANSMIT_FREQ,
+ NAN_REQ_ATTR_AVAILABILITY_DURATION,
+ NAN_REQ_ATTR_AVAILABILITY_INTERVAL,
+ NAN_REQ_ATTR_MESH_ID_LEN,
+ NAN_REQ_ATTR_MESH_ID,
+ NAN_REQ_ATTR_INFRASTRUCTURE_SSID_LEN,
+ NAN_REQ_ATTR_INFRASTRUCTURE_SSID,
+ NAN_REQ_ATTR_FURTHER_AVAIL_NUM_ENTRIES,
+ NAN_REQ_ATTR_FURTHER_AVAIL_VAL,
+ NAN_REQ_ATTR_FURTHER_AVAIL_ENTRY_CTRL,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_CLASS,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_MAPID,
+ NAN_REQ_ATTR_FURTHER_AVAIL_INTERVAL_BITMAP,
+ NAN_REQ_ATTR_PUBLISH_ID,
+ NAN_REQ_ATTR_PUBLISH_TTL,
+ NAN_REQ_ATTR_PUBLISH_PERIOD,
+ NAN_REQ_ATTR_PUBLISH_TYPE,
+ NAN_REQ_ATTR_PUBLISH_TX_TYPE,
+ NAN_REQ_ATTR_PUBLISH_COUNT,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_NAME_LEN,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_NAME,
+ NAN_REQ_ATTR_PUBLISH_MATCH_ALGO,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_INFO_LEN,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_INFO,
+ NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER_LEN,
+ NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER,
+ NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER_LEN,
+ NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER,
+ NAN_REQ_ATTR_PUBLISH_RSSI_THRESHOLD_FLAG,
+ NAN_REQ_ATTR_PUBLISH_CONN_MAP,
+ NAN_REQ_ATTR_PUBLISH_RECV_IND_CFG,
+ NAN_REQ_ATTR_SUBSCRIBE_ID,
+ NAN_REQ_ATTR_SUBSCRIBE_TTL,
+ NAN_REQ_ATTR_SUBSCRIBE_PERIOD,
+ NAN_REQ_ATTR_SUBSCRIBE_TYPE,
+ NAN_REQ_ATTR_SUBSCRIBE_RESP_FILTER_TYPE,
+ NAN_REQ_ATTR_SUBSCRIBE_RESP_INCLUDE,
+ NAN_REQ_ATTR_SUBSCRIBE_USE_RESP_FILTER,
+ NAN_REQ_ATTR_SUBSCRIBE_SSI_REQUIRED,
+ NAN_REQ_ATTR_SUBSCRIBE_MATCH_INDICATOR,
+ NAN_REQ_ATTR_SUBSCRIBE_COUNT,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME_LEN,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO_LEN,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO,
+ NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER_LEN,
+ NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER,
+ NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER_LEN,
+ NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER,
+ NAN_REQ_ATTR_SUBSCRIBE_RSSI_THRESHOLD_FLAG,
+ NAN_REQ_ATTR_SUBSCRIBE_CONN_MAP,
+ NAN_REQ_ATTR_SUBSCRIBE_NUM_INTF_ADDR_PRESENT,
+ NAN_REQ_ATTR_SUBSCRIBE_INTF_ADDR,
+ NAN_REQ_ATTR_SUBSCRIBE_RECV_IND_CFG,
+ NAN_REQ_ATTR_FOLLOWUP_ID,
+ NAN_REQ_ATTR_FOLLOWUP_REQUESTOR_ID,
+ NAN_REQ_ATTR_FOLLOWUP_ADDR,
+ NAN_REQ_ATTR_FOLLOWUP_PRIORITY,
+ NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME_LEN,
+ NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME,
+ NAN_REQ_ATTR_FOLLOWUP_TX_WINDOW,
+ NAN_REQ_ATTR_FOLLOWUP_RECV_IND_CFG,
+} NAN_REQ_ATTRIBUTES;
+
+typedef enum {
+ NAN_REPLY_ATTR_STATUS_TYPE,
+ NAN_REPLY_ATTR_VALUE,
+ NAN_REPLY_ATTR_RESPONSE_TYPE,
+ NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE,
+ NAN_REPLY_ATTR_CAP_MAX_CONCURRENT_CLUSTER,
+ NAN_REPLY_ATTR_CAP_MAX_PUBLISHES,
+ NAN_REPLY_ATTR_CAP_MAX_SUBSCRIBES,
+ NAN_REPLY_ATTR_CAP_MAX_SERVICE_NAME_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_MATCH_FILTER_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_TOTAL_MATCH_FILTER_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_SERVICE_SPECIFIC_INFO_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_VSA_DATA_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_MESH_DATA_LEN,
+ NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES,
+ NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS,
+ NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN,
+} NAN_RESP_ATTRIBUTES;
+
+typedef enum {
+ NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID,
+ NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID,
+ NAN_EVT_ATTR_MATCH_ADDR,
+ NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO_LEN,
+ NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO,
+ NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER_LEN,
+ NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER,
+ NAN_EVT_ATTR_MATCH_MATCH_OCCURED_FLAG,
+ NAN_EVT_ATTR_MATCH_OUT_OF_RESOURCE_FLAG,
+ NAN_EVT_ATTR_MATCH_RSSI_VALUE,
+/*CONN_CAPABILITY*/
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFD_SUPPORTED,
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFDS_SUPPORTED,
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_TDLS_SUPPORTED,
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_IBSS_SUPPORTED,
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_MESH_SUPPORTED,
+ NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_WLAN_INFRA_FIELD,
+ NAN_EVT_ATTR_MATCH_NUM_RX_DISCOVERY_ATTR,
+ NAN_EVT_ATTR_MATCH_RX_DISCOVERY_ATTR,
+/*NANRECEIVEPOSTDISCOVERY DISCOVERY_ATTR,*/
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_TYPE,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_ROLE,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_DURATION,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_AVAIL_INTERVAL_BITMAP,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_MAPID,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_ADDR,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID_LEN,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_LEN,
+ NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_VAL,
+
+ NAN_EVT_ATTR_MATCH_NUM_CHANS,
+ NAN_EVT_ATTR_MATCH_FAMCHAN,
+/*FAMCHAN[32],*/
+ NAN_EVT_ATTR_MATCH_FAM_ENTRY_CONTROL,
+ NAN_EVT_ATTR_MATCH_FAM_CLASS_VAL,
+ NAN_EVT_ATTR_MATCH_FAM_CHANNEL,
+ NAN_EVT_ATTR_MATCH_FAM_MAPID,
+ NAN_EVT_ATTR_MATCH_FAM_AVAIL_INTERVAL_BITMAP,
+ NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE_LEN,
+ NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE,
+ NAN_EVT_ATTR_PUBLISH_ID,
+ NAN_EVT_ATTR_PUBLISH_REASON,
+ NAN_EVT_ATTR_SUBSCRIBE_ID,
+ NAN_EVT_ATTR_SUBSCRIBE_REASON,
+ NAN_EVT_ATTR_DISABLED_REASON,
+ NAN_EVT_ATTR_FOLLOWUP_PUBLISH_SUBSCRIBE_ID,
+ NAN_EVT_ATTR_FOLLOWUP_REQUESTOR_INSTANCE_ID,
+ NAN_EVT_ATTR_FOLLOWUP_ADDR,
+ NAN_EVT_ATTR_FOLLOWUP_DW_OR_FAW,
+ NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO_LEN,
+ NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO,
+ NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE ,
+ NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR,
+ NAN_EVT_ATTR_DISCOVERY_ENGINE_CLUSTER
+
+} NAN_EVT_ATTRIBUTES;
+
+class NanCommand : public WifiCommand {
+ static NanCallbackHandler callbackEventHandler;
+ int subscribeID[2];
+ int publishID[2];
+ int followupID[2];
+ int version;
+ NanCapabilities capabilities;
+
+ void registerNanEvents(void) {
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_PUBLISH_TERMINATED);
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH);
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH_EXPIRED);
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED);
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_FOLLOWUP);
+ registerVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_DISCOVERY_ENGINE);
+ }
+
+ void unregisterNanEvents(void) {
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_PUBLISH_TERMINATED);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_MATCH_EXPIRED);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_FOLLOWUP);
+ unregisterVendorHandler(GOOGLE_OUI, SLSI_NAN_EVENT_DISCOVERY_ENGINE);
+ }
+
+ int processResponse(WifiEvent &reply, NanResponseMsg *response) {
+ NanCapabilities *capabilities = &response->body.nan_capabilities;
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ unsigned int val;
+
+ for(nl_iterator nl_itr(vendor_data); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_REPLY_ATTR_STATUS_TYPE:
+ response->status = NanStatusType(nl_itr.get_u32());
+ break;
+ case NAN_REPLY_ATTR_VALUE:
+ val = nl_itr.get_u32();
+ if (val) {
+ strncpy(response->nan_error, "Lower_layer_error",NAN_ERROR_STR_LEN);
+ }
+ break;
+ case NAN_REPLY_ATTR_RESPONSE_TYPE:
+ response->response_type = NanResponseType(nl_itr.get_u32());
+ break;
+ case NAN_REPLY_ATTR_PUBLISH_SUBSCRIBE_TYPE:
+ response->body.publish_response.publish_id = nl_itr.get_u16();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_CONCURRENT_CLUSTER:
+ capabilities->max_concurrent_nan_clusters = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_PUBLISHES:
+ capabilities->max_publishes = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_SUBSCRIBES:
+ capabilities->max_subscribes = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_SERVICE_NAME_LEN:
+ capabilities->max_service_name_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_MATCH_FILTER_LEN:
+ capabilities->max_match_filter_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_TOTAL_MATCH_FILTER_LEN:
+ capabilities->max_total_match_filter_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_SERVICE_SPECIFIC_INFO_LEN:
+ capabilities->max_service_specific_info_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_VSA_DATA_LEN:
+ capabilities->max_vsa_data_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_MESH_DATA_LEN:
+ capabilities->max_mesh_data_len = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_NDI_INTERFACES:
+ capabilities->max_ndi_interfaces = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_NDP_SESSIONS:
+ capabilities->max_ndp_sessions = nl_itr.get_u32();
+ break;
+ case NAN_REPLY_ATTR_CAP_MAX_APP_INFO_LEN:
+ capabilities->max_app_info_len = nl_itr.get_u32();
+ break;
+ default :
+ ALOGE("received unknown type(%d) in response", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+ this->capabilities = *capabilities;
+ return NL_OK;
+ }
+
+ int processMatchEvent(WifiEvent &event) {
+ NanMatchInd ind;
+ memset(&ind,0,sizeof(NanMatchInd));
+ int famchan_idx = 0, disc_idx = 0;
+ nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
+
+ for(nl_iterator nl_itr(vendor_data); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID:
+ ind.publish_subscribe_id = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID:
+ ind.requestor_instance_id = nl_itr.get_u32();
+ break;
+ case NAN_EVT_ATTR_MATCH_ADDR:
+ memcpy(ind.addr, nl_itr.get_data(), NAN_MAC_ADDR_LEN);
+ break;
+ case NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO_LEN:
+ ind.service_specific_info_len = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_MATCH_SERVICE_SPECIFIC_INFO:
+ memcpy(ind.service_specific_info, nl_itr.get_data(), ind.service_specific_info_len);
+ break;
+ case NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER_LEN:
+ ind.sdf_match_filter_len = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_MATCH_SDF_MATCH_FILTER:
+ memcpy(ind.sdf_match_filter, nl_itr.get_data(), ind.sdf_match_filter_len);
+ break;
+ case NAN_EVT_ATTR_MATCH_MATCH_OCCURED_FLAG:
+ ind.match_occured_flag = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_OUT_OF_RESOURCE_FLAG:
+ ind.out_of_resource_flag = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_RSSI_VALUE:
+ ind.rssi_value = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_IBSS_SUPPORTED:
+ ind.conn_capability.is_ibss_supported = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFD_SUPPORTED:
+ ind.conn_capability.is_wfd_supported = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_WFDS_SUPPORTED:
+ ind.conn_capability.is_wfds_supported = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_TDLS_SUPPORTED:
+ ind.conn_capability.is_tdls_supported = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_IS_MESH_SUPPORTED:
+ ind.conn_capability.is_mesh_supported= nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CONN_CAPABILITY_WLAN_INFRA_FIELD:
+ ind.conn_capability.wlan_infra_field = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_NUM_RX_DISCOVERY_ATTR:
+ ind.num_rx_discovery_attr = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_RX_DISCOVERY_ATTR:
+ NanReceivePostDiscovery *disc_attr;
+ disc_attr = &ind.discovery_attr[disc_idx];
+ disc_idx++;
+ for(nl_iterator nl_nested_itr((struct nlattr *)nl_itr.get_data()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+ switch(nl_nested_itr.get_type()) {
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_TYPE:
+ disc_attr->type = (NanConnectionType)nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_ROLE:
+ disc_attr->role = (NanDeviceRole)nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_DURATION:
+ disc_attr->duration = (NanAvailDuration)nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_AVAIL_INTERVAL_BITMAP:
+ disc_attr->avail_interval_bitmap = nl_nested_itr.get_u32();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_MAPID:
+ disc_attr->mapid = nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_ADDR:
+ memcpy(disc_attr->addr, nl_nested_itr.get_data(), NAN_MAC_ADDR_LEN);
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID_LEN:
+ disc_attr->mesh_id_len = nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_MESH_ID:
+ memcpy(disc_attr->mesh_id, nl_nested_itr.get_data(), disc_attr->mesh_id_len);
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_LEN:
+ disc_attr->infrastructure_ssid_len = nl_nested_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_MATCH_DISC_ATTR_INFRASTRUCTURE_SSID_VAL:
+ memcpy(disc_attr->infrastructure_ssid_val, nl_nested_itr.get_data(), disc_attr->infrastructure_ssid_len);
+ break;
+ }
+ }
+ break;
+ case NAN_EVT_ATTR_MATCH_NUM_CHANS:
+ ind.num_chans = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_FAMCHAN:
+ NanFurtherAvailabilityChannel *famchan;
+ famchan = &ind.famchan[famchan_idx];
+ famchan_idx++;
+ for(nl_iterator nl_nested_itr((struct nlattr *)nl_itr.get_data()); nl_nested_itr.has_next(); nl_nested_itr.next()) {
+ switch(nl_nested_itr.get_type()) {
+ case NAN_EVT_ATTR_MATCH_FAM_ENTRY_CONTROL:
+ famchan->entry_control = (NanAvailDuration)nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_FAM_CLASS_VAL:
+ famchan->class_val = nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_FAM_CHANNEL:
+ famchan->channel = nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_FAM_MAPID:
+ famchan->mapid = nl_nested_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_FAM_AVAIL_INTERVAL_BITMAP:
+ famchan->avail_interval_bitmap = nl_nested_itr.get_u32();
+ break;
+ }
+ }
+ break;
+ case NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE_LEN:
+ ind.cluster_attribute_len = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_MATCH_CLUSTER_ATTRIBUTE:
+ memcpy(ind.cluster_attribute, nl_itr.get_data(), ind.cluster_attribute_len);
+ break;
+ }
+ }
+
+ if (this->callbackEventHandler.EventMatch)
+ this->callbackEventHandler.EventMatch(&ind);
+ return NL_OK;
+ }
+
+ int processMatchExpiredEvent(WifiEvent &event) {
+ NanMatchExpiredInd ind;
+ memset(&ind,0,sizeof(NanMatchExpiredInd));
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_MATCH_PUBLISH_SUBSCRIBE_ID:
+ ind.publish_subscribe_id = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_MATCH_REQUESTOR_INSTANCE_ID:
+ ind.requestor_instance_id = nl_itr.get_u32();
+ break;
+ default :
+ ALOGE("processMatchExpiredEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+
+ if (callbackEventHandler.EventMatchExpired)
+ callbackEventHandler.EventMatchExpired(&ind);
+
+ return NL_OK;
+ }
+
+ int processPublishTerminatedEvent(WifiEvent &event) {
+ NanPublishTerminatedInd ind;
+ memset(&ind,0,sizeof(ind));
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_PUBLISH_ID:
+ ind.publish_id = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_PUBLISH_REASON:
+ ind.reason = (NanStatusType)nl_itr.get_u32();
+ break;
+ default :
+ ALOGE("processPublishTerminatedEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+
+ if (callbackEventHandler.EventPublishTerminated)
+ callbackEventHandler.EventPublishTerminated(&ind);
+
+ return NL_OK;
+
+ }
+
+ int processSubscribeTerminatedEvent(WifiEvent &event) {
+ NanSubscribeTerminatedInd ind;
+ memset(&ind,0,sizeof(ind));
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_SUBSCRIBE_ID:
+ ind.subscribe_id = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_SUBSCRIBE_REASON:
+ ind.reason = (NanStatusType)nl_itr.get_u32();
+ break;
+ default :
+ ALOGE("processSubscribeTerminatedEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+
+ if (callbackEventHandler.EventSubscribeTerminated)
+ callbackEventHandler.EventSubscribeTerminated(&ind);
+
+ return NL_OK;
+ }
+
+ int processFollowupEvent(WifiEvent &event) {
+ NanFollowupInd ind;
+ memset(&ind,0,sizeof(ind));
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_FOLLOWUP_PUBLISH_SUBSCRIBE_ID:
+ ind.publish_subscribe_id = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_FOLLOWUP_REQUESTOR_INSTANCE_ID:
+ ind.requestor_instance_id = nl_itr.get_u32();
+ break;
+ case NAN_EVT_ATTR_FOLLOWUP_ADDR:
+ memcpy(ind.addr, nl_itr.get_data(), NAN_MAC_ADDR_LEN);
+ break;
+ case NAN_EVT_ATTR_FOLLOWUP_DW_OR_FAW:
+ ind.dw_or_faw = nl_itr.get_u8();
+ break;
+ case NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO_LEN:
+ ind.service_specific_info_len = nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_FOLLOWUP_SERVICE_SPECIFIC_INFO:
+ memcpy(ind.service_specific_info, nl_itr.get_data(), ind.service_specific_info_len);
+ break;
+ default :
+ ALOGE("processNanDisabledEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+
+ if (callbackEventHandler.EventFollowup)
+ callbackEventHandler.EventFollowup(&ind);
+
+ return NL_OK;
+ }
+
+ int processNanDisabledEvent(WifiEvent &event) {
+ NanDisabledInd ind;
+ memset(&ind,0,sizeof(ind));
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_DISABLED_REASON:
+ ind.reason = (NanStatusType)nl_itr.get_u32();
+ break;
+ default :
+ ALOGE("processNanDisabledEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+
+ if (callbackEventHandler.EventDisabled)
+ callbackEventHandler.EventDisabled(&ind);
+
+ return NL_OK;
+ }
+
+ int processNanDiscoveryEvent(WifiEvent &event) {
+ NanDiscEngEventInd ind;
+ memset(&ind,0,sizeof(ind));
+ u8 *addr = NULL;
+
+ for(nl_iterator nl_itr((struct nlattr *)event.get_vendor_data()); nl_itr.has_next(); nl_itr.next()) {
+ switch(nl_itr.get_type()) {
+ case NAN_EVT_ATTR_DISCOVERY_ENGINE_EVT_TYPE:
+ ind.event_type = (NanDiscEngEventType)nl_itr.get_u16();
+ break;
+ case NAN_EVT_ATTR_DISCOVERY_ENGINE_MAC_ADDR:
+ addr = (u8 *)nl_itr.get_data();
+ break;
+ default :
+ ALOGE("processNanDiscoveryEvent: unknown attribute(%d)", nl_itr.get_type());
+ return NL_SKIP;
+ }
+ }
+ if (addr) {
+ if (ind.event_type == NAN_EVENT_ID_DISC_MAC_ADDR)
+ memcpy(ind.data.mac_addr.addr, addr, NAN_MAC_ADDR_LEN);
+ else
+ memcpy(ind.data.cluster.addr, addr, NAN_MAC_ADDR_LEN);
+ } else {
+ ALOGE("processNanDiscoveryEvent: No Mac/cluster Address");
+ }
+
+ if (callbackEventHandler.EventDiscEngEvent)
+ callbackEventHandler.EventDiscEngEvent(&ind);
+
+ return NL_OK;
+ }
+
+public:
+ NanCommand(wifi_interface_handle iface, int id)
+ : WifiCommand(iface, id)
+ {
+ subscribeID[0] = 0;
+ subscribeID[1] = 0;
+ publishID[0] = 0;
+ publishID[1] = 0;
+ followupID[0] = 0;
+ followupID[0] = 0;
+ version = 0;
+ memset(&capabilities, 0, sizeof(capabilities));
+ }
+
+ int enable(NanEnableRequest *msg) {
+ ALOGD("Start NAN...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_ENABLE);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("enable: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ /* Valid master pref values are 2-254 */
+ int master_pref;
+ if (msg->master_pref < 2)
+ master_pref = 2;
+ else if (msg->master_pref > 254)
+ master_pref = 254;
+ else
+ master_pref = msg->master_pref;
+ result = request.put_u8(NAN_REQ_ATTR_MASTER_PREF, master_pref);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put master_pref");
+
+ result = request.put_u16(NAN_REQ_ATTR_CLUSTER_LOW, msg->cluster_low);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put cluster_low");
+
+ result = request.put_u16(NAN_REQ_ATTR_CLUSTER_HIGH, msg->cluster_high);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "enable:Failed to put cluster_high");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_support_5g, msg->support_5g_val,
+ NAN_REQ_ATTR_SUPPORT_5G_VAL, request, result, "enable:Failed to put support_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_sid_beacon, msg->sid_beacon_val,
+ NAN_REQ_ATTR_SID_BEACON_VAL, request, result, "enable:Failed to put sid_beacon_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_close, msg->rssi_close_2dot4g_val,
+ NAN_REQ_ATTR_RSSI_CLOSE_2G4_VAL, request, result, "enable:Failed to put rssi_close_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_middle, msg->rssi_middle_2dot4g_val,
+ NAN_REQ_ATTR_RSSI_MIDDLE_2G4_VAL, request, result, "enable:Failed to put rssi_middle_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_rssi_proximity, msg->rssi_proximity_2dot4g_val,
+ NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL, request, result, "enable:Failed to put rssi_proximity_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_limit, msg->hop_count_limit_val,
+ NAN_REQ_ATTR_HOP_COUNT_LIMIT_VAL, request, result, "enable:Failed to put hop_count_limit_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_support, msg->support_2dot4g_val,
+ NAN_REQ_ATTR_SUPPORT_2G4_VAL, request, result, "enable:Failed to put support_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_beacons, msg->beacon_2dot4g_val,
+ NAN_REQ_ATTR_BEACONS_2G4_VAL, request, result, "enable:Failed to put beacon_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_2dot4g_sdf, msg->sdf_2dot4g_val,
+ NAN_REQ_ATTR_SDF_2G4_VAL, request, result, "enable:Failed to put sdf_2dot4g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_beacons, msg->beacon_5g_val,
+ NAN_REQ_ATTR_BEACON_5G_VAL, request, result, "enable:Failed to put beacon_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_sdf, msg->sdf_5g_val,
+ NAN_REQ_ATTR_SDF_5G_VAL, request, result, "enable:Failed to put sdf_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close, msg->rssi_close_5g_val,
+ NAN_REQ_ATTR_RSSI_CLOSE_5G_VAL, request, result, "enable:Failed to put rssi_close_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_middle, msg->rssi_middle_5g_val,
+ NAN_REQ_ATTR_RSSI_MIDDLE_5G_VAL, request, result, "enable:Failed to put rssi_middle_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close_proximity, msg->rssi_close_proximity_5g_val,
+ NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL, request, result, "enable:Failed to put rssi_close_proximity_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_window_size, msg->rssi_window_size_val,
+ NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL, request, result, "enable:Failed to put rssi_window_size_val");
+
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_oui, msg->oui_val,
+ NAN_REQ_ATTR_OUI_VAL, request, result, "enable:Failed to put oui_val");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_intf_addr, msg->intf_addr_val, NAN_MAC_ADDR_LEN,
+ NAN_REQ_ATTR_MAC_ADDR_VAL, request, result, "enable:Failed to put intf_addr_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->config_cluster_attribute_val,
+ NAN_REQ_ATTR_CLUSTER_VAL, request, result, "enable:Failed to put config_cluster_attribute_val");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.dwell_time, sizeof(msg->scan_params_val.dwell_time),
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME, request, result, "enable:Failed to put scan_params_val.dwell_time");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.scan_period, sizeof(msg->scan_params_val.scan_period),
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD, request, result, "enable:Failed to put scan_params_val.scan_period");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_random_factor_force, msg->random_factor_force_val,
+ NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL, request, result, "enable:Failed to put random_factor_force_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_force, msg->hop_count_force_val,
+ NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL, request, result, "enable:Failed to put hop_count_force_val");
+
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_24g_channel, msg->channel_24g_val,
+ NAN_REQ_ATTR_CHANNEL_2G4_MHZ_VAL, request, result, "enable:Failed to put channel_24g_val");
+
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(msg->config_5g_channel, msg->channel_5g_val,
+ NAN_REQ_ATTR_CHANNEL_5G_MHZ_VAL, request, result, "enable:Failed to put channel_5g_val");
+
+ request.attr_end(data);
+
+ registerNanEvents();
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to NAN; result = %d", result);
+ unregisterNanEvents();
+ } else {
+ ALOGD("Start NAN...success");
+ }
+ return result;
+ }
+
+ int disable()
+ {
+ ALOGD("Stop NAN...");
+ WifiRequest request(familyId(), ifaceId());
+
+ unregisterNanEvents();
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_DISABLE);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "disable:Failed to create WifiRequest");
+ result = requestResponse(request);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "disable:Failed to requestResponse");
+ return result;
+ }
+
+ int config(NanConfigRequest *msg) {
+ ALOGD("NAN config...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_CONFIG);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "config:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("config: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_sid_beacon, msg->sid_beacon,
+ NAN_REQ_ATTR_SID_BEACON_VAL, request, result, "config:Failed to put sid_beacon");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_proximity, msg->rssi_proximity,
+ NAN_REQ_ATTR_RSSI_PROXIMITY_2G4_VAL, request, result, "config:Failed to put rssi_proximity");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_master_pref, msg->master_pref,
+ NAN_REQ_ATTR_MASTER_PREF, request, result, "config:Failed to put master_pref");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_5g_rssi_close_proximity, msg->rssi_close_proximity_5g_val,
+ NAN_REQ_ATTR_RSSI_CLOSE_PROXIMITY_5G_VAL, request, result, "config:Failed to put rssi_close_proximity_5g_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_rssi_window_size, msg->rssi_window_size_val,
+ NAN_REQ_ATTR_RSSI_WINDOW_SIZE_VAL, request, result, "config:Failed to put rssi_window_size_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->config_cluster_attribute_val,
+ NAN_REQ_ATTR_CLUSTER_VAL, request, result, "config:Failed to put config_cluster_attribute_val");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.dwell_time, sizeof(msg->scan_params_val.dwell_time),
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_DWELL_TIME, request, result, "config:Failed to put scan_params_val.dwell_time");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->config_scan_params, msg->scan_params_val.scan_period, sizeof(msg->scan_params_val.scan_period),
+ NAN_REQ_ATTR_SOCIAL_CH_SCAN_PERIOD, request, result, "config:Failed to put scan_params_val.scan_period");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_random_factor_force, msg->random_factor_force_val,
+ NAN_REQ_ATTR_RANDOM_FACTOR_FORCE_VAL, request, result, "config:Failed to put random_factor_force_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_hop_count_force, msg->hop_count_force_val,
+ NAN_REQ_ATTR_HOP_COUNT_FORCE_VAL, request, result, "config:Failed to put hop_count_force_val");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.payload_transmit_flag,
+ NAN_REQ_ATTR_CONN_CAPABILITY_PAYLOAD_TX, request, result, "config:Failed to put payload_transmit_flag");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_wfd_supported,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WFD, request, result, "config:Failed to put is_wfd_supported");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_wfds_supported,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WFDS, request, result, "config:Failed to put is_wfds_supported");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_tdls_supported,
+ NAN_REQ_ATTR_CONN_CAPABILITY_TDLS, request, result, "config:Failed to put is_tdls_supported");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_ibss_supported,
+ NAN_REQ_ATTR_CONN_CAPABILITY_IBSS, request, result, "config:Failed to put is_ibss_supported");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.is_mesh_supported,
+ NAN_REQ_ATTR_CONN_CAPABILITY_MESH, request, result, "config:Failed to put is_mesh_supported");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->config_conn_capability, msg->conn_capability_val.wlan_infra_field,
+ NAN_REQ_ATTR_CONN_CAPABILITY_WLAN_INFRA, request, result, "config:Failed to put wlan_infra_field");
+
+ if (msg->num_config_discovery_attr) {
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->num_config_discovery_attr,
+ NAN_REQ_ATTR_DISCOVERY_ATTR_NUM_ENTRIES, request, result, "config:Failed to put msg->num_config_discovery_attr");
+ for (int i = 0; i < msg->num_config_discovery_attr; i++) {
+ nlattr *nl_disc_attribute = request.attr_start(NAN_REQ_ATTR_DISCOVERY_ATTR_VAL);
+ NanTransmitPostDiscovery *discovery_attr = &msg->discovery_attr_val[i];
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->type,
+ NAN_REQ_ATTR_CONN_TYPE, request, result, "config:Failed to put discovery_attr->type");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->role,
+ NAN_REQ_ATTR_NAN_ROLE, request, result, "config:Failed to put discovery_attr->role");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->transmit_freq,
+ NAN_REQ_ATTR_TRANSMIT_FREQ, request, result, "config:Failed to put discovery_attr->transmit_freq");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, discovery_attr->duration,
+ NAN_REQ_ATTR_AVAILABILITY_DURATION, request, result, "config:Failed to put discovery_attr->duration");
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(1, discovery_attr->avail_interval_bitmap,
+ NAN_REQ_ATTR_AVAILABILITY_INTERVAL, request, result, "config:Failed to put discovery_attr->avail_interval_bitmap");
+ CHECK_CONFIG_PUT_RETURN_FAIL(1, discovery_attr->addr, NAN_MAC_ADDR_LEN,
+ NAN_REQ_ATTR_MAC_ADDR_VAL, request, result, "config:Failed to put discovery_attr->addr");
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, discovery_attr->mesh_id_len,
+ NAN_REQ_ATTR_MESH_ID_LEN, request, result, "config:Failed to put discovery_attr->mesh_id");
+ CHECK_CONFIG_PUT_RETURN_FAIL(discovery_attr->mesh_id_len, discovery_attr->mesh_id, discovery_attr->mesh_id_len,
+ NAN_REQ_ATTR_MESH_ID, request, result, "config:Failed to put discovery_attr->mesh_id");
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, discovery_attr->infrastructure_ssid_len,
+ NAN_REQ_ATTR_INFRASTRUCTURE_SSID_LEN, request, result, "config:Failed to put discovery_attr->infrastructure_ssid_val");
+ CHECK_CONFIG_PUT_RETURN_FAIL(discovery_attr->infrastructure_ssid_len, discovery_attr->infrastructure_ssid_val, discovery_attr->infrastructure_ssid_len,
+ NAN_REQ_ATTR_INFRASTRUCTURE_SSID, request, result, "config:Failed to put discovery_attr->infrastructure_ssid_val");
+ request.attr_end(nl_disc_attribute);
+ }
+ }
+
+ if (msg->config_fam) {
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->fam_val.numchans,
+ NAN_REQ_ATTR_FURTHER_AVAIL_NUM_ENTRIES, request, result, "config:Failed to put msg->fam_val.numchans");
+ for (int i = 0; i < msg->fam_val.numchans; i++) {
+ nlattr *nl_fam_attribute = request.attr_start(NAN_REQ_ATTR_FURTHER_AVAIL_VAL);
+ NanFurtherAvailabilityChannel *further_avail_chan = &msg->fam_val.famchan[i];
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->entry_control,
+ NAN_REQ_ATTR_FURTHER_AVAIL_ENTRY_CTRL, request, result, "config:Failed to put further_avail_chan->entry_control");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->class_val,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_CLASS, request, result, "config:Failed to put further_avail_chan->class_val");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->channel,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN, request, result, "config:Failed to put further_avail_chan->channel");
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, further_avail_chan->mapid,
+ NAN_REQ_ATTR_FURTHER_AVAIL_CHAN_MAPID, request, result, "config:Failed to put further_avail_chan->mapid");
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(1, further_avail_chan->avail_interval_bitmap,
+ NAN_REQ_ATTR_FURTHER_AVAIL_INTERVAL_BITMAP, request, result, "config:Failed to put further_avail_chan->avail_interval_bitmap");
+ request.attr_end(nl_fam_attribute);
+ }
+ }
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to set_config; result = %d", result);
+ } else {
+ ALOGD("NAN config...success");
+ }
+ return result;
+ }
+
+ static int setCallbackHandler(NanCallbackHandler handlers) {
+ callbackEventHandler = handlers;
+ return WIFI_SUCCESS;
+ }
+
+ static int getVersion(NanVersion *version) {
+ *version = SLSI_WIFI_HAL_NAN_VERSION;
+ return WIFI_SUCCESS;
+ }
+
+ int publish(NanPublishRequest *msg) {
+ ALOGD("NAN publish...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISH);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "publish:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("publish: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->publish_id, msg->publish_id,
+ NAN_REQ_ATTR_PUBLISH_ID, request, result, "publish:Failed to put msg->publish_id");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->ttl, msg->ttl,
+ NAN_REQ_ATTR_PUBLISH_TTL, request, result, "publish:Failed to put msg->ttl");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->period,
+ NAN_REQ_ATTR_PUBLISH_PERIOD, request, result, "publish:Failed to put msg->period");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_type,
+ NAN_REQ_ATTR_PUBLISH_TYPE, request, result, "publish:Failed to put msg->publish_type");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->tx_type,
+ NAN_REQ_ATTR_PUBLISH_TX_TYPE, request, result, "publish:Failed to put msg->tx_type");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_count,
+ NAN_REQ_ATTR_PUBLISH_COUNT, request, result, "publish:Failed to put msg->publish_count");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_name_len, msg->service_name_len,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_NAME_LEN, request, result, "publish:Failed to put msg->service_name_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_name_len, msg->service_name, msg->service_name_len,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_NAME, request, result, "publish:Failed to put msg->service_name");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->publish_match_indicator,
+ NAN_REQ_ATTR_PUBLISH_MATCH_ALGO, request, result, "publish:Failed to put msg->publish_match_indicator");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_INFO_LEN, request, result, "publish:Failed to put msg->service_specific_info_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+ NAN_REQ_ATTR_PUBLISH_SERVICE_INFO, request, result, "publish:Failed to put msg->service_specific_info");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter_len,
+ NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER_LEN, request, result, "publish:Failed to put msg->rx_match_filter_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter, msg->rx_match_filter_len,
+ NAN_REQ_ATTR_PUBLISH_RX_MATCH_FILTER, request, result, "publish:Failed to put msg->rx_match_filter");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter_len,
+ NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER_LEN, request, result, "publish:Failed to put msg->tx_match_filter_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter, msg->tx_match_filter_len,
+ NAN_REQ_ATTR_PUBLISH_TX_MATCH_FILTER, request, result, "publish:Failed to put msg->tx_match_filter");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->rssi_threshold_flag,
+ NAN_REQ_ATTR_PUBLISH_RSSI_THRESHOLD_FLAG, request, result, "publish:Failed to put msg->rssi_threshold_flag");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->connmap,
+ NAN_REQ_ATTR_PUBLISH_CONN_MAP, request, result, "publish:Failed to put msg->connmap");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+ NAN_REQ_ATTR_PUBLISH_RECV_IND_CFG, request, result, "publish:Failed to put msg->recv_indication_cfg");
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to publish; result = %d", result);
+ } else {
+ ALOGD("NAN publish...success");
+ }
+ return result;
+ }
+
+ int publishCancel(NanPublishCancelRequest *msg) {
+ ALOGD("NAN publishCancel...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_PUBLISHCANCEL);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "publishCancel:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("publishCancel: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->publish_id,
+ NAN_REQ_ATTR_PUBLISH_ID, request, result, "publishCancel:Failed to put msg->publish_id");
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to publishCancel; result = %d", result);
+ } else {
+ ALOGD("NAN publishCancel...success");
+ }
+ return result;
+
+ }
+
+ int subscribe(NanSubscribeRequest *msg) {
+ ALOGD("NAN subscribe...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBE);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "subscribe:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("subscribe: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->subscribe_id, msg->subscribe_id,
+ NAN_REQ_ATTR_SUBSCRIBE_ID, request, result, "subscribe:Failed to put msg->publish_id");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->ttl,
+ NAN_REQ_ATTR_SUBSCRIBE_TTL, request, result, "subscribe:Failed to put msg->ttl");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->period,
+ NAN_REQ_ATTR_SUBSCRIBE_PERIOD, request, result, "subscribe:Failed to put msg->period");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_type,
+ NAN_REQ_ATTR_SUBSCRIBE_TYPE, request, result, "subscribe:Failed to put msg->subscribe_type");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->serviceResponseFilter,
+ NAN_REQ_ATTR_SUBSCRIBE_RESP_FILTER_TYPE, request, result, "subscribe:Failed to put msg->serviceResponseFilter");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->serviceResponseInclude,
+ NAN_REQ_ATTR_SUBSCRIBE_RESP_INCLUDE, request, result, "subscribe:Failed to put msg->serviceResponseInclude");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->useServiceResponseFilter,
+ NAN_REQ_ATTR_SUBSCRIBE_USE_RESP_FILTER, request, result, "subscribe:Failed to put msg->useServiceResponseFilter");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->ssiRequiredForMatchIndication,
+ NAN_REQ_ATTR_SUBSCRIBE_SSI_REQUIRED, request, result, "subscribe:Failed to put msg->ssiRequiredForMatchIndication");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_match_indicator,
+ NAN_REQ_ATTR_SUBSCRIBE_MATCH_INDICATOR, request, result, "subscribe:Failed to put msg->subscribe_match_indicator");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->subscribe_count,
+ NAN_REQ_ATTR_SUBSCRIBE_COUNT, request, result, "subscribe:Failed to put msg->subscribe_count");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_name_len, msg->service_name_len,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME_LEN, request, result, "subscribe:Failed to put msg->service_name_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_name_len, msg->service_name, msg->service_name_len,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_NAME, request, result, "subscribe:Failed to put msg->service_name");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO_LEN, request, result, "subscribe:Failed to put msg->service_specific_info_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+ NAN_REQ_ATTR_SUBSCRIBE_SERVICE_INFO, request, result, "subscribe:Failed to put msg->service_specific_info");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter_len,
+ NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER_LEN, request, result, "subscribe:Failed to put msg->rx_match_filter_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->rx_match_filter_len, msg->rx_match_filter, msg->rx_match_filter_len,
+ NAN_REQ_ATTR_SUBSCRIBE_RX_MATCH_FILTER, request, result, "subscribe:Failed to put msg->rx_match_filter");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter_len,
+ NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER_LEN, request, result, "subscribe:Failed to put msg->tx_match_filter_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->tx_match_filter_len, msg->tx_match_filter, msg->tx_match_filter_len,
+ NAN_REQ_ATTR_SUBSCRIBE_TX_MATCH_FILTER, request, result, "subscribe:Failed to put msg->tx_match_filter");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->rssi_threshold_flag,
+ NAN_REQ_ATTR_SUBSCRIBE_RSSI_THRESHOLD_FLAG, request, result, "subscribe:Failed to put msg->rssi_threshold_flag");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->connmap,
+ NAN_REQ_ATTR_SUBSCRIBE_CONN_MAP, request, result, "subscribe:Failed to put msg->connmap");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(msg->num_intf_addr_present, msg->num_intf_addr_present,
+ NAN_REQ_ATTR_SUBSCRIBE_NUM_INTF_ADDR_PRESENT, request, result, "subscribe:Failed to put msg->num_intf_addr_present");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->num_intf_addr_present, msg->intf_addr, NAN_MAC_ADDR_LEN * msg->num_intf_addr_present,
+ NAN_REQ_ATTR_SUBSCRIBE_INTF_ADDR, request, result, "subscribe:Failed to put msg->intf_addr");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+ NAN_REQ_ATTR_SUBSCRIBE_RECV_IND_CFG, request, result, "subscribe:Failed to put msg->recv_indication_cfg");
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to subscribe; result = %d", result);
+ } else {
+ ALOGD("NAN subscribe...success");
+ }
+ return result;
+
+ }
+
+ int subscribeCancel(NanSubscribeCancelRequest *msg) {
+ ALOGD("NAN subscribeCancel...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_SUBSCRIBECANCEL);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "subscribeCancel:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("subscribeCancel: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->subscribe_id,
+ NAN_REQ_ATTR_SUBSCRIBE_ID, request, result, "subscribeCancel:Failed to put msg->subscribe_id");
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to subscribeCancel; result = %d", result);
+ } else {
+ ALOGD("NAN subscribeCancel...success");
+ }
+ return result;
+ }
+
+ int followup(NanTransmitFollowupRequest *msg) {
+ ALOGD("NAN followup...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_TXFOLLOWUP);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "followup:Failed to create WifiRequest");
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!data) {
+ ALOGE("followup: request.attr_start fail");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(1, msg->publish_subscribe_id,
+ NAN_REQ_ATTR_FOLLOWUP_ID, request, result, "followup:Failed to put msg->publish_subscribe_id");
+
+ CHECK_CONFIG_PUT_32_RETURN_FAIL(1, msg->requestor_instance_id,
+ NAN_REQ_ATTR_FOLLOWUP_REQUESTOR_ID, request, result, "followup:Failed to put msg->requestor_instance_id");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(1, msg->addr, NAN_MAC_ADDR_LEN,
+ NAN_REQ_ATTR_FOLLOWUP_ADDR, request, result, "followup:Failed to put msg->addr");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->priority,
+ NAN_REQ_ATTR_FOLLOWUP_PRIORITY, request, result, "followup:Failed to put msg->priority");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->dw_or_faw,
+ NAN_REQ_ATTR_FOLLOWUP_TX_WINDOW, request, result, "followup:Failed to put msg->dw_or_faw");
+
+ CHECK_CONFIG_PUT_16_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info_len,
+ NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME_LEN, request, result, "followup:Failed to put msg->service_specific_info_len");
+
+ CHECK_CONFIG_PUT_RETURN_FAIL(msg->service_specific_info_len, msg->service_specific_info, msg->service_specific_info_len,
+ NAN_REQ_ATTR_FOLLOWUP_SERVICE_NAME, request, result, "followup:Failed to put msg->service_specific_info");
+
+ CHECK_CONFIG_PUT_8_RETURN_FAIL(1, msg->recv_indication_cfg,
+ NAN_REQ_ATTR_FOLLOWUP_RECV_IND_CFG, request, result, "followup:Failed to put msg->recv_indication_cfg");
+
+ request.attr_end(data);
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to followup; result = %d", result);
+ } else {
+ ALOGD("NAN followup...success");
+ }
+ return result;
+
+ }
+
+ int getCapabilities(void) {
+ ALOGD("NAN getCapabilities...");
+ WifiRequest request(familyId(), ifaceId());
+
+ int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_NAN_CAPABILITIES);
+ CHECK_WIFI_STATUS_RETURN_FAIL(result, "getCapabilities:Failed to create WifiRequest");
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("failed to getCapabilities; result = %d", result);
+ } else {
+ ALOGD("NAN getCapabilities...success");
+ }
+ return result;
+ }
+
+ int handleEvent(WifiEvent &event) {
+ int ret;
+ ALOGD("NAN handleEvent...");
+
+ if (event.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring event with cmd = %d", event.get_cmd());
+ return NL_SKIP;
+ }
+
+ int id = event.get_vendor_id();
+ int subcmd = event.get_vendor_subcmd();
+
+ ALOGI("Id = %0x, subcmd = %d", id, subcmd);
+
+ switch(subcmd) {
+ case SLSI_NAN_EVENT_MATCH:
+ ret = processMatchEvent(event);
+ break;
+ case SLSI_NAN_EVENT_MATCH_EXPIRED:
+ ret = processMatchExpiredEvent(event);
+ break;
+ case SLSI_NAN_EVENT_PUBLISH_TERMINATED:
+ ret = processPublishTerminatedEvent(event);
+ break;
+ case SLSI_NAN_EVENT_SUBSCRIBE_TERMINATED:
+ ret = processSubscribeTerminatedEvent(event);
+ break;
+ case SLSI_NAN_EVENT_FOLLOWUP:
+ ret = processFollowupEvent(event);
+ break;
+ case SLSI_NAN_EVENT_DISABLED:
+ ret = processNanDisabledEvent(event);
+ break;
+ case SLSI_NAN_EVENT_DISCOVERY_ENGINE:
+ ret = processNanDiscoveryEvent(event);
+ break;
+
+ }
+
+ return NL_OK;
+ }
+
+ int handleResponse(WifiEvent &reply) {
+ ALOGD("NAN handleResponse...");
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ NanResponseMsg response;
+ memset(&response, 0, sizeof(response));
+
+ if (processResponse(reply, &response) == NL_SKIP)
+ return NL_SKIP;
+
+ if (callbackEventHandler.NotifyResponse)
+ callbackEventHandler.NotifyResponse(id(), &response);
+ return NL_OK;
+ }
+};
+
+NanCallbackHandler NanCommand::callbackEventHandler;
+
+NanCommand *nan_get_object(transaction_id id,
+ wifi_interface_handle iface) {
+ wifi_handle handle = getWifiHandle(iface);
+ NanCommand *nanRequest = (NanCommand *)wifi_get_cmd(handle, id);
+ if (!nanRequest) {
+ nanRequest = new NanCommand(iface, id);
+ if (!nanRequest){
+ ALOGE("Could not alloc NanCommand");
+ return NULL;
+ }
+ }
+ return nanRequest;
+}
+
+wifi_error nan_enable_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanEnableRequest *msg) {
+ wifi_handle handle = getWifiHandle(iface);
+ wifi_error ret;
+
+ NanCommand *nanRequest = new NanCommand(iface, id);
+ if (!nanRequest) {
+ ALOGE("nan_enable_request:: Unable to create NanCommand");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ wifi_register_cmd(handle, id, nanRequest);
+ ret = (wifi_error)nanRequest->enable(msg);
+ if (ret != WIFI_SUCCESS) {
+ wifi_unregister_cmd(handle, id);
+ delete nanRequest;
+ }
+ return ret;
+}
+
+/* Disable NAN functionality. */
+wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ wifi_error ret;
+
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ ret = (wifi_error)nanRequest->disable();
+ delete nanRequest;
+ return ret;
+}
+
+/* Publish request to advertize a service. */
+wifi_error nan_publish_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanPublishRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->publish(msg);
+}
+
+/* Cancel previous publish requests. */
+wifi_error nan_publish_cancel_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanPublishCancelRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->publishCancel(msg);
+}
+
+/* Subscribe request to search for a service. */
+wifi_error nan_subscribe_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanSubscribeRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->subscribe(msg);
+}
+
+/* Cancel previous subscribe requests. */
+wifi_error nan_subscribe_cancel_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanSubscribeCancelRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->subscribeCancel(msg);
+}
+
+/* NAN transmit follow up request. */
+wifi_error nan_transmit_followup_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanTransmitFollowupRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->followup(msg);
+}
+
+/* NAN configuration request. */
+wifi_error nan_config_request(transaction_id id,
+ wifi_interface_handle iface,
+ NanConfigRequest *msg) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->config(msg);
+}
+
+/* Register NAN callbacks. */
+wifi_error nan_register_handler(wifi_interface_handle iface,
+ NanCallbackHandler handlers) {
+ return (wifi_error)NanCommand::setCallbackHandler(handlers);
+}
+
+/* Get NAN HAL version. */
+wifi_error nan_get_version(wifi_handle handle,
+ NanVersion *version) {
+ return (wifi_error)NanCommand::getVersion(version);
+}
+
+/* Get NAN capabilities. */
+wifi_error nan_get_capabilities(transaction_id id,
+ wifi_interface_handle iface) {
+ NanCommand *nanRequest = nan_get_object(id, iface);
+ if (!nanRequest) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return (wifi_error)nanRequest->getCapabilities();
+}
+
diff --git a/wifi_offload.cpp b/wifi_offload.cpp
new file mode 100644
index 0000000..208afb8
--- /dev/null
+++ b/wifi_offload.cpp
@@ -0,0 +1,227 @@
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/types.h>
+
+#include "nl80211_copy.h"
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL[offload]"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+typedef enum {
+ MKEEP_ALIVE_ATTRIBUTE_ID,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
+ MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
+} WIFI_MKEEP_ALIVE_ATTRIBUTE;
+
+typedef enum {
+ START_MKEEP_ALIVE,
+ STOP_MKEEP_ALIVE,
+} GetCmdType;
+
+///////////////////////////////////////////////////////////////////////////////
+class MKeepAliveCommand : public WifiCommand
+{
+ u8 mIndex;
+ u8 *mIpPkt;
+ u16 mIpPktLen;
+ u8 *mSrcMacAddr;
+ u8 *mDstMacAddr;
+ u32 mPeriodMsec;
+ GetCmdType mType;
+
+public:
+
+ // constructor for start sending
+ MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len,
+ u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mIndex(index), mIpPkt(ip_packet),
+ mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
+ mPeriodMsec(period_msec), mType(cmdType)
+ { }
+
+ // constructor for stop sending
+ MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
+ : WifiCommand(iface, 0), mIndex(index), mType(cmdType)
+ {
+ mIpPkt = NULL;
+ mIpPktLen = 0;
+ mSrcMacAddr = NULL;
+ mDstMacAddr = NULL;
+ mPeriodMsec = 0;
+ }
+
+ int createRequest(WifiRequest &request) {
+ int result;
+
+ switch (mType) {
+ case START_MKEEP_ALIVE:
+ {
+ result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_START_KEEP_ALIVE_OFFLOAD);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create start keep alive request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+ if (result < 0) {
+ ALOGE("Failed to put id request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
+ if (result < 0) {
+ ALOGE("Failed to put ip pkt len request; result = %d", result);
+ return result;
+ }
+
+ result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
+ if (result < 0) {
+ ALOGE("Failed to put ip pkt request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
+ if (result < 0) {
+ ALOGE("Failed to put src mac address request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
+ if (result < 0) {
+ ALOGE("Failed to put dst mac address request; result = %d", result);
+ return result;
+ }
+
+ result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
+ if (result < 0) {
+ ALOGE("Failed to put period request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ break;
+ }
+
+ case STOP_MKEEP_ALIVE:
+ {
+ result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_STOP_KEEP_ALIVE_OFFLOAD);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create stop keep alive request; result = %d", result);
+ return result;
+ }
+
+ nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
+
+ result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
+ if (result < 0) {
+ ALOGE("Failed to put id request; result = %d", result);
+ return result;
+ }
+
+ request.attr_end(data);
+ break;
+ }
+
+ default:
+ ALOGE("Unknown wifi keep alive command");
+ result = WIFI_ERROR_UNKNOWN;
+ }
+ return result;
+ }
+
+ int start() {
+ ALOGD("Start mkeep_alive command");
+ WifiRequest request(familyId(), ifaceId());
+ int result = createRequest(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to create keep alive request; result = %d", result);
+ return result;
+ }
+
+ result = requestResponse(request);
+ if (result != WIFI_SUCCESS) {
+ ALOGE("Failed to register keep alive response; result = %d", result);
+ }
+ return result;
+ }
+
+ virtual int handleResponse(WifiEvent& reply) {
+
+ if (reply.get_cmd() != NL80211_CMD_VENDOR) {
+ ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
+ return NL_SKIP;
+ }
+
+ switch (mType) {
+ case START_MKEEP_ALIVE:
+ case STOP_MKEEP_ALIVE:
+ break;
+
+ default:
+ ALOGW("Unknown mkeep_alive command");
+ }
+ return NL_OK;
+ }
+
+ virtual int handleEvent(WifiEvent& event) {
+ /* NO events! */
+ return NL_SKIP;
+ }
+};
+
+
+/* API to send specified mkeep_alive packet periodically. */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
+ u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
+{
+ if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
+ && (dst_mac_addr != NULL) && (period_msec > 0)
+ && (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
+ MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
+ src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
+ wifi_error result = (wifi_error)cmd->start();
+ delete cmd;
+ return result;
+ } else {
+ ALOGE("Invalid mkeep_alive parameters");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}
+
+/* API to stop sending mkeep_alive packet. */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
+{
+ if (index > 0 && index <= N_AVAIL_ID) {
+ MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
+ wifi_error result = (wifi_error)cmd->start();
+ delete cmd;
+ return result;
+ } else {
+ ALOGE("Invalid mkeep_alive parameters");
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+}