diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl new file mode 100644 index 0000000000..50e1bbbc3c --- /dev/null +++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/ApIfaceParams.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.wifi; +@VintfStability +parcelable ApIfaceParams { + android.hardware.wifi.IfaceConcurrencyType ifaceType; + boolean usesMlo; + @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData; +} diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl index e71dde40fd..af95bee7b9 100644 --- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl +++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiApIface.aidl @@ -40,4 +40,5 @@ interface IWifiApIface { void setCountryCode(in byte[2] code); void resetToFactoryMacAddress(); void setMacAddress(in byte[6] mac); + boolean usesMlo(); } diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl index 5fe7c53830..1af0d659a8 100644 --- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl +++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl @@ -35,7 +35,13 @@ package android.hardware.wifi; @VintfStability interface IWifiChip { void configureChip(in int modeId); + /** + * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams. + */ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApIface(); + /** + * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams. + */ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createBridgedApIface(); @PropagateAllowBlocking android.hardware.wifi.IWifiNanIface createNanIface(); @PropagateAllowBlocking android.hardware.wifi.IWifiP2pIface createP2pIface(); @@ -83,8 +89,12 @@ interface IWifiChip { void triggerSubsystemRestart(); void enableStaChannelForPeerNetwork(in int channelCategoryEnableFlag); void setMloMode(in android.hardware.wifi.IWifiChip.ChipMloMode mode); + /** + * @deprecated This method is deprecated from AIDL v3, newer HALs should use createApOrBridgedApIfaceWithParams. + */ @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIface(in android.hardware.wifi.IfaceConcurrencyType iface, in android.hardware.wifi.common.OuiKeyedData[] vendorData); void setVoipMode(in android.hardware.wifi.IWifiChip.VoipMode mode); + @PropagateAllowBlocking android.hardware.wifi.IWifiApIface createApOrBridgedApIfaceWithParams(in android.hardware.wifi.ApIfaceParams params); const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF; @Backing(type="int") @VintfStability enum FeatureSetMask { diff --git a/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl new file mode 100644 index 0000000000..f075b72cea --- /dev/null +++ b/wifi/aidl/android/hardware/wifi/ApIfaceParams.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 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 android.hardware.wifi; + +import android.hardware.wifi.IfaceConcurrencyType; +import android.hardware.wifi.common.OuiKeyedData; + +/** + * Parameters to use for setting up the access point interfaces. + */ +@VintfStability +parcelable ApIfaceParams { + /** + * IfaceConcurrencyType to be created. Takes one of + * |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED| + */ + IfaceConcurrencyType ifaceType; + /** + * Whether the current iface will be operated on Multi-links on the one MLD device (MLO). + */ + boolean usesMlo; + /** + * Optional vendor-specific configuration parameters. + */ + @nullable OuiKeyedData[] vendorData; +} diff --git a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl index b14a8005b5..a350e527f5 100644 --- a/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl +++ b/wifi/aidl/android/hardware/wifi/IWifiApIface.aidl @@ -85,4 +85,11 @@ interface IWifiApIface { * |WifiStatusCode.ERROR_UNKNOWN| */ void setMacAddress(in byte[6] mac); + + /** + * Check if ApIface is for an AP using Multi-Link Operation + * + * @return true if it is MLO iface, false otherwise. + */ + boolean usesMlo(); } diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl index 4e418d86e5..04f31d25d4 100644 --- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl +++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl @@ -17,6 +17,7 @@ package android.hardware.wifi; import android.hardware.wifi.AfcChannelAllowance; +import android.hardware.wifi.ApIfaceParams; import android.hardware.wifi.IWifiApIface; import android.hardware.wifi.IWifiChipEventCallback; import android.hardware.wifi.IWifiNanIface; @@ -433,6 +434,9 @@ interface IWifiChip { * reached the maximum allowed (specified in |ChipIfaceCombination|) number * of ifaces of the AP type. * + * @deprecated This method is deprecated from AIDL v3, newer HALs should use + * createApOrBridgedApIfaceWithParams. + * * @return AIDL interface object representing the iface if * successful, null otherwise. * @throws ServiceSpecificException with one of the following values: @@ -450,6 +454,9 @@ interface IWifiChip { * reached the maximum allowed (specified in |ChipIfaceCombination|) number * of ifaces of the AP type. * + * @deprecated This method is deprecated from AIDL v3, newer HALs should use + * createApOrBridgedApIfaceWithParams. + * * @return AIDL interface object representing the iface if * successful, null otherwise. * @throws ServiceSpecificException with one of the following values: @@ -1177,6 +1184,9 @@ interface IWifiChip { * reached the maximum allowed (specified in |ChipIfaceCombination|) number * of ifaces of the AP or AP_BRIDGED type. * + * @deprecated This method is deprecated from AIDL v3, newer HALs should use + * createApOrBridgedApIfaceWithParams. + * * @param iface IfaceConcurrencyType to be created. Takes one of |IfaceConcurrencyType.AP| or |IfaceConcurrencyType.AP_BRIDGED| * @param vendorData Vendor-provided configuration data as a list of |OuiKeyedData|. @@ -1210,4 +1220,22 @@ interface IWifiChip { * |WifiStatusCode.ERROR_UNKNOWN| */ void setVoipMode(in VoipMode mode); + + /** + * Create an AP or bridged AP iface on the chip based on ApIfaceParamss. + * + * Depending on the mode the chip is configured in, the interface creation + * may fail (code: |WifiStatusCode.ERROR_NOT_AVAILABLE|) if we've already + * reached the maximum allowed (specified in |ChipIfaceCombination|) number + * of ifaces of the AP type. + * + * @return AIDL interface object representing the iface if + * successful, null otherwise. + * @throws ServiceSpecificException with one of the following values: + * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|, + * |WifiStatusCode.ERROR_NOT_SUPPORTED|, + * |WifiStatusCode.ERROR_NOT_AVAILABLE| + */ + @PropagateAllowBlocking + IWifiApIface createApOrBridgedApIfaceWithParams(in ApIfaceParams params); } diff --git a/wifi/aidl/default/wifi_ap_iface.cpp b/wifi/aidl/default/wifi_ap_iface.cpp index 77797502d3..6a73cc821f 100644 --- a/wifi/aidl/default/wifi_ap_iface.cpp +++ b/wifi/aidl/default/wifi_ap_iface.cpp @@ -28,10 +28,12 @@ namespace hardware { namespace wifi { using aidl_return_util::validateAndCall; -WifiApIface::WifiApIface(const std::string& ifname, const std::vector& instances, +WifiApIface::WifiApIface(const std::string& ifname, const bool usesMlo, + const std::vector& instances, const std::weak_ptr legacy_hal, const std::weak_ptr iface_util) : ifname_(ifname), + uses_mlo_(usesMlo), instances_(instances), legacy_hal_(legacy_hal), iface_util_(iface_util), @@ -50,6 +52,10 @@ std::string WifiApIface::getName() { return ifname_; } +bool WifiApIface::usesMlo() { + return uses_mlo_; +} + void WifiApIface::removeInstance(std::string instance) { instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end()); } @@ -72,7 +78,7 @@ ndk::ScopedAStatus WifiApIface::setMacAddress(const std::array& in_m 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_); + getOperatingInstanceName()); } ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() { @@ -90,14 +96,14 @@ std::pair WifiApIface::getNameInternal() { } 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); + legacy_hal::wifi_error legacy_status = + legacy_hal_.lock()->setCountryCode(getOperatingInstanceName(), code); return createWifiStatusFromLegacyError(legacy_status); } ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array& mac) { // Support random MAC up to 2 interfaces - if (instances_.size() == 2) { + if (instances_.size() == 2 && !uses_mlo_) { int rbyte = 1; for (auto const& intf : instances_) { std::array rmac = mac; @@ -131,7 +137,7 @@ std::pair, ndk::ScopedAStatus> WifiApIface::getFactoryMac ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() { std::pair, ndk::ScopedAStatus> getMacResult; - if (instances_.size() == 2) { + if (instances_.size() == 2 && !uses_mlo_) { for (auto const& intf : instances_) { getMacResult = getFactoryMacAddressInternal(intf); LOG(DEBUG) << "Reset MAC to factory MAC on " << intf; @@ -166,6 +172,11 @@ std::pair, ndk::ScopedAStatus> WifiApIface::getBridgedI return {instances_, ndk::ScopedAStatus::ok()}; } +ndk::ScopedAStatus WifiApIface::usesMlo(bool* _aidl_return) { + *_aidl_return = uses_mlo_; + return ndk::ScopedAStatus::ok(); +} + } // namespace wifi } // namespace hardware } // namespace android diff --git a/wifi/aidl/default/wifi_ap_iface.h b/wifi/aidl/default/wifi_ap_iface.h index 7378f98acf..e07154db14 100644 --- a/wifi/aidl/default/wifi_ap_iface.h +++ b/wifi/aidl/default/wifi_ap_iface.h @@ -33,13 +33,15 @@ namespace wifi { */ class WifiApIface : public BnWifiApIface { public: - WifiApIface(const std::string& ifname, const std::vector& instances, + WifiApIface(const std::string& ifname, const bool usesMlo, + 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(); + bool usesMlo(); void removeInstance(std::string instance); // AIDL methods exposed. @@ -49,6 +51,7 @@ class WifiApIface : public BnWifiApIface { ndk::ScopedAStatus getFactoryMacAddress(std::array* _aidl_return) override; ndk::ScopedAStatus resetToFactoryMacAddress() override; ndk::ScopedAStatus getBridgedInstances(std::vector* _aidl_return) override; + ndk::ScopedAStatus usesMlo(bool* _aidl_return) override; private: // Corresponding worker functions for the AIDL methods. @@ -61,11 +64,18 @@ class WifiApIface : public BnWifiApIface { std::pair, ndk::ScopedAStatus> getBridgedInstancesInternal(); std::string ifname_; + bool uses_mlo_; std::vector instances_; std::weak_ptr legacy_hal_; std::weak_ptr iface_util_; bool is_valid_; + // The mlo is using one interface but owning two link instances. + // The operating should be based on interface. + inline std::string getOperatingInstanceName() { + return (instances_.size() > 0 && !uses_mlo_) ? instances_[0] : ifname_; + }; + DISALLOW_COPY_AND_ASSIGN(WifiApIface); }; diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp index fccfc15859..045e07d43e 100644 --- a/wifi/aidl/default/wifi_chip.cpp +++ b/wifi/aidl/default/wifi_chip.cpp @@ -369,7 +369,7 @@ ndk::ScopedAStatus WifiChip::createApIface(std::shared_ptr* _aidl_ ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr* _aidl_return) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, - &WifiChip::createBridgedApIfaceInternal, _aidl_return); + &WifiChip::createBridgedApIfaceInternal, _aidl_return, false); } ndk::ScopedAStatus WifiChip::createApOrBridgedApIface( @@ -613,6 +613,13 @@ ndk::ScopedAStatus WifiChip::setVoipMode(const VoipMode in_mode) { &WifiChip::setVoipModeInternal, in_mode); } +ndk::ScopedAStatus WifiChip::createApOrBridgedApIfaceWithParams( + const ApIfaceParams& in_params, std::shared_ptr* _aidl_return) { + return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, + &WifiChip::createApOrBridgedApIfaceWithParamsInternal, _aidl_return, + in_params); +} + void WifiChip::invalidateAndRemoveAllIfaces() { invalidateAndClearBridgedApAll(); invalidateAndClearAll(ap_ifaces_); @@ -797,15 +804,15 @@ ndk::ScopedAStatus WifiChip::createVirtualApInterface(const std::string& apVirtI return ndk::ScopedAStatus::ok(); } -std::shared_ptr WifiChip::newWifiApIface(std::string& ifname) { +std::shared_ptr WifiChip::newWifiApIface(std::string& ifname, bool usesMlo) { 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_); + std::shared_ptr iface = ndk::SharedRefBase::make( + ifname, usesMlo, 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()) { @@ -826,47 +833,60 @@ std::pair, ndk::ScopedAStatus> WifiChip::createApI if (!status.isOk()) { return {std::shared_ptr(), std::move(status)}; } - std::shared_ptr iface = newWifiApIface(ifname); + std::shared_ptr iface = newWifiApIface(ifname, false); return {iface, ndk::ScopedAStatus::ok()}; } -std::pair, ndk::ScopedAStatus> -WifiChip::createBridgedApIfaceInternal() { +std::pair, ndk::ScopedAStatus> WifiChip::createBridgedApIfaceInternal( + bool usesMlo) { if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) { return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; } - std::vector ap_instances = allocateBridgedApInstanceNames(); + std::string br_ifname; + std::vector ap_instances = allocateBridgedApInstanceNames(usesMlo); 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. + if (usesMlo) { + // MLO SoftAp is using single interface with two links. So only need to create 1 interface. + br_ifname = allocateApIfaceName(); + } else { + 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)}; } - 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(); - deleteApIface(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(); + if (usesMlo) { + ndk::ScopedAStatus status = createVirtualApInterface(br_ifname); + if (!status.isOk()) { + return {nullptr, std::move(status)}; + } + } else { + if (!iface_util_->createBridge(br_ifname)) { + LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str(); deleteApIface(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(); + deleteApIface(br_ifname); + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)}; + } + } } - std::shared_ptr iface = newWifiApIface(br_ifname); + std::shared_ptr iface = newWifiApIface(br_ifname, usesMlo); return {iface, ndk::ScopedAStatus::ok()}; } @@ -876,7 +896,18 @@ WifiChip::createApOrBridgedApIfaceInternal( if (ifaceType == IfaceConcurrencyType::AP) { return createApIfaceInternal(); } else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) { - return createBridgedApIfaceInternal(); + return createBridgedApIfaceInternal(false); + } else { + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; + } +} + +std::pair, ndk::ScopedAStatus> +WifiChip::createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params) { + if (params.ifaceType == IfaceConcurrencyType::AP) { + return createApIfaceInternal(); + } else if (params.ifaceType == IfaceConcurrencyType::AP_BRIDGED) { + return createBridgedApIfaceInternal(params.usesMlo); } else { return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; } @@ -925,23 +956,28 @@ ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal( 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); + for (auto const& instance : ap_instances) { + if (instance == ifInstanceName) { + if (iface->usesMlo()) { + LOG(INFO) << "Remove Link " << ifInstanceName << " from " << ifname; + } else { + if (!iface_util_->removeIfaceFromBridge(it.first, instance)) { + 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(instance); + if (legacy_status != legacy_hal::WIFI_SUCCESS) { + LOG(ERROR) << "Failed to del interface: " << instance << " " + << legacyErrorToString(legacy_status); + return createWifiStatusFromLegacyError(legacy_status); + } } ap_instances.erase( std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName), @@ -1729,7 +1765,7 @@ std::string WifiChip::getFirstActiveWlanIfaceName() { // 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()) { + if (it.first == ap_ifaces_[0]->getName() && !ap_ifaces_[0]->usesMlo()) { return it.second[0]; } } @@ -1782,9 +1818,19 @@ std::string WifiChip::allocateApIfaceName() { return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface()); } -std::vector WifiChip::allocateBridgedApInstanceNames() { - // Check if we have a dedicated iface for AP. - std::vector instances = getPredefinedApIfaceNames(true); +std::vector WifiChip::allocateBridgedApInstanceNames(bool usesMlo) { + std::vector instances; + if (usesMlo) { + // For MLO AP, the instances are MLO links and it will be maintained in hostapd. + // The hostapd will use 0 as an initial link id and 1 as the next. + // Considering Android didn't support link reconfiguration. Forcing to use 0 & 1 + // should work. + instances.push_back("0"); + instances.push_back("1"); + } else { + // Check if we have a dedicated iface for AP. + instances = getPredefinedApIfaceNames(true); + } if (instances.size() == 2) { return instances; } else { @@ -1856,11 +1902,14 @@ std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned 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); + const auto iface = findUsingName(ap_ifaces_, it.first); + if (!iface->usesMlo()) { + for (auto const& iface : it.second) { + iface_util_->removeIfaceFromBridge(it.first, iface); + legacy_hal_.lock()->deleteVirtualInterface(iface); + } + iface_util_->deleteBridge(it.first); } - iface_util_->deleteBridge(it.first); } br_ifaces_ap_instances_.clear(); } @@ -1868,16 +1917,19 @@ void WifiChip::invalidateAndClearBridgedApAll() { void WifiChip::deleteApIface(const std::string& if_name) { if (if_name.empty()) return; // delete bridged interfaces if any - for (auto const& it : br_ifaces_ap_instances_) { - if (it.first == if_name) { - for (auto const& iface : it.second) { - iface_util_->removeIfaceFromBridge(if_name, iface); - legacy_hal_.lock()->deleteVirtualInterface(iface); + const auto iface = findUsingName(ap_ifaces_, if_name); + if (!iface->usesMlo()) { + for (auto const& it : br_ifaces_ap_instances_) { + if (it.first == if_name) { + for (auto const& instance : it.second) { + iface_util_->removeIfaceFromBridge(if_name, instance); + legacy_hal_.lock()->deleteVirtualInterface(instance); + } + iface_util_->deleteBridge(if_name); + br_ifaces_ap_instances_.erase(if_name); + // ifname is bridged AP, return here. + return; } - iface_util_->deleteBridge(if_name); - br_ifaces_ap_instances_.erase(if_name); - // ifname is bridged AP, return here. - return; } } diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h index ffd507f801..24dd00d2fd 100644 --- a/wifi/aidl/default/wifi_chip.h +++ b/wifi/aidl/default/wifi_chip.h @@ -159,6 +159,8 @@ class WifiChip : public BnWifiChip { binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; ndk::ScopedAStatus setMloMode(const ChipMloMode in_mode) override; ndk::ScopedAStatus setVoipMode(const VoipMode in_mode) override; + ndk::ScopedAStatus createApOrBridgedApIfaceWithParams( + const ApIfaceParams& in_params, std::shared_ptr* _aidl_return) override; private: void invalidateAndRemoveAllIfaces(); @@ -178,12 +180,15 @@ class WifiChip : public BnWifiChip { std::pair requestChipDebugInfoInternal(); std::pair, ndk::ScopedAStatus> requestDriverDebugDumpInternal(); std::pair, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal(); - std::shared_ptr newWifiApIface(std::string& ifname); + std::shared_ptr newWifiApIface(std::string& ifname, bool usesMlo); ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf); std::pair, ndk::ScopedAStatus> createApIfaceInternal(); - std::pair, ndk::ScopedAStatus> createBridgedApIfaceInternal(); + std::pair, ndk::ScopedAStatus> createBridgedApIfaceInternal( + bool usesMlo); std::pair, ndk::ScopedAStatus> createApOrBridgedApIfaceInternal( IfaceConcurrencyType ifaceType, const std::vector& vendorData); + std::pair, ndk::ScopedAStatus> + createApOrBridgedApIfaceWithParamsInternal(const ApIfaceParams& params); std::pair, ndk::ScopedAStatus> getApIfaceNamesInternal(); std::pair, ndk::ScopedAStatus> getApIfaceInternal( const std::string& ifname); @@ -258,7 +263,7 @@ class WifiChip : public BnWifiChip { std::string getFirstActiveWlanIfaceName(); std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx); std::string allocateApIfaceName(); - std::vector allocateBridgedApInstanceNames(); + std::vector allocateBridgedApInstanceNames(bool usesMlo); std::string allocateStaIfaceName(); bool writeRingbufferFilesInternal(); std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx); diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl index 8da3441d9f..7b67102337 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl @@ -39,5 +39,5 @@ parcelable IfaceParams { android.hardware.wifi.hostapd.ChannelParams[] channelParams; @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData; @nullable String[] instanceIdentities; - boolean isMlo; + boolean usesMlo; } diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl index bb646e308d..f4e464770c 100644 --- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl +++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl @@ -46,7 +46,7 @@ parcelable IfaceParams { */ @nullable String[] instanceIdentities; /** - * Whether the current iface is MLO. + * Whether the current iface is using multi-link operation. */ - boolean isMlo; + boolean usesMlo; }