upload android base code part4

This commit is contained in:
August 2018-08-08 17:00:29 +08:00
parent b9e30e05b1
commit 78ea2404cd
23455 changed files with 5250148 additions and 0 deletions

View file

@ -0,0 +1,42 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
# Make the HAL library
# ============================================================
include $(CLEAR_VARS)
LOCAL_CFLAGS := -Wno-unused-parameter
LOCAL_C_INCLUDES += \
external/libnl/include \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
external/wpa_supplicant_8/src/drivers
LOCAL_SRC_FILES := \
wifi_hal.cpp \
rtt.cpp \
common.cpp \
cpp_bindings.cpp \
gscan.cpp \
link_layer_stats.cpp \
wifi_logger.cpp \
wifi_offload.cpp
LOCAL_MODULE := libwifi-hal-bcm
LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_STATIC_LIBRARY)

View file

@ -0,0 +1,245 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
interface_info *getIfaceInfo(wifi_interface_handle handle)
{
return (interface_info *)handle;
}
wifi_handle getWifiHandle(wifi_interface_handle handle)
{
return getIfaceInfo(handle)->handle;
}
hal_info *getHalInfo(wifi_handle handle)
{
return (hal_info *)handle;
}
hal_info *getHalInfo(wifi_interface_handle handle)
{
return getHalInfo(getWifiHandle(handle));
}
wifi_handle getWifiHandle(hal_info *info)
{
return (wifi_handle)info;
}
wifi_interface_handle getIfaceHandle(interface_info *info)
{
return (wifi_interface_handle)info;
}
wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
{
hal_info *info = (hal_info *)handle;
/* TODO: check for multiple handlers? */
pthread_mutex_lock(&info->cb_lock);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_event_cb < info->alloc_event_cb) {
info->event_cb[info->num_event_cb].nl_cmd = cmd;
info->event_cb[info->num_event_cb].vendor_id = 0;
info->event_cb[info->num_event_cb].vendor_subcmd = 0;
info->event_cb[info->num_event_cb].cb_func = func;
info->event_cb[info->num_event_cb].cb_arg = arg;
ALOGV("Successfully added event handler %p:%p for command %d at %d",
arg, func, cmd, info->num_event_cb);
info->num_event_cb++;
result = WIFI_SUCCESS;
}
pthread_mutex_unlock(&info->cb_lock);
return result;
}
wifi_error wifi_register_vendor_handler(wifi_handle handle,
uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
{
hal_info *info = (hal_info *)handle;
/* TODO: check for multiple handlers? */
pthread_mutex_lock(&info->cb_lock);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_event_cb < info->alloc_event_cb) {
info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
info->event_cb[info->num_event_cb].vendor_id = id;
info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
info->event_cb[info->num_event_cb].cb_func = func;
info->event_cb[info->num_event_cb].cb_arg = arg;
ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
arg, func, id, subcmd, info->num_event_cb);
info->num_event_cb++;
result = WIFI_SUCCESS;
}
pthread_mutex_unlock(&info->cb_lock);
return result;
}
void wifi_unregister_handler(wifi_handle handle, int cmd)
{
hal_info *info = (hal_info *)handle;
if (cmd == NL80211_CMD_VENDOR) {
ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
return;
}
pthread_mutex_lock(&info->cb_lock);
for (int i = 0; i < info->num_event_cb; i++) {
if (info->event_cb[i].nl_cmd == cmd) {
ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);
memmove(&info->event_cb[i], &info->event_cb[i+1],
(info->num_event_cb - i - 1) * sizeof(cb_info));
info->num_event_cb--;
break;
}
}
pthread_mutex_unlock(&info->cb_lock);
}
void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
{
hal_info *info = (hal_info *)handle;
pthread_mutex_lock(&info->cb_lock);
for (int i = 0; i < info->num_event_cb; i++) {
if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
&& info->event_cb[i].vendor_id == id
&& info->event_cb[i].vendor_subcmd == subcmd) {
ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
memmove(&info->event_cb[i], &info->event_cb[i+1],
(info->num_event_cb - i - 1) * sizeof(cb_info));
info->num_event_cb--;
break;
}
}
pthread_mutex_unlock(&info->cb_lock);
}
wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
{
hal_info *info = (hal_info *)handle;
ALOGV("registering command %d", id);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_cmd < info->alloc_cmd) {
info->cmd[info->num_cmd].id = id;
info->cmd[info->num_cmd].cmd = cmd;
ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
info->num_cmd++;
result = WIFI_SUCCESS;
} else {
ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
id, cmd, info->num_cmd, info->alloc_cmd);
}
return result;
}
WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
{
hal_info *info = (hal_info *)handle;
ALOGV("un-registering command %d", id);
WifiCommand *cmd = NULL;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].id == id) {
cmd = info->cmd[i].cmd;
memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
info->num_cmd--;
ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
break;
}
}
if (!cmd) {
ALOGI("Failed to remove command %d: %p", id, cmd);
}
return cmd;
}
WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
{
hal_info *info = (hal_info *)handle;
WifiCommand *cmd = NULL;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].id == id) {
cmd = info->cmd[i].cmd;
break;
}
}
return cmd;
}
void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
{
hal_info *info = (hal_info *)handle;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].cmd == cmd) {
int id = info->cmd[i].id;
memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
info->num_cmd--;
ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
break;
}
}
}
wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
{
wifi_handle handle = getWifiHandle(iface);
WifiCommand *cmd = wifi_unregister_cmd(handle, id);
ALOGV("Cancel WifiCommand = %p", cmd);
if (cmd) {
cmd->cancel();
cmd->releaseRef();
return WIFI_SUCCESS;
}
return WIFI_ERROR_INVALID_ARGS;
}

View file

@ -0,0 +1,257 @@
#include "wifi_hal.h"
#ifndef __WIFI_HAL_COMMON_H__
#define __WIFI_HAL_COMMON_H__
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include "nl80211_copy.h"
#include "sync.h"
#define SOCKET_BUFFER_SIZE (32768U)
#define RECV_BUF_SIZE (4096)
#define DEFAULT_EVENT_CB_SIZE (64)
#define DEFAULT_CMD_SIZE (64)
#define DOT11_OUI_LEN 3
#define DOT11_MAX_SSID_LEN 32
#define MAX_PROBE_RESP_IE_LEN 2048
/*
Vendor OUI - This is a unique identifier that identifies organization. Lets
code Android specific functions with Google OUI; although vendors can do more
with their own OUI's as well.
*/
const uint32_t GOOGLE_OUI = 0x001A11;
/* TODO: define vendor OUI here */
/*
This enum defines ranges for various commands; commands themselves
can be defined in respective feature headers; i.e. find gscan command
definitions in gscan.cpp
*/
typedef enum {
/* don't use 0 as a valid subcommand */
VENDOR_NL80211_SUBCMD_UNSPECIFIED,
/* define all vendor startup commands between 0x0 and 0x0FFF */
VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
/* define all GScan related commands between 0x1000 and 0x10FF */
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
/* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
/* define all RTT related commands between 0x1100 and 0x11FF */
ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
/* define all Logger related commands between 0x1400 and 0x14FF */
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF,
/* define all wifi offload related commands between 0x1600 and 0x16FF */
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF,
/* define all NAN related commands between 0x1700 and 0x17FF */
ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700,
ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x17FF,
/* define all Android Packet Filter related commands between 0x1800 and 0x18FF */
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800,
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF,
/* This is reserved for future usage */
} ANDROID_VENDOR_SUB_COMMAND;
typedef enum {
GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */
GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */
GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */
GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */
GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */
GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */
GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */
GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */
GSCAN_SUBCMD_GET_CHANNEL_LIST, /* 0x1009 */
WIFI_SUBCMD_GET_FEATURE_SET, /* 0x100A */
WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x100B */
WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x100C */
WIFI_SUBCMD_NODFS_SET, /* 0x100D */
WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x100E */
/* Add more sub commands here */
GSCAN_SUBCMD_SET_EPNO_SSID, /* 0x100F */
WIFI_SUBCMD_SET_SSID_WHITE_LIST, /* 0x1010 */
WIFI_SUBCMD_SET_ROAM_PARAMS, /* 0x1011 */
WIFI_SUBCMD_ENABLE_LAZY_ROAM, /* 0x1012 */
WIFI_SUBCMD_SET_BSSID_PREF, /* 0x1013 */
WIFI_SUBCMD_SET_BSSID_BLACKLIST, /* 0x1014 */
GSCAN_SUBCMD_ANQPO_CONFIG, /* 0x1015 */
WIFI_SUBCMD_SET_RSSI_MONITOR, /* 0x1016 */
WIFI_SUBCMD_CONFIG_ND_OFFLOAD, /* 0x1017 */
/* Add more sub commands here */
GSCAN_SUBCMD_MAX,
APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
APF_SUBCMD_SET_FILTER,
} WIFI_SUB_COMMAND;
typedef enum {
BRCM_RESERVED1,
BRCM_RESERVED2,
GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS ,
GSCAN_EVENT_HOTLIST_RESULTS_FOUND,
GSCAN_EVENT_SCAN_RESULTS_AVAILABLE,
GSCAN_EVENT_FULL_SCAN_RESULTS,
RTT_EVENT_COMPLETE,
GSCAN_EVENT_COMPLETE_SCAN,
GSCAN_EVENT_HOTLIST_RESULTS_LOST,
GSCAN_EVENT_EPNO_EVENT,
GOOGLE_DEBUG_RING_EVENT,
GOOGLE_DEBUG_MEM_DUMP_EVENT,
GSCAN_EVENT_ANQPO_HOTSPOT_MATCH,
GOOGLE_RSSI_MONITOR_EVENT
} WIFI_EVENT;
typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
class WifiCommand;
typedef struct {
int nl_cmd;
uint32_t vendor_id;
int vendor_subcmd;
nl_recvmsg_msg_cb_t cb_func;
void *cb_arg;
} cb_info;
typedef struct {
wifi_request_id id;
WifiCommand *cmd;
} cmd_info;
typedef struct {
wifi_handle handle; // handle to wifi data
char name[IFNAMSIZ+1]; // interface name + trailing null
int id; // id to use when talking to driver
} interface_info;
typedef struct {
struct nl_sock *cmd_sock; // command socket object
struct nl_sock *event_sock; // event socket object
int nl80211_family_id; // family id for 80211 driver
int cleanup_socks[2]; // sockets used to implement wifi_cleanup
bool in_event_loop; // Indicates that event loop is active
bool clean_up; // Indication to exit since cleanup has started
wifi_internal_event_handler event_handler; // default event handler
wifi_cleaned_up_handler cleaned_up_handler; // socket cleaned up handler
cb_info *event_cb; // event callbacks
int num_event_cb; // number of event callbacks
int alloc_event_cb; // number of allocated callback objects
pthread_mutex_t cb_lock; // mutex for the event_cb access
cmd_info *cmd; // Outstanding commands
int num_cmd; // number of commands
int alloc_cmd; // number of commands allocated
interface_info **interfaces; // array of interfaces
int num_interfaces; // number of interfaces
// add other details
} hal_info;
#define PNO_SSID_FOUND 0x1
#define PNO_SSID_LOST 0x2
typedef struct wifi_pno_result {
unsigned char ssid[DOT11_MAX_SSID_LEN];
unsigned char ssid_len;
signed char rssi;
u16 channel;
u16 flags;
mac_addr bssid;
} wifi_pno_result_t;
typedef struct wifi_gscan_result {
u64 ts; // Time of discovery
u8 ssid[DOT11_MAX_SSID_LEN+1]; // null terminated
mac_addr bssid; // BSSID
u32 channel; // channel frequency in MHz
s32 rssi; // in db
u64 rtt; // in nanoseconds
u64 rtt_sd; // standard deviation in rtt
u16 beacon_period; // units are Kusec
u16 capability; // Capability information
u32 pad;
} wifi_gscan_result_t;
typedef struct wifi_gscan_full_result {
wifi_gscan_result_t fixed;
u32 scan_ch_bucket; // scan chbucket bitmask
u32 ie_length; // byte length of Information Elements
u8 ie_data[1]; // IE data to follow
} wifi_gscan_full_result_t;
wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
wifi_error wifi_register_vendor_handler(wifi_handle handle,
uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
void wifi_unregister_handler(wifi_handle handle, int cmd);
void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);
WifiCommand *wifi_get_cmd(wifi_handle handle, int id);
void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);
interface_info *getIfaceInfo(wifi_interface_handle);
wifi_handle getWifiHandle(wifi_interface_handle handle);
hal_info *getHalInfo(wifi_handle handle);
hal_info *getHalInfo(wifi_interface_handle handle);
wifi_handle getWifiHandle(hal_info *info);
wifi_interface_handle getIfaceHandle(interface_info *info);
wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface);
// some common macros
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
#define NULL_CHECK_RETURN(ptr, str, ret) \
do { \
if (!(ptr)) { \
ALOGE("%s(): null pointer - #ptr (%s)\n", __FUNCTION__, str); \
return ret; \
} \
} while (0)
#endif

View file

@ -0,0 +1,733 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include <ctype.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
void appendFmt(char *buf, int &offset, const char *fmt, ...)
{
va_list params;
va_start(params, fmt);
offset += vsprintf(buf + offset, fmt, params);
va_end(params);
}
#define C2S(x) case x: return #x;
static const char *cmdToString(int cmd)
{
switch (cmd) {
C2S(NL80211_CMD_UNSPEC)
C2S(NL80211_CMD_GET_WIPHY)
C2S(NL80211_CMD_SET_WIPHY)
C2S(NL80211_CMD_NEW_WIPHY)
C2S(NL80211_CMD_DEL_WIPHY)
C2S(NL80211_CMD_GET_INTERFACE)
C2S(NL80211_CMD_SET_INTERFACE)
C2S(NL80211_CMD_NEW_INTERFACE)
C2S(NL80211_CMD_DEL_INTERFACE)
C2S(NL80211_CMD_GET_KEY)
C2S(NL80211_CMD_SET_KEY)
C2S(NL80211_CMD_NEW_KEY)
C2S(NL80211_CMD_DEL_KEY)
C2S(NL80211_CMD_GET_BEACON)
C2S(NL80211_CMD_SET_BEACON)
C2S(NL80211_CMD_START_AP)
C2S(NL80211_CMD_STOP_AP)
C2S(NL80211_CMD_GET_STATION)
C2S(NL80211_CMD_SET_STATION)
C2S(NL80211_CMD_NEW_STATION)
C2S(NL80211_CMD_DEL_STATION)
C2S(NL80211_CMD_GET_MPATH)
C2S(NL80211_CMD_SET_MPATH)
C2S(NL80211_CMD_NEW_MPATH)
C2S(NL80211_CMD_DEL_MPATH)
C2S(NL80211_CMD_SET_BSS)
C2S(NL80211_CMD_SET_REG)
C2S(NL80211_CMD_REQ_SET_REG)
C2S(NL80211_CMD_GET_MESH_CONFIG)
C2S(NL80211_CMD_SET_MESH_CONFIG)
C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
C2S(NL80211_CMD_GET_REG)
C2S(NL80211_CMD_GET_SCAN)
C2S(NL80211_CMD_TRIGGER_SCAN)
C2S(NL80211_CMD_NEW_SCAN_RESULTS)
C2S(NL80211_CMD_SCAN_ABORTED)
C2S(NL80211_CMD_REG_CHANGE)
C2S(NL80211_CMD_AUTHENTICATE)
C2S(NL80211_CMD_ASSOCIATE)
C2S(NL80211_CMD_DEAUTHENTICATE)
C2S(NL80211_CMD_DISASSOCIATE)
C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
C2S(NL80211_CMD_REG_BEACON_HINT)
C2S(NL80211_CMD_JOIN_IBSS)
C2S(NL80211_CMD_LEAVE_IBSS)
C2S(NL80211_CMD_TESTMODE)
C2S(NL80211_CMD_CONNECT)
C2S(NL80211_CMD_ROAM)
C2S(NL80211_CMD_DISCONNECT)
C2S(NL80211_CMD_SET_WIPHY_NETNS)
C2S(NL80211_CMD_GET_SURVEY)
C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
C2S(NL80211_CMD_SET_PMKSA)
C2S(NL80211_CMD_DEL_PMKSA)
C2S(NL80211_CMD_FLUSH_PMKSA)
C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
C2S(NL80211_CMD_REGISTER_FRAME)
C2S(NL80211_CMD_FRAME)
C2S(NL80211_CMD_FRAME_TX_STATUS)
C2S(NL80211_CMD_SET_POWER_SAVE)
C2S(NL80211_CMD_GET_POWER_SAVE)
C2S(NL80211_CMD_SET_CQM)
C2S(NL80211_CMD_NOTIFY_CQM)
C2S(NL80211_CMD_SET_CHANNEL)
C2S(NL80211_CMD_SET_WDS_PEER)
C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
C2S(NL80211_CMD_JOIN_MESH)
C2S(NL80211_CMD_LEAVE_MESH)
C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
C2S(NL80211_CMD_GET_WOWLAN)
C2S(NL80211_CMD_SET_WOWLAN)
C2S(NL80211_CMD_START_SCHED_SCAN)
C2S(NL80211_CMD_STOP_SCHED_SCAN)
C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
C2S(NL80211_CMD_PMKSA_CANDIDATE)
C2S(NL80211_CMD_TDLS_OPER)
C2S(NL80211_CMD_TDLS_MGMT)
C2S(NL80211_CMD_UNEXPECTED_FRAME)
C2S(NL80211_CMD_PROBE_CLIENT)
C2S(NL80211_CMD_REGISTER_BEACONS)
C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
C2S(NL80211_CMD_SET_NOACK_MAP)
C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
C2S(NL80211_CMD_START_P2P_DEVICE)
C2S(NL80211_CMD_STOP_P2P_DEVICE)
C2S(NL80211_CMD_CONN_FAILED)
C2S(NL80211_CMD_SET_MCAST_RATE)
C2S(NL80211_CMD_SET_MAC_ACL)
C2S(NL80211_CMD_RADAR_DETECT)
C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
C2S(NL80211_CMD_UPDATE_FT_IES)
C2S(NL80211_CMD_FT_EVENT)
C2S(NL80211_CMD_CRIT_PROTOCOL_START)
C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
C2S(NL80211_CMD_GET_COALESCE)
C2S(NL80211_CMD_SET_COALESCE)
C2S(NL80211_CMD_CHANNEL_SWITCH)
C2S(NL80211_CMD_VENDOR)
C2S(NL80211_CMD_SET_QOS_MAP)
default:
return "NL80211_CMD_UNKNOWN";
}
}
const char *attributeToString(int attribute)
{
switch (attribute) {
C2S(NL80211_ATTR_UNSPEC)
C2S(NL80211_ATTR_WIPHY)
C2S(NL80211_ATTR_WIPHY_NAME)
C2S(NL80211_ATTR_IFINDEX)
C2S(NL80211_ATTR_IFNAME)
C2S(NL80211_ATTR_IFTYPE)
C2S(NL80211_ATTR_MAC)
C2S(NL80211_ATTR_KEY_DATA)
C2S(NL80211_ATTR_KEY_IDX)
C2S(NL80211_ATTR_KEY_CIPHER)
C2S(NL80211_ATTR_KEY_SEQ)
C2S(NL80211_ATTR_KEY_DEFAULT)
C2S(NL80211_ATTR_BEACON_INTERVAL)
C2S(NL80211_ATTR_DTIM_PERIOD)
C2S(NL80211_ATTR_BEACON_HEAD)
C2S(NL80211_ATTR_BEACON_TAIL)
C2S(NL80211_ATTR_STA_AID)
C2S(NL80211_ATTR_STA_FLAGS)
C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
C2S(NL80211_ATTR_STA_VLAN)
C2S(NL80211_ATTR_STA_INFO)
C2S(NL80211_ATTR_WIPHY_BANDS)
C2S(NL80211_ATTR_MNTR_FLAGS)
C2S(NL80211_ATTR_MESH_ID)
C2S(NL80211_ATTR_STA_PLINK_ACTION)
C2S(NL80211_ATTR_MPATH_NEXT_HOP)
C2S(NL80211_ATTR_MPATH_INFO)
C2S(NL80211_ATTR_BSS_CTS_PROT)
C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
C2S(NL80211_ATTR_HT_CAPABILITY)
C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
C2S(NL80211_ATTR_REG_ALPHA2)
C2S(NL80211_ATTR_REG_RULES)
C2S(NL80211_ATTR_MESH_CONFIG)
C2S(NL80211_ATTR_BSS_BASIC_RATES)
C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
C2S(NL80211_ATTR_WIPHY_FREQ)
C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
C2S(NL80211_ATTR_MGMT_SUBTYPE)
C2S(NL80211_ATTR_IE)
C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
C2S(NL80211_ATTR_SCAN_FREQUENCIES)
C2S(NL80211_ATTR_SCAN_SSIDS)
C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
C2S(NL80211_ATTR_BSS)
C2S(NL80211_ATTR_REG_INITIATOR)
C2S(NL80211_ATTR_REG_TYPE)
C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
C2S(NL80211_ATTR_FRAME)
C2S(NL80211_ATTR_SSID)
C2S(NL80211_ATTR_AUTH_TYPE)
C2S(NL80211_ATTR_REASON_CODE)
C2S(NL80211_ATTR_KEY_TYPE)
C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
C2S(NL80211_ATTR_CIPHER_SUITES)
C2S(NL80211_ATTR_FREQ_BEFORE)
C2S(NL80211_ATTR_FREQ_AFTER)
C2S(NL80211_ATTR_FREQ_FIXED)
C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
C2S(NL80211_ATTR_TIMED_OUT)
C2S(NL80211_ATTR_USE_MFP)
C2S(NL80211_ATTR_STA_FLAGS2)
C2S(NL80211_ATTR_CONTROL_PORT)
C2S(NL80211_ATTR_TESTDATA)
C2S(NL80211_ATTR_PRIVACY)
C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
C2S(NL80211_ATTR_STATUS_CODE)
C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
C2S(NL80211_ATTR_WPA_VERSIONS)
C2S(NL80211_ATTR_AKM_SUITES)
C2S(NL80211_ATTR_REQ_IE)
C2S(NL80211_ATTR_RESP_IE)
C2S(NL80211_ATTR_PREV_BSSID)
C2S(NL80211_ATTR_KEY)
C2S(NL80211_ATTR_KEYS)
C2S(NL80211_ATTR_PID)
C2S(NL80211_ATTR_4ADDR)
C2S(NL80211_ATTR_SURVEY_INFO)
C2S(NL80211_ATTR_PMKID)
C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
C2S(NL80211_ATTR_DURATION)
C2S(NL80211_ATTR_COOKIE)
C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
C2S(NL80211_ATTR_TX_RATES)
C2S(NL80211_ATTR_FRAME_MATCH)
C2S(NL80211_ATTR_ACK)
C2S(NL80211_ATTR_PS_STATE)
C2S(NL80211_ATTR_CQM)
C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
C2S(NL80211_ATTR_AP_ISOLATE)
C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
C2S(NL80211_ATTR_TX_FRAME_TYPES)
C2S(NL80211_ATTR_RX_FRAME_TYPES)
C2S(NL80211_ATTR_FRAME_TYPE)
C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
C2S(NL80211_ATTR_MCAST_RATE)
C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
C2S(NL80211_ATTR_BSS_HT_OPMODE)
C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
C2S(NL80211_ATTR_MESH_SETUP)
C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
C2S(NL80211_ATTR_STA_PLINK_STATE)
C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
C2S(NL80211_ATTR_REKEY_DATA)
C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
C2S(NL80211_ATTR_SCAN_SUPP_RATES)
C2S(NL80211_ATTR_HIDDEN_SSID)
C2S(NL80211_ATTR_IE_PROBE_RESP)
C2S(NL80211_ATTR_IE_ASSOC_RESP)
C2S(NL80211_ATTR_STA_WME)
C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
C2S(NL80211_ATTR_ROAM_SUPPORT)
C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
C2S(NL80211_ATTR_MAX_MATCH_SETS)
C2S(NL80211_ATTR_PMKSA_CANDIDATE)
C2S(NL80211_ATTR_TX_NO_CCK_RATE)
C2S(NL80211_ATTR_TDLS_ACTION)
C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
C2S(NL80211_ATTR_TDLS_OPERATION)
C2S(NL80211_ATTR_TDLS_SUPPORT)
C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
C2S(NL80211_ATTR_DEVICE_AP_SME)
C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
C2S(NL80211_ATTR_FEATURE_FLAGS)
C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
C2S(NL80211_ATTR_PROBE_RESP)
C2S(NL80211_ATTR_DFS_REGION)
C2S(NL80211_ATTR_DISABLE_HT)
C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
C2S(NL80211_ATTR_NOACK_MAP)
C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
C2S(NL80211_ATTR_RX_SIGNAL_DBM)
C2S(NL80211_ATTR_BG_SCAN_PERIOD)
C2S(NL80211_ATTR_WDEV)
C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
C2S(NL80211_ATTR_CONN_FAILED_REASON)
C2S(NL80211_ATTR_SAE_DATA)
C2S(NL80211_ATTR_VHT_CAPABILITY)
C2S(NL80211_ATTR_SCAN_FLAGS)
C2S(NL80211_ATTR_CHANNEL_WIDTH)
C2S(NL80211_ATTR_CENTER_FREQ1)
C2S(NL80211_ATTR_CENTER_FREQ2)
C2S(NL80211_ATTR_P2P_CTWINDOW)
C2S(NL80211_ATTR_P2P_OPPPS)
C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
C2S(NL80211_ATTR_ACL_POLICY)
C2S(NL80211_ATTR_MAC_ADDRS)
C2S(NL80211_ATTR_MAC_ACL_MAX)
C2S(NL80211_ATTR_RADAR_EVENT)
C2S(NL80211_ATTR_EXT_CAPA)
C2S(NL80211_ATTR_EXT_CAPA_MASK)
C2S(NL80211_ATTR_STA_CAPABILITY)
C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
C2S(NL80211_ATTR_PROTOCOL_FEATURES)
C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
C2S(NL80211_ATTR_DISABLE_VHT)
C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
C2S(NL80211_ATTR_MDID)
C2S(NL80211_ATTR_IE_RIC)
C2S(NL80211_ATTR_CRIT_PROT_ID)
C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
C2S(NL80211_ATTR_PEER_AID)
C2S(NL80211_ATTR_COALESCE_RULE)
C2S(NL80211_ATTR_CH_SWITCH_COUNT)
C2S(NL80211_ATTR_CH_SWITCH_BLOCK_TX)
C2S(NL80211_ATTR_CSA_IES)
C2S(NL80211_ATTR_CSA_C_OFF_BEACON)
C2S(NL80211_ATTR_CSA_C_OFF_PRESP)
C2S(NL80211_ATTR_RXMGMT_FLAGS)
C2S(NL80211_ATTR_STA_SUPPORTED_CHANNELS)
C2S(NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES)
C2S(NL80211_ATTR_HANDLE_DFS)
C2S(NL80211_ATTR_SUPPORT_5_MHZ)
C2S(NL80211_ATTR_SUPPORT_10_MHZ)
C2S(NL80211_ATTR_OPMODE_NOTIF)
C2S(NL80211_ATTR_VENDOR_ID)
C2S(NL80211_ATTR_VENDOR_SUBCMD)
C2S(NL80211_ATTR_VENDOR_DATA)
C2S(NL80211_ATTR_VENDOR_EVENTS)
C2S(NL80211_ATTR_QOS_MAP)
default:
return "NL80211_ATTR_UNKNOWN";
}
}
void WifiEvent::log() {
parse();
byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
int len = genlmsg_attrlen(mHeader, 0);
ALOGD("cmd = %s, len = %d", get_cmdString(), len);
ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
for (int i = 0; i < len; i += 16) {
char line[81];
int linelen = min(16, len - i);
int offset = 0;
appendFmt(line, offset, "%02x", data[i]);
for (int j = 1; j < linelen; j++) {
appendFmt(line, offset, " %02x", data[i+j]);
}
for (int j = linelen; j < 16; j++) {
appendFmt(line, offset, " ");
}
line[23] = '-';
appendFmt(line, offset, " ");
for (int j = 0; j < linelen; j++) {
if (isprint(data[i+j])) {
appendFmt(line, offset, "%c", data[i+j]);
} else {
appendFmt(line, offset, "-");
}
}
ALOGD("%s", line);
}
for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
if (mAttributes[i] != NULL) {
ALOGD("found attribute %s", attributeToString(i));
}
}
ALOGD("-- End of message --");
}
const char *WifiEvent::get_cmdString() {
return cmdToString(get_cmd());
}
int WifiEvent::parse() {
if (mHeader != NULL) {
return WIFI_SUCCESS;
}
mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
genlmsg_attrlen(mHeader, 0), NULL);
// ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
return result;
}
int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
destroy();
mMsg = nlmsg_alloc();
if (mMsg != NULL) {
genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
hdrlen, flags, cmd, /* version = */ 0);
return WIFI_SUCCESS;
} else {
return WIFI_ERROR_OUT_OF_MEMORY;
}
}
int WifiRequest::create(uint32_t id, int subcmd) {
int res = create(NL80211_CMD_VENDOR);
if (res < 0) {
return res;
}
res = put_u32(NL80211_ATTR_VENDOR_ID, id);
if (res < 0) {
return res;
}
res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
if (res < 0) {
return res;
}
if (mIface != -1) {
res = set_iface_id(mIface);
}
return res;
}
static int no_seq_check(struct nl_msg *msg, void *arg)
{
return NL_OK;
}
int WifiCommand::requestResponse() {
int err = create(); /* create the message */
if (err < 0) {
return err;
}
return requestResponse(mMsg);
}
int WifiCommand::requestResponse(WifiRequest& request) {
int err = 0;
struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb)
goto out;
err = nl_send_auto_complete(mInfo->cmd_sock, request.getMessage()); /* send message */
if (err < 0)
goto out;
err = 1;
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, response_handler, this);
while (err > 0) { /* wait for reply */
int res = nl_recvmsgs(mInfo->cmd_sock, cb);
if (res) {
ALOGE("nl80211: %s->nl_recvmsgs failed: %d", __func__, res);
}
}
out:
nl_cb_put(cb);
return err;
}
int WifiCommand::requestEvent(int cmd) {
ALOGD("requesting event %d", cmd);
int res = wifi_register_handler(wifiHandle(), cmd, event_handler, this);
if (res < 0) {
return res;
}
res = create(); /* create the message */
if (res < 0)
goto out;
ALOGD("waiting for response %d", cmd);
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
if (res < 0)
goto out;
ALOGD("waiting for event %d", cmd);
res = mCondition.wait();
if (res < 0)
goto out;
out:
wifi_unregister_handler(wifiHandle(), cmd);
return res;
}
int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
int res = wifi_register_vendor_handler(wifiHandle(), id, subcmd, event_handler, this);
if (res < 0) {
return res;
}
res = create(); /* create the message */
if (res < 0)
goto out;
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
if (res < 0)
goto out;
res = mCondition.wait();
if (res < 0)
goto out;
out:
wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
return res;
}
/* Event handlers */
int WifiCommand::response_handler(struct nl_msg *msg, void *arg) {
// ALOGD("response_handler called");
WifiCommand *cmd = (WifiCommand *)arg;
WifiEvent reply(msg);
int res = reply.parse();
if (res < 0) {
ALOGE("Failed to parse reply message = %d", res);
return NL_SKIP;
} else {
// reply.log();
return cmd->handleResponse(reply);
}
}
int WifiCommand::event_handler(struct nl_msg *msg, void *arg) {
WifiCommand *cmd = (WifiCommand *)arg;
WifiEvent event(msg);
int res = event.parse();
if (res < 0) {
ALOGE("Failed to parse event = %d", res);
res = NL_SKIP;
} else {
res = cmd->handleEvent(event);
}
cmd->mCondition.signal();
return res;
}
/* Other event handlers */
int WifiCommand::valid_handler(struct nl_msg *msg, void *arg) {
// ALOGD("valid_handler called");
int *err = (int *)arg;
*err = 0;
return NL_SKIP;
}
int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
// ALOGD("ack_handler called");
int *err = (int *)arg;
*err = 0;
return NL_STOP;
}
int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
// ALOGD("finish_handler called");
int *ret = (int *)arg;
*ret = 0;
return NL_SKIP;
}
int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
int *ret = (int *)arg;
*ret = err->error;
// ALOGD("error_handler received : %d", err->error);
return NL_SKIP;
}

View file

@ -0,0 +1,352 @@
#include "wifi_hal.h"
#include "common.h"
#include "sync.h"
class WifiEvent
{
/* TODO: remove this when nl headers are updated */
static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
private:
struct nl_msg *mMsg;
struct genlmsghdr *mHeader;
struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
public:
WifiEvent(nl_msg *msg) {
mMsg = msg;
mHeader = NULL;
memset(mAttributes, 0, sizeof(mAttributes));
}
~WifiEvent() {
/* don't destroy mMsg; it doesn't belong to us */
}
void log();
int parse();
genlmsghdr *header() {
return mHeader;
}
int get_cmd() {
return mHeader->cmd;
}
int get_vendor_id() {
return get_u32(NL80211_ATTR_VENDOR_ID);
}
int get_vendor_subcmd() {
return get_u32(NL80211_ATTR_VENDOR_SUBCMD);
}
void *get_vendor_data() {
return get_data(NL80211_ATTR_VENDOR_DATA);
}
int get_vendor_data_len() {
return get_len(NL80211_ATTR_VENDOR_DATA);
}
const char *get_cmdString();
nlattr ** attributes() {
return mAttributes;
}
nlattr *get_attribute(int attribute) {
return mAttributes[attribute];
}
uint8_t get_u8(int attribute) {
return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;
}
uint16_t get_u16(int attribute) {
return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;
}
uint32_t get_u32(int attribute) {
return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;
}
uint64_t get_u64(int attribute) {
return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;
}
int get_len(int attribute) {
return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;
}
void *get_data(int attribute) {
return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;
}
private:
WifiEvent(const WifiEvent&); // hide copy constructor to prevent copies
};
class nl_iterator {
struct nlattr *pos;
int rem;
public:
nl_iterator(struct nlattr *attr) {
pos = (struct nlattr *)nla_data(attr);
rem = nla_len(attr);
}
bool has_next() {
return nla_ok(pos, rem);
}
void next() {
pos = (struct nlattr *)nla_next(pos, &(rem));
}
struct nlattr *get() {
return pos;
}
uint16_t get_type() {
return pos->nla_type;
}
uint8_t get_u8() {
return nla_get_u8(pos);
}
uint16_t get_u16() {
return nla_get_u16(pos);
}
uint32_t get_u32() {
return nla_get_u32(pos);
}
uint64_t get_u64() {
return nla_get_u64(pos);
}
void* get_data() {
return nla_data(pos);
}
int get_len() {
return nla_len(pos);
}
private:
nl_iterator(const nl_iterator&); // hide copy constructor to prevent copies
};
class WifiRequest
{
private:
int mFamily;
int mIface;
struct nl_msg *mMsg;
public:
WifiRequest(int family) {
mMsg = NULL;
mFamily = family;
mIface = -1;
}
WifiRequest(int family, int iface) {
mMsg = NULL;
mFamily = family;
mIface = iface;
}
~WifiRequest() {
destroy();
}
void destroy() {
if (mMsg) {
nlmsg_free(mMsg);
mMsg = NULL;
}
}
nl_msg *getMessage() {
return mMsg;
}
/* Command assembly helpers */
int create(int family, uint8_t cmd, int flags, int hdrlen);
int create(uint8_t cmd) {
return create(mFamily, cmd, 0, 0);
}
int create(uint32_t id, int subcmd);
int put(int attribute, void *ptr, unsigned len) {
return nla_put(mMsg, attribute, len, ptr);
}
int put_u8(int attribute, uint8_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u16(int attribute, uint16_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u32(int attribute, uint32_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u64(int attribute, uint64_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_string(int attribute, const char *value) {
return nla_put(mMsg, attribute, strlen(value) + 1, value);
}
int put_addr(int attribute, mac_addr value) {
return nla_put(mMsg, attribute, sizeof(mac_addr), value);
}
struct nlattr * attr_start(int attribute) {
return nla_nest_start(mMsg, attribute);
}
void attr_end(struct nlattr *attr) {
nla_nest_end(mMsg, attr);
}
int set_iface_id(int ifindex) {
return put_u32(NL80211_ATTR_IFINDEX, ifindex);
}
private:
WifiRequest(const WifiRequest&); // hide copy constructor to prevent copies
};
class WifiCommand
{
protected:
const char *mType;
hal_info *mInfo;
WifiRequest mMsg;
Condition mCondition;
wifi_request_id mId;
interface_info *mIfaceInfo;
int mRefs;
public:
WifiCommand(const char *type, wifi_handle handle, wifi_request_id id)
: mType(type), mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)
{
mIfaceInfo = NULL;
mInfo = getHalInfo(handle);
// ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
}
WifiCommand(const char *type, wifi_interface_handle iface, wifi_request_id id)
: mType(type), mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id),
mId(id), mRefs(1)
{
mIfaceInfo = getIfaceInfo(iface);
mInfo = getHalInfo(iface);
// ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
}
virtual ~WifiCommand() {
// ALOGD("WifiCommand %p destroyed", this);
}
wifi_request_id id() {
return mId;
}
const char *getType() {
return mType;
}
virtual void addRef() {
int refs = __sync_add_and_fetch(&mRefs, 1);
// ALOGD("addRef: WifiCommand %p has %d references", this, refs);
}
virtual void releaseRef() {
int refs = __sync_sub_and_fetch(&mRefs, 1);
if (refs == 0) {
delete this;
} else {
// ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);
}
}
virtual int create() {
/* by default there is no way to cancel */
ALOGD("WifiCommand %p can't be created", this);
return WIFI_ERROR_NOT_SUPPORTED;
}
virtual int cancel() {
/* by default there is no way to cancel */
return WIFI_ERROR_NOT_SUPPORTED;
}
int requestResponse();
int requestEvent(int cmd);
int requestVendorEvent(uint32_t id, int subcmd);
int requestResponse(WifiRequest& request);
protected:
wifi_handle wifiHandle() {
return getWifiHandle(mInfo);
}
wifi_interface_handle ifaceHandle() {
return getIfaceHandle(mIfaceInfo);
}
int familyId() {
return mInfo->nl80211_family_id;
}
int ifaceId() {
return mIfaceInfo->id;
}
/* Override this method to parse reply and dig out data; save it in the object */
virtual int handleResponse(WifiEvent& reply) {
ALOGI("skipping a response");
return NL_SKIP;
}
/* Override this method to parse event and dig out data; save it in the object */
virtual int handleEvent(WifiEvent& event) {
ALOGI("skipping an event");
return NL_SKIP;
}
int registerHandler(int cmd) {
return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);
}
void unregisterHandler(int cmd) {
wifi_unregister_handler(wifiHandle(), cmd);
}
int registerVendorHandler(uint32_t id, int subcmd) {
return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
}
void unregisterVendorHandler(uint32_t id, int subcmd) {
wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
}
private:
WifiCommand(const WifiCommand& ); // hide copy constructor to prevent copies
/* Event handling */
static int response_handler(struct nl_msg *msg, void *arg);
static int event_handler(struct nl_msg *msg, void *arg);
/* Other event handlers */
static int valid_handler(struct nl_msg *msg, void *arg);
static int ack_handler(struct nl_msg *msg, void *arg);
static int finish_handler(struct nl_msg *msg, void *arg);
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
};
/* nl message processing macros (required to pass C++ type checks) */
#define for_each_attr(pos, nla, rem) \
for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
nla_ok(pos, rem); \
pos = (nlattr *)nla_next(pos, &(rem)))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,166 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
/* Internal radio statistics structure in the driver */
typedef struct {
wifi_radio radio;
uint32_t on_time;
uint32_t tx_time;
uint32_t rx_time;
uint32_t on_time_scan;
uint32_t on_time_nbd;
uint32_t on_time_gscan;
uint32_t on_time_roam_scan;
uint32_t on_time_pno_scan;
uint32_t on_time_hs20;
uint32_t num_channels;
wifi_channel_stat channels[];
} wifi_radio_stat_internal;
enum {
LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
};
class GetLinkStatsCommand : public WifiCommand
{
wifi_stats_result_handler mHandler;
public:
GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
: WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
{ }
virtual int create() {
// ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
if (ret < 0) {
ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
// ALOGI("In GetLinkStatsCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
// ALOGI("Id = %0x, subcmd = %d", id, subcmd);
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
wifi_radio_stat *radio_stat =
convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
if (!radio_stat) {
ALOGE("Invalid stats pointer received");
return NL_SKIP;
}
if (radio_stat->num_channels > 11) {
ALOGE("Incorrect number of channels = %d", radio_stat->num_channels);
// dump data before num_channels
ALOGE("radio: = %d", radio_stat->radio);
ALOGE("on_time: = %d", radio_stat->on_time);
ALOGE("tx_time: = %d", radio_stat->tx_time);
ALOGE("rx_time: = %d", radio_stat->rx_time);
ALOGE("on_time_scan: = %d", radio_stat->on_time_scan);
ALOGE("on_time_nbd: = %d", radio_stat->on_time_nbd);
ALOGE("on_time_gscan: = %d", radio_stat->on_time_gscan);
ALOGE("on_time_pno_scan: = %d", radio_stat->on_time_pno_scan);
ALOGE("on_time_hs20: = %d", radio_stat->on_time_hs20);
free(radio_stat);
return NL_SKIP;
}
wifi_iface_stat *iface_stat =
(wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
+ radio_stat->num_channels * sizeof(wifi_channel_stat));
(*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
free(radio_stat);
return NL_OK;
}
private:
wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
wifi_radio_stat *external_stat_ptr = NULL;
if (internal_stat_ptr) {
uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
if (external_stat_ptr) {
external_stat_ptr->radio = internal_stat_ptr->radio;
external_stat_ptr->on_time = internal_stat_ptr->on_time;
external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
external_stat_ptr->tx_time_per_levels = NULL;
external_stat_ptr->num_tx_levels = 0;
external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
if (internal_stat_ptr->num_channels) {
memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
channel_size);
}
}
}
return external_stat_ptr;
}
};
wifi_error wifi_get_link_stats(wifi_request_id id,
wifi_interface_handle iface, wifi_stats_result_handler handler)
{
GetLinkStatsCommand command(iface, handler);
return (wifi_error) command.requestResponse();
}
wifi_error wifi_set_link_stats(
wifi_interface_handle /* iface */, wifi_link_layer_params /* params */)
{
/* Return success here since bcom HAL does not need set link stats. */
return WIFI_SUCCESS;
}
wifi_error wifi_clear_link_stats(
wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */,
u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */)
{
/* Return success here since bcom HAL does not support clear link stats. */
return WIFI_SUCCESS;
}

View file

@ -0,0 +1,683 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink-private/object-api.h>
#include <netlink-private/types.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include <utils/String8.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
using namespace android;
#define RTT_RESULT_SIZE (sizeof(wifi_rtt_result));
typedef enum {
RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
RTT_SUBCMD_CANCEL_CONFIG,
RTT_SUBCMD_GETCAPABILITY,
RTT_SUBCMD_GETAVAILCHANNEL,
RTT_SUBCMD_SET_RESPONDER,
RTT_SUBCMD_CANCEL_RESPONDER,
} RTT_SUB_COMMAND;
typedef enum {
RTT_ATTRIBUTE_TARGET_CNT = 0,
RTT_ATTRIBUTE_TARGET_INFO,
RTT_ATTRIBUTE_TARGET_MAC,
RTT_ATTRIBUTE_TARGET_TYPE,
RTT_ATTRIBUTE_TARGET_PEER,
RTT_ATTRIBUTE_TARGET_CHAN,
RTT_ATTRIBUTE_TARGET_PERIOD,
RTT_ATTRIBUTE_TARGET_NUM_BURST,
RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
RTT_ATTRIBUTE_TARGET_LCI,
RTT_ATTRIBUTE_TARGET_LCR,
RTT_ATTRIBUTE_TARGET_BURST_DURATION,
RTT_ATTRIBUTE_TARGET_PREAMBLE,
RTT_ATTRIBUTE_TARGET_BW,
RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
RTT_ATTRIBUTE_RESULTS_PER_TARGET,
RTT_ATTRIBUTE_RESULT_CNT,
RTT_ATTRIBUTE_RESULT
} RTT_ATTRIBUTE;
typedef struct strmap_entry {
int id;
String8 text;
} strmap_entry_t;
struct dot11_rm_ie {
u8 id;
u8 len;
u8 token;
u8 mode;
u8 type;
} __attribute__ ((packed));
typedef struct dot11_rm_ie dot11_rm_ie_t;
#define DOT11_HDR_LEN 2
#define DOT11_RM_IE_LEN 5
#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */
#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */
#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */
static const strmap_entry_t err_info[] = {
{RTT_STATUS_SUCCESS, String8("Success")},
{RTT_STATUS_FAILURE, String8("Failure")},
{RTT_STATUS_FAIL_NO_RSP, String8("No reponse")},
{RTT_STATUS_FAIL_INVALID_TS, String8("Invalid Timestamp")},
{RTT_STATUS_FAIL_PROTOCOL, String8("Protocol error")},
{RTT_STATUS_FAIL_REJECTED, String8("Rejected")},
{RTT_STATUS_FAIL_NOT_SCHEDULED_YET, String8("not scheduled")},
{RTT_STATUS_FAIL_SCHEDULE, String8("schedule failed")},
{RTT_STATUS_FAIL_TM_TIMEOUT, String8("timeout")},
{RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, String8("AP is on difference channel")},
{RTT_STATUS_FAIL_NO_CAPABILITY, String8("no capability")},
{RTT_STATUS_FAIL_BUSY_TRY_LATER, String8("busy and try later")},
{RTT_STATUS_ABORTED, String8("aborted")}
};
static const char*
get_err_info(int status)
{
int i;
const strmap_entry_t *p_entry;
int num_entries = sizeof(err_info)/ sizeof(err_info[0]);
/* scan thru the table till end */
p_entry = err_info;
for (i = 0; i < (int) num_entries; i++)
{
if (p_entry->id == status)
return p_entry->text;
p_entry++; /* next entry */
}
return "unknown error"; /* not found */
}
class GetRttCapabilitiesCommand : public WifiCommand
{
wifi_rtt_capabilities *mCapabilities;
public:
GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites)
: WifiCommand("GetRttCapabilitiesCommand", iface, 0), mCapabilities(capabitlites)
{
memset(mCapabilities, 0, sizeof(*mCapabilities));
}
virtual int create() {
ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In GetRttCapabilitiesCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
sizeof(*mCapabilities));
memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
return NL_OK;
}
};
class GetRttResponderInfoCommand : public WifiCommand
{
wifi_rtt_responder* mResponderInfo;
public:
GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
: WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo)
{
memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
}
virtual int create() {
ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In GetRttResponderInfoCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
sizeof(*mResponderInfo));
memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
return NL_OK;
}
};
class EnableResponderCommand : public WifiCommand
{
wifi_channel_info mChannelInfo;
wifi_rtt_responder* mResponderInfo;
unsigned m_max_duration_sec;
public:
EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
unsigned max_duration_seconds, wifi_rtt_responder *responderInfo)
: WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint),
m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo)
{
memset(mResponderInfo, 0, sizeof(*mResponderInfo));
}
virtual int create() {
ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In EnableResponderCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
sizeof(*mResponderInfo));
memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
return NL_OK;
}
};
class CancelResponderCommand : public WifiCommand
{
public:
CancelResponderCommand(wifi_interface_handle iface, int id)
: WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/
{
}
virtual int create() {
ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
/* Nothing to do on response! */
return NL_SKIP;
}
};
class RttCommand : public WifiCommand
{
unsigned numRttParams;
int mCompleted;
int currentIdx;
int totalCnt;
static const int MAX_RESULTS = 1024;
wifi_rtt_result *rttResults[MAX_RESULTS];
wifi_rtt_config *rttParams;
wifi_rtt_event_handler rttHandler;
public:
RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
: WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config),
rttHandler(handler)
{
memset(rttResults, 0, sizeof(rttResults));
currentIdx = 0;
mCompleted = 0;
totalCnt = 0;
}
RttCommand(wifi_interface_handle iface, int id)
: WifiCommand("RttCommand", iface, id)
{
currentIdx = 0;
mCompleted = 0;
totalCnt = 0;
numRttParams = 0;
}
int createSetupRequest(WifiRequest& request) {
int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
if (result < 0) {
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
if (result < 0) {
return result;
}
nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
for (unsigned i = 0; i < numRttParams; i++) {
nlattr *attr2 = request.attr_start(i);
if (attr2 == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
if (result < 0) {
return result;
}
result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
sizeof(wifi_channel_info));
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
rttParams[i].num_frames_per_burst);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
rttParams[i].num_retries_per_rtt_frame);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
rttParams[i].num_retries_per_ftmr);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD,
rttParams[i].burst_period);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION,
rttParams[i].burst_duration);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI,
rttParams[i].LCI_request);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR,
rttParams[i].LCR_request);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW,
rttParams[i].bw);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE,
rttParams[i].preamble);
if (result < 0) {
return result;
}
request.attr_end(attr2);
}
request.attr_end(rtt_config);
request.attr_end(data);
return WIFI_SUCCESS;
}
int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG);
if (result < 0) {
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
for(unsigned i = 0; i < num_devices; i++) {
result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
if (result < 0) {
return result;
}
}
request.attr_end(data);
return result;
}
int start() {
ALOGD("Setting RTT configuration");
WifiRequest request(familyId(), ifaceId());
int result = createSetupRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create setup request; result = %d", result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to configure RTT setup; result = %d", result);
return result;
}
registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
ALOGI("Successfully started RTT operation");
return result;
}
virtual int cancel() {
ALOGD("Stopping RTT");
WifiRequest request(familyId(), ifaceId());
int result = createTeardownRequest(request, 0, NULL);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create stop request; result = %d", result);
} else {
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to stop scan; result = %d", result);
}
}
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
return WIFI_SUCCESS;
}
int cancel_specific(unsigned num_devices, mac_addr addr[]) {
ALOGE("Stopping RTT");
WifiRequest request(familyId(), ifaceId());
int result = createTeardownRequest(request, num_devices, addr);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create stop request; result = %d", result);
} else {
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to stop RTT; result = %d", result);
}
}
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
return WIFI_SUCCESS;
}
virtual int handleResponse(WifiEvent& reply) {
/* Nothing to do on response! */
return NL_SKIP;
}
virtual int handleEvent(WifiEvent& event) {
ALOGI("Got an RTT event");
nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
int len = event.get_vendor_data_len();
if (vendor_data == NULL || len == 0) {
ALOGI("No rtt results found");
}
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
mCompleted = it.get_u32();
ALOGI("retrieved completed flag : %d\n", mCompleted);
} else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) {
int result_cnt = 0;
mac_addr bssid;
for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) {
memcpy(bssid, it2.get_data(), sizeof(mac_addr));
ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
bssid[0],
bssid[1],
bssid[2],
bssid[3],
bssid[4],
bssid[5]);
} else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) {
result_cnt = it2.get_u32();
ALOGI("retrieved result_cnt : %d\n", result_cnt);
} else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) {
int result_len = it2.get_len();
rttResults[currentIdx] = (wifi_rtt_result *)malloc(it2.get_len());
wifi_rtt_result *rtt_result = rttResults[currentIdx];
if (rtt_result == NULL) {
mCompleted = 1;
ALOGE("failed to allocate the wifi_rtt_result\n");
break;
}
memcpy(rtt_result, it2.get_data(), it2.get_len());
result_len -= sizeof(wifi_rtt_result);
if (result_len > 0) {
result_len -= sizeof(wifi_rtt_result);
dot11_rm_ie_t *ele_1;
dot11_rm_ie_t *ele_2;
/* The result has LCI or LCR element */
ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) {
if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
rtt_result->LCI = (wifi_information_element *)ele_1;
result_len -= (ele_1->len + DOT11_HDR_LEN);
/* get a next rm ie */
if (result_len > 0) {
ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
(ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
rtt_result->LCR = (wifi_information_element *)ele_2;
}
}
} else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){
rtt_result->LCR = (wifi_information_element *)ele_1;
result_len -= (ele_1->len + DOT11_HDR_LEN);
/* get a next rm ie */
if (result_len > 0) {
ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
(ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
rtt_result->LCI = (wifi_information_element *)ele_2;
}
}
}
}
}
totalCnt++;
ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n"
"\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n"
"\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n"
"\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n",
rtt_result->burst_num, rtt_result->measurement_number,
rtt_result->success_number, rtt_result->number_per_burst_peer,
get_err_info(rtt_result->status), rtt_result->retry_after_duration,
rtt_result->rssi, rtt_result->rx_rate.bitrate * 100,
rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10,
rtt_result->burst_duration, rtt_result->negotiated_burst_num);
currentIdx++;
}
}
}
}
if (mCompleted) {
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
(*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
for (int i = 0; i < currentIdx; i++) {
free(rttResults[i]);
rttResults[i] = NULL;
}
totalCnt = currentIdx = 0;
WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
if (cmd)
cmd->releaseRef();
}
return NL_SKIP;
}
};
/* API to request RTT measurement */
wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
{
wifi_handle handle = getWifiHandle(iface);
RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = wifi_register_cmd(handle, id, cmd);
if (result != WIFI_SUCCESS) {
cmd->releaseRef();
return result;
}
result = (wifi_error)cmd->start();
if (result != WIFI_SUCCESS) {
wifi_unregister_cmd(handle, id);
cmd->releaseRef();
return result;
}
return result;
}
/* API to cancel RTT measurements */
wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
unsigned num_devices, mac_addr addr[])
{
wifi_handle handle = getWifiHandle(iface);
RttCommand *cmd = new RttCommand(iface, id);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
cmd->cancel_specific(num_devices, addr);
cmd->releaseRef();
return WIFI_SUCCESS;
}
/* API to get RTT capability */
wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
wifi_rtt_capabilities *capabilities)
{
GetRttCapabilitiesCommand command(iface, capabilities);
return (wifi_error) command.requestResponse();
}
/* API to get the responder information */
wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
wifi_rtt_responder* responderInfo)
{
GetRttResponderInfoCommand command(iface, responderInfo);
return (wifi_error) command.requestResponse();
}
/**
* Enable RTT responder mode.
* channel_hint - hint of the channel information where RTT responder should be enabled on.
* max_duration_seconds - timeout of responder mode.
* wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported.
*/
wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
wifi_channel_info channel_hint, unsigned max_duration_seconds,
wifi_rtt_responder* responderInfo)
{
EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo);
return (wifi_error) command.requestResponse();
}
/**
* Disable RTT responder mode.
*/
wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface)
{
CancelResponderCommand command(iface, id);
return (wifi_error) command.requestResponse();
}

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,231 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink-private/object-api.h>
#include <netlink-private/types.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <log/log.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
typedef enum {
WIFI_OFFLOAD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
WIFI_OFFLOAD_STOP_MKEEP_ALIVE,
} WIFI_OFFLOAD_SUB_COMMAND;
typedef enum {
MKEEP_ALIVE_ATTRIBUTE_ID,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
} WIFI_MKEEP_ALIVE_ATTRIBUTE;
typedef enum {
START_MKEEP_ALIVE,
STOP_MKEEP_ALIVE,
} GetCmdType;
///////////////////////////////////////////////////////////////////////////////
class MKeepAliveCommand : public WifiCommand
{
u8 mIndex;
u8 *mIpPkt;
u16 mIpPktLen;
u8 *mSrcMacAddr;
u8 *mDstMacAddr;
u32 mPeriodMsec;
GetCmdType mType;
public:
// constructor for start sending
MKeepAliveCommand(wifi_interface_handle iface, u8 index, u8 *ip_packet, u16 ip_packet_len,
u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec, GetCmdType cmdType)
: WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet),
mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
mPeriodMsec(period_msec), mType(cmdType)
{ }
// constructor for stop sending
MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
: WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
{ }
int createRequest(WifiRequest &request) {
int result;
switch (mType) {
case START_MKEEP_ALIVE:
{
result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create start keep alive request; result = %d", result);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
if (result < 0) {
ALOGE("Failed to put id request; result = %d", result);
return result;
}
result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
if (result < 0) {
ALOGE("Failed to put ip pkt len request; result = %d", result);
return result;
}
result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
if (result < 0) {
ALOGE("Failed to put ip pkt request; result = %d", result);
return result;
}
result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
if (result < 0) {
ALOGE("Failed to put src mac address request; result = %d", result);
return result;
}
result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
if (result < 0) {
ALOGE("Failed to put dst mac address request; result = %d", result);
return result;
}
result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
if (result < 0) {
ALOGE("Failed to put period request; result = %d", result);
return result;
}
request.attr_end(data);
break;
}
case STOP_MKEEP_ALIVE:
{
result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create stop keep alive request; result = %d", result);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
if (result < 0) {
ALOGE("Failed to put id request; result = %d", result);
return result;
}
request.attr_end(data);
break;
}
default:
ALOGE("Unknown wifi keep alive command");
result = WIFI_ERROR_UNKNOWN;
}
return result;
}
int start() {
ALOGD("Start mkeep_alive command");
WifiRequest request(familyId(), ifaceId());
int result = createRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create keep alive request; result = %d", result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to register keep alive response; result = %d", result);
}
return result;
}
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In MKeepAliveCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
switch (mType) {
case START_MKEEP_ALIVE:
case STOP_MKEEP_ALIVE:
break;
default:
ALOGW("Unknown mkeep_alive command");
}
return NL_OK;
}
virtual int handleEvent(WifiEvent& event) {
/* NO events! */
return NL_SKIP;
}
};
/* API to send specified mkeep_alive packet periodically. */
wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
{
if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
&& (dst_mac_addr != NULL) && (period_msec > 0)
&& (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = (wifi_error)cmd->start();
cmd->releaseRef();
return result;
} else {
ALOGE("Invalid mkeep_alive parameters");
return WIFI_ERROR_INVALID_ARGS;
}
}
/* API to stop sending mkeep_alive packet. */
wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
{
if (index > 0 && index <= N_AVAIL_ID) {
MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = (wifi_error)cmd->start();
cmd->releaseRef();
return result;
} else {
ALOGE("Invalid mkeep_alive parameters");
return WIFI_ERROR_INVALID_ARGS;
}
}