326 lines
9.9 KiB
C++
326 lines
9.9 KiB
C++
|
/*
|
||
|
* Copyright (C) 2017 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.
|
||
|
*/
|
||
|
|
||
|
#include "interface.h"
|
||
|
|
||
|
#include "log.h"
|
||
|
#include "netlink.h"
|
||
|
#include "netlinkmessage.h"
|
||
|
|
||
|
#include <linux/rtnetlink.h>
|
||
|
|
||
|
#include <future>
|
||
|
|
||
|
// Provide some arbitrary firmware and driver versions for now
|
||
|
static const char kFirmwareVersion[] = "1.0";
|
||
|
static const char kDriverVersion[] = "1.0";
|
||
|
|
||
|
// A list of supported channels in the 2.4 GHz band, values in MHz
|
||
|
static const wifi_channel k2p4Channels[] = {
|
||
|
2412,
|
||
|
2417,
|
||
|
2422,
|
||
|
2427,
|
||
|
2432,
|
||
|
2437,
|
||
|
2442,
|
||
|
2447,
|
||
|
2452,
|
||
|
2457,
|
||
|
2462,
|
||
|
2467,
|
||
|
2472,
|
||
|
2484
|
||
|
};
|
||
|
|
||
|
template<typename T, size_t N>
|
||
|
constexpr size_t arraySize(const T (&)[N]) {
|
||
|
return N;
|
||
|
}
|
||
|
|
||
|
Interface::Interface(Netlink& netlink, const char* name)
|
||
|
: mNetlink(netlink)
|
||
|
, mName(name)
|
||
|
, mInterfaceIndex(0) {
|
||
|
}
|
||
|
|
||
|
Interface::Interface(Interface&& other) noexcept
|
||
|
: mNetlink(other.mNetlink)
|
||
|
, mName(std::move(other.mName))
|
||
|
, mInterfaceIndex(other.mInterfaceIndex) {
|
||
|
}
|
||
|
|
||
|
bool Interface::init() {
|
||
|
mInterfaceIndex = if_nametoindex(mName.c_str());
|
||
|
if (mInterfaceIndex == 0) {
|
||
|
ALOGE("Unable to get interface index for %s", mName.c_str());
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getSupportedFeatureSet(feature_set* set) {
|
||
|
if (set == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
*set = 0;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getName(char* name, size_t size) {
|
||
|
if (size < mName.size() + 1) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
strlcpy(name, mName.c_str(), size);
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// Wifi legacy HAL implicitly assumes getLinkStats is blocking and
|
||
|
// handler will be set to nullptr immediately after invocation.
|
||
|
// Therefore, this function will wait until onLinkStatsReply is called.
|
||
|
wifi_error Interface::getLinkStats(wifi_request_id requestId,
|
||
|
wifi_stats_result_handler handler) {
|
||
|
NetlinkMessage message(RTM_GETLINK, mNetlink.getSequenceNumber());
|
||
|
|
||
|
ifinfomsg* info = message.payload<ifinfomsg>();
|
||
|
info->ifi_family = AF_UNSPEC;
|
||
|
info->ifi_type = 1;
|
||
|
info->ifi_index = mInterfaceIndex;
|
||
|
info->ifi_flags = 0;
|
||
|
info->ifi_change = 0xFFFFFFFF;
|
||
|
|
||
|
std::promise<void> p;
|
||
|
|
||
|
auto callback = [this, requestId, &handler,
|
||
|
&p] (const NetlinkMessage& message) {
|
||
|
onLinkStatsReply(requestId, handler, message);
|
||
|
p.set_value();
|
||
|
};
|
||
|
|
||
|
bool success = mNetlink.sendMessage(message, callback);
|
||
|
// Only wait when callback will be invoked. Therefore, test if the message
|
||
|
// is sent successfully first.
|
||
|
if (success) {
|
||
|
p.get_future().wait();
|
||
|
}
|
||
|
return success ? WIFI_SUCCESS : WIFI_ERROR_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::setLinkStats(wifi_link_layer_params /*params*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::setAlertHandler(wifi_request_id /*id*/,
|
||
|
wifi_alert_handler /*handler*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::resetAlertHandler(wifi_request_id /*id*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getFirmwareVersion(char* buffer, size_t size) {
|
||
|
if (size < sizeof(kFirmwareVersion)) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
strcpy(buffer, kFirmwareVersion);
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getDriverVersion(char* buffer, size_t size) {
|
||
|
if (size < sizeof(kDriverVersion)) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
strcpy(buffer, kDriverVersion);
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::setScanningMacOui(oui /*scan_oui*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::clearLinkStats(u32 /*requestMask*/,
|
||
|
u32* responseMask,
|
||
|
u8 /*request*/,
|
||
|
u8* response) {
|
||
|
if (responseMask == nullptr || response == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getValidChannels(int band,
|
||
|
int maxChannels,
|
||
|
wifi_channel* channels,
|
||
|
int* numChannels) {
|
||
|
if (channels == nullptr || numChannels == nullptr || maxChannels < 0) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
switch (band) {
|
||
|
case WIFI_BAND_BG: // 2.4 GHz
|
||
|
*numChannels = std::min<int>(maxChannels,
|
||
|
arraySize(k2p4Channels));
|
||
|
memcpy(channels, k2p4Channels, *numChannels);
|
||
|
|
||
|
return WIFI_SUCCESS;
|
||
|
default:
|
||
|
return WIFI_ERROR_NOT_SUPPORTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::startLogging(u32 /*verboseLevel*/,
|
||
|
u32 /*flags*/,
|
||
|
u32 /*maxIntervalSec*/,
|
||
|
u32 /*minDataSize*/,
|
||
|
char* /*ringName*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::setCountryCode(const char* /*countryCode*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::setLogHandler(wifi_request_id /*id*/,
|
||
|
wifi_ring_buffer_data_handler /*handler*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getRingBuffersStatus(u32* numRings,
|
||
|
wifi_ring_buffer_status* status) {
|
||
|
if (numRings == nullptr || status == nullptr || *numRings == 0) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
|
||
|
memset(status, 0, sizeof(*status));
|
||
|
strlcpy(reinterpret_cast<char*>(status->name),
|
||
|
"ring0",
|
||
|
sizeof(status->name));
|
||
|
*numRings = 1;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getLoggerSupportedFeatureSet(unsigned int* support) {
|
||
|
if (support == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
*support = 0;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getRingData(char* /*ringName*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::configureNdOffload(u8 /*enable*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::startPacketFateMonitoring() {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getTxPacketFates(wifi_tx_report* /*txReportBuffers*/,
|
||
|
size_t /*numRequestedFates*/,
|
||
|
size_t* numProvidedFates) {
|
||
|
if (numProvidedFates == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
*numProvidedFates = 0;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getRxPacketFates(wifi_rx_report* /*rxReportBuffers*/,
|
||
|
size_t /*numRequestedFates*/,
|
||
|
size_t* numProvidedFates) {
|
||
|
if (numProvidedFates == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
*numProvidedFates = 0;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::getPacketFilterCapabilities(u32* version,
|
||
|
u32* maxLength) {
|
||
|
if (version == nullptr || maxLength == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
*version = 0;
|
||
|
*maxLength = 0;
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error
|
||
|
Interface::getWakeReasonStats(WLAN_DRIVER_WAKE_REASON_CNT* wakeReasonCount) {
|
||
|
if (wakeReasonCount == nullptr) {
|
||
|
return WIFI_ERROR_INVALID_ARGS;
|
||
|
}
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::startSendingOffloadedPacket(wifi_request_id /*id*/,
|
||
|
u16 /*ether_type*/,
|
||
|
u8 * /*ip_packet*/,
|
||
|
u16 /*ip_packet_len*/,
|
||
|
u8 * /*src_mac_addr*/,
|
||
|
u8 * /*dst_mac_addr*/,
|
||
|
u32 /*period_msec*/) {
|
||
|
// Drop the packet and pretend everything is fine. Currentlty this is only
|
||
|
// used for keepalive packets to allow the CPU to go to sleep and let the
|
||
|
// hardware send keepalive packets on its own. By dropping this we lose the
|
||
|
// keepalive packets but networking will still be fine.
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
wifi_error Interface::stopSendingOffloadedPacket(wifi_request_id /*id*/) {
|
||
|
return WIFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void Interface::onLinkStatsReply(wifi_request_id requestId,
|
||
|
wifi_stats_result_handler handler,
|
||
|
const NetlinkMessage& message) {
|
||
|
if (message.size() < sizeof(nlmsghdr) + sizeof(ifinfomsg)) {
|
||
|
ALOGE("Invalid link stats response, too small");
|
||
|
return;
|
||
|
}
|
||
|
if (message.type() != RTM_NEWLINK) {
|
||
|
ALOGE("Recieved invalid link stats reply type: %u",
|
||
|
static_cast<unsigned int>(message.type()));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int numRadios = 1;
|
||
|
wifi_radio_stat radioStats;
|
||
|
memset(&radioStats, 0, sizeof(radioStats));
|
||
|
|
||
|
wifi_iface_stat ifStats;
|
||
|
memset(&ifStats, 0, sizeof(ifStats));
|
||
|
ifStats.iface = reinterpret_cast<wifi_interface_handle>(this);
|
||
|
|
||
|
rtnl_link_stats64 netlinkStats64;
|
||
|
rtnl_link_stats netlinkStats;
|
||
|
if (message.getAttribute(IFLA_STATS64, &netlinkStats64)) {
|
||
|
ifStats.ac[WIFI_AC_BE].tx_mpdu = netlinkStats64.tx_packets;
|
||
|
ifStats.ac[WIFI_AC_BE].rx_mpdu = netlinkStats64.rx_packets;
|
||
|
} else if (message.getAttribute(IFLA_STATS, &netlinkStats)) {
|
||
|
ifStats.ac[WIFI_AC_BE].tx_mpdu = netlinkStats.tx_packets;
|
||
|
ifStats.ac[WIFI_AC_BE].rx_mpdu = netlinkStats.rx_packets;
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
handler.on_link_stats_results(requestId, &ifStats, numRadios, &radioStats);
|
||
|
}
|