diff --git a/wifi/aidl/default/Android.bp b/wifi/aidl/default/Android.bp new file mode 100644 index 0000000000..441d461b78 --- /dev/null +++ b/wifi/aidl/default/Android.bp @@ -0,0 +1,214 @@ +// Copyright (C) 2022 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. + +package { + default_applicable_licenses: ["hardware_interfaces_license"], +} + +soong_config_module_type { + name: "wifi_hal_cc_defaults", + module_type: "cc_defaults", + config_namespace: "wifi", + bool_variables: [ + "hidl_feature_aware", // WIFI_HIDL_FEATURE_AWARE + "hidl_feature_dual_interface", // WIFI_HIDL_FEATURE_DUAL_INTERFACE + "hidl_feature_disable_ap", // WIFI_HIDL_FEATURE_DISABLE_AP + "hidl_feature_disable_ap_mac_randomization", // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION + "avoid_iface_reset_mac_change", // WIFI_AVOID_IFACE_RESET_MAC_CHANGE + ], + value_variables: [ + "hal_interface_combinations", // WIFI_HAL_INTERFACE_COMBINATIONS + ], + properties: [ + "cppflags", + ], +} + +wifi_hal_cc_defaults { + name: "android.hardware.wifi-service-cppflags-defaults", + soong_config_variables: { + hidl_feature_aware: { + cppflags: ["-DWIFI_HIDL_FEATURE_AWARE"], + }, + hidl_feature_dual_interface: { + cppflags: ["-DWIFI_HIDL_FEATURE_DUAL_INTERFACE"], + }, + hidl_feature_disable_ap: { + cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP"], + }, + hidl_feature_disable_ap_mac_randomization: { + cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION"], + }, + avoid_iface_reset_mac_change: { + cppflags: ["-DWIFI_AVOID_IFACE_RESET_MAC_CHANGE"], + }, + hal_interface_combinations: { + cppflags: ["-DWIFI_HAL_INTERFACE_COMBINATIONS=%s"], + }, + }, +} + +cc_library_static { + name: "android.hardware.wifi-service-lib", + defaults: ["android.hardware.wifi-service-cppflags-defaults"], + proprietary: true, + compile_multilib: "first", + cppflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + // Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed. + cflags: ["-Wno-error=implicit-fallthrough"], + srcs: [ + "aidl_struct_util.cpp", + "aidl_sync_util.cpp", + "ringbuffer.cpp", + "wifi.cpp", + "wifi_ap_iface.cpp", + "wifi_chip.cpp", + "wifi_feature_flags.cpp", + "wifi_iface_util.cpp", + "wifi_legacy_hal.cpp", + "wifi_legacy_hal_factory.cpp", + "wifi_legacy_hal_stubs.cpp", + "wifi_mode_controller.cpp", + "wifi_nan_iface.cpp", + "wifi_p2p_iface.cpp", + "wifi_rtt_controller.cpp", + "wifi_sta_iface.cpp", + "wifi_status_util.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libnl", + "libutils", + "libwifi-hal", + "libwifi-system-iface", + "libxml2", + "android.hardware.wifi-V1-ndk", + ], + + export_include_dirs: ["."], +} + +cc_binary { + name: "android.hardware.wifi-service", + vintf_fragments: ["android.hardware.wifi-service.xml"], + relative_install_path: "hw", + proprietary: true, + cppflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + srcs: ["service.cpp"], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libnl", + "libutils", + "libwifi-hal", + "libwifi-system-iface", + "libxml2", + "android.hardware.wifi-V1-ndk", + ], + static_libs: ["android.hardware.wifi-service-lib"], + init_rc: ["android.hardware.wifi-service.rc"], +} + +cc_binary { + name: "android.hardware.wifi-service-lazy", + vintf_fragments: ["android.hardware.wifi-service.xml"], + overrides: ["android.hardware.wifi-service"], + cflags: ["-DLAZY_SERVICE"], + relative_install_path: "hw", + proprietary: true, + cppflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + srcs: ["service.cpp"], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libnl", + "libutils", + "libwifi-hal", + "libwifi-system-iface", + "libxml2", + "android.hardware.wifi-V1-ndk", + ], + static_libs: ["android.hardware.wifi-service-lib"], + init_rc: ["android.hardware.wifi-service-lazy.rc"], +} + +cc_test { + name: "android.hardware.wifi-service-tests", + proprietary: true, + compile_multilib: "first", + cppflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + srcs: [ + "tests/aidl_struct_util_unit_tests.cpp", + "tests/main.cpp", + "tests/mock_interface_tool.cpp", + "tests/mock_wifi_feature_flags.cpp", + "tests/mock_wifi_iface_util.cpp", + "tests/mock_wifi_legacy_hal.cpp", + "tests/mock_wifi_mode_controller.cpp", + "tests/ringbuffer_unit_tests.cpp", + "tests/wifi_nan_iface_unit_tests.cpp", + "tests/wifi_chip_unit_tests.cpp", + "tests/wifi_iface_util_unit_tests.cpp", + ], + static_libs: [ + "libgmock", + "libgtest", + "android.hardware.wifi-V1-ndk", + "android.hardware.wifi-service-lib", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libcutils", + "liblog", + "libnl", + "libutils", + "libwifi-hal", + "libwifi-system-iface", + ], +} + +filegroup { + name: "default-android.hardware.wifi-service.rc", + srcs: ["android.hardware.wifi-service.rc"], +} + +filegroup { + name: "default-android.hardware.wifi-service.xml", + srcs: ["android.hardware.wifi-service.xml"], +} diff --git a/wifi/aidl/default/THREADING.README b/wifi/aidl/default/THREADING.README new file mode 100644 index 0000000000..45679da069 --- /dev/null +++ b/wifi/aidl/default/THREADING.README @@ -0,0 +1,35 @@ +Vendor HAL Threading Model +========================== +The vendor HAL service has two threads: +1. AIDL thread: This is the main thread which processes all the incoming AIDL +RPC's. +2. Legacy HAL event loop thread: This is the thread forked off for processing +the legacy HAL event loop (wifi_event_loop()). This thread is used to process +any asynchronous netlink events posted by the driver. Any asynchronous +callbacks passed to the legacy HAL API's are invoked on this thread. + +Synchronization Concerns +======================== +wifi_legacy_hal.cpp has a bunch of global "C" style functions to handle the +legacy callbacks. Each of these "C" style functions invokes a corresponding +"std::function" version of the callback which does the actual processing. +The variables holding these "std::function" callbacks are reset from the AIDL +thread when they are no longer used. For example: stopGscan() will reset the +corresponding "on_gscan_*" callback variables which were set when startGscan() +was invoked. This is not thread safe since these callback variables are +accesed from the legacy hal event loop thread as well. + +Synchronization Solution +======================== +Adding a global lock seems to be the most trivial solution to the problem. +a) All of the asynchronous "C" style callbacks will acquire the global lock +before invoking the corresponding "std::function" callback variables. +b) All of the AIDL methods will also acquire the global lock before processing +(in aidl_return_util::validateAndCall()). + +Note: It's important that we only acquire the global lock for asynchronous +callbacks, because there is no guarantee (or documentation to clarify) that the +synchronous callbacks are invoked on the same invocation thread. If that is not +the case in some implementation, we will end up deadlocking the system since the +AIDL thread would have acquired the global lock which is needed by the +synchronous callback executed on the legacy hal event loop thread. diff --git a/wifi/aidl/default/aidl_callback_util.h b/wifi/aidl/default/aidl_callback_util.h new file mode 100644 index 0000000000..41d70a53aa --- /dev/null +++ b/wifi/aidl/default/aidl_callback_util.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef AIDL_CALLBACK_UTIL_H_ +#define AIDL_CALLBACK_UTIL_H_ + +#include + +#include +#include + +namespace { +std::unordered_map callback_handler_map_; +} + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_callback_util { + +// Provides a class to manage callbacks for the various AIDL interfaces and +// handle the death of the process hosting each callback. +template +class AidlCallbackHandler { + public: + AidlCallbackHandler() { + death_handler_ = AIBinder_DeathRecipient_new(AidlCallbackHandler::onCallbackDeath); + } + ~AidlCallbackHandler() { invalidate(); } + + bool addCallback(const std::shared_ptr& cb) { + void* cbPtr = reinterpret_cast(cb->asBinder().get()); + const auto& cbPosition = findCbInSet(cbPtr); + if (cbPosition != cb_set_.end()) { + LOG(WARNING) << "Duplicate death notification registration"; + return true; + } + + if (AIBinder_linkToDeath(cb->asBinder().get(), death_handler_, cbPtr /* cookie */) != + STATUS_OK) { + LOG(ERROR) << "Failed to register death notification"; + return false; + } + + callback_handler_map_[cbPtr] = reinterpret_cast(this); + cb_set_.insert(cb); + return true; + } + + const std::set>& getCallbacks() { return cb_set_; } + + void invalidate() { + for (auto cb : cb_set_) { + void* cookie = reinterpret_cast(cb->asBinder().get()); + if (AIBinder_unlinkToDeath(cb->asBinder().get(), death_handler_, cookie) != STATUS_OK) { + LOG(ERROR) << "Failed to deregister death notification"; + } + if (!removeCbFromHandlerMap(cookie)) { + LOG(ERROR) << "Failed to remove callback from handler map"; + } + } + cb_set_.clear(); + } + + // Entry point for the death handling logic. AIBinder_DeathRecipient + // can only call a static function, so use the cookie to find the + // proper handler and route the request there. + static void onCallbackDeath(void* cookie) { + auto cbQuery = callback_handler_map_.find(cookie); + if (cbQuery == callback_handler_map_.end()) { + LOG(ERROR) << "Invalid death cookie received"; + return; + } + + AidlCallbackHandler* cbHandler = reinterpret_cast(cbQuery->second); + if (cbHandler == nullptr) { + LOG(ERROR) << "Handler mapping contained an invalid handler"; + return; + } + cbHandler->handleCallbackDeath(cbQuery->first); + } + + private: + std::set> cb_set_; + AIBinder_DeathRecipient* death_handler_; + + typename std::set>::iterator findCbInSet(void* cbPtr) { + const auto& cbPosition = std::find_if( + cb_set_.begin(), cb_set_.end(), [cbPtr](const std::shared_ptr& p) { + return cbPtr == reinterpret_cast(p->asBinder().get()); + }); + return cbPosition; + } + + bool removeCbFromHandlerMap(void* cbPtr) { + auto cbQuery = callback_handler_map_.find(cbPtr); + if (cbQuery != callback_handler_map_.end()) { + callback_handler_map_.erase(cbQuery); + return true; + } + return false; + } + + void handleCallbackDeath(void* cbPtr) { + const auto& cbPosition = findCbInSet(cbPtr); + if (cbPosition == cb_set_.end()) { + LOG(ERROR) << "Unknown callback death notification received"; + return; + } + cb_set_.erase(cbPosition); + + if (!removeCbFromHandlerMap(cbPtr)) { + LOG(ERROR) << "Callback was not in callback handler map"; + } + } + + DISALLOW_COPY_AND_ASSIGN(AidlCallbackHandler); +}; + +} // namespace aidl_callback_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // AIDL_CALLBACK_UTIL_H_ diff --git a/wifi/aidl/default/aidl_return_util.h b/wifi/aidl/default/aidl_return_util.h new file mode 100644 index 0000000000..9a49a22e2a --- /dev/null +++ b/wifi/aidl/default/aidl_return_util.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef AIDL_RETURN_UTIL_H_ +#define AIDL_RETURN_UTIL_H_ + +#include "aidl_sync_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_return_util { +using aidl::android::hardware::wifi::WifiStatusCode; +using aidl::android::hardware::wifi::aidl_sync_util::acquireGlobalLock; + +/** + * These utility functions are used to invoke a method on the provided + * AIDL interface object. + * These functions checks if the provided AIDL interface object is valid. + * a) If valid, Invokes the corresponding internal implementation function of + * the AIDL method. + * b) If invalid, return without calling the internal implementation function. + */ + +// Use for AIDL methods which return only an AIDL status. +template +::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, + WorkFuncT&& work, Args&&... args) { + const auto lock = acquireGlobalLock(); + if (obj->isValid()) { + return (obj->*work)(std::forward(args)...); + } else { + return createWifiStatus(status_code_if_invalid); + } +} + +// Use for AIDL methods which return only an AIDL status. +// This version passes the global lock acquired to the body of the method. +template +::ndk::ScopedAStatus validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid, + WorkFuncT&& work, Args&&... args) { + auto lock = acquireGlobalLock(); + if (obj->isValid()) { + return (obj->*work)(&lock, std::forward(args)...); + } else { + return createWifiStatus(status_code_if_invalid); + } +} + +// Use for AIDL methods which have a return value along with the AIDL status +template +::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid, + WorkFuncT&& work, ReturnT* ret_val, Args&&... args) { + const auto lock = acquireGlobalLock(); + if (obj->isValid()) { + auto call_pair = (obj->*work)(std::forward(args)...); + *ret_val = call_pair.first; + return std::forward<::ndk::ScopedAStatus>(call_pair.second); + } else { + return ndk::ScopedAStatus::fromServiceSpecificError( + static_cast(status_code_if_invalid)); + } +} + +} // namespace aidl_return_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl +#endif // AIDL_RETURN_UTIL_H_ diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp new file mode 100644 index 0000000000..07612b65c5 --- /dev/null +++ b/wifi/aidl/default/aidl_struct_util.cpp @@ -0,0 +1,2775 @@ +/* + * Copyright (C) 2022 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 +#include + +#include "aidl_struct_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_struct_util { + +WifiChannelWidthInMhz convertLegacyWifiChannelWidthToAidl(legacy_hal::wifi_channel_width type); + +std::string safeConvertChar(const char* str, size_t max_len) { + const char* c = str; + size_t size = 0; + while (*c && (unsigned char)*c < 128 && size < max_len) { + ++size; + ++c; + } + return std::string(str, size); +} + +inline std::vector uintToIntVec(const std::vector& in) { + return std::vector(in.begin(), in.end()); +} + +IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToAidlChipCapability(uint32_t feature) { + switch (feature) { + case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED: + return IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_FIRMWARE_DUMP; + case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED: + return IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_DRIVER_DUMP; + case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED: + return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_CONNECT_EVENT; + case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED: + return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_POWER_EVENT; + case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED: + return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_WAKELOCK_EVENT; + }; + CHECK(false) << "Unknown legacy feature: " << feature; + return {}; +} + +IWifiStaIface::StaIfaceCapabilityMask convertLegacyLoggerFeatureToAidlStaIfaceCapability( + uint32_t feature) { + switch (feature) { + case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED: + return IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE; + }; + CHECK(false) << "Unknown legacy feature: " << feature; + return {}; +} + +IWifiChip::ChipCapabilityMask convertLegacyFeatureToAidlChipCapability(uint64_t feature) { + switch (feature) { + case WIFI_FEATURE_SET_TX_POWER_LIMIT: + return IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT; + case WIFI_FEATURE_USE_BODY_HEAD_SAR: + return IWifiChip::ChipCapabilityMask::USE_BODY_HEAD_SAR; + case WIFI_FEATURE_D2D_RTT: + return IWifiChip::ChipCapabilityMask::D2D_RTT; + case WIFI_FEATURE_D2AP_RTT: + return IWifiChip::ChipCapabilityMask::D2AP_RTT; + case WIFI_FEATURE_INFRA_60G: + return IWifiChip::ChipCapabilityMask::WIGIG; + case WIFI_FEATURE_SET_LATENCY_MODE: + return IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE; + case WIFI_FEATURE_P2P_RAND_MAC: + return IWifiChip::ChipCapabilityMask::P2P_RAND_MAC; + }; + CHECK(false) << "Unknown legacy feature: " << feature; + return {}; +} + +IWifiStaIface::StaIfaceCapabilityMask convertLegacyFeatureToAidlStaIfaceCapability( + uint64_t feature) { + switch (feature) { + case WIFI_FEATURE_GSCAN: + return IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN; + case WIFI_FEATURE_LINK_LAYER_STATS: + return IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS; + case WIFI_FEATURE_RSSI_MONITOR: + return IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR; + case WIFI_FEATURE_CONTROL_ROAMING: + return IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING; + case WIFI_FEATURE_IE_WHITELIST: + return IWifiStaIface::StaIfaceCapabilityMask::PROBE_IE_ALLOWLIST; + case WIFI_FEATURE_SCAN_RAND: + return IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND; + case WIFI_FEATURE_INFRA_5G: + return IWifiStaIface::StaIfaceCapabilityMask::STA_5G; + case WIFI_FEATURE_HOTSPOT: + return IWifiStaIface::StaIfaceCapabilityMask::HOTSPOT; + case WIFI_FEATURE_PNO: + return IWifiStaIface::StaIfaceCapabilityMask::PNO; + case WIFI_FEATURE_TDLS: + return IWifiStaIface::StaIfaceCapabilityMask::TDLS; + case WIFI_FEATURE_TDLS_OFFCHANNEL: + return IWifiStaIface::StaIfaceCapabilityMask::TDLS_OFFCHANNEL; + case WIFI_FEATURE_CONFIG_NDO: + return IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD; + case WIFI_FEATURE_MKEEP_ALIVE: + return IWifiStaIface::StaIfaceCapabilityMask::KEEP_ALIVE; + }; + CHECK(false) << "Unknown legacy feature: " << feature; + return {}; +} + +bool convertLegacyFeaturesToAidlChipCapabilities(uint64_t legacy_feature_set, + uint32_t legacy_logger_feature_set, + uint32_t* aidl_caps) { + if (!aidl_caps) { + return false; + } + *aidl_caps = {}; + for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED, + legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED, + legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED, + legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED, + legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) { + if (feature & legacy_logger_feature_set) { + *aidl_caps |= + static_cast(convertLegacyLoggerFeatureToAidlChipCapability(feature)); + } + } + std::vector features = {WIFI_FEATURE_SET_TX_POWER_LIMIT, + WIFI_FEATURE_USE_BODY_HEAD_SAR, + WIFI_FEATURE_D2D_RTT, + WIFI_FEATURE_D2AP_RTT, + WIFI_FEATURE_INFRA_60G, + WIFI_FEATURE_SET_LATENCY_MODE, + WIFI_FEATURE_P2P_RAND_MAC}; + for (const auto feature : features) { + if (feature & legacy_feature_set) { + *aidl_caps |= static_cast(convertLegacyFeatureToAidlChipCapability(feature)); + } + } + + // There are no flags for these 3 in the legacy feature set. Adding them to + // the set because all the current devices support it. + *aidl_caps |= + static_cast(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_VENDOR_DATA); + *aidl_caps |= + static_cast(IWifiChip::ChipCapabilityMask::DEBUG_HOST_WAKE_REASON_STATS); + *aidl_caps |= static_cast(IWifiChip::ChipCapabilityMask::DEBUG_ERROR_ALERTS); + return true; +} + +WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToAidl(uint32_t flag) { + switch (flag) { + case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES: + return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES; + case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES: + return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES; + }; + CHECK(false) << "Unknown legacy flag: " << flag; + return {}; +} + +bool convertLegacyDebugRingBufferStatusToAidl( + const legacy_hal::wifi_ring_buffer_status& legacy_status, + WifiDebugRingBufferStatus* aidl_status) { + if (!aidl_status) { + return false; + } + *aidl_status = {}; + aidl_status->ringName = safeConvertChar(reinterpret_cast(legacy_status.name), + sizeof(legacy_status.name)); + aidl_status->flags = 0; + for (const auto flag : + {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES, WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) { + if (flag & legacy_status.flags) { + aidl_status->flags |= static_cast::type>( + convertLegacyDebugRingBufferFlagsToAidl(flag)); + } + } + aidl_status->ringId = legacy_status.ring_id; + aidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size; + // Calculate free size of the ring the buffer. We don't need to send the + // exact read/write pointers that were there in the legacy HAL interface. + if (legacy_status.written_bytes >= legacy_status.read_bytes) { + aidl_status->freeSizeInBytes = legacy_status.ring_buffer_byte_size - + (legacy_status.written_bytes - legacy_status.read_bytes); + } else { + aidl_status->freeSizeInBytes = legacy_status.read_bytes - legacy_status.written_bytes; + } + aidl_status->verboseLevel = legacy_status.verbose_level; + return true; +} + +bool convertLegacyVectorOfDebugRingBufferStatusToAidl( + const std::vector& legacy_status_vec, + std::vector* aidl_status_vec) { + if (!aidl_status_vec) { + return false; + } + *aidl_status_vec = {}; + for (const auto& legacy_status : legacy_status_vec) { + WifiDebugRingBufferStatus aidl_status; + if (!convertLegacyDebugRingBufferStatusToAidl(legacy_status, &aidl_status)) { + return false; + } + aidl_status_vec->push_back(aidl_status); + } + return true; +} + +bool convertLegacyWakeReasonStatsToAidl(const legacy_hal::WakeReasonStats& legacy_stats, + WifiDebugHostWakeReasonStats* aidl_stats) { + if (!aidl_stats) { + return false; + } + *aidl_stats = {}; + aidl_stats->totalCmdEventWakeCnt = legacy_stats.wake_reason_cnt.total_cmd_event_wake; + aidl_stats->cmdEventWakeCntPerType = uintToIntVec(legacy_stats.cmd_event_wake_cnt); + aidl_stats->totalDriverFwLocalWakeCnt = legacy_stats.wake_reason_cnt.total_driver_fw_local_wake; + aidl_stats->driverFwLocalWakeCntPerType = uintToIntVec(legacy_stats.driver_fw_local_wake_cnt); + aidl_stats->totalRxPacketWakeCnt = legacy_stats.wake_reason_cnt.total_rx_data_wake; + aidl_stats->rxPktWakeDetails.rxUnicastCnt = + legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt; + aidl_stats->rxPktWakeDetails.rxMulticastCnt = + legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt; + aidl_stats->rxPktWakeDetails.rxBroadcastCnt = + legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt; + aidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt = + legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt; + aidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt = + legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt; + aidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt = + legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt; + aidl_stats->rxIcmpPkWakeDetails.icmpPkt = + legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt; + aidl_stats->rxIcmpPkWakeDetails.icmp6Pkt = + legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt; + aidl_stats->rxIcmpPkWakeDetails.icmp6Ra = + legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra; + aidl_stats->rxIcmpPkWakeDetails.icmp6Na = + legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na; + aidl_stats->rxIcmpPkWakeDetails.icmp6Ns = + legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns; + return true; +} + +legacy_hal::wifi_power_scenario convertAidlTxPowerScenarioToLegacy( + IWifiChip::TxPowerScenario aidl_scenario) { + switch (aidl_scenario) { + case IWifiChip::TxPowerScenario::VOICE_CALL: + return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL; + case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF: + return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF; + case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON: + return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON; + case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF: + return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF; + case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON: + return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON; + }; + CHECK(false); +} + +legacy_hal::wifi_latency_mode convertAidlLatencyModeToLegacy( + IWifiChip::LatencyMode aidl_latency_mode) { + switch (aidl_latency_mode) { + case IWifiChip::LatencyMode::NORMAL: + return legacy_hal::WIFI_LATENCY_MODE_NORMAL; + case IWifiChip::LatencyMode::LOW: + return legacy_hal::WIFI_LATENCY_MODE_LOW; + } + CHECK(false); +} + +bool convertLegacyWifiMacInfoToAidl(const legacy_hal::WifiMacInfo& legacy_mac_info, + IWifiChipEventCallback::RadioModeInfo* aidl_radio_mode_info) { + if (!aidl_radio_mode_info) { + return false; + } + *aidl_radio_mode_info = {}; + + aidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id; + // Convert from bitmask of bands in the legacy HAL to enum value in + // the AIDL interface. + if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND && + legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ; + } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ; + } else { + aidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED; + } + std::vector iface_info_vec; + for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) { + IWifiChipEventCallback::IfaceInfo iface_info; + iface_info.name = legacy_iface_info.name; + iface_info.channel = legacy_iface_info.channel; + iface_info_vec.push_back(iface_info); + } + aidl_radio_mode_info->ifaceInfos = iface_info_vec; + return true; +} + +uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand aidl_band) { + switch (aidl_band) { + case WifiBand::BAND_24GHZ: + return legacy_hal::WLAN_MAC_2_4_BAND; + case WifiBand::BAND_5GHZ: + case WifiBand::BAND_5GHZ_DFS: + case WifiBand::BAND_5GHZ_WITH_DFS: + return legacy_hal::WLAN_MAC_5_0_BAND; + case WifiBand::BAND_24GHZ_5GHZ: + case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS: + return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND); + case WifiBand::BAND_6GHZ: + return legacy_hal::WLAN_MAC_6_0_BAND; + case WifiBand::BAND_5GHZ_6GHZ: + return (legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_6_0_BAND); + case WifiBand::BAND_24GHZ_5GHZ_6GHZ: + case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS_6GHZ: + return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND | + legacy_hal::WLAN_MAC_6_0_BAND); + case WifiBand::BAND_60GHZ: + return legacy_hal::WLAN_MAC_60_0_BAND; + default: + return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND | + legacy_hal::WLAN_MAC_6_0_BAND | legacy_hal::WLAN_MAC_60_0_BAND); + } +} + +WifiBand convertLegacyMacBandToAidlWifiBand(uint32_t band) { + switch (band) { + case legacy_hal::WLAN_MAC_2_4_BAND: + return WifiBand::BAND_24GHZ; + case legacy_hal::WLAN_MAC_5_0_BAND: + return WifiBand::BAND_5GHZ; + case legacy_hal::WLAN_MAC_6_0_BAND: + return WifiBand::BAND_6GHZ; + case legacy_hal::WLAN_MAC_60_0_BAND: + return WifiBand::BAND_60GHZ; + default: + return WifiBand::BAND_UNSPECIFIED; + } +} + +uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask) { + uint32_t legacy_iface_mask = 0; + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_STA)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_SOFTAP)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_P2P_CLIENT)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_P2P_GO)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_NAN)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_TDLS)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_MESH)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH); + } + if (aidl_iface_mask & static_cast(WifiIfaceMode::IFACE_MODE_IBSS)) { + legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS); + } + return legacy_iface_mask; +} + +uint32_t convertLegacyWifiInterfaceModeToAidl(uint32_t legacy_iface_mask) { + uint32_t aidl_iface_mask = 0; + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_STA); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_SOFTAP); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_P2P_CLIENT); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_P2P_GO); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_NAN); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_TDLS); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_MESH); + } + if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) { + aidl_iface_mask |= static_cast(WifiIfaceMode::IFACE_MODE_IBSS); + } + return aidl_iface_mask; +} + +uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask) { + uint32_t legacy_filter_mask = 0; + if (aidl_filter_mask & + static_cast(IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE)) { + legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE; + } + if (aidl_filter_mask & static_cast(IWifiChip::UsableChannelFilter::CONCURRENCY)) { + legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY; + } + if (aidl_filter_mask & static_cast(IWifiChip::UsableChannelFilter::NAN_INSTANT_MODE)) { + legacy_filter_mask |= WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE; + } + return legacy_filter_mask; +} + +bool convertLegacyWifiUsableChannelToAidl( + const legacy_hal::wifi_usable_channel& legacy_usable_channel, + WifiUsableChannel* aidl_usable_channel) { + if (!aidl_usable_channel) { + return false; + } + *aidl_usable_channel = {}; + aidl_usable_channel->channel = legacy_usable_channel.freq; + aidl_usable_channel->channelBandwidth = + convertLegacyWifiChannelWidthToAidl(legacy_usable_channel.width); + aidl_usable_channel->ifaceModeMask = static_cast( + convertLegacyWifiInterfaceModeToAidl(legacy_usable_channel.iface_mode_mask)); + + return true; +} + +bool convertLegacyWifiUsableChannelsToAidl( + const std::vector& legacy_usable_channels, + std::vector* aidl_usable_channels) { + if (!aidl_usable_channels) { + return false; + } + *aidl_usable_channels = {}; + for (const auto& legacy_usable_channel : legacy_usable_channels) { + WifiUsableChannel aidl_usable_channel; + if (!convertLegacyWifiUsableChannelToAidl(legacy_usable_channel, &aidl_usable_channel)) { + return false; + } + aidl_usable_channels->push_back(aidl_usable_channel); + } + return true; +} + +bool convertLegacyWifiMacInfosToAidl( + const std::vector& legacy_mac_infos, + std::vector* aidl_radio_mode_infos) { + if (!aidl_radio_mode_infos) { + return false; + } + *aidl_radio_mode_infos = {}; + + for (const auto& legacy_mac_info : legacy_mac_infos) { + IWifiChipEventCallback::RadioModeInfo aidl_radio_mode_info; + if (!convertLegacyWifiMacInfoToAidl(legacy_mac_info, &aidl_radio_mode_info)) { + return false; + } + aidl_radio_mode_infos->push_back(aidl_radio_mode_info); + } + return true; +} + +bool convertLegacyFeaturesToAidlStaCapabilities(uint64_t legacy_feature_set, + uint32_t legacy_logger_feature_set, + uint32_t* aidl_caps) { + if (!aidl_caps) { + return false; + } + *aidl_caps = {}; + for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) { + if (feature & legacy_logger_feature_set) { + *aidl_caps |= static_cast( + convertLegacyLoggerFeatureToAidlStaIfaceCapability(feature)); + } + } + for (const auto feature : + {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS, WIFI_FEATURE_RSSI_MONITOR, + WIFI_FEATURE_CONTROL_ROAMING, WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND, + WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS, + WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) { + if (feature & legacy_feature_set) { + *aidl_caps |= + static_cast(convertLegacyFeatureToAidlStaIfaceCapability(feature)); + } + } + // There is no flag for this one in the legacy feature set. Adding it to the + // set because all the current devices support it. + *aidl_caps |= static_cast(IWifiStaIface::StaIfaceCapabilityMask::APF); + return true; +} + +bool convertLegacyApfCapabilitiesToAidl(const legacy_hal::PacketFilterCapabilities& legacy_caps, + StaApfPacketFilterCapabilities* aidl_caps) { + if (!aidl_caps) { + return false; + } + *aidl_caps = {}; + aidl_caps->version = legacy_caps.version; + aidl_caps->maxLength = legacy_caps.max_len; + return true; +} + +uint8_t convertAidlGscanReportEventFlagToLegacy( + StaBackgroundScanBucketEventReportSchemeMask aidl_flag) { + using AidlFlag = StaBackgroundScanBucketEventReportSchemeMask; + switch (aidl_flag) { + case AidlFlag::EACH_SCAN: + return REPORT_EVENTS_EACH_SCAN; + case AidlFlag::FULL_RESULTS: + return REPORT_EVENTS_FULL_RESULTS; + case AidlFlag::NO_BATCH: + return REPORT_EVENTS_NO_BATCH; + }; + CHECK(false); +} + +StaScanDataFlagMask convertLegacyGscanDataFlagToAidl(uint8_t legacy_flag) { + switch (legacy_flag) { + case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED: + return StaScanDataFlagMask::INTERRUPTED; + }; + CHECK(false) << "Unknown legacy flag: " << legacy_flag; + // To silence the compiler warning about reaching the end of non-void + // function. + return {}; +} + +bool convertLegacyGscanCapabilitiesToAidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps, + StaBackgroundScanCapabilities* aidl_caps) { + if (!aidl_caps) { + return false; + } + *aidl_caps = {}; + aidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size; + aidl_caps->maxBuckets = legacy_caps.max_scan_buckets; + aidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan; + aidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold; + return true; +} + +legacy_hal::wifi_band convertAidlWifiBandToLegacy(WifiBand band) { + switch (band) { + case WifiBand::BAND_UNSPECIFIED: + return legacy_hal::WIFI_BAND_UNSPECIFIED; + case WifiBand::BAND_24GHZ: + return legacy_hal::WIFI_BAND_BG; + case WifiBand::BAND_5GHZ: + return legacy_hal::WIFI_BAND_A; + case WifiBand::BAND_5GHZ_DFS: + return legacy_hal::WIFI_BAND_A_DFS; + case WifiBand::BAND_5GHZ_WITH_DFS: + return legacy_hal::WIFI_BAND_A_WITH_DFS; + case WifiBand::BAND_24GHZ_5GHZ: + return legacy_hal::WIFI_BAND_ABG; + case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS: + return legacy_hal::WIFI_BAND_ABG_WITH_DFS; + default: + CHECK(false); + return {}; + }; +} + +bool convertAidlGscanParamsToLegacy(const StaBackgroundScanParameters& aidl_scan_params, + legacy_hal::wifi_scan_cmd_params* legacy_scan_params) { + if (!legacy_scan_params) { + return false; + } + *legacy_scan_params = {}; + legacy_scan_params->base_period = aidl_scan_params.basePeriodInMs; + legacy_scan_params->max_ap_per_scan = aidl_scan_params.maxApPerScan; + legacy_scan_params->report_threshold_percent = aidl_scan_params.reportThresholdPercent; + legacy_scan_params->report_threshold_num_scans = aidl_scan_params.reportThresholdNumScans; + if (aidl_scan_params.buckets.size() > MAX_BUCKETS) { + return false; + } + legacy_scan_params->num_buckets = aidl_scan_params.buckets.size(); + for (uint32_t bucket_idx = 0; bucket_idx < aidl_scan_params.buckets.size(); bucket_idx++) { + const StaBackgroundScanBucketParameters& aidl_bucket_spec = + aidl_scan_params.buckets[bucket_idx]; + legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec = + legacy_scan_params->buckets[bucket_idx]; + if (aidl_bucket_spec.bucketIdx >= MAX_BUCKETS) { + return false; + } + legacy_bucket_spec.bucket = aidl_bucket_spec.bucketIdx; + legacy_bucket_spec.band = convertAidlWifiBandToLegacy(aidl_bucket_spec.band); + legacy_bucket_spec.period = aidl_bucket_spec.periodInMs; + legacy_bucket_spec.max_period = aidl_bucket_spec.exponentialMaxPeriodInMs; + legacy_bucket_spec.base = aidl_bucket_spec.exponentialBase; + legacy_bucket_spec.step_count = aidl_bucket_spec.exponentialStepCount; + legacy_bucket_spec.report_events = 0; + using AidlFlag = StaBackgroundScanBucketEventReportSchemeMask; + for (const auto flag : {AidlFlag::EACH_SCAN, AidlFlag::FULL_RESULTS, AidlFlag::NO_BATCH}) { + if (static_cast(aidl_bucket_spec.eventReportScheme) & + static_cast::type>(flag)) { + legacy_bucket_spec.report_events |= convertAidlGscanReportEventFlagToLegacy(flag); + } + } + if (aidl_bucket_spec.frequencies.size() > MAX_CHANNELS) { + return false; + } + legacy_bucket_spec.num_channels = aidl_bucket_spec.frequencies.size(); + for (uint32_t freq_idx = 0; freq_idx < aidl_bucket_spec.frequencies.size(); freq_idx++) { + legacy_bucket_spec.channels[freq_idx].channel = aidl_bucket_spec.frequencies[freq_idx]; + } + } + return true; +} + +bool convertLegacyIeToAidl(const legacy_hal::wifi_information_element& legacy_ie, + WifiInformationElement* aidl_ie) { + if (!aidl_ie) { + return false; + } + *aidl_ie = {}; + aidl_ie->id = legacy_ie.id; + aidl_ie->data = std::vector(legacy_ie.data, legacy_ie.data + legacy_ie.len); + return true; +} + +bool convertLegacyIeBlobToAidl(const uint8_t* ie_blob, uint32_t ie_blob_len, + std::vector* aidl_ies) { + if (!ie_blob || !aidl_ies) { + return false; + } + *aidl_ies = {}; + const uint8_t* ies_begin = ie_blob; + const uint8_t* ies_end = ie_blob + ie_blob_len; + const uint8_t* next_ie = ies_begin; + using wifi_ie = legacy_hal::wifi_information_element; + constexpr size_t kIeHeaderLen = sizeof(wifi_ie); + // Each IE should at least have the header (i.e |id| & |len| fields). + while (next_ie + kIeHeaderLen <= ies_end) { + const wifi_ie& legacy_ie = (*reinterpret_cast(next_ie)); + uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len; + if (next_ie + curr_ie_len > ies_end) { + LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie + << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void*)ies_end; + break; + } + WifiInformationElement aidl_ie; + if (!convertLegacyIeToAidl(legacy_ie, &aidl_ie)) { + LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id << ", len: " << legacy_ie.len; + break; + } + aidl_ies->push_back(std::move(aidl_ie)); + next_ie += curr_ie_len; + } + // Check if the blob has been fully consumed. + if (next_ie != ies_end) { + LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void*)next_ie + << ", IEs End: " << (void*)ies_end; + } + return true; +} + +bool convertLegacyGscanResultToAidl(const legacy_hal::wifi_scan_result& legacy_scan_result, + bool has_ie_data, StaScanResult* aidl_scan_result) { + if (!aidl_scan_result) { + return false; + } + *aidl_scan_result = {}; + aidl_scan_result->timeStampInUs = legacy_scan_result.ts; + aidl_scan_result->ssid = std::vector( + legacy_scan_result.ssid, + legacy_scan_result.ssid + + strnlen(legacy_scan_result.ssid, sizeof(legacy_scan_result.ssid) - 1)); + aidl_scan_result->bssid = std::array(); + std::copy(legacy_scan_result.bssid, legacy_scan_result.bssid + 6, + std::begin(aidl_scan_result->bssid)); + aidl_scan_result->frequency = legacy_scan_result.channel; + aidl_scan_result->rssi = legacy_scan_result.rssi; + aidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period; + aidl_scan_result->capability = legacy_scan_result.capability; + if (has_ie_data) { + std::vector ies; + if (!convertLegacyIeBlobToAidl(reinterpret_cast(legacy_scan_result.ie_data), + legacy_scan_result.ie_length, &ies)) { + return false; + } + aidl_scan_result->informationElements = std::move(ies); + } + return true; +} + +bool convertLegacyCachedGscanResultsToAidl( + const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result, + StaScanData* aidl_scan_data) { + if (!aidl_scan_data) { + return false; + } + *aidl_scan_data = {}; + int32_t flags = 0; + for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) { + if (legacy_cached_scan_result.flags & flag) { + flags |= static_cast::type>( + convertLegacyGscanDataFlagToAidl(flag)); + } + } + aidl_scan_data->flags = static_cast(flags); + aidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned; + + CHECK(legacy_cached_scan_result.num_results >= 0 && + legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN); + std::vector aidl_scan_results; + for (int32_t result_idx = 0; result_idx < legacy_cached_scan_result.num_results; result_idx++) { + StaScanResult aidl_scan_result; + if (!convertLegacyGscanResultToAidl(legacy_cached_scan_result.results[result_idx], false, + &aidl_scan_result)) { + return false; + } + aidl_scan_results.push_back(aidl_scan_result); + } + aidl_scan_data->results = std::move(aidl_scan_results); + return true; +} + +bool convertLegacyVectorOfCachedGscanResultsToAidl( + const std::vector& legacy_cached_scan_results, + std::vector* aidl_scan_datas) { + if (!aidl_scan_datas) { + return false; + } + *aidl_scan_datas = {}; + for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) { + StaScanData aidl_scan_data; + if (!convertLegacyCachedGscanResultsToAidl(legacy_cached_scan_result, &aidl_scan_data)) { + return false; + } + aidl_scan_datas->push_back(aidl_scan_data); + } + return true; +} + +WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToAidl(legacy_hal::wifi_tx_packet_fate fate) { + switch (fate) { + case legacy_hal::TX_PKT_FATE_ACKED: + return WifiDebugTxPacketFate::ACKED; + case legacy_hal::TX_PKT_FATE_SENT: + return WifiDebugTxPacketFate::SENT; + case legacy_hal::TX_PKT_FATE_FW_QUEUED: + return WifiDebugTxPacketFate::FW_QUEUED; + case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID: + return WifiDebugTxPacketFate::FW_DROP_INVALID; + case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS: + return WifiDebugTxPacketFate::FW_DROP_NOBUFS; + case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER: + return WifiDebugTxPacketFate::FW_DROP_OTHER; + case legacy_hal::TX_PKT_FATE_DRV_QUEUED: + return WifiDebugTxPacketFate::DRV_QUEUED; + case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID: + return WifiDebugTxPacketFate::DRV_DROP_INVALID; + case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS: + return WifiDebugTxPacketFate::DRV_DROP_NOBUFS; + case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER: + return WifiDebugTxPacketFate::DRV_DROP_OTHER; + }; + CHECK(false) << "Unknown legacy fate type: " << fate; +} + +WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToAidl(legacy_hal::wifi_rx_packet_fate fate) { + switch (fate) { + case legacy_hal::RX_PKT_FATE_SUCCESS: + return WifiDebugRxPacketFate::SUCCESS; + case legacy_hal::RX_PKT_FATE_FW_QUEUED: + return WifiDebugRxPacketFate::FW_QUEUED; + case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER: + return WifiDebugRxPacketFate::FW_DROP_FILTER; + case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID: + return WifiDebugRxPacketFate::FW_DROP_INVALID; + case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS: + return WifiDebugRxPacketFate::FW_DROP_NOBUFS; + case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER: + return WifiDebugRxPacketFate::FW_DROP_OTHER; + case legacy_hal::RX_PKT_FATE_DRV_QUEUED: + return WifiDebugRxPacketFate::DRV_QUEUED; + case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER: + return WifiDebugRxPacketFate::DRV_DROP_FILTER; + case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID: + return WifiDebugRxPacketFate::DRV_DROP_INVALID; + case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS: + return WifiDebugRxPacketFate::DRV_DROP_NOBUFS; + case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER: + return WifiDebugRxPacketFate::DRV_DROP_OTHER; + }; + CHECK(false) << "Unknown legacy fate type: " << fate; +} + +WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToAidl( + legacy_hal::frame_type type) { + switch (type) { + case legacy_hal::FRAME_TYPE_UNKNOWN: + return WifiDebugPacketFateFrameType::UNKNOWN; + case legacy_hal::FRAME_TYPE_ETHERNET_II: + return WifiDebugPacketFateFrameType::ETHERNET_II; + case legacy_hal::FRAME_TYPE_80211_MGMT: + return WifiDebugPacketFateFrameType::MGMT_80211; + }; + CHECK(false) << "Unknown legacy frame type: " << type; +} + +bool convertLegacyDebugPacketFateFrameToAidl(const legacy_hal::frame_info& legacy_frame, + WifiDebugPacketFateFrameInfo* aidl_frame) { + if (!aidl_frame) { + return false; + } + *aidl_frame = {}; + aidl_frame->frameType = convertLegacyDebugPacketFateFrameTypeToAidl(legacy_frame.payload_type); + aidl_frame->frameLen = legacy_frame.frame_len; + aidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec; + aidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec; + const uint8_t* frame_begin = + reinterpret_cast(legacy_frame.frame_content.ethernet_ii_bytes); + aidl_frame->frameContent = + std::vector(frame_begin, frame_begin + legacy_frame.frame_len); + return true; +} + +bool convertLegacyDebugTxPacketFateToAidl(const legacy_hal::wifi_tx_report& legacy_fate, + WifiDebugTxPacketFateReport* aidl_fate) { + if (!aidl_fate) { + return false; + } + *aidl_fate = {}; + aidl_fate->fate = convertLegacyDebugTxPacketFateToAidl(legacy_fate.fate); + return convertLegacyDebugPacketFateFrameToAidl(legacy_fate.frame_inf, &aidl_fate->frameInfo); +} + +bool convertLegacyVectorOfDebugTxPacketFateToAidl( + const std::vector& legacy_fates, + std::vector* aidl_fates) { + if (!aidl_fates) { + return false; + } + *aidl_fates = {}; + for (const auto& legacy_fate : legacy_fates) { + WifiDebugTxPacketFateReport aidl_fate; + if (!convertLegacyDebugTxPacketFateToAidl(legacy_fate, &aidl_fate)) { + return false; + } + aidl_fates->push_back(aidl_fate); + } + return true; +} + +bool convertLegacyDebugRxPacketFateToAidl(const legacy_hal::wifi_rx_report& legacy_fate, + WifiDebugRxPacketFateReport* aidl_fate) { + if (!aidl_fate) { + return false; + } + *aidl_fate = {}; + aidl_fate->fate = convertLegacyDebugRxPacketFateToAidl(legacy_fate.fate); + return convertLegacyDebugPacketFateFrameToAidl(legacy_fate.frame_inf, &aidl_fate->frameInfo); +} + +bool convertLegacyVectorOfDebugRxPacketFateToAidl( + const std::vector& legacy_fates, + std::vector* aidl_fates) { + if (!aidl_fates) { + return false; + } + *aidl_fates = {}; + for (const auto& legacy_fate : legacy_fates) { + WifiDebugRxPacketFateReport aidl_fate; + if (!convertLegacyDebugRxPacketFateToAidl(legacy_fate, &aidl_fate)) { + return false; + } + aidl_fates->push_back(aidl_fate); + } + return true; +} + +bool convertLegacyLinkLayerRadioStatsToAidl( + const legacy_hal::LinkLayerRadioStats& legacy_radio_stat, + StaLinkLayerRadioStats* aidl_radio_stat) { + if (!aidl_radio_stat) { + return false; + } + *aidl_radio_stat = {}; + + aidl_radio_stat->radioId = legacy_radio_stat.stats.radio; + aidl_radio_stat->onTimeInMs = legacy_radio_stat.stats.on_time; + aidl_radio_stat->txTimeInMs = legacy_radio_stat.stats.tx_time; + aidl_radio_stat->rxTimeInMs = legacy_radio_stat.stats.rx_time; + aidl_radio_stat->onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan; + aidl_radio_stat->txTimeInMsPerLevel = uintToIntVec(legacy_radio_stat.tx_time_per_levels); + aidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd; + aidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan; + aidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan; + aidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan; + aidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20; + + std::vector aidl_channel_stats; + + for (const auto& channel_stat : legacy_radio_stat.channel_stats) { + WifiChannelStats aidl_channel_stat; + aidl_channel_stat.onTimeInMs = channel_stat.on_time; + aidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time; + aidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20; + aidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq; + aidl_channel_stat.channel.centerFreq0 = channel_stat.channel.center_freq0; + aidl_channel_stat.channel.centerFreq1 = channel_stat.channel.center_freq1; + aidl_channel_stats.push_back(aidl_channel_stat); + } + + aidl_radio_stat->channelStats = aidl_channel_stats; + + return true; +} + +bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats, + StaLinkLayerStats* aidl_stats) { + if (!aidl_stats) { + return false; + } + *aidl_stats = {}; + // iface legacy_stats conversion. + aidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx; + aidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt; + aidl_stats->iface.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu; + aidl_stats->iface.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu; + aidl_stats->iface.wmeBePktStats.lostMpdu = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost; + aidl_stats->iface.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries; + aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMinInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min; + aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max; + aidl_stats->iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg; + aidl_stats->iface.wmeBeContentionTimeStats.contentionNumSamples = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples; + aidl_stats->iface.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu; + aidl_stats->iface.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu; + aidl_stats->iface.wmeBkPktStats.lostMpdu = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost; + aidl_stats->iface.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries; + aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMinInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min; + aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max; + aidl_stats->iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg; + aidl_stats->iface.wmeBkContentionTimeStats.contentionNumSamples = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples; + aidl_stats->iface.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu; + aidl_stats->iface.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu; + aidl_stats->iface.wmeViPktStats.lostMpdu = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost; + aidl_stats->iface.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries; + aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMinInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min; + aidl_stats->iface.wmeViContentionTimeStats.contentionTimeMaxInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max; + aidl_stats->iface.wmeViContentionTimeStats.contentionTimeAvgInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg; + aidl_stats->iface.wmeViContentionTimeStats.contentionNumSamples = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples; + aidl_stats->iface.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu; + aidl_stats->iface.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu; + aidl_stats->iface.wmeVoPktStats.lostMpdu = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost; + aidl_stats->iface.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries; + aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMinInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min; + aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max; + aidl_stats->iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg; + aidl_stats->iface.wmeVoContentionTimeStats.contentionNumSamples = + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples; + aidl_stats->iface.timeSliceDutyCycleInPercent = + legacy_stats.iface.info.time_slicing_duty_cycle_percent; + // peer info legacy_stats conversion. + std::vector aidl_peers_info_stats; + for (const auto& legacy_peer_info_stats : legacy_stats.peers) { + StaPeerInfo aidl_peer_info_stats; + if (!convertLegacyPeerInfoStatsToAidl(legacy_peer_info_stats, &aidl_peer_info_stats)) { + return false; + } + aidl_peers_info_stats.push_back(aidl_peer_info_stats); + } + aidl_stats->iface.peers = aidl_peers_info_stats; + // radio legacy_stats conversion. + std::vector aidl_radios_stats; + for (const auto& legacy_radio_stats : legacy_stats.radios) { + StaLinkLayerRadioStats aidl_radio_stats; + if (!convertLegacyLinkLayerRadioStatsToAidl(legacy_radio_stats, &aidl_radio_stats)) { + return false; + } + aidl_radios_stats.push_back(aidl_radio_stats); + } + aidl_stats->radios = aidl_radios_stats; + aidl_stats->timeStampInMs = ::android::uptimeMillis(); + return true; +} + +bool convertLegacyPeerInfoStatsToAidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats, + StaPeerInfo* aidl_peer_info_stats) { + if (!aidl_peer_info_stats) { + return false; + } + *aidl_peer_info_stats = {}; + aidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count; + aidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util; + + std::vector aidlRateStats; + for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) { + StaRateStat rateStat; + if (!convertLegacyWifiRateInfoToAidl(legacy_rate_stats.rate, &rateStat.rateInfo)) { + return false; + } + rateStat.txMpdu = legacy_rate_stats.tx_mpdu; + rateStat.rxMpdu = legacy_rate_stats.rx_mpdu; + rateStat.mpduLost = legacy_rate_stats.mpdu_lost; + rateStat.retries = legacy_rate_stats.retries; + aidlRateStats.push_back(rateStat); + } + aidl_peer_info_stats->rateStats = aidlRateStats; + return true; +} + +bool convertLegacyRoamingCapabilitiesToAidl( + const legacy_hal::wifi_roaming_capabilities& legacy_caps, + StaRoamingCapabilities* aidl_caps) { + if (!aidl_caps) { + return false; + } + *aidl_caps = {}; + aidl_caps->maxBlocklistSize = legacy_caps.max_blacklist_size; + aidl_caps->maxAllowlistSize = legacy_caps.max_whitelist_size; + return true; +} + +bool convertAidlRoamingConfigToLegacy(const StaRoamingConfig& aidl_config, + legacy_hal::wifi_roaming_config* legacy_config) { + if (!legacy_config) { + return false; + } + *legacy_config = {}; + if (aidl_config.bssidBlocklist.size() > MAX_BLACKLIST_BSSID || + aidl_config.ssidAllowlist.size() > MAX_WHITELIST_SSID) { + return false; + } + legacy_config->num_blacklist_bssid = aidl_config.bssidBlocklist.size(); + uint32_t i = 0; + for (const auto& bssid : aidl_config.bssidBlocklist) { + CHECK(bssid.data.size() == sizeof(legacy_hal::mac_addr)); + memcpy(legacy_config->blacklist_bssid[i++], bssid.data.data(), bssid.data.size()); + } + legacy_config->num_whitelist_ssid = aidl_config.ssidAllowlist.size(); + i = 0; + for (const auto& ssid : aidl_config.ssidAllowlist) { + CHECK(ssid.data.size() <= sizeof(legacy_hal::ssid_t::ssid_str)); + legacy_config->whitelist_ssid[i].length = ssid.data.size(); + memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data.data(), ssid.data.size()); + i++; + } + return true; +} + +legacy_hal::fw_roaming_state_t convertAidlRoamingStateToLegacy(StaRoamingState state) { + switch (state) { + case StaRoamingState::ENABLED: + return legacy_hal::ROAMING_ENABLE; + case StaRoamingState::DISABLED: + return legacy_hal::ROAMING_DISABLE; + }; + CHECK(false); +} + +legacy_hal::NanMatchAlg convertAidlNanMatchAlgToLegacy(NanMatchAlg type) { + switch (type) { + case NanMatchAlg::MATCH_ONCE: + return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE; + case NanMatchAlg::MATCH_CONTINUOUS: + return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS; + case NanMatchAlg::MATCH_NEVER: + return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER; + } + CHECK(false); +} + +legacy_hal::NanPublishType convertAidlNanPublishTypeToLegacy(NanPublishType type) { + switch (type) { + case NanPublishType::UNSOLICITED: + return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED; + case NanPublishType::SOLICITED: + return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED; + case NanPublishType::UNSOLICITED_SOLICITED: + return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED; + } + CHECK(false); +} + +legacy_hal::NanTxType convertAidlNanTxTypeToLegacy(NanTxType type) { + switch (type) { + case NanTxType::BROADCAST: + return legacy_hal::NAN_TX_TYPE_BROADCAST; + case NanTxType::UNICAST: + return legacy_hal::NAN_TX_TYPE_UNICAST; + } + CHECK(false); +} + +legacy_hal::NanSubscribeType convertAidlNanSubscribeTypeToLegacy(NanSubscribeType type) { + switch (type) { + case NanSubscribeType::PASSIVE: + return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE; + case NanSubscribeType::ACTIVE: + return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE; + } + CHECK(false); +} + +legacy_hal::NanSRFType convertAidlNanSrfTypeToLegacy(NanSrfType type) { + switch (type) { + case NanSrfType::BLOOM_FILTER: + return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER; + case NanSrfType::PARTIAL_MAC_ADDR: + return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR; + } + CHECK(false); +} + +legacy_hal::NanDataPathChannelCfg convertAidlNanDataPathChannelCfgToLegacy( + NanDataPathChannelCfg type) { + switch (type) { + case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED: + return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED; + case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP: + return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP; + case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP: + return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP; + } + CHECK(false); +} + +NanStatusCode convertLegacyNanStatusTypeToAidl(legacy_hal::NanStatusType type) { + switch (type) { + case legacy_hal::NAN_STATUS_SUCCESS: + return NanStatusCode::SUCCESS; + case legacy_hal::NAN_STATUS_INTERNAL_FAILURE: + return NanStatusCode::INTERNAL_FAILURE; + case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE: + return NanStatusCode::PROTOCOL_FAILURE; + case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID: + return NanStatusCode::INVALID_SESSION_ID; + case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE: + return NanStatusCode::NO_RESOURCES_AVAILABLE; + case legacy_hal::NAN_STATUS_INVALID_PARAM: + return NanStatusCode::INVALID_ARGS; + case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID: + return NanStatusCode::INVALID_PEER_ID; + case legacy_hal::NAN_STATUS_INVALID_NDP_ID: + return NanStatusCode::INVALID_NDP_ID; + case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED: + return NanStatusCode::NAN_NOT_ALLOWED; + case legacy_hal::NAN_STATUS_NO_OTA_ACK: + return NanStatusCode::NO_OTA_ACK; + case legacy_hal::NAN_STATUS_ALREADY_ENABLED: + return NanStatusCode::ALREADY_ENABLED; + case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL: + return NanStatusCode::FOLLOWUP_TX_QUEUE_FULL; + case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED: + return NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED; + } + CHECK(false); +} + +void convertToNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len, + NanStatus* nanStatus) { + nanStatus->status = convertLegacyNanStatusTypeToAidl(type); + nanStatus->description = safeConvertChar(str, max_len); +} + +bool convertAidlNanEnableRequestToLegacy(const NanEnableRequest& aidl_request1, + const NanConfigRequestSupplemental& aidl_request2, + legacy_hal::NanEnableRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: null legacy_request"; + return false; + } + *legacy_request = {}; + + legacy_request->config_2dot4g_support = 1; + legacy_request->support_2dot4g_val = + aidl_request1.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ]; + legacy_request->config_support_5g = 1; + legacy_request->support_5g_val = + aidl_request1.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + legacy_request->config_hop_count_limit = 1; + legacy_request->hop_count_limit_val = aidl_request1.hopCountMax; + legacy_request->master_pref = aidl_request1.configParams.masterPref; + legacy_request->discovery_indication_cfg = 0; + legacy_request->discovery_indication_cfg |= + aidl_request1.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0; + legacy_request->discovery_indication_cfg |= + aidl_request1.configParams.disableStartedClusterIndication ? 0x2 : 0x0; + legacy_request->discovery_indication_cfg |= + aidl_request1.configParams.disableJoinedClusterIndication ? 0x4 : 0x0; + legacy_request->config_sid_beacon = 1; + if (aidl_request1.configParams.numberOfPublishServiceIdsInBeacon < 0) { + LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: " + "numberOfPublishServiceIdsInBeacon < 0"; + return false; + } + legacy_request->sid_beacon_val = + (aidl_request1.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0) | + (aidl_request1.configParams.numberOfPublishServiceIdsInBeacon << 1); + legacy_request->config_subscribe_sid_beacon = 1; + if (aidl_request1.configParams.numberOfSubscribeServiceIdsInBeacon < 0) { + LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: " + "numberOfSubscribeServiceIdsInBeacon < 0"; + return false; + } + legacy_request->subscribe_sid_beacon_val = + (aidl_request1.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) | + (aidl_request1.configParams.numberOfSubscribeServiceIdsInBeacon << 1); + legacy_request->config_rssi_window_size = 1; + legacy_request->rssi_window_size_val = aidl_request1.configParams.rssiWindowSize; + legacy_request->config_disc_mac_addr_randomization = 1; + legacy_request->disc_mac_addr_rand_interval_sec = + aidl_request1.configParams.macAddressRandomizationIntervalSec; + legacy_request->config_2dot4g_rssi_close = 1; + if (aidl_request1.configParams.bandSpecificConfig.size() != 3) { + LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: " + "bandSpecificConfig.size() != 3"; + return false; + } + legacy_request->rssi_close_2dot4g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .rssiClose; + legacy_request->config_2dot4g_rssi_middle = 1; + legacy_request->rssi_middle_2dot4g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .rssiMiddle; + legacy_request->config_2dot4g_rssi_proximity = 1; + legacy_request->rssi_proximity_2dot4g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .rssiCloseProximity; + legacy_request->config_scan_params = 1; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .scanPeriodSec; + legacy_request->config_dw.config_2dot4g_dw_band = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .validDiscoveryWindowIntervalVal; + legacy_request->config_dw.dw_2dot4g_interval_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .discoveryWindowIntervalVal; + legacy_request->config_5g_rssi_close = 1; + legacy_request->rssi_close_5g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .rssiClose; + legacy_request->config_5g_rssi_middle = 1; + legacy_request->rssi_middle_5g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .rssiMiddle; + legacy_request->config_5g_rssi_close_proximity = 1; + legacy_request->rssi_close_proximity_5g_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .rssiCloseProximity; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .scanPeriodSec; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .scanPeriodSec; + legacy_request->config_dw.config_5g_dw_band = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .validDiscoveryWindowIntervalVal; + legacy_request->config_dw.dw_5g_interval_val = + aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .discoveryWindowIntervalVal; + if (aidl_request1.debugConfigs.validClusterIdVals) { + legacy_request->cluster_low = aidl_request1.debugConfigs.clusterIdBottomRangeVal; + legacy_request->cluster_high = aidl_request1.debugConfigs.clusterIdTopRangeVal; + } else { // need 'else' since not configurable in legacy HAL + legacy_request->cluster_low = 0x0000; + legacy_request->cluster_high = 0xFFFF; + } + legacy_request->config_intf_addr = aidl_request1.debugConfigs.validIntfAddrVal; + memcpy(legacy_request->intf_addr_val, aidl_request1.debugConfigs.intfAddrVal.data(), 6); + legacy_request->config_oui = aidl_request1.debugConfigs.validOuiVal; + legacy_request->oui_val = aidl_request1.debugConfigs.ouiVal; + legacy_request->config_random_factor_force = + aidl_request1.debugConfigs.validRandomFactorForceVal; + legacy_request->random_factor_force_val = aidl_request1.debugConfigs.randomFactorForceVal; + legacy_request->config_hop_count_force = aidl_request1.debugConfigs.validHopCountForceVal; + legacy_request->hop_count_force_val = aidl_request1.debugConfigs.hopCountForceVal; + legacy_request->config_24g_channel = aidl_request1.debugConfigs.validDiscoveryChannelVal; + legacy_request->channel_24g_val = + aidl_request1.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ]; + legacy_request->config_5g_channel = aidl_request1.debugConfigs.validDiscoveryChannelVal; + legacy_request->channel_5g_val = + aidl_request1.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + legacy_request->config_2dot4g_beacons = aidl_request1.debugConfigs.validUseBeaconsInBandVal; + legacy_request->beacon_2dot4g_val = + aidl_request1.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ]; + legacy_request->config_5g_beacons = aidl_request1.debugConfigs.validUseBeaconsInBandVal; + legacy_request->beacon_5g_val = + aidl_request1.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + legacy_request->config_2dot4g_sdf = aidl_request1.debugConfigs.validUseSdfInBandVal; + legacy_request->sdf_2dot4g_val = + aidl_request1.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ]; + legacy_request->config_5g_sdf = aidl_request1.debugConfigs.validUseSdfInBandVal; + legacy_request->sdf_5g_val = + aidl_request1.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ]; + + legacy_request->config_discovery_beacon_int = 1; + legacy_request->discovery_beacon_interval = aidl_request2.discoveryBeaconIntervalMs; + legacy_request->config_nss = 1; + legacy_request->nss = aidl_request2.numberOfSpatialStreamsInDiscovery; + legacy_request->config_dw_early_termination = 1; + legacy_request->enable_dw_termination = aidl_request2.enableDiscoveryWindowEarlyTermination; + legacy_request->config_enable_ranging = 1; + legacy_request->enable_ranging = aidl_request2.enableRanging; + + legacy_request->config_enable_instant_mode = 1; + legacy_request->enable_instant_mode = aidl_request2.enableInstantCommunicationMode; + legacy_request->config_instant_mode_channel = 1; + legacy_request->instant_mode_channel = aidl_request2.instantModeChannel; + + return true; +} + +bool convertAidlNanConfigRequestToLegacy(const NanConfigRequest& aidl_request1, + const NanConfigRequestSupplemental& aidl_request2, + legacy_hal::NanConfigRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: null legacy_request"; + return false; + } + *legacy_request = {}; + + legacy_request->master_pref = aidl_request1.masterPref; + legacy_request->discovery_indication_cfg = 0; + legacy_request->discovery_indication_cfg |= + aidl_request1.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0; + legacy_request->discovery_indication_cfg |= + aidl_request1.disableStartedClusterIndication ? 0x2 : 0x0; + legacy_request->discovery_indication_cfg |= + aidl_request1.disableJoinedClusterIndication ? 0x4 : 0x0; + legacy_request->config_sid_beacon = 1; + if (aidl_request1.numberOfPublishServiceIdsInBeacon < 0) { + LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: " + "numberOfPublishServiceIdsInBeacon < 0"; + return false; + } + legacy_request->sid_beacon = (aidl_request1.includePublishServiceIdsInBeacon ? 0x1 : 0x0) | + (aidl_request1.numberOfPublishServiceIdsInBeacon << 1); + legacy_request->config_subscribe_sid_beacon = 1; + if (aidl_request1.numberOfSubscribeServiceIdsInBeacon < 0) { + LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: " + "numberOfSubscribeServiceIdsInBeacon < 0"; + return false; + } + legacy_request->subscribe_sid_beacon_val = + (aidl_request1.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) | + (aidl_request1.numberOfSubscribeServiceIdsInBeacon << 1); + legacy_request->config_rssi_window_size = 1; + legacy_request->rssi_window_size_val = aidl_request1.rssiWindowSize; + legacy_request->config_disc_mac_addr_randomization = 1; + legacy_request->disc_mac_addr_rand_interval_sec = + aidl_request1.macAddressRandomizationIntervalSec; + + legacy_request->config_scan_params = 1; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec; + legacy_request->config_dw.config_2dot4g_dw_band = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .validDiscoveryWindowIntervalVal; + legacy_request->config_dw.dw_2dot4g_interval_val = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ] + .discoveryWindowIntervalVal; + + legacy_request->config_5g_rssi_close_proximity = 1; + legacy_request->rssi_close_proximity_5g_val = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .rssiCloseProximity; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec; + legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs; + legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec; + legacy_request->config_dw.config_5g_dw_band = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .validDiscoveryWindowIntervalVal; + legacy_request->config_dw.dw_5g_interval_val = + aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ] + .discoveryWindowIntervalVal; + + legacy_request->config_discovery_beacon_int = 1; + legacy_request->discovery_beacon_interval = aidl_request2.discoveryBeaconIntervalMs; + legacy_request->config_nss = 1; + legacy_request->nss = aidl_request2.numberOfSpatialStreamsInDiscovery; + legacy_request->config_dw_early_termination = 1; + legacy_request->enable_dw_termination = aidl_request2.enableDiscoveryWindowEarlyTermination; + legacy_request->config_enable_ranging = 1; + legacy_request->enable_ranging = aidl_request2.enableRanging; + + legacy_request->config_enable_instant_mode = 1; + legacy_request->enable_instant_mode = aidl_request2.enableInstantCommunicationMode; + legacy_request->config_instant_mode_channel = 1; + legacy_request->instant_mode_channel = aidl_request2.instantModeChannel; + + return true; +} + +bool convertAidlNanPublishRequestToLegacy(const NanPublishRequest& aidl_request, + legacy_hal::NanPublishRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: null legacy_request"; + return false; + } + *legacy_request = {}; + + legacy_request->publish_id = aidl_request.baseConfigs.sessionId; + legacy_request->ttl = aidl_request.baseConfigs.ttlSec; + legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod; + legacy_request->publish_count = aidl_request.baseConfigs.discoveryCount; + legacy_request->service_name_len = aidl_request.baseConfigs.serviceName.size(); + if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: service_name_len " + "too large"; + return false; + } + memcpy(legacy_request->service_name, aidl_request.baseConfigs.serviceName.data(), + legacy_request->service_name_len); + legacy_request->publish_match_indicator = + convertAidlNanMatchAlgToLegacy(aidl_request.baseConfigs.discoveryMatchIndicator); + legacy_request->service_specific_info_len = aidl_request.baseConfigs.serviceSpecificInfo.size(); + if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->service_specific_info, + aidl_request.baseConfigs.serviceSpecificInfo.data(), + legacy_request->service_specific_info_len); + legacy_request->sdea_service_specific_info_len = + aidl_request.baseConfigs.extendedServiceSpecificInfo.size(); + if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "sdea_service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->sdea_service_specific_info, + aidl_request.baseConfigs.extendedServiceSpecificInfo.data(), + legacy_request->sdea_service_specific_info_len); + legacy_request->rx_match_filter_len = aidl_request.baseConfigs.rxMatchFilter.size(); + if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "rx_match_filter_len too large"; + return false; + } + memcpy(legacy_request->rx_match_filter, aidl_request.baseConfigs.rxMatchFilter.data(), + legacy_request->rx_match_filter_len); + legacy_request->tx_match_filter_len = aidl_request.baseConfigs.txMatchFilter.size(); + if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "tx_match_filter_len too large"; + return false; + } + memcpy(legacy_request->tx_match_filter, aidl_request.baseConfigs.txMatchFilter.data(), + legacy_request->tx_match_filter_len); + legacy_request->rssi_threshold_flag = aidl_request.baseConfigs.useRssiThreshold; + legacy_request->recv_indication_cfg = 0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0; + legacy_request->recv_indication_cfg |= 0x8; + legacy_request->cipher_type = (unsigned int)aidl_request.baseConfigs.securityConfig.cipherType; + + legacy_request->scid_len = aidl_request.baseConfigs.securityConfig.scid.size(); + if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: scid_len too large"; + return false; + } + memcpy(legacy_request->scid, aidl_request.baseConfigs.securityConfig.scid.data(), + legacy_request->scid_len); + + if (aidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK; + legacy_request->key_info.body.pmk_info.pmk_len = + aidl_request.baseConfigs.securityConfig.pmk.size(); + if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: invalid pmk_len"; + return false; + } + memcpy(legacy_request->key_info.body.pmk_info.pmk, + aidl_request.baseConfigs.securityConfig.pmk.data(), + legacy_request->key_info.body.pmk_info.pmk_len); + } + if (aidl_request.baseConfigs.securityConfig.securityType == + NanDataPathSecurityType::PASSPHRASE) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE; + legacy_request->key_info.body.passphrase_info.passphrase_len = + aidl_request.baseConfigs.securityConfig.passphrase.size(); + if (legacy_request->key_info.body.passphrase_info.passphrase_len < + NAN_SECURITY_MIN_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "passphrase_len too small"; + return false; + } + if (legacy_request->key_info.body.passphrase_info.passphrase_len > + NAN_SECURITY_MAX_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: " + "passphrase_len too large"; + return false; + } + memcpy(legacy_request->key_info.body.passphrase_info.passphrase, + aidl_request.baseConfigs.securityConfig.passphrase.data(), + legacy_request->key_info.body.passphrase_info.passphrase_len); + } + legacy_request->sdea_params.security_cfg = + (aidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN) + ? legacy_hal::NAN_DP_CONFIG_SECURITY + : legacy_hal::NAN_DP_CONFIG_NO_SECURITY; + + legacy_request->sdea_params.ranging_state = aidl_request.baseConfigs.rangingRequired + ? legacy_hal::NAN_RANGING_ENABLE + : legacy_hal::NAN_RANGING_DISABLE; + legacy_request->ranging_cfg.ranging_interval_msec = aidl_request.baseConfigs.rangingIntervalMs; + legacy_request->ranging_cfg.config_ranging_indications = + static_cast(aidl_request.baseConfigs.configRangingIndications); + legacy_request->ranging_cfg.distance_ingress_mm = + aidl_request.baseConfigs.distanceIngressCm * 10; + legacy_request->ranging_cfg.distance_egress_mm = aidl_request.baseConfigs.distanceEgressCm * 10; + legacy_request->ranging_auto_response = aidl_request.baseConfigs.rangingRequired + ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE + : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE; + legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT; + legacy_request->publish_type = convertAidlNanPublishTypeToLegacy(aidl_request.publishType); + legacy_request->tx_type = convertAidlNanTxTypeToLegacy(aidl_request.txType); + legacy_request->service_responder_policy = aidl_request.autoAcceptDataPathRequests + ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL + : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE; + + return true; +} + +bool convertAidlNanSubscribeRequestToLegacy(const NanSubscribeRequest& aidl_request, + legacy_hal::NanSubscribeRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: legacy_request is null"; + return false; + } + *legacy_request = {}; + + legacy_request->subscribe_id = aidl_request.baseConfigs.sessionId; + legacy_request->ttl = aidl_request.baseConfigs.ttlSec; + legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod; + legacy_request->subscribe_count = aidl_request.baseConfigs.discoveryCount; + legacy_request->service_name_len = aidl_request.baseConfigs.serviceName.size(); + if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "service_name_len too large"; + return false; + } + memcpy(legacy_request->service_name, aidl_request.baseConfigs.serviceName.data(), + legacy_request->service_name_len); + legacy_request->subscribe_match_indicator = + convertAidlNanMatchAlgToLegacy(aidl_request.baseConfigs.discoveryMatchIndicator); + legacy_request->service_specific_info_len = aidl_request.baseConfigs.serviceSpecificInfo.size(); + if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->service_specific_info, + aidl_request.baseConfigs.serviceSpecificInfo.data(), + legacy_request->service_specific_info_len); + legacy_request->sdea_service_specific_info_len = + aidl_request.baseConfigs.extendedServiceSpecificInfo.size(); + if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "sdea_service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->sdea_service_specific_info, + aidl_request.baseConfigs.extendedServiceSpecificInfo.data(), + legacy_request->sdea_service_specific_info_len); + legacy_request->rx_match_filter_len = aidl_request.baseConfigs.rxMatchFilter.size(); + if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "rx_match_filter_len too large"; + return false; + } + memcpy(legacy_request->rx_match_filter, aidl_request.baseConfigs.rxMatchFilter.data(), + legacy_request->rx_match_filter_len); + legacy_request->tx_match_filter_len = aidl_request.baseConfigs.txMatchFilter.size(); + if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "tx_match_filter_len too large"; + return false; + } + memcpy(legacy_request->tx_match_filter, aidl_request.baseConfigs.txMatchFilter.data(), + legacy_request->tx_match_filter_len); + legacy_request->rssi_threshold_flag = aidl_request.baseConfigs.useRssiThreshold; + legacy_request->recv_indication_cfg = 0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0; + legacy_request->recv_indication_cfg |= + aidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0; + legacy_request->cipher_type = (unsigned int)aidl_request.baseConfigs.securityConfig.cipherType; + if (aidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK; + legacy_request->key_info.body.pmk_info.pmk_len = + aidl_request.baseConfigs.securityConfig.pmk.size(); + if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: invalid pmk_len"; + return false; + } + memcpy(legacy_request->key_info.body.pmk_info.pmk, + aidl_request.baseConfigs.securityConfig.pmk.data(), + legacy_request->key_info.body.pmk_info.pmk_len); + } + if (aidl_request.baseConfigs.securityConfig.securityType == + NanDataPathSecurityType::PASSPHRASE) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE; + legacy_request->key_info.body.passphrase_info.passphrase_len = + aidl_request.baseConfigs.securityConfig.passphrase.size(); + if (legacy_request->key_info.body.passphrase_info.passphrase_len < + NAN_SECURITY_MIN_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "passphrase_len too small"; + return false; + } + if (legacy_request->key_info.body.passphrase_info.passphrase_len > + NAN_SECURITY_MAX_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "passphrase_len too large"; + return false; + } + memcpy(legacy_request->key_info.body.passphrase_info.passphrase, + aidl_request.baseConfigs.securityConfig.passphrase.data(), + legacy_request->key_info.body.passphrase_info.passphrase_len); + } + legacy_request->sdea_params.security_cfg = + (aidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN) + ? legacy_hal::NAN_DP_CONFIG_SECURITY + : legacy_hal::NAN_DP_CONFIG_NO_SECURITY; + legacy_request->sdea_params.ranging_state = aidl_request.baseConfigs.rangingRequired + ? legacy_hal::NAN_RANGING_ENABLE + : legacy_hal::NAN_RANGING_DISABLE; + legacy_request->ranging_cfg.ranging_interval_msec = aidl_request.baseConfigs.rangingIntervalMs; + legacy_request->ranging_cfg.config_ranging_indications = + static_cast(aidl_request.baseConfigs.configRangingIndications); + legacy_request->ranging_cfg.distance_ingress_mm = + aidl_request.baseConfigs.distanceIngressCm * 10; + legacy_request->ranging_cfg.distance_egress_mm = aidl_request.baseConfigs.distanceEgressCm * 10; + legacy_request->ranging_auto_response = aidl_request.baseConfigs.rangingRequired + ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE + : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE; + legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT; + legacy_request->subscribe_type = + convertAidlNanSubscribeTypeToLegacy(aidl_request.subscribeType); + legacy_request->serviceResponseFilter = convertAidlNanSrfTypeToLegacy(aidl_request.srfType); + legacy_request->serviceResponseInclude = aidl_request.srfRespondIfInAddressSet + ? legacy_hal::NAN_SRF_INCLUDE_RESPOND + : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND; + legacy_request->useServiceResponseFilter = + aidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF; + legacy_request->ssiRequiredForMatchIndication = + aidl_request.isSsiRequiredForMatch ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND + : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND; + legacy_request->num_intf_addr_present = aidl_request.intfAddr.size(); + if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) { + LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: " + "num_intf_addr_present - too many"; + return false; + } + for (int i = 0; i < legacy_request->num_intf_addr_present; i++) { + memcpy(legacy_request->intf_addr[i], aidl_request.intfAddr[i].data.data(), 6); + } + + return true; +} + +bool convertAidlNanTransmitFollowupRequestToLegacy( + const NanTransmitFollowupRequest& aidl_request, + legacy_hal::NanTransmitFollowupRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: " + "legacy_request is null"; + return false; + } + *legacy_request = {}; + + legacy_request->publish_subscribe_id = aidl_request.discoverySessionId; + legacy_request->requestor_instance_id = aidl_request.peerId; + memcpy(legacy_request->addr, aidl_request.addr.data(), 6); + legacy_request->priority = aidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH + : legacy_hal::NAN_TX_PRIORITY_NORMAL; + legacy_request->dw_or_faw = aidl_request.shouldUseDiscoveryWindow + ? legacy_hal::NAN_TRANSMIT_IN_DW + : legacy_hal::NAN_TRANSMIT_IN_FAW; + legacy_request->service_specific_info_len = aidl_request.serviceSpecificInfo.size(); + if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: " + "service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->service_specific_info, aidl_request.serviceSpecificInfo.data(), + legacy_request->service_specific_info_len); + legacy_request->sdea_service_specific_info_len = + aidl_request.extendedServiceSpecificInfo.size(); + if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) { + LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: " + "sdea_service_specific_info_len too large"; + return false; + } + memcpy(legacy_request->sdea_service_specific_info, + aidl_request.extendedServiceSpecificInfo.data(), + legacy_request->sdea_service_specific_info_len); + legacy_request->recv_indication_cfg = aidl_request.disableFollowupResultIndication ? 0x1 : 0x0; + + return true; +} + +bool convertAidlNanDataPathInitiatorRequestToLegacy( + const NanInitiateDataPathRequest& aidl_request, + legacy_hal::NanDataPathInitiatorRequest* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "legacy_request is null"; + return false; + } + *legacy_request = {}; + + legacy_request->requestor_instance_id = aidl_request.peerId; + memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6); + legacy_request->channel_request_type = + convertAidlNanDataPathChannelCfgToLegacy(aidl_request.channelRequestType); + legacy_request->channel = aidl_request.channel; + if (strnlen(aidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "ifaceName too long"; + return false; + } + strlcpy(legacy_request->ndp_iface, aidl_request.ifaceName.c_str(), IFNAMSIZ + 1); + legacy_request->ndp_cfg.security_cfg = + (aidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN) + ? legacy_hal::NAN_DP_CONFIG_SECURITY + : legacy_hal::NAN_DP_CONFIG_NO_SECURITY; + legacy_request->app_info.ndp_app_info_len = aidl_request.appInfo.size(); + if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "ndp_app_info_len too large"; + return false; + } + memcpy(legacy_request->app_info.ndp_app_info, aidl_request.appInfo.data(), + legacy_request->app_info.ndp_app_info_len); + legacy_request->cipher_type = (unsigned int)aidl_request.securityConfig.cipherType; + if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK; + legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size(); + if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "invalid pmk_len"; + return false; + } + memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(), + legacy_request->key_info.body.pmk_info.pmk_len); + } + if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE; + legacy_request->key_info.body.passphrase_info.passphrase_len = + aidl_request.securityConfig.passphrase.size(); + if (legacy_request->key_info.body.passphrase_info.passphrase_len < + NAN_SECURITY_MIN_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "passphrase_len too small"; + return false; + } + if (legacy_request->key_info.body.passphrase_info.passphrase_len > + NAN_SECURITY_MAX_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "passphrase_len too large"; + return false; + } + memcpy(legacy_request->key_info.body.passphrase_info.passphrase, + aidl_request.securityConfig.passphrase.data(), + legacy_request->key_info.body.passphrase_info.passphrase_len); + } + legacy_request->service_name_len = aidl_request.serviceNameOutOfBand.size(); + if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: " + "service_name_len too large"; + return false; + } + memcpy(legacy_request->service_name, aidl_request.serviceNameOutOfBand.data(), + legacy_request->service_name_len); + legacy_request->scid_len = aidl_request.securityConfig.scid.size(); + if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) { + LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: scid_len too large"; + return false; + } + memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len); + + return true; +} + +bool convertAidlNanDataPathIndicationResponseToLegacy( + const NanRespondToDataPathIndicationRequest& aidl_request, + legacy_hal::NanDataPathIndicationResponse* legacy_request) { + if (!legacy_request) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "legacy_request is null"; + return false; + } + *legacy_request = {}; + + legacy_request->rsp_code = aidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT + : legacy_hal::NAN_DP_REQUEST_REJECT; + legacy_request->ndp_instance_id = aidl_request.ndpInstanceId; + if (strnlen(aidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "ifaceName too long"; + return false; + } + strlcpy(legacy_request->ndp_iface, aidl_request.ifaceName.c_str(), IFNAMSIZ + 1); + legacy_request->ndp_cfg.security_cfg = + (aidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN) + ? legacy_hal::NAN_DP_CONFIG_SECURITY + : legacy_hal::NAN_DP_CONFIG_NO_SECURITY; + legacy_request->app_info.ndp_app_info_len = aidl_request.appInfo.size(); + if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "ndp_app_info_len too large"; + return false; + } + memcpy(legacy_request->app_info.ndp_app_info, aidl_request.appInfo.data(), + legacy_request->app_info.ndp_app_info_len); + legacy_request->cipher_type = (unsigned int)aidl_request.securityConfig.cipherType; + if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK; + legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size(); + if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "invalid pmk_len"; + return false; + } + memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(), + legacy_request->key_info.body.pmk_info.pmk_len); + } + if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) { + legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE; + legacy_request->key_info.body.passphrase_info.passphrase_len = + aidl_request.securityConfig.passphrase.size(); + if (legacy_request->key_info.body.passphrase_info.passphrase_len < + NAN_SECURITY_MIN_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "passphrase_len too small"; + return false; + } + if (legacy_request->key_info.body.passphrase_info.passphrase_len > + NAN_SECURITY_MAX_PASSPHRASE_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "passphrase_len too large"; + return false; + } + memcpy(legacy_request->key_info.body.passphrase_info.passphrase, + aidl_request.securityConfig.passphrase.data(), + legacy_request->key_info.body.passphrase_info.passphrase_len); + } + legacy_request->service_name_len = aidl_request.serviceNameOutOfBand.size(); + if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: " + "service_name_len too large"; + return false; + } + memcpy(legacy_request->service_name, aidl_request.serviceNameOutOfBand.data(), + legacy_request->service_name_len); + legacy_request->scid_len = aidl_request.securityConfig.scid.size(); + if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) { + LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: scid_len too large"; + return false; + } + memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len); + + return true; +} + +bool convertLegacyNanResponseHeaderToAidl(const legacy_hal::NanResponseMsg& legacy_response, + NanStatus* nanStatus) { + if (!nanStatus) { + LOG(ERROR) << "convertLegacyNanResponseHeaderToAidl: nanStatus is null"; + return false; + } + *nanStatus = {}; + + convertToNanStatus(legacy_response.status, legacy_response.nan_error, + sizeof(legacy_response.nan_error), nanStatus); + return true; +} + +bool convertLegacyNanCapabilitiesResponseToAidl(const legacy_hal::NanCapabilities& legacy_response, + NanCapabilities* aidl_response) { + if (!aidl_response) { + LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToAidl: " + "aidl_response is null"; + return false; + } + *aidl_response = {}; + + aidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters; + aidl_response->maxPublishes = legacy_response.max_publishes; + aidl_response->maxSubscribes = legacy_response.max_subscribes; + aidl_response->maxServiceNameLen = legacy_response.max_service_name_len; + aidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len; + aidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len; + aidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len; + aidl_response->maxExtendedServiceSpecificInfoLen = + legacy_response.max_sdea_service_specific_info_len; + aidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces; + aidl_response->maxNdpSessions = legacy_response.max_ndp_sessions; + aidl_response->maxAppInfoLen = legacy_response.max_app_info_len; + aidl_response->maxQueuedTransmitFollowupMsgs = + legacy_response.max_queued_transmit_followup_msgs; + aidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address; + aidl_response->supportedCipherSuites = + static_cast(legacy_response.cipher_suites_supported); + aidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported; + + return true; +} + +bool convertLegacyNanMatchIndToAidl(const legacy_hal::NanMatchInd& legacy_ind, + NanMatchInd* aidl_ind) { + if (!aidl_ind) { + LOG(ERROR) << "convertLegacyNanMatchIndToAidl: aidl_ind is null"; + return false; + } + *aidl_ind = {}; + + aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id; + aidl_ind->peerId = legacy_ind.requestor_instance_id; + aidl_ind->addr = std::array(); + std::copy(legacy_ind.addr, legacy_ind.addr + 6, std::begin(aidl_ind->addr)); + aidl_ind->serviceSpecificInfo = std::vector( + legacy_ind.service_specific_info, + legacy_ind.service_specific_info + legacy_ind.service_specific_info_len); + aidl_ind->extendedServiceSpecificInfo = std::vector( + legacy_ind.sdea_service_specific_info, + legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len); + aidl_ind->matchFilter = + std::vector(legacy_ind.sdf_match_filter, + legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len); + aidl_ind->matchOccurredInBeaconFlag = legacy_ind.match_occured_flag == 1; // NOTYPO + aidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1; + aidl_ind->rssiValue = legacy_ind.rssi_value; + aidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type; + aidl_ind->peerRequiresSecurityEnabledInNdp = + legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY; + aidl_ind->peerRequiresRanging = + legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE; + aidl_ind->rangingMeasurementInMm = legacy_ind.range_info.range_measurement_mm; + aidl_ind->rangingIndicationType = + static_cast(legacy_ind.range_info.ranging_event_type); + aidl_ind->scid = std::vector(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len); + return true; +} + +bool convertLegacyNanFollowupIndToAidl(const legacy_hal::NanFollowupInd& legacy_ind, + NanFollowupReceivedInd* aidl_ind) { + if (!aidl_ind) { + LOG(ERROR) << "convertLegacyNanFollowupIndToAidl: aidl_ind is null"; + return false; + } + *aidl_ind = {}; + + aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id; + aidl_ind->peerId = legacy_ind.requestor_instance_id; + aidl_ind->addr = std::array(); + std::copy(legacy_ind.addr, legacy_ind.addr + 6, std::begin(aidl_ind->addr)); + aidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1; + aidl_ind->serviceSpecificInfo = std::vector( + legacy_ind.service_specific_info, + legacy_ind.service_specific_info + legacy_ind.service_specific_info_len); + aidl_ind->extendedServiceSpecificInfo = std::vector( + legacy_ind.sdea_service_specific_info, + legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len); + + return true; +} + +bool convertLegacyNanDataPathRequestIndToAidl(const legacy_hal::NanDataPathRequestInd& legacy_ind, + NanDataPathRequestInd* aidl_ind) { + if (!aidl_ind) { + LOG(ERROR) << "convertLegacyNanDataPathRequestIndToAidl: aidl_ind is null"; + return false; + } + *aidl_ind = {}; + + aidl_ind->discoverySessionId = legacy_ind.service_instance_id; + aidl_ind->peerDiscMacAddr = std::array(); + std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6, + std::begin(aidl_ind->peerDiscMacAddr)); + aidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id; + aidl_ind->securityRequired = + legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY; + aidl_ind->appInfo = std::vector( + legacy_ind.app_info.ndp_app_info, + legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len); + + return true; +} + +bool convertLegacyNdpChannelInfoToAidl(const legacy_hal::NanChannelInfo& legacy_struct, + NanDataPathChannelInfo* aidl_struct) { + if (!aidl_struct) { + LOG(ERROR) << "convertLegacyNdpChannelInfoToAidl: aidl_struct is null"; + return false; + } + *aidl_struct = {}; + + aidl_struct->channelFreq = legacy_struct.channel; + aidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToAidl( + (legacy_hal::wifi_channel_width)legacy_struct.bandwidth); + aidl_struct->numSpatialStreams = legacy_struct.nss; + + return true; +} + +bool convertLegacyNanDataPathConfirmIndToAidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind, + NanDataPathConfirmInd* aidl_ind) { + if (!aidl_ind) { + LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToAidl: aidl_ind is null"; + return false; + } + *aidl_ind = {}; + + aidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id; + aidl_ind->dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT; + aidl_ind->peerNdiMacAddr = std::array(); + std::copy(legacy_ind.peer_ndi_mac_addr, legacy_ind.peer_ndi_mac_addr + 6, + std::begin(aidl_ind->peerNdiMacAddr)); + aidl_ind->appInfo = std::vector( + legacy_ind.app_info.ndp_app_info, + legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len); + aidl_ind->status.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code); + aidl_ind->status.description = ""; + + std::vector channelInfo; + for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) { + NanDataPathChannelInfo aidl_struct; + if (!convertLegacyNdpChannelInfoToAidl(legacy_ind.channel_info[i], &aidl_struct)) { + return false; + } + channelInfo.push_back(aidl_struct); + } + aidl_ind->channelInfo = channelInfo; + + return true; +} + +bool convertLegacyNanDataPathScheduleUpdateIndToAidl( + const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind, + NanDataPathScheduleUpdateInd* aidl_ind) { + if (!aidl_ind) { + LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToAidl: " + "aidl_ind is null"; + return false; + } + *aidl_ind = {}; + + aidl_ind->peerDiscoveryAddress = std::array(); + std::copy(legacy_ind.peer_mac_addr, legacy_ind.peer_mac_addr + 6, + std::begin(aidl_ind->peerDiscoveryAddress)); + std::vector channelInfo; + for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) { + NanDataPathChannelInfo aidl_struct; + if (!convertLegacyNdpChannelInfoToAidl(legacy_ind.channel_info[i], &aidl_struct)) { + return false; + } + channelInfo.push_back(aidl_struct); + } + aidl_ind->channelInfo = channelInfo; + std::vector ndpInstanceIds; + for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) { + ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]); + } + aidl_ind->ndpInstanceIds = uintToIntVec(ndpInstanceIds); + + return true; +} + +legacy_hal::wifi_rtt_type convertAidlRttTypeToLegacy(RttType type) { + switch (type) { + case RttType::ONE_SIDED: + return legacy_hal::RTT_TYPE_1_SIDED; + case RttType::TWO_SIDED: + return legacy_hal::RTT_TYPE_2_SIDED; + }; + CHECK(false); +} + +RttType convertLegacyRttTypeToAidl(legacy_hal::wifi_rtt_type type) { + switch (type) { + case legacy_hal::RTT_TYPE_1_SIDED: + return RttType::ONE_SIDED; + case legacy_hal::RTT_TYPE_2_SIDED: + return RttType::TWO_SIDED; + }; + CHECK(false) << "Unknown legacy type: " << type; +} + +legacy_hal::rtt_peer_type convertAidlRttPeerTypeToLegacy(RttPeerType type) { + switch (type) { + case RttPeerType::AP: + return legacy_hal::RTT_PEER_AP; + case RttPeerType::STA: + return legacy_hal::RTT_PEER_STA; + case RttPeerType::P2P_GO: + return legacy_hal::RTT_PEER_P2P_GO; + case RttPeerType::P2P_CLIENT: + return legacy_hal::RTT_PEER_P2P_CLIENT; + case RttPeerType::NAN_TYPE: + return legacy_hal::RTT_PEER_NAN; + }; + CHECK(false); +} + +legacy_hal::wifi_channel_width convertAidlWifiChannelWidthToLegacy(WifiChannelWidthInMhz type) { + switch (type) { + case WifiChannelWidthInMhz::WIDTH_20: + return legacy_hal::WIFI_CHAN_WIDTH_20; + case WifiChannelWidthInMhz::WIDTH_40: + return legacy_hal::WIFI_CHAN_WIDTH_40; + case WifiChannelWidthInMhz::WIDTH_80: + return legacy_hal::WIFI_CHAN_WIDTH_80; + case WifiChannelWidthInMhz::WIDTH_160: + return legacy_hal::WIFI_CHAN_WIDTH_160; + case WifiChannelWidthInMhz::WIDTH_80P80: + return legacy_hal::WIFI_CHAN_WIDTH_80P80; + case WifiChannelWidthInMhz::WIDTH_5: + return legacy_hal::WIFI_CHAN_WIDTH_5; + case WifiChannelWidthInMhz::WIDTH_10: + return legacy_hal::WIFI_CHAN_WIDTH_10; + case WifiChannelWidthInMhz::WIDTH_320: + return legacy_hal::WIFI_CHAN_WIDTH_320; + case WifiChannelWidthInMhz::WIDTH_INVALID: + return legacy_hal::WIFI_CHAN_WIDTH_INVALID; + }; + CHECK(false); +} + +WifiChannelWidthInMhz convertLegacyWifiChannelWidthToAidl(legacy_hal::wifi_channel_width type) { + switch (type) { + case legacy_hal::WIFI_CHAN_WIDTH_20: + return WifiChannelWidthInMhz::WIDTH_20; + case legacy_hal::WIFI_CHAN_WIDTH_40: + return WifiChannelWidthInMhz::WIDTH_40; + case legacy_hal::WIFI_CHAN_WIDTH_80: + return WifiChannelWidthInMhz::WIDTH_80; + case legacy_hal::WIFI_CHAN_WIDTH_160: + return WifiChannelWidthInMhz::WIDTH_160; + case legacy_hal::WIFI_CHAN_WIDTH_80P80: + return WifiChannelWidthInMhz::WIDTH_80P80; + case legacy_hal::WIFI_CHAN_WIDTH_5: + return WifiChannelWidthInMhz::WIDTH_5; + case legacy_hal::WIFI_CHAN_WIDTH_10: + return WifiChannelWidthInMhz::WIDTH_10; + case legacy_hal::WIFI_CHAN_WIDTH_320: + return WifiChannelWidthInMhz::WIDTH_320; + default: + return WifiChannelWidthInMhz::WIDTH_INVALID; + }; +} + +legacy_hal::wifi_rtt_preamble convertAidlRttPreambleToLegacy(RttPreamble type) { + switch (type) { + case RttPreamble::LEGACY: + return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY; + case RttPreamble::HT: + return legacy_hal::WIFI_RTT_PREAMBLE_HT; + case RttPreamble::VHT: + return legacy_hal::WIFI_RTT_PREAMBLE_VHT; + case RttPreamble::HE: + return legacy_hal::WIFI_RTT_PREAMBLE_HE; + case RttPreamble::EHT: + return legacy_hal::WIFI_RTT_PREAMBLE_EHT; + }; + CHECK(false); +} + +RttPreamble convertLegacyRttPreambleToAidl(legacy_hal::wifi_rtt_preamble type) { + switch (type) { + case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY: + return RttPreamble::LEGACY; + case legacy_hal::WIFI_RTT_PREAMBLE_HT: + return RttPreamble::HT; + case legacy_hal::WIFI_RTT_PREAMBLE_VHT: + return RttPreamble::VHT; + case legacy_hal::WIFI_RTT_PREAMBLE_HE: + return RttPreamble::HE; + case legacy_hal::WIFI_RTT_PREAMBLE_EHT: + return RttPreamble::EHT; + }; + CHECK(false) << "Unknown legacy type: " << type; +} + +legacy_hal::wifi_rtt_bw convertAidlRttBwToLegacy(RttBw type) { + switch (type) { + case RttBw::BW_5MHZ: + return legacy_hal::WIFI_RTT_BW_5; + case RttBw::BW_10MHZ: + return legacy_hal::WIFI_RTT_BW_10; + case RttBw::BW_20MHZ: + return legacy_hal::WIFI_RTT_BW_20; + case RttBw::BW_40MHZ: + return legacy_hal::WIFI_RTT_BW_40; + case RttBw::BW_80MHZ: + return legacy_hal::WIFI_RTT_BW_80; + case RttBw::BW_160MHZ: + return legacy_hal::WIFI_RTT_BW_160; + case RttBw::BW_320MHZ: + return legacy_hal::WIFI_RTT_BW_320; + }; + CHECK(false); +} + +RttBw convertLegacyRttBwToAidl(legacy_hal::wifi_rtt_bw type) { + switch (type) { + case legacy_hal::WIFI_RTT_BW_5: + return RttBw::BW_5MHZ; + case legacy_hal::WIFI_RTT_BW_10: + return RttBw::BW_10MHZ; + case legacy_hal::WIFI_RTT_BW_20: + return RttBw::BW_20MHZ; + case legacy_hal::WIFI_RTT_BW_40: + return RttBw::BW_40MHZ; + case legacy_hal::WIFI_RTT_BW_80: + return RttBw::BW_80MHZ; + case legacy_hal::WIFI_RTT_BW_160: + return RttBw::BW_160MHZ; + case legacy_hal::WIFI_RTT_BW_320: + return RttBw::BW_320MHZ; + }; + CHECK(false) << "Unknown legacy type: " << type; +} + +legacy_hal::wifi_motion_pattern convertAidlRttMotionPatternToLegacy(RttMotionPattern type) { + switch (type) { + case RttMotionPattern::NOT_EXPECTED: + return legacy_hal::WIFI_MOTION_NOT_EXPECTED; + case RttMotionPattern::EXPECTED: + return legacy_hal::WIFI_MOTION_EXPECTED; + case RttMotionPattern::UNKNOWN: + return legacy_hal::WIFI_MOTION_UNKNOWN; + }; + CHECK(false); +} + +WifiRatePreamble convertLegacyWifiRatePreambleToAidl(uint8_t preamble) { + switch (preamble) { + case 0: + return WifiRatePreamble::OFDM; + case 1: + return WifiRatePreamble::CCK; + case 2: + return WifiRatePreamble::HT; + case 3: + return WifiRatePreamble::VHT; + case 4: + return WifiRatePreamble::HE; + case 5: + return WifiRatePreamble::EHT; + default: + return WifiRatePreamble::RESERVED; + }; + CHECK(false) << "Unknown legacy preamble: " << preamble; +} + +WifiRateNss convertLegacyWifiRateNssToAidl(uint8_t nss) { + switch (nss) { + case 0: + return WifiRateNss::NSS_1x1; + case 1: + return WifiRateNss::NSS_2x2; + case 2: + return WifiRateNss::NSS_3x3; + case 3: + return WifiRateNss::NSS_4x4; + }; + CHECK(false) << "Unknown legacy nss: " << nss; + return {}; +} + +RttStatus convertLegacyRttStatusToAidl(legacy_hal::wifi_rtt_status status) { + switch (status) { + case legacy_hal::RTT_STATUS_SUCCESS: + return RttStatus::SUCCESS; + case legacy_hal::RTT_STATUS_FAILURE: + return RttStatus::FAILURE; + case legacy_hal::RTT_STATUS_FAIL_NO_RSP: + return RttStatus::FAIL_NO_RSP; + case legacy_hal::RTT_STATUS_FAIL_REJECTED: + return RttStatus::FAIL_REJECTED; + case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET: + return RttStatus::FAIL_NOT_SCHEDULED_YET; + case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT: + return RttStatus::FAIL_TM_TIMEOUT; + case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL: + return RttStatus::FAIL_AP_ON_DIFF_CHANNEL; + case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY: + return RttStatus::FAIL_NO_CAPABILITY; + case legacy_hal::RTT_STATUS_ABORTED: + return RttStatus::ABORTED; + case legacy_hal::RTT_STATUS_FAIL_INVALID_TS: + return RttStatus::FAIL_INVALID_TS; + case legacy_hal::RTT_STATUS_FAIL_PROTOCOL: + return RttStatus::FAIL_PROTOCOL; + case legacy_hal::RTT_STATUS_FAIL_SCHEDULE: + return RttStatus::FAIL_SCHEDULE; + case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER: + return RttStatus::FAIL_BUSY_TRY_LATER; + case legacy_hal::RTT_STATUS_INVALID_REQ: + return RttStatus::INVALID_REQ; + case legacy_hal::RTT_STATUS_NO_WIFI: + return RttStatus::NO_WIFI; + case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE: + return RttStatus::FAIL_FTM_PARAM_OVERRIDE; + case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE: + return RttStatus::NAN_RANGING_PROTOCOL_FAILURE; + case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED: + return RttStatus::NAN_RANGING_CONCURRENCY_NOT_SUPPORTED; + }; + CHECK(false) << "Unknown legacy status: " << status; +} + +bool convertAidlWifiChannelInfoToLegacy(const WifiChannelInfo& aidl_info, + legacy_hal::wifi_channel_info* legacy_info) { + if (!legacy_info) { + return false; + } + *legacy_info = {}; + legacy_info->width = convertAidlWifiChannelWidthToLegacy(aidl_info.width); + legacy_info->center_freq = aidl_info.centerFreq; + legacy_info->center_freq0 = aidl_info.centerFreq0; + legacy_info->center_freq1 = aidl_info.centerFreq1; + return true; +} + +bool convertLegacyWifiChannelInfoToAidl(const legacy_hal::wifi_channel_info& legacy_info, + WifiChannelInfo* aidl_info) { + if (!aidl_info) { + return false; + } + *aidl_info = {}; + aidl_info->width = convertLegacyWifiChannelWidthToAidl(legacy_info.width); + aidl_info->centerFreq = legacy_info.center_freq; + aidl_info->centerFreq0 = legacy_info.center_freq0; + aidl_info->centerFreq1 = legacy_info.center_freq1; + return true; +} + +bool convertAidlRttConfigToLegacy(const RttConfig& aidl_config, + legacy_hal::wifi_rtt_config* legacy_config) { + if (!legacy_config) { + return false; + } + *legacy_config = {}; + CHECK(aidl_config.addr.size() == sizeof(legacy_config->addr)); + memcpy(legacy_config->addr, aidl_config.addr.data(), aidl_config.addr.size()); + legacy_config->type = convertAidlRttTypeToLegacy(aidl_config.type); + legacy_config->peer = convertAidlRttPeerTypeToLegacy(aidl_config.peer); + if (!convertAidlWifiChannelInfoToLegacy(aidl_config.channel, &legacy_config->channel)) { + return false; + } + legacy_config->burst_period = aidl_config.burstPeriod; + legacy_config->num_burst = aidl_config.numBurst; + legacy_config->num_frames_per_burst = aidl_config.numFramesPerBurst; + legacy_config->num_retries_per_rtt_frame = aidl_config.numRetriesPerRttFrame; + legacy_config->num_retries_per_ftmr = aidl_config.numRetriesPerFtmr; + legacy_config->LCI_request = aidl_config.mustRequestLci; + legacy_config->LCR_request = aidl_config.mustRequestLcr; + legacy_config->burst_duration = aidl_config.burstDuration; + legacy_config->preamble = convertAidlRttPreambleToLegacy(aidl_config.preamble); + legacy_config->bw = convertAidlRttBwToLegacy(aidl_config.bw); + return true; +} + +bool convertAidlVectorOfRttConfigToLegacy( + const std::vector& aidl_configs, + std::vector* legacy_configs) { + if (!legacy_configs) { + return false; + } + *legacy_configs = {}; + for (const auto& aidl_config : aidl_configs) { + legacy_hal::wifi_rtt_config legacy_config; + if (!convertAidlRttConfigToLegacy(aidl_config, &legacy_config)) { + return false; + } + legacy_configs->push_back(legacy_config); + } + return true; +} + +bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info, + legacy_hal::wifi_lci_information* legacy_info) { + if (!legacy_info) { + return false; + } + *legacy_info = {}; + legacy_info->latitude = aidl_info.latitude; + legacy_info->longitude = aidl_info.longitude; + legacy_info->altitude = aidl_info.altitude; + legacy_info->latitude_unc = aidl_info.latitudeUnc; + legacy_info->longitude_unc = aidl_info.longitudeUnc; + legacy_info->altitude_unc = aidl_info.altitudeUnc; + legacy_info->motion_pattern = convertAidlRttMotionPatternToLegacy(aidl_info.motionPattern); + legacy_info->floor = aidl_info.floor; + legacy_info->height_above_floor = aidl_info.heightAboveFloor; + legacy_info->height_unc = aidl_info.heightUnc; + return true; +} + +bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info, + legacy_hal::wifi_lcr_information* legacy_info) { + if (!legacy_info) { + return false; + } + *legacy_info = {}; + CHECK(aidl_info.countryCode.size() == sizeof(legacy_info->country_code)); + memcpy(legacy_info->country_code, aidl_info.countryCode.data(), aidl_info.countryCode.size()); + if (aidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) { + return false; + } + legacy_info->length = aidl_info.civicInfo.size(); + memcpy(legacy_info->civic_info, aidl_info.civicInfo.c_str(), aidl_info.civicInfo.size()); + return true; +} + +bool convertAidlRttResponderToLegacy(const RttResponder& aidl_responder, + legacy_hal::wifi_rtt_responder* legacy_responder) { + if (!legacy_responder) { + return false; + } + *legacy_responder = {}; + if (!convertAidlWifiChannelInfoToLegacy(aidl_responder.channel, &legacy_responder->channel)) { + return false; + } + legacy_responder->preamble = convertAidlRttPreambleToLegacy(aidl_responder.preamble); + return true; +} + +bool convertLegacyRttResponderToAidl(const legacy_hal::wifi_rtt_responder& legacy_responder, + RttResponder* aidl_responder) { + if (!aidl_responder) { + return false; + } + *aidl_responder = {}; + if (!convertLegacyWifiChannelInfoToAidl(legacy_responder.channel, &aidl_responder->channel)) { + return false; + } + aidl_responder->preamble = convertLegacyRttPreambleToAidl(legacy_responder.preamble); + return true; +} + +bool convertLegacyRttCapabilitiesToAidl( + const legacy_hal::wifi_rtt_capabilities& legacy_capabilities, + RttCapabilities* aidl_capabilities) { + if (!aidl_capabilities) { + return false; + } + *aidl_capabilities = {}; + aidl_capabilities->rttOneSidedSupported = legacy_capabilities.rtt_one_sided_supported; + aidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported; + aidl_capabilities->lciSupported = legacy_capabilities.lci_support; + aidl_capabilities->lcrSupported = legacy_capabilities.lcr_support; + aidl_capabilities->responderSupported = legacy_capabilities.responder_supported; + int32_t preambleSupport = 0; + for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT, + legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE, + legacy_hal::WIFI_RTT_PREAMBLE_EHT}) { + if (legacy_capabilities.preamble_support & flag) { + preambleSupport |= static_cast::type>( + convertLegacyRttPreambleToAidl(flag)); + } + } + aidl_capabilities->preambleSupport = static_cast(preambleSupport); + int32_t bwSupport = 0; + for (const auto flag : + {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20, + legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160, + legacy_hal::WIFI_RTT_BW_320}) { + if (legacy_capabilities.bw_support & flag) { + bwSupport |= + static_cast::type>(convertLegacyRttBwToAidl(flag)); + } + } + aidl_capabilities->bwSupport = static_cast(bwSupport); + aidl_capabilities->mcVersion = legacy_capabilities.mc_version; + return true; +} + +bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate, + WifiRateInfo* aidl_rate) { + if (!aidl_rate) { + return false; + } + *aidl_rate = {}; + aidl_rate->preamble = convertLegacyWifiRatePreambleToAidl(legacy_rate.preamble); + aidl_rate->nss = convertLegacyWifiRateNssToAidl(legacy_rate.nss); + aidl_rate->bw = convertLegacyWifiChannelWidthToAidl( + static_cast(legacy_rate.bw)); + aidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx; + aidl_rate->bitRateInKbps = legacy_rate.bitrate; + return true; +} + +bool convertLegacyRttResultToAidl(const legacy_hal::wifi_rtt_result& legacy_result, + RttResult* aidl_result) { + if (!aidl_result) { + return false; + } + *aidl_result = {}; + aidl_result->addr = std::array(); + CHECK(sizeof(legacy_result.addr) == aidl_result->addr.size()); + std::copy(legacy_result.addr, legacy_result.addr + 6, std::begin(aidl_result->addr)); + aidl_result->burstNum = legacy_result.burst_num; + aidl_result->measurementNumber = legacy_result.measurement_number; + aidl_result->successNumber = legacy_result.success_number; + aidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer; + aidl_result->status = convertLegacyRttStatusToAidl(legacy_result.status); + aidl_result->retryAfterDuration = legacy_result.retry_after_duration; + aidl_result->type = convertLegacyRttTypeToAidl(legacy_result.type); + aidl_result->rssi = legacy_result.rssi; + aidl_result->rssiSpread = legacy_result.rssi_spread; + if (!convertLegacyWifiRateInfoToAidl(legacy_result.tx_rate, &aidl_result->txRate)) { + return false; + } + if (!convertLegacyWifiRateInfoToAidl(legacy_result.rx_rate, &aidl_result->rxRate)) { + return false; + } + aidl_result->rtt = legacy_result.rtt; + aidl_result->rttSd = legacy_result.rtt_sd; + aidl_result->rttSpread = legacy_result.rtt_spread; + aidl_result->distanceInMm = legacy_result.distance_mm; + aidl_result->distanceSdInMm = legacy_result.distance_sd_mm; + aidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm; + aidl_result->timeStampInUs = legacy_result.ts; + aidl_result->burstDurationInMs = legacy_result.burst_duration; + aidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num; + if (legacy_result.LCI && !convertLegacyIeToAidl(*legacy_result.LCI, &aidl_result->lci)) { + return false; + } + if (legacy_result.LCR && !convertLegacyIeToAidl(*legacy_result.LCR, &aidl_result->lcr)) { + return false; + } + return true; +} + +bool convertLegacyVectorOfRttResultToAidl( + const std::vector& legacy_results, + std::vector* aidl_results) { + if (!aidl_results) { + return false; + } + *aidl_results = {}; + for (const auto legacy_result : legacy_results) { + RttResult aidl_result; + if (!convertLegacyRttResultToAidl(*legacy_result, &aidl_result)) { + return false; + } + aidl_results->push_back(aidl_result); + } + return true; +} + +legacy_hal::wifi_interface_type convertAidlIfaceTypeToLegacy(IfaceType aidl_interface_type) { + switch (aidl_interface_type) { + case IfaceType::STA: + return legacy_hal::WIFI_INTERFACE_TYPE_STA; + case IfaceType::AP: + return legacy_hal::WIFI_INTERFACE_TYPE_AP; + case IfaceType::P2P: + return legacy_hal::WIFI_INTERFACE_TYPE_P2P; + case IfaceType::NAN_IFACE: + return legacy_hal::WIFI_INTERFACE_TYPE_NAN; + } + CHECK(false); +} + +legacy_hal::wifi_multi_sta_use_case convertAidlMultiStaUseCaseToLegacy( + IWifiChip::MultiStaUseCase use_case) { + switch (use_case) { + case IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY: + return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY; + case IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED: + return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED; + } + CHECK(false); +} + +bool convertAidlCoexUnsafeChannelToLegacy( + const IWifiChip::CoexUnsafeChannel& aidl_unsafe_channel, + legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) { + if (!legacy_unsafe_channel) { + return false; + } + *legacy_unsafe_channel = {}; + switch (aidl_unsafe_channel.band) { + case WifiBand::BAND_24GHZ: + legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND; + break; + case WifiBand::BAND_5GHZ: + legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND; + break; + default: + return false; + }; + legacy_unsafe_channel->channel = aidl_unsafe_channel.channel; + legacy_unsafe_channel->power_cap_dbm = aidl_unsafe_channel.powerCapDbm; + return true; +} + +bool convertAidlVectorOfCoexUnsafeChannelToLegacy( + const std::vector& aidl_unsafe_channels, + std::vector* legacy_unsafe_channels) { + if (!legacy_unsafe_channels) { + return false; + } + *legacy_unsafe_channels = {}; + for (const auto& aidl_unsafe_channel : aidl_unsafe_channels) { + legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel; + if (!aidl_struct_util::convertAidlCoexUnsafeChannelToLegacy(aidl_unsafe_channel, + &legacy_unsafe_channel)) { + return false; + } + legacy_unsafe_channels->push_back(legacy_unsafe_channel); + } + return true; +} + +WifiAntennaMode convertLegacyAntennaConfigurationToAidl(uint32_t antenna_cfg) { + switch (antenna_cfg) { + case legacy_hal::WIFI_ANTENNA_1X1: + return WifiAntennaMode::WIFI_ANTENNA_MODE_1X1; + case legacy_hal::WIFI_ANTENNA_2X2: + return WifiAntennaMode::WIFI_ANTENNA_MODE_2X2; + case legacy_hal::WIFI_ANTENNA_3X3: + return WifiAntennaMode::WIFI_ANTENNA_MODE_3X3; + case legacy_hal::WIFI_ANTENNA_4X4: + return WifiAntennaMode::WIFI_ANTENNA_MODE_4X4; + default: + return WifiAntennaMode::WIFI_ANTENNA_MODE_UNSPECIFIED; + } +} + +bool convertLegacyWifiRadioConfigurationToAidl( + legacy_hal::wifi_radio_configuration* radio_configuration, + WifiRadioConfiguration* aidl_radio_configuration) { + if (!aidl_radio_configuration) { + return false; + } + *aidl_radio_configuration = {}; + aidl_radio_configuration->bandInfo = + aidl_struct_util::convertLegacyMacBandToAidlWifiBand(radio_configuration->band); + if (aidl_radio_configuration->bandInfo == WifiBand::BAND_UNSPECIFIED) { + LOG(ERROR) << "Unspecified band"; + return false; + } + aidl_radio_configuration->antennaMode = + aidl_struct_util::convertLegacyAntennaConfigurationToAidl( + radio_configuration->antenna_cfg); + return true; +} + +bool convertLegacyRadioCombinationsMatrixToAidl( + legacy_hal::wifi_radio_combination_matrix* legacy_matrix, + WifiRadioCombinationMatrix* aidl_matrix) { + if (!aidl_matrix || !legacy_matrix) { + return false; + } + *aidl_matrix = {}; + + int num_combinations = legacy_matrix->num_radio_combinations; + std::vector radio_combinations_vec; + if (!num_combinations) { + LOG(ERROR) << "zero radio combinations"; + return false; + } + wifi_radio_combination* l_radio_combinations_ptr = legacy_matrix->radio_combinations; + for (int i = 0; i < num_combinations; i++) { + int num_configurations = l_radio_combinations_ptr->num_radio_configurations; + WifiRadioCombination radioCombination; + std::vector radio_configurations_vec; + if (!num_configurations) { + LOG(ERROR) << "zero radio configurations"; + return false; + } + for (int j = 0; j < num_configurations; j++) { + WifiRadioConfiguration radioConfiguration; + wifi_radio_configuration* l_radio_configurations_ptr = + &l_radio_combinations_ptr->radio_configurations[j]; + if (!aidl_struct_util::convertLegacyWifiRadioConfigurationToAidl( + l_radio_configurations_ptr, &radioConfiguration)) { + LOG(ERROR) << "Error converting wifi radio configuration"; + return false; + } + radio_configurations_vec.push_back(radioConfiguration); + } + radioCombination.radioConfigurations = radio_configurations_vec; + radio_combinations_vec.push_back(radioCombination); + l_radio_combinations_ptr = + (wifi_radio_combination*)((u8*)l_radio_combinations_ptr + + sizeof(wifi_radio_combination) + + (sizeof(wifi_radio_configuration) * num_configurations)); + } + aidl_matrix->radioCombinations = radio_combinations_vec; + return true; +} + +} // namespace aidl_struct_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h new file mode 100644 index 0000000000..4ebfc10787 --- /dev/null +++ b/wifi/aidl/default/aidl_struct_util.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef AIDL_STRUCT_UTIL_H_ +#define AIDL_STRUCT_UTIL_H_ + +#include +#include +#include +#include + +#include + +#include "wifi_legacy_hal.h" + +/** + * This file contains a bunch of functions to convert structs from the legacy + * HAL to AIDL and vice versa. + */ +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_struct_util { + +// Chip conversion methods. +bool convertLegacyFeaturesToAidlChipCapabilities(uint64_t legacy_feature_set, + uint32_t legacy_logger_feature_set, + uint32_t* aidl_caps); +bool convertLegacyDebugRingBufferStatusToAidl( + const legacy_hal::wifi_ring_buffer_status& legacy_status, + WifiDebugRingBufferStatus* aidl_status); +bool convertLegacyVectorOfDebugRingBufferStatusToAidl( + const std::vector& legacy_status_vec, + std::vector* aidl_status_vec); +bool convertLegacyWakeReasonStatsToAidl(const legacy_hal::WakeReasonStats& legacy_stats, + WifiDebugHostWakeReasonStats* aidl_stats); +legacy_hal::wifi_power_scenario convertAidlTxPowerScenarioToLegacy( + IWifiChip::TxPowerScenario aidl_scenario); +legacy_hal::wifi_latency_mode convertAidlLatencyModeToLegacy( + IWifiChip::LatencyMode aidl_latency_mode); +bool convertLegacyWifiMacInfosToAidl( + const std::vector& legacy_mac_infos, + std::vector* aidl_radio_mode_infos); +legacy_hal::wifi_interface_type convertAidlIfaceTypeToLegacy(IfaceType aidl_interface_type); +legacy_hal::wifi_multi_sta_use_case convertAidlMultiStaUseCaseToLegacy( + IWifiChip::MultiStaUseCase use_case); +bool convertAidlCoexUnsafeChannelToLegacy( + const IWifiChip::CoexUnsafeChannel& aidl_unsafe_channel, + legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel); +bool convertAidlVectorOfCoexUnsafeChannelToLegacy( + const std::vector& aidl_unsafe_channels, + std::vector* legacy_unsafe_channels); +bool convertLegacyRadioCombinationsMatrixToAidl( + legacy_hal::wifi_radio_combination_matrix* legacy_matrix, + WifiRadioCombinationMatrix* aidl_matrix); +WifiBand convertLegacyMacBandToAidlWifiBand(uint32_t band); +WifiAntennaMode convertLegacyAntennaConfigurationToAidl(uint32_t antenna_cfg); + +// STA iface conversion methods. +bool convertLegacyFeaturesToAidlStaCapabilities(uint64_t legacy_feature_set, + uint32_t legacy_logger_feature_set, + uint32_t* aidl_caps); +bool convertLegacyApfCapabilitiesToAidl(const legacy_hal::PacketFilterCapabilities& legacy_caps, + StaApfPacketFilterCapabilities* aidl_caps); +bool convertLegacyGscanCapabilitiesToAidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps, + StaBackgroundScanCapabilities* aidl_caps); +legacy_hal::wifi_band convertAidlWifiBandToLegacy(WifiBand band); +bool convertAidlGscanParamsToLegacy(const StaBackgroundScanParameters& aidl_scan_params, + legacy_hal::wifi_scan_cmd_params* legacy_scan_params); +// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11 +// Information Elements (IEs) +bool convertLegacyGscanResultToAidl(const legacy_hal::wifi_scan_result& legacy_scan_result, + bool has_ie_data, StaScanResult* aidl_scan_result); +// |cached_results| is assumed to not include IEs. +bool convertLegacyVectorOfCachedGscanResultsToAidl( + const std::vector& legacy_cached_scan_results, + std::vector* aidl_scan_datas); +bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats, + StaLinkLayerStats* aidl_stats); +bool convertLegacyRoamingCapabilitiesToAidl( + const legacy_hal::wifi_roaming_capabilities& legacy_caps, + StaRoamingCapabilities* aidl_caps); +bool convertAidlRoamingConfigToLegacy(const StaRoamingConfig& aidl_config, + legacy_hal::wifi_roaming_config* legacy_config); +legacy_hal::fw_roaming_state_t convertAidlRoamingStateToLegacy(StaRoamingState state); +bool convertLegacyVectorOfDebugTxPacketFateToAidl( + const std::vector& legacy_fates, + std::vector* aidl_fates); +bool convertLegacyVectorOfDebugRxPacketFateToAidl( + const std::vector& legacy_fates, + std::vector* aidl_fates); + +// NAN iface conversion methods. +void convertToNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len, + NanStatus* nanStatus); +bool convertAidlNanEnableRequestToLegacy(const NanEnableRequest& aidl_request1, + const NanConfigRequestSupplemental& aidl_request2, + legacy_hal::NanEnableRequest* legacy_request); +bool convertAidlNanConfigRequestToLegacy(const NanConfigRequest& aidl_request1, + const NanConfigRequestSupplemental& aidl_request2, + legacy_hal::NanConfigRequest* legacy_request); +bool convertAidlNanPublishRequestToLegacy(const NanPublishRequest& aidl_request, + legacy_hal::NanPublishRequest* legacy_request); +bool convertAidlNanSubscribeRequestToLegacy(const NanSubscribeRequest& aidl_request, + legacy_hal::NanSubscribeRequest* legacy_request); +bool convertAidlNanTransmitFollowupRequestToLegacy( + const NanTransmitFollowupRequest& aidl_request, + legacy_hal::NanTransmitFollowupRequest* legacy_request); +bool convertAidlNanDataPathInitiatorRequestToLegacy( + const NanInitiateDataPathRequest& aidl_request, + legacy_hal::NanDataPathInitiatorRequest* legacy_request); +bool convertAidlNanDataPathIndicationResponseToLegacy( + const NanRespondToDataPathIndicationRequest& aidl_response, + legacy_hal::NanDataPathIndicationResponse* legacy_response); +bool convertLegacyNanResponseHeaderToAidl(const legacy_hal::NanResponseMsg& legacy_response, + NanStatus* nanStatus); +bool convertLegacyNanCapabilitiesResponseToAidl(const legacy_hal::NanCapabilities& legacy_response, + NanCapabilities* aidl_response); +bool convertLegacyNanMatchIndToAidl(const legacy_hal::NanMatchInd& legacy_ind, + NanMatchInd* aidl_ind); +bool convertLegacyNanFollowupIndToAidl(const legacy_hal::NanFollowupInd& legacy_ind, + NanFollowupReceivedInd* aidl_ind); +bool convertLegacyNanDataPathRequestIndToAidl(const legacy_hal::NanDataPathRequestInd& legacy_ind, + NanDataPathRequestInd* aidl_ind); +bool convertLegacyNanDataPathConfirmIndToAidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind, + NanDataPathConfirmInd* aidl_ind); +bool convertLegacyNanDataPathScheduleUpdateIndToAidl( + const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind, + NanDataPathScheduleUpdateInd* aidl_ind); + +// RTT controller conversion methods. +bool convertAidlVectorOfRttConfigToLegacy(const std::vector& aidl_configs, + std::vector* legacy_configs); +bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info, + legacy_hal::wifi_lci_information* legacy_info); +bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info, + legacy_hal::wifi_lcr_information* legacy_info); +bool convertAidlRttResponderToLegacy(const RttResponder& aidl_responder, + legacy_hal::wifi_rtt_responder* legacy_responder); +bool convertAidlWifiChannelInfoToLegacy(const WifiChannelInfo& aidl_info, + legacy_hal::wifi_channel_info* legacy_info); +bool convertLegacyRttResponderToAidl(const legacy_hal::wifi_rtt_responder& legacy_responder, + RttResponder* aidl_responder); +bool convertLegacyRttCapabilitiesToAidl( + const legacy_hal::wifi_rtt_capabilities& legacy_capabilities, + RttCapabilities* aidl_capabilities); +bool convertLegacyVectorOfRttResultToAidl( + const std::vector& legacy_results, + std::vector* aidl_results); +uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand band); +uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask); +uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask); +bool convertLegacyWifiUsableChannelsToAidl( + const std::vector& legacy_usable_channels, + std::vector* aidl_usable_channels); +bool convertLegacyPeerInfoStatsToAidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats, + StaPeerInfo* aidl_peer_info_stats); +bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate, + WifiRateInfo* aidl_rate); +} // namespace aidl_struct_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // AIDL_STRUCT_UTIL_H_ diff --git a/wifi/aidl/default/aidl_sync_util.cpp b/wifi/aidl/default/aidl_sync_util.cpp new file mode 100644 index 0000000000..d81eb81182 --- /dev/null +++ b/wifi/aidl/default/aidl_sync_util.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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 "aidl_sync_util.h" + +namespace { +std::recursive_mutex g_mutex; +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_sync_util { + +std::unique_lock acquireGlobalLock() { + return std::unique_lock{g_mutex}; +} + +} // namespace aidl_sync_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/aidl_sync_util.h b/wifi/aidl/default/aidl_sync_util.h new file mode 100644 index 0000000000..a61cd3f57c --- /dev/null +++ b/wifi/aidl/default/aidl_sync_util.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef AIDL_SYNC_UTIL_H_ +#define AIDL_SYNC_UTIL_H_ + +#include + +// Utility that provides a global lock to synchronize access between +// the AIDL thread and the legacy HAL's event loop. +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace aidl_sync_util { +std::unique_lock acquireGlobalLock(); +} // namespace aidl_sync_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl +#endif // AIDL_SYNC_UTIL_H_ diff --git a/wifi/aidl/default/android.hardware.wifi-service-lazy.rc b/wifi/aidl/default/android.hardware.wifi-service-lazy.rc new file mode 100644 index 0000000000..12d3ff7bde --- /dev/null +++ b/wifi/aidl/default/android.hardware.wifi-service-lazy.rc @@ -0,0 +1,8 @@ +service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service-lazy + interface aidl android.hardware.wifi.IWifi/default + oneshot + disabled + class hal + capabilities NET_ADMIN NET_RAW SYS_MODULE + user wifi + group wifi gps diff --git a/wifi/aidl/default/android.hardware.wifi-service.rc b/wifi/aidl/default/android.hardware.wifi-service.rc new file mode 100644 index 0000000000..ec8acf5767 --- /dev/null +++ b/wifi/aidl/default/android.hardware.wifi-service.rc @@ -0,0 +1,6 @@ +service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service + interface aidl android.hardware.wifi.IWifi/default + class hal + capabilities NET_ADMIN NET_RAW SYS_MODULE + user wifi + group wifi gps diff --git a/wifi/aidl/default/android.hardware.wifi-service.xml b/wifi/aidl/default/android.hardware.wifi-service.xml new file mode 100644 index 0000000000..5398ee77b5 --- /dev/null +++ b/wifi/aidl/default/android.hardware.wifi-service.xml @@ -0,0 +1,6 @@ + + + android.hardware.wifi + IWifi/default + + diff --git a/wifi/aidl/default/ringbuffer.cpp b/wifi/aidl/default/ringbuffer.cpp new file mode 100644 index 0000000000..9d08a7368e --- /dev/null +++ b/wifi/aidl/default/ringbuffer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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 "ringbuffer.h" + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {} + +enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector& input) { + if (input.size() == 0) { + return AppendStatus::FAIL_IP_BUFFER_ZERO; + } + if (input.size() > maxSize_) { + LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped"; + return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE; + } + data_.push_back(input); + size_ += input.size() * sizeof(input[0]); + while (size_ > maxSize_) { + if (data_.front().size() <= 0 || data_.front().size() > maxSize_) { + LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: " + << data_.front().size(); + return AppendStatus::FAIL_RING_BUFFER_CORRUPTED; + } + size_ -= data_.front().size() * sizeof(data_.front()[0]); + data_.pop_front(); + } + return AppendStatus::SUCCESS; +} + +const std::list>& Ringbuffer::getData() const { + return data_; +} + +void Ringbuffer::clear() { + data_.clear(); + size_ = 0; +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/ringbuffer.h b/wifi/aidl/default/ringbuffer.h new file mode 100644 index 0000000000..80c0c11045 --- /dev/null +++ b/wifi/aidl/default/ringbuffer.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef RINGBUFFER_H_ +#define RINGBUFFER_H_ + +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * Ringbuffer object used to store debug data. + */ +class Ringbuffer { + public: + // Error codes for the append ring buffer operation + enum AppendStatus { + SUCCESS, + FAIL_GENERIC, + FAIL_IP_BUFFER_ZERO, + FAIL_IP_BUFFER_EXCEEDED_MAXSIZE, + FAIL_RING_BUFFER_CORRUPTED + }; + explicit Ringbuffer(size_t maxSize); + + // Appends the data buffer and deletes from the front until buffer is + // within |maxSize_|. + enum AppendStatus append(const std::vector& input); + const std::list>& getData() const; + void clear(); + + private: + std::list> data_; + size_t size_; + size_t maxSize_; +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // RINGBUFFER_H_ diff --git a/wifi/aidl/default/service.cpp b/wifi/aidl/default/service.cpp new file mode 100644 index 0000000000..789a7a5868 --- /dev/null +++ b/wifi/aidl/default/service.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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 +#include +#include +#include + +#include "wifi.h" +#include "wifi_feature_flags.h" +#include "wifi_legacy_hal.h" +#include "wifi_legacy_hal_factory.h" +#include "wifi_mode_controller.h" + +using aidl::android::hardware::wifi::feature_flags::WifiFeatureFlags; +using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHal; +using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHalFactory; +using aidl::android::hardware::wifi::mode_controller::WifiModeController; + +#ifdef LAZY_SERVICE +const bool kLazyService = true; +#else +const bool kLazyService = false; +#endif + +int main(int /*argc*/, char** argv) { + signal(SIGPIPE, SIG_IGN); + android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); + LOG(INFO) << "Wifi Hal is booting up..."; + + // Prepare the RPC-serving thread pool. Allocate 1 thread in the pool, + // which our main thread will join below. + ABinderProcess_setThreadPoolMaxThreadCount(1); + + const auto iface_tool = std::make_shared<::android::wifi_system::InterfaceTool>(); + const auto legacy_hal_factory = std::make_shared(iface_tool); + + // Setup binder service + std::shared_ptr service = + ndk::SharedRefBase::make( + iface_tool, legacy_hal_factory, std::make_shared(), + std::make_shared()); + std::string instance = + std::string() + aidl::android::hardware::wifi::Wifi::descriptor + "/default"; + if (kLazyService) { + auto result = + AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str()); + CHECK_EQ(result, STATUS_OK) << "Failed to register lazy wifi HAL"; + } else { + auto result = AServiceManager_addService(service->asBinder().get(), instance.c_str()); + CHECK_EQ(result, STATUS_OK) << "Failed to register wifi HAL"; + } + + ABinderProcess_startThreadPool(); + LOG(INFO) << "Joining RPC thread pool"; + ABinderProcess_joinThreadPool(); + + LOG(INFO) << "Wifi Hal is terminating..."; + return 0; +} diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp new file mode 100644 index 0000000000..4a69c2426b --- /dev/null +++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "aidl_struct_util.h" + +using testing::Test; + +namespace { +constexpr uint32_t kMacId1 = 1; +constexpr uint32_t kMacId2 = 2; +constexpr uint32_t kIfaceChannel1 = 3; +constexpr uint32_t kIfaceChannel2 = 5; +constexpr char kIfaceName1[] = "wlan0"; +constexpr char kIfaceName2[] = "wlan1"; +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +class AidlStructUtilTest : public Test {}; + +TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithOneMac) { + std::vector legacy_mac_infos; + legacy_hal::WifiMacInfo legacy_mac_info1 = { + .wlan_mac_id = kMacId1, + .mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND}; + legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1}; + legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2}; + legacy_mac_info1.iface_infos.push_back(legacy_iface_info1); + legacy_mac_info1.iface_infos.push_back(legacy_iface_info2); + legacy_mac_infos.push_back(legacy_mac_info1); + + std::vector aidl_radio_mode_infos; + ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos, + &aidl_radio_mode_infos)); + + ASSERT_EQ(1u, aidl_radio_mode_infos.size()); + auto aidl_radio_mode_info1 = aidl_radio_mode_infos[0]; + EXPECT_EQ(legacy_mac_info1.wlan_mac_id, (uint32_t)aidl_radio_mode_info1.radioId); + EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, aidl_radio_mode_info1.bandInfo); + ASSERT_EQ(2u, aidl_radio_mode_info1.ifaceInfos.size()); + auto aidl_iface_info1 = aidl_radio_mode_info1.ifaceInfos[0]; + EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name); + EXPECT_EQ(static_cast(legacy_iface_info1.channel), aidl_iface_info1.channel); + auto aidl_iface_info2 = aidl_radio_mode_info1.ifaceInfos[1]; + EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name); + EXPECT_EQ(static_cast(legacy_iface_info2.channel), aidl_iface_info2.channel); +} + +TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithTwoMac) { + std::vector legacy_mac_infos; + legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1, + .mac_band = legacy_hal::WLAN_MAC_5_0_BAND}; + legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1}; + legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2, + .mac_band = legacy_hal::WLAN_MAC_2_4_BAND}; + legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2}; + legacy_mac_info1.iface_infos.push_back(legacy_iface_info1); + legacy_mac_infos.push_back(legacy_mac_info1); + legacy_mac_info2.iface_infos.push_back(legacy_iface_info2); + legacy_mac_infos.push_back(legacy_mac_info2); + + std::vector aidl_radio_mode_infos; + ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos, + &aidl_radio_mode_infos)); + + ASSERT_EQ(2u, aidl_radio_mode_infos.size()); + + // Find mac info 1. + const auto aidl_radio_mode_info1 = + std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(), + [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) { + return (uint32_t)x.radioId == legacy_mac_info1.wlan_mac_id; + }); + ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info1); + EXPECT_EQ(WifiBand::BAND_5GHZ, aidl_radio_mode_info1->bandInfo); + ASSERT_EQ(1u, aidl_radio_mode_info1->ifaceInfos.size()); + auto aidl_iface_info1 = aidl_radio_mode_info1->ifaceInfos[0]; + EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name); + EXPECT_EQ(static_cast(legacy_iface_info1.channel), aidl_iface_info1.channel); + + // Find mac info 2. + const auto aidl_radio_mode_info2 = + std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(), + [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) { + return (uint32_t)x.radioId == legacy_mac_info2.wlan_mac_id; + }); + ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info2); + EXPECT_EQ(WifiBand::BAND_24GHZ, aidl_radio_mode_info2->bandInfo); + ASSERT_EQ(1u, aidl_radio_mode_info2->ifaceInfos.size()); + auto aidl_iface_info2 = aidl_radio_mode_info2->ifaceInfos[0]; + EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name); + EXPECT_EQ(static_cast(legacy_iface_info2.channel), aidl_iface_info2.channel); +} + +TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerStatsToAidl) { + legacy_hal::LinkLayerStats legacy_stats{}; + legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{}); + legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{}); + legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{}); + legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{}); + legacy_stats.iface.beacon_rx = rand(); + legacy_stats.iface.rssi_mgmt = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand(); + + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand(); + + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand(); + + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand(); + legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand(); + + legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand(); + legacy_stats.iface.num_peers = 1; + + for (auto& radio : legacy_stats.radios) { + radio.stats.radio = rand(); + radio.stats.on_time = rand(); + radio.stats.tx_time = rand(); + radio.stats.rx_time = rand(); + radio.stats.on_time_scan = rand(); + radio.stats.on_time_nbd = rand(); + radio.stats.on_time_gscan = rand(); + radio.stats.on_time_roam_scan = rand(); + radio.stats.on_time_pno_scan = rand(); + radio.stats.on_time_hs20 = rand(); + for (int i = 0; i < 4; i++) { + radio.tx_time_per_levels.push_back(rand()); + } + + legacy_hal::wifi_channel_stat channel_stat1 = { + .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0}, + .on_time = 0x1111, + .cca_busy_time = 0x55, + }; + legacy_hal::wifi_channel_stat channel_stat2 = { + .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0}, + .on_time = 0x2222, + .cca_busy_time = 0x66, + }; + radio.channel_stats.push_back(channel_stat1); + radio.channel_stats.push_back(channel_stat2); + } + + for (auto& peer : legacy_stats.peers) { + peer.peer_info.bssload.sta_count = rand(); + peer.peer_info.bssload.chan_util = rand(); + wifi_rate_stat rate_stat1 = { + .rate = {3, 1, 2, 5, 0, 0}, + .tx_mpdu = 0, + .rx_mpdu = 1, + .mpdu_lost = 2, + .retries = 3, + .retries_short = 4, + .retries_long = 5, + }; + wifi_rate_stat rate_stat2 = { + .rate = {2, 2, 1, 6, 0, 1}, + .tx_mpdu = 6, + .rx_mpdu = 7, + .mpdu_lost = 8, + .retries = 9, + .retries_short = 10, + .retries_long = 11, + }; + peer.rate_stats.push_back(rate_stat1); + peer.rate_stats.push_back(rate_stat2); + } + + StaLinkLayerStats converted{}; + aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &converted); + EXPECT_EQ(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.beaconRx); + EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu, + converted.iface.wmeBePktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu, + converted.iface.wmeBePktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost, + converted.iface.wmeBePktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries, + converted.iface.wmeBePktStats.retries); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min, + (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max, + (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg, + (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples, + (uint32_t)converted.iface.wmeBeContentionTimeStats.contentionNumSamples); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu, + converted.iface.wmeBkPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu, + converted.iface.wmeBkPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost, + converted.iface.wmeBkPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries, + converted.iface.wmeBkPktStats.retries); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min, + (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max, + (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg, + (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples, + (uint32_t)converted.iface.wmeBkContentionTimeStats.contentionNumSamples); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu, + converted.iface.wmeViPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu, + converted.iface.wmeViPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost, + converted.iface.wmeViPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries, + converted.iface.wmeViPktStats.retries); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min, + (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max, + (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg, + (uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples, + (uint32_t)converted.iface.wmeViContentionTimeStats.contentionNumSamples); + + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu, + converted.iface.wmeVoPktStats.rxMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu, + converted.iface.wmeVoPktStats.txMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost, + converted.iface.wmeVoPktStats.lostMpdu); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries, + converted.iface.wmeVoPktStats.retries); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min, + (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max, + (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg, + (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec); + EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples, + (uint32_t)converted.iface.wmeVoContentionTimeStats.contentionNumSamples); + + EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent, + converted.iface.timeSliceDutyCycleInPercent); + + EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size()); + for (size_t i = 0; i < legacy_stats.radios.size(); i++) { + EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time, (uint32_t)converted.radios[i].onTimeInMs); + EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, (uint32_t)converted.radios[i].txTimeInMs); + EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, (uint32_t)converted.radios[i].rxTimeInMs); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan, + (uint32_t)converted.radios[i].onTimeInMsForScan); + EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(), + converted.radios[i].txTimeInMsPerLevel.size()); + for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) { + EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j], + (uint32_t)converted.radios[i].txTimeInMsPerLevel[j]); + } + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd, + (uint32_t)converted.radios[i].onTimeInMsForNanScan); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan, + (uint32_t)converted.radios[i].onTimeInMsForBgScan); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan, + (uint32_t)converted.radios[i].onTimeInMsForRoamScan); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan, + (uint32_t)converted.radios[i].onTimeInMsForPnoScan); + EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20, + (uint32_t)converted.radios[i].onTimeInMsForHs20Scan); + EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(), + converted.radios[i].channelStats.size()); + for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) { + auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k]; + EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20, + converted.radios[i].channelStats[k].channel.width); + EXPECT_EQ(legacy_channel_st.channel.center_freq, + converted.radios[i].channelStats[k].channel.centerFreq); + EXPECT_EQ(legacy_channel_st.channel.center_freq0, + converted.radios[i].channelStats[k].channel.centerFreq0); + EXPECT_EQ(legacy_channel_st.channel.center_freq1, + converted.radios[i].channelStats[k].channel.centerFreq1); + EXPECT_EQ(legacy_channel_st.cca_busy_time, + (uint32_t)converted.radios[i].channelStats[k].ccaBusyTimeInMs); + EXPECT_EQ(legacy_channel_st.on_time, + (uint32_t)converted.radios[i].channelStats[k].onTimeInMs); + } + } + + EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size()); + for (size_t i = 0; i < legacy_stats.peers.size(); i++) { + EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count, + converted.iface.peers[i].staCount); + EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util, + converted.iface.peers[i].chanUtil); + for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) { + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble, + (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.preamble); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss, + (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw, + (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx, + (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu, + (uint32_t)converted.iface.peers[i].rateStats[j].txMpdu); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu, + (uint32_t)converted.iface.peers[i].rateStats[j].rxMpdu); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost, + (uint32_t)converted.iface.peers[i].rateStats[j].mpduLost); + EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries, + (uint32_t)converted.iface.peers[i].rateStats[j].retries); + } + } +} + +TEST_F(AidlStructUtilTest, CanConvertLegacyFeaturesToAidl) { + using AidlChipCaps = IWifiChip::ChipCapabilityMask; + + uint32_t aidl_caps; + + uint32_t legacy_feature_set = WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE; + uint32_t legacy_logger_feature_set = legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED; + + ASSERT_TRUE(aidl_struct_util::convertLegacyFeaturesToAidlChipCapabilities( + legacy_feature_set, legacy_logger_feature_set, &aidl_caps)); + + EXPECT_EQ((uint32_t)AidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA | + (uint32_t)AidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS | + (uint32_t)AidlChipCaps::DEBUG_ERROR_ALERTS | (uint32_t)AidlChipCaps::D2D_RTT | + (uint32_t)AidlChipCaps::SET_LATENCY_MODE | + (uint32_t)AidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP, + aidl_caps); +} + +void insertRadioCombination(legacy_hal::wifi_radio_combination* dst_radio_combination_ptr, + int num_radio_configurations, + legacy_hal::wifi_radio_configuration* radio_configuration) { + dst_radio_combination_ptr->num_radio_configurations = num_radio_configurations; + memcpy(dst_radio_combination_ptr->radio_configurations, radio_configuration, + num_radio_configurations * sizeof(legacy_hal::wifi_radio_configuration)); +} + +void verifyRadioCombination(WifiRadioCombination* radioCombination, size_t num_radio_configurations, + legacy_hal::wifi_radio_configuration* radio_configuration) { + EXPECT_EQ(num_radio_configurations, radioCombination->radioConfigurations.size()); + for (size_t i = 0; i < num_radio_configurations; i++) { + EXPECT_EQ(aidl_struct_util::convertLegacyMacBandToAidlWifiBand(radio_configuration->band), + radioCombination->radioConfigurations[i].bandInfo); + EXPECT_EQ(aidl_struct_util::convertLegacyAntennaConfigurationToAidl( + radio_configuration->antenna_cfg), + radioCombination->radioConfigurations[i].antennaMode); + radio_configuration++; + } +} + +TEST_F(AidlStructUtilTest, canConvertLegacyRadioCombinationsMatrixToAidl) { + legacy_hal::wifi_radio_configuration radio_configurations_array1[] = { + {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1}, + }; + legacy_hal::wifi_radio_configuration radio_configurations_array2[] = { + {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2}, + {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_3X3}, + }; + legacy_hal::wifi_radio_configuration radio_configurations_array3[] = { + {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2}, + {.band = legacy_hal::WLAN_MAC_6_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1}, + {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_4X4}, + }; + + int num_radio_configs = 0; + int num_combinations = 0; + std::array buffer; + buffer.fill(0); + legacy_hal::wifi_radio_combination_matrix* legacy_matrix = + reinterpret_cast(buffer.data()); + legacy_hal::wifi_radio_combination* radio_combinations; + + // Prepare a legacy wifi_radio_combination_matrix + legacy_matrix->num_radio_combinations = 3; + // Insert first combination + radio_combinations = + (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations); + insertRadioCombination( + radio_combinations, + sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]), + radio_configurations_array1); + num_combinations++; + num_radio_configs += + sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]); + + // Insert second combination + radio_combinations = + (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations + + (num_combinations * + sizeof(legacy_hal::wifi_radio_combination)) + + (num_radio_configs * + sizeof(wifi_radio_configuration))); + insertRadioCombination( + radio_combinations, + sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]), + radio_configurations_array2); + num_combinations++; + num_radio_configs += + sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]); + + // Insert third combination + radio_combinations = + (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations + + (num_combinations * + sizeof(legacy_hal::wifi_radio_combination)) + + (num_radio_configs * + sizeof(wifi_radio_configuration))); + insertRadioCombination( + radio_combinations, + sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]), + radio_configurations_array3); + + WifiRadioCombinationMatrix converted_matrix{}; + aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, &converted_matrix); + + // Verify the conversion + EXPECT_EQ(legacy_matrix->num_radio_combinations, converted_matrix.radioCombinations.size()); + verifyRadioCombination( + &converted_matrix.radioCombinations[0], + sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]), + radio_configurations_array1); + verifyRadioCombination( + &converted_matrix.radioCombinations[1], + sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]), + radio_configurations_array2); + verifyRadioCombination( + &converted_matrix.radioCombinations[2], + sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]), + radio_configurations_array3); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/main.cpp b/wifi/aidl/default/tests/main.cpp new file mode 100644 index 0000000000..767422c408 --- /dev/null +++ b/wifi/aidl/default/tests/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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 +#include + +#include + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::InitGoogleMock(&argc, argv); + // Force ourselves to always log to stderr + android::base::InitLogging(argv, android::base::StderrLogger); + return RUN_ALL_TESTS(); +} diff --git a/wifi/aidl/default/tests/mock_interface_tool.cpp b/wifi/aidl/default/tests/mock_interface_tool.cpp new file mode 100644 index 0000000000..79f3d1e638 --- /dev/null +++ b/wifi/aidl/default/tests/mock_interface_tool.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "mock_interface_tool.h" + +namespace android { +namespace wifi_system { + +MockInterfaceTool::MockInterfaceTool() {} + +} // namespace wifi_system +} // namespace android diff --git a/wifi/aidl/default/tests/mock_interface_tool.h b/wifi/aidl/default/tests/mock_interface_tool.h new file mode 100644 index 0000000000..9795de8014 --- /dev/null +++ b/wifi/aidl/default/tests/mock_interface_tool.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef MOCK_INTERFACE_TOOL_H +#define MOCK_INTERFACE_TOOL_H + +#include +#include + +namespace android { +namespace wifi_system { + +class MockInterfaceTool : public InterfaceTool { + public: + MockInterfaceTool(); + + MOCK_METHOD1(GetUpState, bool(const char* if_name)); + MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up)); + MOCK_METHOD1(SetWifiUpState, bool(bool request_up)); + MOCK_METHOD2(SetMacAddress, + bool(const char* if_name, const std::array& address)); + MOCK_METHOD1(GetFactoryMacAddress, std::array(const char* if_name)); + +}; // class MockInterfaceTool + +} // namespace wifi_system +} // namespace android + +#endif // MOCK_INTERFACE_TOOL_H diff --git a/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp b/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp new file mode 100644 index 0000000000..0c4e59deb3 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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 + +#include "mock_wifi_feature_flags.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace feature_flags { + +MockWifiFeatureFlags::MockWifiFeatureFlags() {} + +} // namespace feature_flags +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/mock_wifi_feature_flags.h b/wifi/aidl/default/tests/mock_wifi_feature_flags.h new file mode 100644 index 0000000000..9143d15d61 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_feature_flags.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef MOCK_WIFI_FEATURE_FLAGS_H_ +#define MOCK_WIFI_FEATURE_FLAGS_H_ + +#include + +#include "wifi_feature_flags.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace feature_flags { + +class MockWifiFeatureFlags : public WifiFeatureFlags { + public: + MockWifiFeatureFlags(); + + MOCK_METHOD1(getChipModes, std::vector(bool is_primary)); + MOCK_METHOD0(isApMacRandomizationDisabled, bool()); +}; + +} // namespace feature_flags +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // MOCK_WIFI_FEATURE_FLAGS_H_ diff --git a/wifi/aidl/default/tests/mock_wifi_iface_util.cpp b/wifi/aidl/default/tests/mock_wifi_iface_util.cpp new file mode 100644 index 0000000000..0f787f22b2 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_iface_util.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "mock_wifi_iface_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace iface_util { + +MockWifiIfaceUtil::MockWifiIfaceUtil( + const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::weak_ptr legacy_hal) + : WifiIfaceUtil(iface_tool, legacy_hal) {} + +} // namespace iface_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/mock_wifi_iface_util.h b/wifi/aidl/default/tests/mock_wifi_iface_util.h new file mode 100644 index 0000000000..49a8636345 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_iface_util.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef MOCK_WIFI_IFACE_UTIL_H_ +#define MOCK_WIFI_IFACE_UTIL_H_ + +#include + +#include "wifi_iface_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace iface_util { + +class MockWifiIfaceUtil : public iface_util::WifiIfaceUtil { + public: + MockWifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::weak_ptr legacy_hal); + MOCK_METHOD1(getFactoryMacAddress, std::array(const std::string&)); + MOCK_METHOD2(setMacAddress, bool(const std::string&, const std::array&)); + MOCK_METHOD0(getOrCreateRandomMacAddress, std::array()); + MOCK_METHOD2(registerIfaceEventHandlers, + void(const std::string&, iface_util::IfaceEventHandlers)); + MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&)); + MOCK_METHOD2(setUpState, bool(const std::string&, bool)); + MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&)); +}; + +} // namespace iface_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // MOCK_WIFI_IFACE_UTIL_H_ diff --git a/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp b/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp new file mode 100644 index 0000000000..33b2b1ce36 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "mock_wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { + +MockWifiLegacyHal::MockWifiLegacyHal( + const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const wifi_hal_fn& fn, bool is_primary) + : WifiLegacyHal(iface_tool, fn, is_primary) {} +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/mock_wifi_legacy_hal.h b/wifi/aidl/default/tests/mock_wifi_legacy_hal.h new file mode 100644 index 0000000000..28129a9947 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_legacy_hal.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef MOCK_WIFI_LEGACY_HAL_H_ +#define MOCK_WIFI_LEGACY_HAL_H_ + +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { + +class MockWifiLegacyHal : public WifiLegacyHal { + public: + MockWifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const wifi_hal_fn& fn, bool is_primary); + MOCK_METHOD0(initialize, wifi_error()); + MOCK_METHOD0(start, wifi_error()); + MOCK_METHOD2(stop, + wifi_error(std::unique_lock*, const std::function&)); + MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool)); + MOCK_METHOD2(registerRadioModeChangeCallbackHandler, + wifi_error(const std::string&, const on_radio_mode_change_callback&)); + MOCK_METHOD1(getFirmwareVersion, + std::pair(const std::string& iface_name)); + MOCK_METHOD1(getDriverVersion, + std::pair(const std::string& iface_name)); + + MOCK_METHOD2(selectTxPowerScenario, + wifi_error(const std::string& iface_name, wifi_power_scenario scenario)); + MOCK_METHOD1(resetTxPowerScenario, wifi_error(const std::string& iface_name)); + MOCK_METHOD2(nanRegisterCallbackHandlers, + wifi_error(const std::string&, const NanCallbackHandlers&)); + MOCK_METHOD2(nanDisableRequest, wifi_error(const std::string&, transaction_id)); + MOCK_METHOD3(nanDataInterfaceDelete, + wifi_error(const std::string&, transaction_id, const std::string&)); + MOCK_METHOD2(createVirtualInterface, + wifi_error(const std::string& ifname, wifi_interface_type iftype)); + MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname)); + MOCK_METHOD0(waitForDriverReady, wifi_error()); + MOCK_METHOD2(getSupportedIfaceName, wifi_error(uint32_t, std::string&)); + MOCK_METHOD1(registerSubsystemRestartCallbackHandler, + wifi_error(const on_subsystem_restart_callback&)); + MOCK_METHOD1(getSupportedFeatureSet, std::pair(const std::string&)); +}; +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // MOCK_WIFI_LEGACY_HAL_H_ diff --git a/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp b/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp new file mode 100644 index 0000000000..f4cc4c4108 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "mock_wifi_mode_controller.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace mode_controller { + +MockWifiModeController::MockWifiModeController() : WifiModeController() {} + +} // namespace mode_controller +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/mock_wifi_mode_controller.h b/wifi/aidl/default/tests/mock_wifi_mode_controller.h new file mode 100644 index 0000000000..f77f7d0f96 --- /dev/null +++ b/wifi/aidl/default/tests/mock_wifi_mode_controller.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef MOCK_WIFI_MODE_CONTROLLER_H_ +#define MOCK_WIFI_MODE_CONTROLLER_H_ + +#include + +#include "wifi_mode_controller.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace mode_controller { + +class MockWifiModeController : public WifiModeController { + public: + MockWifiModeController(); + MOCK_METHOD0(initialize, bool()); + MOCK_METHOD1(changeFirmwareMode, bool(IfaceType)); + MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType)); + MOCK_METHOD0(deinitialize, bool()); +}; +} // namespace mode_controller +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // MOCK_WIFI_MODE_CONTROLLER_H_ diff --git a/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp b/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp new file mode 100644 index 0000000000..c257100be9 --- /dev/null +++ b/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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 + +#include "ringbuffer.h" + +using testing::Return; +using testing::Test; + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +class RingbufferTest : public Test { + public: + const uint32_t maxBufferSize_ = 10; + Ringbuffer buffer_{maxBufferSize_}; +}; + +TEST_F(RingbufferTest, CreateEmptyBuffer) { + ASSERT_TRUE(buffer_.getData().empty()); +} + +TEST_F(RingbufferTest, CanUseFullBufferCapacity) { + const std::vector input(maxBufferSize_ / 2, '0'); + const std::vector input2(maxBufferSize_ / 2, '1'); + buffer_.append(input); + buffer_.append(input2); + ASSERT_EQ(2u, buffer_.getData().size()); + EXPECT_EQ(input, buffer_.getData().front()); + EXPECT_EQ(input2, buffer_.getData().back()); +} + +TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) { + const std::vector input(maxBufferSize_ / 2, '0'); + const std::vector input2(maxBufferSize_ / 2, '1'); + const std::vector input3 = {'G'}; + buffer_.append(input); + buffer_.append(input2); + buffer_.append(input3); + ASSERT_EQ(2u, buffer_.getData().size()); + EXPECT_EQ(input2, buffer_.getData().front()); + EXPECT_EQ(input3, buffer_.getData().back()); +} + +TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) { + const std::vector input(maxBufferSize_ / 2, '0'); + const std::vector input2(maxBufferSize_ / 2, '1'); + const std::vector input3(maxBufferSize_, '2'); + buffer_.append(input); + buffer_.append(input2); + buffer_.append(input3); + ASSERT_EQ(1u, buffer_.getData().size()); + EXPECT_EQ(input3, buffer_.getData().front()); +} + +TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) { + const std::vector input = {}; + buffer_.append(input); + ASSERT_TRUE(buffer_.getData().empty()); +} + +TEST_F(RingbufferTest, OversizedAppendIsDropped) { + const std::vector input(maxBufferSize_ + 1, '0'); + buffer_.append(input); + ASSERT_TRUE(buffer_.getData().empty()); +} + +TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) { + const std::vector input(maxBufferSize_, '0'); + const std::vector input2(maxBufferSize_ + 1, '1'); + buffer_.append(input); + buffer_.append(input2); + ASSERT_EQ(1u, buffer_.getData().size()); + EXPECT_EQ(input, buffer_.getData().front()); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/runtests.sh b/wifi/aidl/default/tests/runtests.sh new file mode 100755 index 0000000000..1f53ab8e05 --- /dev/null +++ b/wifi/aidl/default/tests/runtests.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# Copyright(C) 2022 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. + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi +set -e + +$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode android.hardware.wifi-service-tests +adb root +adb sync data +adb shell /data/nativetest64/vendor/android.hardware.wifi-service-tests/android.hardware.wifi-service-tests diff --git a/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp b/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp new file mode 100644 index 0000000000..e66b650ded --- /dev/null +++ b/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp @@ -0,0 +1,855 @@ +/* + * Copyright (C) 2022 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 +#include +#include +#include + +#include "wifi_chip.h" + +#include "mock_interface_tool.h" +#include "mock_wifi_feature_flags.h" +#include "mock_wifi_iface_util.h" +#include "mock_wifi_legacy_hal.h" +#include "mock_wifi_mode_controller.h" + +using testing::NiceMock; +using testing::Return; +using testing::Test; + +namespace { +constexpr int kFakeChipId = 5; +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +class WifiChipTest : public Test { + protected: + void setupV1IfaceCombination() { + // clang-format off + // 1 STA + 1 P2P + const std::vector combinationsSta = + { + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::P2P}, 1} + } + } + }; + // 1 AP + const std::vector combinationsAp = + { + { + { + {{IfaceConcurrencyType::AP}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}, + {feature_flags::chip_mode_ids::kV1Ap, combinationsAp} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void setupV1_AwareIfaceCombination() { + // clang-format off + // 1 STA + 1 of (P2P or NAN) + const std::vector combinationsSta = + { + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1} + } + } + }; + // 1 AP + const std::vector combinationsAp = + { + { + { + {{IfaceConcurrencyType::AP}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}, + {feature_flags::chip_mode_ids::kV1Ap, combinationsAp} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void setupV1_AwareDisabledApIfaceCombination() { + // clang-format off + // 1 STA + 1 of (P2P or NAN) + const std::vector combinationsSta = + { + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV1Sta, combinationsSta} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void setupV2_AwareIfaceCombination() { + // clang-format off + // (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN)) + const std::vector combinations = + { + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::AP}, 1} + } + }, + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void setupV2_AwareDisabledApIfaceCombination() { + // clang-format off + // 1 STA + 1 of (P2P or NAN) + const std::vector combinations = + { + { + { + {{IfaceConcurrencyType::STA}, 1}, + {{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void setup_MultiIfaceCombination() { + // clang-format off + // 3 STA + 1 AP + const std::vector combinations = + { + { + { + {{IfaceConcurrencyType::STA}, 3}, + {{IfaceConcurrencyType::AP}, 1} + } + } + }; + const std::vector modes = { + {feature_flags::chip_mode_ids::kV3, combinations} + }; + // clang-format on + EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes)); + } + + void assertNumberOfModes(uint32_t num_modes) { + std::vector modes; + ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk()); + // V2_Aware has 1 mode of operation. + ASSERT_EQ(num_modes, modes.size()); + } + + void findModeAndConfigureForIfaceType(const IfaceConcurrencyType& type) { + // This should be aligned with kInvalidModeId in wifi_chip.cpp + int32_t mode_id = INT32_MAX; + std::vector modes; + ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk()); + + for (const auto& mode : modes) { + for (const auto& combination : mode.availableCombinations) { + for (const auto& limit : combination.limits) { + if (limit.types.end() != + std::find(limit.types.begin(), limit.types.end(), type)) { + mode_id = mode.id; + } + } + } + } + + ASSERT_NE(INT32_MAX, mode_id); + ASSERT_TRUE(chip_->configureChip(mode_id).isOk()); + } + + // Returns an empty string on error. + std::string createIface(const IfaceType& type) { + std::string iface_name; + if (type == IfaceType::AP) { + std::shared_ptr iface; + if (!chip_->createApIface(&iface).isOk()) { + return ""; + } + EXPECT_NE(iface.get(), nullptr); + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + } else if (type == IfaceType::NAN_IFACE) { + std::shared_ptr iface; + if (!chip_->createNanIface(&iface).isOk()) { + return ""; + } + EXPECT_NE(iface.get(), nullptr); + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + } else if (type == IfaceType::P2P) { + std::shared_ptr iface; + if (!chip_->createP2pIface(&iface).isOk()) { + return ""; + } + EXPECT_NE(iface.get(), nullptr); + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + } else if (type == IfaceType::STA) { + std::shared_ptr iface; + if (!chip_->createStaIface(&iface).isOk()) { + return ""; + } + EXPECT_NE(iface.get(), nullptr); + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + } + return iface_name; + } + + void removeIface(const IfaceType& type, const std::string& iface_name) { + if (type == IfaceType::AP) { + ASSERT_TRUE(chip_->removeApIface(iface_name).isOk()); + } else if (type == IfaceType::NAN_IFACE) { + ASSERT_TRUE(chip_->removeNanIface(iface_name).isOk()); + } else if (type == IfaceType::P2P) { + ASSERT_TRUE(chip_->removeP2pIface(iface_name).isOk()); + } else if (type == IfaceType::STA) { + ASSERT_TRUE(chip_->removeStaIface(iface_name).isOk()); + } + } + + bool createRttController() { + std::shared_ptr rtt_controller; + auto status = chip_->createRttController(nullptr, &rtt_controller); + return status.isOk(); + } + + static void subsystemRestartHandler(const std::string& /*error*/) {} + + std::shared_ptr chip_; + int chip_id_ = kFakeChipId; + legacy_hal::wifi_hal_fn fake_func_table_; + std::shared_ptr> iface_tool_{ + new NiceMock<::android::wifi_system::MockInterfaceTool>}; + std::shared_ptr> legacy_hal_{ + new NiceMock(iface_tool_, fake_func_table_, true)}; + std::shared_ptr> mode_controller_{ + new NiceMock}; + std::shared_ptr> iface_util_{ + new NiceMock(iface_tool_, legacy_hal_)}; + std::shared_ptr> feature_flags_{ + new NiceMock}; + + public: + void SetUp() override { + chip_ = WifiChip::create(chip_id_, true, legacy_hal_, mode_controller_, iface_util_, + feature_flags_, subsystemRestartHandler); + + EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_)) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*legacy_hal_, start()) + .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS)); + // Vendor HAL does not override the name by default. + EXPECT_CALL(*legacy_hal_, getSupportedIfaceName(testing::_, testing::_)) + .WillRepeatedly(testing::Return(legacy_hal::WIFI_ERROR_UNKNOWN)); + } + + void TearDown() override { + // Restore default system iface names (This should ideally be using a + // mock). + property_set("wifi.interface", "wlan0"); + property_set("wifi.concurrent.interface", "wlan1"); + property_set("wifi.aware.interface", nullptr); + } +}; + +////////// V1 Iface Combinations //////////// +// Mode 1 - STA + P2P +// Mode 2 - AP +class WifiChipV1IfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV1IfaceCombination(); + WifiChipTest::SetUp(); + // V1 has 2 modes of operation. + assertNumberOfModes(2); + } +}; + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::AP), "wlan0"); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +////////// V1 + Aware Iface Combinations //////////// +// Mode 1 - STA + P2P/NAN +// Mode 2 - AP +class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV1_AwareIfaceCombination(); + WifiChipTest::SetUp(); + // V1_Aware has 2 modes of operation. + assertNumberOfModes(2u); + } +}; + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string nan_iface_name = createIface(IfaceType::NAN_IFACE); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN_IFACE, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::AP), "wlan0"); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + std::string ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(ap_iface_name.empty()); + ASSERT_FALSE(createRttController()); + + removeIface(IfaceType::AP, ap_iface_name); + + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_)) + .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS)); + ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::AP), "wlan0"); + EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_)) + .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS)); + ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk()); +} + +////////// V2 + Aware Iface Combinations //////////// +// Mode 1 - STA + STA/AP +// - STA + P2P/NAN +class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV2_AwareIfaceCombination(); + WifiChipTest::SetUp(); + // V2_Aware has 1 mode of operation. + assertNumberOfModes(1u); + } +}; + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::AP), "wlan1"); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + ASSERT_EQ(createIface(IfaceType::AP), "wlan1"); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::AP), "wlan1"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_AfterStaApRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + std::string sta_iface_name = createIface(IfaceType::STA); + ASSERT_FALSE(sta_iface_name.empty()); + std::string ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(ap_iface_name.empty()); + + ASSERT_TRUE(createIface(IfaceType::STA).empty()); + + // After removing AP & STA iface, STA iface creation should succeed. + removeIface(IfaceType::STA, sta_iface_name); + removeIface(IfaceType::AP, ap_iface_name); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string nan_iface_name = createIface(IfaceType::NAN_IFACE); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN_IFACE, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + std::string nan_iface_name = createIface(IfaceType::NAN_IFACE); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN_IFACE, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + std::string sta_iface_name = createIface(IfaceType::STA); + std::string ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(sta_iface_name.empty()); + ASSERT_FALSE(ap_iface_name.empty()); + ASSERT_NE(sta_iface_name, ap_iface_name); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createRttController()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_)) + .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS)); + ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP); + ASSERT_EQ(createIface(IfaceType::AP), "wlan1"); + EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_)) + .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS)); + ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + + // Create NAN iface + ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0"); + + // We should have 1 nan iface. + std::vector iface_names; + ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk()); + ASSERT_EQ(iface_names.size(), 1u); + ASSERT_EQ(iface_names[0], "wlan0"); + + // Retrieve the nan iface object. + std::shared_ptr nan_iface; + ASSERT_TRUE(chip_->getNanIface("wlan0", &nan_iface).isOk()); + ASSERT_NE(nan_iface.get(), nullptr); + + // Remove the STA iface. We should have 0 nan ifaces now. + removeIface(IfaceType::STA, "wlan0"); + ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk()); + ASSERT_EQ(iface_names.size(), 0u); + + // Any operation on the nan iface object should now return an error. + std::string name; + auto status = nan_iface->getName(&name); + ASSERT_EQ(status.getServiceSpecificError(), + static_cast(WifiStatusCode::ERROR_WIFI_IFACE_INVALID)); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + + // Create RTT controller + std::shared_ptr rtt_controller; + ASSERT_TRUE(chip_->createRttController(nullptr, &rtt_controller).isOk()); + + // Remove the STA iface. + removeIface(IfaceType::STA, "wlan0"); + + // Any operation on the rtt controller object should now return an error. + std::shared_ptr bound_iface; + auto status = rtt_controller->getBoundIface(&bound_iface); + ASSERT_EQ(status.getServiceSpecificError(), + static_cast(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID)); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) { + property_set("wifi.aware.interface", nullptr); + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0"); + removeIface(IfaceType::NAN_IFACE, "wlan0"); + EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) { + property_set("wifi.aware.interface", "aware0"); + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + EXPECT_CALL(*iface_util_, ifNameToIndex("aware0")).WillOnce(testing::Return(4)); + EXPECT_CALL(*iface_util_, setUpState("aware0", true)).WillOnce(testing::Return(true)); + ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "aware0"); + + EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true)); + removeIface(IfaceType::NAN_IFACE, "aware0"); +} + +////////// V1 Iface Combinations when AP creation is disabled ////////// +class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV1_AwareDisabledApIfaceCombination(); + WifiChipTest::SetUp(); + } +}; + +TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +////////// V2 Iface Combinations when AP creation is disabled ////////// +class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest { + public: + void SetUp() override { + setupV2_AwareDisabledApIfaceCombination(); + WifiChipTest::SetUp(); + } +}; + +TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +////////// Hypothetical Iface Combination with multiple ifaces ////////// +class WifiChip_MultiIfaceTest : public WifiChipTest { + public: + void SetUp() override { + setup_MultiIfaceCombination(); + WifiChipTest::SetUp(); + } +}; + +TEST_F(WifiChip_MultiIfaceTest, Create3Sta) { + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) { + property_set("wifi.interface.0", ""); + property_set("wifi.interface.1", ""); + property_set("wifi.interface.2", ""); + property_set("wifi.interface", ""); + property_set("wifi.concurrent.interface", ""); + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan1"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan2"); +} + +TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) { + property_set("wifi.interface.0", "test0"); + property_set("wifi.interface.1", "test1"); + property_set("wifi.interface.2", "test2"); + property_set("wifi.interface", "bad0"); + property_set("wifi.concurrent.interface", "bad1"); + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "bad0"); + ASSERT_EQ(createIface(IfaceType::STA), "bad1"); + ASSERT_EQ(createIface(IfaceType::STA), "test2"); +} + +TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) { + property_set("wifi.interface.0", ""); + property_set("wifi.interface.1", ""); + property_set("wifi.interface.2", ""); + property_set("wifi.interface", "testA0"); + property_set("wifi.concurrent.interface", "testA1"); + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "testA0"); + ASSERT_EQ(createIface(IfaceType::STA), "testA1"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan2"); +} + +TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) { + // WifiChip_MultiIfaceTest iface combo: STAx3 + APx1 + // When the HAL support dual STAs, AP should start with idx 2. + findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA); + // First AP will be slotted to wlan1. + ASSERT_EQ(createIface(IfaceType::AP), "wlan2"); + // First STA will be slotted to wlan0. + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + // All further STA will be slotted to the remaining free indices. + ASSERT_EQ(createIface(IfaceType::STA), "wlan1"); + ASSERT_EQ(createIface(IfaceType::STA), "wlan3"); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp new file mode 100644 index 0000000000..e0db6fdc90 --- /dev/null +++ b/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "wifi_iface_util.h" + +#include "mock_interface_tool.h" +#include "mock_wifi_legacy_hal.h" + +using testing::NiceMock; +using testing::Test; + +namespace { +constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02; +constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc}; +constexpr char kIfaceName[] = "test-wlan0"; + +bool isValidUnicastLocallyAssignedMacAddress(const std::array& mac_address) { + uint8_t first_byte = mac_address[0]; + return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask; +} +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace iface_util { + +class WifiIfaceUtilTest : public Test { + protected: + std::shared_ptr> iface_tool_{ + new NiceMock<::android::wifi_system::MockInterfaceTool>}; + legacy_hal::wifi_hal_fn fake_func_table_; + std::shared_ptr> legacy_hal_{ + new NiceMock(iface_tool_, fake_func_table_, true)}; + WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_); +}; + +TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) { + auto mac_address = iface_util_->getOrCreateRandomMacAddress(); + ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address)); + + // All further calls should return the same MAC address. + ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress()); + ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress()); +} + +TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) { + std::array mac_address = {}; + std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(mac_address)); + EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_)) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_)) + .WillRepeatedly(testing::Return(true)); + + // Register for iface state toggle events. + bool callback_invoked = false; + iface_util::IfaceEventHandlers event_handlers = {}; + event_handlers.on_state_toggle_off_on = + [&callback_invoked](const std::string& /* iface_name */) { callback_invoked = true; }; + iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers); + // Invoke setMacAddress and ensure that the cb is invoked. + ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address)); + ASSERT_TRUE(callback_invoked); + + // Unregister for iface state toggle events. + callback_invoked = false; + iface_util_->unregisterIfaceEventHandlers(kIfaceName); + // Invoke setMacAddress and ensure that the cb is not invoked. + ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address)); + ASSERT_FALSE(callback_invoked); +} +} // namespace iface_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp new file mode 100644 index 0000000000..d40801faef --- /dev/null +++ b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2022 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 +#include +#include +#include + +#include "wifi_nan_iface.h" + +#include "mock_interface_tool.h" +#include "mock_wifi_feature_flags.h" +#include "mock_wifi_iface_util.h" +#include "mock_wifi_legacy_hal.h" + +using testing::NiceMock; +using testing::Return; +using testing::Test; + +namespace { +constexpr char kIfaceName[] = "mockWlan0"; +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +bool CaptureIfaceEventHandlers(const std::string& /* iface_name*/, + iface_util::IfaceEventHandlers in_iface_event_handlers, + iface_util::IfaceEventHandlers* out_iface_event_handlers) { + *out_iface_event_handlers = in_iface_event_handlers; + return true; +} + +class MockNanIface : public WifiNanIface { + public: + MockNanIface(const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) + : WifiNanIface(ifname, is_dedicated_iface, legacy_hal, iface_util) {} + + static std::shared_ptr createMock( + const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) { + std::shared_ptr ptr = ndk::SharedRefBase::make( + ifname, is_dedicated_iface, legacy_hal, iface_util); + std::weak_ptr weak_ptr_this(ptr); + ptr->setWeakPtr(weak_ptr_this); + ptr->registerCallbackHandlers(); + return ptr; + } + + // Override getEventCallbacks() so that we can return a mocked callback object. + std::set> getEventCallbacks() override { + return {callback_}; + } + + void setMockCallback(std::shared_ptr cb) { callback_ = cb; } + + private: + std::shared_ptr callback_; +}; + +class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback { + public: + ndk::SpAIBinder asBinder() override { return ::ndk::SpAIBinder{}; } + bool isRemote() override { return false; } + + ::ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) override { + *_aidl_return = 1; + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus getInterfaceHash(std::string* _aidl_return) override { + *_aidl_return = "some_hash"; + return ndk::ScopedAStatus::ok(); + } + + MOCK_METHOD3(notifyCapabilitiesResponse, + ndk::ScopedAStatus(char16_t, const NanStatus&, const NanCapabilities&)); + MOCK_METHOD2(notifyEnableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyConfigResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyDisableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD3(notifyStartPublishResponse, + ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t)); + MOCK_METHOD2(notifyStopPublishResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD3(notifyStartSubscribeResponse, + ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t)); + MOCK_METHOD2(notifyStopSubscribeResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyTransmitFollowupResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyCreateDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyDeleteDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD3(notifyInitiateDataPathResponse, + ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t)); + MOCK_METHOD2(notifyRespondToDataPathIndicationResponse, + ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD2(notifyTerminateDataPathResponse, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD1(eventClusterEvent, ndk::ScopedAStatus(const NanClusterEventInd&)); + MOCK_METHOD1(eventDisabled, ndk::ScopedAStatus(const NanStatus&)); + MOCK_METHOD2(eventPublishTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&)); + MOCK_METHOD2(eventSubscribeTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&)); + MOCK_METHOD1(eventMatch, ndk::ScopedAStatus(const NanMatchInd&)); + MOCK_METHOD2(eventMatchExpired, ndk::ScopedAStatus(int8_t, int32_t)); + MOCK_METHOD1(eventFollowupReceived, ndk::ScopedAStatus(const NanFollowupReceivedInd&)); + MOCK_METHOD2(eventTransmitFollowup, ndk::ScopedAStatus(char16_t, const NanStatus&)); + MOCK_METHOD1(eventDataPathRequest, ndk::ScopedAStatus(const NanDataPathRequestInd&)); + MOCK_METHOD1(eventDataPathConfirm, ndk::ScopedAStatus(const NanDataPathConfirmInd&)); + MOCK_METHOD1(eventDataPathTerminated, ndk::ScopedAStatus(int32_t)); + MOCK_METHOD1(eventDataPathScheduleUpdate, + ndk::ScopedAStatus(const NanDataPathScheduleUpdateInd&)); +}; + +class WifiNanIfaceTest : public Test { + protected: + legacy_hal::wifi_hal_fn fake_func_table_; + std::shared_ptr> iface_tool_{ + new NiceMock<::android::wifi_system::MockInterfaceTool>}; + std::shared_ptr> legacy_hal_{ + new NiceMock(iface_tool_, fake_func_table_, true)}; + std::shared_ptr> iface_util_{ + new NiceMock(iface_tool_, legacy_hal_)}; +}; + +TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) { + // Ensure that event handlers are registered during nan iface creation. + iface_util::IfaceEventHandlers captured_iface_event_handlers = {}; + EXPECT_CALL(*legacy_hal_, nanRegisterCallbackHandlers(testing::_, testing::_)) + .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS)); + EXPECT_CALL(*iface_util_, registerIfaceEventHandlers(testing::_, testing::_)) + .WillOnce(testing::Invoke(bind(CaptureIfaceEventHandlers, std::placeholders::_1, + std::placeholders::_2, &captured_iface_event_handlers))); + + // Create nan iface and register a callback. + // Note: Since we can't register a callback directly (gTest fails on + // AIBinder_linkToDeath), simulate the registration by overriding + // getEventCallbacks() to return our mock callback object. + std::shared_ptr mock_nan_iface = + MockNanIface::createMock(kIfaceName, false, legacy_hal_, iface_util_); + std::shared_ptr mock_event_callback = + ndk::SharedRefBase::make(); + mock_nan_iface->setMockCallback(mock_event_callback); + + // Ensure that the eventDisabled() function in the mock callback will be invoked. + NanStatus expected_nan_status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""}; + EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status)).Times(1); + + // Trigger the iface state toggle callback. + captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi.cpp b/wifi/aidl/default/wifi.cpp new file mode 100644 index 0000000000..e30c38abcf --- /dev/null +++ b/wifi/aidl/default/wifi.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2022 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 "wifi.h" + +#include + +#include "aidl_return_util.h" +#include "wifi_status_util.h" + +namespace { +// Starting Chip ID, will be assigned to primary chip +static constexpr int32_t kPrimaryChipId = 0; +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; +using aidl_return_util::validateAndCallWithLock; + +Wifi::Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::shared_ptr legacy_hal_factory, + const std::shared_ptr mode_controller, + const std::shared_ptr feature_flags) + : iface_tool_(iface_tool), + legacy_hal_factory_(legacy_hal_factory), + mode_controller_(mode_controller), + feature_flags_(feature_flags), + run_state_(RunState::STOPPED) {} + +bool Wifi::isValid() { + // This object is always valid. + return true; +} + +ndk::ScopedAStatus Wifi::registerEventCallback( + const std::shared_ptr& in_callback) { + return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, + &Wifi::registerEventCallbackInternal, in_callback); +} + +ndk::ScopedAStatus Wifi::isStarted(bool* _aidl_return) { + *_aidl_return = (run_state_ != RunState::STOPPED); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Wifi::start() { + return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal); +} + +ndk::ScopedAStatus Wifi::stop() { + return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal); +} + +ndk::ScopedAStatus Wifi::getChipIds(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal, + _aidl_return); +} + +ndk::ScopedAStatus Wifi::getChip(int32_t in_chipId, std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal, + _aidl_return, in_chipId); +} + +binder_status_t Wifi::dump(int fd, const char** args, uint32_t numArgs) { + LOG(INFO) << "-----------Debug was called----------------"; + if (chips_.size() == 0) { + LOG(INFO) << "No chips to display."; + return STATUS_OK; + } + + for (std::shared_ptr chip : chips_) { + if (!chip.get()) continue; + chip->dump(fd, args, numArgs); + } + return STATUS_OK; +} + +ndk::ScopedAStatus Wifi::registerEventCallbackInternal( + const std::shared_ptr& event_callback) { + if (!event_cb_handler_.addCallback(event_callback)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Wifi::startInternal() { + if (run_state_ == RunState::STARTED) { + return ndk::ScopedAStatus::ok(); + } else if (run_state_ == RunState::STOPPING) { + return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping"); + } + ndk::ScopedAStatus wifi_status = initializeModeControllerAndLegacyHal(); + if (wifi_status.isOk()) { + // Register the callback for subsystem restart + const auto& on_subsystem_restart_callback = [this](const std::string& error) { + ndk::ScopedAStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + LOG(INFO) << "Attempting to invoke onSubsystemRestart " + "callback"; + WifiStatusCode errorCode = + static_cast(wifi_status.getServiceSpecificError()); + if (!callback->onSubsystemRestart(errorCode).isOk()) { + LOG(ERROR) << "Failed to invoke onSubsystemRestart callback"; + } else { + LOG(INFO) << "Succeeded to invoke onSubsystemRestart " + "callback"; + } + } + }; + + // Create the chip instance once the HAL is started. + int32_t chipId = kPrimaryChipId; + for (auto& hal : legacy_hals_) { + chips_.push_back( + WifiChip::create(chipId, chipId == kPrimaryChipId, hal, mode_controller_, + std::make_shared(iface_tool_, hal), + feature_flags_, on_subsystem_restart_callback)); + chipId++; + } + run_state_ = RunState::STARTED; + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onStart().isOk()) { + LOG(ERROR) << "Failed to invoke onStart callback"; + }; + } + LOG(INFO) << "Wifi HAL started"; + } else { + for (const auto& callback : event_cb_handler_.getCallbacks()) { + WifiStatusCode errorCode = + static_cast(wifi_status.getServiceSpecificError()); + if (!callback->onFailure(errorCode).isOk()) { + LOG(ERROR) << "Failed to invoke onFailure callback"; + } + } + LOG(ERROR) << "Wifi HAL start failed"; + // Clear the event callback objects since the HAL start failed. + event_cb_handler_.invalidate(); + } + return wifi_status; +} + +ndk::ScopedAStatus Wifi::stopInternal( + /* NONNULL */ std::unique_lock* lock) { + if (run_state_ == RunState::STOPPED) { + return ndk::ScopedAStatus::ok(); + } else if (run_state_ == RunState::STOPPING) { + return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping"); + } + // Clear the chip object and its child objects since the HAL is now + // stopped. + for (auto& chip : chips_) { + if (chip.get()) { + chip->invalidate(); + chip.reset(); + } + } + chips_.clear(); + ndk::ScopedAStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock); + if (wifi_status.isOk()) { + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onStop().isOk()) { + LOG(ERROR) << "Failed to invoke onStop callback"; + }; + } + LOG(INFO) << "Wifi HAL stopped"; + } else { + for (const auto& callback : event_cb_handler_.getCallbacks()) { + WifiStatusCode errorCode = + static_cast(wifi_status.getServiceSpecificError()); + if (!callback->onFailure(errorCode).isOk()) { + LOG(ERROR) << "Failed to invoke onFailure callback"; + } + } + LOG(ERROR) << "Wifi HAL stop failed"; + } + // Clear the event callback objects since the HAL is now stopped. + event_cb_handler_.invalidate(); + return wifi_status; +} + +std::pair, ndk::ScopedAStatus> Wifi::getChipIdsInternal() { + std::vector chip_ids; + + for (auto& chip : chips_) { + int32_t chip_id = getChipIdFromWifiChip(chip); + if (chip_id != INT32_MAX) chip_ids.emplace_back(chip_id); + } + return {std::move(chip_ids), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> Wifi::getChipInternal(int32_t chip_id) { + for (auto& chip : chips_) { + int32_t cand_id = getChipIdFromWifiChip(chip); + if ((cand_id != INT32_MAX) && (cand_id == chip_id)) return {chip, ndk::ScopedAStatus::ok()}; + } + + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; +} + +ndk::ScopedAStatus Wifi::initializeModeControllerAndLegacyHal() { + if (!mode_controller_->initialize()) { + LOG(ERROR) << "Failed to initialize firmware mode controller"; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + + legacy_hals_ = legacy_hal_factory_->getHals(); + if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + int index = 0; // for failure log + for (auto& hal : legacy_hals_) { + legacy_hal::wifi_error legacy_status = hal->initialize(); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // Currently WifiLegacyHal::initialize does not allocate extra mem, + // only initializes the function table. If this changes, need to + // implement WifiLegacyHal::deinitialize and deinitalize the + // HALs already initialized + LOG(ERROR) << "Failed to initialize legacy HAL index: " << index + << " error: " << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } + index++; + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Wifi::stopLegacyHalAndDeinitializeModeController( + /* NONNULL */ std::unique_lock* lock) { + legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS; + int index = 0; + + run_state_ = RunState::STOPPING; + for (auto& hal : legacy_hals_) { + legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {}); + if (tmp != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to stop legacy HAL index: " << index + << " error: " << legacyErrorToString(legacy_status); + legacy_status = tmp; + } + index++; + } + run_state_ = RunState::STOPPED; + + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "One or more legacy HALs failed to stop"; + return createWifiStatusFromLegacyError(legacy_status); + } + if (!mode_controller_->deinitialize()) { + LOG(ERROR) << "Failed to deinitialize firmware mode controller"; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +int32_t Wifi::getChipIdFromWifiChip(std::shared_ptr& chip) { + int32_t chip_id = INT32_MAX; + if (chip.get()) { + ndk::ScopedAStatus status = chip->getId(&chip_id); + if (!status.isOk()) { + // Reset value if operation failed. + chip_id = INT32_MAX; + } + } + return chip_id; +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi.h b/wifi/aidl/default/wifi.h new file mode 100644 index 0000000000..933452448e --- /dev/null +++ b/wifi/aidl/default/wifi.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_H_ +#define WIFI_H_ + +#include +#include +#include + +#include + +#include "aidl_callback_util.h" +#include "wifi_chip.h" +#include "wifi_feature_flags.h" +#include "wifi_legacy_hal.h" +#include "wifi_legacy_hal_factory.h" +#include "wifi_mode_controller.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * Root AIDL interface object used to control the Wifi HAL. + */ +class Wifi : public BnWifi { + public: + Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::shared_ptr legacy_hal_factory, + const std::shared_ptr mode_controller, + const std::shared_ptr feature_flags); + + bool isValid(); + + // AIDL methods exposed. + ndk::ScopedAStatus registerEventCallback( + const std::shared_ptr& in_callback) override; + ndk::ScopedAStatus isStarted(bool* _aidl_return) override; + ndk::ScopedAStatus start() override; + ndk::ScopedAStatus stop() override; + ndk::ScopedAStatus getChipIds(std::vector* _aidl_return) override; + ndk::ScopedAStatus getChip(int32_t in_chipId, + std::shared_ptr* _aidl_return) override; + binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; + + private: + enum class RunState { STOPPED, STARTED, STOPPING }; + + // Corresponding worker functions for the AIDL methods. + ndk::ScopedAStatus registerEventCallbackInternal( + const std::shared_ptr& event_callback __unused); + ndk::ScopedAStatus startInternal(); + ndk::ScopedAStatus stopInternal(std::unique_lock* lock); + std::pair, ndk::ScopedAStatus> getChipIdsInternal(); + std::pair, ndk::ScopedAStatus> getChipInternal(int32_t chip_id); + + ndk::ScopedAStatus initializeModeControllerAndLegacyHal(); + ndk::ScopedAStatus stopLegacyHalAndDeinitializeModeController( + std::unique_lock* lock); + int32_t getChipIdFromWifiChip(std::shared_ptr& chip); + + // Instance is created in this root level |IWifi| AIDL interface object + // and shared with all the child AIDL interface objects. + std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool_; + std::shared_ptr legacy_hal_factory_; + std::shared_ptr mode_controller_; + std::vector> legacy_hals_; + std::shared_ptr feature_flags_; + RunState run_state_; + std::vector> chips_; + aidl_callback_util::AidlCallbackHandler event_cb_handler_; + + DISALLOW_COPY_AND_ASSIGN(Wifi); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_H_ diff --git a/wifi/aidl/default/wifi_ap_iface.cpp b/wifi/aidl/default/wifi_ap_iface.cpp new file mode 100644 index 0000000000..6cd932df41 --- /dev/null +++ b/wifi/aidl/default/wifi_ap_iface.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2022 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 "wifi_ap_iface.h" + +#include + +#include "aidl_return_util.h" +#include "aidl_struct_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; + +WifiApIface::WifiApIface(const std::string& ifname, const std::vector& instances, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) + : ifname_(ifname), + instances_(instances), + legacy_hal_(legacy_hal), + iface_util_(iface_util), + is_valid_(true) {} + +void WifiApIface::invalidate() { + legacy_hal_.reset(); + is_valid_ = false; +} + +bool WifiApIface::isValid() { + return is_valid_; +} + +std::string WifiApIface::getName() { + return ifname_; +} + +void WifiApIface::removeInstance(std::string instance) { + instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end()); +} + +ndk::ScopedAStatus WifiApIface::getName(std::string* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::getNameInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiApIface::setCountryCode(const std::array& in_code) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::setCountryCodeInternal, in_code); +} + +ndk::ScopedAStatus WifiApIface::getValidFrequenciesForBand(WifiBand in_band, + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::getValidFrequenciesForBandInternal, _aidl_return, in_band); +} + +ndk::ScopedAStatus WifiApIface::setMacAddress(const std::array& in_mac) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::setMacAddressInternal, in_mac); +} + +ndk::ScopedAStatus WifiApIface::getFactoryMacAddress(std::array* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::getFactoryMacAddressInternal, _aidl_return, + instances_.size() > 0 ? instances_[0] : ifname_); +} + +ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::resetToFactoryMacAddressInternal); +} + +ndk::ScopedAStatus WifiApIface::getBridgedInstances(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiApIface::getBridgedInstancesInternal, _aidl_return); +} + +std::pair WifiApIface::getNameInternal() { + return {ifname_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiApIface::setCountryCodeInternal(const std::array& code) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode( + instances_.size() > 0 ? instances_[0] : ifname_, code); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair, ndk::ScopedAStatus> WifiApIface::getValidFrequenciesForBandInternal( + WifiBand band) { + static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch"); + legacy_hal::wifi_error legacy_status; + std::vector valid_frequencies; + std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand( + instances_.size() > 0 ? instances_[0] : ifname_, + aidl_struct_util::convertAidlWifiBandToLegacy(band)); + return {std::vector(valid_frequencies.begin(), valid_frequencies.end()), + createWifiStatusFromLegacyError(legacy_status)}; +} + +ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array& mac) { + // Support random MAC up to 2 interfaces + if (instances_.size() == 2) { + int rbyte = 1; + for (auto const& intf : instances_) { + std::array rmac = mac; + // reverse the bits to avoid collision + rmac[rbyte] = 0xff - rmac[rbyte]; + if (!iface_util_.lock()->setMacAddress(intf, rmac)) { + LOG(INFO) << "Failed to set random mac address on " << intf; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + rbyte++; + } + } + // It also needs to set mac address for bridged interface, otherwise the mac + // address of bridged interface will be changed after one of instance + // down. + if (!iface_util_.lock()->setMacAddress(ifname_, mac)) { + LOG(ERROR) << "Fail to config MAC for interface " << ifname_; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiApIface::getFactoryMacAddressInternal( + const std::string& ifaceName) { + std::array mac = iface_util_.lock()->getFactoryMacAddress(ifaceName); + if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) { + return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {mac, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() { + std::pair, ndk::ScopedAStatus> getMacResult; + if (instances_.size() == 2) { + for (auto const& intf : instances_) { + getMacResult = getFactoryMacAddressInternal(intf); + LOG(DEBUG) << "Reset MAC to factory MAC on " << intf; + if (!getMacResult.second.isOk() || + !iface_util_.lock()->setMacAddress(intf, getMacResult.first)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + } + // We need to set mac address for bridged interface, otherwise the mac + // address of the bridged interface will be changed after one of the + // instances goes down. Thus we are generating a random MAC address for + // the bridged interface even if we got the request to reset the Factory + // MAC. This is because the bridged interface is an internal interface + // for the operation of bpf and other networking operations. + if (!iface_util_.lock()->setMacAddress(ifname_, + iface_util_.lock()->createRandomMacAddress())) { + LOG(ERROR) << "Fail to config MAC for bridged interface " << ifname_; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + } else { + getMacResult = getFactoryMacAddressInternal(ifname_); + LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_; + if (!getMacResult.second.isOk() || + !iface_util_.lock()->setMacAddress(ifname_, getMacResult.first)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + } + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiApIface::getBridgedInstancesInternal() { + return {instances_, ndk::ScopedAStatus::ok()}; +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_ap_iface.h b/wifi/aidl/default/wifi_ap_iface.h new file mode 100644 index 0000000000..b5673fcaac --- /dev/null +++ b/wifi/aidl/default/wifi_ap_iface.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_AP_IFACE_H_ +#define WIFI_AP_IFACE_H_ + +#include +#include + +#include "wifi_iface_util.h" +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control an AP Iface instance. + */ +class WifiApIface : public BnWifiApIface { + public: + WifiApIface(const std::string& ifname, const std::vector& instances, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); + // Refer to |WifiChip::invalidate()|. + void invalidate(); + bool isValid(); + std::string getName(); + void removeInstance(std::string instance); + + // AIDL methods exposed. + ndk::ScopedAStatus getName(std::string* _aidl_return) override; + ndk::ScopedAStatus setCountryCode(const std::array& in_code) override; + ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band, + std::vector* _aidl_return) override; + ndk::ScopedAStatus setMacAddress(const std::array& in_mac) override; + ndk::ScopedAStatus getFactoryMacAddress(std::array* _aidl_return) override; + ndk::ScopedAStatus resetToFactoryMacAddress() override; + ndk::ScopedAStatus getBridgedInstances(std::vector* _aidl_return) override; + + private: + // Corresponding worker functions for the AIDL methods. + std::pair getNameInternal(); + ndk::ScopedAStatus setCountryCodeInternal(const std::array& code); + std::pair, ndk::ScopedAStatus> getValidFrequenciesForBandInternal( + WifiBand band); + ndk::ScopedAStatus setMacAddressInternal(const std::array& mac); + std::pair, ndk::ScopedAStatus> getFactoryMacAddressInternal( + const std::string& ifaceName); + ndk::ScopedAStatus resetToFactoryMacAddressInternal(); + std::pair, ndk::ScopedAStatus> getBridgedInstancesInternal(); + + std::string ifname_; + std::vector instances_; + std::weak_ptr legacy_hal_; + std::weak_ptr iface_util_; + bool is_valid_; + + DISALLOW_COPY_AND_ASSIGN(WifiApIface); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_AP_IFACE_H_ diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp new file mode 100644 index 0000000000..076f351448 --- /dev/null +++ b/wifi/aidl/default/wifi_chip.cpp @@ -0,0 +1,1910 @@ +/* + * Copyright (C) 2022 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 "wifi_chip.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "aidl_return_util.h" +#include "aidl_struct_util.h" +#include "wifi_status_util.h" + +#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-" + +namespace { +using aidl::android::hardware::wifi::IfaceType; +using aidl::android::hardware::wifi::IWifiChip; +using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction; +using android::base::unique_fd; + +constexpr char kCpioMagic[] = "070701"; +constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3; +constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10; +constexpr uint32_t kMaxRingBufferFileNum = 20; +constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/"; +constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface"; +constexpr char kNoActiveWlanIfaceNamePropertyValue[] = ""; +constexpr unsigned kMaxWlanIfaces = 5; +constexpr char kApBridgeIfacePrefix[] = "ap_br_"; + +template +void invalidateAndClear(std::vector>& ifaces, std::shared_ptr iface) { + iface->invalidate(); + ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end()); +} + +template +void invalidateAndClearAll(std::vector>& ifaces) { + for (const auto& iface : ifaces) { + iface->invalidate(); + } + ifaces.clear(); +} + +template +std::vector getNames(std::vector>& ifaces) { + std::vector names; + for (const auto& iface : ifaces) { + names.emplace_back(iface->getName()); + } + return names; +} + +template +std::shared_ptr findUsingName(std::vector>& ifaces, + const std::string& name) { + std::vector names; + for (const auto& iface : ifaces) { + if (name == iface->getName()) { + return iface; + } + } + return nullptr; +} + +std::string getWlanIfaceName(unsigned idx) { + if (idx >= kMaxWlanIfaces) { + CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces; + return {}; + } + + std::array buffer; + if (idx == 0 || idx == 1) { + const char* altPropName = (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface"; + auto res = property_get(altPropName, buffer.data(), nullptr); + if (res > 0) return buffer.data(); + } + std::string propName = "wifi.interface." + std::to_string(idx); + auto res = property_get(propName.c_str(), buffer.data(), nullptr); + if (res > 0) return buffer.data(); + + return "wlan" + std::to_string(idx); +} + +// Returns the dedicated iface name if defined. +// Returns two ifaces in bridged mode. +std::vector getPredefinedApIfaceNames(bool is_bridged) { + std::vector ifnames; + std::array buffer; + buffer.fill(0); + if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == 0) { + return ifnames; + } + ifnames.push_back(buffer.data()); + if (is_bridged) { + buffer.fill(0); + if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(), nullptr) == 0) { + return ifnames; + } + ifnames.push_back(buffer.data()); + } + return ifnames; +} + +std::string getPredefinedP2pIfaceName() { + std::array primaryIfaceName; + char p2pParentIfname[100]; + std::string p2pDevIfName = ""; + std::array buffer; + property_get("wifi.direct.interface", buffer.data(), "p2p0"); + if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) { + /* Get the p2p parent interface name from p2p device interface name set + * in property */ + strlcpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX), + strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)); + if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(), nullptr) == 0) { + return buffer.data(); + } + /* Check if the parent interface derived from p2p device interface name + * is active */ + if (strncmp(p2pParentIfname, primaryIfaceName.data(), + strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) != 0) { + /* + * Update the predefined p2p device interface parent interface name + * with current active wlan interface + */ + p2pDevIfName += P2P_MGMT_DEVICE_PREFIX; + p2pDevIfName += primaryIfaceName.data(); + LOG(INFO) << "update the p2p device interface name to " << p2pDevIfName.c_str(); + return p2pDevIfName; + } + } + return buffer.data(); +} + +// Returns the dedicated iface name if one is defined. +std::string getPredefinedNanIfaceName() { + std::array buffer; + if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) { + return {}; + } + return buffer.data(); +} + +void setActiveWlanIfaceNameProperty(const std::string& ifname) { + auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data()); + if (res != 0) { + PLOG(ERROR) << "Failed to set active wlan iface name property"; + } +} + +// Delete files that meet either condition: +// 1. Older than a predefined time in the wifi tombstone dir. +// 2. Files in excess to a predefined amount, starting from the oldest ones +bool removeOldFilesInternal() { + time_t now = time(0); + const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds; + std::unique_ptr dir_dump(opendir(kTombstoneFolderPath), closedir); + if (!dir_dump) { + PLOG(ERROR) << "Failed to open directory"; + return false; + } + struct dirent* dp; + bool success = true; + std::list> valid_files; + while ((dp = readdir(dir_dump.get()))) { + if (dp->d_type != DT_REG) { + continue; + } + std::string cur_file_name(dp->d_name); + struct stat cur_file_stat; + std::string cur_file_path = kTombstoneFolderPath + cur_file_name; + if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) { + PLOG(ERROR) << "Failed to get file stat for " << cur_file_path; + success = false; + continue; + } + const time_t cur_file_time = cur_file_stat.st_mtime; + valid_files.push_back(std::pair(cur_file_time, cur_file_path)); + } + valid_files.sort(); // sort the list of files by last modified time from + // small to big. + uint32_t cur_file_count = valid_files.size(); + for (auto cur_file : valid_files) { + if (cur_file_count > kMaxRingBufferFileNum || cur_file.first < delete_files_before) { + if (unlink(cur_file.second.c_str()) != 0) { + PLOG(ERROR) << "Error deleting file"; + success = false; + } + cur_file_count--; + } else { + break; + } + } + return success; +} + +// Helper function for |cpioArchiveFilesInDir| +bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) { + const int buf_size = 32 * 1024; + std::array read_buf; + ssize_t llen = snprintf( + read_buf.data(), buf_size, "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X", + kCpioMagic, static_cast(st.st_ino), st.st_mode, st.st_uid, st.st_gid, + static_cast(st.st_nlink), static_cast(st.st_mtime), + static_cast(st.st_size), major(st.st_dev), minor(st.st_dev), major(st.st_rdev), + minor(st.st_rdev), static_cast(file_name_len), 0); + if (write(out_fd, read_buf.data(), llen < buf_size ? llen : buf_size - 1) == -1) { + PLOG(ERROR) << "Error writing cpio header to file " << file_name; + return false; + } + if (write(out_fd, file_name, file_name_len) == -1) { + PLOG(ERROR) << "Error writing filename to file " << file_name; + return false; + } + + // NUL Pad header up to 4 multiple bytes. + llen = (llen + file_name_len) % 4; + if (llen != 0) { + const uint32_t zero = 0; + if (write(out_fd, &zero, 4 - llen) == -1) { + PLOG(ERROR) << "Error padding 0s to file " << file_name; + return false; + } + } + return true; +} + +// Helper function for |cpioArchiveFilesInDir| +size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) { + // writing content of file + std::array read_buf; + ssize_t llen = st.st_size; + size_t n_error = 0; + while (llen > 0) { + ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size()); + if (bytes_read == -1) { + PLOG(ERROR) << "Error reading file"; + return ++n_error; + } + llen -= bytes_read; + if (write(out_fd, read_buf.data(), bytes_read) == -1) { + PLOG(ERROR) << "Error writing data to file"; + return ++n_error; + } + if (bytes_read == 0) { // this should never happen, but just in case + // to unstuck from while loop + PLOG(ERROR) << "Unexpected read result"; + n_error++; + break; + } + } + llen = st.st_size % 4; + if (llen != 0) { + const uint32_t zero = 0; + if (write(out_fd, &zero, 4 - llen) == -1) { + PLOG(ERROR) << "Error padding 0s to file"; + return ++n_error; + } + } + return n_error; +} + +// Helper function for |cpioArchiveFilesInDir| +bool cpioWriteFileTrailer(int out_fd) { + const int buf_size = 4096; + std::array read_buf; + read_buf.fill(0); + ssize_t llen = snprintf(read_buf.data(), 4096, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0); + if (write(out_fd, read_buf.data(), (llen < buf_size ? llen : buf_size - 1) + 4) == -1) { + PLOG(ERROR) << "Error writing trailing bytes"; + return false; + } + return true; +} + +// Archives all files in |input_dir| and writes result into |out_fd| +// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive" +// portion +size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) { + struct dirent* dp; + size_t n_error = 0; + std::unique_ptr dir_dump(opendir(input_dir), closedir); + if (!dir_dump) { + PLOG(ERROR) << "Failed to open directory"; + return ++n_error; + } + while ((dp = readdir(dir_dump.get()))) { + if (dp->d_type != DT_REG) { + continue; + } + std::string cur_file_name(dp->d_name); + struct stat st; + const std::string cur_file_path = kTombstoneFolderPath + cur_file_name; + if (stat(cur_file_path.c_str(), &st) == -1) { + PLOG(ERROR) << "Failed to get file stat for " << cur_file_path; + n_error++; + continue; + } + const int fd_read = open(cur_file_path.c_str(), O_RDONLY); + if (fd_read == -1) { + PLOG(ERROR) << "Failed to open file " << cur_file_path; + n_error++; + continue; + } + std::string file_name_with_last_modified_time = + cur_file_name + "-" + std::to_string(st.st_mtime); + // string.size() does not include the null terminator. The cpio FreeBSD + // file header expects the null character to be included in the length. + const size_t file_name_len = file_name_with_last_modified_time.size() + 1; + unique_fd file_auto_closer(fd_read); + if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(), + file_name_len)) { + return ++n_error; + } + size_t write_error = cpioWriteFileContent(fd_read, out_fd, st); + if (write_error) { + return n_error + write_error; + } + } + if (!cpioWriteFileTrailer(out_fd)) { + return ++n_error; + } + return n_error; +} + +// Helper function to create a non-const char*. +std::vector makeCharVec(const std::string& str) { + std::vector vec(str.size() + 1); + vec.assign(str.begin(), str.end()); + vec.push_back('\0'); + return vec; +} + +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; +using aidl_return_util::validateAndCallWithLock; + +WifiChip::WifiChip(int32_t chip_id, bool is_primary, + const std::weak_ptr legacy_hal, + const std::weak_ptr mode_controller, + const std::shared_ptr iface_util, + const std::weak_ptr feature_flags, + const std::function& handler) + : chip_id_(chip_id), + legacy_hal_(legacy_hal), + mode_controller_(mode_controller), + iface_util_(iface_util), + is_valid_(true), + current_mode_id_(feature_flags::chip_mode_ids::kInvalid), + modes_(feature_flags.lock()->getChipModes(is_primary)), + debug_ring_buffer_cb_registered_(false), + subsystemCallbackHandler_(handler) { + setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue); +} + +std::shared_ptr WifiChip::create( + int32_t chip_id, bool is_primary, const std::weak_ptr legacy_hal, + const std::weak_ptr mode_controller, + const std::shared_ptr iface_util, + const std::weak_ptr feature_flags, + const std::function& handler) { + std::shared_ptr ptr = ndk::SharedRefBase::make( + chip_id, is_primary, legacy_hal, mode_controller, iface_util, feature_flags, handler); + std::weak_ptr weak_ptr_this(ptr); + ptr->setWeakPtr(weak_ptr_this); + return ptr; +} + +void WifiChip::invalidate() { + if (!writeRingbufferFilesInternal()) { + LOG(ERROR) << "Error writing files to flash"; + } + invalidateAndRemoveAllIfaces(); + setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue); + legacy_hal_.reset(); + event_cb_handler_.invalidate(); + is_valid_ = false; +} + +void WifiChip::setWeakPtr(std::weak_ptr ptr) { + weak_ptr_this_ = ptr; +} + +bool WifiChip::isValid() { + return is_valid_; +} + +std::set> WifiChip::getEventCallbacks() { + return event_cb_handler_.getCallbacks(); +} + +ndk::ScopedAStatus WifiChip::getId(int32_t* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal, + _aidl_return); +} + +ndk::ScopedAStatus WifiChip::registerEventCallback( + const std::shared_ptr& event_callback) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::registerEventCallbackInternal, event_callback); +} + +ndk::ScopedAStatus WifiChip::getCapabilities(IWifiChip::ChipCapabilityMask* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getAvailableModes(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getAvailableModesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::configureChip(int32_t in_modeId) { + return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::configureChipInternal, in_modeId); +} + +ndk::ScopedAStatus WifiChip::getMode(int32_t* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getModeInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::requestChipDebugInfoInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::requestDriverDebugDump(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::requestDriverDebugDumpInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::requestFirmwareDebugDump(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::requestFirmwareDebugDumpInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::createApIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createApIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createBridgedApIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getApIfaceNames(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getApIfaceNamesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getApIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getApIfaceInternal, _aidl_return, in_ifname); +} + +ndk::ScopedAStatus WifiChip::removeApIface(const std::string& in_ifname) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::removeApIfaceInternal, in_ifname); +} + +ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIface( + const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, in_brIfaceName, + in_ifaceInstanceName); +} + +ndk::ScopedAStatus WifiChip::createNanIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createNanIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getNanIfaceNames(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getNanIfaceNamesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getNanIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getNanIfaceInternal, _aidl_return, in_ifname); +} + +ndk::ScopedAStatus WifiChip::removeNanIface(const std::string& in_ifname) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::removeNanIfaceInternal, in_ifname); +} + +ndk::ScopedAStatus WifiChip::createP2pIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createP2pIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getP2pIfaceNames(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getP2pIfaceNamesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getP2pIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getP2pIfaceInternal, _aidl_return, in_ifname); +} + +ndk::ScopedAStatus WifiChip::removeP2pIface(const std::string& in_ifname) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::removeP2pIfaceInternal, in_ifname); +} + +ndk::ScopedAStatus WifiChip::createStaIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createStaIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getStaIfaceNames(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getStaIfaceNamesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::getStaIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getStaIfaceInternal, _aidl_return, in_ifname); +} + +ndk::ScopedAStatus WifiChip::removeStaIface(const std::string& in_ifname) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::removeStaIfaceInternal, in_ifname); +} + +ndk::ScopedAStatus WifiChip::createRttController( + const std::shared_ptr& in_boundIface, + std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createRttControllerInternal, _aidl_return, in_boundIface); +} + +ndk::ScopedAStatus WifiChip::getDebugRingBuffersStatus( + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getDebugRingBuffersStatusInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBuffer( + const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel, + int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::startLoggingToDebugRingBufferInternal, in_ringName, + in_verboseLevel, in_maxIntervalInSec, in_minDataSizeInBytes); +} + +ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBuffer(const std::string& in_ringName) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::forceDumpToDebugRingBufferInternal, in_ringName); +} + +ndk::ScopedAStatus WifiChip::flushRingBufferToFile() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::flushRingBufferToFileInternal); +} + +ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBuffer() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::stopLoggingToDebugRingBufferInternal); +} + +ndk::ScopedAStatus WifiChip::getDebugHostWakeReasonStats( + WifiDebugHostWakeReasonStats* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getDebugHostWakeReasonStatsInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiChip::enableDebugErrorAlerts(bool in_enable) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::enableDebugErrorAlertsInternal, in_enable); +} + +ndk::ScopedAStatus WifiChip::selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::selectTxPowerScenarioInternal, in_scenario); +} + +ndk::ScopedAStatus WifiChip::resetTxPowerScenario() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::resetTxPowerScenarioInternal); +} + +ndk::ScopedAStatus WifiChip::setLatencyMode(IWifiChip::LatencyMode in_mode) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setLatencyModeInternal, in_mode); +} + +binder_status_t WifiChip::dump(int fd, const char**, uint32_t) { + { + std::unique_lock lk(lock_t); + for (const auto& item : ringbuffer_map_) { + forceDumpToDebugRingBufferInternal(item.first); + } + // unique_lock unlocked here + } + usleep(100 * 1000); // sleep for 100 milliseconds to wait for + // ringbuffer updates. + if (!writeRingbufferFilesInternal()) { + LOG(ERROR) << "Error writing files to flash"; + } + uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath); + if (n_error != 0) { + LOG(ERROR) << n_error << " errors occurred in cpio function"; + } + fsync(fd); + return STATUS_OK; +} + +ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnection(const std::string& in_ifName) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setMultiStaPrimaryConnectionInternal, in_ifName); +} + +ndk::ScopedAStatus WifiChip::setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setMultiStaUseCaseInternal, in_useCase); +} + +ndk::ScopedAStatus WifiChip::setCoexUnsafeChannels( + const std::vector& in_unsafeChannels, + CoexRestriction in_restrictions) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::setCoexUnsafeChannelsInternal, in_unsafeChannels, + in_restrictions); +} + +ndk::ScopedAStatus WifiChip::setCountryCode(const std::array& in_code) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiChip::setCountryCodeInternal, in_code); +} + +ndk::ScopedAStatus WifiChip::getUsableChannels(WifiBand in_band, WifiIfaceMode in_ifaceModeMask, + UsableChannelFilter in_filterMask, + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getUsableChannelsInternal, _aidl_return, in_band, + in_ifaceModeMask, in_filterMask); +} + +ndk::ScopedAStatus WifiChip::triggerSubsystemRestart() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::triggerSubsystemRestartInternal); +} + +ndk::ScopedAStatus WifiChip::getSupportedRadioCombinationsMatrix( + WifiRadioCombinationMatrix* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::getSupportedRadioCombinationsMatrixInternal, _aidl_return); +} + +void WifiChip::invalidateAndRemoveAllIfaces() { + invalidateAndClearBridgedApAll(); + invalidateAndClearAll(ap_ifaces_); + invalidateAndClearAll(nan_ifaces_); + invalidateAndClearAll(p2p_ifaces_); + invalidateAndClearAll(sta_ifaces_); + // Since all the ifaces are invalid now, all RTT controller objects + // using those ifaces also need to be invalidated. + for (const auto& rtt : rtt_controllers_) { + rtt->invalidate(); + } + rtt_controllers_.clear(); +} + +void WifiChip::invalidateAndRemoveDependencies(const std::string& removed_iface_name) { + for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) { + auto nan_iface = *it; + if (nan_iface->getName() == removed_iface_name) { + nan_iface->invalidate(); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, removed_iface_name).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; + } + } + it = nan_ifaces_.erase(it); + } else { + ++it; + } + } + + for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) { + auto rtt = *it; + if (rtt->getIfaceName() == removed_iface_name) { + rtt->invalidate(); + it = rtt_controllers_.erase(it); + } else { + ++it; + } + } +} + +std::pair WifiChip::getIdInternal() { + return {chip_id_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::registerEventCallbackInternal( + const std::shared_ptr& event_callback) { + if (!event_cb_handler_.addCallback(event_callback)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +std::pair WifiChip::getCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + uint32_t legacy_logger_feature_set; + const auto ifname = getFirstActiveWlanIfaceName(); + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {IWifiChip::ChipCapabilityMask{}, createWifiStatusFromLegacyError(legacy_status)}; + } + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t aidl_caps; + if (!aidl_struct_util::convertLegacyFeaturesToAidlChipCapabilities( + legacy_feature_set, legacy_logger_feature_set, &aidl_caps)) { + return {IWifiChip::ChipCapabilityMask{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {static_cast(aidl_caps), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> +WifiChip::getAvailableModesInternal() { + return {modes_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::configureChipInternal( + /* NONNULL */ std::unique_lock* lock, int32_t mode_id) { + if (!isValidModeId(mode_id)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + if (mode_id == current_mode_id_) { + LOG(DEBUG) << "Already in the specified mode " << mode_id; + return ndk::ScopedAStatus::ok(); + } + ndk::ScopedAStatus status = handleChipConfiguration(lock, mode_id); + if (!status.isOk()) { + WifiStatusCode errorCode = static_cast(status.getServiceSpecificError()); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onChipReconfigureFailure(errorCode).isOk()) { + LOG(ERROR) << "Failed to invoke onChipReconfigureFailure callback"; + } + } + return status; + } + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onChipReconfigured(mode_id).isOk()) { + LOG(ERROR) << "Failed to invoke onChipReconfigured callback"; + } + } + current_mode_id_ = mode_id; + LOG(INFO) << "Configured chip in mode " << mode_id; + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + + legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(subsystemCallbackHandler_); + + return status; +} + +std::pair WifiChip::getModeInternal() { + if (!isValidModeId(current_mode_id_)) { + return {current_mode_id_, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + return {current_mode_id_, ndk::ScopedAStatus::ok()}; +} + +std::pair WifiChip::requestChipDebugInfoInternal() { + IWifiChip::ChipDebugInfo result; + legacy_hal::wifi_error legacy_status; + std::string driver_desc; + const auto ifname = getFirstActiveWlanIfaceName(); + std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status); + ndk::ScopedAStatus status = + createWifiStatusFromLegacyError(legacy_status, "failed to get driver version"); + return {std::move(result), std::move(status)}; + } + result.driverDescription = driver_desc.c_str(); + + std::string firmware_desc; + std::tie(legacy_status, firmware_desc) = legacy_hal_.lock()->getFirmwareVersion(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status); + ndk::ScopedAStatus status = + createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version"); + return {std::move(result), std::move(status)}; + } + result.firmwareDescription = firmware_desc.c_str(); + + return {std::move(result), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::requestDriverDebugDumpInternal() { + legacy_hal::wifi_error legacy_status; + std::vector driver_dump; + std::tie(legacy_status, driver_dump) = + legacy_hal_.lock()->requestDriverMemoryDump(getFirstActiveWlanIfaceName()); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status); + return {std::vector(), createWifiStatusFromLegacyError(legacy_status)}; + } + return {driver_dump, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::requestFirmwareDebugDumpInternal() { + legacy_hal::wifi_error legacy_status; + std::vector firmware_dump; + std::tie(legacy_status, firmware_dump) = + legacy_hal_.lock()->requestFirmwareMemoryDump(getFirstActiveWlanIfaceName()); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status); + return {std::vector(), createWifiStatusFromLegacyError(legacy_status)}; + } + return {firmware_dump, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) { + legacy_hal::wifi_error legacy_status; + legacy_status = legacy_hal_.lock()->createVirtualInterface( + apVirtIf, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::AP)); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to add interface: " << apVirtIf << " " + << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } + return ndk::ScopedAStatus::ok(); +} + +std::shared_ptr WifiChip::newWifiApIface(std::string& ifname) { + std::vector ap_instances; + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == ifname) { + ap_instances = it.second; + } + } + std::shared_ptr iface = + ndk::SharedRefBase::make(ifname, ap_instances, legacy_hal_, iface_util_); + ap_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + return iface; +} + +std::pair, ndk::ScopedAStatus> WifiChip::createApIfaceInternal() { + if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP)) { + return {std::shared_ptr(), + createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::string ifname = allocateApIfaceName(); + ndk::ScopedAStatus status = createVirtualApInterface(ifname); + if (!status.isOk()) { + return {std::shared_ptr(), std::move(status)}; + } + std::shared_ptr iface = newWifiApIface(ifname); + return {iface, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> +WifiChip::createBridgedApIfaceInternal() { + if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::vector ap_instances = allocateBridgedApInstanceNames(); + if (ap_instances.size() < 2) { + LOG(ERROR) << "Fail to allocate two instances"; + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0]; + for (int i = 0; i < 2; i++) { + ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]); + if (!status.isOk()) { + if (i != 0) { // The failure happened when creating second virtual + // iface. + legacy_hal_.lock()->deleteVirtualInterface( + ap_instances.front()); // Remove the first virtual iface. + } + return {nullptr, std::move(status)}; + } + } + br_ifaces_ap_instances_[br_ifname] = ap_instances; + if (!iface_util_->createBridge(br_ifname)) { + LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str(); + invalidateAndClearBridgedAp(br_ifname); + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + for (auto const& instance : ap_instances) { + // Bind ap instance interface to AP bridge + if (!iface_util_->addIfaceToBridge(br_ifname, instance)) { + LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str(); + invalidateAndClearBridgedAp(br_ifname); + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + } + std::shared_ptr iface = newWifiApIface(br_ifname); + return {iface, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getApIfaceNamesInternal() { + if (ap_ifaces_.empty()) { + return {std::vector(), ndk::ScopedAStatus::ok()}; + } + return {getNames(ap_ifaces_), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getApIfaceInternal( + const std::string& ifname) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + // Invalidate & remove any dependent objects first. + // Note: This is probably not required because we never create + // nan/rtt objects over AP iface. But, there is no harm to do it + // here and not make that assumption all over the place. + invalidateAndRemoveDependencies(ifname); + // Clear the bridge interface and the iface instance. + invalidateAndClearBridgedAp(ifname); + invalidateAndClear(ap_ifaces_, iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; + } + } + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal( + const std::string& ifname, const std::string& ifInstanceName) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get() || ifInstanceName.empty()) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + // Requires to remove one of the instance in bridge mode + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == ifname) { + std::vector ap_instances = it.second; + for (auto const& iface : ap_instances) { + if (iface == ifInstanceName) { + if (!iface_util_->removeIfaceFromBridge(it.first, iface)) { + LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from " + << ifname; + return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->deleteVirtualInterface(iface); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to del interface: " << iface << " " + << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } + ap_instances.erase( + std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName), + ap_instances.end()); + br_ifaces_ap_instances_[ifname] = ap_instances; + break; + } + } + break; + } + } + iface->removeInstance(ifInstanceName); + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiChip::createNanIfaceInternal() { + if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::NAN_IFACE)) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + bool is_dedicated_iface = true; + std::string ifname = getPredefinedNanIfaceName(); + if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) { + // Use the first shared STA iface (wlan0) if a dedicated aware iface is + // not defined. + ifname = getFirstActiveWlanIfaceName(); + is_dedicated_iface = false; + } + std::shared_ptr iface = + WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_); + nan_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getNanIfaceNamesInternal() { + if (nan_ifaces_.empty()) { + return {std::vector(), ndk::ScopedAStatus::ok()}; + } + return {getNames(nan_ifaces_), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getNanIfaceInternal( + const std::string& ifname) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + invalidateAndClear(nan_ifaces_, iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiChip::createP2pIfaceInternal() { + if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::P2P)) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::string ifname = getPredefinedP2pIfaceName(); + std::shared_ptr iface = + ndk::SharedRefBase::make(ifname, legacy_hal_); + p2p_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getP2pIfaceNamesInternal() { + if (p2p_ifaces_.empty()) { + return {std::vector(), ndk::ScopedAStatus::ok()}; + } + return {getNames(p2p_ifaces_), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getP2pIfaceInternal( + const std::string& ifname) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + invalidateAndClear(p2p_ifaces_, iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; + } + } + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiChip::createStaIfaceInternal() { + if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::string ifname = allocateStaIfaceName(); + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface( + ifname, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::STA)); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to add interface: " << ifname << " " + << legacyErrorToString(legacy_status); + return {nullptr, createWifiStatusFromLegacyError(legacy_status)}; + } + std::shared_ptr iface = + ndk::SharedRefBase::make(ifname, legacy_hal_, iface_util_); + sta_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + return {iface, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getStaIfaceNamesInternal() { + if (sta_ifaces_.empty()) { + return {std::vector(), ndk::ScopedAStatus::ok()}; + } + return {getNames(sta_ifaces_), ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> WifiChip::getStaIfaceInternal( + const std::string& ifname) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } + return {iface, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + // Invalidate & remove any dependent objects first. + invalidateAndRemoveDependencies(ifname); + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(ifname); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to remove interface: " << ifname << " " + << legacyErrorToString(legacy_status); + } + invalidateAndClear(sta_ifaces_, iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; + } + } + setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName()); + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> +WifiChip::createRttControllerInternal(const std::shared_ptr& bound_iface) { + if (sta_ifaces_.size() == 0 && + !canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) { + LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs " + "(and RTT by extension)"; + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + std::shared_ptr rtt = + WifiRttController::create(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_); + rtt_controllers_.emplace_back(rtt); + return {rtt, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> +WifiChip::getDebugRingBuffersStatusInternal() { + legacy_hal::wifi_error legacy_status; + std::vector legacy_ring_buffer_status_vec; + std::tie(legacy_status, legacy_ring_buffer_status_vec) = + legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName()); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {std::vector(), + createWifiStatusFromLegacyError(legacy_status)}; + } + std::vector aidl_ring_buffer_status_vec; + if (!aidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToAidl( + legacy_ring_buffer_status_vec, &aidl_ring_buffer_status_vec)) { + return {std::vector(), + createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_ring_buffer_status_vec, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBufferInternal( + const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level, + uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) { + ndk::ScopedAStatus status = registerDebugRingBufferCallback(); + if (!status.isOk()) { + return status; + } + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging( + getFirstActiveWlanIfaceName(), ring_name, + static_cast::type>(verbose_level), + max_interval_in_sec, min_data_size_in_bytes); + ringbuffer_map_.insert( + std::pair(ring_name, Ringbuffer(kMaxBufferSizeBytes))); + // if verbose logging enabled, turn up HAL daemon logging as well. + if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) { + ::android::base::SetMinimumLogSeverity(::android::base::DEBUG); + } else { + ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE); + } + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBufferInternal(const std::string& ring_name) { + ndk::ScopedAStatus status = registerDebugRingBufferCallback(); + if (!status.isOk()) { + return status; + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name); + + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::flushRingBufferToFileInternal() { + if (!writeRingbufferFilesInternal()) { + LOG(ERROR) << "Error writing files to flash"; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBufferInternal() { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->deregisterRingBufferCallbackHandler(getFirstActiveWlanIfaceName()); + if (legacy_status == legacy_hal::WIFI_SUCCESS) { + debug_ring_buffer_cb_registered_ = false; + } + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair +WifiChip::getDebugHostWakeReasonStatsInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::WakeReasonStats legacy_stats; + std::tie(legacy_status, legacy_stats) = + legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName()); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {WifiDebugHostWakeReasonStats{}, createWifiStatusFromLegacyError(legacy_status)}; + } + WifiDebugHostWakeReasonStats aidl_stats; + if (!aidl_struct_util::convertLegacyWakeReasonStatsToAidl(legacy_stats, &aidl_stats)) { + return {WifiDebugHostWakeReasonStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_stats, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) { + legacy_hal::wifi_error legacy_status; + if (enable) { + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_alert_callback = [weak_ptr_this](int32_t error_code, + std::vector debug_data) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) { + LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback"; + } + } + }; + legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler( + getFirstActiveWlanIfaceName(), on_alert_callback); + } else { + legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler( + getFirstActiveWlanIfaceName()); + } + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario) { + auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario( + getFirstActiveWlanIfaceName(), + aidl_struct_util::convertAidlTxPowerScenarioToLegacy(scenario)); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::resetTxPowerScenarioInternal() { + auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName()); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::setLatencyModeInternal(IWifiChip::LatencyMode mode) { + auto legacy_status = legacy_hal_.lock()->setLatencyMode( + getFirstActiveWlanIfaceName(), aidl_struct_util::convertAidlLatencyModeToLegacy(mode)); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) { + auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case) { + auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase( + aidl_struct_util::convertAidlMultiStaUseCaseToLegacy(use_case)); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::setCoexUnsafeChannelsInternal( + std::vector unsafe_channels, CoexRestriction restrictions) { + std::vector legacy_unsafe_channels; + if (!aidl_struct_util::convertAidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels, + &legacy_unsafe_channels)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + uint32_t aidl_restrictions = static_cast(restrictions); + uint32_t legacy_restrictions = 0; + if (aidl_restrictions & static_cast(CoexRestriction::WIFI_DIRECT)) { + legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT; + } + if (aidl_restrictions & static_cast(CoexRestriction::SOFTAP)) { + legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP; + } + if (aidl_restrictions & static_cast(CoexRestriction::WIFI_AWARE)) { + legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE; + } + auto legacy_status = + legacy_hal_.lock()->setCoexUnsafeChannels(legacy_unsafe_channels, legacy_restrictions); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::setCountryCodeInternal(const std::array& code) { + auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair, ndk::ScopedAStatus> WifiChip::getUsableChannelsInternal( + WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask) { + legacy_hal::wifi_error legacy_status; + std::vector legacy_usable_channels; + std::tie(legacy_status, legacy_usable_channels) = legacy_hal_.lock()->getUsableChannels( + aidl_struct_util::convertAidlWifiBandToLegacyMacBand(band), + aidl_struct_util::convertAidlWifiIfaceModeToLegacy( + static_cast(ifaceModeMask)), + aidl_struct_util::convertAidlUsableChannelFilterToLegacy( + static_cast(filterMask))); + + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {std::vector(), createWifiStatusFromLegacyError(legacy_status)}; + } + std::vector aidl_usable_channels; + if (!aidl_struct_util::convertLegacyWifiUsableChannelsToAidl(legacy_usable_channels, + &aidl_usable_channels)) { + return {std::vector(), createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_usable_channels, ndk::ScopedAStatus::ok()}; +} + +std::pair +WifiChip::getSupportedRadioCombinationsMatrixInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_radio_combination_matrix* legacy_matrix; + + std::tie(legacy_status, legacy_matrix) = + legacy_hal_.lock()->getSupportedRadioCombinationsMatrix(); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: " + << legacyErrorToString(legacy_status); + return {WifiRadioCombinationMatrix{}, createWifiStatusFromLegacyError(legacy_status)}; + } + + WifiRadioCombinationMatrix aidl_matrix; + if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, + &aidl_matrix)) { + LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() "; + return {WifiRadioCombinationMatrix(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } + return {aidl_matrix, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() { + auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart(); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::handleChipConfiguration( + /* NONNULL */ std::unique_lock* lock, int32_t mode_id) { + // If the chip is already configured in a different mode, stop + // the legacy HAL and then start it after firmware mode change. + if (isValidModeId(current_mode_id_)) { + LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id; + invalidateAndRemoveAllIfaces(); + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop(lock, []() {}); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to stop legacy HAL: " << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } + } + // Firmware mode change not needed for V2 devices. + bool success = true; + if (mode_id == feature_flags::chip_mode_ids::kV1Sta) { + success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA); + } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) { + success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP); + } + if (!success) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start(); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to start legacy HAL: " << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } + // Every time the HAL is restarted, we need to register the + // radio mode change callback. + ndk::ScopedAStatus status = registerRadioModeChangeCallback(); + if (!status.isOk()) { + // This is probably not a critical failure? + LOG(ERROR) << "Failed to register radio mode change callback"; + } + // Extract and save the version information into property. + std::pair version_info; + version_info = WifiChip::requestChipDebugInfoInternal(); + if (version_info.second.isOk()) { + property_set("vendor.wlan.firmware.version", + version_info.first.firmwareDescription.c_str()); + property_set("vendor.wlan.driver.version", version_info.first.driverDescription.c_str()); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus WifiChip::registerDebugRingBufferCallback() { + if (debug_ring_buffer_cb_registered_) { + return ndk::ScopedAStatus::ok(); + } + + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_ring_buffer_data_callback = + [weak_ptr_this](const std::string& name, const std::vector& data, + const legacy_hal::wifi_ring_buffer_status& status) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + WifiDebugRingBufferStatus aidl_status; + Ringbuffer::AppendStatus appendstatus; + if (!aidl_struct_util::convertLegacyDebugRingBufferStatusToAidl(status, + &aidl_status)) { + LOG(ERROR) << "Error converting ring buffer status"; + return; + } + { + std::unique_lock lk(shared_ptr_this->lock_t); + const auto& target = shared_ptr_this->ringbuffer_map_.find(name); + if (target != shared_ptr_this->ringbuffer_map_.end()) { + Ringbuffer& cur_buffer = target->second; + appendstatus = cur_buffer.append(data); + } else { + LOG(ERROR) << "Ringname " << name << " not found"; + return; + } + // unique_lock unlocked here + } + if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) { + LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer"; + shared_ptr_this->writeRingbufferFilesInternal(); + return; + } + }; + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler( + getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback); + + if (legacy_status == legacy_hal::WIFI_SUCCESS) { + debug_ring_buffer_cb_registered_ = true; + } + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiChip::registerRadioModeChangeCallback() { + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_radio_mode_change_callback = + [weak_ptr_this](const std::vector& mac_infos) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + std::vector aidl_radio_mode_infos; + if (!aidl_struct_util::convertLegacyWifiMacInfosToAidl(mac_infos, + &aidl_radio_mode_infos)) { + LOG(ERROR) << "Error converting wifi mac info"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onRadioModeChange(aidl_radio_mode_infos).isOk()) { + LOG(ERROR) << "Failed to invoke onRadioModeChange callback"; + } + } + }; + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->registerRadioModeChangeCallbackHandler( + getFirstActiveWlanIfaceName(), on_radio_mode_change_callback); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::vector +WifiChip::getCurrentModeConcurrencyCombinations() { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return std::vector(); + } + for (const auto& mode : modes_) { + if (mode.id == current_mode_id_) { + return mode.availableCombinations; + } + } + CHECK(0) << "Expected to find concurrency combinations for current mode!"; + return std::vector(); +} + +// Returns a map indexed by IfaceConcurrencyType with the number of ifaces currently +// created of the corresponding concurrency type. +std::map WifiChip::getCurrentConcurrencyCombination() { + std::map iface_counts; + uint32_t num_ap = 0; + uint32_t num_ap_bridged = 0; + for (const auto& ap_iface : ap_ifaces_) { + std::string ap_iface_name = ap_iface->getName(); + if (br_ifaces_ap_instances_.count(ap_iface_name) > 0 && + br_ifaces_ap_instances_[ap_iface_name].size() > 1) { + num_ap_bridged++; + } else { + num_ap++; + } + } + iface_counts[IfaceConcurrencyType::AP] = num_ap; + iface_counts[IfaceConcurrencyType::AP_BRIDGED] = num_ap_bridged; + iface_counts[IfaceConcurrencyType::NAN_IFACE] = nan_ifaces_.size(); + iface_counts[IfaceConcurrencyType::P2P] = p2p_ifaces_.size(); + iface_counts[IfaceConcurrencyType::STA] = sta_ifaces_.size(); + return iface_counts; +} + +// This expands the provided concurrency combinations to a more parseable +// form. Returns a vector of available combinations possible with the number +// of each concurrency type in the combination. +// This method is a port of HalDeviceManager.expandConcurrencyCombos() from framework. +std::vector> WifiChip::expandConcurrencyCombinations( + const IWifiChip::ChipConcurrencyCombination& combination) { + int32_t num_expanded_combos = 1; + for (const auto& limit : combination.limits) { + for (int32_t i = 0; i < limit.maxIfaces; i++) { + num_expanded_combos *= limit.types.size(); + } + } + + // Allocate the vector of expanded combos and reset all concurrency type counts to 0 + // in each combo. + std::vector> expanded_combos; + expanded_combos.resize(num_expanded_combos); + for (auto& expanded_combo : expanded_combos) { + for (const auto type : {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, + IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, + IfaceConcurrencyType::STA}) { + expanded_combo[type] = 0; + } + } + int32_t span = num_expanded_combos; + for (const auto& limit : combination.limits) { + for (int32_t i = 0; i < limit.maxIfaces; i++) { + span /= limit.types.size(); + for (int32_t k = 0; k < num_expanded_combos; ++k) { + const auto iface_type = limit.types[(k / span) % limit.types.size()]; + expanded_combos[k][iface_type]++; + } + } + } + return expanded_combos; +} + +bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes( + const std::map& expanded_combo, + IfaceConcurrencyType requested_type) { + const auto current_combo = getCurrentConcurrencyCombination(); + + // Check if we have space for 1 more iface of |type| in this combo + for (const auto type : + {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, + IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) { + size_t num_ifaces_needed = current_combo.at(type); + if (type == requested_type) { + num_ifaces_needed++; + } + size_t num_ifaces_allowed = expanded_combo.at(type); + if (num_ifaces_needed > num_ifaces_allowed) { + return false; + } + } + return true; +} + +// This method does the following: +// a) Enumerate all possible concurrency combos by expanding the current +// ChipConcurrencyCombination. +// b) Check if the requested concurrency type can be added to the current mode +// with the concurrency combination that is already active. +bool WifiChip::canCurrentModeSupportConcurrencyTypeWithCurrentTypes( + IfaceConcurrencyType requested_type) { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return false; + } + const auto combinations = getCurrentModeConcurrencyCombinations(); + for (const auto& combination : combinations) { + const auto expanded_combos = expandConcurrencyCombinations(combination); + for (const auto& expanded_combo : expanded_combos) { + if (canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(expanded_combo, + requested_type)) { + return true; + } + } + } + return false; +} + +// Note: This does not consider concurrency types already active. It only checks if the +// provided expanded concurrency combination can support the requested combo. +bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyCombo( + const std::map& expanded_combo, + const std::map& req_combo) { + // Check if we have space for 1 more |type| in this combo + for (const auto type : + {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED, + IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) { + if (req_combo.count(type) == 0) { + // Concurrency type not in the req_combo. + continue; + } + size_t num_ifaces_needed = req_combo.at(type); + size_t num_ifaces_allowed = expanded_combo.at(type); + if (num_ifaces_needed > num_ifaces_allowed) { + return false; + } + } + return true; +} + +// This method does the following: +// a) Enumerate all possible concurrency combos by expanding the current +// ChipConcurrencyCombination. +// b) Check if the requested concurrency combo can be added to the current mode. +// Note: This does not consider concurrency types already active. It only checks if the +// current mode can support the requested combo. +bool WifiChip::canCurrentModeSupportConcurrencyCombo( + const std::map& req_combo) { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return false; + } + const auto combinations = getCurrentModeConcurrencyCombinations(); + for (const auto& combination : combinations) { + const auto expanded_combos = expandConcurrencyCombinations(combination); + for (const auto& expanded_combo : expanded_combos) { + if (canExpandedConcurrencyComboSupportConcurrencyCombo(expanded_combo, req_combo)) { + return true; + } + } + } + return false; +} + +// This method does the following: +// a) Enumerate all possible concurrency combos by expanding the current +// ChipConcurrencyCombination. +// b) Check if the requested concurrency type can be added to the current mode. +bool WifiChip::canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type) { + // Check if we can support at least 1 of the requested concurrency type. + std::map req_iface_combo; + req_iface_combo[requested_type] = 1; + return canCurrentModeSupportConcurrencyCombo(req_iface_combo); +} + +bool WifiChip::isValidModeId(int32_t mode_id) { + for (const auto& mode : modes_) { + if (mode.id == mode_id) { + return true; + } + } + return false; +} + +bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() { + // Check if we can support at least 1 STA & 1 AP concurrently. + std::map req_iface_combo; + req_iface_combo[IfaceConcurrencyType::STA] = 1; + req_iface_combo[IfaceConcurrencyType::AP] = 1; + return canCurrentModeSupportConcurrencyCombo(req_iface_combo); +} + +bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() { + // Check if we can support at least 2 STA concurrently. + std::map req_iface_combo; + req_iface_combo[IfaceConcurrencyType::STA] = 2; + return canCurrentModeSupportConcurrencyCombo(req_iface_combo); +} + +std::string WifiChip::getFirstActiveWlanIfaceName() { + if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName(); + if (ap_ifaces_.size() > 0) { + // If the first active wlan iface is bridged iface. + // Return first instance name. + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == ap_ifaces_[0]->getName()) { + return it.second[0]; + } + } + return ap_ifaces_[0]->getName(); + } + // This could happen if the chip call is made before any STA/AP + // iface is created. Default to wlan0 for such cases. + LOG(WARNING) << "No active wlan interfaces in use! Using default"; + return getWlanIfaceNameWithType(IfaceType::STA, 0); +} + +// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx| +// not already in use. +// Note: This doesn't check the actual presence of these interfaces. +std::string WifiChip::allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx) { + for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) { + const auto ifname = getWlanIfaceNameWithType(type, idx); + if (findUsingNameFromBridgedApInstances(ifname)) continue; + if (findUsingName(ap_ifaces_, ifname)) continue; + if (findUsingName(sta_ifaces_, ifname)) continue; + return ifname; + } + // This should never happen. We screwed up somewhere if it did. + CHECK(false) << "All wlan interfaces in use already!"; + return {}; +} + +uint32_t WifiChip::startIdxOfApIface() { + if (isDualStaConcurrencyAllowedInCurrentMode()) { + // When the HAL support dual STAs, AP should start with idx 2. + return 2; + } else if (isStaApConcurrencyAllowedInCurrentMode()) { + // When the HAL support STA + AP but it doesn't support dual STAs. + // AP should start with idx 1. + return 1; + } + // No concurrency support. + return 0; +} + +// AP iface names start with idx 1 for modes supporting +// concurrent STA and not dual AP, else start with idx 0. +std::string WifiChip::allocateApIfaceName() { + // Check if we have a dedicated iface for AP. + std::vector ifnames = getPredefinedApIfaceNames(true); + for (auto const& ifname : ifnames) { + if (findUsingName(ap_ifaces_, ifname)) continue; + return ifname; + } + return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface()); +} + +std::vector WifiChip::allocateBridgedApInstanceNames() { + // Check if we have a dedicated iface for AP. + std::vector instances = getPredefinedApIfaceNames(true); + if (instances.size() == 2) { + return instances; + } else { + int num_ifaces_need_to_allocate = 2 - instances.size(); + for (int i = 0; i < num_ifaces_need_to_allocate; i++) { + std::string instance_name = + allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface() + i); + if (!instance_name.empty()) { + instances.push_back(instance_name); + } + } + } + return instances; +} + +// STA iface names start with idx 0. +// Primary STA iface will always be 0. +std::string WifiChip::allocateStaIfaceName() { + return allocateApOrStaIfaceName(IfaceType::STA, 0); +} + +bool WifiChip::writeRingbufferFilesInternal() { + if (!removeOldFilesInternal()) { + LOG(ERROR) << "Error occurred while deleting old tombstone files"; + return false; + } + // write ringbuffers to file + { + std::unique_lock lk(lock_t); + for (auto& item : ringbuffer_map_) { + Ringbuffer& cur_buffer = item.second; + if (cur_buffer.getData().empty()) { + continue; + } + const std::string file_path_raw = kTombstoneFolderPath + item.first + "XXXXXXXXXX"; + const int dump_fd = mkstemp(makeCharVec(file_path_raw).data()); + if (dump_fd == -1) { + PLOG(ERROR) << "create file failed"; + return false; + } + unique_fd file_auto_closer(dump_fd); + for (const auto& cur_block : cur_buffer.getData()) { + if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) { + PLOG(ERROR) << "Ring buffer: " << item.first + << " is corrupted. Invalid block size: " << cur_block.size(); + break; + } + if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) == + -1) { + PLOG(ERROR) << "Error writing to file"; + } + } + cur_buffer.clear(); + } + // unique_lock unlocked here + } + return true; +} + +std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) { + std::string ifname; + + // let the legacy hal override the interface name + legacy_hal::wifi_error err = legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname); + if (err == legacy_hal::WIFI_SUCCESS) return ifname; + + return getWlanIfaceName(idx); +} + +void WifiChip::invalidateAndClearBridgedApAll() { + for (auto const& it : br_ifaces_ap_instances_) { + for (auto const& iface : it.second) { + iface_util_->removeIfaceFromBridge(it.first, iface); + legacy_hal_.lock()->deleteVirtualInterface(iface); + } + iface_util_->deleteBridge(it.first); + } + br_ifaces_ap_instances_.clear(); +} + +void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) { + if (br_name.empty()) return; + // delete managed interfaces + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == br_name) { + for (auto const& iface : it.second) { + iface_util_->removeIfaceFromBridge(br_name, iface); + legacy_hal_.lock()->deleteVirtualInterface(iface); + } + iface_util_->deleteBridge(br_name); + br_ifaces_ap_instances_.erase(br_name); + break; + } + } + return; +} + +bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) { + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == name) { + return true; + } + for (auto const& iface : it.second) { + if (iface == name) { + return true; + } + } + } + return false; +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h new file mode 100644 index 0000000000..59eaa4a58c --- /dev/null +++ b/wifi/aidl/default/wifi_chip.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_CHIP_H_ +#define WIFI_CHIP_H_ + +#include +#include +#include + +#include +#include +#include + +#include "aidl_callback_util.h" +#include "ringbuffer.h" +#include "wifi_ap_iface.h" +#include "wifi_feature_flags.h" +#include "wifi_legacy_hal.h" +#include "wifi_mode_controller.h" +#include "wifi_nan_iface.h" +#include "wifi_p2p_iface.h" +#include "wifi_rtt_controller.h" +#include "wifi_sta_iface.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control a Wifi HAL chip instance. + * Since there is only a single chip instance used today, there is no + * identifying handle information stored here. + */ +class WifiChip : public BnWifiChip { + public: + WifiChip(int32_t chip_id, bool is_primary, + const std::weak_ptr legacy_hal, + const std::weak_ptr mode_controller, + const std::shared_ptr iface_util, + const std::weak_ptr feature_flags, + const std::function& subsystemCallbackHandler); + + // Factory method - use instead of default constructor. + static std::shared_ptr create( + int32_t chip_id, bool is_primary, + const std::weak_ptr legacy_hal, + const std::weak_ptr mode_controller, + const std::shared_ptr iface_util, + const std::weak_ptr feature_flags, + const std::function& subsystemCallbackHandler); + + // AIDL does not provide a built-in mechanism to let the server invalidate + // an AIDL interface object after creation. If any client process holds onto + // a reference to the object in their context, any method calls on that + // reference will continue to be directed to the server. + // + // However Wifi HAL needs to control the lifetime of these objects. So, add + // a public |invalidate| method to |WifiChip| and its child objects. This + // will be used to mark an object invalid when either: + // a) Wifi HAL is stopped, or + // b) Wifi Chip is reconfigured. + // + // All AIDL method implementations should check if the object is still + // marked valid before processing them. + void invalidate(); + bool isValid(); + std::set> getEventCallbacks(); + + // AIDL methods exposed. + ndk::ScopedAStatus getId(int32_t* _aidl_return) override; + ndk::ScopedAStatus registerEventCallback( + const std::shared_ptr& in_callback) override; + ndk::ScopedAStatus getCapabilities(IWifiChip::ChipCapabilityMask* _aidl_return) override; + ndk::ScopedAStatus getAvailableModes(std::vector* _aidl_return) override; + ndk::ScopedAStatus configureChip(int32_t in_modeId) override; + ndk::ScopedAStatus getMode(int32_t* _aidl_return) override; + ndk::ScopedAStatus requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) override; + ndk::ScopedAStatus requestDriverDebugDump(std::vector* _aidl_return) override; + ndk::ScopedAStatus requestFirmwareDebugDump(std::vector* _aidl_return) override; + ndk::ScopedAStatus createApIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus createBridgedApIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getApIfaceNames(std::vector* _aidl_return) override; + ndk::ScopedAStatus getApIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus removeApIface(const std::string& in_ifname) override; + ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIface( + const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) override; + ndk::ScopedAStatus createNanIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getNanIfaceNames(std::vector* _aidl_return) override; + ndk::ScopedAStatus getNanIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus removeNanIface(const std::string& in_ifname) override; + ndk::ScopedAStatus createP2pIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getP2pIfaceNames(std::vector* _aidl_return) override; + ndk::ScopedAStatus getP2pIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus removeP2pIface(const std::string& in_ifname) override; + ndk::ScopedAStatus createStaIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getStaIfaceNames(std::vector* _aidl_return) override; + ndk::ScopedAStatus getStaIface(const std::string& in_ifname, + std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus removeStaIface(const std::string& in_ifname) override; + ndk::ScopedAStatus createRttController( + const std::shared_ptr& in_boundIface, + std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getDebugRingBuffersStatus( + std::vector* _aidl_return) override; + ndk::ScopedAStatus startLoggingToDebugRingBuffer( + const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel, + int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) override; + ndk::ScopedAStatus forceDumpToDebugRingBuffer(const std::string& in_ringName) override; + ndk::ScopedAStatus flushRingBufferToFile() override; + ndk::ScopedAStatus stopLoggingToDebugRingBuffer() override; + ndk::ScopedAStatus getDebugHostWakeReasonStats( + WifiDebugHostWakeReasonStats* _aidl_return) override; + ndk::ScopedAStatus enableDebugErrorAlerts(bool in_enable) override; + ndk::ScopedAStatus selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) override; + ndk::ScopedAStatus resetTxPowerScenario() override; + ndk::ScopedAStatus setLatencyMode(IWifiChip::LatencyMode in_mode) override; + ndk::ScopedAStatus setMultiStaPrimaryConnection(const std::string& in_ifName) override; + ndk::ScopedAStatus setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) override; + ndk::ScopedAStatus setCoexUnsafeChannels( + const std::vector& in_unsafeChannels, + CoexRestriction in_restrictions) override; + ndk::ScopedAStatus setCountryCode(const std::array& in_code) override; + ndk::ScopedAStatus getUsableChannels(WifiBand in_band, WifiIfaceMode in_ifaceModeMask, + UsableChannelFilter in_filterMask, + std::vector* _aidl_return) override; + ndk::ScopedAStatus triggerSubsystemRestart() override; + ndk::ScopedAStatus getSupportedRadioCombinationsMatrix( + WifiRadioCombinationMatrix* _aidl_return) override; + binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; + + private: + void invalidateAndRemoveAllIfaces(); + // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are + // invalidated & removed. + void invalidateAndRemoveDependencies(const std::string& removed_iface_name); + + // Corresponding worker functions for the AIDL methods. + std::pair getIdInternal(); + ndk::ScopedAStatus registerEventCallbackInternal( + const std::shared_ptr& event_callback); + std::pair getCapabilitiesInternal(); + std::pair, ndk::ScopedAStatus> getAvailableModesInternal(); + ndk::ScopedAStatus configureChipInternal(std::unique_lock* lock, + int32_t mode_id); + std::pair getModeInternal(); + std::pair requestChipDebugInfoInternal(); + std::pair, ndk::ScopedAStatus> requestDriverDebugDumpInternal(); + std::pair, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal(); + std::shared_ptr newWifiApIface(std::string& ifname); + ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf); + std::pair, ndk::ScopedAStatus> createApIfaceInternal(); + std::pair, ndk::ScopedAStatus> createBridgedApIfaceInternal(); + std::pair, ndk::ScopedAStatus> getApIfaceNamesInternal(); + std::pair, ndk::ScopedAStatus> getApIfaceInternal( + const std::string& ifname); + ndk::ScopedAStatus removeApIfaceInternal(const std::string& ifname); + ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIfaceInternal( + const std::string& brIfaceName, const std::string& ifInstanceName); + std::pair, ndk::ScopedAStatus> createNanIfaceInternal(); + std::pair, ndk::ScopedAStatus> getNanIfaceNamesInternal(); + std::pair, ndk::ScopedAStatus> getNanIfaceInternal( + const std::string& ifname); + ndk::ScopedAStatus removeNanIfaceInternal(const std::string& ifname); + std::pair, ndk::ScopedAStatus> createP2pIfaceInternal(); + std::pair, ndk::ScopedAStatus> getP2pIfaceNamesInternal(); + std::pair, ndk::ScopedAStatus> getP2pIfaceInternal( + const std::string& ifname); + ndk::ScopedAStatus removeP2pIfaceInternal(const std::string& ifname); + std::pair, ndk::ScopedAStatus> createStaIfaceInternal(); + std::pair, ndk::ScopedAStatus> getStaIfaceNamesInternal(); + std::pair, ndk::ScopedAStatus> getStaIfaceInternal( + const std::string& ifname); + ndk::ScopedAStatus removeStaIfaceInternal(const std::string& ifname); + std::pair, ndk::ScopedAStatus> createRttControllerInternal( + const std::shared_ptr& bound_iface); + std::pair, ndk::ScopedAStatus> + getDebugRingBuffersStatusInternal(); + ndk::ScopedAStatus startLoggingToDebugRingBufferInternal( + const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level, + uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes); + ndk::ScopedAStatus forceDumpToDebugRingBufferInternal(const std::string& ring_name); + ndk::ScopedAStatus flushRingBufferToFileInternal(); + ndk::ScopedAStatus stopLoggingToDebugRingBufferInternal(); + std::pair + getDebugHostWakeReasonStatsInternal(); + ndk::ScopedAStatus enableDebugErrorAlertsInternal(bool enable); + ndk::ScopedAStatus selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario); + ndk::ScopedAStatus resetTxPowerScenarioInternal(); + ndk::ScopedAStatus setLatencyModeInternal(IWifiChip::LatencyMode mode); + ndk::ScopedAStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname); + ndk::ScopedAStatus setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case); + ndk::ScopedAStatus setCoexUnsafeChannelsInternal( + std::vector unsafe_channels, + CoexRestriction restrictions); + ndk::ScopedAStatus setCountryCodeInternal(const std::array& in_code); + std::pair, ndk::ScopedAStatus> getUsableChannelsInternal( + WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask); + ndk::ScopedAStatus handleChipConfiguration(std::unique_lock* lock, + int32_t mode_id); + ndk::ScopedAStatus registerDebugRingBufferCallback(); + ndk::ScopedAStatus registerRadioModeChangeCallback(); + + std::vector getCurrentModeConcurrencyCombinations(); + std::map getCurrentConcurrencyCombination(); + std::vector> expandConcurrencyCombinations( + const ChipConcurrencyCombination& combination); + bool canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes( + const std::map& expanded_combo, + IfaceConcurrencyType requested_type); + bool canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType requested_type); + bool canExpandedConcurrencyComboSupportConcurrencyCombo( + const std::map& expanded_combo, + const std::map& req_combo); + bool canCurrentModeSupportConcurrencyCombo( + const std::map& req_combo); + bool canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type); + + bool isValidModeId(int32_t mode_id); + bool isStaApConcurrencyAllowedInCurrentMode(); + bool isDualStaConcurrencyAllowedInCurrentMode(); + uint32_t startIdxOfApIface(); + std::string getFirstActiveWlanIfaceName(); + std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx); + std::string allocateApIfaceName(); + std::vector allocateBridgedApInstanceNames(); + std::string allocateStaIfaceName(); + bool writeRingbufferFilesInternal(); + std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx); + void invalidateAndClearBridgedApAll(); + void invalidateAndClearBridgedAp(const std::string& br_name); + bool findUsingNameFromBridgedApInstances(const std::string& name); + ndk::ScopedAStatus triggerSubsystemRestartInternal(); + std::pair + getSupportedRadioCombinationsMatrixInternal(); + void setWeakPtr(std::weak_ptr ptr); + + int32_t chip_id_; + std::weak_ptr legacy_hal_; + std::weak_ptr mode_controller_; + std::shared_ptr iface_util_; + std::vector> ap_ifaces_; + std::vector> nan_ifaces_; + std::vector> p2p_ifaces_; + std::vector> sta_ifaces_; + std::vector> rtt_controllers_; + std::map ringbuffer_map_; + bool is_valid_; + // Members pertaining to chip configuration. + int32_t current_mode_id_; + std::mutex lock_t; + std::vector modes_; + // The legacy ring buffer callback API has only a global callback + // registration mechanism. Use this to check if we have already + // registered a callback. + bool debug_ring_buffer_cb_registered_; + aidl_callback_util::AidlCallbackHandler event_cb_handler_; + std::weak_ptr weak_ptr_this_; + + const std::function subsystemCallbackHandler_; + std::map> br_ifaces_ap_instances_; + DISALLOW_COPY_AND_ASSIGN(WifiChip); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_CHIP_H_ diff --git a/wifi/aidl/default/wifi_feature_flags.cpp b/wifi/aidl/default/wifi_feature_flags.cpp new file mode 100644 index 0000000000..3c9f042607 --- /dev/null +++ b/wifi/aidl/default/wifi_feature_flags.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2022 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 + +#include +#include + +#include "wifi_feature_flags.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace feature_flags { + +/* The chip may either have a single mode supporting any number of combinations, + * or a fixed dual-mode (so it involves firmware loading to switch between + * modes) setting. If there is a need to support more modes, it needs to be + * implemented manually in WiFi HAL (see changeFirmwareMode in + * WifiChip::handleChipConfiguration). + * + * Supported combinations are defined in device's makefile, for example: + * WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}}, + * WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}} + * What this means: + * Interface concurrency combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface + * operations. + * Interface concurrency combination 2: 1 STA and 2 AP concurrent iface operations. + * + * For backward compatibility, the following makefile flags can be used to + * generate combinations list: + * - WIFI_HIDL_FEATURE_DUAL_INTERFACE + * - WIFI_HIDL_FEATURE_DISABLE_AP + * - WIFI_HIDL_FEATURE_AWARE + * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided. + * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with + * two concurrency combinations: + * Interface Concurrency Combination 1: Will support 1 STA and 1 P2P or NAN (optional) + * concurrent iface operations. + * Interface Concurrency Combination 2: Will support 1 STA and 1 AP concurrent + * iface operations. + * + * The only dual-mode configuration supported is for alternating STA and AP + * mode, that may involve firmware reloading. In such case, there are 2 separate + * modes of operation with 1 concurrency combination each: + * Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional) + * concurrent iface operations. + * Mode 2 (AP mode): Will support 1 AP iface operation. + * + * If Aware is enabled, the concurrency combination will be modified to support either + * P2P or NAN in place of just P2P. + */ +// clang-format off +#ifdef WIFI_HAL_INTERFACE_COMBINATIONS +constexpr int kMainModeId = chip_mode_ids::kV3; +#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE) +// former V2 (fixed dual interface) setup expressed as V3 +constexpr int kMainModeId = chip_mode_ids::kV3; +# ifdef WIFI_HIDL_FEATURE_DISABLE_AP +# ifdef WIFI_HIDL_FEATURE_AWARE +// 1 STA + 1 of (P2P or NAN) +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}} +# else +// 1 STA + 1 P2P +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}} +# endif +# else +# ifdef WIFI_HIDL_FEATURE_AWARE +// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN)) +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\ + {{{STA}, 1}, {{P2P, NAN}, 1}} +# else +// (1 STA + 1 AP) or (1 STA + 1 P2P) +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\ + {{{STA}, 1}, {{P2P}, 1}} +# endif +# endif +#else +// V1 (fixed single interface, dual-mode chip) +constexpr int kMainModeId = chip_mode_ids::kV1Sta; +# ifdef WIFI_HIDL_FEATURE_AWARE +// 1 STA + 1 of (P2P or NAN) +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}} +# else +// 1 STA + 1 P2P +# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}} +# endif + +# ifndef WIFI_HIDL_FEATURE_DISABLE_AP +# define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}} +# endif +#endif +// clang-format on + +// Convert from the legacy format (used by the WIFI_HAL_INTERFACE_COMBINATIONS +// config variable) to a list of ChipConcurrencyCombination objects. +std::vector legacyToChipConcurrencyComboList( + std::vector> legacyLimits) { + std::vector combos; + for (auto& legacyLimit : legacyLimits) { + IWifiChip::ChipConcurrencyCombination combo = {legacyLimit}; + combos.push_back(combo); + } + return combos; +} + +#define STA IfaceConcurrencyType::STA +#define AP IfaceConcurrencyType::AP +#define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED +#define P2P IfaceConcurrencyType::P2P +#define NAN IfaceConcurrencyType::NAN_IFACE +static const std::vector kChipModesPrimary{ + {kMainModeId, legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS})}, +#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP + {chip_mode_ids::kV1Ap, + legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_AP})}, +#endif +}; + +static const std::vector kChipModesSecondary{ +#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP + {chip_mode_ids::kV3, + legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})}, +#endif +}; + +constexpr char kDebugPresetInterfaceCombinationIdxProperty[] = + "persist.vendor.debug.wifi.hal.preset_interface_combination_idx"; +// List of pre-defined concurrency combinations that can be enabled at runtime via +// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the +// corresponding index value. +static const std::vector>> kDebugChipModes{ + // Legacy combination - No STA/AP concurrencies. + // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN)) + {"No STA/AP Concurrency", + {{kMainModeId, + legacyToChipConcurrencyComboList({{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}}, + + // STA + AP concurrency + // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN)) + {"STA + AP Concurrency", + {{kMainModeId, legacyToChipConcurrencyComboList( + {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}}, + + // STA + STA concurrency + // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN)) + {"Dual STA Concurrency", + {{kMainModeId, legacyToChipConcurrencyComboList( + {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}}, + + // AP + AP + STA concurrency + // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN)) + {"Dual AP Concurrency", + {{kMainModeId, legacyToChipConcurrencyComboList( + {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}}, + + // STA + STA concurrency and AP + AP + STA concurrency + // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN)) + {"Dual STA & Dual AP Concurrency", + {{kMainModeId, legacyToChipConcurrencyComboList( + {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}}, + + // STA + STA concurrency + // 5 - (1 STA + 1 AP (bridged or single) | P2P | NAN), or (2 STA)) + {"Dual STA or STA plus single other interface", + {{kMainModeId, legacyToChipConcurrencyComboList( + {{{{STA}, 1}, {{P2P, NAN, AP, AP_BRIDGED}, 1}}, {{{STA}, 2}}})}}}}; + +#undef STA +#undef AP +#undef AP_BRIDGED +#undef P2P +#undef NAN + +#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION +#pragma message \ + "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \ + "'config_wifi_ap_randomization_supported' in " \ + "frameworks/base/core/res/res/values/config.xml in the device overlay " \ + "instead" +#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION + +WifiFeatureFlags::WifiFeatureFlags() {} + +std::vector WifiFeatureFlags::getChipModesForPrimary() { + std::array buffer; + auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty, buffer.data(), nullptr); + // Debug property not set, use the device preset concurrency combination. + if (res <= 0) return kChipModesPrimary; + + // Debug property set, use one of the debug preset concurrency combination. + unsigned long idx = std::stoul(buffer.data()); + if (idx >= kDebugChipModes.size()) { + LOG(ERROR) << "Invalid index set in property: " + << kDebugPresetInterfaceCombinationIdxProperty; + return kChipModesPrimary; + } + std::string name; + std::vector chip_modes; + std::tie(name, chip_modes) = kDebugChipModes[idx]; + LOG(INFO) << "Using debug chip mode: <" << name + << "> set via property: " << kDebugPresetInterfaceCombinationIdxProperty; + return chip_modes; +} + +std::vector WifiFeatureFlags::getChipModes(bool is_primary) { + return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary; +} + +} // namespace feature_flags +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_feature_flags.h b/wifi/aidl/default/wifi_feature_flags.h new file mode 100644 index 0000000000..af1b6a674d --- /dev/null +++ b/wifi/aidl/default/wifi_feature_flags.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_FEATURE_FLAGS_H_ +#define WIFI_FEATURE_FLAGS_H_ + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace feature_flags { + +namespace chip_mode_ids { +// These mode ID's should be unique (even across combo versions). Refer to +// handleChipConfiguration() for its usage. +constexpr uint32_t kInvalid = UINT32_MAX; +// Mode ID's for V1 +constexpr uint32_t kV1Sta = 0; +constexpr uint32_t kV1Ap = 1; +// Mode ID for V3 +constexpr uint32_t kV3 = 3; +} // namespace chip_mode_ids + +class WifiFeatureFlags { + public: + WifiFeatureFlags(); + virtual ~WifiFeatureFlags() = default; + + virtual std::vector getChipModes(bool is_primary); + + private: + std::vector getChipModesForPrimary(); +}; + +} // namespace feature_flags +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_FEATURE_FLAGS_H_ diff --git a/wifi/aidl/default/wifi_iface_util.cpp b/wifi/aidl/default/wifi_iface_util.cpp new file mode 100644 index 0000000000..f788217dcf --- /dev/null +++ b/wifi/aidl/default/wifi_iface_util.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2022 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 +#include +#include +#include + +#include +#include +#include +#include + +#include "wifi_iface_util.h" + +namespace { +// Constants to set the local bit & clear the multicast bit. +constexpr uint8_t kMacAddressMulticastMask = 0x01; +constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02; + +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace iface_util { + +WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::weak_ptr legacy_hal) + : iface_tool_(iface_tool), + legacy_hal_(legacy_hal), + random_mac_address_(nullptr), + event_handlers_map_() {} + +std::array WifiIfaceUtil::getFactoryMacAddress(const std::string& iface_name) { + return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str()); +} + +bool WifiIfaceUtil::setMacAddress(const std::string& iface_name, + const std::array& mac) { +#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(iface_name); + + if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) && + !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) { + LOG(ERROR) << "SetUpState(false) failed."; + return false; + } +#endif + bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac); +#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE + if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) && + !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) { + LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready."; + // Wait for driver ready and try to set iface UP again + if (legacy_hal_.lock()->waitForDriverReady() != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "SetUpState(true) wait for driver ready failed."; + return false; + } + if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) { + LOG(ERROR) << "SetUpState(true) failed after retry."; + return false; + } + } +#endif + IfaceEventHandlers event_handlers = {}; + const auto it = event_handlers_map_.find(iface_name); + if (it != event_handlers_map_.end()) { + event_handlers = it->second; + } + if (event_handlers.on_state_toggle_off_on != nullptr) { + event_handlers.on_state_toggle_off_on(iface_name); + } + if (!success) { + LOG(ERROR) << "SetMacAddress failed on " << iface_name; + } else { + LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name; + } + return success; +} + +std::array WifiIfaceUtil::getOrCreateRandomMacAddress() { + if (random_mac_address_) { + return *random_mac_address_.get(); + } + random_mac_address_ = std::make_unique>(createRandomMacAddress()); + return *random_mac_address_.get(); +} + +void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name, + IfaceEventHandlers handlers) { + event_handlers_map_[iface_name] = handlers; +} + +void WifiIfaceUtil::unregisterIfaceEventHandlers(const std::string& iface_name) { + event_handlers_map_.erase(iface_name); +} + +std::array WifiIfaceUtil::createRandomMacAddress() { + std::array address = {}; + std::random_device rd; + std::default_random_engine engine(rd()); + std::uniform_int_distribution dist(std::numeric_limits::min(), + std::numeric_limits::max()); + for (size_t i = 0; i < address.size(); i++) { + address[i] = dist(engine); + } + // Set the local bit and clear the multicast bit. + address[0] |= kMacAddressLocallyAssignedMask; + address[0] &= ~kMacAddressMulticastMask; + return address; +} + +bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) { + if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) { + LOG(ERROR) << "SetUpState to " << request_up << " failed"; + return false; + } + return true; +} + +unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) { + return if_nametoindex(iface_name.c_str()); +} + +bool WifiIfaceUtil::createBridge(const std::string& br_name) { + if (!iface_tool_.lock()->createBridge(br_name)) { + return false; + } + + if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) { + LOG(ERROR) << "bridge SetUpState(true) failed."; + } + return true; +} + +bool WifiIfaceUtil::deleteBridge(const std::string& br_name) { + if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) { + LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str(); + } + + return iface_tool_.lock()->deleteBridge(br_name); +} + +bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name, const std::string& if_name) { + return iface_tool_.lock()->addIfaceToBridge(br_name, if_name); +} + +bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) { + return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name); +} + +} // namespace iface_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_iface_util.h b/wifi/aidl/default/wifi_iface_util.h new file mode 100644 index 0000000000..a3236a5622 --- /dev/null +++ b/wifi/aidl/default/wifi_iface_util.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_IFACE_UTIL_H_ +#define WIFI_IFACE_UTIL_H_ + +#include +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace iface_util { + +// Iface event handlers. +struct IfaceEventHandlers { + // Callback to be invoked when the iface is set down & up for MAC address + // change. + std::function on_state_toggle_off_on; +}; + +/** + * Util class for common iface operations. + */ +class WifiIfaceUtil { + public: + WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const std::weak_ptr legacy_hal); + virtual ~WifiIfaceUtil() = default; + + virtual std::array getFactoryMacAddress(const std::string& iface_name); + virtual bool setMacAddress(const std::string& iface_name, const std::array& mac); + // Get or create a random MAC address. The MAC address returned from + // this method will remain the same throughout the lifetime of the HAL + // daemon. (So, changes on every reboot) + virtual std::array getOrCreateRandomMacAddress(); + + // Register for any iface event callbacks for the provided interface. + virtual void registerIfaceEventHandlers(const std::string& iface_name, + IfaceEventHandlers handlers); + virtual void unregisterIfaceEventHandlers(const std::string& iface_name); + virtual bool setUpState(const std::string& iface_name, bool request_up); + virtual unsigned ifNameToIndex(const std::string& iface_name); + + virtual bool createBridge(const std::string& br_name); + + virtual bool deleteBridge(const std::string& br_name); + + virtual bool addIfaceToBridge(const std::string& br_name, const std::string& if_name); + + virtual bool removeIfaceFromBridge(const std::string& br_name, const std::string& if_name); + // Get a random MAC address. + virtual std::array createRandomMacAddress(); + + private: + std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_; + std::weak_ptr legacy_hal_; + std::unique_ptr> random_mac_address_; + std::map event_handlers_map_; +}; + +} // namespace iface_util +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_IFACE_UTIL_H_ diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp new file mode 100644 index 0000000000..43e73cae9f --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal.cpp @@ -0,0 +1,1654 @@ +/* + * Copyright (C) 2022 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 "wifi_legacy_hal.h" + +#include +#include +#include + +#include +#include + +#include "aidl_sync_util.h" +#include "wifi_legacy_hal_stubs.h" + +namespace { +// Constants ported over from the legacy HAL calling code +// (com_android_server_wifi_WifiNative.cpp). This will all be thrown +// away when this shim layer is replaced by the real vendor +// implementation. +static constexpr uint32_t kMaxVersionStringLength = 256; +static constexpr uint32_t kMaxCachedGscanResults = 64; +static constexpr uint32_t kMaxGscanFrequenciesForBand = 64; +static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128; +static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32; +static constexpr uint32_t kMaxRingBuffers = 10; +static constexpr uint32_t kMaxWifiUsableChannels = 256; +static constexpr uint32_t kMaxSupportedRadioCombinationsMatrixLength = 256; +// Need a long timeout (1000ms) for chips that unload their driver. +static constexpr uint32_t kMaxStopCompleteWaitMs = 1000; +static constexpr char kDriverPropName[] = "wlan.driver.status"; + +// Helper function to create a non-const char* for legacy Hal API's. +std::vector makeCharVec(const std::string& str) { + std::vector vec(str.size() + 1); + vec.assign(str.begin(), str.end()); + vec.push_back('\0'); + return vec; +} +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { + +// 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 on_stop_complete_internal_callback; +void onAsyncStopComplete(wifi_handle handle) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_stop_complete_internal_callback) { + on_stop_complete_internal_callback(handle); + // Invalidate this callback since we don't want this firing again. + on_stop_complete_internal_callback = nullptr; + } +} + +// Callback to be invoked for driver dump. +std::function on_driver_memory_dump_internal_callback; +void onSyncDriverMemoryDump(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 on_firmware_memory_dump_internal_callback; +void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) { + if (on_firmware_memory_dump_internal_callback) { + on_firmware_memory_dump_internal_callback(buffer, buffer_size); + } +} + +// Callback to be invoked for Gscan events. +std::function on_gscan_event_internal_callback; +void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_gscan_event_internal_callback) { + on_gscan_event_internal_callback(id, event); + } +} + +// Callback to be invoked for Gscan full results. +std::function + on_gscan_full_result_internal_callback; +void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result, + uint32_t buckets_scanned) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_gscan_full_result_internal_callback) { + on_gscan_full_result_internal_callback(id, result, buckets_scanned); + } +} + +// Callback to be invoked for link layer stats results. +std::function + on_link_layer_stats_result_internal_callback; +void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios, + wifi_radio_stat* radio_stat) { + if (on_link_layer_stats_result_internal_callback) { + on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios, radio_stat); + } +} + +// Callback to be invoked for rssi threshold breach. +std::function + on_rssi_threshold_breached_internal_callback; +void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_rssi_threshold_breached_internal_callback) { + on_rssi_threshold_breached_internal_callback(id, bssid, rssi); + } +} + +// Callback to be invoked for ring buffer data indication. +std::function + on_ring_buffer_data_internal_callback; +void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size, + wifi_ring_buffer_status* status) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_ring_buffer_data_internal_callback) { + on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size, status); + } +} + +// Callback to be invoked for error alert indication. +std::function on_error_alert_internal_callback; +void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size, int err_code) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_error_alert_internal_callback) { + on_error_alert_internal_callback(id, buffer, buffer_size, err_code); + } +} + +// Callback to be invoked for radio mode change indication. +std::function + on_radio_mode_change_internal_callback; +void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs, wifi_mac_info* mac_infos) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_radio_mode_change_internal_callback) { + on_radio_mode_change_internal_callback(id, num_macs, mac_infos); + } +} + +// Callback to be invoked to report subsystem restart +std::function on_subsystem_restart_internal_callback; +void onAsyncSubsystemRestart(const char* error) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_subsystem_restart_internal_callback) { + on_subsystem_restart_internal_callback(error); + } +} + +// Callback to be invoked for rtt results results. +std::function + on_rtt_results_internal_callback; +void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_rtt_results_internal_callback) { + on_rtt_results_internal_callback(id, num_results, rtt_results); + on_rtt_results_internal_callback = nullptr; + } +} + +// Callbacks for the various NAN operations. +// NOTE: These have very little conversions to perform before invoking the user +// callbacks. +// So, handle all of them here directly to avoid adding an unnecessary layer. +std::function on_nan_notify_response_user_callback; +void onAsyncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_notify_response_user_callback && msg) { + on_nan_notify_response_user_callback(id, *msg); + } +} + +std::function on_nan_event_publish_replied_user_callback; +void onAsyncNanEventPublishReplied(NanPublishRepliedInd* /* event */) { + LOG(ERROR) << "onAsyncNanEventPublishReplied triggered"; +} + +std::function on_nan_event_publish_terminated_user_callback; +void onAsyncNanEventPublishTerminated(NanPublishTerminatedInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_publish_terminated_user_callback && event) { + on_nan_event_publish_terminated_user_callback(*event); + } +} + +std::function on_nan_event_match_user_callback; +void onAsyncNanEventMatch(NanMatchInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_match_user_callback && event) { + on_nan_event_match_user_callback(*event); + } +} + +std::function on_nan_event_match_expired_user_callback; +void onAsyncNanEventMatchExpired(NanMatchExpiredInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_match_expired_user_callback && event) { + on_nan_event_match_expired_user_callback(*event); + } +} + +std::function + on_nan_event_subscribe_terminated_user_callback; +void onAsyncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_subscribe_terminated_user_callback && event) { + on_nan_event_subscribe_terminated_user_callback(*event); + } +} + +std::function on_nan_event_followup_user_callback; +void onAsyncNanEventFollowup(NanFollowupInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_followup_user_callback && event) { + on_nan_event_followup_user_callback(*event); + } +} + +std::function on_nan_event_disc_eng_event_user_callback; +void onAsyncNanEventDiscEngEvent(NanDiscEngEventInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_disc_eng_event_user_callback && event) { + on_nan_event_disc_eng_event_user_callback(*event); + } +} + +std::function on_nan_event_disabled_user_callback; +void onAsyncNanEventDisabled(NanDisabledInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_disabled_user_callback && event) { + on_nan_event_disabled_user_callback(*event); + } +} + +std::function on_nan_event_tca_user_callback; +void onAsyncNanEventTca(NanTCAInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_tca_user_callback && event) { + on_nan_event_tca_user_callback(*event); + } +} + +std::function on_nan_event_beacon_sdf_payload_user_callback; +void onAsyncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_beacon_sdf_payload_user_callback && event) { + on_nan_event_beacon_sdf_payload_user_callback(*event); + } +} + +std::function on_nan_event_data_path_request_user_callback; +void onAsyncNanEventDataPathRequest(NanDataPathRequestInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_data_path_request_user_callback && event) { + on_nan_event_data_path_request_user_callback(*event); + } +} +std::function on_nan_event_data_path_confirm_user_callback; +void onAsyncNanEventDataPathConfirm(NanDataPathConfirmInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_data_path_confirm_user_callback && event) { + on_nan_event_data_path_confirm_user_callback(*event); + } +} + +std::function on_nan_event_data_path_end_user_callback; +void onAsyncNanEventDataPathEnd(NanDataPathEndInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_data_path_end_user_callback && event) { + on_nan_event_data_path_end_user_callback(*event); + } +} + +std::function on_nan_event_transmit_follow_up_user_callback; +void onAsyncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_transmit_follow_up_user_callback && event) { + on_nan_event_transmit_follow_up_user_callback(*event); + } +} + +std::function on_nan_event_range_request_user_callback; +void onAsyncNanEventRangeRequest(NanRangeRequestInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_range_request_user_callback && event) { + on_nan_event_range_request_user_callback(*event); + } +} + +std::function on_nan_event_range_report_user_callback; +void onAsyncNanEventRangeReport(NanRangeReportInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_range_report_user_callback && event) { + on_nan_event_range_report_user_callback(*event); + } +} + +std::function on_nan_event_schedule_update_user_callback; +void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_nan_event_schedule_update_user_callback && event) { + on_nan_event_schedule_update_user_callback(*event); + } +} + +// Callbacks for the various TWT operations. +std::function on_twt_event_setup_response_callback; +void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_twt_event_setup_response_callback && event) { + on_twt_event_setup_response_callback(*event); + } +} + +std::function on_twt_event_teardown_completion_callback; +void onAsyncTwtEventTeardownCompletion(TwtTeardownCompletion* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_twt_event_teardown_completion_callback && event) { + on_twt_event_teardown_completion_callback(*event); + } +} + +std::function on_twt_event_info_frame_received_callback; +void onAsyncTwtEventInfoFrameReceived(TwtInfoFrameReceived* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_twt_event_info_frame_received_callback && event) { + on_twt_event_info_frame_received_callback(*event); + } +} + +std::function on_twt_event_device_notify_callback; +void onAsyncTwtEventDeviceNotify(TwtDeviceNotify* event) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_twt_event_device_notify_callback && event) { + on_twt_event_device_notify_callback(*event); + } +} + +// Callback to report current CHRE NAN state +std::function on_chre_nan_rtt_internal_callback; +void onAsyncChreNanRttState(chre_nan_rtt_state state) { + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (on_chre_nan_rtt_internal_callback) { + on_chre_nan_rtt_internal_callback(state); + } +} + +// Callback to report cached scan results +std::function on_cached_scan_results_internal_callback; +void onSyncCachedScanResults(wifi_cached_scan_report* cache_report) { + if (on_cached_scan_results_internal_callback) { + on_cached_scan_results_internal_callback(cache_report); + } +} + +// End of the free-standing "C" style callbacks. + +WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const wifi_hal_fn& fn, bool is_primary) + : global_func_table_(fn), + global_handle_(nullptr), + awaiting_event_loop_termination_(false), + is_started_(false), + iface_tool_(iface_tool), + is_primary_(is_primary) {} + +wifi_error WifiLegacyHal::initialize() { + LOG(DEBUG) << "Initialize legacy HAL"; + // this now does nothing, since HAL function table is provided + // to the constructor + return WIFI_SUCCESS; +} + +wifi_error WifiLegacyHal::start() { + // Ensure that we're starting in a good state. + CHECK(global_func_table_.wifi_initialize && !global_handle_ && iface_name_to_handle_.empty() && + !awaiting_event_loop_termination_); + if (is_started_) { + LOG(DEBUG) << "Legacy HAL already started"; + return WIFI_SUCCESS; + } + LOG(DEBUG) << "Waiting for the driver ready"; + wifi_error status = global_func_table_.wifi_wait_for_driver_ready(); + if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) { + LOG(ERROR) << "Failed or timed out awaiting driver ready"; + return status; + } + + if (is_primary_) { + property_set(kDriverPropName, "ok"); + + if (!iface_tool_.lock()->SetWifiUpState(true)) { + LOG(ERROR) << "Failed to set WiFi interface up"; + return WIFI_ERROR_UNKNOWN; + } + } + + LOG(DEBUG) << "Starting legacy HAL"; + status = global_func_table_.wifi_initialize(&global_handle_); + if (status != WIFI_SUCCESS || !global_handle_) { + LOG(ERROR) << "Failed to retrieve global handle"; + return status; + } + std::thread(&WifiLegacyHal::runEventLoop, this).detach(); + status = retrieveIfaceHandles(); + if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) { + LOG(ERROR) << "Failed to retrieve wlan interface handle"; + return status; + } + LOG(DEBUG) << "Legacy HAL start complete"; + is_started_ = true; + return WIFI_SUCCESS; +} + +wifi_error WifiLegacyHal::stop( + /* NONNULL */ std::unique_lock* lock, + const std::function& on_stop_complete_user_callback) { + if (!is_started_) { + LOG(DEBUG) << "Legacy HAL already stopped"; + on_stop_complete_user_callback(); + return WIFI_SUCCESS; + } + LOG(DEBUG) << "Stopping legacy HAL"; + on_stop_complete_internal_callback = [on_stop_complete_user_callback, + this](wifi_handle handle) { + CHECK_EQ(global_handle_, handle) << "Handle mismatch"; + LOG(INFO) << "Legacy HAL stop complete callback received"; + // Invalidate all the internal pointers now that the HAL is + // stopped. + invalidate(); + if (is_primary_) iface_tool_.lock()->SetWifiUpState(false); + on_stop_complete_user_callback(); + is_started_ = false; + }; + awaiting_event_loop_termination_ = true; + global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete); + const auto status = + stop_wait_cv_.wait_for(*lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs), + [this] { return !awaiting_event_loop_termination_; }); + if (!status) { + LOG(ERROR) << "Legacy HAL stop failed or timed out"; + return WIFI_ERROR_UNKNOWN; + } + LOG(DEBUG) << "Legacy HAL stop complete"; + return WIFI_SUCCESS; +} + +bool WifiLegacyHal::isStarted() { + return is_started_; +} + +wifi_error WifiLegacyHal::waitForDriverReady() { + return global_func_table_.wifi_wait_for_driver_ready(); +} + +std::pair WifiLegacyHal::getDriverVersion(const std::string& iface_name) { + std::array buffer; + buffer.fill(0); + wifi_error status = global_func_table_.wifi_get_driver_version(getIfaceHandle(iface_name), + buffer.data(), buffer.size()); + return {status, buffer.data()}; +} + +std::pair WifiLegacyHal::getFirmwareVersion( + const std::string& iface_name) { + std::array buffer; + buffer.fill(0); + wifi_error status = global_func_table_.wifi_get_firmware_version(getIfaceHandle(iface_name), + buffer.data(), buffer.size()); + return {status, buffer.data()}; +} + +std::pair> WifiLegacyHal::requestDriverMemoryDump( + const std::string& iface_name) { + std::vector driver_dump; + on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer, int buffer_size) { + driver_dump.insert(driver_dump.end(), reinterpret_cast(buffer), + reinterpret_cast(buffer) + buffer_size); + }; + wifi_error status = global_func_table_.wifi_get_driver_memory_dump(getIfaceHandle(iface_name), + {onSyncDriverMemoryDump}); + on_driver_memory_dump_internal_callback = nullptr; + return {status, std::move(driver_dump)}; +} + +std::pair> WifiLegacyHal::requestFirmwareMemoryDump( + const std::string& iface_name) { + std::vector firmware_dump; + on_firmware_memory_dump_internal_callback = [&firmware_dump](char* buffer, int buffer_size) { + firmware_dump.insert(firmware_dump.end(), reinterpret_cast(buffer), + reinterpret_cast(buffer) + buffer_size); + }; + wifi_error status = global_func_table_.wifi_get_firmware_memory_dump( + getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump}); + on_firmware_memory_dump_internal_callback = nullptr; + return {status, std::move(firmware_dump)}; +} + +std::pair WifiLegacyHal::getSupportedFeatureSet( + const std::string& iface_name) { + feature_set set = 0, chip_set = 0; + wifi_error status = WIFI_SUCCESS; + + static_assert(sizeof(set) == sizeof(uint64_t), + "Some feature_flags can not be represented in output"); + wifi_interface_handle iface_handle = getIfaceHandle(iface_name); + + global_func_table_.wifi_get_chip_feature_set( + global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */ + + if (iface_handle) { + status = global_func_table_.wifi_get_supported_feature_set(iface_handle, &set); + } + return {status, static_cast(set | chip_set)}; +} + +std::pair WifiLegacyHal::getPacketFilterCapabilities( + const std::string& iface_name) { + PacketFilterCapabilities caps; + wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities( + getIfaceHandle(iface_name), &caps.version, &caps.max_len); + return {status, caps}; +} + +wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name, + const std::vector& program) { + return global_func_table_.wifi_set_packet_filter(getIfaceHandle(iface_name), program.data(), + program.size()); +} + +std::pair> WifiLegacyHal::readApfPacketFilterData( + const std::string& iface_name) { + PacketFilterCapabilities caps; + wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities( + getIfaceHandle(iface_name), &caps.version, &caps.max_len); + if (status != WIFI_SUCCESS) { + return {status, {}}; + } + + // Size the buffer to read the entire program & work memory. + std::vector buffer(caps.max_len); + + status = global_func_table_.wifi_read_packet_filter( + getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(), buffer.size()); + return {status, std::move(buffer)}; +} + +std::pair WifiLegacyHal::getGscanCapabilities( + const std::string& iface_name) { + wifi_gscan_capabilities caps; + wifi_error status = + global_func_table_.wifi_get_gscan_capabilities(getIfaceHandle(iface_name), &caps); + return {status, caps}; +} + +wifi_error WifiLegacyHal::startGscan( + const std::string& iface_name, wifi_request_id id, const wifi_scan_cmd_params& params, + const std::function& on_failure_user_callback, + const on_gscan_results_callback& on_results_user_callback, + const on_gscan_full_result_callback& on_full_result_user_callback) { + // If there is already an ongoing background scan, reject new scan requests. + if (on_gscan_event_internal_callback || on_gscan_full_result_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + + // This callback will be used to either trigger |on_results_user_callback| + // or |on_failure_user_callback|. + on_gscan_event_internal_callback = [iface_name, on_failure_user_callback, + on_results_user_callback, + this](wifi_request_id id, wifi_scan_event event) { + switch (event) { + case WIFI_SCAN_RESULTS_AVAILABLE: + case WIFI_SCAN_THRESHOLD_NUM_SCANS: + case WIFI_SCAN_THRESHOLD_PERCENT: { + wifi_error status; + std::vector cached_scan_results; + std::tie(status, cached_scan_results) = getGscanCachedResults(iface_name); + if (status == WIFI_SUCCESS) { + on_results_user_callback(id, cached_scan_results); + return; + } + FALLTHROUGH_INTENDED; + } + // Fall through if failed. Failure to retrieve cached scan + // results should trigger a background scan failure. + case WIFI_SCAN_FAILED: + on_failure_user_callback(id); + on_gscan_event_internal_callback = nullptr; + on_gscan_full_result_internal_callback = nullptr; + return; + } + LOG(FATAL) << "Unexpected gscan event received: " << event; + }; + + on_gscan_full_result_internal_callback = [on_full_result_user_callback]( + wifi_request_id id, wifi_scan_result* result, + uint32_t buckets_scanned) { + if (result) { + on_full_result_user_callback(id, result, buckets_scanned); + } + }; + + wifi_scan_result_handler handler = {onAsyncGscanFullResult, onAsyncGscanEvent}; + wifi_error status = + global_func_table_.wifi_start_gscan(id, getIfaceHandle(iface_name), params, handler); + if (status != WIFI_SUCCESS) { + on_gscan_event_internal_callback = nullptr; + on_gscan_full_result_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name, wifi_request_id id) { + // If there is no an ongoing background scan, reject stop requests. + // TODO(b/32337212): This needs to be handled by the HIDL object because we + // need to return the NOT_STARTED error code. + if (!on_gscan_event_internal_callback && !on_gscan_full_result_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + wifi_error status = global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name)); + // If the request Id is wrong, don't stop the ongoing background scan. Any + // other error should be treated as the end of background scan. + if (status != WIFI_ERROR_INVALID_REQUEST_ID) { + on_gscan_event_internal_callback = nullptr; + on_gscan_full_result_internal_callback = nullptr; + } + return status; +} + +std::pair> WifiLegacyHal::getValidFrequenciesForBand( + const std::string& iface_name, wifi_band band) { + static_assert(sizeof(uint32_t) >= sizeof(wifi_channel), + "Wifi Channel cannot be represented in output"); + std::vector freqs; + freqs.resize(kMaxGscanFrequenciesForBand); + int32_t num_freqs = 0; + wifi_error status = global_func_table_.wifi_get_valid_channels( + getIfaceHandle(iface_name), band, freqs.size(), + reinterpret_cast(freqs.data()), &num_freqs); + CHECK(num_freqs >= 0 && static_cast(num_freqs) <= kMaxGscanFrequenciesForBand); + freqs.resize(num_freqs); + return {status, std::move(freqs)}; +} + +wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name, bool dfs_on) { + return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name), dfs_on ? 0 : 1); +} + +wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name, bool debug) { + wifi_link_layer_params params; + params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold; + params.aggressive_statistics_gathering = debug; + return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name), params); +} + +wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) { + // TODO: Do we care about these responses? + uint32_t clear_mask_rsp; + uint8_t stop_rsp; + return global_func_table_.wifi_clear_link_stats(getIfaceHandle(iface_name), 0xFFFFFFFF, + &clear_mask_rsp, 1, &stop_rsp); +} + +std::pair WifiLegacyHal::getLinkLayerStats( + const std::string& iface_name) { + LinkLayerStats link_stats{}; + LinkLayerStats* link_stats_ptr = &link_stats; + + on_link_layer_stats_result_internal_callback = [&link_stats_ptr]( + wifi_request_id /* id */, + wifi_iface_stat* iface_stats_ptr, + int num_radios, + wifi_radio_stat* radio_stats_ptr) { + wifi_radio_stat* l_radio_stats_ptr; + wifi_peer_info* l_peer_info_stats_ptr; + + if (iface_stats_ptr != nullptr) { + link_stats_ptr->iface = *iface_stats_ptr; + l_peer_info_stats_ptr = iface_stats_ptr->peer_info; + for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) { + WifiPeerInfo peer; + peer.peer_info = *l_peer_info_stats_ptr; + if (l_peer_info_stats_ptr->num_rate > 0) { + /* Copy the rate stats */ + peer.rate_stats.assign( + l_peer_info_stats_ptr->rate_stats, + l_peer_info_stats_ptr->rate_stats + l_peer_info_stats_ptr->num_rate); + } + peer.peer_info.num_rate = 0; + link_stats_ptr->peers.push_back(peer); + l_peer_info_stats_ptr = + (wifi_peer_info*)((u8*)l_peer_info_stats_ptr + sizeof(wifi_peer_info) + + (sizeof(wifi_rate_stat) * + l_peer_info_stats_ptr->num_rate)); + } + link_stats_ptr->iface.num_peers = 0; + } else { + LOG(ERROR) << "Invalid iface stats in link layer stats"; + } + if (num_radios <= 0 || radio_stats_ptr == nullptr) { + LOG(ERROR) << "Invalid radio stats in link layer stats"; + return; + } + l_radio_stats_ptr = radio_stats_ptr; + for (int i = 0; i < num_radios; i++) { + LinkLayerRadioStats radio; + + radio.stats = *l_radio_stats_ptr; + // Copy over the tx level array to the separate vector. + if (l_radio_stats_ptr->num_tx_levels > 0 && + l_radio_stats_ptr->tx_time_per_levels != nullptr) { + radio.tx_time_per_levels.assign( + l_radio_stats_ptr->tx_time_per_levels, + l_radio_stats_ptr->tx_time_per_levels + l_radio_stats_ptr->num_tx_levels); + } + radio.stats.num_tx_levels = 0; + radio.stats.tx_time_per_levels = nullptr; + /* Copy over the channel stat to separate vector */ + if (l_radio_stats_ptr->num_channels > 0) { + /* Copy the channel stats */ + radio.channel_stats.assign( + l_radio_stats_ptr->channels, + l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels); + } + link_stats_ptr->radios.push_back(radio); + l_radio_stats_ptr = + (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) + + (sizeof(wifi_channel_stat) * + l_radio_stats_ptr->num_channels)); + } + }; + + wifi_error status = global_func_table_.wifi_get_link_stats(0, getIfaceHandle(iface_name), + {onSyncLinkLayerStatsResult}); + on_link_layer_stats_result_internal_callback = nullptr; + return {status, link_stats}; +} + +wifi_error WifiLegacyHal::startRssiMonitoring( + const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi, + const on_rssi_threshold_breached_callback& on_threshold_breached_user_callback) { + if (on_rssi_threshold_breached_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_rssi_threshold_breached_internal_callback = [on_threshold_breached_user_callback]( + wifi_request_id id, uint8_t* bssid_ptr, + int8_t rssi) { + if (!bssid_ptr) { + return; + } + std::array bssid_arr; + // |bssid_ptr| pointer is assumed to have 6 bytes for the mac + // address. + std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr)); + on_threshold_breached_user_callback(id, bssid_arr, rssi); + }; + wifi_error status = global_func_table_.wifi_start_rssi_monitoring( + id, getIfaceHandle(iface_name), max_rssi, min_rssi, {onAsyncRssiThresholdBreached}); + if (status != WIFI_SUCCESS) { + on_rssi_threshold_breached_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name, wifi_request_id id) { + if (!on_rssi_threshold_breached_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + wifi_error status = + global_func_table_.wifi_stop_rssi_monitoring(id, getIfaceHandle(iface_name)); + // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any + // other error should be treated as the end of background scan. + if (status != WIFI_ERROR_INVALID_REQUEST_ID) { + on_rssi_threshold_breached_internal_callback = nullptr; + } + return status; +} + +std::pair WifiLegacyHal::getRoamingCapabilities( + const std::string& iface_name) { + wifi_roaming_capabilities caps; + wifi_error status = + global_func_table_.wifi_get_roaming_capabilities(getIfaceHandle(iface_name), &caps); + return {status, caps}; +} + +wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name, + const wifi_roaming_config& config) { + wifi_roaming_config config_internal = config; + return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name), &config_internal); +} + +wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name, + fw_roaming_state_t state) { + return global_func_table_.wifi_enable_firmware_roaming(getIfaceHandle(iface_name), state); +} + +wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name, bool enable) { + return global_func_table_.wifi_configure_nd_offload(getIfaceHandle(iface_name), enable); +} + +wifi_error WifiLegacyHal::startSendingOffloadedPacket(const std::string& iface_name, int32_t cmd_id, + uint16_t ether_type, + const std::vector& ip_packet_data, + const std::array& src_address, + const std::array& dst_address, + int32_t period_in_ms) { + std::vector ip_packet_data_internal(ip_packet_data); + std::vector src_address_internal(src_address.data(), + src_address.data() + src_address.size()); + std::vector dst_address_internal(dst_address.data(), + dst_address.data() + dst_address.size()); + return global_func_table_.wifi_start_sending_offloaded_packet( + cmd_id, getIfaceHandle(iface_name), ether_type, ip_packet_data_internal.data(), + ip_packet_data_internal.size(), src_address_internal.data(), + dst_address_internal.data(), period_in_ms); +} + +wifi_error WifiLegacyHal::stopSendingOffloadedPacket(const std::string& iface_name, + uint32_t cmd_id) { + return global_func_table_.wifi_stop_sending_offloaded_packet(cmd_id, + getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name, + wifi_power_scenario scenario) { + return global_func_table_.wifi_select_tx_power_scenario(getIfaceHandle(iface_name), scenario); +} + +wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) { + return global_func_table_.wifi_reset_tx_power_scenario(getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, wifi_latency_mode mode) { + return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name), mode); +} + +wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode, + uint32_t completion_window) { + return global_func_table_.wifi_set_thermal_mitigation_mode(global_handle_, mode, + completion_window); +} + +wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(uint32_t start, uint32_t end, + uint32_t access_category) { + return global_func_table_.wifi_map_dscp_access_category(global_handle_, start, end, + access_category); +} + +wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() { + return global_func_table_.wifi_reset_dscp_mapping(global_handle_); +} + +std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( + const std::string& iface_name) { + uint32_t supported_feature_flags = 0; + wifi_error status = WIFI_SUCCESS; + + wifi_interface_handle iface_handle = getIfaceHandle(iface_name); + + if (iface_handle) { + status = global_func_table_.wifi_get_logger_supported_feature_set(iface_handle, + &supported_feature_flags); + } + return {status, supported_feature_flags}; +} + +wifi_error WifiLegacyHal::startPktFateMonitoring(const std::string& iface_name) { + return global_func_table_.wifi_start_pkt_fate_monitoring(getIfaceHandle(iface_name)); +} + +std::pair> WifiLegacyHal::getTxPktFates( + const std::string& iface_name) { + std::vector tx_pkt_fates; + tx_pkt_fates.resize(MAX_FATE_LOG_LEN); + size_t num_fates = 0; + wifi_error status = global_func_table_.wifi_get_tx_pkt_fates( + getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(), &num_fates); + CHECK(num_fates <= MAX_FATE_LOG_LEN); + tx_pkt_fates.resize(num_fates); + return {status, std::move(tx_pkt_fates)}; +} + +std::pair> WifiLegacyHal::getRxPktFates( + const std::string& iface_name) { + std::vector rx_pkt_fates; + rx_pkt_fates.resize(MAX_FATE_LOG_LEN); + size_t num_fates = 0; + wifi_error status = global_func_table_.wifi_get_rx_pkt_fates( + getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(), &num_fates); + CHECK(num_fates <= MAX_FATE_LOG_LEN); + rx_pkt_fates.resize(num_fates); + return {status, std::move(rx_pkt_fates)}; +} + +std::pair WifiLegacyHal::getWakeReasonStats( + const std::string& iface_name) { + WakeReasonStats stats; + stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize); + stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize); + + // This legacy struct needs separate memory to store the variable sized wake + // reason types. + stats.wake_reason_cnt.cmd_event_wake_cnt = + reinterpret_cast(stats.cmd_event_wake_cnt.data()); + stats.wake_reason_cnt.cmd_event_wake_cnt_sz = stats.cmd_event_wake_cnt.size(); + stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0; + stats.wake_reason_cnt.driver_fw_local_wake_cnt = + reinterpret_cast(stats.driver_fw_local_wake_cnt.data()); + stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz = stats.driver_fw_local_wake_cnt.size(); + stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0; + + wifi_error status = global_func_table_.wifi_get_wake_reason_stats(getIfaceHandle(iface_name), + &stats.wake_reason_cnt); + + CHECK(stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 && + static_cast(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <= + kMaxWakeReasonStatsArraySize); + stats.cmd_event_wake_cnt.resize(stats.wake_reason_cnt.cmd_event_wake_cnt_used); + stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr; + + CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 && + static_cast(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <= + kMaxWakeReasonStatsArraySize); + stats.driver_fw_local_wake_cnt.resize(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used); + stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr; + + return {status, stats}; +} + +wifi_error WifiLegacyHal::registerRingBufferCallbackHandler( + const std::string& iface_name, const on_ring_buffer_data_callback& on_user_data_callback) { + if (on_ring_buffer_data_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_ring_buffer_data_internal_callback = [on_user_data_callback]( + char* ring_name, char* buffer, int buffer_size, + wifi_ring_buffer_status* status) { + if (status && buffer) { + std::vector buffer_vector(reinterpret_cast(buffer), + reinterpret_cast(buffer) + buffer_size); + on_user_data_callback(ring_name, buffer_vector, *status); + } + }; + wifi_error status = global_func_table_.wifi_set_log_handler(0, getIfaceHandle(iface_name), + {onAsyncRingBufferData}); + if (status != WIFI_SUCCESS) { + on_ring_buffer_data_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(const std::string& iface_name) { + if (!on_ring_buffer_data_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_ring_buffer_data_internal_callback = nullptr; + return global_func_table_.wifi_reset_log_handler(0, getIfaceHandle(iface_name)); +} + +std::pair> WifiLegacyHal::getRingBuffersStatus( + const std::string& iface_name) { + std::vector ring_buffers_status; + ring_buffers_status.resize(kMaxRingBuffers); + uint32_t num_rings = kMaxRingBuffers; + wifi_error status = global_func_table_.wifi_get_ring_buffers_status( + getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data()); + CHECK(num_rings <= kMaxRingBuffers); + ring_buffers_status.resize(num_rings); + return {status, std::move(ring_buffers_status)}; +} + +wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name, + const std::string& ring_name, + uint32_t verbose_level, uint32_t max_interval_sec, + uint32_t min_data_size) { + return global_func_table_.wifi_start_logging(getIfaceHandle(iface_name), verbose_level, 0, + max_interval_sec, min_data_size, + makeCharVec(ring_name).data()); +} + +wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name, + const std::string& ring_name) { + return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name), + makeCharVec(ring_name).data()); +} + +wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler( + const std::string& iface_name, const on_error_alert_callback& on_user_alert_callback) { + if (on_error_alert_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_error_alert_internal_callback = [on_user_alert_callback](wifi_request_id id, char* buffer, + int buffer_size, int err_code) { + if (buffer) { + CHECK(id == 0); + on_user_alert_callback( + err_code, + std::vector(reinterpret_cast(buffer), + reinterpret_cast(buffer) + buffer_size)); + } + }; + wifi_error status = global_func_table_.wifi_set_alert_handler(0, getIfaceHandle(iface_name), + {onAsyncErrorAlert}); + if (status != WIFI_SUCCESS) { + on_error_alert_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(const std::string& iface_name) { + if (!on_error_alert_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_error_alert_internal_callback = nullptr; + return global_func_table_.wifi_reset_alert_handler(0, getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler( + const std::string& iface_name, + const on_radio_mode_change_callback& on_user_change_callback) { + if (on_radio_mode_change_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_radio_mode_change_internal_callback = [on_user_change_callback]( + wifi_request_id /* id */, uint32_t num_macs, + wifi_mac_info* mac_infos_arr) { + if (num_macs > 0 && mac_infos_arr) { + std::vector mac_infos_vec; + for (uint32_t i = 0; i < num_macs; i++) { + WifiMacInfo mac_info; + mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id; + mac_info.mac_band = mac_infos_arr[i].mac_band; + for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) { + WifiIfaceInfo iface_info; + iface_info.name = mac_infos_arr[i].iface_info[j].iface_name; + iface_info.channel = mac_infos_arr[i].iface_info[j].channel; + mac_info.iface_infos.push_back(iface_info); + } + mac_infos_vec.push_back(mac_info); + } + on_user_change_callback(mac_infos_vec); + } + }; + wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler( + 0, getIfaceHandle(iface_name), {onAsyncRadioModeChange}); + if (status != WIFI_SUCCESS) { + on_radio_mode_change_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler( + const on_subsystem_restart_callback& on_restart_callback) { + if (on_subsystem_restart_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + on_subsystem_restart_internal_callback = [on_restart_callback](const char* error) { + on_restart_callback(error); + }; + wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler( + global_handle_, {onAsyncSubsystemRestart}); + if (status != WIFI_SUCCESS) { + on_subsystem_restart_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::startRttRangeRequest( + const std::string& iface_name, wifi_request_id id, + const std::vector& rtt_configs, + const on_rtt_results_callback& on_results_user_callback) { + if (on_rtt_results_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + + on_rtt_results_internal_callback = [on_results_user_callback](wifi_request_id id, + unsigned num_results, + wifi_rtt_result* rtt_results[]) { + if (num_results > 0 && !rtt_results) { + LOG(ERROR) << "Unexpected nullptr in RTT results"; + return; + } + std::vector rtt_results_vec; + std::copy_if(rtt_results, rtt_results + num_results, back_inserter(rtt_results_vec), + [](wifi_rtt_result* rtt_result) { return rtt_result != nullptr; }); + on_results_user_callback(id, rtt_results_vec); + }; + + std::vector rtt_configs_internal(rtt_configs); + wifi_error status = global_func_table_.wifi_rtt_range_request( + id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(), + {onAsyncRttResults}); + if (status != WIFI_SUCCESS) { + on_rtt_results_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::cancelRttRangeRequest( + const std::string& iface_name, wifi_request_id id, + const std::vector>& mac_addrs) { + if (!on_rtt_results_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + static_assert(sizeof(mac_addr) == sizeof(std::array), + "MAC address size mismatch"); + // TODO: How do we handle partial cancels (i.e only a subset of enabled mac + // addressed are cancelled). + std::vector> mac_addrs_internal(mac_addrs); + wifi_error status = global_func_table_.wifi_rtt_range_cancel( + id, getIfaceHandle(iface_name), mac_addrs.size(), + reinterpret_cast(mac_addrs_internal.data())); + // If the request Id is wrong, don't stop the ongoing range request. Any + // other error should be treated as the end of rtt ranging. + if (status != WIFI_ERROR_INVALID_REQUEST_ID) { + on_rtt_results_internal_callback = nullptr; + } + return status; +} + +std::pair WifiLegacyHal::getRttCapabilities( + const std::string& iface_name) { + wifi_rtt_capabilities rtt_caps; + wifi_error status = + global_func_table_.wifi_get_rtt_capabilities(getIfaceHandle(iface_name), &rtt_caps); + return {status, rtt_caps}; +} + +std::pair WifiLegacyHal::getRttResponderInfo( + const std::string& iface_name) { + wifi_rtt_responder rtt_responder; + wifi_error status = global_func_table_.wifi_rtt_get_responder_info(getIfaceHandle(iface_name), + &rtt_responder); + return {status, rtt_responder}; +} + +wifi_error WifiLegacyHal::enableRttResponder(const std::string& iface_name, wifi_request_id id, + const wifi_channel_info& channel_hint, + uint32_t max_duration_secs, + const wifi_rtt_responder& info) { + wifi_rtt_responder info_internal(info); + return global_func_table_.wifi_enable_responder(id, getIfaceHandle(iface_name), channel_hint, + max_duration_secs, &info_internal); +} + +wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name, wifi_request_id id) { + return global_func_table_.wifi_disable_responder(id, getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name, wifi_request_id id, + const wifi_lci_information& info) { + wifi_lci_information info_internal(info); + return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name), &info_internal); +} + +wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name, wifi_request_id id, + const wifi_lcr_information& info) { + wifi_lcr_information info_internal(info); + return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name), &info_internal); +} + +wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(const std::string& iface_name, + const NanCallbackHandlers& user_callbacks) { + on_nan_notify_response_user_callback = user_callbacks.on_notify_response; + on_nan_event_publish_terminated_user_callback = user_callbacks.on_event_publish_terminated; + on_nan_event_match_user_callback = user_callbacks.on_event_match; + on_nan_event_match_expired_user_callback = user_callbacks.on_event_match_expired; + on_nan_event_subscribe_terminated_user_callback = user_callbacks.on_event_subscribe_terminated; + on_nan_event_followup_user_callback = user_callbacks.on_event_followup; + on_nan_event_disc_eng_event_user_callback = user_callbacks.on_event_disc_eng_event; + on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled; + on_nan_event_tca_user_callback = user_callbacks.on_event_tca; + on_nan_event_beacon_sdf_payload_user_callback = user_callbacks.on_event_beacon_sdf_payload; + on_nan_event_data_path_request_user_callback = user_callbacks.on_event_data_path_request; + on_nan_event_data_path_confirm_user_callback = user_callbacks.on_event_data_path_confirm; + on_nan_event_data_path_end_user_callback = user_callbacks.on_event_data_path_end; + on_nan_event_transmit_follow_up_user_callback = user_callbacks.on_event_transmit_follow_up; + on_nan_event_range_request_user_callback = user_callbacks.on_event_range_request; + on_nan_event_range_report_user_callback = user_callbacks.on_event_range_report; + on_nan_event_schedule_update_user_callback = user_callbacks.on_event_schedule_update; + + return global_func_table_.wifi_nan_register_handler( + getIfaceHandle(iface_name), + {onAsyncNanNotifyResponse, onAsyncNanEventPublishReplied, + onAsyncNanEventPublishTerminated, onAsyncNanEventMatch, onAsyncNanEventMatchExpired, + onAsyncNanEventSubscribeTerminated, onAsyncNanEventFollowup, + onAsyncNanEventDiscEngEvent, onAsyncNanEventDisabled, onAsyncNanEventTca, + onAsyncNanEventBeaconSdfPayload, onAsyncNanEventDataPathRequest, + onAsyncNanEventDataPathConfirm, onAsyncNanEventDataPathEnd, + onAsyncNanEventTransmitFollowUp, onAsyncNanEventRangeRequest, + onAsyncNanEventRangeReport, onAsyncNanEventScheduleUpdate}); +} + +wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name, transaction_id id, + const NanEnableRequest& msg) { + NanEnableRequest msg_internal(msg); + return global_func_table_.wifi_nan_enable_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name, transaction_id id) { + return global_func_table_.wifi_nan_disable_request(id, getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name, transaction_id id, + const NanPublishRequest& msg) { + NanPublishRequest msg_internal(msg); + return global_func_table_.wifi_nan_publish_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanPublishCancelRequest(const std::string& iface_name, transaction_id id, + const NanPublishCancelRequest& msg) { + NanPublishCancelRequest msg_internal(msg); + return global_func_table_.wifi_nan_publish_cancel_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name, transaction_id id, + const NanSubscribeRequest& msg) { + NanSubscribeRequest msg_internal(msg); + return global_func_table_.wifi_nan_subscribe_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanSubscribeCancelRequest(const std::string& iface_name, + transaction_id id, + const NanSubscribeCancelRequest& msg) { + NanSubscribeCancelRequest msg_internal(msg); + return global_func_table_.wifi_nan_subscribe_cancel_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanTransmitFollowupRequest(const std::string& iface_name, + transaction_id id, + const NanTransmitFollowupRequest& msg) { + NanTransmitFollowupRequest msg_internal(msg); + return global_func_table_.wifi_nan_transmit_followup_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name, transaction_id id, + const NanStatsRequest& msg) { + NanStatsRequest msg_internal(msg); + return global_func_table_.wifi_nan_stats_request(id, getIfaceHandle(iface_name), &msg_internal); +} + +wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name, transaction_id id, + const NanConfigRequest& msg) { + NanConfigRequest msg_internal(msg); + return global_func_table_.wifi_nan_config_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name, transaction_id id, + const NanTCARequest& msg) { + NanTCARequest msg_internal(msg); + return global_func_table_.wifi_nan_tca_request(id, getIfaceHandle(iface_name), &msg_internal); +} + +wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(const std::string& iface_name, + transaction_id id, + const NanBeaconSdfPayloadRequest& msg) { + NanBeaconSdfPayloadRequest msg_internal(msg); + return global_func_table_.wifi_nan_beacon_sdf_payload_request(id, getIfaceHandle(iface_name), + &msg_internal); +} + +std::pair WifiLegacyHal::nanGetVersion() { + NanVersion version; + wifi_error status = global_func_table_.wifi_nan_get_version(global_handle_, &version); + return {status, version}; +} + +wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name, transaction_id id) { + return global_func_table_.wifi_nan_get_capabilities(id, getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::nanDataInterfaceCreate(const std::string& iface_name, transaction_id id, + const std::string& data_iface_name) { + return global_func_table_.wifi_nan_data_interface_create(id, getIfaceHandle(iface_name), + makeCharVec(data_iface_name).data()); +} + +wifi_error WifiLegacyHal::nanDataInterfaceDelete(const std::string& iface_name, transaction_id id, + const std::string& data_iface_name) { + return global_func_table_.wifi_nan_data_interface_delete(id, getIfaceHandle(iface_name), + makeCharVec(data_iface_name).data()); +} + +wifi_error WifiLegacyHal::nanDataRequestInitiator(const std::string& iface_name, transaction_id id, + const NanDataPathInitiatorRequest& msg) { + NanDataPathInitiatorRequest msg_internal(msg); + return global_func_table_.wifi_nan_data_request_initiator(id, getIfaceHandle(iface_name), + &msg_internal); +} + +wifi_error WifiLegacyHal::nanDataIndicationResponse(const std::string& iface_name, + transaction_id id, + const NanDataPathIndicationResponse& msg) { + NanDataPathIndicationResponse msg_internal(msg); + return global_func_table_.wifi_nan_data_indication_response(id, getIfaceHandle(iface_name), + &msg_internal); +} + +typedef struct { + u8 num_ndp_instances; + NanDataPathId ndp_instance_id; +} NanDataPathEndSingleNdpIdRequest; + +wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name, transaction_id id, + uint32_t ndpInstanceId) { + NanDataPathEndSingleNdpIdRequest msg; + msg.num_ndp_instances = 1; + msg.ndp_instance_id = ndpInstanceId; + wifi_error status = global_func_table_.wifi_nan_data_end(id, getIfaceHandle(iface_name), + (NanDataPathEndRequest*)&msg); + return status; +} + +wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name, + const std::array code) { + std::string code_str(code.data(), code.data() + code.size()); + return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name), code_str.c_str()); +} + +wifi_error WifiLegacyHal::retrieveIfaceHandles() { + 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; + } + iface_name_to_handle_.clear(); + for (int i = 0; i < num_iface_handles; ++i) { + std::array iface_name_arr = {}; + status = global_func_table_.wifi_get_iface_name(iface_handles[i], iface_name_arr.data(), + iface_name_arr.size()); + if (status != WIFI_SUCCESS) { + LOG(WARNING) << "Failed to get interface handle name"; + continue; + } + // Assuming the interface name is null terminated since the legacy HAL + // API does not return a size. + std::string iface_name(iface_name_arr.data()); + LOG(INFO) << "Adding interface handle for " << iface_name; + iface_name_to_handle_[iface_name] = iface_handles[i]; + } + return WIFI_SUCCESS; +} + +wifi_interface_handle WifiLegacyHal::getIfaceHandle(const std::string& iface_name) { + const auto iface_handle_iter = iface_name_to_handle_.find(iface_name); + if (iface_handle_iter == iface_name_to_handle_.end()) { + LOG(ERROR) << "Unknown iface name: " << iface_name; + return nullptr; + } + return iface_handle_iter->second; +} + +void WifiLegacyHal::runEventLoop() { + LOG(DEBUG) << "Starting legacy HAL event loop"; + global_func_table_.wifi_event_loop(global_handle_); + const auto lock = aidl_sync_util::acquireGlobalLock(); + if (!awaiting_event_loop_termination_) { + LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping"; + } + LOG(DEBUG) << "Legacy HAL event loop terminated"; + awaiting_event_loop_termination_ = false; + stop_wait_cv_.notify_one(); +} + +std::pair> WifiLegacyHal::getGscanCachedResults( + const std::string& iface_name) { + std::vector cached_scan_results; + cached_scan_results.resize(kMaxCachedGscanResults); + int32_t num_results = 0; + wifi_error status = global_func_table_.wifi_get_cached_gscan_results( + getIfaceHandle(iface_name), true /* always flush */, cached_scan_results.size(), + cached_scan_results.data(), &num_results); + CHECK(num_results >= 0 && static_cast(num_results) <= kMaxCachedGscanResults); + cached_scan_results.resize(num_results); + // Check for invalid IE lengths in these cached scan results and correct it. + for (auto& cached_scan_result : cached_scan_results) { + int num_scan_results = cached_scan_result.num_results; + for (int i = 0; i < num_scan_results; i++) { + auto& scan_result = cached_scan_result.results[i]; + if (scan_result.ie_length > 0) { + LOG(DEBUG) << "Cached scan result has non-zero IE length " << scan_result.ie_length; + scan_result.ie_length = 0; + } + } + } + return {status, std::move(cached_scan_results)}; +} + +wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname, + wifi_interface_type iftype) { + // Create the interface if it doesn't exist. If interface already exist, + // Vendor Hal should return WIFI_SUCCESS. + wifi_error status = global_func_table_.wifi_virtual_interface_create(global_handle_, + ifname.c_str(), iftype); + return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status); +} + +wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) { + // Delete the interface if it was created dynamically. + wifi_error status = + global_func_table_.wifi_virtual_interface_delete(global_handle_, ifname.c_str()); + return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status); +} + +wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname, + wifi_error status) { + if (status == WIFI_SUCCESS) { + // refresh list of handlers now. + status = retrieveIfaceHandles(); + } else if (status == WIFI_ERROR_NOT_SUPPORTED) { + // Vendor hal does not implement this API. Such vendor implementations + // are expected to create / delete interface by other means. + + // check if interface exists. + if (if_nametoindex(ifname.c_str())) { + status = retrieveIfaceHandles(); + } + } + return status; +} + +wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type, std::string& ifname) { + std::array buffer; + + wifi_error res = global_func_table_.wifi_get_supported_iface_name( + global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size()); + if (res == WIFI_SUCCESS) ifname = buffer.data(); + + return res; +} + +wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(const std::string& ifname) { + return global_func_table_.wifi_multi_sta_set_primary_connection(global_handle_, + getIfaceHandle(ifname)); +} + +wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) { + return global_func_table_.wifi_multi_sta_set_use_case(global_handle_, use_case); +} + +wifi_error WifiLegacyHal::setCoexUnsafeChannels( + std::vector unsafe_channels, uint32_t restrictions) { + return global_func_table_.wifi_set_coex_unsafe_channels(global_handle_, unsafe_channels.size(), + unsafe_channels.data(), restrictions); +} + +wifi_error WifiLegacyHal::setVoipMode(const std::string& iface_name, wifi_voip_mode mode) { + return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode); +} + +wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name, + const TwtCallbackHandlers& user_callbacks) { + on_twt_event_setup_response_callback = user_callbacks.on_setup_response; + on_twt_event_teardown_completion_callback = user_callbacks.on_teardown_completion; + on_twt_event_info_frame_received_callback = user_callbacks.on_info_frame_received; + on_twt_event_device_notify_callback = user_callbacks.on_device_notify; + + return global_func_table_.wifi_twt_register_handler( + getIfaceHandle(iface_name), + {onAsyncTwtEventSetupResponse, onAsyncTwtEventTeardownCompletion, + onAsyncTwtEventInfoFrameReceived, onAsyncTwtEventDeviceNotify}); +} + +std::pair WifiLegacyHal::twtGetCapability( + const std::string& iface_name) { + TwtCapabilitySet capSet; + wifi_error status = + global_func_table_.wifi_twt_get_capability(getIfaceHandle(iface_name), &capSet); + return {status, capSet}; +} + +wifi_error WifiLegacyHal::twtSetupRequest(const std::string& iface_name, + const TwtSetupRequest& msg) { + TwtSetupRequest msgInternal(msg); + return global_func_table_.wifi_twt_setup_request(getIfaceHandle(iface_name), &msgInternal); +} + +wifi_error WifiLegacyHal::twtTearDownRequest(const std::string& iface_name, + const TwtTeardownRequest& msg) { + TwtTeardownRequest msgInternal(msg); + return global_func_table_.wifi_twt_teardown_request(getIfaceHandle(iface_name), &msgInternal); +} + +wifi_error WifiLegacyHal::twtInfoFrameRequest(const std::string& iface_name, + const TwtInfoFrameRequest& msg) { + TwtInfoFrameRequest msgInternal(msg); + return global_func_table_.wifi_twt_info_frame_request(getIfaceHandle(iface_name), &msgInternal); +} + +std::pair WifiLegacyHal::twtGetStats(const std::string& iface_name, + uint8_t configId) { + TwtStats stats; + wifi_error status = + global_func_table_.wifi_twt_get_stats(getIfaceHandle(iface_name), configId, &stats); + return {status, stats}; +} + +wifi_error WifiLegacyHal::twtClearStats(const std::string& iface_name, uint8_t configId) { + return global_func_table_.wifi_twt_clear_stats(getIfaceHandle(iface_name), configId); +} + +wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name, uint32_t multiplier) { + return global_func_table_.wifi_set_dtim_config(getIfaceHandle(iface_name), multiplier); +} + +std::pair> WifiLegacyHal::getUsableChannels( + uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask) { + std::vector channels; + channels.resize(kMaxWifiUsableChannels); + uint32_t size = 0; + wifi_error status = global_func_table_.wifi_get_usable_channels( + global_handle_, band_mask, iface_mode_mask, filter_mask, channels.size(), &size, + reinterpret_cast(channels.data())); + CHECK(size >= 0 && size <= kMaxWifiUsableChannels); + channels.resize(size); + return {status, std::move(channels)}; +} + +wifi_error WifiLegacyHal::triggerSubsystemRestart() { + return global_func_table_.wifi_trigger_subsystem_restart(global_handle_); +} + +wifi_error WifiLegacyHal::setIndoorState(bool isIndoor) { + return global_func_table_.wifi_set_indoor_state(global_handle_, isIndoor); +} + +std::pair +WifiLegacyHal::getSupportedRadioCombinationsMatrix() { + char* buffer = new char[kMaxSupportedRadioCombinationsMatrixLength]; + std::fill(buffer, buffer + kMaxSupportedRadioCombinationsMatrixLength, 0); + uint32_t size = 0; + wifi_radio_combination_matrix* radio_combination_matrix_ptr = + reinterpret_cast(buffer); + wifi_error status = global_func_table_.wifi_get_supported_radio_combinations_matrix( + global_handle_, kMaxSupportedRadioCombinationsMatrixLength, &size, + radio_combination_matrix_ptr); + CHECK(size >= 0 && size <= kMaxSupportedRadioCombinationsMatrixLength); + return {status, radio_combination_matrix_ptr}; +} + +wifi_error WifiLegacyHal::chreNanRttRequest(const std::string& iface_name, bool enable) { + if (enable) + return global_func_table_.wifi_nan_rtt_chre_enable_request(0, getIfaceHandle(iface_name), + NULL); + else + return global_func_table_.wifi_nan_rtt_chre_disable_request(0, getIfaceHandle(iface_name)); +} + +wifi_error WifiLegacyHal::chreRegisterHandler(const std::string& iface_name, + const ChreCallbackHandlers& handler) { + if (on_chre_nan_rtt_internal_callback) { + return WIFI_ERROR_NOT_AVAILABLE; + } + + on_chre_nan_rtt_internal_callback = handler.on_wifi_chre_nan_rtt_state; + + wifi_error status = global_func_table_.wifi_chre_register_handler(getIfaceHandle(iface_name), + {onAsyncChreNanRttState}); + if (status != WIFI_SUCCESS) { + on_chre_nan_rtt_internal_callback = nullptr; + } + return status; +} + +wifi_error WifiLegacyHal::enableWifiTxPowerLimits(const std::string& iface_name, bool enable) { + return global_func_table_.wifi_enable_tx_power_limits(getIfaceHandle(iface_name), enable); +} + +wifi_error WifiLegacyHal::getWifiCachedScanResults( + const std::string& iface_name, const CachedScanResultsCallbackHandlers& handler) { + on_cached_scan_results_internal_callback = handler.on_cached_scan_results; + + wifi_error status = global_func_table_.wifi_get_cached_scan_results(getIfaceHandle(iface_name), + {onSyncCachedScanResults}); + + on_cached_scan_results_internal_callback = nullptr; + return status; +} + +void WifiLegacyHal::invalidate() { + global_handle_ = nullptr; + iface_name_to_handle_.clear(); + on_driver_memory_dump_internal_callback = nullptr; + on_firmware_memory_dump_internal_callback = nullptr; + on_gscan_event_internal_callback = nullptr; + on_gscan_full_result_internal_callback = nullptr; + on_link_layer_stats_result_internal_callback = nullptr; + on_rssi_threshold_breached_internal_callback = nullptr; + on_ring_buffer_data_internal_callback = nullptr; + on_error_alert_internal_callback = nullptr; + on_radio_mode_change_internal_callback = nullptr; + on_subsystem_restart_internal_callback = nullptr; + on_rtt_results_internal_callback = nullptr; + on_nan_notify_response_user_callback = nullptr; + on_nan_event_publish_terminated_user_callback = nullptr; + on_nan_event_match_user_callback = nullptr; + on_nan_event_match_expired_user_callback = nullptr; + on_nan_event_subscribe_terminated_user_callback = nullptr; + on_nan_event_followup_user_callback = nullptr; + on_nan_event_disc_eng_event_user_callback = nullptr; + on_nan_event_disabled_user_callback = nullptr; + on_nan_event_tca_user_callback = nullptr; + on_nan_event_beacon_sdf_payload_user_callback = nullptr; + on_nan_event_data_path_request_user_callback = nullptr; + on_nan_event_data_path_confirm_user_callback = nullptr; + on_nan_event_data_path_end_user_callback = nullptr; + on_nan_event_transmit_follow_up_user_callback = nullptr; + on_nan_event_range_request_user_callback = nullptr; + on_nan_event_range_report_user_callback = nullptr; + on_nan_event_schedule_update_user_callback = nullptr; + on_twt_event_setup_response_callback = nullptr; + on_twt_event_teardown_completion_callback = nullptr; + on_twt_event_info_frame_received_callback = nullptr; + on_twt_event_device_notify_callback = nullptr; + on_chre_nan_rtt_internal_callback = nullptr; +} + +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h new file mode 100644 index 0000000000..cd8c0b1136 --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal.h @@ -0,0 +1,738 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_LEGACY_HAL_H_ +#define WIFI_LEGACY_HAL_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +// This is in a separate namespace to prevent typename conflicts between +// the legacy HAL types and the AIDL interface types. +namespace legacy_hal { +// Import all the types defined inside the legacy HAL header files into this +// namespace. +using ::chre_nan_rtt_state; +using ::frame_info; +using ::frame_type; +using ::FRAME_TYPE_80211_MGMT; +using ::FRAME_TYPE_ETHERNET_II; +using ::FRAME_TYPE_UNKNOWN; +using ::fw_roaming_state_t; +using ::mac_addr; +using ::NAN_CHANNEL_24G_BAND; +using ::NAN_CHANNEL_5G_BAND_HIGH; +using ::NAN_CHANNEL_5G_BAND_LOW; +using ::NAN_DISABLE_RANGE_REPORT; +using ::NAN_DO_NOT_USE_SRF; +using ::NAN_DP_CHANNEL_NOT_REQUESTED; +using ::NAN_DP_CONFIG_NO_SECURITY; +using ::NAN_DP_CONFIG_SECURITY; +using ::NAN_DP_END; +using ::NAN_DP_FORCE_CHANNEL_SETUP; +using ::NAN_DP_INITIATOR_RESPONSE; +using ::NAN_DP_INTERFACE_CREATE; +using ::NAN_DP_INTERFACE_DELETE; +using ::NAN_DP_REQUEST_ACCEPT; +using ::NAN_DP_REQUEST_CHANNEL_SETUP; +using ::NAN_DP_REQUEST_REJECT; +using ::NAN_DP_RESPONDER_RESPONSE; +using ::NAN_GET_CAPABILITIES; +using ::NAN_MATCH_ALG_MATCH_CONTINUOUS; +using ::NAN_MATCH_ALG_MATCH_NEVER; +using ::NAN_MATCH_ALG_MATCH_ONCE; +using ::NAN_PUBLISH_TYPE_SOLICITED; +using ::NAN_PUBLISH_TYPE_UNSOLICITED; +using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED; +using ::NAN_RANGING_AUTO_RESPONSE_DISABLE; +using ::NAN_RANGING_AUTO_RESPONSE_ENABLE; +using ::NAN_RANGING_DISABLE; +using ::NAN_RANGING_ENABLE; +using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD; +using ::NAN_RESPONSE_CONFIG; +using ::NAN_RESPONSE_DISABLED; +using ::NAN_RESPONSE_ENABLED; +using ::NAN_RESPONSE_ERROR; +using ::NAN_RESPONSE_PUBLISH; +using ::NAN_RESPONSE_PUBLISH_CANCEL; +using ::NAN_RESPONSE_STATS; +using ::NAN_RESPONSE_SUBSCRIBE; +using ::NAN_RESPONSE_SUBSCRIBE_CANCEL; +using ::NAN_RESPONSE_TCA; +using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP; +using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE; +using ::NAN_SECURITY_KEY_INPUT_PMK; +using ::NAN_SERVICE_ACCEPT_POLICY_ALL; +using ::NAN_SERVICE_ACCEPT_POLICY_NONE; +using ::NAN_SRF_ATTR_BLOOM_FILTER; +using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR; +using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND; +using ::NAN_SRF_INCLUDE_RESPOND; +using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND; +using ::NAN_SSI_REQUIRED_IN_MATCH_IND; +using ::NAN_STATUS_ALREADY_ENABLED; +using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL; +using ::NAN_STATUS_INTERNAL_FAILURE; +using ::NAN_STATUS_INVALID_NDP_ID; +using ::NAN_STATUS_INVALID_PARAM; +using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID; +using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID; +using ::NAN_STATUS_NAN_NOT_ALLOWED; +using ::NAN_STATUS_NO_OTA_ACK; +using ::NAN_STATUS_NO_RESOURCE_AVAILABLE; +using ::NAN_STATUS_PROTOCOL_FAILURE; +using ::NAN_STATUS_SUCCESS; +using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED; +using ::NAN_SUBSCRIBE_TYPE_ACTIVE; +using ::NAN_SUBSCRIBE_TYPE_PASSIVE; +using ::NAN_TRANSMIT_IN_DW; +using ::NAN_TRANSMIT_IN_FAW; +using ::NAN_TX_PRIORITY_HIGH; +using ::NAN_TX_PRIORITY_NORMAL; +using ::NAN_TX_TYPE_BROADCAST; +using ::NAN_TX_TYPE_UNICAST; +using ::NAN_USE_SRF; +using ::NanBeaconSdfPayloadInd; +using ::NanCapabilities; +using ::NanChannelInfo; +using ::NanConfigRequest; +using ::NanDataPathChannelCfg; +using ::NanDataPathConfirmInd; +using ::NanDataPathEndInd; +using ::NanDataPathIndicationResponse; +using ::NanDataPathInitiatorRequest; +using ::NanDataPathRequestInd; +using ::NanDataPathScheduleUpdateInd; +using ::NanDisabledInd; +using ::NanDiscEngEventInd; +using ::NanEnableRequest; +using ::NanFollowupInd; +using ::NanMatchAlg; +using ::NanMatchExpiredInd; +using ::NanMatchInd; +using ::NanPublishCancelRequest; +using ::NanPublishRequest; +using ::NanPublishTerminatedInd; +using ::NanPublishType; +using ::NanRangeReportInd; +using ::NanRangeRequestInd; +using ::NanResponseMsg; +using ::NanSRFType; +using ::NanStatusType; +using ::NanSubscribeCancelRequest; +using ::NanSubscribeRequest; +using ::NanSubscribeTerminatedInd; +using ::NanSubscribeType; +using ::NanTransmitFollowupInd; +using ::NanTransmitFollowupRequest; +using ::NanTxType; +using ::ROAMING_DISABLE; +using ::ROAMING_ENABLE; +using ::RTT_PEER_AP; +using ::RTT_PEER_NAN; +using ::RTT_PEER_P2P_CLIENT; +using ::RTT_PEER_P2P_GO; +using ::RTT_PEER_STA; +using ::rtt_peer_type; +using ::RTT_STATUS_ABORTED; +using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL; +using ::RTT_STATUS_FAIL_BUSY_TRY_LATER; +using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE; +using ::RTT_STATUS_FAIL_INVALID_TS; +using ::RTT_STATUS_FAIL_NO_CAPABILITY; +using ::RTT_STATUS_FAIL_NO_RSP; +using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET; +using ::RTT_STATUS_FAIL_PROTOCOL; +using ::RTT_STATUS_FAIL_REJECTED; +using ::RTT_STATUS_FAIL_SCHEDULE; +using ::RTT_STATUS_FAIL_TM_TIMEOUT; +using ::RTT_STATUS_FAILURE; +using ::RTT_STATUS_INVALID_REQ; +using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED; +using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE; +using ::RTT_STATUS_NO_WIFI; +using ::RTT_STATUS_SUCCESS; +using ::RTT_TYPE_1_SIDED; +using ::RTT_TYPE_2_SIDED; +using ::RX_PKT_FATE_DRV_DROP_FILTER; +using ::RX_PKT_FATE_DRV_DROP_INVALID; +using ::RX_PKT_FATE_DRV_DROP_NOBUFS; +using ::RX_PKT_FATE_DRV_DROP_OTHER; +using ::RX_PKT_FATE_DRV_QUEUED; +using ::RX_PKT_FATE_FW_DROP_FILTER; +using ::RX_PKT_FATE_FW_DROP_INVALID; +using ::RX_PKT_FATE_FW_DROP_NOBUFS; +using ::RX_PKT_FATE_FW_DROP_OTHER; +using ::RX_PKT_FATE_FW_QUEUED; +using ::RX_PKT_FATE_SUCCESS; +using ::ssid_t; +using ::transaction_id; +using ::TX_PKT_FATE_ACKED; +using ::TX_PKT_FATE_DRV_DROP_INVALID; +using ::TX_PKT_FATE_DRV_DROP_NOBUFS; +using ::TX_PKT_FATE_DRV_DROP_OTHER; +using ::TX_PKT_FATE_DRV_QUEUED; +using ::TX_PKT_FATE_FW_DROP_INVALID; +using ::TX_PKT_FATE_FW_DROP_NOBUFS; +using ::TX_PKT_FATE_FW_DROP_OTHER; +using ::TX_PKT_FATE_FW_QUEUED; +using ::TX_PKT_FATE_SENT; +using ::WIFI_AC_BE; +using ::WIFI_AC_BK; +using ::WIFI_AC_VI; +using ::WIFI_AC_VO; +using ::WIFI_ANTENNA_1X1; +using ::WIFI_ANTENNA_2X2; +using ::WIFI_ANTENNA_3X3; +using ::WIFI_ANTENNA_4X4; +using ::WIFI_ANTENNA_UNSPECIFIED; +using ::wifi_band; +using ::WIFI_BAND_A; +using ::WIFI_BAND_A_DFS; +using ::WIFI_BAND_A_WITH_DFS; +using ::WIFI_BAND_ABG; +using ::WIFI_BAND_ABG_WITH_DFS; +using ::WIFI_BAND_BG; +using ::WIFI_BAND_UNSPECIFIED; +using ::wifi_cached_scan_report; +using ::wifi_cached_scan_results; +using ::WIFI_CHAN_WIDTH_10; +using ::WIFI_CHAN_WIDTH_160; +using ::WIFI_CHAN_WIDTH_20; +using ::WIFI_CHAN_WIDTH_320; +using ::WIFI_CHAN_WIDTH_40; +using ::WIFI_CHAN_WIDTH_5; +using ::WIFI_CHAN_WIDTH_80; +using ::WIFI_CHAN_WIDTH_80P80; +using ::WIFI_CHAN_WIDTH_INVALID; +using ::wifi_channel_info; +using ::wifi_channel_stat; +using ::wifi_channel_width; +using ::wifi_coex_restriction; +using ::wifi_coex_unsafe_channel; +using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED; +using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY; +using ::wifi_error; +using ::WIFI_ERROR_BUSY; +using ::WIFI_ERROR_INVALID_ARGS; +using ::WIFI_ERROR_INVALID_REQUEST_ID; +using ::WIFI_ERROR_NONE; +using ::WIFI_ERROR_NOT_AVAILABLE; +using ::WIFI_ERROR_NOT_SUPPORTED; +using ::WIFI_ERROR_OUT_OF_MEMORY; +using ::WIFI_ERROR_TIMED_OUT; +using ::WIFI_ERROR_TOO_MANY_REQUESTS; +using ::WIFI_ERROR_UNINITIALIZED; +using ::WIFI_ERROR_UNKNOWN; +using ::wifi_gscan_capabilities; +using ::wifi_hal_fn; +using ::wifi_information_element; +using ::WIFI_INTERFACE_IBSS; +using ::WIFI_INTERFACE_MESH; +using ::wifi_interface_mode; +using ::WIFI_INTERFACE_NAN; +using ::WIFI_INTERFACE_P2P_CLIENT; +using ::WIFI_INTERFACE_P2P_GO; +using ::WIFI_INTERFACE_SOFTAP; +using ::WIFI_INTERFACE_STA; +using ::WIFI_INTERFACE_TDLS; +using ::wifi_interface_type; +using ::WIFI_INTERFACE_TYPE_AP; +using ::WIFI_INTERFACE_TYPE_NAN; +using ::WIFI_INTERFACE_TYPE_P2P; +using ::WIFI_INTERFACE_TYPE_STA; +using ::WIFI_INTERFACE_UNKNOWN; +using ::wifi_latency_mode; +using ::WIFI_LATENCY_MODE_LOW; +using ::WIFI_LATENCY_MODE_NORMAL; +using ::wifi_lci_information; +using ::wifi_lcr_information; +using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED; +using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED; +using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED; +using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED; +using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED; +using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED; +using ::WIFI_MOTION_EXPECTED; +using ::WIFI_MOTION_NOT_EXPECTED; +using ::wifi_motion_pattern; +using ::WIFI_MOTION_UNKNOWN; +using ::wifi_multi_sta_use_case; +using ::wifi_power_scenario; +using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF; +using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON; +using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF; +using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON; +using ::WIFI_POWER_SCENARIO_VOICE_CALL; +using ::wifi_radio_combination; +using ::wifi_radio_combination_matrix; +using ::wifi_radio_configuration; +using ::wifi_rate; +using ::wifi_request_id; +using ::wifi_ring_buffer_status; +using ::wifi_roaming_capabilities; +using ::wifi_roaming_config; +using ::wifi_rtt_bw; +using ::WIFI_RTT_BW_10; +using ::WIFI_RTT_BW_160; +using ::WIFI_RTT_BW_20; +using ::WIFI_RTT_BW_320; +using ::WIFI_RTT_BW_40; +using ::WIFI_RTT_BW_5; +using ::WIFI_RTT_BW_80; +using ::wifi_rtt_capabilities; +using ::wifi_rtt_config; +using ::wifi_rtt_preamble; +using ::WIFI_RTT_PREAMBLE_EHT; +using ::WIFI_RTT_PREAMBLE_HE; +using ::WIFI_RTT_PREAMBLE_HT; +using ::WIFI_RTT_PREAMBLE_LEGACY; +using ::WIFI_RTT_PREAMBLE_VHT; +using ::wifi_rtt_responder; +using ::wifi_rtt_result; +using ::wifi_rtt_status; +using ::wifi_rtt_type; +using ::wifi_rx_packet_fate; +using ::wifi_rx_report; +using ::wifi_scan_bucket_spec; +using ::wifi_scan_cmd_params; +using ::WIFI_SCAN_FLAG_INTERRUPTED; +using ::wifi_scan_result; +using ::WIFI_SUCCESS; +using ::wifi_tx_packet_fate; +using ::wifi_tx_report; +using ::wifi_usable_channel; +using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE; +using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY; +using ::WLAN_MAC_2_4_BAND; +using ::WLAN_MAC_5_0_BAND; +using ::WLAN_MAC_60_0_BAND; +using ::WLAN_MAC_6_0_BAND; + +// APF capabilities supported by the iface. +struct PacketFilterCapabilities { + uint32_t version; + uint32_t max_len; +}; + +// WARNING: We don't care about the variable sized members of either +// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma +// to escape the compiler warnings regarding this. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end" +// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in +// |wifi_radio_stat| structure in the legacy HAL API. Separate that out +// into a separate return element to avoid passing pointers around. +struct LinkLayerRadioStats { + wifi_radio_stat stats; + std::vector tx_time_per_levels; + std::vector channel_stats; +}; + +struct WifiPeerInfo { + wifi_peer_info peer_info; + std::vector rate_stats; +}; + +struct LinkLayerStats { + wifi_iface_stat iface; + std::vector radios; + std::vector peers; +}; +#pragma GCC diagnostic pop + +// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and +// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided +// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL +// API. Separate that out into a separate return elements to avoid passing +// pointers around. +struct WakeReasonStats { + WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt; + std::vector cmd_event_wake_cnt; + std::vector driver_fw_local_wake_cnt; +}; + +// NAN response and event callbacks struct. +struct NanCallbackHandlers { + // NotifyResponse invoked to notify the status of the Request. + std::function on_notify_response; + // Various event callbacks. + std::function on_event_publish_terminated; + std::function on_event_match; + std::function on_event_match_expired; + std::function on_event_subscribe_terminated; + std::function on_event_followup; + std::function on_event_disc_eng_event; + std::function on_event_disabled; + std::function on_event_tca; + std::function on_event_beacon_sdf_payload; + std::function on_event_data_path_request; + std::function on_event_data_path_confirm; + std::function on_event_data_path_end; + std::function on_event_transmit_follow_up; + std::function on_event_range_request; + std::function on_event_range_report; + std::function on_event_schedule_update; +}; + +// Full scan results contain IE info and are hence passed by reference, to +// preserve the variable length array member |ie_data|. Callee must not retain +// the pointer. +using on_gscan_full_result_callback = + std::function; +// These scan results don't contain any IE info, so no need to pass by +// reference. +using on_gscan_results_callback = + std::function&)>; + +// Invoked when the rssi value breaches the thresholds set. +using on_rssi_threshold_breached_callback = + std::function, int8_t)>; + +// Callback for RTT range request results. +// Rtt results contain IE info and are hence passed by reference, to +// preserve the |LCI| and |LCR| pointers. Callee must not retain +// the pointer. +using on_rtt_results_callback = + std::function&)>; + +// Callback for ring buffer data. +using on_ring_buffer_data_callback = std::function&, const wifi_ring_buffer_status&)>; + +// Callback for alerts. +using on_error_alert_callback = std::function&)>; + +// Callback for subsystem restart +using on_subsystem_restart_callback = std::function; + +// Struct for the mac info from the legacy HAL. This is a cleaner version +// of the |wifi_mac_info| & |wifi_iface_info|. +typedef struct { + std::string name; + wifi_channel channel; +} WifiIfaceInfo; + +typedef struct { + uint32_t wlan_mac_id; + /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */ + uint32_t mac_band; + /* Represents the connected Wi-Fi interfaces associated with each MAC */ + std::vector iface_infos; +} WifiMacInfo; + +// Callback for radio mode change +using on_radio_mode_change_callback = std::function&)>; + +// TWT response and event callbacks struct. +struct TwtCallbackHandlers { + // Callback for TWT setup response + std::function on_setup_response; + // Callback for TWT teardown completion + std::function on_teardown_completion; + // Callback for TWT info frame received event + std::function on_info_frame_received; + // Callback for TWT notification from the device + std::function on_device_notify; +}; + +// CHRE response and event callbacks struct. +struct ChreCallbackHandlers { + // Callback for CHRE NAN RTT + std::function on_wifi_chre_nan_rtt_state; +}; + +// Cached Scan Results response and event callbacks struct. +struct CachedScanResultsCallbackHandlers { + // Callback for Cached Scan Results + std::function on_cached_scan_results; +}; + +/** + * Class that encapsulates all legacy HAL interactions. + * This class manages the lifetime of the event loop thread used by legacy HAL. + * + * Note: There will only be a single instance of this class created in the Wifi + * object and will be valid for the lifetime of the process. + */ +class WifiLegacyHal { + public: + WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool, + const wifi_hal_fn& fn, bool is_primary); + virtual ~WifiLegacyHal() = default; + + // Initialize the legacy HAL function table. + virtual wifi_error initialize(); + // Start the legacy HAL and the event looper thread. + virtual wifi_error start(); + // Deinitialize the legacy HAL and wait for the event loop thread to exit + // using a predefined timeout. + virtual wifi_error stop(std::unique_lock* lock, + const std::function& on_complete_callback); + virtual wifi_error waitForDriverReady(); + // Checks if legacy HAL has successfully started + bool isStarted(); + // Wrappers for all the functions in the legacy HAL function table. + virtual std::pair getDriverVersion(const std::string& iface_name); + virtual std::pair getFirmwareVersion(const std::string& iface_name); + std::pair> requestDriverMemoryDump( + const std::string& iface_name); + std::pair> requestFirmwareMemoryDump( + const std::string& iface_name); + virtual std::pair getSupportedFeatureSet(const std::string& iface_name); + // APF functions. + std::pair getPacketFilterCapabilities( + const std::string& iface_name); + wifi_error setPacketFilter(const std::string& iface_name, const std::vector& program); + std::pair> readApfPacketFilterData( + const std::string& iface_name); + // Gscan functions. + std::pair getGscanCapabilities( + const std::string& iface_name); + // These API's provides a simplified interface over the legacy Gscan API's: + // a) All scan events from the legacy HAL API other than the + // |WIFI_SCAN_FAILED| are treated as notification of results. + // This method then retrieves the cached scan results from the legacy + // HAL API and triggers the externally provided + // |on_results_user_callback| on success. + // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan + // results + // Triggers the externally provided |on_failure_user_callback|. + // c) Full scan result event triggers the externally provided + // |on_full_result_user_callback|. + wifi_error startGscan(const std::string& iface_name, wifi_request_id id, + const wifi_scan_cmd_params& params, + const std::function& on_failure_callback, + const on_gscan_results_callback& on_results_callback, + const on_gscan_full_result_callback& on_full_result_callback); + wifi_error stopGscan(const std::string& iface_name, wifi_request_id id); + std::pair> getValidFrequenciesForBand( + const std::string& iface_name, wifi_band band); + virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on); + // Link layer stats functions. + wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug); + wifi_error disableLinkLayerStats(const std::string& iface_name); + std::pair getLinkLayerStats(const std::string& iface_name); + // RSSI monitor functions. + wifi_error startRssiMonitoring( + const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi, + const on_rssi_threshold_breached_callback& on_threshold_breached_callback); + wifi_error stopRssiMonitoring(const std::string& iface_name, wifi_request_id id); + std::pair getRoamingCapabilities( + const std::string& iface_name); + wifi_error configureRoaming(const std::string& iface_name, const wifi_roaming_config& config); + wifi_error enableFirmwareRoaming(const std::string& iface_name, fw_roaming_state_t state); + wifi_error configureNdOffload(const std::string& iface_name, bool enable); + wifi_error startSendingOffloadedPacket(const std::string& iface_name, int32_t cmd_id, + uint16_t ether_type, + const std::vector& ip_packet_data, + const std::array& src_address, + const std::array& dst_address, + int32_t period_in_ms); + wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id); + virtual wifi_error selectTxPowerScenario(const std::string& iface_name, + wifi_power_scenario scenario); + virtual wifi_error resetTxPowerScenario(const std::string& iface_name); + wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode); + wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window); + wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end, + uint32_t access_category); + wifi_error resetDscpToAccessCategoryMapping(); + // Logger/debug functions. + std::pair getLoggerSupportedFeatureSet(const std::string& iface_name); + wifi_error startPktFateMonitoring(const std::string& iface_name); + std::pair> getTxPktFates(const std::string& iface_name); + std::pair> getRxPktFates(const std::string& iface_name); + std::pair getWakeReasonStats(const std::string& iface_name); + wifi_error registerRingBufferCallbackHandler( + const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback); + wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name); + virtual wifi_error registerSubsystemRestartCallbackHandler( + const on_subsystem_restart_callback& on_restart_callback); + std::pair> getRingBuffersStatus( + const std::string& iface_name); + wifi_error startRingBufferLogging(const std::string& iface_name, const std::string& ring_name, + uint32_t verbose_level, uint32_t max_interval_sec, + uint32_t min_data_size); + wifi_error getRingBufferData(const std::string& iface_name, const std::string& ring_name); + wifi_error registerErrorAlertCallbackHandler(const std::string& iface_name, + const on_error_alert_callback& on_alert_callback); + wifi_error deregisterErrorAlertCallbackHandler(const std::string& iface_name); + // Radio mode functions. + virtual wifi_error registerRadioModeChangeCallbackHandler( + const std::string& iface_name, + const on_radio_mode_change_callback& on_user_change_callback); + // RTT functions. + wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id, + const std::vector& rtt_configs, + const on_rtt_results_callback& on_results_callback); + wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id, + const std::vector>& mac_addrs); + std::pair getRttCapabilities(const std::string& iface_name); + std::pair getRttResponderInfo(const std::string& iface_name); + wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id, + const wifi_channel_info& channel_hint, uint32_t max_duration_secs, + const wifi_rtt_responder& info); + wifi_error disableRttResponder(const std::string& iface_name, wifi_request_id id); + wifi_error setRttLci(const std::string& iface_name, wifi_request_id id, + const wifi_lci_information& info); + wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id, + const wifi_lcr_information& info); + // NAN functions. + virtual wifi_error nanRegisterCallbackHandlers(const std::string& iface_name, + const NanCallbackHandlers& callbacks); + wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id, + const NanEnableRequest& msg); + virtual wifi_error nanDisableRequest(const std::string& iface_name, transaction_id id); + wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id, + const NanPublishRequest& msg); + wifi_error nanPublishCancelRequest(const std::string& iface_name, transaction_id id, + const NanPublishCancelRequest& msg); + wifi_error nanSubscribeRequest(const std::string& iface_name, transaction_id id, + const NanSubscribeRequest& msg); + wifi_error nanSubscribeCancelRequest(const std::string& iface_name, transaction_id id, + const NanSubscribeCancelRequest& msg); + wifi_error nanTransmitFollowupRequest(const std::string& iface_name, transaction_id id, + const NanTransmitFollowupRequest& msg); + wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id, + const NanStatsRequest& msg); + wifi_error nanConfigRequest(const std::string& iface_name, transaction_id id, + const NanConfigRequest& msg); + wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id, + const NanTCARequest& msg); + wifi_error nanBeaconSdfPayloadRequest(const std::string& iface_name, transaction_id id, + const NanBeaconSdfPayloadRequest& msg); + std::pair nanGetVersion(); + wifi_error nanGetCapabilities(const std::string& iface_name, transaction_id id); + wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id, + const std::string& data_iface_name); + virtual wifi_error nanDataInterfaceDelete(const std::string& iface_name, transaction_id id, + const std::string& data_iface_name); + wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id, + const NanDataPathInitiatorRequest& msg); + wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id, + const NanDataPathIndicationResponse& msg); + wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId); + // AP functions. + wifi_error setCountryCode(const std::string& iface_name, const std::array code); + + // Interface functions. + virtual wifi_error createVirtualInterface(const std::string& ifname, + wifi_interface_type iftype); + virtual wifi_error deleteVirtualInterface(const std::string& ifname); + virtual wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname); + + // STA + STA functions + virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname); + virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case); + + // Coex functions. + virtual wifi_error setCoexUnsafeChannels(std::vector unsafe_channels, + uint32_t restrictions); + + wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode); + + wifi_error twtRegisterHandler(const std::string& iface_name, + const TwtCallbackHandlers& handler); + + std::pair twtGetCapability(const std::string& iface_name); + + wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg); + + wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg); + + wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg); + + std::pair twtGetStats(const std::string& iface_name, uint8_t configId); + + wifi_error twtClearStats(const std::string& iface_name, uint8_t configId); + + wifi_error setDtimConfig(const std::string& iface_name, uint32_t multiplier); + + // Retrieve the list of usable channels in the requested bands + // for the requested modes + std::pair> getUsableChannels( + uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask); + + wifi_error triggerSubsystemRestart(); + + wifi_error setIndoorState(bool isIndoor); + + std::pair getSupportedRadioCombinationsMatrix(); + + // CHRE NAN RTT function + wifi_error chreNanRttRequest(const std::string& iface_name, bool enable); + + wifi_error chreRegisterHandler(const std::string& iface_name, + const ChreCallbackHandlers& handler); + + wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable); + wifi_error getWifiCachedScanResults(const std::string& iface_name, + const CachedScanResultsCallbackHandlers& handler); + + private: + // Retrieve interface handles for all the available interfaces. + wifi_error retrieveIfaceHandles(); + wifi_interface_handle getIfaceHandle(const std::string& iface_name); + // Run the legacy HAL event loop thread. + void runEventLoop(); + // Retrieve the cached gscan results to pass the results back to the + // external callbacks. + std::pair> getGscanCachedResults( + const std::string& iface_name); + void invalidate(); + // Handles wifi (error) status of Virtual interface create/delete + wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname, + wifi_error status); + + // Global function table of legacy HAL. + wifi_hal_fn global_func_table_; + // Opaque handle to be used for all global operations. + wifi_handle global_handle_; + // Map of interface name to handle that is to be used for all interface + // specific operations. + std::map iface_name_to_handle_; + // Flag to indicate if we have initiated the cleanup of legacy HAL. + std::atomic awaiting_event_loop_termination_; + std::condition_variable_any stop_wait_cv_; + // Flag to indicate if the legacy HAL has been started. + bool is_started_; + std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_; + // Flag to indicate if this HAL is for the primary chip. This is used + // in order to avoid some hard-coded behavior used with older HALs, + // such as bring wlan0 interface up/down on start/stop HAL. + // it may be removed once vendor HALs are updated. + bool is_primary_; +}; + +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_LEGACY_HAL_H_ diff --git a/wifi/aidl/default/wifi_legacy_hal_factory.cpp b/wifi/aidl/default/wifi_legacy_hal_factory.cpp new file mode 100644 index 0000000000..60f81ed764 --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal_factory.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2022 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 "wifi_legacy_hal_factory.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_legacy_hal_stubs.h" + +namespace { +static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals"; +static constexpr char kVendorHalsDescExt[] = ".xml"; +static constexpr uint32_t kVendorHalsDescVersion = 1; + +bool isDirectory(struct dirent* entryPtr) { + bool isDir = false; + if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) { + isDir = (entryPtr->d_type == DT_DIR); + } else { + struct stat entryStat; + stat(entryPtr->d_name, &entryStat); + isDir = S_ISDIR(entryStat.st_mode); + } + return isDir; +} + +bool isFileExtension(const char* name, const char* ext) { + if (name == NULL) return false; + if (ext == NULL) return false; + + size_t extLen = strlen(ext); + size_t nameLen = strlen(name); + + if (extLen > nameLen) return false; + + if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false; + + return true; +} +}; // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { + +WifiLegacyHalFactory::WifiLegacyHalFactory( + const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool) + : iface_tool_(iface_tool) {} + +std::vector> WifiLegacyHalFactory::getHals() { + if (legacy_hals_.empty()) { + if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList(); + for (auto& desc : descs_) { + std::shared_ptr hal = + std::make_shared(iface_tool_, desc.fn, desc.primary); + legacy_hals_.push_back(hal); + } + } + + return legacy_hals_; +} + +bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() { + wifi_hal_lib_desc desc; + + if (!initLinkedHalFunctionTable(&desc.fn)) return false; + + desc.primary = true; + desc.handle = NULL; + descs_.push_back(desc); + return true; +} + +bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) { + init_wifi_vendor_hal_func_table_t initfn; + + initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT, + "init_wifi_vendor_hal_func_table"); + if (!initfn) { + LOG(INFO) << "no vendor HAL library linked, will try dynamic load"; + return false; + } + + if (!initHalFuncTableWithStubs(hal_fn)) { + LOG(ERROR) << "Can not initialize the basic function pointer table"; + return false; + } + + if (initfn(hal_fn) != WIFI_SUCCESS) { + LOG(ERROR) << "Can not initialize the vendor function pointer table"; + return false; + } + + return true; +} + +/* + * Overall structure of the HAL descriptor XML schema + * + * + * + * /vendor/lib64/libwifi-hal-qcom.so + * 1 + * + */ +void WifiLegacyHalFactory::initVendorHalsDescriptorList() { + xmlDocPtr xml; + xmlNodePtr node, cnode; + char* version; + std::string path; + xmlChar* value; + wifi_hal_lib_desc desc; + + LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath; + DIR* dirPtr = ::opendir(kVendorHalsDescPath); + if (dirPtr == NULL) { + LOG(ERROR) << "failed to open " << kVendorHalsDescPath; + return; + } + for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL; + entryPtr = ::readdir(dirPtr)) { + if (isDirectory(entryPtr)) continue; + + if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt)) + continue; // only process .xml files + + LOG(INFO) << "processing config file: " << entryPtr->d_name; + + std::string fullPath(kVendorHalsDescPath); + fullPath.append("/"); + fullPath.append(entryPtr->d_name); + xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER); + if (!xml) { + LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping..."; + continue; + } + node = xmlDocGetRootElement(xml); + if (!node) { + LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping..."; + goto skip; + } + if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) { + LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name + << " skipping..."; + goto skip; + } + version = (char*)xmlGetProp(node, BAD_CAST "version"); + if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) { + LOG(ERROR) << "conf file: " << entryPtr->d_name + << "must have version: " << kVendorHalsDescVersion << ", skipping..."; + goto skip; + } + cnode = node->children; + path.clear(); + desc.primary = false; + while (cnode) { + if (!xmlStrcmp(cnode->name, BAD_CAST "path")) { + value = xmlNodeListGetString(xml, cnode->children, 1); + if (value) path = (char*)value; + xmlFree(value); + } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) { + value = xmlNodeListGetString(xml, cnode->children, 1); + desc.primary = !xmlStrcmp(value, BAD_CAST "1"); + xmlFree(value); + } + cnode = cnode->next; + } + if (path.empty()) { + LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name + << ", skipping..."; + goto skip; + } + if (loadVendorHalLib(path, desc)) { + if (desc.primary) + descs_.insert(descs_.begin(), desc); + else + descs_.push_back(desc); + } + skip: + xmlFreeDoc(xml); + } + ::closedir(dirPtr); +} + +bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) { + void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + init_wifi_vendor_hal_func_table_t initfn; + wifi_error res; + + if (!h) { + LOG(ERROR) << "failed to open vendor hal library: " << path; + return false; + } + initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table"); + if (!initfn) { + LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path; + goto out_err; + } + + if (!initHalFuncTableWithStubs(&desc.fn)) { + LOG(ERROR) << "Can not initialize the basic function pointer table"; + goto out_err; + } + res = initfn(&desc.fn); + if (res != WIFI_SUCCESS) { + LOG(ERROR) << "failed to initialize the vendor func table in: " << path + << " error: " << res; + goto out_err; + } + + res = desc.fn.wifi_early_initialize(); + // vendor HALs which do not implement early_initialize will return + // WIFI_ERROR_NOT_SUPPORTED, treat this as success. + if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) { + LOG(ERROR) << "early initialization failed in: " << path << " error: " << res; + goto out_err; + } + + desc.handle = h; + return true; +out_err: + dlclose(h); + return false; +} + +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_legacy_hal_factory.h b/wifi/aidl/default/wifi_legacy_hal_factory.h new file mode 100644 index 0000000000..e7b287a6f5 --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal_factory.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_LEGACY_HAL_FACTORY_H_ +#define WIFI_LEGACY_HAL_FACTORY_H_ + +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +// This is in a separate namespace to prevent typename conflicts between +// the legacy HAL types and the AIDL interface types. +namespace legacy_hal { +/** + * Class that creates WifiLegacyHal objects for vendor HALs in the system. + */ +class WifiLegacyHalFactory { + public: + WifiLegacyHalFactory(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool); + virtual ~WifiLegacyHalFactory() = default; + + std::vector> getHals(); + + private: + typedef struct { + wifi_hal_fn fn; + bool primary; + void* handle; + } wifi_hal_lib_desc; + + bool initVendorHalDescriptorFromLinked(); + void initVendorHalsDescriptorList(); + bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn); + bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc); + + std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_; + std::vector descs_; + std::vector> legacy_hals_; +}; + +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_LEGACY_HAL_FACTORY_H_ diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp new file mode 100644 index 0000000000..cff7f6977b --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2022 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 "wifi_legacy_hal_stubs.h" + +// TODO: Remove these stubs from HalTool in libwifi-system. +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { +template +struct stubFunction; + +template +struct stubFunction { + static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; } +}; +template +struct stubFunction { + static constexpr void invoke(Args...) {} +}; + +template +void populateStubFor(T* val) { + *val = &stubFunction::invoke; +} + +bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) { + if (hal_fn == nullptr) { + return false; + } + populateStubFor(&hal_fn->wifi_initialize); + populateStubFor(&hal_fn->wifi_wait_for_driver_ready); + populateStubFor(&hal_fn->wifi_cleanup); + populateStubFor(&hal_fn->wifi_event_loop); + populateStubFor(&hal_fn->wifi_get_error_info); + populateStubFor(&hal_fn->wifi_get_supported_feature_set); + populateStubFor(&hal_fn->wifi_get_concurrency_matrix); + populateStubFor(&hal_fn->wifi_set_scanning_mac_oui); + populateStubFor(&hal_fn->wifi_get_supported_channels); + populateStubFor(&hal_fn->wifi_is_epr_supported); + populateStubFor(&hal_fn->wifi_get_ifaces); + populateStubFor(&hal_fn->wifi_get_iface_name); + populateStubFor(&hal_fn->wifi_set_iface_event_handler); + populateStubFor(&hal_fn->wifi_reset_iface_event_handler); + populateStubFor(&hal_fn->wifi_start_gscan); + populateStubFor(&hal_fn->wifi_stop_gscan); + populateStubFor(&hal_fn->wifi_get_cached_gscan_results); + populateStubFor(&hal_fn->wifi_set_bssid_hotlist); + populateStubFor(&hal_fn->wifi_reset_bssid_hotlist); + populateStubFor(&hal_fn->wifi_set_significant_change_handler); + populateStubFor(&hal_fn->wifi_reset_significant_change_handler); + populateStubFor(&hal_fn->wifi_get_gscan_capabilities); + populateStubFor(&hal_fn->wifi_set_link_stats); + populateStubFor(&hal_fn->wifi_get_link_stats); + populateStubFor(&hal_fn->wifi_clear_link_stats); + populateStubFor(&hal_fn->wifi_get_valid_channels); + populateStubFor(&hal_fn->wifi_rtt_range_request); + populateStubFor(&hal_fn->wifi_rtt_range_cancel); + populateStubFor(&hal_fn->wifi_get_rtt_capabilities); + populateStubFor(&hal_fn->wifi_rtt_get_responder_info); + populateStubFor(&hal_fn->wifi_enable_responder); + populateStubFor(&hal_fn->wifi_disable_responder); + populateStubFor(&hal_fn->wifi_set_nodfs_flag); + populateStubFor(&hal_fn->wifi_start_logging); + populateStubFor(&hal_fn->wifi_set_epno_list); + populateStubFor(&hal_fn->wifi_reset_epno_list); + populateStubFor(&hal_fn->wifi_set_country_code); + populateStubFor(&hal_fn->wifi_get_firmware_memory_dump); + populateStubFor(&hal_fn->wifi_set_log_handler); + populateStubFor(&hal_fn->wifi_reset_log_handler); + populateStubFor(&hal_fn->wifi_set_alert_handler); + populateStubFor(&hal_fn->wifi_reset_alert_handler); + populateStubFor(&hal_fn->wifi_get_firmware_version); + populateStubFor(&hal_fn->wifi_get_ring_buffers_status); + populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set); + populateStubFor(&hal_fn->wifi_get_ring_data); + populateStubFor(&hal_fn->wifi_enable_tdls); + populateStubFor(&hal_fn->wifi_disable_tdls); + populateStubFor(&hal_fn->wifi_get_tdls_status); + populateStubFor(&hal_fn->wifi_get_tdls_capabilities); + populateStubFor(&hal_fn->wifi_get_driver_version); + populateStubFor(&hal_fn->wifi_set_passpoint_list); + populateStubFor(&hal_fn->wifi_reset_passpoint_list); + populateStubFor(&hal_fn->wifi_set_lci); + populateStubFor(&hal_fn->wifi_set_lcr); + populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet); + populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet); + populateStubFor(&hal_fn->wifi_start_rssi_monitoring); + populateStubFor(&hal_fn->wifi_stop_rssi_monitoring); + populateStubFor(&hal_fn->wifi_get_wake_reason_stats); + populateStubFor(&hal_fn->wifi_configure_nd_offload); + populateStubFor(&hal_fn->wifi_get_driver_memory_dump); + populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring); + populateStubFor(&hal_fn->wifi_get_tx_pkt_fates); + populateStubFor(&hal_fn->wifi_get_rx_pkt_fates); + populateStubFor(&hal_fn->wifi_nan_enable_request); + populateStubFor(&hal_fn->wifi_nan_disable_request); + populateStubFor(&hal_fn->wifi_nan_publish_request); + populateStubFor(&hal_fn->wifi_nan_publish_cancel_request); + populateStubFor(&hal_fn->wifi_nan_subscribe_request); + populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request); + populateStubFor(&hal_fn->wifi_nan_transmit_followup_request); + populateStubFor(&hal_fn->wifi_nan_stats_request); + populateStubFor(&hal_fn->wifi_nan_config_request); + populateStubFor(&hal_fn->wifi_nan_tca_request); + populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request); + populateStubFor(&hal_fn->wifi_nan_register_handler); + populateStubFor(&hal_fn->wifi_nan_get_version); + populateStubFor(&hal_fn->wifi_nan_get_capabilities); + populateStubFor(&hal_fn->wifi_nan_data_interface_create); + populateStubFor(&hal_fn->wifi_nan_data_interface_delete); + populateStubFor(&hal_fn->wifi_nan_data_request_initiator); + populateStubFor(&hal_fn->wifi_nan_data_indication_response); + populateStubFor(&hal_fn->wifi_nan_data_end); + populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities); + populateStubFor(&hal_fn->wifi_set_packet_filter); + populateStubFor(&hal_fn->wifi_read_packet_filter); + populateStubFor(&hal_fn->wifi_get_roaming_capabilities); + populateStubFor(&hal_fn->wifi_enable_firmware_roaming); + populateStubFor(&hal_fn->wifi_configure_roaming); + populateStubFor(&hal_fn->wifi_select_tx_power_scenario); + populateStubFor(&hal_fn->wifi_reset_tx_power_scenario); + populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler); + populateStubFor(&hal_fn->wifi_set_latency_mode); + populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode); + populateStubFor(&hal_fn->wifi_virtual_interface_create); + populateStubFor(&hal_fn->wifi_virtual_interface_delete); + populateStubFor(&hal_fn->wifi_map_dscp_access_category); + populateStubFor(&hal_fn->wifi_reset_dscp_mapping); + populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler); + populateStubFor(&hal_fn->wifi_get_supported_iface_name); + populateStubFor(&hal_fn->wifi_early_initialize); + populateStubFor(&hal_fn->wifi_get_chip_feature_set); + populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection); + populateStubFor(&hal_fn->wifi_multi_sta_set_use_case); + populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels); + populateStubFor(&hal_fn->wifi_set_voip_mode); + populateStubFor(&hal_fn->wifi_twt_register_handler); + populateStubFor(&hal_fn->wifi_twt_get_capability); + populateStubFor(&hal_fn->wifi_twt_setup_request); + populateStubFor(&hal_fn->wifi_twt_teardown_request); + populateStubFor(&hal_fn->wifi_twt_info_frame_request); + populateStubFor(&hal_fn->wifi_twt_get_stats); + populateStubFor(&hal_fn->wifi_twt_clear_stats); + populateStubFor(&hal_fn->wifi_set_dtim_config); + populateStubFor(&hal_fn->wifi_get_usable_channels); + populateStubFor(&hal_fn->wifi_trigger_subsystem_restart); + populateStubFor(&hal_fn->wifi_set_indoor_state); + populateStubFor(&hal_fn->wifi_get_supported_radio_combinations_matrix); + populateStubFor(&hal_fn->wifi_nan_rtt_chre_enable_request); + populateStubFor(&hal_fn->wifi_nan_rtt_chre_disable_request); + populateStubFor(&hal_fn->wifi_chre_register_handler); + populateStubFor(&hal_fn->wifi_enable_tx_power_limits); + populateStubFor(&hal_fn->wifi_get_cached_scan_results); + return true; +} + +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.h b/wifi/aidl/default/wifi_legacy_hal_stubs.h new file mode 100644 index 0000000000..603ecf2eae --- /dev/null +++ b/wifi/aidl/default/wifi_legacy_hal_stubs.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_LEGACY_HAL_STUBS_H_ +#define WIFI_LEGACY_HAL_STUBS_H_ + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace legacy_hal { + +bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn); +} // namespace legacy_hal +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_LEGACY_HAL_STUBS_H_ diff --git a/wifi/aidl/default/wifi_mode_controller.cpp b/wifi/aidl/default/wifi_mode_controller.cpp new file mode 100644 index 0000000000..07cb072363 --- /dev/null +++ b/wifi/aidl/default/wifi_mode_controller.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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 "wifi_mode_controller.h" + +#include +#include +#include + +namespace { +using aidl::android::hardware::wifi::IfaceType; +using android::wifi_hal::DriverTool; + +int convertIfaceTypeToFirmwareMode(IfaceType type) { + int mode; + switch (type) { + case IfaceType::AP: + mode = DriverTool::kFirmwareModeAp; + break; + case IfaceType::P2P: + mode = DriverTool::kFirmwareModeP2p; + break; + case IfaceType::NAN_IFACE: + // NAN is exposed in STA mode currently. + mode = DriverTool::kFirmwareModeSta; + break; + case IfaceType::STA: + mode = DriverTool::kFirmwareModeSta; + break; + } + return mode; +} +} // namespace + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace mode_controller { + +WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {} + +bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) { + return driver_tool_->IsFirmwareModeChangeNeeded(convertIfaceTypeToFirmwareMode(type)); +} + +bool WifiModeController::initialize() { + if (!driver_tool_->LoadDriver()) { + LOG(ERROR) << "Failed to load WiFi driver"; + return false; + } + return true; +} + +bool WifiModeController::changeFirmwareMode(IfaceType type) { + if (!driver_tool_->ChangeFirmwareMode(convertIfaceTypeToFirmwareMode(type))) { + LOG(ERROR) << "Failed to change firmware mode"; + return false; + } + return true; +} + +bool WifiModeController::deinitialize() { + if (!driver_tool_->UnloadDriver()) { + LOG(ERROR) << "Failed to unload WiFi driver"; + return false; + } + return true; +} + +} // namespace mode_controller +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_mode_controller.h b/wifi/aidl/default/wifi_mode_controller.h new file mode 100644 index 0000000000..1a9fb1a498 --- /dev/null +++ b/wifi/aidl/default/wifi_mode_controller.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_MODE_CONTROLLER_H_ +#define WIFI_MODE_CONTROLLER_H_ + +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +namespace mode_controller { + +/** + * Class that encapsulates all firmware mode configuration. + * This class will perform the necessary firmware reloads to put the chip in the + * required state (essentially a wrapper over DriverTool). + */ +class WifiModeController { + public: + WifiModeController(); + virtual ~WifiModeController() = default; + + // Checks if a firmware mode change is necessary to support the specified + // iface type operations. + virtual bool isFirmwareModeChangeNeeded(IfaceType type); + virtual bool initialize(); + // Change the firmware mode to support the specified iface type operations. + virtual bool changeFirmwareMode(IfaceType type); + // Unload the driver. This should be invoked whenever |IWifi.stop()| is + // invoked. + virtual bool deinitialize(); + + private: + std::unique_ptr<::android::wifi_hal::DriverTool> driver_tool_; +}; + +} // namespace mode_controller +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_MODE_CONTROLLER_H_ diff --git a/wifi/aidl/default/wifi_nan_iface.cpp b/wifi/aidl/default/wifi_nan_iface.cpp new file mode 100644 index 0000000000..9edef09b7b --- /dev/null +++ b/wifi/aidl/default/wifi_nan_iface.cpp @@ -0,0 +1,751 @@ +/* + * Copyright (C) 2022 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 "wifi_nan_iface.h" + +#include + +#include "aidl_return_util.h" +#include "aidl_struct_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; + +WifiNanIface::WifiNanIface(const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) + : ifname_(ifname), + is_dedicated_iface_(is_dedicated_iface), + legacy_hal_(legacy_hal), + iface_util_(iface_util), + is_valid_(true) {} + +std::shared_ptr WifiNanIface::create( + const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) { + std::shared_ptr ptr = ndk::SharedRefBase::make( + ifname, is_dedicated_iface, legacy_hal, iface_util); + if (is_dedicated_iface) { + // If using a dedicated iface, set the iface up first. + if (!iface_util.lock()->setUpState(ifname, true)) { + // Fatal failure, invalidate the iface object. + ptr->invalidate(); + return nullptr; + } + } + std::weak_ptr weak_ptr_this(ptr); + ptr->setWeakPtr(weak_ptr_this); + ptr->registerCallbackHandlers(); + return ptr; +} + +void WifiNanIface::registerCallbackHandlers() { + // Register all the callbacks here. These should be valid for the lifetime + // of the object. Whenever the mode changes legacy HAL will remove + // all of these callbacks. + legacy_hal::NanCallbackHandlers callback_handlers; + std::weak_ptr weak_ptr_this = weak_ptr_this_; + + // Callback for response. + callback_handlers.on_notify_response = [weak_ptr_this](legacy_hal::transaction_id id, + const legacy_hal::NanResponseMsg& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanStatus nanStatus; + if (!aidl_struct_util::convertLegacyNanResponseHeaderToAidl(msg, &nanStatus)) { + LOG(ERROR) << "Failed to convert nan response header"; + return; + } + + switch (msg.response_type) { + case legacy_hal::NAN_RESPONSE_ENABLED: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyEnableResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_DISABLED: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyDisableResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_PUBLISH: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyStartPublishResponse(id, nanStatus, + msg.body.publish_response.publish_id) + .isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyStopPublishResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyTransmitFollowupResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_SUBSCRIBE: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyStartSubscribeResponse( + id, nanStatus, msg.body.subscribe_response.subscribe_id) + .isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyStopSubscribeResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_CONFIG: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyConfigResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_GET_CAPABILITIES: { + NanCapabilities aidl_struct; + if (!aidl_struct_util::convertLegacyNanCapabilitiesResponseToAidl( + msg.body.nan_capabilities, &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyCapabilitiesResponse(id, nanStatus, aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_DP_INTERFACE_CREATE: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyCreateDataInterfaceResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_DP_INTERFACE_DELETE: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyDeleteDataInterfaceResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_DP_INITIATOR_RESPONSE: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyInitiateDataPathResponse( + id, nanStatus, + msg.body.data_request_response.ndp_instance_id) + .isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_DP_RESPONDER_RESPONSE: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyRespondToDataPathIndicationResponse(id, nanStatus) + .isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_DP_END: { + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->notifyTerminateDataPathResponse(id, nanStatus).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + break; + } + case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD: + /* fall through */ + case legacy_hal::NAN_RESPONSE_TCA: + /* fall through */ + case legacy_hal::NAN_RESPONSE_STATS: + /* fall through */ + case legacy_hal::NAN_RESPONSE_ERROR: + /* fall through */ + default: + LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type; + return; + } + }; + + callback_handlers.on_event_disc_eng_event = [weak_ptr_this]( + const legacy_hal::NanDiscEngEventInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanClusterEventInd aidl_struct; + // event types defined identically - hence can be cast + aidl_struct.eventType = (NanClusterEventType)msg.event_type; + aidl_struct.addr = std::array(); + std::copy(msg.data.mac_addr.addr, msg.data.mac_addr.addr + 6, std::begin(aidl_struct.addr)); + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventClusterEvent(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_disabled = [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanStatus status; + aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason), + &status); + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventDisabled(status).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_publish_terminated = + [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanStatus status; + aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, + sizeof(msg.nan_reason), &status); + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_subscribe_terminated = + [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanStatus status; + aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, + sizeof(msg.nan_reason), &status); + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_match = [weak_ptr_this](const legacy_hal::NanMatchInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanMatchInd aidl_struct; + if (!aidl_struct_util::convertLegacyNanMatchIndToAidl(msg, &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventMatch(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_match_expired = [weak_ptr_this]( + const legacy_hal::NanMatchExpiredInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventMatchExpired(msg.publish_subscribe_id, msg.requestor_instance_id) + .isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_followup = [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanFollowupReceivedInd aidl_struct; + if (!aidl_struct_util::convertLegacyNanFollowupIndToAidl(msg, &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventFollowupReceived(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_transmit_follow_up = + [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanStatus status; + aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, + sizeof(msg.nan_reason), &status); + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventTransmitFollowup(msg.id, status).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_data_path_request = + [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanDataPathRequestInd aidl_struct; + if (!aidl_struct_util::convertLegacyNanDataPathRequestIndToAidl(msg, + &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventDataPathRequest(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_data_path_confirm = + [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanDataPathConfirmInd aidl_struct; + if (!aidl_struct_util::convertLegacyNanDataPathConfirmIndToAidl(msg, + &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventDataPathConfirm(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + callback_handlers.on_event_data_path_end = + [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + for (int i = 0; i < msg.num_ndp_instances; ++i) { + if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + } + }; + + callback_handlers.on_event_beacon_sdf_payload = + [](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) { + LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called"; + }; + + callback_handlers.on_event_range_request = [](const legacy_hal::NanRangeRequestInd& /* msg */) { + LOG(ERROR) << "on_event_range_request - should not be called"; + }; + + callback_handlers.on_event_range_report = [](const legacy_hal::NanRangeReportInd& /* msg */) { + LOG(ERROR) << "on_event_range_report - should not be called"; + }; + + callback_handlers.on_event_schedule_update = + [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& msg) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + NanDataPathScheduleUpdateInd aidl_struct; + if (!aidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToAidl( + msg, &aidl_struct)) { + LOG(ERROR) << "Failed to convert nan capabilities response"; + return; + } + + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventDataPathScheduleUpdate(aidl_struct).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_, callback_handlers); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to register nan callbacks. Invalidating object"; + invalidate(); + } + + // Register for iface state toggle events. + iface_util::IfaceEventHandlers event_handlers = {}; + event_handlers.on_state_toggle_off_on = [weak_ptr_this](const std::string& /* iface_name */) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + // Tell framework that NAN has been disabled. + NanStatus status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""}; + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->eventDisabled(status).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers); +} + +void WifiNanIface::setWeakPtr(std::weak_ptr ptr) { + weak_ptr_this_ = ptr; +} + +void WifiNanIface::invalidate() { + if (!isValid()) { + return; + } + // send commands to HAL to actually disable and destroy interfaces + legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF); + legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0"); + legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1"); + iface_util_.lock()->unregisterIfaceEventHandlers(ifname_); + legacy_hal_.reset(); + event_cb_handler_.invalidate(); + is_valid_ = false; + if (is_dedicated_iface_) { + // If using a dedicated iface, set the iface down. + iface_util_.lock()->setUpState(ifname_, false); + } +} + +bool WifiNanIface::isValid() { + return is_valid_; +} + +std::string WifiNanIface::getName() { + return ifname_; +} + +std::set> WifiNanIface::getEventCallbacks() { + LOG(ERROR) << "Using original getEventCallbacks"; + return event_cb_handler_.getCallbacks(); +} + +ndk::ScopedAStatus WifiNanIface::getName(std::string* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::getNameInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiNanIface::registerEventCallback( + const std::shared_ptr& callback) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::registerEventCallbackInternal, callback); +} + +ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequest(char16_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::getCapabilitiesRequestInternal, in_cmdId); +} + +ndk::ScopedAStatus WifiNanIface::enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1, + const NanConfigRequestSupplemental& in_msg2) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::enableRequestInternal, in_cmdId, in_msg1, in_msg2); +} + +ndk::ScopedAStatus WifiNanIface::configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1, + const NanConfigRequestSupplemental& in_msg2) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::configRequestInternal, in_cmdId, in_msg1, in_msg2); +} + +ndk::ScopedAStatus WifiNanIface::disableRequest(char16_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::disableRequestInternal, in_cmdId); +} + +ndk::ScopedAStatus WifiNanIface::startPublishRequest(char16_t in_cmdId, + const NanPublishRequest& in_msg) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::startPublishRequestInternal, in_cmdId, in_msg); +} + +ndk::ScopedAStatus WifiNanIface::stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::stopPublishRequestInternal, in_cmdId, in_sessionId); +} + +ndk::ScopedAStatus WifiNanIface::startSubscribeRequest(char16_t in_cmdId, + const NanSubscribeRequest& in_msg) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::startSubscribeRequestInternal, in_cmdId, in_msg); +} + +ndk::ScopedAStatus WifiNanIface::stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::stopSubscribeRequestInternal, in_cmdId, in_sessionId); +} + +ndk::ScopedAStatus WifiNanIface::transmitFollowupRequest(char16_t in_cmdId, + const NanTransmitFollowupRequest& in_msg) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::transmitFollowupRequestInternal, in_cmdId, in_msg); +} + +ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequest(char16_t in_cmdId, + const std::string& in_ifaceName) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::createDataInterfaceRequestInternal, in_cmdId, + in_ifaceName); +} + +ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequest(char16_t in_cmdId, + const std::string& in_ifaceName) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::deleteDataInterfaceRequestInternal, in_cmdId, + in_ifaceName); +} + +ndk::ScopedAStatus WifiNanIface::initiateDataPathRequest(char16_t in_cmdId, + const NanInitiateDataPathRequest& in_msg) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::initiateDataPathRequestInternal, in_cmdId, in_msg); +} + +ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequest( + char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::respondToDataPathIndicationRequestInternal, in_cmdId, + in_msg); +} + +ndk::ScopedAStatus WifiNanIface::terminateDataPathRequest(char16_t in_cmdId, + int32_t in_ndpInstanceId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiNanIface::terminateDataPathRequestInternal, in_cmdId, + in_ndpInstanceId); +} + +std::pair WifiNanIface::getNameInternal() { + return {ifname_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiNanIface::registerEventCallbackInternal( + const std::shared_ptr& callback) { + if (!event_cb_handler_.addCallback(callback)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequestInternal(char16_t cmd_id) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::enableRequestInternal(char16_t cmd_id, + const NanEnableRequest& msg1, + const NanConfigRequestSupplemental& msg2) { + legacy_hal::NanEnableRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanEnableRequestToLegacy(msg1, msg2, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::configRequestInternal(char16_t cmd_id, + const NanConfigRequest& msg1, + const NanConfigRequestSupplemental& msg2) { + legacy_hal::NanConfigRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanConfigRequestToLegacy(msg1, msg2, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::disableRequestInternal(char16_t cmd_id) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::startPublishRequestInternal(char16_t cmd_id, + const NanPublishRequest& msg) { + legacy_hal::NanPublishRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanPublishRequestToLegacy(msg, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId) { + legacy_hal::NanPublishCancelRequest legacy_msg; + legacy_msg.publish_id = sessionId; + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::startSubscribeRequestInternal(char16_t cmd_id, + const NanSubscribeRequest& msg) { + legacy_hal::NanSubscribeRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanSubscribeRequestToLegacy(msg, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId) { + legacy_hal::NanSubscribeCancelRequest legacy_msg; + legacy_msg.subscribe_id = sessionId; + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::transmitFollowupRequestInternal( + char16_t cmd_id, const NanTransmitFollowupRequest& msg) { + legacy_hal::NanTransmitFollowupRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequestInternal(char16_t cmd_id, + const std::string& iface_name) { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name); + return createWifiStatusFromLegacyError(legacy_status); +} +ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequestInternal(char16_t cmd_id, + const std::string& iface_name) { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name); + return createWifiStatusFromLegacyError(legacy_status); +} +ndk::ScopedAStatus WifiNanIface::initiateDataPathRequestInternal( + char16_t cmd_id, const NanInitiateDataPathRequest& msg) { + legacy_hal::NanDataPathInitiatorRequest legacy_msg; + if (!aidl_struct_util::convertAidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} +ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequestInternal( + char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) { + legacy_hal::NanDataPathIndicationResponse legacy_msg; + if (!aidl_struct_util::convertAidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg); + return createWifiStatusFromLegacyError(legacy_status); +} +ndk::ScopedAStatus WifiNanIface::terminateDataPathRequestInternal(char16_t cmd_id, + int32_t ndpInstanceId) { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId); + return createWifiStatusFromLegacyError(legacy_status); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_nan_iface.h b/wifi/aidl/default/wifi_nan_iface.h new file mode 100644 index 0000000000..101890594c --- /dev/null +++ b/wifi/aidl/default/wifi_nan_iface.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_NAN_IFACE_H_ +#define WIFI_NAN_IFACE_H_ + +#include +#include +#include + +#include "aidl_callback_util.h" +#include "wifi_iface_util.h" +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control a NAN Iface instance. + */ +class WifiNanIface : public BnWifiNanIface { + public: + WifiNanIface(const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); + + // Factory method - use instead of default constructor. + static std::shared_ptr create( + const std::string& ifname, bool is_dedicated_iface, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); + + // Refer to |WifiChip::invalidate()|. + void invalidate(); + bool isValid(); + std::string getName(); + + // AIDL methods exposed. + ndk::ScopedAStatus getName(std::string* _aidl_return) override; + ndk::ScopedAStatus registerEventCallback( + const std::shared_ptr& in_callback) override; + ndk::ScopedAStatus getCapabilitiesRequest(char16_t in_cmdId) override; + ndk::ScopedAStatus enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1, + const NanConfigRequestSupplemental& in_msg2) override; + ndk::ScopedAStatus configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1, + const NanConfigRequestSupplemental& in_msg2) override; + ndk::ScopedAStatus disableRequest(char16_t in_cmdId) override; + ndk::ScopedAStatus startPublishRequest(char16_t in_cmdId, + const NanPublishRequest& in_msg) override; + ndk::ScopedAStatus stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) override; + ndk::ScopedAStatus startSubscribeRequest(char16_t in_cmdId, + const NanSubscribeRequest& in_msg) override; + ndk::ScopedAStatus stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) override; + ndk::ScopedAStatus transmitFollowupRequest(char16_t in_cmdId, + const NanTransmitFollowupRequest& in_msg) override; + ndk::ScopedAStatus createDataInterfaceRequest(char16_t in_cmdId, + const std::string& in_ifaceName) override; + ndk::ScopedAStatus deleteDataInterfaceRequest(char16_t in_cmdId, + const std::string& in_ifaceName) override; + ndk::ScopedAStatus initiateDataPathRequest(char16_t in_cmdId, + const NanInitiateDataPathRequest& in_msg) override; + ndk::ScopedAStatus respondToDataPathIndicationRequest( + char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) override; + ndk::ScopedAStatus terminateDataPathRequest(char16_t in_cmdId, + int32_t in_ndpInstanceId) override; + + protected: + // Accessible to child class in the gTest suite. + void setWeakPtr(std::weak_ptr ptr); + void registerCallbackHandlers(); + + private: + // Corresponding worker functions for the AIDL methods. + std::pair getNameInternal(); + ndk::ScopedAStatus registerEventCallbackInternal( + const std::shared_ptr& callback); + ndk::ScopedAStatus getCapabilitiesRequestInternal(char16_t cmd_id); + ndk::ScopedAStatus enableRequestInternal(char16_t cmd_id, const NanEnableRequest& msg1, + const NanConfigRequestSupplemental& msg2); + ndk::ScopedAStatus configRequestInternal(char16_t cmd_id, const NanConfigRequest& msg1, + const NanConfigRequestSupplemental& msg2); + ndk::ScopedAStatus disableRequestInternal(char16_t cmd_id); + ndk::ScopedAStatus startPublishRequestInternal(char16_t cmd_id, const NanPublishRequest& msg); + ndk::ScopedAStatus stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId); + ndk::ScopedAStatus startSubscribeRequestInternal(char16_t cmd_id, + const NanSubscribeRequest& msg); + ndk::ScopedAStatus stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId); + ndk::ScopedAStatus transmitFollowupRequestInternal(char16_t cmd_id, + const NanTransmitFollowupRequest& msg); + ndk::ScopedAStatus createDataInterfaceRequestInternal(char16_t cmd_id, + const std::string& iface_name); + ndk::ScopedAStatus deleteDataInterfaceRequestInternal(char16_t cmd_id, + const std::string& iface_name); + ndk::ScopedAStatus initiateDataPathRequestInternal(char16_t cmd_id, + const NanInitiateDataPathRequest& msg); + ndk::ScopedAStatus respondToDataPathIndicationRequestInternal( + char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg); + ndk::ScopedAStatus terminateDataPathRequestInternal(char16_t cmd_id, int32_t ndpInstanceId); + + // Overridden in the gTest suite. + virtual std::set> getEventCallbacks(); + + std::string ifname_; + bool is_dedicated_iface_; + std::weak_ptr legacy_hal_; + std::weak_ptr iface_util_; + bool is_valid_; + std::weak_ptr weak_ptr_this_; + aidl_callback_util::AidlCallbackHandler event_cb_handler_; + + DISALLOW_COPY_AND_ASSIGN(WifiNanIface); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_NAN_IFACE_H_ diff --git a/wifi/aidl/default/wifi_p2p_iface.cpp b/wifi/aidl/default/wifi_p2p_iface.cpp new file mode 100644 index 0000000000..48ec6d6d87 --- /dev/null +++ b/wifi/aidl/default/wifi_p2p_iface.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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 "wifi_p2p_iface.h" + +#include + +#include "aidl_return_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; + +WifiP2pIface::WifiP2pIface(const std::string& ifname, + const std::weak_ptr legacy_hal) + : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {} + +void WifiP2pIface::invalidate() { + legacy_hal_.reset(); + is_valid_ = false; +} + +bool WifiP2pIface::isValid() { + return is_valid_; +} + +std::string WifiP2pIface::getName() { + return ifname_; +} + +ndk::ScopedAStatus WifiP2pIface::getName(std::string* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiP2pIface::getNameInternal, _aidl_return); +} + +std::pair WifiP2pIface::getNameInternal() { + return {ifname_, ndk::ScopedAStatus::ok()}; +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_p2p_iface.h b/wifi/aidl/default/wifi_p2p_iface.h new file mode 100644 index 0000000000..d17470ed23 --- /dev/null +++ b/wifi/aidl/default/wifi_p2p_iface.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_P2P_IFACE_H_ +#define WIFI_P2P_IFACE_H_ + +#include +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control a P2P Iface instance. + */ +class WifiP2pIface : public BnWifiP2pIface { + public: + WifiP2pIface(const std::string& ifname, + const std::weak_ptr legacy_hal); + // Refer to |WifiChip::invalidate()|. + void invalidate(); + bool isValid(); + std::string getName(); + + // AIDL methods exposed. + ndk::ScopedAStatus getName(std::string* _aidl_return) override; + + private: + // Corresponding worker functions for the AIDL methods. + std::pair getNameInternal(); + + std::string ifname_; + std::weak_ptr legacy_hal_; + bool is_valid_; + + DISALLOW_COPY_AND_ASSIGN(WifiP2pIface); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_P2P_IFACE_H_ diff --git a/wifi/aidl/default/wifi_rtt_controller.cpp b/wifi/aidl/default/wifi_rtt_controller.cpp new file mode 100644 index 0000000000..856c3cd054 --- /dev/null +++ b/wifi/aidl/default/wifi_rtt_controller.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2022 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 "wifi_rtt_controller.h" + +#include + +#include "aidl_return_util.h" +#include "aidl_struct_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; + +WifiRttController::WifiRttController(const std::string& iface_name, + const std::shared_ptr& bound_iface, + const std::weak_ptr legacy_hal) + : ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {} + +std::shared_ptr WifiRttController::create( + const std::string& iface_name, const std::shared_ptr& bound_iface, + const std::weak_ptr legacy_hal) { + std::shared_ptr ptr = + ndk::SharedRefBase::make(iface_name, bound_iface, legacy_hal); + std::weak_ptr weak_ptr_this(ptr); + ptr->setWeakPtr(weak_ptr_this); + return ptr; +} + +void WifiRttController::invalidate() { + legacy_hal_.reset(); + event_callbacks_.clear(); + is_valid_ = false; +}; + +bool WifiRttController::isValid() { + return is_valid_; +} + +void WifiRttController::setWeakPtr(std::weak_ptr ptr) { + weak_ptr_this_ = ptr; +} + +std::vector> +WifiRttController::getEventCallbacks() { + return event_callbacks_; +} + +std::string WifiRttController::getIfaceName() { + return ifname_; +} + +ndk::ScopedAStatus WifiRttController::getBoundIface(std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::getBoundIfaceInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiRttController::registerEventCallback( + const std::shared_ptr& callback) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::registerEventCallbackInternal, callback); +} + +ndk::ScopedAStatus WifiRttController::rangeRequest(int32_t in_cmdId, + const std::vector& in_rttConfigs) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::rangeRequestInternal, in_cmdId, in_rttConfigs); +} + +ndk::ScopedAStatus WifiRttController::rangeCancel(int32_t in_cmdId, + const std::vector& in_addrs) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::rangeCancelInternal, in_cmdId, in_addrs); +} + +ndk::ScopedAStatus WifiRttController::getCapabilities(RttCapabilities* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::getCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiRttController::setLci(int32_t in_cmdId, const RttLciInformation& in_lci) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::setLciInternal, in_cmdId, in_lci); +} + +ndk::ScopedAStatus WifiRttController::setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::setLcrInternal, in_cmdId, in_lcr); +} + +ndk::ScopedAStatus WifiRttController::getResponderInfo(RttResponder* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::getResponderInfoInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiRttController::enableResponder(int32_t in_cmdId, + const WifiChannelInfo& in_channelHint, + int32_t in_maxDurationInSeconds, + const RttResponder& in_info) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::enableResponderInternal, in_cmdId, in_channelHint, + in_maxDurationInSeconds, in_info); +} + +ndk::ScopedAStatus WifiRttController::disableResponder(int32_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + &WifiRttController::disableResponderInternal, in_cmdId); +} + +std::pair, ndk::ScopedAStatus> +WifiRttController::getBoundIfaceInternal() { + return {bound_iface_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiRttController::registerEventCallbackInternal( + const std::shared_ptr& callback) { + event_callbacks_.emplace_back(callback); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus WifiRttController::rangeRequestInternal( + int32_t cmd_id, const std::vector& rtt_configs) { + std::vector legacy_configs; + if (!aidl_struct_util::convertAidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_results_callback = + [weak_ptr_this](legacy_hal::wifi_request_id id, + const std::vector& results) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + std::vector aidl_results; + if (!aidl_struct_util::convertLegacyVectorOfRttResultToAidl(results, + &aidl_results)) { + LOG(ERROR) << "Failed to convert rtt results to AIDL structs"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onResults(id, aidl_results).isOk()) { + LOG(ERROR) << "Failed to invoke the callback"; + } + } + }; + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest( + ifname_, cmd_id, legacy_configs, on_results_callback); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiRttController::rangeCancelInternal(int32_t cmd_id, + const std::vector& addrs) { + std::vector> legacy_addrs; + for (const auto& addr : addrs) { + std::array addr_array; + std::copy_n(addr.data.begin(), ETH_ALEN, addr_array.begin()); + legacy_addrs.push_back(addr_array); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair WifiRttController::getCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_rtt_capabilities legacy_caps; + std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {RttCapabilities{}, createWifiStatusFromLegacyError(legacy_status)}; + } + RttCapabilities aidl_caps; + if (!aidl_struct_util::convertLegacyRttCapabilitiesToAidl(legacy_caps, &aidl_caps)) { + return {RttCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_caps, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiRttController::setLciInternal(int32_t cmd_id, const RttLciInformation& lci) { + legacy_hal::wifi_lci_information legacy_lci; + if (!aidl_struct_util::convertAidlRttLciInformationToLegacy(lci, &legacy_lci)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiRttController::setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr) { + legacy_hal::wifi_lcr_information legacy_lcr; + if (!aidl_struct_util::convertAidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair WifiRttController::getResponderInfoInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_rtt_responder legacy_responder; + std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {RttResponder{}, createWifiStatusFromLegacyError(legacy_status)}; + } + RttResponder aidl_responder; + if (!aidl_struct_util::convertLegacyRttResponderToAidl(legacy_responder, &aidl_responder)) { + return {RttResponder{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_responder, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiRttController::enableResponderInternal(int32_t cmd_id, + const WifiChannelInfo& channel_hint, + int32_t max_duration_seconds, + const RttResponder& info) { + legacy_hal::wifi_channel_info legacy_channel_info; + if (!aidl_struct_util::convertAidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_rtt_responder legacy_responder; + if (!aidl_struct_util::convertAidlRttResponderToLegacy(info, &legacy_responder)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder( + ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiRttController::disableResponderInternal(int32_t cmd_id) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_rtt_controller.h b/wifi/aidl/default/wifi_rtt_controller.h new file mode 100644 index 0000000000..db690c3ad3 --- /dev/null +++ b/wifi/aidl/default/wifi_rtt_controller.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_RTT_CONTROLLER_H_ +#define WIFI_RTT_CONTROLLER_H_ + +#include +#include +#include +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control all RTT operations. + */ +class WifiRttController : public BnWifiRttController { + public: + WifiRttController(const std::string& iface_name, + const std::shared_ptr& bound_iface, + const std::weak_ptr legacy_hal); + // Factory method - use instead of default constructor. + static std::shared_ptr create( + const std::string& iface_name, const std::shared_ptr& bound_iface, + const std::weak_ptr legacy_hal); + + // Refer to |WifiChip::invalidate()|. + void invalidate(); + bool isValid(); + std::vector> getEventCallbacks(); + std::string getIfaceName(); + + // AIDL methods exposed. + ndk::ScopedAStatus getBoundIface(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus registerEventCallback( + const std::shared_ptr& callback) override; + ndk::ScopedAStatus rangeRequest(int32_t in_cmdId, + const std::vector& in_rttConfigs) override; + ndk::ScopedAStatus rangeCancel(int32_t in_cmdId, + const std::vector& in_addrs) override; + ndk::ScopedAStatus getCapabilities(RttCapabilities* _aidl_return) override; + ndk::ScopedAStatus setLci(int32_t in_cmdId, const RttLciInformation& in_lci) override; + ndk::ScopedAStatus setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) override; + ndk::ScopedAStatus getResponderInfo(RttResponder* _aidl_return) override; + ndk::ScopedAStatus enableResponder(int32_t in_cmdId, const WifiChannelInfo& in_channelHint, + int32_t in_maxDurationInSeconds, + const RttResponder& in_info) override; + ndk::ScopedAStatus disableResponder(int32_t in_cmdId) override; + + private: + // Corresponding worker functions for the AIDL methods. + std::pair, ndk::ScopedAStatus> getBoundIfaceInternal(); + ndk::ScopedAStatus registerEventCallbackInternal( + const std::shared_ptr& callback); + ndk::ScopedAStatus rangeRequestInternal(int32_t cmd_id, + const std::vector& rtt_configs); + ndk::ScopedAStatus rangeCancelInternal(int32_t cmd_id, const std::vector& addrs); + std::pair getCapabilitiesInternal(); + ndk::ScopedAStatus setLciInternal(int32_t cmd_id, const RttLciInformation& lci); + ndk::ScopedAStatus setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr); + std::pair getResponderInfoInternal(); + ndk::ScopedAStatus enableResponderInternal(int32_t cmd_id, const WifiChannelInfo& channel_hint, + int32_t max_duration_seconds, + const RttResponder& info); + ndk::ScopedAStatus disableResponderInternal(int32_t cmd_id); + + void setWeakPtr(std::weak_ptr ptr); + + std::string ifname_; + std::shared_ptr bound_iface_; + std::weak_ptr legacy_hal_; + std::vector> event_callbacks_; + std::weak_ptr weak_ptr_this_; + bool is_valid_; + + DISALLOW_COPY_AND_ASSIGN(WifiRttController); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_RTT_CONTROLLER_H_ diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp new file mode 100644 index 0000000000..ce90349bc5 --- /dev/null +++ b/wifi/aidl/default/wifi_sta_iface.cpp @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2022 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 "wifi_sta_iface.h" + +#include + +#include "aidl_return_util.h" +#include "aidl_struct_util.h" +#include "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using aidl_return_util::validateAndCall; + +WifiStaIface::WifiStaIface(const std::string& ifname, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) + : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) { + // Turn on DFS channel usage for STA iface. + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable."; + } +} + +std::shared_ptr WifiStaIface::create( + const std::string& ifname, const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util) { + std::shared_ptr ptr = + ndk::SharedRefBase::make(ifname, legacy_hal, iface_util); + std::weak_ptr weak_ptr_this(ptr); + ptr->setWeakPtr(weak_ptr_this); + return ptr; +} + +void WifiStaIface::invalidate() { + legacy_hal_.reset(); + event_cb_handler_.invalidate(); + is_valid_ = false; +} + +void WifiStaIface::setWeakPtr(std::weak_ptr ptr) { + weak_ptr_this_ = ptr; +} + +bool WifiStaIface::isValid() { + return is_valid_; +} + +std::string WifiStaIface::getName() { + return ifname_; +} + +std::set> WifiStaIface::getEventCallbacks() { + return event_cb_handler_.getCallbacks(); +} + +ndk::ScopedAStatus WifiStaIface::getName(std::string* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getNameInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::registerEventCallback( + const std::shared_ptr& in_callback) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::registerEventCallbackInternal, in_callback); +} + +ndk::ScopedAStatus WifiStaIface::getCapabilities( + IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::getApfPacketFilterCapabilities( + StaApfPacketFilterCapabilities* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getApfPacketFilterCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::installApfPacketFilter(const std::vector& in_program) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::installApfPacketFilterInternal, in_program); +} + +ndk::ScopedAStatus WifiStaIface::readApfPacketFilterData(std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::readApfPacketFilterDataInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::getBackgroundScanCapabilities( + StaBackgroundScanCapabilities* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getBackgroundScanCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::getValidFrequenciesForBand(WifiBand in_band, + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getValidFrequenciesForBandInternal, _aidl_return, + in_band); +} + +ndk::ScopedAStatus WifiStaIface::startBackgroundScan(int32_t in_cmdId, + const StaBackgroundScanParameters& in_params) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::startBackgroundScanInternal, in_cmdId, in_params); +} + +ndk::ScopedAStatus WifiStaIface::stopBackgroundScan(int32_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::stopBackgroundScanInternal, in_cmdId); +} + +ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollection(bool in_debug) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::enableLinkLayerStatsCollectionInternal, in_debug); +} + +ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollection() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::disableLinkLayerStatsCollectionInternal); +} + +ndk::ScopedAStatus WifiStaIface::getLinkLayerStats(StaLinkLayerStats* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getLinkLayerStatsInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi, + int32_t in_minRssi) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::startRssiMonitoringInternal, in_cmdId, in_maxRssi, + in_minRssi); +} + +ndk::ScopedAStatus WifiStaIface::stopRssiMonitoring(int32_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::stopRssiMonitoringInternal, in_cmdId); +} + +ndk::ScopedAStatus WifiStaIface::getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getRoamingCapabilitiesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::configureRoaming(const StaRoamingConfig& in_config) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::configureRoamingInternal, in_config); +} + +ndk::ScopedAStatus WifiStaIface::setRoamingState(StaRoamingState in_state) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::setRoamingStateInternal, in_state); +} + +ndk::ScopedAStatus WifiStaIface::enableNdOffload(bool in_enable) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::enableNdOffloadInternal, in_enable); +} + +ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePackets( + int32_t in_cmdId, const std::vector& in_ipPacketData, char16_t in_etherType, + const std::array& in_srcAddress, const std::array& in_dstAddress, + int32_t in_periodInMs) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::startSendingKeepAlivePacketsInternal, in_cmdId, + in_ipPacketData, in_etherType, in_srcAddress, in_dstAddress, + in_periodInMs); +} + +ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePackets(int32_t in_cmdId) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::stopSendingKeepAlivePacketsInternal, in_cmdId); +} + +ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoring() { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::startDebugPacketFateMonitoringInternal); +} + +ndk::ScopedAStatus WifiStaIface::getDebugTxPacketFates( + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getDebugTxPacketFatesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::getDebugRxPacketFates( + std::vector* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getDebugRxPacketFatesInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::setMacAddress(const std::array& in_mac) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::setMacAddressInternal, in_mac); +} + +ndk::ScopedAStatus WifiStaIface::getFactoryMacAddress(std::array* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::getFactoryMacAddressInternal, _aidl_return); +} + +ndk::ScopedAStatus WifiStaIface::setScanMode(bool in_enable) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, + &WifiStaIface::setScanModeInternal, in_enable); +} + +std::pair WifiStaIface::getNameInternal() { + return {ifname_, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::registerEventCallbackInternal( + const std::shared_ptr& callback) { + if (!event_cb_handler_.addCallback(callback)) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +std::pair +WifiStaIface::getCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + uint64_t legacy_feature_set; + std::tie(legacy_status, legacy_feature_set) = + legacy_hal_.lock()->getSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {IWifiStaIface::StaIfaceCapabilityMask{}, + createWifiStatusFromLegacyError(legacy_status)}; + } + uint32_t legacy_logger_feature_set; + std::tie(legacy_status, legacy_logger_feature_set) = + legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + // some devices don't support querying logger feature set + legacy_logger_feature_set = 0; + } + uint32_t aidl_caps; + if (!aidl_struct_util::convertLegacyFeaturesToAidlStaCapabilities( + legacy_feature_set, legacy_logger_feature_set, &aidl_caps)) { + return {IWifiStaIface::StaIfaceCapabilityMask{}, + createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {static_cast(aidl_caps), + ndk::ScopedAStatus::ok()}; +} + +std::pair +WifiStaIface::getApfPacketFilterCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::PacketFilterCapabilities legacy_caps; + std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getPacketFilterCapabilities(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {StaApfPacketFilterCapabilities{}, createWifiStatusFromLegacyError(legacy_status)}; + } + StaApfPacketFilterCapabilities aidl_caps; + if (!aidl_struct_util::convertLegacyApfCapabilitiesToAidl(legacy_caps, &aidl_caps)) { + return {StaApfPacketFilterCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_caps, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::installApfPacketFilterInternal( + const std::vector& program) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair, ndk::ScopedAStatus> +WifiStaIface::readApfPacketFilterDataInternal() { + const std::pair> legacy_status_and_data = + legacy_hal_.lock()->readApfPacketFilterData(ifname_); + return {std::move(legacy_status_and_data.second), + createWifiStatusFromLegacyError(legacy_status_and_data.first)}; +} + +std::pair +WifiStaIface::getBackgroundScanCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_gscan_capabilities legacy_caps; + std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getGscanCapabilities(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {StaBackgroundScanCapabilities{}, createWifiStatusFromLegacyError(legacy_status)}; + } + StaBackgroundScanCapabilities aidl_caps; + if (!aidl_struct_util::convertLegacyGscanCapabilitiesToAidl(legacy_caps, &aidl_caps)) { + return {StaBackgroundScanCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_caps, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> +WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) { + static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch"); + legacy_hal::wifi_error legacy_status; + std::vector valid_frequencies; + std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand( + ifname_, aidl_struct_util::convertAidlWifiBandToLegacy(band)); + return {std::vector(valid_frequencies.begin(), valid_frequencies.end()), + createWifiStatusFromLegacyError(legacy_status)}; +} + +ndk::ScopedAStatus WifiStaIface::startBackgroundScanInternal( + int32_t cmd_id, const StaBackgroundScanParameters& params) { + legacy_hal::wifi_scan_cmd_params legacy_params; + if (!aidl_struct_util::convertAidlGscanParamsToLegacy(params, &legacy_params)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onBackgroundScanFailure(id).isOk()) { + LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback"; + } + } + }; + const auto& on_results_callback = + [weak_ptr_this](legacy_hal::wifi_request_id id, + const std::vector& results) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + std::vector aidl_scan_datas; + if (!aidl_struct_util::convertLegacyVectorOfCachedGscanResultsToAidl( + results, &aidl_scan_datas)) { + LOG(ERROR) << "Failed to convert scan results to AIDL structs"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onBackgroundScanResults(id, aidl_scan_datas).isOk()) { + LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback"; + } + } + }; + const auto& on_full_result_callback = [weak_ptr_this]( + legacy_hal::wifi_request_id id, + const legacy_hal::wifi_scan_result* result, + uint32_t buckets_scanned) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + StaScanResult aidl_scan_result; + if (!aidl_struct_util::convertLegacyGscanResultToAidl(*result, true, &aidl_scan_result)) { + LOG(ERROR) << "Failed to convert full scan results to AIDL structs"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onBackgroundFullScanResult(id, buckets_scanned, aidl_scan_result) + .isOk()) { + LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback"; + } + } + }; + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->startGscan(ifname_, cmd_id, legacy_params, on_failure_callback, + on_results_callback, on_full_result_callback); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::stopBackgroundScanInternal(int32_t cmd_id) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair WifiStaIface::getLinkLayerStatsInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::LinkLayerStats legacy_stats; + std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {StaLinkLayerStats{}, createWifiStatusFromLegacyError(legacy_status)}; + } + StaLinkLayerStats aidl_stats; + if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) { + return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_stats, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi, + int32_t min_rssi) { + std::weak_ptr weak_ptr_this = weak_ptr_this_; + const auto& on_threshold_breached_callback = + [weak_ptr_this](legacy_hal::wifi_request_id id, std::array bssid, + int8_t rssi) { + const auto shared_ptr_this = weak_ptr_this.lock(); + if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) { + LOG(ERROR) << "Callback invoked on an invalid object"; + return; + } + for (const auto& callback : shared_ptr_this->getEventCallbacks()) { + if (!callback->onRssiThresholdBreached(id, bssid, rssi).isOk()) { + LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback"; + } + } + }; + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRssiMonitoring( + ifname_, cmd_id, max_rssi, min_rssi, on_threshold_breached_callback); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::stopRssiMonitoringInternal(int32_t cmd_id) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair +WifiStaIface::getRoamingCapabilitiesInternal() { + legacy_hal::wifi_error legacy_status; + legacy_hal::wifi_roaming_capabilities legacy_caps; + std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRoamingCapabilities(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {StaRoamingCapabilities{}, createWifiStatusFromLegacyError(legacy_status)}; + } + StaRoamingCapabilities aidl_caps; + if (!aidl_struct_util::convertLegacyRoamingCapabilitiesToAidl(legacy_caps, &aidl_caps)) { + return {StaRoamingCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_caps, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) { + legacy_hal::wifi_roaming_config legacy_config; + if (!aidl_struct_util::convertAidlRoamingConfigToLegacy(config, &legacy_config)) { + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); + } + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->configureRoaming(ifname_, legacy_config); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming( + ifname_, aidl_struct_util::convertAidlRoamingStateToLegacy(state)); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::enableNdOffloadInternal(bool enable) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePacketsInternal( + int32_t cmd_id, const std::vector& ip_packet_data, char16_t ether_type, + const std::array& src_address, const std::array& dst_address, + int32_t period_in_ms) { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startSendingOffloadedPacket( + ifname_, cmd_id, ether_type, ip_packet_data, src_address, dst_address, period_in_ms); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(int32_t cmd_id) { + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id); + return createWifiStatusFromLegacyError(legacy_status); +} + +ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoringInternal() { + legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_); + return createWifiStatusFromLegacyError(legacy_status); +} + +std::pair, ndk::ScopedAStatus> +WifiStaIface::getDebugTxPacketFatesInternal() { + legacy_hal::wifi_error legacy_status; + std::vector legacy_fates; + std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {std::vector(), + createWifiStatusFromLegacyError(legacy_status)}; + } + std::vector aidl_fates; + if (!aidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToAidl(legacy_fates, + &aidl_fates)) { + return {std::vector(), + createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_fates, ndk::ScopedAStatus::ok()}; +} + +std::pair, ndk::ScopedAStatus> +WifiStaIface::getDebugRxPacketFatesInternal() { + legacy_hal::wifi_error legacy_status; + std::vector legacy_fates; + std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates(ifname_); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + return {std::vector(), + createWifiStatusFromLegacyError(legacy_status)}; + } + std::vector aidl_fates; + if (!aidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToAidl(legacy_fates, + &aidl_fates)) { + return {std::vector(), + createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {aidl_fates, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::setMacAddressInternal(const std::array& mac) { + bool status = iface_util_.lock()->setMacAddress(ifname_, mac); + if (!status) { + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } + return ndk::ScopedAStatus::ok(); +} + +std::pair, ndk::ScopedAStatus> WifiStaIface::getFactoryMacAddressInternal() { + std::array mac = iface_util_.lock()->getFactoryMacAddress(ifname_); + if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) { + return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } + return {mac, ndk::ScopedAStatus::ok()}; +} + +ndk::ScopedAStatus WifiStaIface::setScanModeInternal(bool enable) { + // OEM's need to implement this on their devices if needed. + LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported"; + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h new file mode 100644 index 0000000000..8ac3470edb --- /dev/null +++ b/wifi/aidl/default/wifi_sta_iface.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_STA_IFACE_H_ +#define WIFI_STA_IFACE_H_ + +#include +#include +#include + +#include "aidl_callback_util.h" +#include "wifi_iface_util.h" +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +/** + * AIDL interface object used to control a STA Iface instance. + */ +class WifiStaIface : public BnWifiStaIface { + public: + WifiStaIface(const std::string& ifname, + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); + + // Factory method - use instead of default constructor. + static std::shared_ptr create( + const std::string& ifname, const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); + + // Refer to |WifiChip::invalidate()|. + void invalidate(); + bool isValid(); + std::set> getEventCallbacks(); + std::string getName(); + + // AIDL methods exposed. + ndk::ScopedAStatus getName(std::string* _aidl_return) override; + ndk::ScopedAStatus registerEventCallback( + const std::shared_ptr& in_callback) override; + ndk::ScopedAStatus getCapabilities( + IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) override; + ndk::ScopedAStatus getApfPacketFilterCapabilities( + StaApfPacketFilterCapabilities* _aidl_return) override; + ndk::ScopedAStatus installApfPacketFilter(const std::vector& in_program) override; + ndk::ScopedAStatus readApfPacketFilterData(std::vector* _aidl_return) override; + ndk::ScopedAStatus getBackgroundScanCapabilities( + StaBackgroundScanCapabilities* _aidl_return) override; + ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band, + std::vector* _aidl_return) override; + ndk::ScopedAStatus startBackgroundScan(int32_t in_cmdId, + const StaBackgroundScanParameters& in_params) override; + ndk::ScopedAStatus stopBackgroundScan(int32_t in_cmdId) override; + ndk::ScopedAStatus enableLinkLayerStatsCollection(bool in_debug) override; + ndk::ScopedAStatus disableLinkLayerStatsCollection() override; + ndk::ScopedAStatus getLinkLayerStats(StaLinkLayerStats* _aidl_return) override; + ndk::ScopedAStatus startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi, + int32_t in_minRssi) override; + ndk::ScopedAStatus stopRssiMonitoring(int32_t in_cmdId) override; + ndk::ScopedAStatus getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) override; + ndk::ScopedAStatus configureRoaming(const StaRoamingConfig& in_config) override; + ndk::ScopedAStatus setRoamingState(StaRoamingState in_state) override; + ndk::ScopedAStatus enableNdOffload(bool in_enable) override; + ndk::ScopedAStatus startSendingKeepAlivePackets(int32_t in_cmdId, + const std::vector& in_ipPacketData, + char16_t in_etherType, + const std::array& in_srcAddress, + const std::array& in_dstAddress, + int32_t in_periodInMs) override; + ndk::ScopedAStatus stopSendingKeepAlivePackets(int32_t in_cmdId) override; + ndk::ScopedAStatus startDebugPacketFateMonitoring() override; + ndk::ScopedAStatus getDebugTxPacketFates( + std::vector* _aidl_return) override; + ndk::ScopedAStatus getDebugRxPacketFates( + std::vector* _aidl_return) override; + ndk::ScopedAStatus setMacAddress(const std::array& in_mac) override; + ndk::ScopedAStatus getFactoryMacAddress(std::array* _aidl_return) override; + ndk::ScopedAStatus setScanMode(bool in_enable) override; + + private: + // Corresponding worker functions for the AIDL methods. + std::pair getNameInternal(); + ndk::ScopedAStatus registerEventCallbackInternal( + const std::shared_ptr& callback); + std::pair getCapabilitiesInternal(); + std::pair + getApfPacketFilterCapabilitiesInternal(); + ndk::ScopedAStatus installApfPacketFilterInternal(const std::vector& program); + std::pair, ndk::ScopedAStatus> readApfPacketFilterDataInternal(); + std::pair + getBackgroundScanCapabilitiesInternal(); + std::pair, ndk::ScopedAStatus> getValidFrequenciesForBandInternal( + WifiBand band); + ndk::ScopedAStatus startBackgroundScanInternal(int32_t cmd_id, + const StaBackgroundScanParameters& params); + ndk::ScopedAStatus stopBackgroundScanInternal(int32_t cmd_id); + ndk::ScopedAStatus enableLinkLayerStatsCollectionInternal(bool debug); + ndk::ScopedAStatus disableLinkLayerStatsCollectionInternal(); + std::pair getLinkLayerStatsInternal(); + ndk::ScopedAStatus startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi, + int32_t min_rssi); + ndk::ScopedAStatus stopRssiMonitoringInternal(int32_t cmd_id); + std::pair getRoamingCapabilitiesInternal(); + ndk::ScopedAStatus configureRoamingInternal(const StaRoamingConfig& config); + ndk::ScopedAStatus setRoamingStateInternal(StaRoamingState state); + ndk::ScopedAStatus enableNdOffloadInternal(bool enable); + ndk::ScopedAStatus startSendingKeepAlivePacketsInternal( + int32_t cmd_id, const std::vector& ip_packet_data, char16_t ether_type, + const std::array& src_address, const std::array& dst_address, + int32_t period_in_ms); + ndk::ScopedAStatus stopSendingKeepAlivePacketsInternal(int32_t cmd_id); + ndk::ScopedAStatus startDebugPacketFateMonitoringInternal(); + std::pair, ndk::ScopedAStatus> + getDebugTxPacketFatesInternal(); + std::pair, ndk::ScopedAStatus> + getDebugRxPacketFatesInternal(); + ndk::ScopedAStatus setMacAddressInternal(const std::array& mac); + std::pair, ndk::ScopedAStatus> getFactoryMacAddressInternal(); + ndk::ScopedAStatus setScanModeInternal(bool enable); + + void setWeakPtr(std::weak_ptr ptr); + + std::string ifname_; + std::weak_ptr legacy_hal_; + std::weak_ptr iface_util_; + std::weak_ptr weak_ptr_this_; + bool is_valid_; + aidl_callback_util::AidlCallbackHandler event_cb_handler_; + + DISALLOW_COPY_AND_ASSIGN(WifiStaIface); +}; + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_STA_IFACE_H_ diff --git a/wifi/aidl/default/wifi_status_util.cpp b/wifi/aidl/default/wifi_status_util.cpp new file mode 100644 index 0000000000..25ecd716da --- /dev/null +++ b/wifi/aidl/default/wifi_status_util.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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 "wifi_status_util.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { + +std::string legacyErrorToString(legacy_hal::wifi_error error) { + switch (error) { + case legacy_hal::WIFI_SUCCESS: + return "SUCCESS"; + case legacy_hal::WIFI_ERROR_UNINITIALIZED: + return "UNINITIALIZED"; + case legacy_hal::WIFI_ERROR_NOT_AVAILABLE: + return "NOT_AVAILABLE"; + case legacy_hal::WIFI_ERROR_NOT_SUPPORTED: + return "NOT_SUPPORTED"; + case legacy_hal::WIFI_ERROR_INVALID_ARGS: + return "INVALID_ARGS"; + case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID: + return "INVALID_REQUEST_ID"; + case legacy_hal::WIFI_ERROR_TIMED_OUT: + return "TIMED_OUT"; + case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS: + return "TOO_MANY_REQUESTS"; + case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case legacy_hal::WIFI_ERROR_BUSY: + return "BUSY"; + case legacy_hal::WIFI_ERROR_UNKNOWN: + return "UNKNOWN"; + default: + return "UNKNOWN ERROR"; + } +} + +ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description) { + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(static_cast(code), + description.c_str()); +} + +ndk::ScopedAStatus createWifiStatus(WifiStatusCode code) { + return ndk::ScopedAStatus::fromServiceSpecificError(static_cast(code)); +} + +ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, + const std::string& desc) { + switch (error) { + case legacy_hal::WIFI_ERROR_NONE: + return ndk::ScopedAStatus::ok(); + + case legacy_hal::WIFI_ERROR_UNINITIALIZED: + case legacy_hal::WIFI_ERROR_NOT_AVAILABLE: + return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc); + + case legacy_hal::WIFI_ERROR_NOT_SUPPORTED: + return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc); + + case legacy_hal::WIFI_ERROR_INVALID_ARGS: + case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID: + return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc); + + case legacy_hal::WIFI_ERROR_TIMED_OUT: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", timed out"); + + case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", too many requests"); + + case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", out of memory"); + + case legacy_hal::WIFI_ERROR_BUSY: + return createWifiStatus(WifiStatusCode::ERROR_BUSY); + + case legacy_hal::WIFI_ERROR_UNKNOWN: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown"); + + default: + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error"); + } +} + +ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) { + return createWifiStatusFromLegacyError(error, ""); +} + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/wifi/aidl/default/wifi_status_util.h b/wifi/aidl/default/wifi_status_util.h new file mode 100644 index 0000000000..633811dbf6 --- /dev/null +++ b/wifi/aidl/default/wifi_status_util.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef WIFI_STATUS_UTIL_H_ +#define WIFI_STATUS_UTIL_H_ + +#include + +#include "wifi_legacy_hal.h" + +namespace aidl { +namespace android { +namespace hardware { +namespace wifi { +using ::aidl::android::hardware::wifi::WifiStatusCode; + +std::string legacyErrorToString(legacy_hal::wifi_error error); +ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description); +ndk::ScopedAStatus createWifiStatus(WifiStatusCode code); +ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error, + const std::string& description); +ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error); + +} // namespace wifi +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // WIFI_STATUS_UTIL_H_ diff --git a/wifi/aidl/vts/functional/Android.bp b/wifi/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..1277182493 --- /dev/null +++ b/wifi/aidl/vts/functional/Android.bp @@ -0,0 +1,169 @@ +// +// Copyright (C) 2022 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. +// + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_test { + name: "VtsHalWifiChipTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "wifi_chip_aidl_test.cpp", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libvndksupport", + ], + static_libs: [ + "VtsHalWifiTargetTestUtil", + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_test { + name: "VtsHalWifiStaIfaceTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "wifi_sta_iface_aidl_test.cpp", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libvndksupport", + ], + static_libs: [ + "VtsHalWifiTargetTestUtil", + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_test { + name: "VtsHalWifiApIfaceTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "wifi_ap_iface_aidl_test.cpp", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libvndksupport", + ], + static_libs: [ + "VtsHalWifiTargetTestUtil", + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_test { + name: "VtsHalWifiNanIfaceTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "wifi_nan_iface_aidl_test.cpp", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libvndksupport", + ], + static_libs: [ + "VtsHalWifiTargetTestUtil", + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_test { + name: "VtsHalWifiRttControllerTargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "wifi_rtt_controller_aidl_test.cpp", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libvndksupport", + ], + static_libs: [ + "VtsHalWifiTargetTestUtil", + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_library_static { + name: "VtsHalWifiTargetTestUtil", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "wifi_aidl_test_utils.cpp", + ], + export_include_dirs: [ + ".", + ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libnativehelper", + ], + static_libs: [ + "android.hardware.wifi-V1-ndk", + "libwifi-system-iface", + ], +} diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp new file mode 100644 index 0000000000..6722f36dc9 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2022 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 "wifi_aidl_test_utils.h" + +using ::android::wifi_system::InterfaceTool; + +namespace { +bool findAnyModeSupportingConcurrencyType(IfaceConcurrencyType desired_type, + const std::vector& modes, + int* mode_id) { + for (const auto& mode : modes) { + for (const auto& combination : mode.availableCombinations) { + for (const auto& iface_limit : combination.limits) { + const auto& iface_types = iface_limit.types; + if (std::find(iface_types.begin(), iface_types.end(), desired_type) != + iface_types.end()) { + *mode_id = mode.id; + return true; + } + } + } + } + return false; +} + +bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr& wifi_chip, + IfaceConcurrencyType type, + int* configured_mode_id) { + if (!configured_mode_id) { + return false; + } + std::vector chip_modes; + auto status = wifi_chip->getAvailableModes(&chip_modes); + if (!status.isOk()) { + return false; + } + if (!findAnyModeSupportingConcurrencyType(type, chip_modes, configured_mode_id)) { + return false; + } + if (!wifi_chip->configureChip(*configured_mode_id).isOk()) { + return false; + } + return true; +} + +bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr& wifi_chip, + IfaceConcurrencyType type) { + int mode_id; + return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, &mode_id); +} +} // namespace + +bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code) { + if (status == nullptr) { + return false; + } + return status->getServiceSpecificError() == static_cast(expected_code); +} + +std::shared_ptr getWifi(const char* instance_name) { + return IWifi::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(instance_name))); +} + +std::shared_ptr getWifiChip(const char* instance_name) { + std::shared_ptr wifi = getWifi(instance_name); + if (!wifi.get()) { + return nullptr; + } + + const int retry_interval_ms = 2; + const int max_retries = 5; + int retry_count = 0; + auto status = wifi->start(); + while (retry_count < max_retries && !status.isOk()) { + retry_count++; + usleep(retry_interval_ms * 1000); + status = wifi->start(); + } + if (!status.isOk()) { + return nullptr; + } + + std::vector chip_ids = {}; + status = wifi->getChipIds(&chip_ids); + if (!status.isOk() || chip_ids.size() == 0) { + return nullptr; + } + std::shared_ptr chip; + status = wifi->getChip(chip_ids[0], &chip); + if (!status.isOk()) { + return nullptr; + } + return chip; +} + +void setupStaIface(const std::shared_ptr& iface) { + std::string iface_name; + auto status = iface->getName(&iface_name); + if (status.isOk()) { + InterfaceTool iface_tool; + iface_tool.SetUpState(iface_name.c_str(), true); + } +} + +void setupNanIface(const std::shared_ptr& iface) { + std::string iface_name; + auto status = iface->getName(&iface_name); + if (status.isOk()) { + InterfaceTool iface_tool; + iface_tool.SetUpState(iface_name.c_str(), true); + } +} + +std::shared_ptr getWifiStaIface(const char* instance_name) { + std::shared_ptr wifi_chip = getWifiChip(instance_name); + if (!wifi_chip.get()) { + return nullptr; + } + if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::STA)) { + return nullptr; + } + std::shared_ptr iface; + auto status = wifi_chip->createStaIface(&iface); + if (!status.isOk()) { + return nullptr; + } + setupStaIface(iface); + return iface; +} + +std::shared_ptr getWifiNanIface(const char* instance_name) { + std::shared_ptr wifi_chip = getWifiChip(instance_name); + if (!wifi_chip.get()) { + return nullptr; + } + if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, + IfaceConcurrencyType::NAN_IFACE)) { + return nullptr; + } + std::shared_ptr iface; + auto status = wifi_chip->createNanIface(&iface); + if (!status.isOk()) { + return nullptr; + } + setupNanIface(iface); + return iface; +} + +std::shared_ptr getWifiApIface(const char* instance_name) { + std::shared_ptr wifi_chip = getWifiChip(instance_name); + if (!wifi_chip.get()) { + return nullptr; + } + if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP)) { + return nullptr; + } + std::shared_ptr iface; + auto status = wifi_chip->createApIface(&iface); + if (!status.isOk()) { + return nullptr; + } + return iface; +} + +std::shared_ptr getBridgedWifiApIface(std::shared_ptr wifi_chip) { + if (!wifi_chip.get()) { + return nullptr; + } + int mode_id; + std::shared_ptr iface; + configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP, &mode_id); + auto status = wifi_chip->createBridgedApIface(&iface); + if (!status.isOk()) { + return nullptr; + } + return iface; +} + +std::shared_ptr getBridgedWifiApIface(const char* instance_name) { + std::shared_ptr wifi_chip = getWifiChip(instance_name); + return getBridgedWifiApIface(wifi_chip); +} + +bool configureChipToSupportConcurrencyType(const std::shared_ptr& wifi_chip, + IfaceConcurrencyType type, int* configured_mode_id) { + return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, configured_mode_id); +} + +void stopWifiService(const char* instance_name) { + std::shared_ptr wifi = getWifi(instance_name); + if (wifi != nullptr) { + wifi->stop(); + } +} + +int32_t getChipCapabilities(const std::shared_ptr& wifi_chip) { + IWifiChip::ChipCapabilityMask caps = {}; + if (wifi_chip->getCapabilities(&caps).isOk()) { + return static_cast(caps); + } + return 0; +} diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h new file mode 100644 index 0000000000..ad16603dd3 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +using aidl::android::hardware::wifi::IfaceConcurrencyType; +using aidl::android::hardware::wifi::IWifi; +using aidl::android::hardware::wifi::IWifiApIface; +using aidl::android::hardware::wifi::IWifiChip; +using aidl::android::hardware::wifi::IWifiNanIface; +using aidl::android::hardware::wifi::IWifiStaIface; +using aidl::android::hardware::wifi::WifiStatusCode; + +// Helper functions to obtain references to the various AIDL interface objects. +std::shared_ptr getWifi(const char* instance_name); +std::shared_ptr getWifiChip(const char* instance_name); +std::shared_ptr getWifiStaIface(const char* instance_name); +std::shared_ptr getWifiNanIface(const char* instance_name); +std::shared_ptr getWifiApIface(const char* instance_name); +std::shared_ptr getBridgedWifiApIface(const char* instance_name); +std::shared_ptr getBridgedWifiApIface(std::shared_ptr wifi_chip); +// Configure the chip in a mode to support the creation of the provided iface type. +bool configureChipToSupportConcurrencyType(const std::shared_ptr& wifi_chip, + IfaceConcurrencyType type, int* configured_mode_id); +// Used to trigger IWifi.stop() at the end of every test. +void stopWifiService(const char* instance_name); +int32_t getChipCapabilities(const std::shared_ptr& wifi_chip); +bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code); diff --git a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp new file mode 100644 index 0000000000..0eaf660d49 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_aidl_test_utils.h" + +using aidl::android::hardware::wifi::IWifiApIface; +using aidl::android::hardware::wifi::WifiBand; + +class WifiApIfaceAidlTest : public testing::TestWithParam { + public: + void SetUp() override { + isBridgedSupport_ = testing::checkSubstringInCommandOutput( + "/system/bin/cmd wifi get-softap-supported-features", + "wifi_softap_bridged_ap_supported"); + stopWifiService(getInstanceName()); + } + + void TearDown() override { stopWifiService(getInstanceName()); } + + protected: + bool isBridgedSupport_ = false; + const char* getInstanceName() { return GetParam().c_str(); } +}; + +/* + * SetMacAddress + */ +TEST_P(WifiApIfaceAidlTest, SetMacAddress) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + std::array mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44}; + EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk()); +} + +/* + * SetCountryCode + */ +TEST_P(WifiApIfaceAidlTest, SetCountryCode) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + const std::array country_code = {0x55, 0x53}; + EXPECT_TRUE(wifi_ap_iface->setCountryCode(country_code).isOk()); +} + +/* + * GetValidFrequenciesForBand + * Ensures that we can retrieve valid frequencies for the 2.4 GHz band. + */ +TEST_P(WifiApIfaceAidlTest, GetValidFrequenciesForBand) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + std::vector freqs; + EXPECT_TRUE(wifi_ap_iface->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk()); + EXPECT_NE(freqs.size(), 0); +} + +/* + * GetFactoryMacAddress + */ +TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + std::array mac; + EXPECT_TRUE(wifi_ap_iface->getFactoryMacAddress(&mac).isOk()); + std::array all_zero_mac = {0, 0, 0, 0, 0, 0}; + EXPECT_NE(mac, all_zero_mac); +} + +/** + * GetBridgedInstances - non-bridged mode + */ +TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + std::vector instances; + EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk()); + EXPECT_EQ(instances.size(), 0); +} + +/** + * GetBridgedInstances - bridged AP mode. + */ +TEST_P(WifiApIfaceAidlTest, GetBridgedInstances_Bridged) { + if (!isBridgedSupport_) { + GTEST_SKIP() << "Missing Bridged AP support"; + } + std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + std::vector instances; + EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk()); + EXPECT_EQ(instances.size(), 2); +} + +/** + * ResetToFactoryMacAddress - non-bridged mode + */ +TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) { + std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk()); +} + +/** + * ResetToFactoryMacAddress - bridged AP mode + */ +TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress_Bridged) { + if (!isBridgedSupport_) { + GTEST_SKIP() << "Missing Bridged AP support"; + } + std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceAidlTest); +INSTANTIATE_TEST_SUITE_P(WifiTest, WifiApIfaceAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::ProcessState::self()->setThreadPoolMaxThreadCount(1); + android::ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp new file mode 100644 index 0000000000..0806ed289d --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp @@ -0,0 +1,889 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Staache 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_aidl_test_utils.h" + +using aidl::android::hardware::wifi::BnWifiChipEventCallback; +using aidl::android::hardware::wifi::IfaceType; +using aidl::android::hardware::wifi::IWifiApIface; +using aidl::android::hardware::wifi::IWifiChip; +using aidl::android::hardware::wifi::IWifiNanIface; +using aidl::android::hardware::wifi::IWifiP2pIface; +using aidl::android::hardware::wifi::IWifiRttController; +using aidl::android::hardware::wifi::WifiBand; +using aidl::android::hardware::wifi::WifiDebugHostWakeReasonStats; +using aidl::android::hardware::wifi::WifiDebugRingBufferStatus; +using aidl::android::hardware::wifi::WifiDebugRingBufferVerboseLevel; +using aidl::android::hardware::wifi::WifiIfaceMode; +using aidl::android::hardware::wifi::WifiRadioCombinationMatrix; +using aidl::android::hardware::wifi::WifiStatusCode; +using aidl::android::hardware::wifi::WifiUsableChannel; + +class WifiChipAidlTest : public testing::TestWithParam { + public: + void SetUp() override { + stopWifiService(getInstanceName()); + wifi_chip_ = getWifiChip(getInstanceName()); + ASSERT_NE(nullptr, wifi_chip_.get()); + } + + void TearDown() override { stopWifiService(getInstanceName()); } + + protected: + int configureChipForConcurrencyType(IfaceConcurrencyType type) { + int mode_id; + EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip_, type, &mode_id)); + return mode_id; + } + + std::shared_ptr configureChipForStaAndGetIface() { + std::shared_ptr iface; + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk()); + EXPECT_NE(nullptr, iface.get()); + return iface; + } + + std::shared_ptr configureChipForP2pAndGetIface() { + std::shared_ptr iface; + configureChipForConcurrencyType(IfaceConcurrencyType::P2P); + EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk()); + EXPECT_NE(nullptr, iface.get()); + return iface; + } + + std::shared_ptr configureChipForApAndGetIface() { + std::shared_ptr iface; + configureChipForConcurrencyType(IfaceConcurrencyType::AP); + EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk()); + EXPECT_NE(nullptr, iface.get()); + return iface; + } + + std::shared_ptr configureChipForNanAndGetIface() { + std::shared_ptr iface; + configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE); + EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk()); + EXPECT_NE(nullptr, iface.get()); + return iface; + } + + std::string getStaIfaceName(const std::shared_ptr& iface) { + std::string iface_name; + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + return iface_name; + } + + std::string getP2pIfaceName(const std::shared_ptr& iface) { + std::string iface_name; + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + return iface_name; + } + + std::string getApIfaceName(const std::shared_ptr& iface) { + std::string iface_name; + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + return iface_name; + } + + std::string getNanIfaceName(const std::shared_ptr& iface) { + std::string iface_name; + EXPECT_TRUE(iface->getName(&iface_name).isOk()); + return iface_name; + } + + std::vector> create2StaIfacesIfPossible() { + std::shared_ptr iface1 = configureChipForStaAndGetIface(); + + // Try create a create second iface. + std::shared_ptr iface2; + bool add_second_success = wifi_chip_->createStaIface(&iface2).isOk(); + if (!add_second_success) { + return {iface1}; + } + EXPECT_NE(nullptr, iface2.get()); + return {iface1, iface2}; + } + + bool hasAnyRingBufferCapabilities(int32_t caps) { + return caps & + (static_cast( + IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_CONNECT_EVENT) | + static_cast(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_POWER_EVENT) | + static_cast( + IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_WAKELOCK_EVENT) | + static_cast(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_VENDOR_DATA)); + } + + const char* getInstanceName() { return GetParam().c_str(); } + + std::shared_ptr wifi_chip_; +}; + +class WifiChipEventCallback : public BnWifiChipEventCallback { + public: + WifiChipEventCallback() = default; + + ::ndk::ScopedAStatus onChipReconfigureFailure(WifiStatusCode /* status */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onChipReconfigured(int /* modeId */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onDebugErrorAlert(int /* errorCode */, + const std::vector& /* debugData */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onDebugRingBufferDataAvailable( + const WifiDebugRingBufferStatus& /* status */, + const std::vector& /* data */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onIfaceAdded(IfaceType /* type */, + const std::string& /* name */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onIfaceRemoved(IfaceType /* type */, + const std::string& /* name */) override { + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus onRadioModeChange( + const std::vector& /* radioModeInfos */) override { + return ndk::ScopedAStatus::ok(); + } +}; + +/* + * RegisterEventCallback + * + * Note: it is not feasible to test the invocation of the callback function, + * since events are triggered internally in the HAL implementation and cannot be + * triggered from the test case. + */ +TEST_P(WifiChipAidlTest, RegisterEventCallback) { + std::shared_ptr callback = + ndk::SharedRefBase::make(); + ASSERT_NE(nullptr, callback.get()); + EXPECT_TRUE(wifi_chip_->registerEventCallback(callback).isOk()); +} + +/* + * GetCapabilities + */ +TEST_P(WifiChipAidlTest, GetCapabilities) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + EXPECT_NE(static_cast(caps), 0); +} + +/* + * GetId + */ +TEST_P(WifiChipAidlTest, GetId) { + int id; + EXPECT_TRUE(wifi_chip_->getId(&id).isOk()); +} + +/* + * GetAvailableModes + */ +TEST_P(WifiChipAidlTest, GetAvailableModes) { + std::vector modes; + EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk()); + EXPECT_NE(modes.size(), 0); +} + +/* + * GetMode + */ +TEST_P(WifiChipAidlTest, GetMode) { + int expected_mode = configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int retrieved_mode; + EXPECT_TRUE(wifi_chip_->getMode(&retrieved_mode).isOk()); + EXPECT_EQ(retrieved_mode, expected_mode); +} + +/* + * GetUsableChannels + */ +TEST_P(WifiChipAidlTest, GetUsableChannels) { + WifiBand band = WifiBand::BAND_24GHZ_5GHZ_6GHZ; + uint32_t ifaceModeMask = static_cast(WifiIfaceMode::IFACE_MODE_P2P_CLIENT) | + static_cast(WifiIfaceMode::IFACE_MODE_P2P_GO); + uint32_t filterMask = + static_cast(IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) | + static_cast(IWifiChip::UsableChannelFilter::CONCURRENCY); + + std::vector channels; + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + auto status = wifi_chip_->getUsableChannels( + band, static_cast(ifaceModeMask), + static_cast(filterMask), &channels); + if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + GTEST_SKIP() << "getUsableChannels() is not supported by vendor."; + } + EXPECT_TRUE(status.isOk()); +} + +/* + * GetSupportedRadioCombinationsMatrix + */ +TEST_P(WifiChipAidlTest, GetSupportedRadioCombinationsMatrix) { + WifiRadioCombinationMatrix combination_matrix = {}; + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + auto status = wifi_chip_->getSupportedRadioCombinationsMatrix(&combination_matrix); + if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + GTEST_SKIP() << "Skipping this test since getSupportedRadioCombinationsMatrix() " + "is not supported by vendor."; + } + EXPECT_TRUE(status.isOk()); +} + +/* + * SetCountryCode + */ +TEST_P(WifiChipAidlTest, SetCountryCode) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + std::array country_code = {0x55, 0x53}; + EXPECT_TRUE(wifi_chip_->setCountryCode(country_code).isOk()); +} + +/* + * SetLatencyMode_normal + * Tests the setLatencyMode() API with Latency mode NORMAL. + */ +TEST_P(WifiChipAidlTest, SetLatencyMode_normal) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::NORMAL); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SetLatencyMode_low + * Tests the setLatencyMode() API with Latency mode LOW. + */ +TEST_P(WifiChipAidlTest, SetLatencyMode_low) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::LOW); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SetMultiStaPrimaryConnection + * + * Only runs if the device supports 2 STA ifaces. + */ +TEST_P(WifiChipAidlTest, SetMultiStaPrimaryConnection) { + auto ifaces = create2StaIfacesIfPossible(); + if (ifaces.size() < 2) { + GTEST_SKIP() << "Device does not support more than 1 STA concurrently"; + } + + auto status = wifi_chip_->setMultiStaPrimaryConnection(getStaIfaceName(ifaces[0])); + if (!status.isOk()) { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SetMultiStaUseCase + * + * Only runs if the device supports 2 STA ifaces. + */ +TEST_P(WifiChipAidlTest, setMultiStaUseCase) { + auto ifaces = create2StaIfacesIfPossible(); + if (ifaces.size() < 2) { + GTEST_SKIP() << "Device does not support more than 1 STA concurrently"; + } + + auto status = wifi_chip_->setMultiStaUseCase( + IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY); + if (!status.isOk()) { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SetCoexUnsafeChannels + */ +TEST_P(WifiChipAidlTest, SetCoexUnsafeChannels) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + + // Test with an empty vector of CoexUnsafeChannels. + std::vector vec; + IWifiChip::CoexRestriction restrictions = static_cast(0); + auto status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions); + if (!status.isOk()) { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } + + // Test with a non-empty vector of CoexUnsafeChannels. + IWifiChip::CoexUnsafeChannel unsafeChannel24Ghz; + unsafeChannel24Ghz.band = WifiBand::BAND_24GHZ; + unsafeChannel24Ghz.channel = 6; + vec.push_back(unsafeChannel24Ghz); + IWifiChip::CoexUnsafeChannel unsafeChannel5Ghz; + unsafeChannel5Ghz.band = WifiBand::BAND_5GHZ; + unsafeChannel5Ghz.channel = 36; + vec.push_back(unsafeChannel5Ghz); + restrictions = static_cast( + static_cast(IWifiChip::CoexRestriction::WIFI_AWARE) | + static_cast(IWifiChip::CoexRestriction::SOFTAP) | + static_cast(IWifiChip::CoexRestriction::WIFI_DIRECT)); + + status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions); + if (!status.isOk()) { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SelectTxPowerScenario - Body + */ +TEST_P(WifiChipAidlTest, SelectTxPowerScenario_body) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + int32_t expected_caps = + static_cast(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT) | + static_cast(IWifiChip::ChipCapabilityMask::USE_BODY_HEAD_SAR); + auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF); + if (caps & expected_caps) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * SelectTxPowerScenario - Voice Call + */ +TEST_P(WifiChipAidlTest, SelectTxPowerScenario_voiceCall) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::VOICE_CALL); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * ResetTxPowerScenario + */ +TEST_P(WifiChipAidlTest, ResetTxPowerScenario) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + auto status = wifi_chip_->resetTxPowerScenario(); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * ConfigureChip + */ +TEST_P(WifiChipAidlTest, ConfigureChip) { + std::vector modes; + EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk()); + EXPECT_NE(modes.size(), 0); + for (const auto& mode : modes) { + // configureChip() requires a fresh IWifiChip object. + wifi_chip_ = getWifiChip(getInstanceName()); + ASSERT_NE(nullptr, wifi_chip_.get()); + EXPECT_TRUE(wifi_chip_->configureChip(mode.id).isOk()); + stopWifiService(getInstanceName()); + // Sleep for 5 milliseconds between each wifi state toggle. + usleep(5000); + } +} + +/* + * RequestChipDebugInfo + */ +TEST_P(WifiChipAidlTest, RequestChipDebugInfo) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + IWifiChip::ChipDebugInfo debug_info = {}; + EXPECT_TRUE(wifi_chip_->requestChipDebugInfo(&debug_info).isOk()); + EXPECT_NE(debug_info.driverDescription.size(), 0); + EXPECT_NE(debug_info.firmwareDescription.size(), 0); +} + +/* + * RequestFirmwareDebugDump + */ +TEST_P(WifiChipAidlTest, RequestFirmwareDebugDump) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + std::vector debug_dump; + auto status = wifi_chip_->requestFirmwareDebugDump(&debug_dump); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_FIRMWARE_DUMP)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * RequestDriverDebugDump + */ +TEST_P(WifiChipAidlTest, RequestDriverDebugDump) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + std::vector debug_dump; + auto status = wifi_chip_->requestDriverDebugDump(&debug_dump); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_DRIVER_DUMP)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * GetDebugRingBuffersStatus + */ +TEST_P(WifiChipAidlTest, GetDebugRingBuffersStatus) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + std::vector ring_buffer_status; + auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status); + if (hasAnyRingBufferCapabilities(caps)) { + EXPECT_TRUE(status.isOk()); + ASSERT_NE(ring_buffer_status.size(), 0); + for (const auto& ring_buffer : ring_buffer_status) { + EXPECT_NE(ring_buffer.ringName.size(), 0); + } + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * GetDebugHostWakeReasonStats + */ +TEST_P(WifiChipAidlTest, GetDebugHostWakeReasonStats) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + WifiDebugHostWakeReasonStats wake_reason_stats = {}; + auto status = wifi_chip_->getDebugHostWakeReasonStats(&wake_reason_stats); + if (caps & static_cast(IWifiChip::ChipCapabilityMask::DEBUG_HOST_WAKE_REASON_STATS)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * StartLoggingToDebugRingBuffer + */ +TEST_P(WifiChipAidlTest, StartLoggingToDebugRingBuffer) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + std::string ring_name; + std::vector ring_buffer_status; + auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status); + + if (hasAnyRingBufferCapabilities(caps)) { + EXPECT_TRUE(status.isOk()); + ASSERT_NE(ring_buffer_status.size(), 0); + ring_name = ring_buffer_status[0].ringName; + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } + + status = wifi_chip_->startLoggingToDebugRingBuffer( + ring_name, WifiDebugRingBufferVerboseLevel::VERBOSE, 5, 1024); + if (hasAnyRingBufferCapabilities(caps)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * ForceDumpToDebugRingBuffer + */ +TEST_P(WifiChipAidlTest, ForceDumpToDebugRingBuffer) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + int32_t caps = getChipCapabilities(wifi_chip_); + std::string ring_name; + std::vector ring_buffer_status; + auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status); + + if (hasAnyRingBufferCapabilities(caps)) { + EXPECT_TRUE(status.isOk()); + ASSERT_NE(ring_buffer_status.size(), 0); + ring_name = ring_buffer_status[0].ringName; + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } + + status = wifi_chip_->forceDumpToDebugRingBuffer(ring_name); + if (hasAnyRingBufferCapabilities(caps)) { + EXPECT_TRUE(status.isOk()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/* + * CreateStaIface + * Configures the chip in STA mode and creates an iface. + */ +TEST_P(WifiChipAidlTest, CreateStaIface) { + configureChipForStaAndGetIface(); +} + +/* + * CreateApIface + */ +TEST_P(WifiChipAidlTest, CreateApIface) { + configureChipForApAndGetIface(); +} + +/* + * CreateNanIface + */ +TEST_P(WifiChipAidlTest, CreateNanIface) { + configureChipForNanAndGetIface(); +} + +/* + * CreateP2pIface + */ +TEST_P(WifiChipAidlTest, CreateP2pIface) { + configureChipForNanAndGetIface(); +} + +/* + * GetStaIfaceNames + * Configures the chip in STA mode and ensures that the iface name list is + * empty before creating the iface. Then create the iface and ensure that + * iface name is returned in the iface name list. + */ +TEST_P(WifiChipAidlTest, GetStaIfaceNames) { + configureChipForConcurrencyType(IfaceConcurrencyType::STA); + + std::vector iface_names; + EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); + + std::shared_ptr iface; + EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk()); + ASSERT_NE(nullptr, iface.get()); + + std::string iface_name = getStaIfaceName(iface); + EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 1); + EXPECT_EQ(iface_name, iface_names[0]); + + EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk()); + EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); +} + +/* + * GetP2pIfaceNames + */ +TEST_P(WifiChipAidlTest, GetP2pIfaceNames) { + configureChipForConcurrencyType(IfaceConcurrencyType::P2P); + + std::vector iface_names; + EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); + + std::shared_ptr iface; + EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk()); + ASSERT_NE(nullptr, iface.get()); + + std::string iface_name = getP2pIfaceName(iface); + EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 1); + EXPECT_EQ(iface_name, iface_names[0]); + + EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk()); + EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); +} + +/* + * GetApIfaceNames + */ +TEST_P(WifiChipAidlTest, GetApIfaceNames) { + configureChipForConcurrencyType(IfaceConcurrencyType::AP); + + std::vector iface_names; + EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); + + std::shared_ptr iface; + EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk()); + ASSERT_NE(nullptr, iface.get()); + + std::string iface_name = getApIfaceName(iface); + EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 1); + EXPECT_EQ(iface_name, iface_names[0]); + + EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk()); + EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); +} + +/* + * GetNanIfaceNames + */ +TEST_P(WifiChipAidlTest, GetNanIfaceNames) { + configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE); + + std::vector iface_names; + EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); + + std::shared_ptr iface; + EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk()); + ASSERT_NE(nullptr, iface.get()); + + std::string iface_name = getNanIfaceName(iface); + EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 1); + EXPECT_EQ(iface_name, iface_names[0]); + + EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk()); + EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk()); + EXPECT_EQ(iface_names.size(), 0); +} + +/* + * GetStaIface + * Configures the chip in STA mode and creates an iface. Then retrieves + * the iface object using its name and ensures that any other name + * doesn't retrieve a valid iface object. + */ +TEST_P(WifiChipAidlTest, GetStaIface) { + std::shared_ptr iface = configureChipForStaAndGetIface(); + std::string iface_name = getStaIfaceName(iface); + + std::shared_ptr retrieved_iface; + EXPECT_TRUE(wifi_chip_->getStaIface(iface_name, &retrieved_iface).isOk()); + EXPECT_NE(nullptr, retrieved_iface.get()); + + std::string invalid_name = iface_name + "0"; + std::shared_ptr invalid_iface; + auto status = wifi_chip_->getStaIface(invalid_name, &invalid_iface); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_EQ(nullptr, invalid_iface.get()); +} + +/* + * GetP2pIface + */ +TEST_P(WifiChipAidlTest, GetP2pIface) { + std::shared_ptr iface = configureChipForP2pAndGetIface(); + std::string iface_name = getP2pIfaceName(iface); + + std::shared_ptr retrieved_iface; + EXPECT_TRUE(wifi_chip_->getP2pIface(iface_name, &retrieved_iface).isOk()); + EXPECT_NE(nullptr, retrieved_iface.get()); + + std::string invalid_name = iface_name + "0"; + std::shared_ptr invalid_iface; + auto status = wifi_chip_->getP2pIface(invalid_name, &invalid_iface); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_EQ(nullptr, invalid_iface.get()); +} + +/* + * GetApIface + */ +TEST_P(WifiChipAidlTest, GetApIface) { + std::shared_ptr iface = configureChipForApAndGetIface(); + std::string iface_name = getApIfaceName(iface); + + std::shared_ptr retrieved_iface; + EXPECT_TRUE(wifi_chip_->getApIface(iface_name, &retrieved_iface).isOk()); + EXPECT_NE(nullptr, retrieved_iface.get()); + + std::string invalid_name = iface_name + "0"; + std::shared_ptr invalid_iface; + auto status = wifi_chip_->getApIface(invalid_name, &invalid_iface); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_EQ(nullptr, invalid_iface.get()); +} + +/* + * GetNanIface + */ +TEST_P(WifiChipAidlTest, GetNanIface) { + std::shared_ptr iface = configureChipForNanAndGetIface(); + std::string iface_name = getNanIfaceName(iface); + + std::shared_ptr retrieved_iface; + EXPECT_TRUE(wifi_chip_->getNanIface(iface_name, &retrieved_iface).isOk()); + EXPECT_NE(nullptr, retrieved_iface.get()); + + std::string invalid_name = iface_name + "0"; + std::shared_ptr invalid_iface; + auto status = wifi_chip_->getNanIface(invalid_name, &invalid_iface); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_EQ(nullptr, invalid_iface.get()); +} + +/* + * RemoveStaIface + * Configures the chip in STA mode and creates an iface. Then removes + * the iface object using the correct name and ensures that any other + * name doesn't remove the iface. + */ +TEST_P(WifiChipAidlTest, RemoveStaIface) { + std::shared_ptr iface = configureChipForStaAndGetIface(); + std::string iface_name = getStaIfaceName(iface); + + std::string invalid_name = iface_name + "0"; + auto status = wifi_chip_->removeStaIface(invalid_name); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk()); + + // No such iface exists now, so this should return failure. + EXPECT_FALSE(wifi_chip_->removeStaIface(iface_name).isOk()); +} + +/* + * RemoveP2pIface + */ +TEST_P(WifiChipAidlTest, RemoveP2pIface) { + std::shared_ptr iface = configureChipForP2pAndGetIface(); + std::string iface_name = getP2pIfaceName(iface); + + std::string invalid_name = iface_name + "0"; + auto status = wifi_chip_->removeP2pIface(invalid_name); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk()); + + // No such iface exists now, so this should return failure. + EXPECT_FALSE(wifi_chip_->removeP2pIface(iface_name).isOk()); +} + +/* + * RemoveApIface + */ +TEST_P(WifiChipAidlTest, RemoveApIface) { + std::shared_ptr iface = configureChipForApAndGetIface(); + std::string iface_name = getApIfaceName(iface); + + std::string invalid_name = iface_name + "0"; + auto status = wifi_chip_->removeApIface(invalid_name); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk()); + + // No such iface exists now, so this should return failure. + EXPECT_FALSE(wifi_chip_->removeApIface(iface_name).isOk()); +} + +/* + * RemoveNanIface + */ +TEST_P(WifiChipAidlTest, RemoveNanIface) { + std::shared_ptr iface = configureChipForNanAndGetIface(); + std::string iface_name = getNanIfaceName(iface); + + std::string invalid_name = iface_name + "0"; + auto status = wifi_chip_->removeNanIface(invalid_name); + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk()); + + // No such iface exists now, so this should return failure. + EXPECT_FALSE(wifi_chip_->removeNanIface(iface_name).isOk()); +} + +/* + * CreateRttController + */ +TEST_P(WifiChipAidlTest, CreateRttController) { + std::shared_ptr iface = configureChipForStaAndGetIface(); + std::shared_ptr rtt_controller; + auto status = wifi_chip_->createRttController(iface, &rtt_controller); + if (status.isOk()) { + EXPECT_NE(nullptr, rtt_controller.get()); + } else { + EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + } +} + +/** + * CreateBridgedApIface & RemoveIfaceInstanceFromBridgedApIface + */ +TEST_P(WifiChipAidlTest, CreateBridgedApIfaceAndremoveIfaceInstanceFromBridgedApIfaceTest) { + bool isBridgedSupport = testing::checkSubstringInCommandOutput( + "/system/bin/cmd wifi get-softap-supported-features", + "wifi_softap_bridged_ap_supported"); + if (!isBridgedSupport) { + GTEST_SKIP() << "Missing Bridged AP support"; + } + + std::shared_ptr wifi_chip = getWifiChip(getInstanceName()); + ASSERT_NE(nullptr, wifi_chip.get()); + std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(wifi_chip); + ASSERT_NE(nullptr, wifi_ap_iface.get()); + + std::string br_name; + std::vector instances; + EXPECT_TRUE(wifi_ap_iface->getName(&br_name).isOk()); + EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk()); + EXPECT_EQ(instances.size(), 2); + + std::vector instances_after_remove; + EXPECT_TRUE(wifi_chip->removeIfaceInstanceFromBridgedApIface(br_name, instances[0]).isOk()); + EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances_after_remove).isOk()); + EXPECT_EQ(instances_after_remove.size(), 1); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest); +INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::ProcessState::self()->setThreadPoolMaxThreadCount(1); + android::ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp new file mode 100644 index 0000000000..457d57ad75 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_aidl_test_utils.h" + +using aidl::android::hardware::wifi::BnWifiNanIfaceEventCallback; +using aidl::android::hardware::wifi::IWifiNanIface; +using aidl::android::hardware::wifi::NanBandIndex; +using aidl::android::hardware::wifi::NanBandSpecificConfig; +using aidl::android::hardware::wifi::NanCapabilities; +using aidl::android::hardware::wifi::NanClusterEventInd; +using aidl::android::hardware::wifi::NanConfigRequest; +using aidl::android::hardware::wifi::NanConfigRequestSupplemental; +using aidl::android::hardware::wifi::NanDataPathConfirmInd; +using aidl::android::hardware::wifi::NanDataPathRequestInd; +using aidl::android::hardware::wifi::NanDataPathScheduleUpdateInd; +using aidl::android::hardware::wifi::NanDataPathSecurityType; +using aidl::android::hardware::wifi::NanEnableRequest; +using aidl::android::hardware::wifi::NanFollowupReceivedInd; +using aidl::android::hardware::wifi::NanInitiateDataPathRequest; +using aidl::android::hardware::wifi::NanMatchAlg; +using aidl::android::hardware::wifi::NanMatchInd; +using aidl::android::hardware::wifi::NanPublishRequest; +using aidl::android::hardware::wifi::NanPublishType; +using aidl::android::hardware::wifi::NanRespondToDataPathIndicationRequest; +using aidl::android::hardware::wifi::NanStatus; +using aidl::android::hardware::wifi::NanStatusCode; +using aidl::android::hardware::wifi::NanTxType; + +#define TIMEOUT_PERIOD 10 + +class WifiNanIfaceAidlTest : public testing::TestWithParam { + public: + void SetUp() override { + if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware")) + GTEST_SKIP() << "Skipping this test since NAN is not supported."; + stopWifiService(getInstanceName()); + + wifi_nan_iface_ = getWifiNanIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_nan_iface_.get()); + std::shared_ptr callback = + ndk::SharedRefBase::make(*this); + EXPECT_TRUE(wifi_nan_iface_->registerEventCallback(callback).isOk()); + } + + void TearDown() override { stopWifiService(getInstanceName()); } + + // Used as a mechanism to inform the test about data/event callbacks. + inline void notify() { + std::unique_lock lock(mtx_); + count_++; + cv_.notify_one(); + } + + enum CallbackType { + INVALID = -2, + ANY_CALLBACK = -1, + + NOTIFY_CAPABILITIES_RESPONSE = 0, + NOTIFY_ENABLE_RESPONSE, + NOTIFY_CONFIG_RESPONSE, + NOTIFY_DISABLE_RESPONSE, + NOTIFY_START_PUBLISH_RESPONSE, + NOTIFY_STOP_PUBLISH_RESPONSE, + NOTIFY_START_SUBSCRIBE_RESPONSE, + NOTIFY_STOP_SUBSCRIBE_RESPONSE, + NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE, + NOTIFY_CREATE_DATA_INTERFACE_RESPONSE, + NOTIFY_DELETE_DATA_INTERFACE_RESPONSE, + NOTIFY_INITIATE_DATA_PATH_RESPONSE, + NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE, + NOTIFY_TERMINATE_DATA_PATH_RESPONSE, + + EVENT_CLUSTER_EVENT, + EVENT_DISABLED, + EVENT_PUBLISH_TERMINATED, + EVENT_SUBSCRIBE_TERMINATED, + EVENT_MATCH, + EVENT_MATCH_EXPIRED, + EVENT_FOLLOWUP_RECEIVED, + EVENT_TRANSMIT_FOLLOWUP, + EVENT_DATA_PATH_REQUEST, + EVENT_DATA_PATH_CONFIRM, + EVENT_DATA_PATH_TERMINATED, + EVENT_DATA_PATH_SCHEDULE_UPDATE, + }; + + // Test code calls this function to wait for data/event callback. + // Must set callbackType = INVALID before calling this function. + inline std::cv_status wait(CallbackType waitForCallbackType) { + std::unique_lock lock(mtx_); + EXPECT_NE(INVALID, waitForCallbackType); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count_ == 0) { + status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) return status; + if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID && + callback_type_ != waitForCallbackType) { + count_--; + } + } + count_--; + return status; + } + + class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback { + public: + WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){}; + + ::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override { + parent_.callback_type_ = EVENT_CLUSTER_EVENT; + parent_.nan_cluster_event_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override { + parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM; + parent_.nan_data_path_confirm_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override { + parent_.callback_type_ = EVENT_DATA_PATH_REQUEST; + parent_.nan_data_path_request_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventDataPathScheduleUpdate( + const NanDataPathScheduleUpdateInd& event) override { + parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE; + parent_.nan_data_path_schedule_update_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override { + parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED; + parent_.ndp_instance_id_ = ndpInstanceId; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override { + parent_.callback_type_ = EVENT_DISABLED; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override { + parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED; + parent_.nan_followup_received_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override { + parent_.callback_type_ = EVENT_MATCH; + parent_.nan_match_ind_ = event; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override { + parent_.callback_type_ = EVENT_MATCH_EXPIRED; + parent_.session_id_ = discoverySessionId; + parent_.peer_id_ = peerId; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId, + const NanStatus& status) override { + parent_.callback_type_ = EVENT_PUBLISH_TERMINATED; + parent_.session_id_ = sessionId; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId, + const NanStatus& status) override { + parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED; + parent_.session_id_ = sessionId; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override { + parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyCapabilitiesResponse( + char16_t id, const NanStatus& status, + const NanCapabilities& capabilities) override { + parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.capabilities_ = capabilities; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status, + int32_t ndpInstanceId) override { + parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.ndp_instance_id_ = ndpInstanceId; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse( + char16_t id, const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status, + int8_t sessionId) override { + parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.session_id_ = sessionId; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status, + int8_t sessionId) override { + parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.session_id_ = sessionId; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id, + const NanStatus& status) override { + parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE; + parent_.id_ = id; + parent_.status_ = status; + parent_.notify(); + return ndk::ScopedAStatus::ok(); + } + + private: + WifiNanIfaceAidlTest& parent_; + }; + + protected: + std::shared_ptr wifi_nan_iface_; + CallbackType callback_type_; + uint16_t id_; + uint8_t session_id_; + uint32_t ndp_instance_id_; + uint32_t peer_id_; + NanCapabilities capabilities_; + NanClusterEventInd nan_cluster_event_ind_; + NanDataPathConfirmInd nan_data_path_confirm_ind_; + NanDataPathRequestInd nan_data_path_request_ind_; + NanDataPathScheduleUpdateInd nan_data_path_schedule_update_ind_; + NanFollowupReceivedInd nan_followup_received_ind_; + NanMatchInd nan_match_ind_; + NanStatus status_; + + const char* getInstanceName() { return GetParam().c_str(); } + + private: + // synchronization objects + std::mutex mtx_; + std::condition_variable cv_; + int count_ = 0; +}; + +/* + * FailOnIfaceInvalid + * Ensure that API calls to an interface fail with code ERROR_WIFI_IFACE_INVALID + * after wifi is disabled. + */ +TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) { + stopWifiService(getInstanceName()); + sleep(5); // Ensure that all chips/interfaces are invalidated. + auto status = wifi_nan_iface_->getCapabilitiesRequest(0); + ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_WIFI_IFACE_INVALID)); +} + +/* + * EnableRequest - Invalid Args + */ +TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) { + uint16_t inputCmdId = 10; + callback_type_ = INVALID; + NanEnableRequest nanEnableRequest = {}; + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + auto status = + wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp); + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(status.isOk()); + + // Wait for a callback. + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); + ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_EQ(id_, inputCmdId); + ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); + } +} + +/* + * ConfigRequest - Invalid Args + */ +TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) { + uint16_t inputCmdId = 10; + callback_type_ = INVALID; + NanConfigRequest nanConfigRequest = {}; + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + auto status = + wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp); + + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(status.isOk()); + + // Wait for a callback. + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE)); + ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_); + ASSERT_EQ(id_, inputCmdId); + ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS); + } +} + +/* + * EnableRequest - Invalid Args in Shim Conversion + */ +TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidShimArgs) { + uint16_t inputCmdId = 10; + NanEnableRequest nanEnableRequest = {}; + nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = -15; // must be > 0 + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + auto status = + wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp); + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + } +} + +/* + * ConfigRequest - Invalid Args in Shim Conversion + */ +TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) { + uint16_t inputCmdId = 10; + NanConfigRequest nanConfigRequest = {}; + nanConfigRequest.numberOfPublishServiceIdsInBeacon = -15; // must be > 0 + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + auto status = + wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp); + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS)); + } +} + +/* + * NotifyCapabilitiesResponse + */ +TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) { + uint16_t inputCmdId = 10; + callback_type_ = INVALID; + EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk()); + + // Wait for a callback. + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); + ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_); + ASSERT_EQ(id_, inputCmdId); + ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); + + // Check for reasonable capability values. + EXPECT_GT(capabilities_.maxConcurrentClusters, 0); + EXPECT_GT(capabilities_.maxPublishes, 0); + EXPECT_GT(capabilities_.maxSubscribes, 0); + EXPECT_EQ(capabilities_.maxServiceNameLen, 255); + EXPECT_EQ(capabilities_.maxMatchFilterLen, 255); + EXPECT_GT(capabilities_.maxTotalMatchFilterLen, 255); + EXPECT_EQ(capabilities_.maxServiceSpecificInfoLen, 255); + EXPECT_GE(capabilities_.maxExtendedServiceSpecificInfoLen, 255); + EXPECT_GT(capabilities_.maxNdiInterfaces, 0); + EXPECT_GT(capabilities_.maxNdpSessions, 0); + EXPECT_GT(capabilities_.maxAppInfoLen, 0); + EXPECT_GT(capabilities_.maxQueuedTransmitFollowupMsgs, 0); + EXPECT_GT(capabilities_.maxSubscribeInterfaceAddresses, 0); + EXPECT_NE(static_cast(capabilities_.supportedCipherSuites), 0); +} + +/* + * StartPublishRequest + */ +TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) { + uint16_t inputCmdId = 10; + NanBandSpecificConfig config24 = {}; + config24.rssiClose = 60; + config24.rssiMiddle = 70; + config24.rssiCloseProximity = 60; + config24.dwellTimeMs = 200; + config24.scanPeriodSec = 20; + config24.validDiscoveryWindowIntervalVal = false; + config24.discoveryWindowIntervalVal = 0; + + NanBandSpecificConfig config5 = {}; + config5.rssiClose = 60; + config5.rssiMiddle = 75; + config5.rssiCloseProximity = 60; + config5.dwellTimeMs = 200; + config5.scanPeriodSec = 20; + config5.validDiscoveryWindowIntervalVal = false; + config5.discoveryWindowIntervalVal = 0; + + NanEnableRequest req = {}; + req.operateInBand[static_cast(NanBandIndex::NAN_BAND_24GHZ)] = true; + req.operateInBand[static_cast(NanBandIndex::NAN_BAND_5GHZ)] = false; + req.hopCountMax = 2; + req.configParams.masterPref = 0; + req.configParams.disableDiscoveryAddressChangeIndication = true; + req.configParams.disableStartedClusterIndication = true; + req.configParams.disableJoinedClusterIndication = true; + req.configParams.includePublishServiceIdsInBeacon = true; + req.configParams.numberOfPublishServiceIdsInBeacon = 0; + req.configParams.includeSubscribeServiceIdsInBeacon = true; + req.configParams.numberOfSubscribeServiceIdsInBeacon = 0; + req.configParams.rssiWindowSize = 8; + req.configParams.macAddressRandomizationIntervalSec = 1800; + req.configParams.bandSpecificConfig[static_cast(NanBandIndex::NAN_BAND_24GHZ)] = + config24; + req.configParams.bandSpecificConfig[static_cast(NanBandIndex::NAN_BAND_5GHZ)] = + config5; + + req.debugConfigs.validClusterIdVals = true; + req.debugConfigs.clusterIdTopRangeVal = 65535; + req.debugConfigs.clusterIdBottomRangeVal = 0; + req.debugConfigs.validIntfAddrVal = false; + req.debugConfigs.validOuiVal = false; + req.debugConfigs.ouiVal = 0; + req.debugConfigs.validRandomFactorForceVal = false; + req.debugConfigs.randomFactorForceVal = 0; + req.debugConfigs.validHopCountForceVal = false; + req.debugConfigs.hopCountForceVal = 0; + req.debugConfigs.validDiscoveryChannelVal = false; + req.debugConfigs.discoveryChannelMhzVal[static_cast(NanBandIndex::NAN_BAND_24GHZ)] = 0; + req.debugConfigs.discoveryChannelMhzVal[static_cast(NanBandIndex::NAN_BAND_5GHZ)] = 0; + req.debugConfigs.validUseBeaconsInBandVal = false; + req.debugConfigs.useBeaconsInBandVal[static_cast(NanBandIndex::NAN_BAND_24GHZ)] = true; + req.debugConfigs.useBeaconsInBandVal[static_cast(NanBandIndex::NAN_BAND_5GHZ)] = true; + req.debugConfigs.validUseSdfInBandVal = false; + req.debugConfigs.useSdfInBandVal[static_cast(NanBandIndex::NAN_BAND_24GHZ)] = true; + req.debugConfigs.useSdfInBandVal[static_cast(NanBandIndex::NAN_BAND_5GHZ)] = true; + + NanConfigRequestSupplemental nanConfigRequestSupp = {}; + nanConfigRequestSupp.discoveryBeaconIntervalMs = 20; + nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0; + nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false; + + callback_type_ = INVALID; + auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp); + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(status.isOk()); + + // Wait for a callback. + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE)); + ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_); + ASSERT_EQ(id_, inputCmdId); + ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); + } + + NanPublishRequest nanPublishRequest = {}; + nanPublishRequest.baseConfigs.sessionId = 0; + nanPublishRequest.baseConfigs.ttlSec = 0; + nanPublishRequest.baseConfigs.discoveryWindowPeriod = 1; + nanPublishRequest.baseConfigs.discoveryCount = 0; + nanPublishRequest.baseConfigs.serviceName = {97}; + nanPublishRequest.baseConfigs.discoveryMatchIndicator = NanMatchAlg::MATCH_NEVER; + nanPublishRequest.baseConfigs.useRssiThreshold = false; + nanPublishRequest.baseConfigs.disableDiscoveryTerminationIndication = false; + nanPublishRequest.baseConfigs.disableMatchExpirationIndication = true; + nanPublishRequest.baseConfigs.disableFollowupReceivedIndication = false; + nanPublishRequest.baseConfigs.securityConfig.securityType = NanDataPathSecurityType::OPEN; + nanPublishRequest.autoAcceptDataPathRequests = false; + nanPublishRequest.publishType = NanPublishType::UNSOLICITED; + nanPublishRequest.txType = NanTxType::BROADCAST; + + status = wifi_nan_iface_->startPublishRequest(inputCmdId + 1, nanPublishRequest); + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_TRUE(status.isOk()); + + // Wait for a callback. + ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE)); + ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_); + ASSERT_EQ(id_, inputCmdId + 1); + ASSERT_EQ(status_.status, NanStatusCode::SUCCESS); + } +} + +/* + * RespondToDataPathIndicationRequest - Invalid Args + */ +TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) { + uint16_t inputCmdId = 10; + callback_type_ = INVALID; + NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {}; + nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong"; + auto status = wifi_nan_iface_->respondToDataPathIndicationRequest( + inputCmdId, nanRespondToDataPathIndicationRequest); + + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_EQ(status.getServiceSpecificError(), + static_cast(WifiStatusCode::ERROR_INVALID_ARGS)); + } +} + +/* + * InitiateDataPathRequest - Invalid Args + */ +TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) { + uint16_t inputCmdId = 10; + callback_type_ = INVALID; + NanInitiateDataPathRequest nanInitiateDataPathRequest = {}; + nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong"; + auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest); + + if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + ASSERT_EQ(status.getServiceSpecificError(), + static_cast(WifiStatusCode::ERROR_INVALID_ARGS)); + } +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceAidlTest); +INSTANTIATE_TEST_SUITE_P(WifiTest, WifiNanIfaceAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::ProcessState::self()->setThreadPoolMaxThreadCount(1); + android::ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp new file mode 100644 index 0000000000..d763fe64a5 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_aidl_test_utils.h" + +using aidl::android::hardware::wifi::BnWifiRttControllerEventCallback; +using aidl::android::hardware::wifi::IWifiRttController; +using aidl::android::hardware::wifi::RttBw; +using aidl::android::hardware::wifi::RttCapabilities; +using aidl::android::hardware::wifi::RttConfig; +using aidl::android::hardware::wifi::RttPeerType; +using aidl::android::hardware::wifi::RttPreamble; +using aidl::android::hardware::wifi::RttResponder; +using aidl::android::hardware::wifi::RttResult; +using aidl::android::hardware::wifi::RttType; +using aidl::android::hardware::wifi::WifiChannelInfo; +using aidl::android::hardware::wifi::WifiChannelWidthInMhz; +using aidl::android::hardware::wifi::WifiStatusCode; + +class WifiRttControllerAidlTest : public testing::TestWithParam { + public: + void SetUp() override { + if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt")) + GTEST_SKIP() << "Skipping this test since RTT is not supported."; + stopWifiService(getInstanceName()); + wifi_rtt_controller_ = getWifiRttController(); + ASSERT_NE(nullptr, wifi_rtt_controller_.get()); + + // Check RTT support before we run the test. + RttCapabilities caps = {}; + auto status = wifi_rtt_controller_->getCapabilities(&caps); + if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) { + GTEST_SKIP() << "Skipping this test since RTT is not supported."; + } + } + + void TearDown() override { stopWifiService(getInstanceName()); } + + protected: + std::shared_ptr getWifiRttController() { + std::shared_ptr wifi_chip = getWifiChip(getInstanceName()); + EXPECT_NE(nullptr, wifi_chip.get()); + + std::shared_ptr wifi_sta_iface = getWifiStaIface(getInstanceName()); + EXPECT_NE(nullptr, wifi_sta_iface.get()); + + std::shared_ptr rtt_controller; + EXPECT_TRUE(wifi_chip->createRttController(wifi_sta_iface, &rtt_controller).isOk()); + EXPECT_NE(nullptr, rtt_controller.get()); + return rtt_controller; + } + + std::shared_ptr wifi_rtt_controller_; + + private: + const char* getInstanceName() { return GetParam().c_str(); } +}; + +class WifiRttControllerEventCallback : public BnWifiRttControllerEventCallback { + public: + WifiRttControllerEventCallback() = default; + + ::ndk::ScopedAStatus onResults(int /* cmdId */, + const std::vector& /* results */) override { + return ndk::ScopedAStatus::ok(); + } +}; + +/* + * RegisterEventCallback + * + * Note: it is not feasible to test the invocation of the callback function, + * since events are triggered internally in the HAL implementation and cannot be + * triggered from the test case. + */ +TEST_P(WifiRttControllerAidlTest, RegisterEventCallback) { + std::shared_ptr callback = + ndk::SharedRefBase::make(); + ASSERT_NE(nullptr, callback.get()); + EXPECT_TRUE(wifi_rtt_controller_->registerEventCallback(callback).isOk()); +} + +/* + * GetCapabilities + */ +TEST_P(WifiRttControllerAidlTest, GetCapabilities) { + RttCapabilities caps = {}; + EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk()); +} + +/* + * GetResponderInfo + */ +TEST_P(WifiRttControllerAidlTest, GetResponderInfo) { + RttResponder responder = {}; + EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk()); +} + +/* + * EnableResponder + */ +TEST_P(WifiRttControllerAidlTest, EnableResponder) { + int cmdId = 55; + WifiChannelInfo channelInfo; + channelInfo.width = WifiChannelWidthInMhz::WIDTH_80; + channelInfo.centerFreq = 5660; + channelInfo.centerFreq0 = 5660; + channelInfo.centerFreq1 = 0; + + RttResponder responder = {}; + EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk()); + EXPECT_TRUE(wifi_rtt_controller_->enableResponder(cmdId, channelInfo, 10, responder).isOk()); +} + +/* + * Request2SidedRangeMeasurement + * Tests the two sided ranging - 802.11mc FTM protocol. + */ +TEST_P(WifiRttControllerAidlTest, Request2SidedRangeMeasurement) { + RttCapabilities caps = {}; + EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk()); + if (!caps.rttFtmSupported) { + GTEST_SKIP() << "Skipping two sided RTT since driver/fw does not support"; + } + + RttConfig config; + config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}}; + config.type = RttType::TWO_SIDED; + config.peer = RttPeerType::AP; + config.channel.width = WifiChannelWidthInMhz::WIDTH_80; + config.channel.centerFreq = 5180; + config.channel.centerFreq0 = 5210; + config.channel.centerFreq1 = 0; + config.bw = RttBw::BW_20MHZ; + config.preamble = RttPreamble::HT; + config.mustRequestLci = false; + config.mustRequestLcr = false; + config.burstPeriod = 0; + config.numBurst = 0; + config.numFramesPerBurst = 8; + config.numRetriesPerRttFrame = 0; + config.numRetriesPerFtmr = 0; + config.burstDuration = 9; + + int cmdId = 55; + std::vector configs = {config}; + EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk()); + + // Sleep for 2 seconds to wait for driver/firmware to complete RTT. + sleep(2); +} + +/* + * RangeRequest + */ +TEST_P(WifiRttControllerAidlTest, RangeRequest) { + RttCapabilities caps = {}; + EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk()); + if (!caps.rttOneSidedSupported) { + GTEST_SKIP() << "Skipping one sided RTT since driver/fw does not support"; + } + + // Get the highest supported preamble. + int preamble = 1; + int caps_preamble_support = static_cast(caps.preambleSupport); + caps_preamble_support >>= 1; + while (caps_preamble_support != 0) { + caps_preamble_support >>= 1; + preamble <<= 1; + } + + RttConfig config; + config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}}; + config.type = RttType::ONE_SIDED; + config.peer = RttPeerType::AP; + config.channel.width = WifiChannelWidthInMhz::WIDTH_80; + config.channel.centerFreq = 5765; + config.channel.centerFreq0 = 5775; + config.channel.centerFreq1 = 0; + config.bw = RttBw::BW_80MHZ; + config.preamble = static_cast(preamble); + config.mustRequestLci = false; + config.mustRequestLcr = false; + config.burstPeriod = 0; + config.numBurst = 0; + config.numFramesPerBurst = 8; + config.numRetriesPerRttFrame = 3; + config.numRetriesPerFtmr = 3; + config.burstDuration = 9; + + int cmdId = 55; + std::vector configs = {config}; + EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk()); + + // Sleep for 2 seconds to wait for driver/firmware to complete RTT. + sleep(2); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerAidlTest); +INSTANTIATE_TEST_SUITE_P(WifiTest, WifiRttControllerAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::ProcessState::self()->setThreadPoolMaxThreadCount(1); + android::ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp new file mode 100644 index 0000000000..ef7e2747c9 --- /dev/null +++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Staache 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wifi_aidl_test_utils.h" + +using aidl::android::hardware::wifi::IWifi; +using aidl::android::hardware::wifi::IWifiStaIface; +using aidl::android::hardware::wifi::MacAddress; +using aidl::android::hardware::wifi::Ssid; +using aidl::android::hardware::wifi::StaApfPacketFilterCapabilities; +using aidl::android::hardware::wifi::StaBackgroundScanCapabilities; +using aidl::android::hardware::wifi::StaLinkLayerStats; +using aidl::android::hardware::wifi::StaRoamingCapabilities; +using aidl::android::hardware::wifi::StaRoamingConfig; +using aidl::android::hardware::wifi::StaRoamingState; +using aidl::android::hardware::wifi::WifiBand; +using aidl::android::hardware::wifi::WifiDebugRxPacketFateReport; +using aidl::android::hardware::wifi::WifiDebugTxPacketFateReport; +using aidl::android::hardware::wifi::WifiStatusCode; + +class WifiStaIfaceAidlTest : public testing::TestWithParam { + public: + void SetUp() override { + stopWifiService(getInstanceName()); + wifi_sta_iface_ = getWifiStaIface(getInstanceName()); + ASSERT_NE(nullptr, wifi_sta_iface_.get()); + } + + void TearDown() override { stopWifiService(getInstanceName()); } + + protected: + bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask expected) { + IWifiStaIface::StaIfaceCapabilityMask caps = {}; + EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk()); + return static_cast(caps) & static_cast(expected); + } + + ndk::ScopedAStatus createStaIface(std::shared_ptr* sta_iface) { + std::shared_ptr wifi_chip = getWifiChip(getInstanceName()); + EXPECT_NE(nullptr, wifi_chip.get()); + return wifi_chip->createStaIface(sta_iface); + } + + std::shared_ptr wifi_sta_iface_; + + private: + const char* getInstanceName() { return GetParam().c_str(); } +}; + +/* + * GetFactoryMacAddress + * Ensures that calls to getFactoryMacAddress will retrieve a non-zero MAC. + */ +TEST_P(WifiStaIfaceAidlTest, GetFactoryMacAddress) { + std::array mac; + EXPECT_TRUE(wifi_sta_iface_->getFactoryMacAddress(&mac).isOk()); + std::array all_zero_mac = {0, 0, 0, 0, 0, 0}; + EXPECT_NE(mac, all_zero_mac); +} + +/* + * GetCapabilities + */ +TEST_P(WifiStaIfaceAidlTest, GetCapabilities) { + IWifiStaIface::StaIfaceCapabilityMask caps = {}; + EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk()); + EXPECT_NE(static_cast(caps), 0); +} + +/* + * GetApfPacketFilterCapabilities + */ +TEST_P(WifiStaIfaceAidlTest, GetApfPacketFilterCapabilities) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) { + GTEST_SKIP() << "APF packet filter capabilities are not supported."; + } + StaApfPacketFilterCapabilities apf_caps = {}; + EXPECT_TRUE(wifi_sta_iface_->getApfPacketFilterCapabilities(&apf_caps).isOk()); +} + +/* + * GetBackgroundScanCapabilities + */ +TEST_P(WifiStaIfaceAidlTest, GetBackgroundScanCapabilities) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) { + GTEST_SKIP() << "Background scan capabilities are not supported."; + } + StaBackgroundScanCapabilities caps = {}; + EXPECT_TRUE(wifi_sta_iface_->getBackgroundScanCapabilities(&caps).isOk()); +} + +/* + * GetValidFrequenciesForBand + * Ensures that we can retrieve valid frequencies for the 2.4 GHz band. + */ +TEST_P(WifiStaIfaceAidlTest, GetValidFrequenciesForBand) { + std::vector freqs; + EXPECT_TRUE(wifi_sta_iface_->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk()); + EXPECT_NE(freqs.size(), 0); +} + +/* + * GetLinkLayerStats + * Ensures that calls to getLinkLayerStats will retrieve a non-empty + * StaLinkLayerStats after link layer stats collection is enabled. + */ +TEST_P(WifiStaIfaceAidlTest, GetLinkLayerStats) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { + GTEST_SKIP() << "Skipping this test since link layer stats are not supported."; + } + + // Enable link layer stats collection. + EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk()); + + // Retrieve link layer stats. + StaLinkLayerStats link_layer_stats = {}; + EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk()); + EXPECT_GT(link_layer_stats.timeStampInMs, 0); + + // Try to create a 2nd iface. If successful, it should fill the duty cycle field. + std::shared_ptr iface; + auto status = createStaIface(&iface); + if (status.isOk()) { + EXPECT_GT(link_layer_stats.iface.timeSliceDutyCycleInPercent, 0); + } + + // Disable link layer stats collection. + EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk()); +} + +/* + * SetMacAddress + * Ensures that calls to setMacAddress will return successfully. + */ +TEST_P(WifiStaIfaceAidlTest, SetMacAddress) { + std::array mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x41}; + EXPECT_TRUE(wifi_sta_iface_->setMacAddress(mac).isOk()); +} + +/* + * SetScanMode + */ +TEST_P(WifiStaIfaceAidlTest, SetScanMode) { + auto status = wifi_sta_iface_->setScanMode(true); + EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); + + status = wifi_sta_iface_->setScanMode(false); + EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)); +} + +/* + * LinkLayerStatsCollection + */ +TEST_P(WifiStaIfaceAidlTest, LinkLayerStatsCollection) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) { + GTEST_SKIP() << "Link layer stats collection is not supported."; + } + + // Enable link layer stats collection. + EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk()); + + // Retrieve link layer stats. + StaLinkLayerStats link_layer_stats = {}; + EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk()); + + // Disable link layer stats collection. + EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk()); +} + +/* + * RSSIMonitoring + * Ensures that calls to startRssiMonitoring and stopRssiMonitoring will fail + * if the device is not connected to an AP. + */ +TEST_P(WifiStaIfaceAidlTest, RSSIMonitoring) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) { + GTEST_SKIP() << "RSSI monitoring is not supported."; + } + + const int cmd = 1; + const int maxRssi = -50; + const int minRssi = -90; + // Expected to fail because device is not connected to an AP. + EXPECT_FALSE(wifi_sta_iface_->startRssiMonitoring(cmd, maxRssi, minRssi).isOk()); + EXPECT_FALSE(wifi_sta_iface_->stopRssiMonitoring(cmd).isOk()); +} + +/* + * RoamingControl + */ +TEST_P(WifiStaIfaceAidlTest, RoamingControl) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) { + GTEST_SKIP() << "Roaming control is not supported."; + } + + // Retrieve roaming capabilities. + StaRoamingCapabilities caps = {}; + EXPECT_TRUE(wifi_sta_iface_->getRoamingCapabilities(&caps).isOk()); + + // Set up roaming configuration based on roaming capabilities. + StaRoamingConfig roaming_config = {}; + if (caps.maxBlocklistSize > 0) { + MacAddress block_list_entry; + block_list_entry.data = std::array{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}}; + roaming_config.bssidBlocklist = {block_list_entry}; + } + if (caps.maxAllowlistSize > 0) { + Ssid allow_list_entry = {}; + allow_list_entry.data = std::array{{0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}}; + roaming_config.ssidAllowlist = {allow_list_entry}; + } + + // Configure roaming. + EXPECT_TRUE(wifi_sta_iface_->configureRoaming(roaming_config).isOk()); + + // Enable roaming. + EXPECT_TRUE(wifi_sta_iface_->setRoamingState(StaRoamingState::ENABLED).isOk()); +} + +/* + * EnableNDOffload + */ +TEST_P(WifiStaIfaceAidlTest, EnableNDOffload) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) { + GTEST_SKIP() << "ND offload is not supported."; + } + EXPECT_TRUE(wifi_sta_iface_->enableNdOffload(true).isOk()); +} + +/* + * PacketFateMonitoring + */ +TEST_P(WifiStaIfaceAidlTest, PacketFateMonitoring) { + if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) { + GTEST_SKIP() << "Packet fate monitoring is not supported."; + } + + // Start packet fate monitoring. + EXPECT_TRUE(wifi_sta_iface_->startDebugPacketFateMonitoring().isOk()); + + // Retrieve packets. + std::vector rx_reports; + std::vector tx_reports; + EXPECT_TRUE(wifi_sta_iface_->getDebugRxPacketFates(&rx_reports).isOk()); + EXPECT_TRUE(wifi_sta_iface_->getDebugTxPacketFates(&tx_reports).isOk()); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceAidlTest); +INSTANTIATE_TEST_SUITE_P(WifiTest, WifiStaIfaceAidlTest, + testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)), + android::PrintInstanceNameToString); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + android::ProcessState::self()->setThreadPoolMaxThreadCount(1); + android::ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +}