platform_hardware_interfaces/wifi/1.0/default/wifi_legacy_hal.cpp

236 lines
8.1 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <array>
#include "wifi_legacy_hal.h"
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <wifi_system/hal_tool.h>
#include <wifi_system/interface_tool.h>
namespace {
static constexpr uint32_t kMaxVersionStringLength = 256;
// Legacy HAL functions accept "C" style function pointers, so use global
// functions to pass to the legacy HAL function and store the corresponding
// std::function methods to be invoked.
// Callback to be invoked once |stop| is complete.
std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
void onStopComplete(wifi_handle handle) {
if (on_stop_complete_internal_callback) {
on_stop_complete_internal_callback(handle);
}
}
// Callback to be invoked for driver dump.
std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
void onDriverMemoryDump(char* buffer, int buffer_size) {
if (on_driver_memory_dump_internal_callback) {
on_driver_memory_dump_internal_callback(buffer, buffer_size);
}
}
// Callback to be invoked for firmware dump.
std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
void onFirmwareMemoryDump(char* buffer, int buffer_size) {
if (on_firmware_memory_dump_internal_callback) {
on_firmware_memory_dump_internal_callback(buffer, buffer_size);
}
}
}
namespace android {
namespace hardware {
namespace wifi {
namespace V1_0 {
namespace implementation {
WifiLegacyHal::WifiLegacyHal()
: global_handle_(nullptr),
wlan_interface_handle_(nullptr),
awaiting_event_loop_termination_(false) {}
wifi_error WifiLegacyHal::start() {
// Ensure that we're starting in a good state.
CHECK(!global_handle_ && !wlan_interface_handle_ &&
!awaiting_event_loop_termination_);
android::wifi_system::HalTool hal_tool;
android::wifi_system::InterfaceTool if_tool;
if (!hal_tool.InitFunctionTable(&global_func_table_)) {
LOG(ERROR) << "Failed to initialize legacy hal function table";
return WIFI_ERROR_UNKNOWN;
}
if (!if_tool.SetWifiUpState(true)) {
LOG(ERROR) << "Failed to set WiFi interface up";
return WIFI_ERROR_UNKNOWN;
}
LOG(INFO) << "Starting legacy HAL";
wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
if (status != WIFI_SUCCESS || !global_handle_) {
LOG(ERROR) << "Failed to retrieve global handle";
return status;
}
event_loop_thread_ = std::thread(&WifiLegacyHal::runEventLoop, this);
status = retrieveWlanInterfaceHandle();
if (status != WIFI_SUCCESS || !wlan_interface_handle_) {
LOG(ERROR) << "Failed to retrieve wlan interface handle";
return status;
}
LOG(VERBOSE) << "Legacy HAL start complete";
return WIFI_SUCCESS;
}
wifi_error WifiLegacyHal::stop(
const std::function<void()>& on_stop_complete_user_callback) {
LOG(INFO) << "Stopping legacy HAL";
on_stop_complete_internal_callback = [&](wifi_handle handle) {
CHECK_EQ(global_handle_, handle) << "Handle mismatch";
on_stop_complete_user_callback();
// Invalidate all the internal pointers now that the HAL is
// stopped.
invalidate();
};
awaiting_event_loop_termination_ = true;
global_func_table_.wifi_cleanup(global_handle_, onStopComplete);
LOG(VERBOSE) << "Legacy HAL stop initiated";
return WIFI_SUCCESS;
}
std::string WifiLegacyHal::getApIfaceName() {
// Fake name. This interface does not exist in legacy HAL
// API's.
return "ap0";
}
std::string WifiLegacyHal::getNanIfaceName() {
// Fake name. This interface does not exist in legacy HAL
// API's.
return "nan0";
}
std::string WifiLegacyHal::getP2pIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.direct.interface", buffer.data(), "p2p0");
return buffer.data();
}
std::string WifiLegacyHal::getStaIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.interface", buffer.data(), "wlan0");
return buffer.data();
}
std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion() {
std::array<char, kMaxVersionStringLength> buffer;
buffer.fill(0);
wifi_error status = global_func_table_.wifi_get_driver_version(
wlan_interface_handle_, buffer.data(), buffer.size());
return std::make_pair(status, buffer.data());
}
std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion() {
std::array<char, kMaxVersionStringLength> buffer;
buffer.fill(0);
wifi_error status = global_func_table_.wifi_get_firmware_version(
wlan_interface_handle_, buffer.data(), buffer.size());
return std::make_pair(status, buffer.data());
}
std::pair<wifi_error, std::vector<uint8_t>>
WifiLegacyHal::requestDriverMemoryDump() {
std::vector<uint8_t> driver_dump;
on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
int buffer_size) {
driver_dump.insert(driver_dump.end(),
reinterpret_cast<uint8_t*>(buffer),
reinterpret_cast<uint8_t*>(buffer) + buffer_size);
};
wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
wlan_interface_handle_, {onDriverMemoryDump});
on_driver_memory_dump_internal_callback = nullptr;
return std::make_pair(status, std::move(driver_dump));
}
std::pair<wifi_error, std::vector<uint8_t>>
WifiLegacyHal::requestFirmwareMemoryDump() {
std::vector<uint8_t> firmware_dump;
on_firmware_memory_dump_internal_callback = [&firmware_dump](
char* buffer, int buffer_size) {
firmware_dump.insert(firmware_dump.end(),
reinterpret_cast<uint8_t*>(buffer),
reinterpret_cast<uint8_t*>(buffer) + buffer_size);
};
wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
wlan_interface_handle_, {onFirmwareMemoryDump});
on_firmware_memory_dump_internal_callback = nullptr;
return std::make_pair(status, std::move(firmware_dump));
}
wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() {
const std::string& ifname_to_find = getStaIfaceName();
wifi_interface_handle* iface_handles = nullptr;
int num_iface_handles = 0;
wifi_error status = global_func_table_.wifi_get_ifaces(
global_handle_, &num_iface_handles, &iface_handles);
if (status != WIFI_SUCCESS) {
LOG(ERROR) << "Failed to enumerate interface handles";
return status;
}
for (int i = 0; i < num_iface_handles; ++i) {
std::array<char, IFNAMSIZ> current_ifname;
current_ifname.fill(0);
status = global_func_table_.wifi_get_iface_name(
iface_handles[i], current_ifname.data(), current_ifname.size());
if (status != WIFI_SUCCESS) {
LOG(WARNING) << "Failed to get interface handle name";
continue;
}
if (ifname_to_find == current_ifname.data()) {
wlan_interface_handle_ = iface_handles[i];
return WIFI_SUCCESS;
}
}
return WIFI_ERROR_UNKNOWN;
}
void WifiLegacyHal::runEventLoop() {
LOG(VERBOSE) << "Starting legacy HAL event loop";
global_func_table_.wifi_event_loop(global_handle_);
if (!awaiting_event_loop_termination_) {
LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
}
LOG(VERBOSE) << "Legacy HAL event loop terminated";
awaiting_event_loop_termination_ = false;
android::wifi_system::InterfaceTool if_tool;
if_tool.SetWifiUpState(false);
}
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
wlan_interface_handle_ = nullptr;
on_stop_complete_internal_callback = nullptr;
on_driver_memory_dump_internal_callback = nullptr;
on_firmware_memory_dump_internal_callback = nullptr;
}
} // namespace implementation
} // namespace V1_0
} // namespace wifi
} // namespace hardware
} // namespace android