/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "wificond/server.h" #include // for std::find_if #include #include #include #include #include #include #include "wificond/logging_utils.h" #include "wificond/net/netlink_utils.h" #include "wificond/scanning/scan_utils.h" using android::base::WriteStringToFd; using android::binder::Status; using android::sp; using android::IBinder; using android::net::wifi::nl80211::IApInterface; using android::net::wifi::nl80211::IClientInterface; using android::net::wifi::nl80211::IInterfaceEventCallback; using android::net::wifi::nl80211::DeviceWiphyCapabilities; using android::net::wifi::nl80211::IWificondEventCallback; using android::wifi_system::InterfaceTool; using std::endl; using std::optional; using std::placeholders::_1; using std::placeholders::_2; using std::string; using std::stringstream; using std::unique_ptr; using std::vector; namespace android { namespace wificond { namespace { constexpr const char* kPermissionDump = "android.permission.DUMP"; } // namespace Server::Server(unique_ptr if_tool, NetlinkUtils* netlink_utils, ScanUtils* scan_utils) : if_tool_(std::move(if_tool)), netlink_utils_(netlink_utils), scan_utils_(scan_utils) { } Status Server::registerWificondEventCallback(const sp& callback) { for (const auto& it : wificond_event_callbacks_) { if (IInterface::asBinder(callback) == IInterface::asBinder(it)) { LOG(WARNING) << "Ignore duplicate wificond event callback registration"; return Status::ok(); } } LOG(INFO) << "New wificond event callback registered"; wificond_event_callbacks_.push_back(callback); return Status::ok(); } Status Server::unregisterWificondEventCallback(const sp& callback) { for (auto it = wificond_event_callbacks_.begin(); it != wificond_event_callbacks_.end(); it++) { if (IInterface::asBinder(callback) == IInterface::asBinder(*it)) { wificond_event_callbacks_.erase(it); LOG(INFO) << "Unregister interface event callback"; return Status::ok(); } } LOG(WARNING) << "Failed to find registered wificond event callback" << " to unregister"; return Status::ok(); } Status Server::RegisterCallback(const sp& callback) { for (auto& it : interface_event_callbacks_) { if (IInterface::asBinder(callback) == IInterface::asBinder(it)) { LOG(WARNING) << "Ignore duplicate interface event callback registration"; return Status::ok(); } } LOG(INFO) << "New interface event callback registered"; interface_event_callbacks_.push_back(callback); return Status::ok(); } Status Server::UnregisterCallback(const sp& callback) { for (auto it = interface_event_callbacks_.begin(); it != interface_event_callbacks_.end(); it++) { if (IInterface::asBinder(callback) == IInterface::asBinder(*it)) { interface_event_callbacks_.erase(it); LOG(INFO) << "Unregister interface event callback"; return Status::ok(); } } LOG(WARNING) << "Failed to find registered interface event callback" << " to unregister"; return Status::ok(); } Status Server::createApInterface(const std::string& iface_name, sp* created_interface) { InterfaceInfo interface; uint32_t wiphy_index; if (!SetupInterface(iface_name, &interface, &wiphy_index)) { return Status::ok(); // Logging was done internally } LOG(INFO) << "createApInterface: wiphy_index " << wiphy_index << " iface_name " << iface_name; unique_ptr ap_interface(new ApInterfaceImpl( interface.name, interface.if_index, netlink_utils_, if_tool_.get())); *created_interface = ap_interface->GetBinder(); BroadcastApInterfaceReady(ap_interface->GetBinder()); ap_interfaces_[iface_name] = std::move(ap_interface); if (hasNoIfaceForWiphyIndex(wiphy_index)) { UpdateBandWiphyIndexMap(wiphy_index); } else { LOG(INFO) << "Band info for wiphy_index " << wiphy_index << " already available"; } iface_to_wiphy_index_map_[iface_name] = wiphy_index; return Status::ok(); } Status Server::tearDownApInterface(const std::string& iface_name, bool* out_success) { *out_success = false; const auto iter = ap_interfaces_.find(iface_name); if (iter != ap_interfaces_.end()) { BroadcastApInterfaceTornDown(iter->second->GetBinder()); ap_interfaces_.erase(iter); *out_success = true; } const auto iter_wi = iface_to_wiphy_index_map_.find(iface_name); if (iter_wi != iface_to_wiphy_index_map_.end()) { int wiphy_index = iter_wi->second; LOG(INFO) << "tearDownApInterface: erasing wiphy_index for iface_name " << iface_name; iface_to_wiphy_index_map_.erase(iter_wi); if (hasNoIfaceForWiphyIndex(wiphy_index)) { EraseBandWiphyIndexMap(wiphy_index); } else { LOG(INFO) << "Band info for wiphy_index " << wiphy_index << " retained"; } } return Status::ok(); } bool Server::hasNoIfaceForWiphyIndex(int wiphy_index) { return std::find_if( iface_to_wiphy_index_map_.begin(), iface_to_wiphy_index_map_.end(), [wiphy_index](const auto& kv) { return kv.second == wiphy_index; }) == iface_to_wiphy_index_map_.end(); } Status Server::createClientInterface(const std::string& iface_name, sp* created_interface) { InterfaceInfo interface; uint32_t wiphy_index; if (!SetupInterface(iface_name, &interface, &wiphy_index)) { return Status::ok(); // Logging was done internally } LOG(INFO) << "createClientInterface: wiphy_index " << wiphy_index << " iface_name " << iface_name; unique_ptr client_interface(new ClientInterfaceImpl( wiphy_index, interface.name, interface.if_index, interface.mac_address, if_tool_.get(), netlink_utils_, scan_utils_)); *created_interface = client_interface->GetBinder(); BroadcastClientInterfaceReady(client_interface->GetBinder()); client_interfaces_[iface_name] = std::move(client_interface); if (hasNoIfaceForWiphyIndex(wiphy_index)) { UpdateBandWiphyIndexMap(wiphy_index); } else { LOG(INFO) << "Band info for wiphy_index " << wiphy_index << " already available"; } iface_to_wiphy_index_map_[iface_name] = wiphy_index; return Status::ok(); } Status Server::tearDownClientInterface(const std::string& iface_name, bool* out_success) { *out_success = false; const auto iter = client_interfaces_.find(iface_name); if (iter != client_interfaces_.end()) { BroadcastClientInterfaceTornDown(iter->second->GetBinder()); client_interfaces_.erase(iter); *out_success = true; } const auto iter_wi = iface_to_wiphy_index_map_.find(iface_name); if (iter_wi != iface_to_wiphy_index_map_.end()) { int wiphy_index = iter_wi->second; LOG(INFO) << "tearDownClientInterface: erasing wiphy_index for iface_name " << iface_name; iface_to_wiphy_index_map_.erase(iter_wi); if (hasNoIfaceForWiphyIndex(wiphy_index)) { EraseBandWiphyIndexMap(wiphy_index); } else { LOG(INFO) << "Band info for wiphy_index " << wiphy_index << " retained"; } } return Status::ok(); } Status Server::tearDownInterfaces() { for (auto& it : client_interfaces_) { BroadcastClientInterfaceTornDown(it.second->GetBinder()); } client_interfaces_.clear(); for (auto& it : ap_interfaces_) { BroadcastApInterfaceTornDown(it.second->GetBinder()); } ap_interfaces_.clear(); MarkDownAllInterfaces(); for (auto& it : iface_to_wiphy_index_map_) { netlink_utils_->UnsubscribeRegDomainChange(it.second); EraseBandWiphyIndexMap(it.second); } iface_to_wiphy_index_map_.clear(); return Status::ok(); } Status Server::GetClientInterfaces(vector>* out_client_interfaces) { vector> client_interfaces_binder; for (auto& it : client_interfaces_) { out_client_interfaces->push_back(asBinder(it.second->GetBinder())); } return binder::Status::ok(); } Status Server::GetApInterfaces(vector>* out_ap_interfaces) { vector> ap_interfaces_binder; for (auto& it : ap_interfaces_) { out_ap_interfaces->push_back(asBinder(it.second->GetBinder())); } return binder::Status::ok(); } status_t Server::dump(int fd, const Vector& /*args*/) { if (!PermissionCache::checkCallingPermission(String16(kPermissionDump))) { IPCThreadState* ipc = android::IPCThreadState::self(); LOG(ERROR) << "Caller (uid: " << ipc->getCallingUid() << ") is not permitted to dump wificond state"; return PERMISSION_DENIED; } stringstream ss; ss << "Cached interfaces list from kernel message: " << endl; for (const auto& iface : debug_interfaces_) { ss << "Interface index: " << iface.if_index << ", name: " << iface.name << ", wiphy index: " << iface.wiphy_index << ", mac address: " << LoggingUtils::GetMacString(iface.mac_address) << endl; } string country_code; if (netlink_utils_->GetCountryCode(&country_code)) { ss << "Current country code from kernel: " << country_code << endl; } else { ss << "Failed to get country code from kernel." << endl; } for (const auto& iface : client_interfaces_) { iface.second->Dump(&ss); } for (const auto& iface : ap_interfaces_) { iface.second->Dump(&ss); } ss << "Channel Type / Wiphy Index Mapping:" << endl; for (const auto& it : band_to_wiphy_index_map_) { ss << "Channel type " << it.first << ": " << it.second << endl; } if (!WriteStringToFd(ss.str(), fd)) { PLOG(ERROR) << "Failed to dump state to fd " << fd; return FAILED_TRANSACTION; } return OK; } void Server::MarkDownAllInterfaces() { std::string iface_name; for (auto& it : iface_to_wiphy_index_map_) { iface_name = it.first; if_tool_->SetUpState(iface_name.c_str(), false); } } Status Server::getAvailable2gChannels( std::optional>* out_frequencies) { int wiphy_index = GetWiphyIndexFromBand(NL80211_BAND_2GHZ); BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) { out_frequencies->reset(); return Status::ok(); } if (band_info.band_2g.size() == 0) out_frequencies->reset(); else out_frequencies->emplace(band_info.band_2g.begin(), band_info.band_2g.end()); return Status::ok(); } Status Server::getAvailable5gNonDFSChannels( std::optional>* out_frequencies) { int wiphy_index = GetWiphyIndexFromBand(NL80211_BAND_5GHZ); BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) { out_frequencies->reset(); return Status::ok(); } if (band_info.band_5g.size() == 0) out_frequencies->reset(); else out_frequencies->emplace(band_info.band_5g.begin(), band_info.band_5g.end()); return Status::ok(); } Status Server::getAvailableDFSChannels( std::optional>* out_frequencies) { int wiphy_index = GetWiphyIndexFromBand(NL80211_BAND_5GHZ); BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) { out_frequencies->reset(); return Status::ok(); } if (band_info.band_dfs.size() == 0) out_frequencies->reset(); else out_frequencies->emplace(band_info.band_dfs.begin(), band_info.band_dfs.end()); return Status::ok(); } Status Server::getAvailable6gChannels( std::optional>* out_frequencies) { int wiphy_index = GetWiphyIndexFromBand(NL80211_BAND_6GHZ); BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) { out_frequencies->reset(); return Status::ok(); } if (band_info.band_6g.size() == 0) out_frequencies->reset(); else out_frequencies->emplace(band_info.band_6g.begin(), band_info.band_6g.end()); return Status::ok(); } Status Server::getAvailable60gChannels( std::optional>* out_frequencies) { int wiphy_index = GetWiphyIndexFromBand(NL80211_BAND_60GHZ); BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) { out_frequencies->reset(); return Status::ok(); } if (band_info.band_60g.size() == 0) out_frequencies->reset(); else out_frequencies->emplace( band_info.band_60g.begin(), band_info.band_60g.end()); return Status::ok(); } Status Server::getDeviceWiphyCapabilities( const std::string& iface_name, std::optional* capabilities) { int wiphy_index = FindWiphyIndex(iface_name); if (wiphy_index == -1) { LOG(ERROR) << "Failed to find iface_name " << iface_name; capabilities = nullptr; return Status::ok(); } BandInfo band_info; ScanCapabilities scan_capabilities_ignored; WiphyFeatures wiphy_features_ignored; if (!netlink_utils_->GetWiphyInfo(wiphy_index, &band_info, &scan_capabilities_ignored, &wiphy_features_ignored)) { LOG(ERROR) << "Failed to get wiphy info from kernel"; capabilities = nullptr; return Status::ok(); } capabilities->emplace(); capabilities->value().is80211nSupported_ = band_info.is_80211n_supported; capabilities->value().is80211acSupported_ = band_info.is_80211ac_supported; capabilities->value().is80211axSupported_ = band_info.is_80211ax_supported; capabilities->value().is160MhzSupported_ = band_info.is_160_mhz_supported; capabilities->value().is80p80MhzSupported_ = band_info.is_80p80_mhz_supported; capabilities->value().maxTxStreams_ = band_info.max_tx_streams; capabilities->value().maxRxStreams_ = band_info.max_rx_streams; return Status::ok(); } bool Server::SetupInterface(const std::string& iface_name, InterfaceInfo* interface, uint32_t *wiphy_index) { if (!netlink_utils_->GetWiphyIndex(wiphy_index, iface_name)) { LOG(ERROR) << "Failed to get wiphy index"; return false; } // TODO: It may need to handle multi-chips case to get multi-wiphy index and // register corresponding callback. netlink_utils_->SubscribeRegDomainChange( *wiphy_index, std::bind(&Server::OnRegDomainChanged, this, _1, _2)); debug_interfaces_.clear(); if (!netlink_utils_->GetInterfaces(*wiphy_index, &debug_interfaces_)) { LOG(ERROR) << "Failed to get interfaces info from kernel for iface_name " << iface_name << " wiphy_index " << *wiphy_index; return false; } for (const auto& iface : debug_interfaces_) { if (iface.name == iface_name) { *interface = iface; return true; } } LOG(ERROR) << "No usable interface found"; return false; } void Server::OnRegDomainChanged(uint32_t wiphy_index, std::string& country_code) { if (country_code.empty()) { LOG(INFO) << "Regulatory domain changed"; } else { LOG(INFO) << "Regulatory domain changed to country: " << country_code << " on wiphy_index: " << wiphy_index; BroadcastRegDomainChanged(country_code); } LogSupportedBands(wiphy_index); } void Server::LogSupportedBands(uint32_t wiphy_index) { BandInfo band_info; ScanCapabilities scan_capabilities; WiphyFeatures wiphy_features; netlink_utils_->GetWiphyInfo(wiphy_index, &band_info, &scan_capabilities, &wiphy_features); stringstream ss; for (unsigned int i = 0; i < band_info.band_2g.size(); i++) { ss << " " << band_info.band_2g[i]; } LOG(INFO) << "2.4Ghz frequencies:"<< ss.str(); ss.str(""); for (unsigned int i = 0; i < band_info.band_5g.size(); i++) { ss << " " << band_info.band_5g[i]; } LOG(INFO) << "5Ghz non-DFS frequencies:"<< ss.str(); ss.str(""); for (unsigned int i = 0; i < band_info.band_dfs.size(); i++) { ss << " " << band_info.band_dfs[i]; } LOG(INFO) << "5Ghz DFS frequencies:"<< ss.str(); ss.str(""); for (unsigned int i = 0; i < band_info.band_6g.size(); i++) { ss << " " << band_info.band_6g[i]; } LOG(INFO) << "6Ghz frequencies:"<< ss.str(); ss.str(""); for (unsigned int i = 0; i < band_info.band_60g.size(); i++) { ss << " " << band_info.band_60g[i]; } LOG(INFO) << "60Ghz frequencies:"<< ss.str(); } void Server::BroadcastClientInterfaceReady( sp network_interface) { for (auto& it : interface_event_callbacks_) { it->OnClientInterfaceReady(network_interface); } } void Server::BroadcastApInterfaceReady( sp network_interface) { for (auto& it : interface_event_callbacks_) { it->OnApInterfaceReady(network_interface); } } void Server::BroadcastClientInterfaceTornDown( sp network_interface) { for (auto& it : interface_event_callbacks_) { it->OnClientTorndownEvent(network_interface); } } void Server::BroadcastApInterfaceTornDown( sp network_interface) { for (auto& it : interface_event_callbacks_) { it->OnApTorndownEvent(network_interface); } } void Server::BroadcastRegDomainChanged( std::string country_code) { for (const auto& it : wificond_event_callbacks_) { it->OnRegDomainChanged(country_code); } } int Server::FindWiphyIndex( const std::string& iface_name) { int wiphy_index = -1; for (auto& it : iface_to_wiphy_index_map_) { if (it.first == iface_name) { wiphy_index = it.second; break; } } return wiphy_index; } bool Server::GetBandInfo( int wiphy_index, BandInfo* band_info) { if (wiphy_index == -1) return false; ScanCapabilities scan_capabilities_ignored; WiphyFeatures wiphy_features_ignored; if (!netlink_utils_->GetWiphyInfo(wiphy_index, band_info, &scan_capabilities_ignored, &wiphy_features_ignored)) { LOG(ERROR) << "Failed to get wiphy index " << wiphy_index << " info from kernel"; return false; } return true; } int Server::GetWiphyIndexFromBand(int band) { auto iter = band_to_wiphy_index_map_.find(band); return (iter != band_to_wiphy_index_map_.end()) ? iter->second : -1; } void Server::UpdateBandWiphyIndexMap(int wiphy_index) { LOG(DEBUG) << "UpdateBandWiphyIndexMap for wiphy_index " << wiphy_index; BandInfo band_info; if (!GetBandInfo(wiphy_index, &band_info)) return; if (band_info.band_2g.size() != 0 && band_to_wiphy_index_map_.find(NL80211_BAND_2GHZ) == band_to_wiphy_index_map_.end()) { band_to_wiphy_index_map_[NL80211_BAND_2GHZ] = wiphy_index; LOG(INFO) << "add channel type " << NL80211_BAND_2GHZ << " support at wiphy index: " << wiphy_index; } if (band_info.band_5g.size() != 0 && band_to_wiphy_index_map_.find(NL80211_BAND_5GHZ) == band_to_wiphy_index_map_.end()) { band_to_wiphy_index_map_[NL80211_BAND_5GHZ] = wiphy_index; LOG(INFO) << "add channel type " << NL80211_BAND_5GHZ << " support at wiphy index: " << wiphy_index; } if (band_info.band_dfs.size() != 0 && band_to_wiphy_index_map_.find(NL80211_BAND_5GHZ) == band_to_wiphy_index_map_.end()) { band_to_wiphy_index_map_[NL80211_BAND_5GHZ] = wiphy_index; LOG(INFO) << "add channel type " << NL80211_BAND_5GHZ << " support at wiphy index: " << wiphy_index; } if (band_info.band_6g.size() != 0 && band_to_wiphy_index_map_.find(NL80211_BAND_6GHZ) == band_to_wiphy_index_map_.end()) { band_to_wiphy_index_map_[NL80211_BAND_6GHZ] = wiphy_index; LOG(INFO) << "add channel type " << NL80211_BAND_6GHZ << " support at wiphy index: " << wiphy_index; } if (band_info.band_60g.size() != 0 && band_to_wiphy_index_map_.find(NL80211_BAND_60GHZ) == band_to_wiphy_index_map_.end()) { band_to_wiphy_index_map_[NL80211_BAND_60GHZ] = wiphy_index; LOG(INFO) << "add channel type " << NL80211_BAND_60GHZ << " support at wiphy index: " << wiphy_index; } } void Server::EraseBandWiphyIndexMap(int wiphy_index) { LOG(DEBUG) << "EraseBandWiphyIndexMap for wiphy_index " << wiphy_index; for (auto it = band_to_wiphy_index_map_.begin(); // end() is computed every iteration since erase() could invalidate it it != band_to_wiphy_index_map_.end(); /* no increment */ ) { if (it->second == wiphy_index) { LOG(INFO) << "remove channel type " << it->first << " support at wiphy index " << it->second; // erase returns iterator to element following erased element, or end() if the last element // was erased it = band_to_wiphy_index_map_.erase(it); } else { ++it; } } } } // namespace wificond } // namespace android