hal: add mediatek wifi_hal

This commit is contained in:
Stricted
2021-01-17 01:27:11 +00:00
committed by Joel Bacchus
parent ce6ecac911
commit c95336cd0c
12 changed files with 5752 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
# Make the HAL library
# ============================================================
include $(CLEAR_VARS)
LOCAL_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 \
wifi_offload.cpp
LOCAL_MODULE := libwifi-hal-mt66xx
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := mtk
include $(BUILD_STATIC_LIBRARY)
+24
View File
@@ -0,0 +1,24 @@
Copyright (c) <YEAR>, <OWNER>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+27
View File
@@ -0,0 +1,27 @@
This directory contains WIFI_HAL interface and function
WHAT IT DOES?
=============
It provide another method for WIFI HAL to access WIFI driver which is different from wpa_supplicant.
HOW IT WAS BUILT?
==================
It needs the following libs from AOSP:
and the following libs from MediaTek:
All source/dependency modules of this module are already put in
'hardware/mediatek/wlan/wifi_hal' folder.
HOW TO USE IT?
==============
Files in this directory is used for WIFI HAL interface and function
+245
View File
@@ -0,0 +1,245 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
interface_info *getIfaceInfo(wifi_interface_handle handle)
{
return (interface_info *)handle;
}
wifi_handle getWifiHandle(wifi_interface_handle handle)
{
return getIfaceInfo(handle)->handle;
}
hal_info *getHalInfo(wifi_handle handle)
{
return (hal_info *)handle;
}
hal_info *getHalInfo(wifi_interface_handle handle)
{
return getHalInfo(getWifiHandle(handle));
}
wifi_handle getWifiHandle(hal_info *info)
{
return (wifi_handle)info;
}
wifi_interface_handle getIfaceHandle(interface_info *info)
{
return (wifi_interface_handle)info;
}
wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
{
hal_info *info = (hal_info *)handle;
/* TODO: check for multiple handlers? */
pthread_mutex_lock(&info->cb_lock);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_event_cb < info->alloc_event_cb) {
info->event_cb[info->num_event_cb].nl_cmd = cmd;
info->event_cb[info->num_event_cb].vendor_id = 0;
info->event_cb[info->num_event_cb].vendor_subcmd = 0;
info->event_cb[info->num_event_cb].cb_func = func;
info->event_cb[info->num_event_cb].cb_arg = arg;
ALOGV("Successfully added event handler %p:%p for command %d at %d",
arg, func, cmd, info->num_event_cb);
info->num_event_cb++;
result = WIFI_SUCCESS;
}
pthread_mutex_unlock(&info->cb_lock);
return result;
}
wifi_error wifi_register_vendor_handler(wifi_handle handle,
uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
{
hal_info *info = (hal_info *)handle;
/* TODO: check for multiple handlers? */
pthread_mutex_lock(&info->cb_lock);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_event_cb < info->alloc_event_cb) {
info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
info->event_cb[info->num_event_cb].vendor_id = id;
info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
info->event_cb[info->num_event_cb].cb_func = func;
info->event_cb[info->num_event_cb].cb_arg = arg;
ALOGV("Added event handler %p:%p for vendor 0x%0x and subcmd 0x%0x at %d",
arg, func, id, subcmd, info->num_event_cb);
info->num_event_cb++;
result = WIFI_SUCCESS;
}
pthread_mutex_unlock(&info->cb_lock);
return result;
}
void wifi_unregister_handler(wifi_handle handle, int cmd)
{
hal_info *info = (hal_info *)handle;
if (cmd == NL80211_CMD_VENDOR) {
ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
return;
}
pthread_mutex_lock(&info->cb_lock);
for (int i = 0; i < info->num_event_cb; i++) {
if (info->event_cb[i].nl_cmd == cmd) {
ALOGV("Successfully removed event handler %p:%p for cmd = 0x%0x from %d",
info->event_cb[i].cb_arg, info->event_cb[i].cb_func, cmd, i);
memmove(&info->event_cb[i], &info->event_cb[i+1],
(info->num_event_cb - i - 1) * sizeof(cb_info));
info->num_event_cb--;
break;
}
}
pthread_mutex_unlock(&info->cb_lock);
}
void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
{
hal_info *info = (hal_info *)handle;
pthread_mutex_lock(&info->cb_lock);
for (int i = 0; i < info->num_event_cb; i++) {
if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
&& info->event_cb[i].vendor_id == id
&& info->event_cb[i].vendor_subcmd == subcmd) {
ALOGV("Successfully removed event handler %p:%p for vendor 0x%0x, subcmd 0x%0x from %d",
info->event_cb[i].cb_arg, info->event_cb[i].cb_func, id, subcmd, i);
memmove(&info->event_cb[i], &info->event_cb[i+1],
(info->num_event_cb - i - 1) * sizeof(cb_info));
info->num_event_cb--;
break;
}
}
pthread_mutex_unlock(&info->cb_lock);
}
wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
{
hal_info *info = (hal_info *)handle;
ALOGV("registering command %d", id);
wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
if (info->num_cmd < info->alloc_cmd) {
info->cmd[info->num_cmd].id = id;
info->cmd[info->num_cmd].cmd = cmd;
ALOGV("Successfully added command %d: %p at %d", id, cmd, info->num_cmd);
info->num_cmd++;
result = WIFI_SUCCESS;
} else {
ALOGE("Failed to add command %d: %p at %d, reached max limit %d",
id, cmd, info->num_cmd, info->alloc_cmd);
}
return result;
}
WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
{
hal_info *info = (hal_info *)handle;
ALOGV("un-registering command %d", id);
WifiCommand *cmd = NULL;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].id == id) {
cmd = info->cmd[i].cmd;
memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
info->num_cmd--;
ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
break;
}
}
if (!cmd) {
ALOGI("Failed to remove command %d: %p", id, cmd);
}
return cmd;
}
WifiCommand *wifi_get_cmd(wifi_handle handle, int id)
{
hal_info *info = (hal_info *)handle;
WifiCommand *cmd = NULL;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].id == id) {
cmd = info->cmd[i].cmd;
break;
}
}
return cmd;
}
void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
{
hal_info *info = (hal_info *)handle;
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].cmd == cmd) {
int id = info->cmd[i].id;
memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i - 1) * sizeof(cmd_info));
info->num_cmd--;
ALOGV("Successfully removed command %d: %p from %d", id, cmd, i);
break;
}
}
}
wifi_error wifi_cancel_cmd(wifi_request_id id, wifi_interface_handle iface)
{
wifi_handle handle = getWifiHandle(iface);
WifiCommand *cmd = wifi_unregister_cmd(handle, id);
ALOGV("Cancel WifiCommand = %p", cmd);
if (cmd) {
cmd->cancel();
cmd->releaseRef();
return WIFI_SUCCESS;
}
return WIFI_ERROR_INVALID_ARGS;
}
+260
View File
@@ -0,0 +1,260 @@
#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 {
WIFI_SUBCMD_GET_CHANNEL_LIST = ANDROID_NL80211_SUBCMD_WIFI_RANGE_START,
WIFI_SUBCMD_GET_FEATURE_SET, /* 0x0002 */
WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x0003 */
WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x0004 */
WIFI_SUBCMD_NODFS_SET, /* 0x0005 */
WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x0006 */
WIFI_SUBCMD_SET_RSSI_MONITOR, /* 0x0007 */
/* Add more sub commands here */
} WIFI_SUB_COMMAND;
typedef enum {
GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */
GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */
GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */
GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */
GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */
GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */
GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */
GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */
GSCAN_SUBCMD_SET_EPNO_SSID = 0x100F, /* 0x100F */
GSCAN_SUBCMD_SET_SSID_WHITE_LIST, /* 0x1010 */
GSCAN_SUBCMD_SET_ROAM_PARAMS, /* 0x1011 */
GSCAN_SUBCMD_ENABLE_LAZY_ROAM, /* 0x1012 */
GSCAN_SUBCMD_SET_BSSID_PREF, /* 0x1013 */
GSCAN_SUBCMD_SET_BSSID_BLACKLIST, /* 0x1014 */
GSCAN_SUBCMD_ANQPO_CONFIG, /* 0x1015 */
/* Add more sub commands here */
} GSCAN_SUB_COMMAND;
typedef enum {
WIFI_ATTRIBUTE_BAND = 1,
WIFI_ATTRIBUTE_NUM_CHANNELS,
WIFI_ATTRIBUTE_CHANNEL_LIST,
WIFI_ATTRIBUTE_NUM_FEATURE_SET,
WIFI_ATTRIBUTE_FEATURE_SET,
WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
WIFI_ATTRIBUTE_NODFS_VALUE,
WIFI_ATTRIBUTE_COUNTRY_CODE,
WIFI_ATTRIBUTE_MAX_RSSI,
WIFI_ATTRIBUTE_MIN_RSSI,
WIFI_ATTRIBUTE_RSSI_MONITOR_START,
} WIFI_ATTRIBUTE;
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[8+1]; // interface name + trailing null
int id; // id to use when talking to driver
} interface_info;
typedef struct {
struct nl_sock *cmd_sock; // command socket object
struct nl_sock *event_sock; // event socket object
int nl80211_family_id; // family id for 80211 driver
int cleanup_socks[2]; // sockets used to implement wifi_cleanup
bool in_event_loop; // Indicates that event loop is active
bool clean_up; // Indication to exit since cleanup has started
wifi_internal_event_handler event_handler; // default event handler
wifi_cleaned_up_handler cleaned_up_handler; // socket cleaned up handler
cb_info *event_cb; // event callbacks
int num_event_cb; // number of event callbacks
int alloc_event_cb; // number of allocated callback objects
pthread_mutex_t cb_lock; // mutex for the event_cb access
cmd_info *cmd; // Outstanding commands
int num_cmd; // number of commands
int alloc_cmd; // number of commands allocated
interface_info **interfaces; // array of interfaces
int num_interfaces; // number of interfaces
// add other details
} hal_info;
#define PNO_SSID_FOUND 0x1
#define PNO_SSID_LOST 0x2
typedef struct wifi_pno_result {
unsigned char ssid[DOT11_MAX_SSID_LEN];
unsigned char ssid_len;
signed char rssi;
u16 channel;
u16 flags;
mac_addr bssid;
} wifi_pno_result_t;
typedef struct wifi_gscan_result {
u64 ts; // Time of discovery
u8 ssid[DOT11_MAX_SSID_LEN+1]; // null terminated
mac_addr bssid; // BSSID
u32 channel; // channel frequency in MHz
s32 rssi; // in db
u64 rtt; // in nanoseconds
u64 rtt_sd; // standard deviation in rtt
u16 beacon_period; // units are Kusec
u16 capability; // Capability information
u32 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))
#define NULL_CHECK_RETURN(ptr, str, ret) \
do { \
if (!(ptr)) { \
ALOGE("%s(): null pointer - #ptr (%s)\n", __FUNCTION__, str); \
return ret; \
} \
} while (0)
#endif
+739
View File
@@ -0,0 +1,739 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>
#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>
#include <ctype.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
void appendFmt(char *buf, int &offset, const char *fmt, ...)
{
va_list params;
va_start(params, fmt);
offset += vsprintf(buf + offset, fmt, params);
va_end(params);
}
#define C2S(x) case x: return #x;
static const char *cmdToString(int cmd)
{
switch (cmd) {
C2S(NL80211_CMD_UNSPEC)
C2S(NL80211_CMD_GET_WIPHY)
C2S(NL80211_CMD_SET_WIPHY)
C2S(NL80211_CMD_NEW_WIPHY)
C2S(NL80211_CMD_DEL_WIPHY)
C2S(NL80211_CMD_GET_INTERFACE)
C2S(NL80211_CMD_SET_INTERFACE)
C2S(NL80211_CMD_NEW_INTERFACE)
C2S(NL80211_CMD_DEL_INTERFACE)
C2S(NL80211_CMD_GET_KEY)
C2S(NL80211_CMD_SET_KEY)
C2S(NL80211_CMD_NEW_KEY)
C2S(NL80211_CMD_DEL_KEY)
C2S(NL80211_CMD_GET_BEACON)
C2S(NL80211_CMD_SET_BEACON)
C2S(NL80211_CMD_START_AP)
C2S(NL80211_CMD_STOP_AP)
C2S(NL80211_CMD_GET_STATION)
C2S(NL80211_CMD_SET_STATION)
C2S(NL80211_CMD_NEW_STATION)
C2S(NL80211_CMD_DEL_STATION)
C2S(NL80211_CMD_GET_MPATH)
C2S(NL80211_CMD_SET_MPATH)
C2S(NL80211_CMD_NEW_MPATH)
C2S(NL80211_CMD_DEL_MPATH)
C2S(NL80211_CMD_SET_BSS)
C2S(NL80211_CMD_SET_REG)
C2S(NL80211_CMD_REQ_SET_REG)
C2S(NL80211_CMD_GET_MESH_CONFIG)
C2S(NL80211_CMD_SET_MESH_CONFIG)
C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
C2S(NL80211_CMD_GET_REG)
C2S(NL80211_CMD_GET_SCAN)
C2S(NL80211_CMD_TRIGGER_SCAN)
C2S(NL80211_CMD_NEW_SCAN_RESULTS)
C2S(NL80211_CMD_SCAN_ABORTED)
C2S(NL80211_CMD_REG_CHANGE)
C2S(NL80211_CMD_AUTHENTICATE)
C2S(NL80211_CMD_ASSOCIATE)
C2S(NL80211_CMD_DEAUTHENTICATE)
C2S(NL80211_CMD_DISASSOCIATE)
C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
C2S(NL80211_CMD_REG_BEACON_HINT)
C2S(NL80211_CMD_JOIN_IBSS)
C2S(NL80211_CMD_LEAVE_IBSS)
C2S(NL80211_CMD_TESTMODE)
C2S(NL80211_CMD_CONNECT)
C2S(NL80211_CMD_ROAM)
C2S(NL80211_CMD_DISCONNECT)
C2S(NL80211_CMD_SET_WIPHY_NETNS)
C2S(NL80211_CMD_GET_SURVEY)
C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
C2S(NL80211_CMD_SET_PMKSA)
C2S(NL80211_CMD_DEL_PMKSA)
C2S(NL80211_CMD_FLUSH_PMKSA)
C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
C2S(NL80211_CMD_REGISTER_FRAME)
C2S(NL80211_CMD_FRAME)
C2S(NL80211_CMD_FRAME_TX_STATUS)
C2S(NL80211_CMD_SET_POWER_SAVE)
C2S(NL80211_CMD_GET_POWER_SAVE)
C2S(NL80211_CMD_SET_CQM)
C2S(NL80211_CMD_NOTIFY_CQM)
C2S(NL80211_CMD_SET_CHANNEL)
C2S(NL80211_CMD_SET_WDS_PEER)
C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
C2S(NL80211_CMD_JOIN_MESH)
C2S(NL80211_CMD_LEAVE_MESH)
C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
C2S(NL80211_CMD_GET_WOWLAN)
C2S(NL80211_CMD_SET_WOWLAN)
C2S(NL80211_CMD_START_SCHED_SCAN)
C2S(NL80211_CMD_STOP_SCHED_SCAN)
C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
C2S(NL80211_CMD_PMKSA_CANDIDATE)
C2S(NL80211_CMD_TDLS_OPER)
C2S(NL80211_CMD_TDLS_MGMT)
C2S(NL80211_CMD_UNEXPECTED_FRAME)
C2S(NL80211_CMD_PROBE_CLIENT)
C2S(NL80211_CMD_REGISTER_BEACONS)
C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
C2S(NL80211_CMD_SET_NOACK_MAP)
C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
C2S(NL80211_CMD_START_P2P_DEVICE)
C2S(NL80211_CMD_STOP_P2P_DEVICE)
C2S(NL80211_CMD_CONN_FAILED)
C2S(NL80211_CMD_SET_MCAST_RATE)
C2S(NL80211_CMD_SET_MAC_ACL)
C2S(NL80211_CMD_RADAR_DETECT)
C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
C2S(NL80211_CMD_UPDATE_FT_IES)
C2S(NL80211_CMD_FT_EVENT)
C2S(NL80211_CMD_CRIT_PROTOCOL_START)
C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
C2S(NL80211_CMD_GET_COALESCE)
C2S(NL80211_CMD_SET_COALESCE)
C2S(NL80211_CMD_CHANNEL_SWITCH)
C2S(NL80211_CMD_VENDOR)
C2S(NL80211_CMD_SET_QOS_MAP)
default:
return "NL80211_CMD_UNKNOWN";
}
}
const char *attributeToString(int attribute)
{
switch (attribute) {
C2S(NL80211_ATTR_UNSPEC)
C2S(NL80211_ATTR_WIPHY)
C2S(NL80211_ATTR_WIPHY_NAME)
C2S(NL80211_ATTR_IFINDEX)
C2S(NL80211_ATTR_IFNAME)
C2S(NL80211_ATTR_IFTYPE)
C2S(NL80211_ATTR_MAC)
C2S(NL80211_ATTR_KEY_DATA)
C2S(NL80211_ATTR_KEY_IDX)
C2S(NL80211_ATTR_KEY_CIPHER)
C2S(NL80211_ATTR_KEY_SEQ)
C2S(NL80211_ATTR_KEY_DEFAULT)
C2S(NL80211_ATTR_BEACON_INTERVAL)
C2S(NL80211_ATTR_DTIM_PERIOD)
C2S(NL80211_ATTR_BEACON_HEAD)
C2S(NL80211_ATTR_BEACON_TAIL)
C2S(NL80211_ATTR_STA_AID)
C2S(NL80211_ATTR_STA_FLAGS)
C2S(NL80211_ATTR_STA_LISTEN_INTERVAL)
C2S(NL80211_ATTR_STA_SUPPORTED_RATES)
C2S(NL80211_ATTR_STA_VLAN)
C2S(NL80211_ATTR_STA_INFO)
C2S(NL80211_ATTR_WIPHY_BANDS)
C2S(NL80211_ATTR_MNTR_FLAGS)
C2S(NL80211_ATTR_MESH_ID)
C2S(NL80211_ATTR_STA_PLINK_ACTION)
C2S(NL80211_ATTR_MPATH_NEXT_HOP)
C2S(NL80211_ATTR_MPATH_INFO)
C2S(NL80211_ATTR_BSS_CTS_PROT)
C2S(NL80211_ATTR_BSS_SHORT_PREAMBLE)
C2S(NL80211_ATTR_BSS_SHORT_SLOT_TIME)
C2S(NL80211_ATTR_HT_CAPABILITY)
C2S(NL80211_ATTR_SUPPORTED_IFTYPES)
C2S(NL80211_ATTR_REG_ALPHA2)
C2S(NL80211_ATTR_REG_RULES)
C2S(NL80211_ATTR_MESH_CONFIG)
C2S(NL80211_ATTR_BSS_BASIC_RATES)
C2S(NL80211_ATTR_WIPHY_TXQ_PARAMS)
C2S(NL80211_ATTR_WIPHY_FREQ)
C2S(NL80211_ATTR_WIPHY_CHANNEL_TYPE)
C2S(NL80211_ATTR_KEY_DEFAULT_MGMT)
C2S(NL80211_ATTR_MGMT_SUBTYPE)
C2S(NL80211_ATTR_IE)
C2S(NL80211_ATTR_MAX_NUM_SCAN_SSIDS)
C2S(NL80211_ATTR_SCAN_FREQUENCIES)
C2S(NL80211_ATTR_SCAN_SSIDS)
C2S(NL80211_ATTR_GENERATION) /* replaces old SCAN_GENERATION */
C2S(NL80211_ATTR_BSS)
C2S(NL80211_ATTR_REG_INITIATOR)
C2S(NL80211_ATTR_REG_TYPE)
C2S(NL80211_ATTR_SUPPORTED_COMMANDS)
C2S(NL80211_ATTR_FRAME)
C2S(NL80211_ATTR_SSID)
C2S(NL80211_ATTR_AUTH_TYPE)
C2S(NL80211_ATTR_REASON_CODE)
C2S(NL80211_ATTR_KEY_TYPE)
C2S(NL80211_ATTR_MAX_SCAN_IE_LEN)
C2S(NL80211_ATTR_CIPHER_SUITES)
C2S(NL80211_ATTR_FREQ_BEFORE)
C2S(NL80211_ATTR_FREQ_AFTER)
C2S(NL80211_ATTR_FREQ_FIXED)
C2S(NL80211_ATTR_WIPHY_RETRY_SHORT)
C2S(NL80211_ATTR_WIPHY_RETRY_LONG)
C2S(NL80211_ATTR_WIPHY_FRAG_THRESHOLD)
C2S(NL80211_ATTR_WIPHY_RTS_THRESHOLD)
C2S(NL80211_ATTR_TIMED_OUT)
C2S(NL80211_ATTR_USE_MFP)
C2S(NL80211_ATTR_STA_FLAGS2)
C2S(NL80211_ATTR_CONTROL_PORT)
C2S(NL80211_ATTR_TESTDATA)
C2S(NL80211_ATTR_PRIVACY)
C2S(NL80211_ATTR_DISCONNECTED_BY_AP)
C2S(NL80211_ATTR_STATUS_CODE)
C2S(NL80211_ATTR_CIPHER_SUITES_PAIRWISE)
C2S(NL80211_ATTR_CIPHER_SUITE_GROUP)
C2S(NL80211_ATTR_WPA_VERSIONS)
C2S(NL80211_ATTR_AKM_SUITES)
C2S(NL80211_ATTR_REQ_IE)
C2S(NL80211_ATTR_RESP_IE)
C2S(NL80211_ATTR_PREV_BSSID)
C2S(NL80211_ATTR_KEY)
C2S(NL80211_ATTR_KEYS)
C2S(NL80211_ATTR_PID)
C2S(NL80211_ATTR_4ADDR)
C2S(NL80211_ATTR_SURVEY_INFO)
C2S(NL80211_ATTR_PMKID)
C2S(NL80211_ATTR_MAX_NUM_PMKIDS)
C2S(NL80211_ATTR_DURATION)
C2S(NL80211_ATTR_COOKIE)
C2S(NL80211_ATTR_WIPHY_COVERAGE_CLASS)
C2S(NL80211_ATTR_TX_RATES)
C2S(NL80211_ATTR_FRAME_MATCH)
C2S(NL80211_ATTR_ACK)
C2S(NL80211_ATTR_PS_STATE)
C2S(NL80211_ATTR_CQM)
C2S(NL80211_ATTR_LOCAL_STATE_CHANGE)
C2S(NL80211_ATTR_AP_ISOLATE)
C2S(NL80211_ATTR_WIPHY_TX_POWER_SETTING)
C2S(NL80211_ATTR_WIPHY_TX_POWER_LEVEL)
C2S(NL80211_ATTR_TX_FRAME_TYPES)
C2S(NL80211_ATTR_RX_FRAME_TYPES)
C2S(NL80211_ATTR_FRAME_TYPE)
C2S(NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
C2S(NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)
C2S(NL80211_ATTR_SUPPORT_IBSS_RSN)
C2S(NL80211_ATTR_WIPHY_ANTENNA_TX)
C2S(NL80211_ATTR_WIPHY_ANTENNA_RX)
C2S(NL80211_ATTR_MCAST_RATE)
C2S(NL80211_ATTR_OFFCHANNEL_TX_OK)
C2S(NL80211_ATTR_BSS_HT_OPMODE)
C2S(NL80211_ATTR_KEY_DEFAULT_TYPES)
C2S(NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION)
C2S(NL80211_ATTR_MESH_SETUP)
C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX)
C2S(NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX)
C2S(NL80211_ATTR_SUPPORT_MESH_AUTH)
C2S(NL80211_ATTR_STA_PLINK_STATE)
C2S(NL80211_ATTR_WOWLAN_TRIGGERS)
C2S(NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED)
C2S(NL80211_ATTR_SCHED_SCAN_INTERVAL)
C2S(NL80211_ATTR_INTERFACE_COMBINATIONS)
C2S(NL80211_ATTR_SOFTWARE_IFTYPES)
C2S(NL80211_ATTR_REKEY_DATA)
C2S(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS)
C2S(NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN)
C2S(NL80211_ATTR_SCAN_SUPP_RATES)
C2S(NL80211_ATTR_HIDDEN_SSID)
C2S(NL80211_ATTR_IE_PROBE_RESP)
C2S(NL80211_ATTR_IE_ASSOC_RESP)
C2S(NL80211_ATTR_STA_WME)
C2S(NL80211_ATTR_SUPPORT_AP_UAPSD)
C2S(NL80211_ATTR_ROAM_SUPPORT)
C2S(NL80211_ATTR_SCHED_SCAN_MATCH)
C2S(NL80211_ATTR_MAX_MATCH_SETS)
C2S(NL80211_ATTR_PMKSA_CANDIDATE)
C2S(NL80211_ATTR_TX_NO_CCK_RATE)
C2S(NL80211_ATTR_TDLS_ACTION)
C2S(NL80211_ATTR_TDLS_DIALOG_TOKEN)
C2S(NL80211_ATTR_TDLS_OPERATION)
C2S(NL80211_ATTR_TDLS_SUPPORT)
C2S(NL80211_ATTR_TDLS_EXTERNAL_SETUP)
C2S(NL80211_ATTR_DEVICE_AP_SME)
C2S(NL80211_ATTR_DONT_WAIT_FOR_ACK)
C2S(NL80211_ATTR_FEATURE_FLAGS)
C2S(NL80211_ATTR_PROBE_RESP_OFFLOAD)
C2S(NL80211_ATTR_PROBE_RESP)
C2S(NL80211_ATTR_DFS_REGION)
C2S(NL80211_ATTR_DISABLE_HT)
C2S(NL80211_ATTR_HT_CAPABILITY_MASK)
C2S(NL80211_ATTR_NOACK_MAP)
C2S(NL80211_ATTR_INACTIVITY_TIMEOUT)
C2S(NL80211_ATTR_RX_SIGNAL_DBM)
C2S(NL80211_ATTR_BG_SCAN_PERIOD)
C2S(NL80211_ATTR_WDEV)
C2S(NL80211_ATTR_USER_REG_HINT_TYPE)
C2S(NL80211_ATTR_CONN_FAILED_REASON)
C2S(NL80211_ATTR_SAE_DATA)
C2S(NL80211_ATTR_VHT_CAPABILITY)
C2S(NL80211_ATTR_SCAN_FLAGS)
C2S(NL80211_ATTR_CHANNEL_WIDTH)
C2S(NL80211_ATTR_CENTER_FREQ1)
C2S(NL80211_ATTR_CENTER_FREQ2)
C2S(NL80211_ATTR_P2P_CTWINDOW)
C2S(NL80211_ATTR_P2P_OPPPS)
C2S(NL80211_ATTR_LOCAL_MESH_POWER_MODE)
C2S(NL80211_ATTR_ACL_POLICY)
C2S(NL80211_ATTR_MAC_ADDRS)
C2S(NL80211_ATTR_MAC_ACL_MAX)
C2S(NL80211_ATTR_RADAR_EVENT)
C2S(NL80211_ATTR_EXT_CAPA)
C2S(NL80211_ATTR_EXT_CAPA_MASK)
C2S(NL80211_ATTR_STA_CAPABILITY)
C2S(NL80211_ATTR_STA_EXT_CAPABILITY)
C2S(NL80211_ATTR_PROTOCOL_FEATURES)
C2S(NL80211_ATTR_SPLIT_WIPHY_DUMP)
C2S(NL80211_ATTR_DISABLE_VHT)
C2S(NL80211_ATTR_VHT_CAPABILITY_MASK)
C2S(NL80211_ATTR_MDID)
C2S(NL80211_ATTR_IE_RIC)
C2S(NL80211_ATTR_CRIT_PROT_ID)
C2S(NL80211_ATTR_MAX_CRIT_PROT_DURATION)
C2S(NL80211_ATTR_PEER_AID)
C2S(NL80211_ATTR_COALESCE_RULE)
C2S(NL80211_ATTR_CH_SWITCH_COUNT)
C2S(NL80211_ATTR_CH_SWITCH_BLOCK_TX)
C2S(NL80211_ATTR_CSA_IES)
C2S(NL80211_ATTR_CSA_C_OFF_BEACON)
C2S(NL80211_ATTR_CSA_C_OFF_PRESP)
C2S(NL80211_ATTR_RXMGMT_FLAGS)
C2S(NL80211_ATTR_STA_SUPPORTED_CHANNELS)
C2S(NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES)
C2S(NL80211_ATTR_HANDLE_DFS)
C2S(NL80211_ATTR_SUPPORT_5_MHZ)
C2S(NL80211_ATTR_SUPPORT_10_MHZ)
C2S(NL80211_ATTR_OPMODE_NOTIF)
C2S(NL80211_ATTR_VENDOR_ID)
C2S(NL80211_ATTR_VENDOR_SUBCMD)
C2S(NL80211_ATTR_VENDOR_DATA)
C2S(NL80211_ATTR_VENDOR_EVENTS)
C2S(NL80211_ATTR_QOS_MAP)
default:
return "NL80211_ATTR_UNKNOWN";
}
}
void WifiEvent::log() {
parse();
byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
int len = genlmsg_attrlen(mHeader, 0);
ALOGD("cmd = %s, len = %d", get_cmdString(), len);
ALOGD("vendor_id = %04x, vendor_subcmd = %d", get_vendor_id(), get_vendor_subcmd());
for (int i = 0; i < len; i += 16) {
char line[81];
int linelen = min(16, len - i);
int offset = 0;
appendFmt(line, offset, "%02x", data[i]);
for (int j = 1; j < linelen; j++) {
appendFmt(line, offset, " %02x", data[i+j]);
}
for (int j = linelen; j < 16; j++) {
appendFmt(line, offset, " ");
}
line[23] = '-';
appendFmt(line, offset, " ");
for (int j = 0; j < linelen; j++) {
if (isprint(data[i+j])) {
appendFmt(line, offset, "%c", data[i+j]);
} else {
appendFmt(line, offset, "-");
}
}
ALOGD("%s", line);
}
for (unsigned i = 0; i < NL80211_ATTR_MAX_INTERNAL; i++) {
if (mAttributes[i] != NULL) {
ALOGD("found attribute %s", attributeToString(i));
}
}
ALOGD("-- End of message --");
}
const char *WifiEvent::get_cmdString() {
return cmdToString(get_cmd());
}
int WifiEvent::parse() {
if (mHeader != NULL) {
return WIFI_SUCCESS;
}
mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
genlmsg_attrlen(mHeader, 0), NULL);
// ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
return result;
}
int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
destroy();
mMsg = nlmsg_alloc();
if (mMsg != NULL) {
genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
hdrlen, flags, cmd, /* version = */ 0);
return WIFI_SUCCESS;
} else {
return WIFI_ERROR_OUT_OF_MEMORY;
}
}
int WifiRequest::create(uint32_t id, int subcmd) {
int res = create(NL80211_CMD_VENDOR);
if (res < 0) {
return res;
}
res = put_u32(NL80211_ATTR_VENDOR_ID, id);
if (res < 0) {
return res;
}
res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
if (res < 0) {
return res;
}
if (mIface != -1) {
res = set_iface_id(mIface);
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;
ALOGD("WifiCommand::requestEvent waiting for response %d", cmd);
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;
}
/* Other event handlers */
int WifiCommand::valid_handler(struct nl_msg *msg, void *arg) {
// ALOGD("valid_handler called");
int *err = (int *)arg;
*err = 0;
return NL_SKIP;
}
int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
// ALOGD("ack_handler called");
int *err = (int *)arg;
*err = 0;
return NL_STOP;
}
int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
// ALOGD("finish_handler called");
int *ret = (int *)arg;
*ret = 0;
return NL_SKIP;
}
int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
int *ret = (int *)arg;
*ret = err->error;
// ALOGD("error_handler received : %d", err->error);
return NL_SKIP;
}
+352
View File
@@ -0,0 +1,352 @@
#include "wifi_hal.h"
#include "common.h"
#include "sync.h"
class WifiEvent
{
/* TODO: remove this when nl headers are updated */
static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
private:
struct nl_msg *mMsg;
struct genlmsghdr *mHeader;
struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
public:
WifiEvent(nl_msg *msg) {
mMsg = msg;
mHeader = NULL;
memset(mAttributes, 0, sizeof(mAttributes));
}
~WifiEvent() {
/* don't destroy mMsg; it doesn't belong to us */
}
void log();
int parse();
genlmsghdr *header() {
return mHeader;
}
int get_cmd() {
return mHeader->cmd;
}
int get_vendor_id() {
return get_u32(NL80211_ATTR_VENDOR_ID);
}
int get_vendor_subcmd() {
return get_u32(NL80211_ATTR_VENDOR_SUBCMD);
}
void *get_vendor_data() {
return get_data(NL80211_ATTR_VENDOR_DATA);
}
int get_vendor_data_len() {
return get_len(NL80211_ATTR_VENDOR_DATA);
}
const char *get_cmdString();
nlattr ** attributes() {
return mAttributes;
}
nlattr *get_attribute(int attribute) {
return mAttributes[attribute];
}
uint8_t get_u8(int attribute) {
return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0;
}
uint16_t get_u16(int attribute) {
return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0;
}
uint32_t get_u32(int attribute) {
return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0;
}
uint64_t get_u64(int attribute) {
return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0;
}
int get_len(int attribute) {
return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0;
}
void *get_data(int attribute) {
return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL;
}
private:
WifiEvent(const WifiEvent&); // hide copy constructor to prevent copies
};
class nl_iterator {
struct nlattr *pos;
int rem;
public:
nl_iterator(struct nlattr *attr) {
pos = (struct nlattr *)nla_data(attr);
rem = nla_len(attr);
}
bool has_next() {
return nla_ok(pos, rem);
}
void next() {
pos = (struct nlattr *)nla_next(pos, &(rem));
}
struct nlattr *get() {
return pos;
}
uint16_t get_type() {
return pos->nla_type;
}
uint8_t get_u8() {
return nla_get_u8(pos);
}
uint16_t get_u16() {
return nla_get_u16(pos);
}
uint32_t get_u32() {
return nla_get_u32(pos);
}
uint64_t get_u64() {
return nla_get_u64(pos);
}
void* get_data() {
return nla_data(pos);
}
int get_len() {
return nla_len(pos);
}
private:
nl_iterator(const nl_iterator&); // hide copy constructor to prevent copies
};
class WifiRequest
{
private:
int mFamily;
int mIface;
struct nl_msg *mMsg;
public:
WifiRequest(int family) {
mMsg = NULL;
mFamily = family;
mIface = -1;
}
WifiRequest(int family, int iface) {
mMsg = NULL;
mFamily = family;
mIface = iface;
}
~WifiRequest() {
destroy();
}
void destroy() {
if (mMsg) {
nlmsg_free(mMsg);
mMsg = NULL;
}
}
nl_msg *getMessage() {
return mMsg;
}
/* Command assembly helpers */
int create(int family, uint8_t cmd, int flags, int hdrlen);
int create(uint8_t cmd) {
return create(mFamily, cmd, 0, 0);
}
int create(uint32_t id, int subcmd);
int put(int attribute, void *ptr, unsigned len) {
return nla_put(mMsg, attribute, len, ptr);
}
int put_u8(int attribute, uint8_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u16(int attribute, uint16_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u32(int attribute, uint32_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_u64(int attribute, uint64_t value) {
return nla_put(mMsg, attribute, sizeof(value), &value);
}
int put_string(int attribute, const char *value) {
return nla_put(mMsg, attribute, strlen(value) + 1, value);
}
int put_addr(int attribute, mac_addr value) {
return nla_put(mMsg, attribute, sizeof(mac_addr), value);
}
struct nlattr * attr_start(int attribute) {
return nla_nest_start(mMsg, attribute);
}
void attr_end(struct nlattr *attr) {
nla_nest_end(mMsg, attr);
}
int set_iface_id(int ifindex) {
return put_u32(NL80211_ATTR_IFINDEX, ifindex);
}
private:
WifiRequest(const WifiRequest&); // hide copy constructor to prevent copies
};
class WifiCommand
{
protected:
const char *mType;
hal_info *mInfo;
WifiRequest mMsg;
Condition mCondition;
wifi_request_id mId;
interface_info *mIfaceInfo;
int mRefs;
public:
WifiCommand(const char *type, wifi_handle handle, wifi_request_id id)
: mType(type), mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1)
{
mIfaceInfo = NULL;
mInfo = getHalInfo(handle);
// ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo);
}
WifiCommand(const char *type, wifi_interface_handle iface, wifi_request_id id)
: mType(type), mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id),
mId(id), mRefs(1)
{
mIfaceInfo = getIfaceInfo(iface);
mInfo = getHalInfo(iface);
// ALOGD("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;
}
const char *getType() {
return mType;
}
virtual void addRef() {
int refs = __sync_add_and_fetch(&mRefs, 1);
// ALOGD("addRef: WifiCommand %p has %d references", this, refs);
}
virtual void releaseRef() {
int refs = __sync_sub_and_fetch(&mRefs, 1);
if (refs == 0) {
delete this;
} else {
// ALOGD("releaseRef: WifiCommand %p has %d references", this, refs);
}
}
virtual int create() {
/* by default there is no way to cancel */
ALOGD("WifiCommand %p can't be created", this);
return WIFI_ERROR_NOT_SUPPORTED;
}
virtual int cancel() {
/* by default there is no way to cancel */
return WIFI_ERROR_NOT_SUPPORTED;
}
int requestResponse();
int requestEvent(int cmd);
int requestVendorEvent(uint32_t id, int subcmd);
int requestResponse(WifiRequest& request);
protected:
wifi_handle wifiHandle() {
return getWifiHandle(mInfo);
}
wifi_interface_handle ifaceHandle() {
return getIfaceHandle(mIfaceInfo);
}
int familyId() {
return mInfo->nl80211_family_id;
}
int ifaceId() {
return mIfaceInfo->id;
}
/* Override this method to parse reply and dig out data; save it in the object */
virtual int handleResponse(WifiEvent& reply) {
ALOGI("skipping a response");
return NL_SKIP;
}
/* Override this method to parse event and dig out data; save it in the object */
virtual int handleEvent(WifiEvent& event) {
ALOGI("skipping an event");
return NL_SKIP;
}
int registerHandler(int cmd) {
return wifi_register_handler(wifiHandle(), cmd, &event_handler, this);
}
void unregisterHandler(int cmd) {
wifi_unregister_handler(wifiHandle(), cmd);
}
int registerVendorHandler(uint32_t id, int subcmd) {
return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this);
}
void unregisterVendorHandler(uint32_t id, int subcmd) {
wifi_unregister_vendor_handler(wifiHandle(), id, subcmd);
}
private:
WifiCommand(const WifiCommand& ); // hide copy constructor to prevent copies
/* Event handling */
static int response_handler(struct nl_msg *msg, void *arg);
static int event_handler(struct nl_msg *msg, void *arg);
/* Other event handlers */
static int valid_handler(struct nl_msg *msg, void *arg);
static int ack_handler(struct nl_msg *msg, void *arg);
static int finish_handler(struct nl_msg *msg, void *arg);
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
};
/* nl message processing macros (required to pass C++ type checks) */
#define for_each_attr(pos, nla, rem) \
for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
nla_ok(pos, rem); \
pos = (nlattr *)nla_next(pos, &(rem)))
+1881
View File
File diff suppressed because it is too large Load Diff
+697
View File
@@ -0,0 +1,697 @@
#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 "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("GetRttCapabilitiesCommand", 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 GetRttResponderInfoCommand : public WifiCommand
{
wifi_rtt_responder* mResponderInfo;
public:
GetRttResponderInfoCommand(wifi_interface_handle iface, wifi_rtt_responder *responderInfo)
: WifiCommand("GetRttResponderInfoCommand", iface, 0), mResponderInfo(responderInfo)
{
memset(mResponderInfo, 0 , sizeof(*mResponderInfo));
}
virtual int create() {
ALOGD("Creating message to get responder info ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETAVAILCHANNEL);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In GetRttResponderInfoCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
sizeof(*mResponderInfo));
memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
return NL_OK;
}
};
class EnableResponderCommand : public WifiCommand
{
wifi_channel_info mChannelInfo;
unsigned m_max_duration_sec;
wifi_rtt_responder* mResponderInfo;
public:
EnableResponderCommand(wifi_interface_handle iface, int id, wifi_channel_info channel_hint,
unsigned max_duration_seconds, wifi_rtt_responder *responderInfo)
: WifiCommand("EnableResponderCommand", iface, 0), mChannelInfo(channel_hint),
m_max_duration_sec(max_duration_seconds), mResponderInfo(responderInfo)
{
memset(mResponderInfo, 0, sizeof(*mResponderInfo));
}
virtual int create() {
ALOGD("Creating message to set responder ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_SET_RESPONDER);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In EnableResponderCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
int id = reply.get_vendor_id();
int subcmd = reply.get_vendor_subcmd();
void *data = reply.get_vendor_data();
int len = reply.get_vendor_data_len();
ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
sizeof(*mResponderInfo));
memcpy(mResponderInfo, data, min(len, (int) sizeof(*mResponderInfo)));
return NL_OK;
}
};
class CancelResponderCommand : public WifiCommand
{
public:
CancelResponderCommand(wifi_interface_handle iface, int id)
: WifiCommand("CancelResponderCommand", iface, 0)/*, mChannelInfo(channel)*/
{
}
virtual int create() {
ALOGD("Creating message to cancel responder ; iface = %d", mIfaceInfo->id);
int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_RESPONDER);
if (ret < 0) {
return ret;
}
return ret;
}
protected:
virtual int handleResponse(WifiEvent& reply) {
/* Nothing to do on response! */
return NL_SKIP;
}
};
class RttCommand : public WifiCommand
{
unsigned numRttParams;
int mCompleted;
int currentIdx;
int totalCnt;
static const int MAX_RESULTS = 1024;
wifi_rtt_result *rttResults[MAX_RESULTS];
wifi_rtt_config *rttParams;
wifi_rtt_event_handler rttHandler;
public:
RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config,
wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
: WifiCommand("RttCommand", iface, id), numRttParams(num_rtt_config), rttParams(rtt_config),
rttHandler(handler)
{
memset(rttResults, 0, sizeof(rttResults));
currentIdx = 0;
mCompleted = 0;
totalCnt = 0;
}
RttCommand(wifi_interface_handle iface, int id)
: WifiCommand("RttCommand", iface, id)
{
currentIdx = 0;
mCompleted = 0;
totalCnt = 0;
numRttParams = 0;
}
int createSetupRequest(WifiRequest& request) {
int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG);
if (result < 0) {
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams);
if (result < 0) {
return result;
}
nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO);
for (unsigned i = 0; i < numRttParams; i++) {
nlattr *attr2 = request.attr_start(i);
if (attr2 == NULL) {
return WIFI_ERROR_OUT_OF_MEMORY;
}
result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer);
if (result < 0) {
return result;
}
result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel,
sizeof(wifi_channel_info));
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_BURST, rttParams[i].num_burst);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
rttParams[i].num_frames_per_burst);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
rttParams[i].num_retries_per_rtt_frame);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
rttParams[i].num_retries_per_ftmr);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_PERIOD,
rttParams[i].burst_period);
if (result < 0) {
return result;
}
result = request.put_u32(RTT_ATTRIBUTE_TARGET_BURST_DURATION,
rttParams[i].burst_duration);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCI,
rttParams[i].LCI_request);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_LCR,
rttParams[i].LCR_request);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_BW,
rttParams[i].bw);
if (result < 0) {
return result;
}
result = request.put_u8(RTT_ATTRIBUTE_TARGET_PREAMBLE,
rttParams[i].preamble);
if (result < 0) {
return result;
}
request.attr_end(attr2);
}
request.attr_end(rtt_config);
request.attr_end(data);
return WIFI_SUCCESS;
}
int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) {
int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG);
if (result < 0) {
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices);
for(unsigned i = 0; i < num_devices; i++) {
result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]);
if (result < 0) {
return result;
}
}
request.attr_end(data);
return result;
}
int start() {
ALOGD("Setting RTT configuration");
WifiRequest request(familyId(), ifaceId());
int result = createSetupRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create setup request; result = %d", result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to configure RTT setup; result = %d", result);
return result;
}
registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
ALOGI("Successfully started RTT operation");
return result;
}
virtual int cancel() {
ALOGD("Stopping RTT");
WifiRequest request(familyId(), ifaceId());
int result = createTeardownRequest(request, 0, NULL);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create stop request; result = %d", result);
} else {
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to stop scan; result = %d", result);
}
}
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
return WIFI_SUCCESS;
}
int cancel_specific(unsigned num_devices, mac_addr addr[]) {
ALOGE("Stopping RTT");
WifiRequest request(familyId(), ifaceId());
int result = createTeardownRequest(request, num_devices, addr);
if (result != WIFI_SUCCESS) {
ALOGE("failed to create stop request; result = %d", result);
} else {
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("failed to stop RTT; result = %d", result);
}
}
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
return WIFI_SUCCESS;
}
virtual int handleResponse(WifiEvent& reply) {
/* Nothing to do on response! */
return NL_SKIP;
}
virtual int handleEvent(WifiEvent& event) {
ALOGI("Got an RTT event");
nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
int len = event.get_vendor_data_len();
if (vendor_data == NULL || len == 0) {
ALOGI("No rtt results found");
}
for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
if (it.get_type() == RTT_ATTRIBUTE_RESULTS_COMPLETE) {
mCompleted = it.get_u32();
ALOGI("retrieved completed flag : %d\n", mCompleted);
} else if (it.get_type() == RTT_ATTRIBUTE_RESULTS_PER_TARGET) {
int result_cnt = 0;
mac_addr bssid;
for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
if (it2.get_type() == RTT_ATTRIBUTE_TARGET_MAC) {
memcpy(bssid, it2.get_data(), sizeof(mac_addr));
ALOGI("retrived target mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
bssid[0],
bssid[1],
bssid[2],
bssid[3],
bssid[4],
bssid[5]);
} else if (it2.get_type() == RTT_ATTRIBUTE_RESULT_CNT) {
result_cnt = it2.get_u32();
ALOGI("retrieved result_cnt : %d\n", result_cnt);
} else if (it2.get_type() == RTT_ATTRIBUTE_RESULT) {
int result_len = it2.get_len();
rttResults[currentIdx] = (wifi_rtt_result *)malloc(it2.get_len());
wifi_rtt_result *rtt_result = rttResults[currentIdx];
if (rtt_result == NULL) {
mCompleted = 1;
ALOGE("failed to allocate the wifi_rtt_result\n");
break;
}
memcpy(rtt_result, it2.get_data(), it2.get_len());
result_len -= sizeof(wifi_rtt_result);
if (result_len > 0) {
result_len -= sizeof(wifi_rtt_result);
dot11_rm_ie_t *ele_1;
dot11_rm_ie_t *ele_2;
/* The result has LCI or LCR element */
ele_1 = (dot11_rm_ie_t *)(rtt_result + 1);
if (ele_1->id == DOT11_MNG_MEASURE_REQUEST_ID) {
if (ele_1->type == DOT11_MEASURE_TYPE_LCI) {
rtt_result->LCI = (wifi_information_element *)ele_1;
result_len -= (ele_1->len + DOT11_HDR_LEN);
/* get a next rm ie */
if (result_len > 0) {
ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
(ele_2->type == DOT11_MEASURE_TYPE_CIVICLOC)) {
rtt_result->LCR = (wifi_information_element *)ele_2;
}
}
} else if (ele_1->type == DOT11_MEASURE_TYPE_CIVICLOC){
rtt_result->LCR = (wifi_information_element *)ele_1;
result_len -= (ele_1->len + DOT11_HDR_LEN);
/* get a next rm ie */
if (result_len > 0) {
ele_2 = (dot11_rm_ie_t *)((char *)ele_1 + (ele_1->len + DOT11_HDR_LEN));
if ((ele_2->id == DOT11_MNG_MEASURE_REQUEST_ID) &&
(ele_2->type == DOT11_MEASURE_TYPE_LCI)) {
rtt_result->LCI = (wifi_information_element *)ele_2;
}
}
}
}
}
totalCnt++;
ALOGI("retrived rtt_result : \n\tburst_num :%d, measurement_number : %d, success_number : %d\n"
"\tnumber_per_burst_peer : %d, status : %s, retry_after_duration : %d s\n"
"\trssi : %d dbm, rx_rate : %d Kbps, rtt : %llu ns, rtt_sd : %llu\n"
"\tdistance : %d, burst_duration : %d ms, negotiated_burst_num : %d\n",
rtt_result->burst_num, rtt_result->measurement_number,
rtt_result->success_number, rtt_result->number_per_burst_peer,
get_err_info(rtt_result->status), rtt_result->retry_after_duration,
rtt_result->rssi, rtt_result->rx_rate.bitrate * 100,
rtt_result->rtt/10, rtt_result->rtt_sd, rtt_result->distance_mm / 10,
rtt_result->burst_duration, rtt_result->negotiated_burst_num);
currentIdx++;
}
}
}
}
if (mCompleted) {
unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE);
(*rttHandler.on_rtt_results)(id(), totalCnt, rttResults);
for (int i = 0; i < currentIdx; i++) {
free(rttResults[i]);
rttResults[i] = NULL;
}
totalCnt = currentIdx = 0;
WifiCommand *cmd = wifi_unregister_cmd(wifiHandle(), id());
if (cmd)
cmd->releaseRef();
}
return NL_SKIP;
}
};
/* API to request RTT measurement */
wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler)
{
wifi_handle handle = getWifiHandle(iface);
RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = wifi_register_cmd(handle, id, cmd);
if (result != WIFI_SUCCESS) {
cmd->releaseRef();
return result;
}
result = (wifi_error)cmd->start();
if (result != WIFI_SUCCESS) {
wifi_unregister_cmd(handle, id);
cmd->releaseRef();
return result;
}
return result;
}
/* API to cancel RTT measurements */
wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
unsigned num_devices, mac_addr addr[])
{
wifi_handle handle = getWifiHandle(iface);
RttCommand *cmd = new RttCommand(iface, id);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
cmd->cancel_specific(num_devices, addr);
cmd->releaseRef();
return WIFI_SUCCESS;
}
/* API to get RTT capability */
wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
wifi_rtt_capabilities *capabilities)
{
GetRttCapabilitiesCommand command(iface, capabilities);
return (wifi_error) command.requestResponse();
}
/* API to get the responder information */
wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
wifi_rtt_responder* responderInfo)
{
GetRttResponderInfoCommand command(iface, responderInfo);
return (wifi_error) command.requestResponse();
}
/**
* Enable RTT responder mode.
* channel_hint - hint of the channel information where RTT responder should be enabled on.
* max_duration_seconds - timeout of responder mode.
* wifi_rtt_responder - information for RTT responder e.g. channel used and preamble supported.
*/
wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
wifi_channel_info channel_hint, unsigned max_duration_seconds,
wifi_rtt_responder* responderInfo)
{
EnableResponderCommand command(iface, id, channel_hint, max_duration_seconds, responderInfo);
return (wifi_error) command.requestResponse();
}
/**
* Disable RTT responder mode.
*/
wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface)
{
CancelResponderCommand command(iface, id);
return (wifi_error) command.requestResponse();
}
+54
View File
@@ -0,0 +1,54 @@
#include <pthread.h>
#ifndef __WIFI_HAL_SYNC_H__
#define __WIFI_HAL_SYNC_H__
class Mutex
{
private:
pthread_mutex_t mMutex;
public:
Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
~Mutex() {
pthread_mutex_destroy(&mMutex);
}
int tryLock() {
return pthread_mutex_trylock(&mMutex);
}
int lock() {
return pthread_mutex_lock(&mMutex);
}
void unlock() {
pthread_mutex_unlock(&mMutex);
}
};
class Condition
{
private:
pthread_cond_t mCondition;
pthread_mutex_t mMutex;
public:
Condition() {
pthread_mutex_init(&mMutex, NULL);
pthread_cond_init(&mCondition, NULL);
}
~Condition() {
pthread_cond_destroy(&mCondition);
pthread_mutex_destroy(&mMutex);
}
int wait() {
return pthread_cond_wait(&mCondition, &mMutex);
}
void signal() {
pthread_cond_signal(&mCondition);
}
};
#endif
File diff suppressed because it is too large Load Diff
+230
View File
@@ -0,0 +1,230 @@
#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 "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("MKeepAliveCommand", iface, 0), mIndex(index), mIpPkt(ip_packet),
mIpPktLen(ip_packet_len), mSrcMacAddr(src_mac_addr), mDstMacAddr(dst_mac_addr),
mPeriodMsec(period_msec), mType(cmdType)
{ }
// constructor for stop sending
MKeepAliveCommand(wifi_interface_handle iface, u8 index, GetCmdType cmdType)
: WifiCommand("MKeepAliveCommand", iface, 0), mIndex(index), mType(cmdType)
{ }
int createRequest(WifiRequest &request) {
int result;
switch (mType) {
case START_MKEEP_ALIVE:
{
result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_START_MKEEP_ALIVE);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create start keep alive request; result = %d", result);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
if (result < 0) {
ALOGE("Failed to put id request; result = %d", result);
return result;
}
result = request.put_u16(MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, mIpPktLen);
if (result < 0) {
ALOGE("Failed to put ip pkt len request; result = %d", result);
return result;
}
result = request.put(MKEEP_ALIVE_ATTRIBUTE_IP_PKT, (u8*)mIpPkt, mIpPktLen);
if (result < 0) {
ALOGE("Failed to put ip pkt request; result = %d", result);
return result;
}
result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, mSrcMacAddr);
if (result < 0) {
ALOGE("Failed to put src mac address request; result = %d", result);
return result;
}
result = request.put_addr(MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, mDstMacAddr);
if (result < 0) {
ALOGE("Failed to put dst mac address request; result = %d", result);
return result;
}
result = request.put_u32(MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, mPeriodMsec);
if (result < 0) {
ALOGE("Failed to put period request; result = %d", result);
return result;
}
request.attr_end(data);
break;
}
case STOP_MKEEP_ALIVE:
{
result = request.create(GOOGLE_OUI, WIFI_OFFLOAD_STOP_MKEEP_ALIVE);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create stop keep alive request; result = %d", result);
return result;
}
nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
result = request.put_u8(MKEEP_ALIVE_ATTRIBUTE_ID, mIndex);
if (result < 0) {
ALOGE("Failed to put id request; result = %d", result);
return result;
}
request.attr_end(data);
break;
}
default:
ALOGE("Unknown wifi keep alive command");
result = WIFI_ERROR_UNKNOWN;
}
return result;
}
int start() {
ALOGD("Start mkeep_alive command");
WifiRequest request(familyId(), ifaceId());
int result = createRequest(request);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to create keep alive request; result = %d", result);
return result;
}
result = requestResponse(request);
if (result != WIFI_SUCCESS) {
ALOGE("Failed to register keep alive response; result = %d", result);
}
return result;
}
virtual int handleResponse(WifiEvent& reply) {
ALOGD("In MKeepAliveCommand::handleResponse");
if (reply.get_cmd() != NL80211_CMD_VENDOR) {
ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
return NL_SKIP;
}
switch (mType) {
case START_MKEEP_ALIVE:
case STOP_MKEEP_ALIVE:
break;
default:
ALOGW("Unknown mkeep_alive command");
}
return NL_OK;
}
virtual int handleEvent(WifiEvent& event) {
/* NO events! */
return NL_SKIP;
}
};
/* API to send specified mkeep_alive packet periodically. */
wifi_error wifi_start_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface,
u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec)
{
if ((index > 0 && index <= N_AVAIL_ID) && (ip_packet != NULL) && (src_mac_addr != NULL)
&& (dst_mac_addr != NULL) && (period_msec > 0)
&& (ip_packet_len <= MKEEP_ALIVE_IP_PKT_MAX)) {
MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, ip_packet, ip_packet_len,
src_mac_addr, dst_mac_addr, period_msec, START_MKEEP_ALIVE);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = (wifi_error)cmd->start();
cmd->releaseRef();
return result;
} else {
ALOGE("Invalid mkeep_alive parameters");
return WIFI_ERROR_INVALID_ARGS;
}
}
/* API to stop sending mkeep_alive packet. */
wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id index, wifi_interface_handle iface)
{
if (index > 0 && index <= N_AVAIL_ID) {
MKeepAliveCommand *cmd = new MKeepAliveCommand(iface, index, STOP_MKEEP_ALIVE);
NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
wifi_error result = (wifi_error)cmd->start();
cmd->releaseRef();
return result;
} else {
ALOGE("Invalid mkeep_alive parameters");
return WIFI_ERROR_INVALID_ARGS;
}
}