* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
* 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.
*/
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/pkt_sched.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/attr.h>
#include <netlink/handlers.h>
#include <netlink/msg.h>
#include <dirent.h>
#include <net/if.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "wifi_hal.h"
#include "cpp_bindings.h"
#include "common.h"
#include <hdf_log.h>
#include "securec.h"
#include "gscan.h"
#include "wifi_ioctl.h"
#include "wifi_scan.h"
#include "v2_0/ichip_iface.h"
constexpr int32_t WIFI_HAL_CMD_SOCK_PORT = 644;
constexpr int32_t WIFI_HAL_EVENT_SOCK_PORT = 645;
constexpr int32_t MAX_VIRTUAL_IFACES = 5;
constexpr int32_t WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE = 105;
constexpr int32_t EVENT_BUF_SIZE = 2048;
constexpr int32_t POLL_DRIVER_DURATION_US = 100000;
constexpr int32_t POLL_DRIVER_MAX_TIME_MS = 10000;
constexpr int32_t SIZE_BATE = 256;
constexpr int32_t SIZE_1K = 1024;
constexpr int32_t NUM_4 = 4;
constexpr int32_t DEFAULT_OFFSET = 22;
constexpr int32_t CALLOC_MAX_VALUE = 10;
constexpr int32_t OFFSET_8 = 8;
constexpr int32_t OFFSET_16 = 16;
constexpr int32_t OFFSET_24 = 24;
constexpr int32_t MASK_CSMA = 0xFF;
static std::mutex g_callbackMutex;
static int WifiGetMulticastId(wifiHandle handle, const char *name, const char *group);
static int wifiAddMemberShip(wifiHandle handle, const char *group);
static WifiError WifiInitInterfaces(wifiHandle handle);
static int GetInterface(const char *name, InterfaceInfo *info);
static bool IsWifiInterface(const char *name);
static void WifiCleanupDynamicIfaces(wifiHandle handle);
static void InternalCleanedUpHandler(wifiHandle handle);
static int InternalPollinHandler(wifiHandle handle);
static WifiError WifiSetCountryCode(wifiInterfaceHandle handle, const char *country_code);
static WifiError WifiGetSignalInfo(wifiInterfaceHandle handle,
OHOS::HDI::Wlan::Chip::V2_0::SignalPollResult& signalPollresult);
static WifiError RegisterIfaceCallBack(const char *ifaceName,
WifiCallbackHandler OnCallbackEvent);
static WifiError VendorHalCreateIface(wifiHandle handle, const char* ifname,
HalIfaceType ifaceType);
static WifiError VendorHalDeleteIface(wifiHandle handle, const char* ifname);
static void CheckWhetherAddIface(wifiHandle handle, const char* ifname);
WifiError IsSupportCoex(bool& isCoex);
static WifiError SendCmdToDriver(const char *ifaceName, int32_t commandId,
const std::vector<int8_t>& paramData, std::vector<int8_t>& result);
static WifiError SendP2pCmdToDriver(wifiInterfaceHandle handle, const char *interfaceName, int32_t commandId,
const std::vector<int8_t> ¶mData, std::vector<int8_t> &result);
typedef enum WifiAttr {
HAL_INVALID = 0,
HAL_FEATURE_SET_NUM = 1,
HAL_FEATURE_SET = 2,
HAL_PNO_RANDOM_MAC_OUI = 3,
HAL_NODFS_SET = 4,
HAL_COUNTRY = 5,
HAL_ND_OFFLOAD_VALUE = 6,
HAL_TCPACK_SUP_VALUE = 7,
HAL_LATENCY_MODE = 8,
HAL_RANDOM_MAC = 9,
HAL_TX_POWER_SCENARIO = 10,
HAL_THERMAL_MITIGATION = 11,
HAL_THERMAL_COMPLETION_WINDOW = 12,
HAL_VOIP_MODE = 13,
HAL_DTIM_MULTIPLIER = 14,
HAL_MAX
} WifiAttrT;
#define NET_FILE_PATH "/sys/class/net/wlan0"
#define NL80211_SCAN_CMD(cmd) ((cmd) == NL80211_CMD_NEW_SCAN_RESULTS || (cmd) == NL80211_CMD_SCHED_SCAN_RESULTS || \
(cmd) == NL80211_CMD_SCAN_ABORTED)
static const int RSV_MAX_SIZE = 3;
typedef struct {
int index;
int c0Rssi;
int c1Rssi;
int rsv[RSV_MAX_SIZE];
} RssiReportStru;
HalInfo *g_halInfo = nullptr;
static void WifiPreDeinitialize(void)
{
HDF_LOGI("wifi_pre_uninitialize enter");
if (g_halInfo->cmdSock != nullptr) {
close(g_halInfo->cleanupSocks[0]);
close(g_halInfo->cleanupSocks[1]);
nl_socket_free(g_halInfo->cmdSock);
nl_socket_free(g_halInfo->eventSock);
g_halInfo->cmdSock = nullptr;
g_halInfo->eventSock = nullptr;
}
pthread_mutex_destroy(&g_halInfo->cbLock);
DestroyResponseLock();
free(g_halInfo);
g_halInfo = nullptr;
}
WifiError InitWifiVendorHalFuncTable(WifiHalFn *fn)
{
if (fn == NULL) {
return HAL_UNKNOWN;
}
fn->vendorHalInit = VendorHalInit;
fn->waitDriverStart = WaitDriverStart;
fn->vendorHalExit = VendorHalExit;
fn->startHalLoop = StartHalLoop;
fn->vendorHalGetIfaces = VendorHalGetIfaces;
fn->vendorHalGetIfName = VendorHalGetIfName;
fn->vendorHalGetChannelsInBand = VendorHalGetChannelsInBand;
fn->vendorHalSetRestartHandler = VendorHalSetRestartHandler;
fn->vendorHalCreateIface = VendorHalCreateIface;
fn->vendorHalDeleteIface = VendorHalDeleteIface;
fn->triggerVendorHalRestart = TriggerVendorHalRestart;
fn->wifiSetCountryCode = WifiSetCountryCode;
fn->getSignalPollInfo = WifiGetSignalInfo;
fn->wifiStartScan = WifiStartScan;
fn->registerIfaceCallBack = RegisterIfaceCallBack;
fn->getScanResults = WifiGetScanInfo;
fn->wifiStartPnoScan = WifiStartPnoScan;
fn->wifiStopPnoScan = WifiStopPnoScan;
fn->wifiGetSupportedFeatureSet = WifiGetSupportedFeatureSet;
fn->getChipCaps = GetChipCaps;
fn->isSupportCoex = IsSupportCoex;
fn->sendCmdToDriver = SendCmdToDriver;
fn->sendP2pCmdToDriver = SendP2pCmdToDriver;
return HAL_SUCCESS;
}
static void WifiSocketSetLocalPort(struct nl_sock *sock, uint32_t port)
{
constexpr int32_t num = DEFAULT_OFFSET;
uint32_t pid = static_cast<uint32_t>(getpid()) & 0x3FFFFF;
nl_socket_set_local_port(sock, pid + (port << num));
}
static nl_sock* WifiCreateNlSocket(int port)
{
struct nl_sock *sock = nl_socket_alloc();
if (sock == nullptr) {
HDF_LOGE("Could not create handle");
return nullptr;
}
WifiSocketSetLocalPort(sock, port);
if (nl_connect(sock, NETLINK_GENERIC)) {
HDF_LOGE("Could not connect handle");
nl_socket_free(sock);
return nullptr;
}
return sock;
}
static int ReportEventCallback(int cmd, WifiEvent &event)
{
std::unique_lock<std::mutex> lock(g_callbackMutex);
if (NL80211_SCAN_CMD(cmd)) {
if (g_halInfo->ifaceCallBack.onScanEvent != nullptr) {
g_halInfo->ifaceCallBack.onScanEvent(cmd);
return NL_OK;
}
}
return NL_SKIP;
}
static int InternalNoSeqCheck(struct nl_msg *msg, void *arg)
{
return NL_OK;
}
static int InternalValidMessageHandler(nl_msg *msg, void *arg)
{
HalInfo *info = GetHalInfo((wifiHandle)arg);
WifiEvent event(msg);
int res = event.Parse();
if (res < 0 || info == nullptr) {
HDF_LOGE("Failed to Parse event: %{public}d", res);
return NL_SKIP;
}
int cmd = event.GetCmd();
uint32_t vendorId = 0;
int subcmd = 0;
if (cmd == NL80211_CMD_VENDOR) {
vendorId = event.GetU32(NL80211_ATTR_VENDOR_ID);
subcmd = static_cast<int>(event.GetU32(NL80211_ATTR_VENDOR_SUBCMD));
HDF_LOGD("event receive %{public}d, vendorId = 0x%{public}0x, subcmd = 0x%{public}0x", cmd, vendorId, subcmd);
}
if (ReportEventCallback(cmd, event) == NL_OK) {
return NL_OK;
}
pthread_mutex_lock(&info->cbLock);
for (int i = 0; i < info->numEventCb; i++) {
if (cmd == info->eventCb[i].nlCmd) {
if (cmd == NL80211_CMD_VENDOR && ((vendorId != info->eventCb[i].vendorId) ||
(subcmd != info->eventCb[i].vendorSubcmd))) {
continue;
}
CbInfo *cbi = &(info->eventCb[i]);
nl_recvmsg_msg_cb_t cbFunc = cbi->cbFunc;
WifiCommand *wifiCommand = (WifiCommand *)cbi->cbArg;
if (wifiCommand != nullptr) {
wifiCommand->AddRef();
}
pthread_mutex_unlock(&info->cbLock);
if (cbFunc) {
(*cbFunc)(msg, cbi->cbArg);
}
if (wifiCommand != nullptr) {
wifiCommand->ReleaseRef();
}
return NL_OK;
}
}
pthread_mutex_unlock(&info->cbLock);
return NL_OK;
}
static int wifiAddMemberShip(wifiHandle handle, const char *group)
{
HalInfo *info = GetHalInfo(handle);
int id = WifiGetMulticastId(handle, "nl80211", group);
if (id < 0 || info == nullptr) {
HDF_LOGE("Could not find group %{public}s", group);
return id;
}
int ret = nl_socket_add_membership(info->eventSock, id);
if (ret < 0) {
HDF_LOGE("Could not add membership to group %{public}s", group);
}
return ret;
}
static WifiError GetInterfaceNum(int* n)
{
int cnt = 0;
DIR *d = opendir("/sys/class/net");
if (d == nullptr) {
return HAL_UNKNOWN;
}
struct dirent *de;
while ((de = readdir(d))) {
if (de->d_name[0] == '.') {
continue;
}
if (IsWifiInterface(de->d_name)) {
cnt++;
}
}
closedir(d);
*n = cnt;
return HAL_SUCCESS;
}
static void RelaseHalInfoSpace(HalInfo *info)
{
if (info == nullptr || info->interfaces == nullptr || info->numInterfaces == 0) {
return;
}
int i = 0;
while (i < info->numInterfaces) {
free(info->interfaces[i]);
i++;
}
free(info->interfaces);
info->interfaces = nullptr;
info->numInterfaces = 0;
}
static WifiError WifiInitInterfacesSplitting(wifiHandle handle, HalInfo *info, DIR *d, int &i, int &n)
{
struct dirent *de;
while ((de = readdir(d)) && i < n) {
if (de->d_name[0] == '.') {
continue;
}
if (IsWifiInterface(de->d_name)) {
InterfaceInfo *ifinfo = (InterfaceInfo *)malloc(sizeof(InterfaceInfo));
if (ifinfo == nullptr) {
return HAL_OUT_OF_MEMORY;
}
if (memset_s(ifinfo, sizeof(InterfaceInfo), 0, sizeof(InterfaceInfo)) != EOK ||
GetInterface(de->d_name, ifinfo) != HAL_SUCCESS) {
free(ifinfo);
return HAL_OUT_OF_MEMORY;
}
ifinfo->isVirtual = false;
ifinfo->handle = handle;
info->interfaces[i] = ifinfo;
i++;
}
}
return HAL_SUCCESS;
}
static WifiError WifiInitInterfaces(wifiHandle handle)
{
HalInfo *info = (HalInfo *)handle;
int n = 0;
WifiError ret = GetInterfaceNum(&n);
if (ret == HAL_UNKNOWN) {
return HAL_UNKNOWN;
}
if (n == 0) {
return HAL_NOT_AVAILABLE;
}
DIR *d = opendir("/sys/class/net");
if (d == nullptr) {
return HAL_UNKNOWN;
}
n += MAX_VIRTUAL_IFACES;
if (n > CALLOC_MAX_VALUE) {
closedir(d);
return HAL_OUT_OF_MEMORY;
}
info->interfaces = (InterfaceInfo **)calloc(n, sizeof(InterfaceInfo *) * n);
if (!info->interfaces) {
RelaseHalInfoSpace(info);
closedir(d);
return HAL_OUT_OF_MEMORY;
}
int i = 0;
if (WifiInitInterfacesSplitting(handle, info, d, i, n) != HAL_SUCCESS) {
RelaseHalInfoSpace(info);
closedir(d);
return HAL_OUT_OF_MEMORY;
}
closedir(d);
info->numInterfaces = i;
info->maxNumInterfaces = n;
return HAL_SUCCESS;
}
class GetMulticastIdCommand : public WifiCommand {
public:
GetMulticastIdCommand(wifiHandle handle, const char *name, const char *group)
: WifiCommand("GetMulticastIdCommand", handle, 0)
{
mName = name;
mGroup = group;
mId = -1;
}
int GetId()
{
return mId;
}
int Create() override
{
int nlctrlFamily = genl_ctrl_resolve(mInfo->cmdSock, "nlctrl");
int ret = mMsg.Create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
if (ret < 0) {
return ret;
}
ret = mMsg.PutString(CTRL_ATTR_FAMILY_NAME, mName);
return ret;
}
int HandleResponse(WifiEvent& reply) override
{
struct nlattr **tb = reply.Attributes();
struct nlattr *mcgrp = nullptr;
int i;
if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
HDF_LOGI("No multicast groups found");
return NL_SKIP;
}
FOR_EACH_ATTR(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
nla_len(mcgrp), NULL);
if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
continue;
}
char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
if (strncmp(grpName, mGroup, grpNameLen) != 0) {
continue;
}
mId = static_cast<int32_t>(nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]));
break;
}
return NL_SKIP;
}
private:
const char *mName;
const char *mGroup;
int mId;
};
static int WifiGetMulticastId(wifiHandle handle, const char *name, const char *group)
{
GetMulticastIdCommand cmd(handle, name, group);
auto lock = ReadLockData();
int res = cmd.RequestResponse();
if (res < 0) {
return res;
} else {
return cmd.GetId();
}
}
static bool IsWifiInterface(const char *name)
{
constexpr int32_t NUM_3 = 3;
constexpr int32_t NUM_5 = 5;
if (strncmp(name, "wlan", NUM_4) != 0 && strncmp(name, "swlan", NUM_5) != 0 &&
strncmp(name, "p2p", NUM_3) != 0 && strncmp(name, "aware", NUM_5) != 0 &&
strncmp(name, "nan", NUM_3) != 0) {
return false;
} else {
return true;
}
}
static int GetInterface(const char *name, InterfaceInfo *info)
{
unsigned int size = 0;
size = strlcpy(info->name, name, sizeof(info->name));
if (size >= sizeof(info->name)) {
return HAL_OUT_OF_MEMORY;
}
info->id = static_cast<int>(if_nametoindex(name));
return HAL_SUCCESS;
}
wifiInterfaceHandle WifiGetWlanInterface(wifiHandle info, wifiInterfaceHandle *ifaceHandles, int numIfaceHandles)
{
constexpr int32_t NUM_5 = 5;
char buf[EVENT_BUF_SIZE];
wifiInterfaceHandle wlan0Handle;
WifiError res = VendorHalGetIfaces((wifiHandle)info, &numIfaceHandles, &ifaceHandles);
if (res < 0) {
return NULL;
}
for (int i = 0; i < numIfaceHandles; i++) {
if (VendorHalGetIfName(ifaceHandles[i], buf, sizeof(buf)) == HAL_SUCCESS) {
if (strncmp(buf, "wlan0", NUM_5) == 0) {
HDF_LOGI("found interface %{public}s\n", buf);
wlan0Handle = ifaceHandles[i];
return wlan0Handle;
}
}
}
return NULL;
}
static void PreInitFail(bool needCloseSock, struct nl_sock *eventSock,
struct nl_sock *cmdSock, bool needClearLock, bool needClearcb)
{
if (needCloseSock) {
close(g_halInfo->cleanupSocks[0]);
close(g_halInfo->cleanupSocks[1]);
}
if (cmdSock != nullptr) {
nl_socket_free(cmdSock);
}
if (eventSock != nullptr) {
nl_socket_free(eventSock);
}
if (needClearLock) {
pthread_mutex_destroy(&g_halInfo->cbLock);
DestroyResponseLock();
}
if (needClearcb) {
if (g_halInfo->eventCb != nullptr) {
free(g_halInfo->eventCb);
g_halInfo->eventCb = nullptr;
}
if (g_halInfo->cmd != nullptr) {
free(g_halInfo->cmd);
g_halInfo->cmd = nullptr;
}
}
if (g_halInfo != nullptr) {
free(g_halInfo);
g_halInfo = nullptr;
}
}
static bool SetHalInfo(struct nl_sock *eventSock, struct nl_sock *cmdSock)
{
struct nl_cb *cb = nl_socket_get_cb(eventSock);
if (cb == nullptr) {
HDF_LOGE("Could not create handle");
return false;
}
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, InternalNoSeqCheck, g_halInfo);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, InternalValidMessageHandler, g_halInfo);
nl_cb_put(cb);
g_halInfo->cmdSock = cmdSock;
g_halInfo->eventSock = eventSock;
g_halInfo->cleanUp = false;
g_halInfo->inEventLoop = false;
g_halInfo->eventCb = reinterpret_cast<CbInfo *>(malloc(sizeof(CbInfo) * DEFAULT_EVENT_CB_SIZE));
if (g_halInfo->eventCb == nullptr) {
return false;
}
g_halInfo->allocEventCb = DEFAULT_EVENT_CB_SIZE;
g_halInfo->numEventCb = 0;
g_halInfo->cmd = reinterpret_cast<CmdInfo *>(malloc(sizeof(CmdInfo) * DEFAULT_CMD_SIZE));
if (g_halInfo->cmd == nullptr) {
free(g_halInfo->eventCb);
g_halInfo->eventCb = nullptr;
return false;
}
g_halInfo->allocCmd = DEFAULT_CMD_SIZE;
g_halInfo->numCmd = 0;
g_halInfo->nl80211FamilyId = genl_ctrl_resolve(cmdSock, "nl80211");
if (g_halInfo->nl80211FamilyId < 0) {
HDF_LOGE("Could not resolve nl80211 familty id");
free(g_halInfo->eventCb);
g_halInfo->eventCb = nullptr;
free(g_halInfo->cmd);
g_halInfo->cmd = nullptr;
return false;
}
return true;
}
static struct nl_sock *InitCmdSock()
{
struct nl_sock *cmdSock = WifiCreateNlSocket(WIFI_HAL_CMD_SOCK_PORT);
if (cmdSock == nullptr) {
HDF_LOGE("cmd sock create failed");
return nullptr;
}
if (nl_socket_set_buffer_size(cmdSock, (SIZE_BATE * SIZE_1K), 0) < 0) {
HDF_LOGE("Could not set size for cmdSock: %{public}s", strerror(errno));
}
return cmdSock;
}
static struct nl_sock *InitEventSock()
{
struct nl_sock *eventSock = WifiCreateNlSocket(WIFI_HAL_EVENT_SOCK_PORT);
if (eventSock == nullptr) {
HDF_LOGE("event sock create failed");
return nullptr;
}
if (nl_socket_set_buffer_size(eventSock, (NUM_4 * SIZE_1K * SIZE_1K), 0) < 0) {
HDF_LOGE("Could not set size for eventSock: %{public}s", strerror(errno));
}
return eventSock;
}
static bool InitHalInfo()
{
g_halInfo = reinterpret_cast<HalInfo *>(malloc(sizeof(HalInfo)));
if (g_halInfo == nullptr) {
HDF_LOGE("Could not allocate HalInfo");
return false;
}
if (memset_s(g_halInfo, sizeof(*g_halInfo), 0, sizeof(*g_halInfo)) != EOK) {
HDF_LOGE("memset HalInfo failed");
free(g_halInfo);
g_halInfo = nullptr;
return false;
}
return true;
}
static WifiError WifiPreInitialize(void)
{
wifiHandle handle;
HDF_LOGI("WifiPreInitialize");
if (g_halInfo != nullptr) {
WifiPreDeinitialize();
}
if (!InitHalInfo()) {
return HAL_UNKNOWN;
}
HDF_LOGI("Creating socket");
if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_halInfo->cleanupSocks) == -1) {
HDF_LOGE("Could not create cleanup sockets");
PreInitFail(false, nullptr, nullptr, false, false);
return HAL_UNKNOWN;
}
struct nl_sock *cmdSock = InitCmdSock();
if (cmdSock == nullptr) {
PreInitFail(true, nullptr, nullptr, false, false);
return HAL_UNKNOWN;
}
struct nl_sock *eventSock = InitEventSock();
if (eventSock == nullptr) {
PreInitFail(true, nullptr, cmdSock, false, false);
return HAL_UNKNOWN;
}
if (!SetHalInfo(eventSock, cmdSock)) {
PreInitFail(true, eventSock, cmdSock, false, false);
return HAL_UNKNOWN;
}
pthread_mutex_init(&g_halInfo->cbLock, nullptr);
InitResponseLock();
handle = (wifiHandle) g_halInfo;
if (WifiInitInterfaces(handle) != HAL_SUCCESS) {
HDF_LOGE("No wifi interface found");
PreInitFail(true, eventSock, cmdSock, true, true);
return HAL_NOT_AVAILABLE;
}
if ((wifiAddMemberShip(handle, "scan") < 0) || (wifiAddMemberShip(handle, "mlme") < 0) ||
(wifiAddMemberShip(handle, "regulatory") < 0) || (wifiAddMemberShip(handle, "vendor") < 0)) {
HDF_LOGE("Add membership failed");
PreInitFail(true, eventSock, cmdSock, true, true);
return HAL_NOT_AVAILABLE;
}
HDF_LOGI("Initialized Wifi HAL Successfully; vendor cmd = %{public}d", NL80211_CMD_VENDOR);
return HAL_SUCCESS;
}
WifiError VendorHalInit(wifiHandle *handle)
{
WifiError result = HAL_SUCCESS;
HDF_LOGI("WifiInitialize");
if (g_halInfo == nullptr) {
result = WifiPreInitialize();
if (result != HAL_SUCCESS) {
HDF_LOGE("WifiInitialize WifiPreInitialize failed");
return result;
} else {
HDF_LOGE("WifiInitialize WifiPreInitialize succeeded");
}
}
*handle = (wifiHandle) g_halInfo;
return HAL_SUCCESS;
}
WifiError WaitDriverStart(void)
{
#ifdef SUPPORT_EMULATOR
return HAL_SUCCESS;
#endif
int count = (POLL_DRIVER_MAX_TIME_MS * 1000) / POLL_DRIVER_DURATION_US;
FILE *fd;
do {
if ((fd = fopen(NET_FILE_PATH, "r")) != nullptr) {
fclose(fd);
WifiPreInitialize();
return HAL_SUCCESS;
}
usleep(POLL_DRIVER_DURATION_US);
} while (--count > 0);
HDF_LOGE("Timed out waiting on Driver ready ... ");
return HAL_TIMED_OUT;
}
static std::vector<std::string> added_ifaces;
static void WifiCleanupDynamicIfaces(wifiHandle handle)
{
unsigned int len = added_ifaces.size();
HDF_LOGI("%{public}s: virtual iface size %{public}d\n", __FUNCTION__, len);
while (len--) {
VendorHalDeleteIface(handle, added_ifaces.front().c_str());
HDF_LOGI("%{public}s: deleted virtual iface %{public}s\n",
__FUNCTION__, added_ifaces.front().c_str());
}
added_ifaces.clear();
}
static void VendorHalExitSplitting(wifiHandle handle, HalInfo *info)
{
pthread_mutex_lock(&info->cbLock);
int badCommands = 0;
HDF_LOGI("eventCb callbacks left: %{public}d ", info->numEventCb);
for (int i = 0; i < info->numEventCb; i++) {
HDF_LOGI("eventCb cleanup. index:%{public}d", i);
CbInfo *cbi = &(info->eventCb[i]);
if (!cbi) {
HDF_LOGE("cbi null for index %{public}d", i);
continue;
}
HDF_LOGI("eventCb cleanup. vendor cmd:%{public}d sub_cmd:%{public}d", cbi->vendorId, cbi->vendorSubcmd);
WifiCommand *cmd = (WifiCommand *)cbi->cbArg;
if (cmd != nullptr) {
HDF_LOGI("Command left in eventCb");
}
}
HDF_LOGI("Check bad commands: numCmd:%{public}d badCommands:%{public}d", info->numCmd, badCommands);
while (info->numCmd > badCommands) {
int numCmd = info->numCmd;
CmdInfo *cmdi = &(info->cmd[badCommands]);
WifiCommand *cmd = cmdi->cmd;
if (cmd != nullptr) {
HDF_LOGI("Cancelling command:%{public}s", cmd->GetType());
pthread_mutex_unlock(&info->cbLock);
cmd->Cancel();
pthread_mutex_lock(&info->cbLock);
if (numCmd == info->numCmd) {
HDF_LOGI("Cancelling command:%{public}s did not work", (cmd ? cmd->GetType() : ""));
badCommands++;
}
cmd->ReleaseRef();
}
}
for (int i = 0; i < info->numEventCb; i++) {
CbInfo *cbi = &(info->eventCb[i]);
if (!cbi) {
HDF_LOGE("cbi null for index %{public}d", i);
continue;
}
}
if (!GetGHalutilMode()) {
WifiCleanupDynamicIfaces(handle);
}
pthread_mutex_unlock(&info->cbLock);
}
void VendorHalExit(wifiHandle handle, VendorHalExitHandler handler)
{
if (!handle) {
HDF_LOGE("Handle is null");
return;
}
HalInfo *info = GetHalInfo(handle);
int numIfaceHandles = 0;
wifiInterfaceHandle *ifaceHandles = NULL;
wifiInterfaceHandle wlan0Handle;
info->CleanedUpHandler = handler;
auto lock = WriteLock();
wlan0Handle = WifiGetWlanInterface((wifiHandle) info, ifaceHandles, numIfaceHandles);
if (wlan0Handle != NULL) {
HDF_LOGE("Calling hal cleanup");
if (!GetGHalutilMode()) {
WifiCleanupDynamicIfaces(handle);
HDF_LOGI("Cleaned dynamic virtual ifaces\n");
HDF_LOGI("wifi_stop_hal success");
}
} else {
HDF_LOGE("Not cleaning up hal as global_iface is NULL");
}
VendorHalExitSplitting(handle, info);
info->cleanUp = true;
if (TEMP_FAILURE_RETRY(write(info->cleanupSocks[0], "Exit", NUM_4)) < 1) {
HDF_LOGE("could not write to the cleanup socket");
}
HDF_LOGE("wifi_cleanUp done");
}
static void InternalCleanedUpHandler(wifiHandle handle)
{
auto lock = WriteLock();
HalInfo *info = GetHalInfo(handle);
if (info == nullptr) {
HDF_LOGE("InternalCleanedUpHandler: info is null");
return;
}
VendorHalExitHandler cleanedUpHandler = info->CleanedUpHandler;
HDF_LOGI("internal clean up");
if (info->cmdSock != nullptr) {
HDF_LOGI("cmdSock non null. clean up");
close(info->cleanupSocks[0]);
close(info->cleanupSocks[1]);
nl_socket_free(info->cmdSock);
nl_socket_free(info->eventSock);
info->cmdSock = nullptr;
info->eventSock = nullptr;
}
if (cleanedUpHandler) {
HDF_LOGI("cleanup_handler cb");
(*cleanedUpHandler)(handle);
} else {
HDF_LOGE("!! clean up handler is null!!");
}
DestroyResponseLock();
pthread_mutex_destroy(&info->cbLock);
free(info);
g_halInfo = nullptr;
HDF_LOGI("Internal cleanup completed");
}
static int InternalPollinHandler(wifiHandle handle)
{
HalInfo *info = GetHalInfo(handle);
if (info == nullptr) {
HDF_LOGE("InternalPollinHandler: info is nullptr");
return -1;
}
struct nl_cb *cb = nl_socket_get_cb(info->eventSock);
int res = nl_recvmsgs(info->eventSock, cb);
HDF_LOGD("nl_recvmsgs returned %{public}d", res);
nl_cb_put(cb);
return res;
}
void StartHalLoop(wifiHandle handle)
{
constexpr int32_t NUM_2 = 2;
HalInfo *info = GetHalInfo(handle);
if (info == nullptr || info->eventSock == nullptr || info->inEventLoop) {
return;
} else {
info->inEventLoop = true;
}
pollfd pfd[2];
if (memset_s(&pfd[0], sizeof(pollfd) * NUM_2, 0, sizeof(pollfd) * NUM_2) != EOK) {
return;
}
pfd[0].fd = nl_socket_get_fd(info->eventSock);
pfd[0].events = POLLIN;
pfd[1].fd = info->cleanupSocks[1];
pfd[1].events = POLLIN;
char buf[2048];
do {
int timeout = -1;
pfd[0].revents = 0;
pfd[1].revents = 0;
int result = TEMP_FAILURE_RETRY(poll(pfd, NUM_2, timeout));
if (result < 0) {
HDF_LOGE("Error polling socket");
} else if (static_cast<uint32_t>(pfd[0].revents) & POLLERR) {
HDF_LOGE("POLL Error; error no = %{public}d (%{public}s)", errno, strerror(errno));
ssize_t result2 = TEMP_FAILURE_RETRY(read(pfd[0].fd, buf, sizeof(buf)));
HDF_LOGE("Read after POLL returned %zd, error no = %{public}d (%{public}s)", result2,
errno, strerror(errno));
if (errno == WIFI_HAL_EVENT_BUFFER_NOT_AVAILABLE) {
HDF_LOGE("Exit, No buffer space");
break;
}
} else if (static_cast<uint32_t>(pfd[0].revents) & POLLHUP) {
HDF_LOGE("Remote side hung up");
break;
} else if ((static_cast<uint32_t>(pfd[0].revents) & (POLLIN)) && (!info->cleanUp)) {
InternalPollinHandler(handle);
} else if (static_cast<uint32_t>(pfd[1].revents) & POLLIN) {
HDF_LOGI("Got a Signal to exit!!!");
} else {
HDF_LOGE("Unknown event - %{public}0x, %{public}0x", pfd[0].revents, pfd[1].revents);
}
} while (!info->cleanUp);
InternalCleanedUpHandler(handle);
HDF_LOGE("Exit %{public}s", __FUNCTION__);
}
class VirtualIfaceConfig : public WifiCommand {
const char *mIfname;
nl80211_iftype mType;
uint32_t mwlan0Id;
public:
VirtualIfaceConfig(wifiInterfaceHandle handle, const char* ifname, nl80211_iftype ifaceType, uint32_t wlan0Id)
: WifiCommand("VirtualIfaceConfig", handle, 0), mIfname(ifname), mType(ifaceType), mwlan0Id(wlan0Id)
{
mIfname = ifname;
mType = ifaceType;
mwlan0Id = wlan0Id;
}
int CreateRequest(WifiRequest& request, const char* ifname,
nl80211_iftype ifaceType, uint32_t wlan0Id)
{
HDF_LOGD("add ifname = %{public}s, ifaceType = %{public}d, wlan0Id = %{public}d",
ifname, ifaceType, wlan0Id);
int result = request.Create(NL80211_CMD_NEW_INTERFACE);
if (result < 0) {
HDF_LOGE("failed to create NL80211_CMD_NEW_INTERFACE; result = %{public}d", result);
return result;
}
result = request.PutU32(NL80211_ATTR_IFINDEX, wlan0Id);
if (result < 0) {
HDF_LOGE("failed to put NL80211_ATTR_IFINDEX; result = %{public}d", result);
return result;
}
result = request.PutString(NL80211_ATTR_IFNAME, ifname);
if (result < 0) {
HDF_LOGE("failed to put NL80211_ATTR_IFNAME = %{public}s; result = %{public}d", ifname, result);
return result;
}
result = request.PutU32(NL80211_ATTR_IFTYPE, ifaceType);
if (result < 0) {
HDF_LOGE("failed to put NL80211_ATTR_IFTYPE = %{public}d; result = %{public}d", ifaceType, result);
return result;
}
return HAL_SUCCESS;
}
int DeleteRequest(WifiRequest& request, const char* ifname)
{
HDF_LOGD("delete ifname = %{public}s\n", ifname);
int result = request.Create(NL80211_CMD_DEL_INTERFACE);
if (result < 0) {
HDF_LOGE("failed to create NL80211_CMD_DEL_INTERFACE; result = %{public}d", result);
return result;
}
result = request.PutU32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
if (result < 0) {
HDF_LOGE("failed to put NL80211_ATTR_IFINDEX = %{public}d; result = %{public}d",
if_nametoindex(ifname), result);
return result;
}
result = request.PutString(NL80211_ATTR_IFNAME, ifname);
if (result < 0) {
HDF_LOGE("failed to put NL80211_ATTR_IFNAME = %{public}s; result = %{public}d", ifname, result);
return result;
}
return HAL_SUCCESS;
}
int CreateIface()
{
HDF_LOGD("Creating virtual interface");
WifiRequest request(FamilyId(), IfaceId());
int result = CreateRequest(request, mIfname, mType, mwlan0Id);
if (result != HAL_SUCCESS) {
HDF_LOGE("failed to create virtual iface request; result = %{public}d\n", result);
return result;
}
auto lock = ReadLockData();
result = RequestResponse(request);
if (result != HAL_SUCCESS) {
HDF_LOGE("failed to Get the virtual iface create response; result = %{public}d\n", result);
return result;
}
HDF_LOGD("Created virtual interface");
return HAL_SUCCESS;
}
int DeleteIface()
{
HDF_LOGD("Deleting virtual interface");
WifiRequest request(FamilyId(), IfaceId());
int result = DeleteRequest(request, mIfname);
if (result != HAL_SUCCESS) {
HDF_LOGE("failed to create virtual iface delete request; result = %{public}d\n", result);
return result;
}
auto lock = ReadLockData();
result = RequestResponse(request);
if (result != HAL_SUCCESS) {
HDF_LOGE("failed to Get response of delete virtual interface; result = %{public}d\n", result);
return result;
}
HDF_LOGD("Deleted virtual interface");
return HAL_SUCCESS;
}
protected:
int HandleResponse(WifiEvent& reply) override
{
HDF_LOGD("Request complete!");
return NL_SKIP;
}
};
static WifiError WifiAddIfaceHalInfo(wifiHandle handle, const char* ifname, bool isVirtual)
{
HalInfo *info = nullptr;
int i = 0;
bool hasAdd = false;
info = (HalInfo *)handle;
if (info == nullptr) {
HDF_LOGE("Could not find info\n");
return HAL_UNKNOWN;
}
HDF_LOGI("%{public}s: add InterfaceInfo for iface: %{public}s\n", __FUNCTION__, ifname);
if (info->numInterfaces == MAX_VIRTUAL_IFACES) {
HDF_LOGE("No space. MAX limit reached for virtual interfaces %{public}d\n", info->numInterfaces);
return HAL_OUT_OF_MEMORY;
}
InterfaceInfo *ifinfo = (InterfaceInfo *)malloc(sizeof(InterfaceInfo));
if (!ifinfo) {
free(info->interfaces);
info->numInterfaces = 0;
return HAL_OUT_OF_MEMORY;
}
ifinfo->handle = handle;
while (i < info->maxNumInterfaces) {
if (info->interfaces[i] == nullptr) {
if (GetInterface(ifname, ifinfo) != HAL_SUCCESS) {
continue;
}
ifinfo->isVirtual = isVirtual;
info->interfaces[i] = ifinfo;
info->numInterfaces++;
hasAdd = true;
HDF_LOGI("%{public}s: Added iface: %{public}s at the index %{public}d\n", __FUNCTION__, ifname, i);
break;
}
i++;
}
if (!hasAdd && ifinfo != nullptr) {
free(ifinfo);
free(info->interfaces);
info->numInterfaces = 0;
HDF_LOGI("Added iface: %{public}s failed, not found", ifname);
return HAL_OUT_OF_MEMORY;
}
return HAL_SUCCESS;
}
static void CheckWhetherAddIface(wifiHandle handle, const char* ifname)
{
HalInfo *info = (HalInfo *)handle;
int i = 0;
while (i < info->maxNumInterfaces) {
if (info->interfaces[i] != nullptr &&
strncmp(info->interfaces[i]->name,
ifname, sizeof(info->interfaces[i]->name)) == 0) {
HDF_LOGD("%{public}s is exists", ifname);
return;
}
i++;
}
WifiAddIfaceHalInfo((wifiHandle)handle, ifname, false);
}
static WifiError VendorHalCreateIface(wifiHandle handle, const char* ifname, HalIfaceType ifaceType)
{
int numIfaceHandles = 0;
WifiError ret = HAL_SUCCESS;
wifiInterfaceHandle *ifaceHandles = NULL;
wifiInterfaceHandle wlan0Handle;
nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
uint32_t wlan0Id = if_nametoindex("wlan0");
if (!handle || !wlan0Id) {
HDF_LOGE("%{public}s: Error wifiHandle NULL or wlan0 not present\n", __FUNCTION__);
return HAL_UNKNOWN;
}
if (if_nametoindex(ifname)) {
HDF_LOGI("%{public}s: if_nametoindex(%{public}s) = %{public}d already exists, skip create \n",
__FUNCTION__, ifname, if_nametoindex(ifname));
CheckWhetherAddIface(handle, ifname);
return HAL_SUCCESS;
}
HDF_LOGI("%{public}s: ifname name = %{public}s, type = %{public}u\n", __FUNCTION__, ifname,
ifaceType);
switch (ifaceType) {
case HAL_TYPE_STA:
type = NL80211_IFTYPE_STATION;
break;
case HAL_TYPE_AP:
type = NL80211_IFTYPE_AP;
break;
case HAL_TYPE_P2P:
type = NL80211_IFTYPE_P2P_DEVICE;
break;
case HAL_TYPE_NAN:
type = NL80211_IFTYPE_NAN;
break;
default:
HDF_LOGE("%{public}s: Wrong interface type %{public}u\n", __FUNCTION__, ifaceType);
return HAL_UNKNOWN;
}
wlan0Handle = WifiGetWlanInterface((wifiHandle)handle, ifaceHandles, numIfaceHandles);
VirtualIfaceConfig command(wlan0Handle, ifname, type, wlan0Id);
ret = (WifiError)command.CreateIface();
if (ret != HAL_SUCCESS) {
HDF_LOGE("%{public}s: Iface add Error:%{public}d", __FUNCTION__, ret);
return ret;
}
added_ifaces.push_back(std::string(ifname));
ret = WifiAddIfaceHalInfo((wifiHandle)handle, ifname, true);
return ret;
}
static WifiError WifiClearIfaceHalInfo(wifiHandle handle, const char* ifname)
{
HalInfo *info = (HalInfo *)handle;
int i = 0;
HDF_LOGI("%s: clear hal info for iface: %s\n", __FUNCTION__, ifname);
while (i < info->maxNumInterfaces) {
if ((info->interfaces[i] != nullptr) &&
strncmp(info->interfaces[i]->name, ifname,
sizeof(info->interfaces[i]->name)) == 0) {
free(info->interfaces[i]);
info->interfaces[i] = nullptr;
info->numInterfaces--;
HDF_LOGI("%s: Cleared the index = %d for iface: %s\n", __FUNCTION__, i, ifname);
break;
}
i++;
}
if (i < info->numInterfaces) {
for (int j = i; j < info->numInterfaces; j++) {
info->interfaces[j] = info->interfaces[j + 1];
}
info->interfaces[info->numInterfaces] = nullptr;
}
return HAL_SUCCESS;
}
static WifiError VendorHalDeleteIface(wifiHandle handle, const char* ifname)
{
int numIfaceHandles = 0;
int i = 0;
WifiError ret = HAL_SUCCESS;
wifiInterfaceHandle *ifaceHandles = NULL;
wifiInterfaceHandle wlan0Handle;
HalInfo *info = (HalInfo *)handle;
uint32_t wlan0Id = if_nametoindex("wlan0");
if (!handle || !wlan0Id) {
HDF_LOGE("%{public}s: Error wifiHandle NULL or wlan0 not present\n", __FUNCTION__);
return HAL_UNKNOWN;
}
while (i < info->maxNumInterfaces) {
if (info->interfaces[i] != nullptr &&
strncmp(info->interfaces[i]->name,
ifname, sizeof(info->interfaces[i]->name)) == 0) {
if (!info->interfaces[i]->isVirtual) {
HDF_LOGI("%{public}s: %{public}s is static iface, skip delete\n",
__FUNCTION__, ifname);
return HAL_SUCCESS;
}
}
i++;
}
HDF_LOGD("%{public}s: iface name=%{public}s\n", __FUNCTION__, ifname);
wlan0Handle = WifiGetWlanInterface((wifiHandle)handle, ifaceHandles, numIfaceHandles);
VirtualIfaceConfig command(wlan0Handle, ifname, (nl80211_iftype)0, 0);
ret = (WifiError)command.DeleteIface();
if (ret != HAL_SUCCESS) {
HDF_LOGE("%{public}s: Iface delete Error:%{public}d", __FUNCTION__, ret);
return ret;
}
added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)),
added_ifaces.end());
ret = WifiClearIfaceHalInfo((wifiHandle)handle, ifname);
return ret;
}
WifiError VendorHalGetIfaces(wifiHandle handle, int *num, wifiInterfaceHandle **interfaces)
{
if (!handle) {
HDF_LOGE("Handle is null");
return HAL_UNKNOWN;
}
HalInfo *info = (HalInfo *)handle;
*interfaces = (wifiInterfaceHandle *)info->interfaces;
*num = info->numInterfaces;
return HAL_SUCCESS;
}
WifiError VendorHalGetIfName(wifiInterfaceHandle handle, char *name, size_t size)
{
if (!handle) {
HDF_LOGE("Handle is null");
return HAL_UNKNOWN;
}
InterfaceInfo *info = (InterfaceInfo *)handle;
if (strncpy_s(name, IFNAMSIZ, info->name, IFNAMSIZ) != EOK) {
return HAL_UNKNOWN;
}
name[IFNAMSIZ - 1] = '\0';
return HAL_SUCCESS;
}
class SetCountryCodeCommand : public WifiCommand {
public:
SetCountryCodeCommand(wifiInterfaceHandle handle, const char *countryCode)
: WifiCommand("SetCountryCodeCommand", handle, 0)
{
mCountryCode = countryCode;
}
int Create() override
{
int ret;
ret = mMsg.Create(HAL_OUI, WIFI_SUBCMD_SET_COUNTRY_CODE);
if (ret < 0) {
HDF_LOGE("Can't create message to send to driver - %{public}d", ret);
return ret;
}
nlattr *data = mMsg.AttrStart(NL80211_ATTR_VENDOR_DATA);
ret = mMsg.PutString(HAL_COUNTRY, mCountryCode);
if (ret < 0) {
return ret;
}
mMsg.AttrEnd(data);
return HAL_SUCCESS;
}
private:
const char *mCountryCode;
};
static WifiError WifiSetCountryCode(wifiInterfaceHandle handle, const char *country_code)
{
if (!handle) {
HDF_LOGE("Handle is null");
return HAL_INVALID_ARGS;
}
auto lock = ReadLockData();
SetCountryCodeCommand command(handle, country_code);
return (WifiError) command.RequestResponse();
}
class GetAssociatedInfoCommand : public WifiCommand {
public:
GetAssociatedInfoCommand(wifiInterfaceHandle handle, AssociatedInfo *info)
: WifiCommand("GetAssociatedInfoCommand", handle, 0)
{
mAssocInfo = info;
}
int Create() override
{
int ret;
ret = mMsg.Create(FamilyId(), NL80211_CMD_GET_SCAN, NLM_F_DUMP, 0);
if (ret < 0) {
HDF_LOGE("Can't create message to send to driver - %{public}d", ret);
return ret;
}
ret = mMsg.PutU32(NL80211_ATTR_IFINDEX, IfaceId());
if (ret < 0) {
return ret;
}
return HAL_SUCCESS;
}
protected:
int HandleResponse(WifiEvent& reply) override
{
uint32_t status;
struct nlattr **attr = reply.Attributes();
struct nlattr *bss[NL80211_BSS_MAX + 1];
struct nla_policy bssPolicy[NL80211_BSS_MAX + 1];
bssPolicy[NL80211_BSS_BSSID].type = NLA_UNSPEC;
bssPolicy[NL80211_BSS_FREQUENCY].type = NLA_U32;
bssPolicy[NL80211_BSS_STATUS].type = NLA_U32;
HDF_LOGD("In GetAssociatedInfoCommand::HandleResponse");
if (!attr[NL80211_ATTR_BSS]) {
HDF_LOGE("HandleResponse: BSS info missing!");
return NL_SKIP;
}
if (nla_parse_nested(bss, NL80211_BSS_MAX, attr[NL80211_ATTR_BSS], bssPolicy) < 0 ||
bss[NL80211_BSS_STATUS] == NULL) {
HDF_LOGD("HandleResponse BSS attr or status missing!");
return NL_SKIP;
}
status = nla_get_u32(bss[NL80211_BSS_STATUS]);
if (status == BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_FREQUENCY]) {
mAssocInfo->associatedFreq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
}
if (status == BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_BSSID]) {
if (memcpy_s(mAssocInfo->associatedBssid, ETH_ADDR_LEN,
nla_data(bss[NL80211_BSS_BSSID]), ETH_ADDR_LEN) != EOK) {
HDF_LOGE("HandleResponse: memcpy_s failed!");
return NL_SKIP;
}
}
return NL_SKIP;
}
private:
AssociatedInfo *mAssocInfo;
};
static int WifiGetAssociateInfo(wifiInterfaceHandle handle, AssociatedInfo *info)
{
GetAssociatedInfoCommand command(handle, info);
auto lock = ReadLockData();
return (WifiError) command.RequestResponse();
}
class GetSignalInfoCommand : public WifiCommand {
public:
GetSignalInfoCommand(wifiInterfaceHandle handle, AssociatedInfo assocInfo)
: WifiCommand("GetSignalInfoCommand", handle, 0)
{
mAssocInfo = assocInfo;
if (memset_s(&mSignalInfo, sizeof(mSignalInfo), 0, sizeof(mSignalInfo)) != EOK) {
HDF_LOGE("memset mSignalInfo failed");
}
}
int Create() override
{
int ret;
ret = mMsg.Create(FamilyId(), NL80211_CMD_GET_STATION, 0, 0);
if (ret < 0) {
HDF_LOGE("Can't create message to send to driver - %{public}d", ret);
return ret;
}
ret = mMsg.PutU32(NL80211_ATTR_IFINDEX, IfaceId());
if (ret < 0) {
return ret;
}
ret = mMsg.Put(NL80211_ATTR_MAC, mAssocInfo.associatedBssid, ETH_ADDR_LEN);
if (ret < 0) {
return ret;
}
mSignalInfo.associatedFreq = static_cast<int32_t>(mAssocInfo.associatedFreq);
return HAL_SUCCESS;
}
OHOS::HDI::Wlan::Chip::V2_0::SignalPollResult &GetScanResultsInfo()
{
return mSignalInfo;
}
protected:
int HandleResponse(WifiEvent& reply) override
{
struct nlattr **attr = reply.Attributes();
struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
struct nla_policy statsPolicy[NL80211_STA_INFO_MAX + 1];
statsPolicy[NL80211_STA_INFO_SIGNAL].type = NLA_S8;
statsPolicy[NL80211_STA_INFO_RX_BYTES].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_TX_BYTES].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_RX_PACKETS].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_TX_PACKETS].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_TX_FAILED].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_NOISE].type = NLA_S32;
statsPolicy[NL80211_STA_INFO_SNR].type = NLA_S32;
statsPolicy[NL80211_STA_INFO_CNAHLOAD].type = NLA_S32;
statsPolicy[NL80211_STA_INFO_UL_DELAY].type = NLA_S32;
statsPolicy[NL80211_STA_INFO_UL_DELAY_ARRAY].type = NLA_U16;
statsPolicy[NL80211_STA_INFO_TX_TIME].type = NLA_U16;
statsPolicy[NL80211_STA_INFO_BEACON_RSSI].type = NLA_S8;
statsPolicy[NL80211_STA_INFO_CHLOAD_SELF].type = NLA_U16;
statsPolicy[NL80211_STA_INFO_SIGNAL_DUAL].type = NLA_S8;
statsPolicy[NL80211_STA_INFO_TX_PPDU_CNT].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_TX_PPDU_RETRY_CNT].type = NLA_U32;
statsPolicy[NL80211_STA_INFO_PPDU_PER].type = NLA_U8;
statsPolicy[NL80211_STA_INFO_TX_MCS].type = NLA_U8;
statsPolicy[NL80211_STA_INFO_CWMIN].type = NLA_U8;
statsPolicy[NL80211_STA_INFO_CWMAX].type = NLA_S8;
statsPolicy[NL80211_STA_INFO_ULDELAY_CDF].type = NLA_U16;
statsPolicy[NL80211_STA_INFO_TX_TIME_CDF].type = NLA_U16;
if (!attr[NL80211_ATTR_STA_INFO]) {
HDF_LOGE("HandleResponse: sta stats missing!");
return NL_SKIP;
}
if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, attr[NL80211_ATTR_STA_INFO], statsPolicy) < 0) {
HDF_LOGE("HandleResponse: nla_parse_nested NL80211_ATTR_STA_INFO failed!");
return NL_SKIP;
}
FillSignal(stats, NL80211_STA_INFO_MAX + 1);
FillSignalExt(stats, NL80211_STA_INFO_MAX + 1);
FillSignalAiWifi(stats, NL80211_STA_INFO_MAX + 1);
FillSignalRate(stats, NL80211_STA_INFO_MAX + 1);
return NL_SKIP;
}
private:
OHOS::HDI::Wlan::Chip::V2_0::SignalPollResult mSignalInfo;
AssociatedInfo mAssocInfo;
void FillSignal(struct nlattr **stats, uint32_t size)
{
if (size < NL80211_STA_INFO_MAX + 1) {
HDF_LOGE("size of stats is not enough");
return;
}
if (stats[NL80211_STA_INFO_SIGNAL] != nullptr) {
mSignalInfo.currentRssi = nla_get_s8(stats[NL80211_STA_INFO_SIGNAL]);
}
if (stats[NL80211_STA_INFO_TX_BYTES] != nullptr) {
mSignalInfo.currentTxBytes = (uint64_t)nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
}
if (stats[NL80211_STA_INFO_RX_BYTES] != nullptr) {
mSignalInfo.currentRxBytes = (uint64_t)nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
}
if (stats[NL80211_STA_INFO_TX_PACKETS] != nullptr) {
mSignalInfo.currentTxPackets = (int32_t)nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
}
if (stats[NL80211_STA_INFO_RX_PACKETS] != nullptr) {
mSignalInfo.currentRxPackets = (int32_t)nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
}
if (stats[NL80211_STA_INFO_TX_FAILED] != nullptr) {
mSignalInfo.currentTxFailed = (int32_t)nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
}
}
void FillSignalExt(struct nlattr **stats, uint32_t size)
{
if (size < NL80211_STA_INFO_MAX + 1) {
HDF_LOGE("size of stats is not enough");
return;
}
if (stats[NL80211_STA_INFO_NOISE] != NULL) {
mSignalInfo.currentNoise = nla_get_s32(stats[NL80211_STA_INFO_NOISE]);
}
if (stats[NL80211_STA_INFO_SNR] != NULL) {
mSignalInfo.currentSnr = nla_get_s32(stats[NL80211_STA_INFO_SNR]);
}
if (stats[NL80211_STA_INFO_CNAHLOAD] != NULL) {
mSignalInfo.currentChload = nla_get_s32(stats[NL80211_STA_INFO_CNAHLOAD]);
}
if (stats[NL80211_STA_INFO_UL_DELAY] != NULL) {
mSignalInfo.currentUlDelay = nla_get_s32(stats[NL80211_STA_INFO_UL_DELAY]);
}
if (stats[NL80211_STA_INFO_UL_DELAY_ARRAY] != NULL) {
uint16_t *ulDelayArray = (uint16_t *)nla_data(stats[NL80211_STA_INFO_UL_DELAY_ARRAY]);
HDF_LOGD("mSignalInfo.ulDelayArray[0]=%{public}d ", ulDelayArray[0]);
}
if (stats[NL80211_STA_INFO_TX_TIME] != NULL) {
uint16_t *txTime = (uint16_t *)nla_data(stats[NL80211_STA_INFO_TX_TIME]);
HDF_LOGD("mSignalInfo.txTime[0]=%{public}d ", txTime[0]);
}
if (stats[NL80211_STA_INFO_CHLOAD_SELF] != NULL) {
mSignalInfo.chloadSelf = nla_get_u16(stats[NL80211_STA_INFO_CHLOAD_SELF]);
}
if (stats[NL80211_STA_INFO_SIGNAL_DUAL] != NULL) {
int8_t *rptRssi = (int8_t *)nla_data(stats[NL80211_STA_INFO_SIGNAL_DUAL]);
mSignalInfo.c0Rssi = rptRssi[0];
mSignalInfo.c1Rssi = rptRssi[1];
}
FillSignalAiWifi(stats, NL80211_STA_INFO_MAX + 1);
}
void FillSignalAiWifi(struct nlattr **stats, uint32_t size)
{
const int beaconRssiMaxLen = 10;
if (size < NL80211_STA_INFO_MAX + 1) {
HDF_LOGE("size of stats is not enough");
return;
}
if (stats[NL80211_STA_INFO_BEACON_RSSI] != NULL) {
int8_t *beaconRssi = (int8_t *)nla_data(stats[NL80211_STA_INFO_BEACON_RSSI]);
int beaconRssiLen = (int32_t)(nla_len(stats[NL80211_STA_INFO_BEACON_RSSI]));
std::vector<uint8_t> beaconRssiVec(beaconRssi, beaconRssi + beaconRssiLen);
if (beaconRssiLen > 0 && beaconRssiLen <= beaconRssiMaxLen) {
mSignalInfo.ext.insert(mSignalInfo.ext.end(), beaconRssiVec.begin(), beaconRssiVec.end());
}
}
if (stats[NL80211_STA_INFO_TX_PPDU_CNT] != NULL) {
uint32_t txPpduCnt = nla_get_u32(stats[NL80211_STA_INFO_TX_PPDU_CNT]);
mSignalInfo.ext.push_back(static_cast<uint8_t>(txPpduCnt & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduCnt >> OFFSET_8) & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduCnt >> OFFSET_16) & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduCnt >> OFFSET_24) & MASK_CSMA));
}
if (stats[NL80211_STA_INFO_TX_PPDU_RETRY_CNT] != NULL) {
uint32_t txPpduRetryCnt = nla_get_u32(stats[NL80211_STA_INFO_TX_PPDU_RETRY_CNT]);
mSignalInfo.ext.push_back(static_cast<uint8_t>(txPpduRetryCnt & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduRetryCnt >> OFFSET_8) & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduRetryCnt >> OFFSET_16) & MASK_CSMA));
mSignalInfo.ext.push_back(static_cast<uint8_t>((txPpduRetryCnt >> OFFSET_24) & MASK_CSMA));
}
if (stats[NL80211_STA_INFO_PPDU_PER] != NULL) {
uint8_t ppduPer = nla_get_u8(stats[NL80211_STA_INFO_PPDU_PER]);
mSignalInfo.ext.push_back(ppduPer);
}
if (stats[NL80211_STA_INFO_TX_MCS] != NULL) {
uint8_t txMcs = nla_get_u8(stats[NL80211_STA_INFO_TX_MCS]);
mSignalInfo.ext.push_back(txMcs);
}
FillSignalAiWifiEx(stats, size);
}
void FillSignalAiWifiEx(struct nlattr **stats, uint32_t size)
{
if (size < NL80211_STA_INFO_MAX + 1) {
HDF_LOGE("size of stats is not enough");
return;
}
if (stats[NL80211_STA_INFO_CWMIN] != NULL) {
uint8_t cwMin = nla_get_u8(stats[NL80211_STA_INFO_CWMIN]);
mSignalInfo.ext.push_back(cwMin);
}
if (stats[NL80211_STA_INFO_CWMAX] != NULL) {
uint8_t cwMax = nla_get_u8(stats[NL80211_STA_INFO_CWMAX]);
mSignalInfo.ext.push_back(cwMax);
}
if (stats[NL80211_STA_INFO_ULDELAY_CDF] != NULL) {
uint8_t *uldelayCdf = (uint8_t *)nla_data(stats[NL80211_STA_INFO_ULDELAY_CDF]);
int uldelayCdfLen = (int32_t)(nla_len(stats[NL80211_STA_INFO_ULDELAY_CDF]));
for (int i = 0; i < uldelayCdfLen; ++i) {
mSignalInfo.ext.push_back(static_cast<uint8_t>(uldelayCdf[i]));
}
}
if (stats[NL80211_STA_INFO_TX_TIME_CDF] != NULL) {
uint8_t *txtimeCdf = (uint8_t *)nla_data(stats[NL80211_STA_INFO_TX_TIME_CDF]);
int txtimeCdfLen = (int32_t)(nla_len(stats[NL80211_STA_INFO_TX_TIME_CDF]));
for (int i = 0; i < txtimeCdfLen; ++i) {
mSignalInfo.ext.push_back(static_cast<uint8_t>(txtimeCdf[i]));
}
}
}
void FillSignalRate(struct nlattr **stats, uint32_t size)
{
struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
struct nla_policy ratePolicy[NL80211_RATE_INFO_MAX + 1];
ratePolicy[NL80211_RATE_INFO_BITRATE].type = NLA_U16;
ratePolicy[NL80211_RATE_INFO_BITRATE32].type = NLA_U32;
if (size < NL80211_STA_INFO_MAX + 1) {
HDF_LOGE("FillSignalRate: size of stats is not enough");
return;
}
if (stats[NL80211_STA_INFO_RX_BITRATE] != NULL &&
nla_parse_nested(rate, NL80211_RATE_INFO_MAX, stats[NL80211_STA_INFO_RX_BITRATE], ratePolicy) == 0) {
if (rate[NL80211_RATE_INFO_BITRATE32] != nullptr) {
mSignalInfo.rxBitrate = (int32_t)nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
} else if (rate[NL80211_RATE_INFO_BITRATE] != nullptr) {
mSignalInfo.rxBitrate = nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
}
}
if (stats[NL80211_STA_INFO_TX_BITRATE] != NULL &&
nla_parse_nested(rate, NL80211_RATE_INFO_MAX, stats[NL80211_STA_INFO_TX_BITRATE], ratePolicy) == 0) {
if (rate[NL80211_RATE_INFO_BITRATE32] != nullptr) {
mSignalInfo.txBitrate = (int32_t)nla_get_u32(rate[NL80211_RATE_INFO_BITRATE32]);
} else if (rate[NL80211_RATE_INFO_BITRATE] != nullptr) {
mSignalInfo.txBitrate = nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]);
}
}
}
};
static WifiError WifiGetSignalInfo(wifiInterfaceHandle handle,
OHOS::HDI::Wlan::Chip::V2_0::SignalPollResult& signalPollresult)
{
AssociatedInfo associatedInfo;
if (!handle) {
HDF_LOGE("Handle is null");
return HAL_INVALID_ARGS;
}
(void)memset_s(&associatedInfo, sizeof(associatedInfo), 0, sizeof(associatedInfo));
if (WifiGetAssociateInfo(handle, &associatedInfo) < 0) {
return HAL_NONE;
}
GetSignalInfoCommand command(handle, associatedInfo);
auto lock = ReadLockData();
command.RequestResponse();
signalPollresult = command.GetScanResultsInfo();
return HAL_SUCCESS;
}
static WifiError RegisterIfaceCallBack(const char *ifaceName, WifiCallbackHandler OnCallbackEvent)
{
std::unique_lock<std::mutex> lock(g_callbackMutex);
if (ifaceName == nullptr) {
HDF_LOGE(" ifaceName is null!");
return HAL_NONE;
}
g_halInfo->ifaceCallBack = OnCallbackEvent;
return HAL_SUCCESS;
}
WifiError IsSupportCoex(bool& isCoex)
{
isCoex = false;
return HAL_SUCCESS;
}
static WifiError SendCmdToDriver(const char *ifaceName, int32_t commandId,
const std::vector<int8_t>& paramData, std::vector<int8_t>& result)
{
return HAL_SUCCESS;
}
static WifiError SendP2pCmdToDriver(wifiInterfaceHandle handle, const char *interfaceName, int32_t commandId,
const std::vector<int8_t> ¶mData, std::vector<int8_t> &result)
{
return HAL_UNKNOWN;
}