mtk: added wifi HAL

Signed-off-by: Moyster <oysterized@gmail.com>
This commit is contained in:
Yuri Konotopov 2017-12-08 19:23:24 +00:00 committed by Moyster
parent a2386698bc
commit 8161216738
12 changed files with 6526 additions and 0 deletions

48
mtk/wifi_hal/Android.mk Normal file
View File

@ -0,0 +1,48 @@
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
# Make the HAL library
# ============================================================
include $(CLEAR_VARS)
LOCAL_REQUIRED_MODULES :=
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(MTK_TC7_FEATURE), yes)
LOCAL_CFLAGS += -DCONFIG_PNO_SUPPORT
endif
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_offload.cpp
LOCAL_MODULE := libwifi-hal-mt66xx
include $(BUILD_STATIC_LIBRARY)

246
mtk/wifi_hal/common.cpp Normal file
View File

@ -0,0 +1,246 @@
#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 <stdlib.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) * sizeof(cmd_info));
info->num_cmd--;
ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
break;
}
}
if (!cmd) {
ALOGE("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) * 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;
}

195
mtk/wifi_hal/common.h Normal file
View File

@ -0,0 +1,195 @@
#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 */
#ifndef MAC2STR
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
#endif
/*
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 */
ANDROID_NL80211_SUBCMD_UNSPECIFIED,
/* Define all vendor startup commands between 0x0 and 0x0FFF */
ANDROID_NL80211_SUBCMD_WIFI_RANGE_START = 0x0001,
ANDROID_NL80211_SUBCMD_WIFI_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 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,
/* This is reserved for future usage */
} ANDROID_VENDOR_SUB_COMMAND;
typedef enum {
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,
WIFI_EVENT_RSSI_MONITOR,
GSCAN_EVENT_EPNO_EVENT,
GSCAN_EVENT_ANQPO_HOTSPOT_MATCH,
} WIFI_VENDOR_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 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;
#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 ie_length;
char ie_data[1];
} 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))
#endif

View File

@ -0,0 +1,734 @@
#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) {
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);
ALOGD("WifiRequest::create vendor command to iface %d, vendor_id=0x%x, subcmd=0x%04x, res=%d",
mIface, id, subcmd, res);
}
return res;
}
static int no_seq_check(struct nl_msg *msg, void *arg)
{
return NL_OK;
}
int WifiCommand::requestResponse() {
int err = create();
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;
/* send message */
err = nl_send_auto_complete(mInfo->cmd_sock, request.getMessage());
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);
/* wait for reply */
while (err > 0) {
int res = nl_recvmsgs(mInfo->cmd_sock, cb);
if (res) {
ALOGE("WifiCommand::requestResponse nl_recvmsgs failed: %d", res);
}
}
if (err)
ALOGD("WifiCommand::requestResponse err=%d", err);
out:
nl_cb_put(cb);
return err;
}
int WifiCommand::requestEvent(int cmd) {
ALOGD("WifiCommand::requestEvent for cmd %d", cmd);
int res = wifi_register_handler(wifiHandle(), cmd, event_handler, this);
if (res < 0) {
return res;
}
res = create();
if (res < 0)
goto out;
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
if (res < 0)
goto out;
ALOGD("WifiCommand::requestEvent waiting for event");
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();
if (res < 0)
goto out;
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
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;
}
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 called, err->error=%d", err->error);
return NL_SKIP;
}

346
mtk/wifi_hal/cpp_bindings.h Normal file
View File

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

1882
mtk/wifi_hal/gscan.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
typedef enum {
LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
} LSTATS_SUB_COMMAND;
typedef enum {
LSTATS_ATTRIBUTE_STATS = 2,
} LSTATS_ATTRIBUTE;
///////////////////////////////////////////////////////////////////////////////////
class GetLinkStatsCommand : public WifiCommand
{
wifi_stats_result_handler mHandler;
public:
GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
: WifiCommand(iface, 0), mHandler(handler)
{ }
virtual int create() {
ALOGD("[WIFI HAL]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) {
ALOGD("[WIFI HAL]In GetLinkStatsCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGE("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);
struct nlattr *vendor_data = (struct nlattr *)reply.get_vendor_data();
int len = reply.get_vendor_data_len();
wifi_radio_stat *data;
if(vendor_data->nla_type == LSTATS_ATTRIBUTE_STATS)
data = (wifi_radio_stat *)nla_data(vendor_data);
else
return NL_SKIP;
int num_chan = data->num_channels;
if (num_chan > 32) {
ALOGE("Incorrect number of channels = %d", num_chan);
return NL_SKIP;
}
/*
(*mHandler.on_link_stats_results)(id,
(wifi_iface_stat *)((char *)&(data)->channels
+ num_chan*sizeof(wifi_channel_stat)),
1, data);
*/
return NL_OK;
}
};
wifi_error wifi_get_link_stats(wifi_request_id id,
wifi_interface_handle iface, wifi_stats_result_handler handler)
{
#if 0
GetLinkStatsCommand command(iface, handler);
return (wifi_error) command.requestResponse();
#else
ALOGD("[WIFI HAL]don't support wifi_get_link_stats");
return WIFI_ERROR_NOT_SUPPORTED;
#endif
}

690
mtk/wifi_hal/rtt.cpp Normal file
View File

@ -0,0 +1,690 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink-types.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include <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_CAPABILITIES = 1,
RTT_ATTRIBUTE_TARGET_CNT = 10,
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(iface, 0), mCapabilities(capabitlites)
{
memset(mCapabilities, 0, sizeof(*mCapabilities));
}
virtual int create() {
ALOGD("[WIFI HAL]Creating message to get Rtt 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();
int wiphy_id = reply.get_u32(NL80211_ATTR_WIPHY);
int if_id = reply.get_u32(NL80211_ATTR_IFINDEX);
struct nlattr *vendor_data = (struct nlattr *)reply.get_vendor_data();
int len = reply.get_vendor_data_len();
void *payload = NULL;
if(vendor_data->nla_type == RTT_ATTRIBUTE_CAPABILITIES) {
payload = nla_data(vendor_data);
len -= NLA_HDRLEN;
}
ALOGD("wiphy_id=%d, if_id=%d, Id=%0x, subcmd=%d, len=%d, expected len=%d", wiphy_id, if_id, id, subcmd, len,
sizeof(*mCapabilities));
if (payload)
memcpy(mCapabilities, payload, min(len, (int) sizeof(*mCapabilities)));
ALOGI("RTT capability: %d, %d, %d, %d, %d, %d",
mCapabilities->rtt_one_sided_supported, mCapabilities->rtt_ftm_supported,
mCapabilities->lci_support, mCapabilities->lcr_support,
mCapabilities->preamble_support, mCapabilities->bw_support);
return NL_OK;
}
};
class GetRttAvailableChannelCommand : public WifiCommand
{
wifi_channel_info* mChannelInfo;
public:
GetRttAvailableChannelCommand(wifi_interface_handle iface, wifi_channel_info *channel)
: WifiCommand(iface, 0), mChannelInfo(channel)
{
memset(mChannelInfo, 0 , sizeof(*mChannelInfo));
}
virtual int create() {
ALOGD("Creating message to get available channel ; 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 GetRttAvailableChannelCommand::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(*mChannelInfo));
memcpy(mChannelInfo, data, min(len, (int) sizeof(*mChannelInfo)));
return NL_OK;
}
};
class EnableResponderCommand : public WifiCommand
{
wifi_channel_info mChannelInfo;
wifi_channel_info* mChannelUsed;
unsigned m_max_duration_sec;
public:
EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
unsigned max_duration_seconds, wifi_channel_info *channel_used)
: WifiCommand(iface, 0), mChannelInfo(channel_hint),
m_max_duration_sec(max_duration_seconds), mChannelUsed(channel_used)
{
memset(mChannelUsed, 0 , sizeof(*mChannelUsed));
}
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(*mChannelUsed));
memcpy(mChannelUsed, data, min(len, (int) sizeof(*mChannelUsed)));
return NL_OK;
}
};
class CancelResponderCommand : public WifiCommand
{
public:
CancelResponderCommand(wifi_interface_handle iface, int id)
: WifiCommand(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(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(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);
wifi_register_cmd(handle, id, cmd);
return (wifi_error)cmd->start();
}
/* 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);
if (cmd) {
cmd->cancel_specific(num_devices, addr);
cmd->releaseRef();
return WIFI_SUCCESS;
}
return WIFI_ERROR_INVALID_ARGS;
}
/* 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 channel */
wifi_error wifi_rtt_get_available_channel(wifi_interface_handle iface, wifi_channel_info* channel)
{
GetRttAvailableChannelCommand command(iface, channel);
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.
* channel_used - channel used for RTT responder, NULL if responder is not enabled.
*/
wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
wifi_channel_info channel_hint, unsigned max_duration_seconds,
wifi_channel_info* channel_used )
{
EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, channel_used);
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();
}

54
mtk/wifi_hal/sync.h Normal file
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

1181
mtk/wifi_hal/wifi_hal.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,812 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink-types.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
using namespace android;
typedef enum {
LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
LOGGER_TRIGGER_MEM_DUMP,
LOGGER_GET_MEM_DUMP,
LOGGER_GET_VER,
LOGGER_GET_RING_STATUS,
LOGGER_GET_RING_DATA,
LOGGER_GET_FEATURE,
LOGGER_RESET_LOGGING,
} DEBUG_SUB_COMMAND;
typedef enum {
LOGGER_ATTRIBUTE_DRIVER_VER,
LOGGER_ATTRIBUTE_FW_VER,
LOGGER_ATTRIBUTE_RING_ID,
LOGGER_ATTRIBUTE_RING_NAME,
LOGGER_ATTRIBUTE_RING_FLAGS,
LOGGER_ATTRIBUTE_LOG_LEVEL,
LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
LOGGER_ATTRIBUTE_FW_DUMP_LEN,
LOGGER_ATTRIBUTE_FW_DUMP_DATA,
// LOGGER_ATTRIBUTE_FW_ERR_CODE,
LOGGER_ATTRIBUTE_RING_DATA,
LOGGER_ATTRIBUTE_RING_STATUS,
LOGGER_ATTRIBUTE_RING_NUM,
} LOGGER_ATTRIBUTE;
typedef enum {
DEBUG_OFF = 0,
DEBUG_NORMAL,
DEBUG_VERBOSE,
DEBUG_VERY,
DEBUG_VERY_VERY,
} LOGGER_LEVEL;
typedef enum {
GET_FW_VER,
GET_DRV_VER,
GET_RING_DATA,
GET_RING_STATUS,
GET_FEATURE,
START_RING_LOG,
} GetCmdType;
///////////////////////////////////////////////////////////////////////////////
class DebugCommand : public WifiCommand
{
char *mBuff;
int *mBuffSize;
u32 *mNumRings;
wifi_ring_buffer_status *mStatus;
unsigned int *mSupport;
u32 mVerboseLevel;
u32 mFlags;
u32 mMaxIntervalSec;
u32 mMinDataSize;
char *mRingName;
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, 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(LOGGER_ATTRIBUTE_LOG_LEVEL, mVerboseLevel);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to put log level; result = %d", result);
return result;
}
result = request.put_u32(LOGGER_ATTRIBUTE_RING_FLAGS, mFlags);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to put ring flags; result = %d", result);
return result;
}
result = request.put_u32(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(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(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, 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(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, 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(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, 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(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, 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, 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() == 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(), LOGGER_ATTRIBUTE_RING_NUM);
return NL_SKIP;
}
it.next();
for (unsigned int i = 0; it.has_next() && i < *mNumRings; it.next()) {
if (it.get_type() == LOGGER_ATTRIBUTE_RING_STATUS) {
memcpy(status, it.get_data(), sizeof(wifi_ring_buffer_status));
i++;
status++;
} 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();
int len = reply.get_vendor_data_len();
ALOGD("len = %d, expected len = %d", len, 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 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);
return (wifi_error)cmd->start();
} 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);
return (wifi_error)cmd->start();
} else {
ALOGE("Driver version 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);
return (wifi_error)cmd->start();
}
/* 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);
return (wifi_error)cmd->start();
} else {
ALOGE("Ring status buffer NULL");
return WIFI_ERROR_INVALID_ARGS;
}
}
/* 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);
return (wifi_error)cmd->start();
} else {
ALOGE("Get support buffer NULL");
return WIFI_ERROR_INVALID_ARGS;
}
}
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);
return (wifi_error)cmd->start();
} else {
ALOGE("Ring name 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)
{ }
SetLogHandler(wifi_interface_handle iface, int id)
: WifiCommand(iface, id)
{ }
int start() {
ALOGD("Register log handler");
registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
return WIFI_SUCCESS;
}
virtual int cancel() {
/* Send a command to driver to stop generating logging events */
ALOGD("Reset event handler");
WifiRequest request(familyId(), ifaceId());
int result = request.create(GOOGLE_OUI, 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;
}
/* unregister event handler */
unregisterVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_RING_EVENT);
ALOGD("Success to reset event handler");
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 == GOOGLE_DEBUG_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() == LOGGER_ATTRIBUTE_RING_STATUS) {
memcpy(&status, it.get_data(), sizeof(status));
} else if (it.get_type() == 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);
SetLogHandler *cmd = new SetLogHandler(iface, id, handler);
ALOGI("Logger start, handle = %p", handle);
if (cmd) {
wifi_register_cmd(handle, id, cmd);
return (wifi_error)cmd->start();
} else {
ALOGD("Out of memory");
return WIFI_ERROR_OUT_OF_MEMORY;
}
}
wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface)
{
wifi_handle handle = getWifiHandle(iface);
SetLogHandler *cmd = new SetLogHandler(iface, id);
ALOGI("Logger reset, handle = %p", handle);
if (cmd) {
cmd->cancel();
cmd->releaseRef();
return WIFI_SUCCESS;
}
return WIFI_ERROR_INVALID_ARGS;
}
///////////////////////////////////////////////////////////////////////////////
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() {
ALOGD("Start Alerting");
registerVendorHandler(GOOGLE_OUI, GOOGLE_DEBUG_MEM_DUMP_EVENT);
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() == 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) {
wifi_ring_buffer_id ring_id;
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 == GOOGLE_DEBUG_MEM_DUMP_EVENT) {
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
if (it.get_type() == LOGGER_ATTRIBUTE_FW_DUMP_LEN) {
mBuffSize = it.get_u32();
} else if (it.get_type() == LOGGER_ATTRIBUTE_RING_DATA) {
buffer_size = it.get_len();
buffer = (char *)it.get_data();
/*
} else if (it.get_type() == 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, LOGGER_GET_MEM_DUMP);
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(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(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);
SetAlertHandler *cmd = new SetAlertHandler(iface, id, handler);
ALOGI("Alert start, handle = %p", handle);
wifi_register_cmd(handle, id, cmd);
return (wifi_error)cmd->start();
}
///////////////////////////////////////////////////////////////////////////////
class MemoryDumpCommand: public WifiCommand
{
wifi_firmware_memory_dump_handler mHandler;
int mBuffSize;
char *mBuff;
public:
MemoryDumpCommand(wifi_interface_handle iface, wifi_firmware_memory_dump_handler handler)
: WifiCommand(iface, 0), mHandler(handler), mBuffSize(0), mBuff(NULL)
{ }
int start() {
ALOGD("Start memory dump command");
WifiRequest request(familyId(), ifaceId());
int result = request.create(GOOGLE_OUI, LOGGER_TRIGGER_MEM_DUMP);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create trigger fw 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;
}
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
if (it.get_type() == 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, LOGGER_GET_MEM_DUMP);
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(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(LOGGER_ATTRIBUTE_FW_DUMP_DATA, (uint64_t)mBuff);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to put get memory dump request; result = %d", result);
return result;
}
request.attr_end(data);
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to register get momory dump response; result = %d", result);
}
} else if (it.get_type() == 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());
}
}
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);
return (wifi_error)cmd->start();
}

View File

@ -0,0 +1,229 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink-types.h>
#include "nl80211_copy.h"
#include "sync.h"
#define LOG_TAG "WifiHAL"
#include <utils/Log.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
using namespace android;
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 = 1,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
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)
{ }
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);
wifi_error err = (wifi_error) cmd->start();
delete cmd;
return err;
} 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 err = (wifi_error) cmd->start();
delete cmd;
return err;
} else {
ALOGE("Invalid mkeep_alive parameters");
return WIFI_ERROR_INVALID_ARGS;
}
}