diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp index 7928328489..22359e956c 100644 --- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp +++ b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp @@ -700,6 +700,72 @@ TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) { }); } +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + InvalidateAndRemoveNanOnStaRemove) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + + // Create NAN iface + ASSERT_EQ(createIface(IfaceType::NAN), "wlan0"); + + // We should have 1 nan iface. + chip_->getNanIfaceNames( + [](const WifiStatus& status, const hidl_vec& iface_names) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + ASSERT_EQ(iface_names.size(), 1u); + ASSERT_EQ(iface_names[0], "wlan0"); + }); + // Retrieve the exact iface object. + sp nan_iface; + chip_->getNanIface("wlan0", [&nan_iface](const WifiStatus& status, + const sp& iface) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + ASSERT_NE(iface.get(), nullptr); + nan_iface = iface; + }); + + // Remove the STA iface. + removeIface(IfaceType::STA, "wlan0"); + // We should have 0 nan iface now. + chip_->getNanIfaceNames( + [](const WifiStatus& status, const hidl_vec& iface_names) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + ASSERT_EQ(iface_names.size(), 0u); + }); + // Any operation on the nan iface object should return error now. + nan_iface->getName( + [](const WifiStatus& status, const std::string& /* iface_name */) { + ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code); + }); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + InvalidateAndRemoveRttControllerOnStaRemove) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_EQ(createIface(IfaceType::STA), "wlan0"); + + // Create RTT controller + sp rtt_controller; + chip_->createRttController( + NULL, [&rtt_controller](const WifiStatus& status, + const sp& rtt) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(rtt.get(), nullptr); + rtt_controller = rtt; + } + }); + + // Remove the STA iface. + removeIface(IfaceType::STA, "wlan0"); + + // Any operation on the rtt controller object should return error now. + rtt_controller->getBoundIface( + [](const WifiStatus& status, const sp& /* iface */) { + ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, + status.code); + }); +} + ////////// V1 Iface Combinations when AP creation is disabled ////////// class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest { public: @@ -732,6 +798,7 @@ TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, ASSERT_TRUE(createIface(IfaceType::AP).empty()); } +////////// Hypothetical Iface Combination with multiple ifaces ////////// class WifiChip_MultiIfaceTest : public WifiChipTest { public: void SetUp() override { diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp index b768959f2a..6c2fd678da 100644 --- a/wifi/1.3/default/wifi_chip.cpp +++ b/wifi/1.3/default/wifi_chip.cpp @@ -634,6 +634,27 @@ void WifiChip::invalidateAndRemoveAllIfaces() { rtt_controllers_.clear(); } +void WifiChip::invalidateAndRemoveDependencies( + const std::string& removed_iface_name) { + for (const auto& nan_iface : nan_ifaces_) { + if (nan_iface->getName() == removed_iface_name) { + invalidateAndClear(nan_ifaces_, nan_iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback + ->onIfaceRemoved(IfaceType::NAN, removed_iface_name) + .isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; + } + } + } + } + for (const auto& rtt : rtt_controllers_) { + if (rtt->getIfaceName() == removed_iface_name) { + invalidateAndClear(rtt_controllers_, rtt); + } + } +} + std::pair WifiChip::getIdInternal() { return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_}; } @@ -819,6 +840,11 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& 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); invalidateAndClear(ap_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) { @@ -835,7 +861,7 @@ std::pair> WifiChip::createNanIfaceInternal() { } // These are still assumed to be based on wlan0. std::string ifname = getFirstActiveWlanIfaceName(); - sp iface = new WifiNanIface(ifname, legacy_hal_); + sp iface = new WifiNanIface(ifname, legacy_hal_, iface_util_); nan_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { @@ -960,6 +986,8 @@ WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } + // Invalidate & remove any dependent objects first. + invalidateAndRemoveDependencies(ifname); invalidateAndClear(sta_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) { diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h index 3d12f4c9b7..d5ae900247 100644 --- a/wifi/1.3/default/wifi_chip.h +++ b/wifi/1.3/default/wifi_chip.h @@ -155,6 +155,9 @@ class WifiChip : public V1_3::IWifiChip { 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 HIDL methods. std::pair getIdInternal(); diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.3/default/wifi_iface_util.cpp index 5d61271410..7042af0b87 100644 --- a/wifi/1.3/default/wifi_iface_util.cpp +++ b/wifi/1.3/default/wifi_iface_util.cpp @@ -39,7 +39,8 @@ namespace V1_3 { namespace implementation { namespace iface_util { -WifiIfaceUtil::WifiIfaceUtil() : random_mac_address_(nullptr) {} +WifiIfaceUtil::WifiIfaceUtil() + : random_mac_address_(nullptr), event_handlers_map_() {} std::array WifiIfaceUtil::getFactoryMacAddress( const std::string& iface_name) { @@ -60,6 +61,14 @@ bool WifiIfaceUtil::setMacAddress(const std::string& iface_name, LOG(ERROR) << "SetUpState(true) failed."; return false; } + 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); + } LOG(DEBUG) << "Successfully SetMacAddress."; return true; } @@ -73,6 +82,16 @@ std::array WifiIfaceUtil::getOrCreateRandomMacAddress() { 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; diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.3/default/wifi_iface_util.h index b2382344ed..325fbe8390 100644 --- a/wifi/1.3/default/wifi_iface_util.h +++ b/wifi/1.3/default/wifi_iface_util.h @@ -28,6 +28,13 @@ namespace V1_3 { namespace implementation { 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. */ @@ -45,11 +52,17 @@ class WifiIfaceUtil { // 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); + private: std::array createRandomMacAddress(); wifi_system::InterfaceTool iface_tool_; std::unique_ptr> random_mac_address_; + std::map event_handlers_map_; }; } // namespace iface_util diff --git a/wifi/1.3/default/wifi_nan_iface.cpp b/wifi/1.3/default/wifi_nan_iface.cpp index 4325f44dad..ff9f4224df 100644 --- a/wifi/1.3/default/wifi_nan_iface.cpp +++ b/wifi/1.3/default/wifi_nan_iface.cpp @@ -30,8 +30,12 @@ using hidl_return_util::validateAndCall; WifiNanIface::WifiNanIface( const std::string& ifname, - const std::weak_ptr legacy_hal) - : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) { + 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) { // 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. @@ -498,6 +502,26 @@ WifiNanIface::WifiNanIface( 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.promote(); + 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. + WifiNanStatus status = { + NanStatusType::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::invalidate() { @@ -505,7 +529,7 @@ void WifiNanIface::invalidate() { 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(); event_cb_handler_1_2_.invalidate(); diff --git a/wifi/1.3/default/wifi_nan_iface.h b/wifi/1.3/default/wifi_nan_iface.h index f735d61cf9..737be93217 100644 --- a/wifi/1.3/default/wifi_nan_iface.h +++ b/wifi/1.3/default/wifi_nan_iface.h @@ -22,6 +22,7 @@ #include #include "hidl_callback_util.h" +#include "wifi_iface_util.h" #include "wifi_legacy_hal.h" namespace android { @@ -37,7 +38,8 @@ using namespace android::hardware::wifi::V1_0; class WifiNanIface : public V1_2::IWifiNanIface { public: WifiNanIface(const std::string& ifname, - const std::weak_ptr legacy_hal); + const std::weak_ptr legacy_hal, + const std::weak_ptr iface_util); // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); @@ -147,6 +149,7 @@ class WifiNanIface : public V1_2::IWifiNanIface { std::string ifname_; std::weak_ptr legacy_hal_; + std::weak_ptr iface_util_; bool is_valid_; hidl_callback_util::HidlCallbackHandler event_cb_handler_; diff --git a/wifi/1.3/default/wifi_rtt_controller.cpp b/wifi/1.3/default/wifi_rtt_controller.cpp index fa317e3aeb..3dcbee687b 100644 --- a/wifi/1.3/default/wifi_rtt_controller.cpp +++ b/wifi/1.3/default/wifi_rtt_controller.cpp @@ -49,6 +49,8 @@ WifiRttController::getEventCallbacks() { return event_callbacks_; } +std::string WifiRttController::getIfaceName() { return ifname_; } + Return WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) { return validateAndCall( this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID, diff --git a/wifi/1.3/default/wifi_rtt_controller.h b/wifi/1.3/default/wifi_rtt_controller.h index 9798b79f8d..eedd22aeef 100644 --- a/wifi/1.3/default/wifi_rtt_controller.h +++ b/wifi/1.3/default/wifi_rtt_controller.h @@ -42,6 +42,7 @@ class WifiRttController : public V1_0::IWifiRttController { void invalidate(); bool isValid(); std::vector> getEventCallbacks(); + std::string getIfaceName(); // HIDL methods exposed. Return getBoundIface(getBoundIface_cb hidl_status_cb) override;