714 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			714 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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 <algorithm> // for std::find_if
 | |
| #include <sstream>
 | |
| #include <set>
 | |
| 
 | |
| #include <android-base/file.h>
 | |
| #include <android-base/logging.h>
 | |
| #include <android-base/strings.h>
 | |
| #include <binder/IPCThreadState.h>
 | |
| #include <binder/PermissionCache.h>
 | |
| 
 | |
| #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::set;
 | |
| 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<InterfaceTool> 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<IWificondEventCallback>& 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<IWificondEventCallback>& 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<IInterfaceEventCallback>& 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<IInterfaceEventCallback>& 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<IApInterface>* 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<ApInterfaceImpl> 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<IClientInterface>* 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<ClientInterfaceImpl> 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<sp<IBinder>>* out_client_interfaces) {
 | |
|   vector<sp<android::IBinder>> 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<sp<IBinder>>* out_ap_interfaces) {
 | |
|   vector<sp<IBinder>> 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<String16>& /*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<vector<int32_t>>* 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<vector<int32_t>>* 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<vector<int32_t>>* 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<vector<int32_t>>* 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<vector<int32_t>>* 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<DeviceWiphyCapabilities>* 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().is80211beSupported_ = band_info.is_80211be_supported;
 | |
|   capabilities->value().is160MhzSupported_ = band_info.is_160_mhz_supported;
 | |
|   capabilities->value().is80p80MhzSupported_ = band_info.is_80p80_mhz_supported;
 | |
|   capabilities->value().is320MhzSupported_ = band_info.is_320_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::handleCountryCodeChanged() {
 | |
|   uint32_t wiphy_index;
 | |
|   set<uint32_t> handled_wiphy_index;
 | |
|   for (auto& it : client_interfaces_) {
 | |
|     it.second->UpdateBandInfo();
 | |
|     if (netlink_utils_->GetWiphyIndex(&wiphy_index, it.first)) {
 | |
|       if (handled_wiphy_index.find(wiphy_index) == handled_wiphy_index.end()) {
 | |
|         UpdateBandWiphyIndexMap(wiphy_index);
 | |
|         LogSupportedBands(wiphy_index);
 | |
|         handled_wiphy_index.insert(wiphy_index);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   for (auto& it : ap_interfaces_) {
 | |
|     if (netlink_utils_->GetWiphyIndex(&wiphy_index, it.first)) {
 | |
|       if (handled_wiphy_index.find(wiphy_index) == handled_wiphy_index.end()) {
 | |
|         UpdateBandWiphyIndexMap(wiphy_index);
 | |
|         LogSupportedBands(wiphy_index);
 | |
|         handled_wiphy_index.insert(wiphy_index);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void Server::OnRegDomainChanged(uint32_t wiphy_index, std::string& country_code) {
 | |
|   string current_country_code;
 | |
|   if (country_code.empty()) {
 | |
|     LOG(DEBUG) << "Regulatory domain changed with empty country code (world mode?)";
 | |
|     if (!netlink_utils_->GetCountryCode(¤t_country_code)) {
 | |
|         LOG(ERROR) << "Fail to get country code on wiphy_index:" << wiphy_index;
 | |
|     }
 | |
|   } else {
 | |
|       current_country_code = country_code;
 | |
|   }
 | |
|   if (!current_country_code.empty()) {
 | |
|       LOG(INFO) << "Regulatory domain changed to country: " << current_country_code
 | |
|                 << " on wiphy_index: " << wiphy_index;
 | |
|       BroadcastRegDomainChanged(current_country_code);
 | |
|   }
 | |
|   // Sometimes lower layer sends stale wiphy index when there are no
 | |
|   // interfaces. So update band - wiphy index mapping only if an
 | |
|   // interface exists
 | |
|   if (!hasNoIfaceForWiphyIndex(wiphy_index)) {
 | |
|     handleCountryCodeChanged();
 | |
|   }
 | |
| }
 | |
| 
 | |
| android::binder::Status Server::notifyCountryCodeChanged() {
 | |
|   LOG(INFO) << "Receive notifyCountryCodeChanged";
 | |
|   handleCountryCodeChanged();
 | |
|   return Status::ok();
 | |
| }
 | |
| 
 | |
| 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<IClientInterface> network_interface) {
 | |
|   for (auto& it : interface_event_callbacks_) {
 | |
|     it->OnClientInterfaceReady(network_interface);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void Server::BroadcastApInterfaceReady(
 | |
|     sp<IApInterface> network_interface) {
 | |
|   for (auto& it : interface_event_callbacks_) {
 | |
|     it->OnApInterfaceReady(network_interface);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void Server::BroadcastClientInterfaceTornDown(
 | |
|     sp<IClientInterface> network_interface) {
 | |
|   for (auto& it : interface_event_callbacks_) {
 | |
|     it->OnClientTorndownEvent(network_interface);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void Server::BroadcastApInterfaceTornDown(
 | |
|     sp<IApInterface> 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
 |