diff options
| author | Kiyoung Kim <kiyoungkim@google.com> | 2019-05-24 18:40:35 +0900 |
|---|---|---|
| committer | Kiyoung Kim <kiyoungkim@google.com> | 2019-05-24 18:40:35 +0900 |
| commit | 5aa1494eec4e58af0a28cffd53a029eb98d5a54f (patch) | |
| tree | d225c93fdfe9ee8f2f80956bf759b0154440b8f6 | |
| parent | d2140c7404559d2cf9bce690e76c75efaa1c47ba (diff) | |
| parent | 22f0c70e22abff0cd28ee7da4ac55f0a931beb7b (diff) | |
Merge KeystoneQ-ww-20190522
Change-Id: I03b64105c115f2d90fb39cb9e620350458daeed0
| -rwxr-xr-x | Android.mk | 40 | ||||
| -rwxr-xr-x | common.cpp | 244 | ||||
| -rwxr-xr-x | common.h | 302 | ||||
| -rwxr-xr-x | cpp_bindings.cpp | 694 | ||||
| -rwxr-xr-x | cpp_bindings.h | 347 | ||||
| -rwxr-xr-x | gscan.cpp | 1350 | ||||
| -rwxr-xr-x | link_layer_stats.cpp | 274 | ||||
| -rwxr-xr-x | roam.cpp | 224 | ||||
| -rwxr-xr-x | rtt.cpp | 632 | ||||
| -rwxr-xr-x | sync.h | 54 | ||||
| -rwxr-xr-x | wifi_hal.cpp | 1029 | ||||
| -rwxr-xr-x | wifi_logger.cpp | 1444 | ||||
| -rwxr-xr-x | wifi_nan.cpp | 1419 | ||||
| -rw-r--r-- | wifi_offload.cpp | 227 |
14 files changed, 8280 insertions, 0 deletions
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;
+}
@@ -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; + +} @@ -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; + } +} |
