mtk: added wifi HAL
Signed-off-by: Moyster <oysterized@gmail.com>
This commit is contained in:
parent
a2386698bc
commit
8161216738
|
@ -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)
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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)))
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue