/* * 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 #include "aidl_return_util.h" #include "aidl_struct_util.h" #include "wifi_legacy_hal.h" #include "wifi_status_util.h" #define P2P_MGMT_DEVICE_PREFIX "p2p-dev-" namespace { using android::base::unique_fd; 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 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, bool using_dynamic_iface_combination) : 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), using_dynamic_iface_combination_(using_dynamic_iface_combination), subsystemCallbackHandler_(handler) { setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue); } void WifiChip::retrieveDynamicIfaceCombination() { if (using_dynamic_iface_combination_) return; legacy_hal::wifi_iface_concurrency_matrix legacy_matrix; legacy_hal::wifi_error legacy_status; std::tie(legacy_status, legacy_matrix) = legacy_hal_.lock()->getSupportedIfaceConcurrencyMatrix(); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get SupportedIfaceCombinations matrix from legacy HAL: " << legacyErrorToString(legacy_status); return; } IWifiChip::ChipMode aidl_chip_mode; if (!aidl_struct_util::convertLegacyIfaceCombinationsMatrixToChipMode(legacy_matrix, &aidl_chip_mode)) { LOG(ERROR) << "Failed convertLegacyIfaceCombinationsMatrixToChipMode() "; return; } LOG(INFO) << "Reloading iface concurrency combination from driver"; aidl_chip_mode.id = feature_flags::chip_mode_ids::kV3; modes_.clear(); modes_.push_back(aidl_chip_mode); using_dynamic_iface_combination_ = true; } 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, bool using_dynamic_iface_combination) { std::shared_ptr ptr = ndk::SharedRefBase::make( chip_id, is_primary, legacy_hal, mode_controller, iface_util, feature_flags, handler, using_dynamic_iface_combination); 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::getFeatureSet(int32_t* _aidl_return) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getFeatureSetInternal, _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::createApOrBridgedApIface( IfaceConcurrencyType in_ifaceType, const std::vector& in_vendorData, std::shared_ptr* _aidl_return) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::createApOrBridgedApIfaceInternal, _aidl_return, in_ifaceType, in_vendorData); } 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 __unused, 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"; } 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, int32_t 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, int32_t in_ifaceModeMask, int32_t 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::setAfcChannelAllowance( const AfcChannelAllowance& afcChannelAllowance) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::setAfcChannelAllowanceInternal, afcChannelAllowance); } ndk::ScopedAStatus WifiChip::triggerSubsystemRestart() { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::triggerSubsystemRestartInternal); } ndk::ScopedAStatus WifiChip::getSupportedRadioCombinations( std::vector* _aidl_return) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getSupportedRadioCombinationsInternal, _aidl_return); } ndk::ScopedAStatus WifiChip::getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getWifiChipCapabilitiesInternal, _aidl_return); } ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetwork(int32_t in_channelCategoryEnableFlag) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::enableStaChannelForPeerNetworkInternal, in_channelCategoryEnableFlag); } ndk::ScopedAStatus WifiChip::setMloMode(const ChipMloMode in_mode) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::setMloModeInternal, in_mode); } ndk::ScopedAStatus WifiChip::setVoipMode(const VoipMode in_mode) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::setVoipModeInternal, in_mode); } 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::getFeatureSetInternal() { 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 {0, 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_feature_set; if (!aidl_struct_util::convertLegacyChipFeaturesToAidl(legacy_feature_set, &aidl_feature_set)) { return {0, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; } return {aidl_feature_set, 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(); 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); return {iface, ndk::ScopedAStatus::ok()}; } std::pair, ndk::ScopedAStatus> WifiChip::createApOrBridgedApIfaceInternal( IfaceConcurrencyType ifaceType, const std::vector& /* vendorData */) { if (ifaceType == IfaceConcurrencyType::AP) { return createApIfaceInternal(); } else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) { return createBridgedApIfaceInternal(); } else { return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; } } 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); deleteApIface(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 = WifiStaIface::create(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, int32_t aidl_restrictions) { std::vector legacy_unsafe_channels; if (!aidl_struct_util::convertAidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels, &legacy_unsafe_channels)) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } 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, int32_t ifaceModeMask, int32_t 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(ifaceModeMask), aidl_struct_util::convertAidlUsableChannelFilterToLegacy(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()}; } ndk::ScopedAStatus WifiChip::setAfcChannelAllowanceInternal( const AfcChannelAllowance& afcChannelAllowance) { LOG(INFO) << "setAfcChannelAllowance is not yet supported. availableAfcFrequencyInfos size=" << afcChannelAllowance.availableAfcFrequencyInfos.size() << " availableAfcChannelInfos size=" << afcChannelAllowance.availableAfcChannelInfos.size() << " availabilityExpireTimeMs=" << afcChannelAllowance.availabilityExpireTimeMs; return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED); } std::pair, ndk::ScopedAStatus> WifiChip::getSupportedRadioCombinationsInternal() { legacy_hal::wifi_error legacy_status; legacy_hal::wifi_radio_combination_matrix* legacy_matrix; std::vector aidl_combinations; 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); if (legacy_matrix != nullptr) { free(legacy_matrix); } return {aidl_combinations, createWifiStatusFromLegacyError(legacy_status)}; } if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, &aidl_combinations)) { LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() "; if (legacy_matrix != nullptr) { free(legacy_matrix); } return {aidl_combinations, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; } if (legacy_matrix != nullptr) { free(legacy_matrix); } return {aidl_combinations, ndk::ScopedAStatus::ok()}; } std::pair WifiChip::getWifiChipCapabilitiesInternal() { legacy_hal::wifi_error legacy_status; legacy_hal::wifi_chip_capabilities legacy_chip_capabilities; std::tie(legacy_status, legacy_chip_capabilities) = legacy_hal_.lock()->getWifiChipCapabilities(); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to get chip capabilities from legacy HAL: " << legacyErrorToString(legacy_status); return {WifiChipCapabilities(), createWifiStatusFromLegacyError(legacy_status)}; } WifiChipCapabilities aidl_chip_capabilities; if (!aidl_struct_util::convertLegacyWifiChipCapabilitiesToAidl(legacy_chip_capabilities, aidl_chip_capabilities)) { LOG(ERROR) << "Failed convertLegacyWifiChipCapabilitiesToAidl() "; return {WifiChipCapabilities(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)}; } return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()}; } ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetworkInternal( int32_t channelCategoryEnableFlag) { auto legacy_status = legacy_hal_.lock()->enableStaChannelForPeerNetwork( aidl_struct_util::convertAidlChannelCategoryToLegacy(channelCategoryEnableFlag)); return createWifiStatusFromLegacyError(legacy_status); } 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()); } // Get the driver supported interface combination. retrieveDynamicIfaceCombination(); 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::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); } iface_util_->deleteBridge(if_name); br_ifaces_ap_instances_.erase(if_name); // ifname is bridged AP, return here. return; } } // No bridged AP case, delete AP iface legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(if_name); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to remove interface: " << if_name << " " << legacyErrorToString(legacy_status); } } 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; } ndk::ScopedAStatus WifiChip::setMloModeInternal(const WifiChip::ChipMloMode in_mode) { legacy_hal::wifi_mlo_mode mode; switch (in_mode) { case WifiChip::ChipMloMode::DEFAULT: mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_DEFAULT; break; case WifiChip::ChipMloMode::LOW_LATENCY: mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_LOW_LATENCY; break; case WifiChip::ChipMloMode::HIGH_THROUGHPUT: mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_HIGH_THROUGHPUT; break; case WifiChip::ChipMloMode::LOW_POWER: mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_LOW_POWER; break; default: PLOG(ERROR) << "Error: invalid mode: " << toString(in_mode); return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } return createWifiStatusFromLegacyError(legacy_hal_.lock()->setMloMode(mode)); } ndk::ScopedAStatus WifiChip::setVoipModeInternal(const WifiChip::VoipMode in_mode) { const auto ifname = getFirstActiveWlanIfaceName(); wifi_voip_mode mode; switch (in_mode) { case WifiChip::VoipMode::VOICE: mode = wifi_voip_mode::WIFI_VOIP_MODE_VOICE; break; case WifiChip::VoipMode::OFF: mode = wifi_voip_mode::WIFI_VOIP_MODE_OFF; break; default: PLOG(ERROR) << "Error: invalid mode: " << toString(in_mode); return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } return createWifiStatusFromLegacyError(legacy_hal_.lock()->setVoipMode(ifname, mode)); } } // namespace wifi } // namespace hardware } // namespace android } // namespace aidl