// // Copyright (C) 2015 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 #include "proxy_dbus_shill_wifi_client.h" namespace { const int kRescanIntervalMilliseconds = 200; const int kServiceDisconnectTimeoutMilliseconds = 5000; const char kDefaultBgscanMethod[] = "default"; const char kDefaultProfileName[] = "default"; } // namespace ProxyDbusShillWifiClient::ProxyDbusShillWifiClient( scoped_refptr dbus_bus) { dbus_client_.reset(new ProxyDbusClient(dbus_bus)); } bool ProxyDbusShillWifiClient::SetLogging() { dbus_client_->SetLogging(ProxyDbusClient::TECHNOLOGY_WIFI); return true; } bool ProxyDbusShillWifiClient::RemoveAllWifiEntries() { for (auto& profile_proxy : dbus_client_->GetProfileProxies()) { brillo::Any property_value; CHECK(dbus_client_->GetPropertyValueFromProfileProxy( profile_proxy.get(), shill::kEntriesProperty, &property_value)); auto entry_ids = property_value.Get>(); for (const auto& entry_id : entry_ids) { brillo::VariantDictionary entry_props; if (profile_proxy->GetEntry(entry_id, &entry_props, nullptr)) { if (entry_props[shill::kTypeProperty].Get() == shill::kTypeWifi) { profile_proxy->DeleteEntry(entry_id, nullptr); } } } } return true; } bool ProxyDbusShillWifiClient::ConfigureServiceByGuid( const std::string& guid, AutoConnectType autoconnect, const std::string& passphrase) { brillo::VariantDictionary service_params; if (guid.empty()) { return false; } SetAutoConnectInServiceParams(autoconnect, &service_params); if (!passphrase.empty()) { service_params.insert(std::make_pair( shill::kPassphraseProperty, brillo::Any(passphrase))); } return dbus_client_->ConfigureServiceByGuid(guid, service_params); } bool ProxyDbusShillWifiClient::ConfigureWifiService( const std::string& ssid, const std::string& security, const brillo::VariantDictionary& security_params, bool save_credentials, StationType station_type, bool hidden_network, const std::string& guid, AutoConnectType autoconnect) { brillo::VariantDictionary service_params; // Create the configure params dictionary. service_params.insert(std::make_pair( shill::kTypeProperty, brillo::Any(std::string(shill::kTypeWifi)))); service_params.insert(std::make_pair( shill::kWifiHiddenSsid, brillo::Any(hidden_network))); service_params.insert(std::make_pair( shill::kSSIDProperty, brillo::Any(ssid))); service_params.insert(std::make_pair( shill::kSecurityClassProperty, brillo::Any(security))); service_params.insert(std::make_pair( shill::kModeProperty, brillo::Any(GetModeFromStationType(station_type)))); SetAutoConnectInServiceParams(autoconnect, &service_params); service_params.insert(security_params.begin(), security_params.end()); if (!guid.empty()) { service_params.insert(std::make_pair( shill::kGuidProperty, brillo::Any(guid))); } for (const auto& param: service_params) { LOG(INFO) << __func__ << ". Param: " << param.first << "=" << param.second.TryGet() << "," << param.second.TryGet() << "," << param.second.TryGet() << "."; } return dbus_client_->ConfigureService(service_params); } bool ProxyDbusShillWifiClient::ConnectToWifiNetwork( const std::string& ssid, const std::string& security, const brillo::VariantDictionary& security_params, bool save_credentials, StationType station_type, bool hidden_network, const std::string& guid, AutoConnectType autoconnect, long discovery_timeout_milliseconds, long association_timeout_milliseconds, long configuration_timeout_milliseconds, long* discovery_time_milliseconds, long* association_time_milliseconds, long* configuration_time_milliseconds, std::string* failure_reason) { *discovery_time_milliseconds = -1; *association_time_milliseconds = -1; *configuration_time_milliseconds = -1; if (station_type != kStationTypeManaged && station_type != kStationTypeIBSS) { *failure_reason = "FAIL(Invalid station type specified.)"; return false; } if (hidden_network && !ConfigureWifiService( ssid, security, security_params, save_credentials, station_type, hidden_network, guid,autoconnect)) { *failure_reason = "FAIL(Failed to configure hidden SSID)"; return false; } brillo::VariantDictionary service_params; service_params.insert(std::make_pair( shill::kTypeProperty, brillo::Any(std::string(shill::kTypeWifi)))); service_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(ssid))); service_params.insert(std::make_pair( shill::kSecurityClassProperty, brillo::Any(security))); service_params.insert(std::make_pair( shill::kModeProperty, brillo::Any(GetModeFromStationType(station_type)))); for (const auto& param: service_params) { LOG(INFO) << __func__ << ". Param: " << param.first << "=" << param.second.TryGet() << "," << param.second.TryGet() << "," << param.second.TryGet() << "."; } brillo::Any signal_strength; auto service = dbus_client_->WaitForMatchingServiceProxy( service_params, shill::kTypeWifi, discovery_timeout_milliseconds, kRescanIntervalMilliseconds, discovery_time_milliseconds); if (!service || !dbus_client_->GetPropertyValueFromServiceProxy( service.get(), shill::kSignalStrengthProperty, &signal_strength) || (signal_strength.Get() < 0)) { *failure_reason = "FAIL(Discovery timed out)"; return false; } for (const auto& security_param : security_params) { CHECK(service->SetProperty(security_param.first, security_param.second, nullptr)); } if (!guid.empty()) { CHECK(service->SetProperty(shill::kGuidProperty, brillo::Any(guid), nullptr)); } if (autoconnect != kAutoConnectTypeUnspecified) { CHECK(service->SetProperty( shill::kAutoConnectProperty, brillo::Any(bool(autoconnect)), nullptr)); } brillo::ErrorPtr error; if (!service->Connect(&error) && error->GetCode() != shill::kErrorResultAlreadyConnected) { *failure_reason = "FAIL(Failed to call connect)"; return false; } brillo::Any final_value; std::vector associated_states = { brillo::Any(std::string("configuration")), brillo::Any(std::string("ready")), brillo::Any(std::string("portal")), brillo::Any(std::string("online")) }; if (!dbus_client_->WaitForServiceProxyPropertyValueIn( service->GetObjectPath(), shill::kStateProperty, associated_states, association_timeout_milliseconds, &final_value, association_time_milliseconds)) { *failure_reason = "FAIL(Association timed out)"; LOG(ERROR) << "FAIL(Association timed out). Final State: " << final_value.Get(); return false; } std::vector configured_states = { brillo::Any(std::string("ready")), brillo::Any(std::string("portal")), brillo::Any(std::string("online")) }; if (!dbus_client_->WaitForServiceProxyPropertyValueIn( service->GetObjectPath(), shill::kStateProperty, configured_states, configuration_timeout_milliseconds, nullptr, configuration_time_milliseconds)) { *failure_reason = "FAIL(Configuration timed out)"; LOG(ERROR) << "FAIL(Configuration timed out). Final State: " << final_value.Get(); return false; } *failure_reason = "SUCCESS(Connection successful)"; return true; } bool ProxyDbusShillWifiClient::DisconnectFromWifiNetwork( const std::string& ssid, long disconnect_timeout_milliseconds, long* disconnect_time_milliseconds, std::string* failure_reason) { *disconnect_time_milliseconds = -1; if (disconnect_timeout_milliseconds == 0) { disconnect_timeout_milliseconds = kServiceDisconnectTimeoutMilliseconds; } brillo::VariantDictionary service_params; service_params.insert(std::make_pair( shill::kTypeProperty, brillo::Any(std::string(shill::kTypeWifi)))); service_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(ssid))); std::unique_ptr service = dbus_client_->GetMatchingServiceProxy(service_params); if (!service) { *failure_reason = "FAIL(Service not found)"; return false; } if (!service->Disconnect(nullptr)) { *failure_reason = "FAIL(Failed to call disconnect)"; return false; } brillo::Any final_value; std::vector disconnect_states = { brillo::Any(std::string("idle")) }; if (!dbus_client_->WaitForServiceProxyPropertyValueIn( service->GetObjectPath(), shill::kStateProperty, disconnect_states, disconnect_timeout_milliseconds, &final_value, disconnect_time_milliseconds)) { *failure_reason = "FAIL(Disconnection timed out)"; return false; } *failure_reason = "SUCCESS(Disconnection successful)"; return true; } bool ProxyDbusShillWifiClient::ConfigureBgScan( const std::string& interface_name, const std::string& method_name, uint16_t short_interval, uint16_t long_interval, int signal_threshold) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } bool is_success = true; if (method_name == kDefaultBgscanMethod) { is_success &= device->ClearProperty(shill::kBgscanMethodProperty, nullptr); } else { is_success &= device->SetProperty( shill::kBgscanMethodProperty, brillo::Any(method_name), nullptr); } is_success &= device->SetProperty( shill::kBgscanShortIntervalProperty, brillo::Any(short_interval), nullptr); is_success &= device->SetProperty( shill::kScanIntervalProperty, brillo::Any(long_interval), nullptr); is_success &= device->SetProperty( shill::kBgscanSignalThresholdProperty, brillo::Any(signal_threshold), nullptr); return is_success; } bool ProxyDbusShillWifiClient::GetActiveWifiSsids( std::vector* ssids) { for (auto& service : dbus_client_->GetServiceProxies()) { brillo::Any service_type, signal_strength, ssid_hex; std::vector ssid_bytes; brillo::VariantDictionary proxy_properties; brillo::ErrorPtr error; if (service->GetProperties(&proxy_properties, &error)) { service_type = proxy_properties[shill::kTypeProperty]; signal_strength = proxy_properties[shill::kSignalStrengthProperty]; ssid_hex = proxy_properties[shill::kWifiHexSsid]; if ((service_type.TryGet() == shill::kTypeWifi) && (signal_strength.TryGet() > 0) && !ssid_hex.TryGet().empty() && base::HexStringToBytes(ssid_hex.Get(), &ssid_bytes)) { ssids->emplace_back(std::string(ssid_bytes.begin(), ssid_bytes.end())); } } else { // Ignore unknown object path errors since we might be using some proxies // for objects which may have been destroyed since. CHECK(error->GetCode() == ProxyDbusClient::kDbusErrorObjectUnknown); } } return true; } bool ProxyDbusShillWifiClient::WaitForServiceStates( const std::string& ssid, const std::vector& expected_states, long wait_timeout_milliseconds, std::string* final_state, long* wait_time_milliseconds) { *wait_time_milliseconds = -1; brillo::VariantDictionary service_params; service_params.insert(std::make_pair( shill::kTypeProperty, brillo::Any(std::string(shill::kTypeWifi)))); service_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(ssid))); long discovery_time_milliseconds; auto service = dbus_client_->WaitForMatchingServiceProxy( service_params, shill::kTypeWifi, wait_timeout_milliseconds, kRescanIntervalMilliseconds, &discovery_time_milliseconds); if (!service) { *final_state = "unknown"; return false; } brillo::Any final_value; std::vector expected_states_any; for (auto& state : expected_states) { expected_states_any.emplace_back(brillo::Any(state)); } bool is_success = dbus_client_->WaitForServiceProxyPropertyValueIn( service->GetObjectPath(), shill::kStateProperty, expected_states_any, wait_timeout_milliseconds - discovery_time_milliseconds, &final_value, wait_time_milliseconds); *wait_time_milliseconds += discovery_time_milliseconds; *final_state = final_value.Get(); return is_success; } bool ProxyDbusShillWifiClient::CreateProfile(const std::string& profile_name) { return dbus_client_->CreateProfile(profile_name); } bool ProxyDbusShillWifiClient::PushProfile(const std::string& profile_name) { return dbus_client_->PushProfile(profile_name); } bool ProxyDbusShillWifiClient::PopProfile(const std::string& profile_name) { if (profile_name.empty()) { return dbus_client_->PopAnyProfile(); } else { return dbus_client_->PopProfile(profile_name); } } bool ProxyDbusShillWifiClient::RemoveProfile(const std::string& profile_name) { return dbus_client_->RemoveProfile(profile_name); } bool ProxyDbusShillWifiClient::CleanProfiles() { while (true) { auto active_profile = dbus_client_->GetActiveProfileProxy(); brillo::Any profile_name; if (!dbus_client_->GetPropertyValueFromProfileProxy( active_profile.get(), shill::kNameProperty, &profile_name)) { return false; } std::string profile_name_str = profile_name.Get(); if (profile_name_str == kDefaultProfileName) { return true; } dbus_client_->PopProfile(profile_name_str); dbus_client_->RemoveProfile(profile_name_str); } return false; } bool ProxyDbusShillWifiClient::DeleteEntriesForSsid(const std::string& ssid) { auto profiles = dbus_client_->GetProfileProxies(); for (auto& profile : profiles) { brillo::Any property_value; if (!dbus_client_->GetPropertyValueFromProfileProxy( profile.get(), shill::kEntriesProperty, &property_value)) { continue; } auto entry_ids = property_value.Get>(); for (const auto& entry_id : entry_ids) { brillo::VariantDictionary entry_props; if ((profile->GetEntry(entry_id, &entry_props, nullptr)) && (entry_props[shill::kNameProperty].Get() == ssid)) { profile->DeleteEntry(entry_id, nullptr); } } } return true; } bool ProxyDbusShillWifiClient::ListControlledWifiInterfaces( std::vector* interface_names) { for (auto& device : dbus_client_->GetDeviceProxies()) { brillo::Any device_type; brillo::Any device_name; if (!dbus_client_->GetPropertyValueFromDeviceProxy( device.get(), shill::kTypeProperty, &device_type)) { return false; } if (device_type.Get() == shill::kTypeWifi) { if (!dbus_client_->GetPropertyValueFromDeviceProxy( device.get(), shill::kNameProperty, &device_name)) { return false; } interface_names->emplace_back(device_name.Get()); } } return true; } bool ProxyDbusShillWifiClient::Disconnect(const std::string& ssid) { long disconnect_time_milliseconds; std::string failure_reason; return DisconnectFromWifiNetwork( ssid, 0, &disconnect_time_milliseconds, &failure_reason); } bool ProxyDbusShillWifiClient::GetServiceOrder(std::string* service_order) { return dbus_client_->GetServiceOrder(service_order); } bool ProxyDbusShillWifiClient::SetServiceOrder(const std::string& service_order) { return dbus_client_->SetServiceOrder(service_order); } bool ProxyDbusShillWifiClient::GetServiceProperties( const std::string& ssid, brillo::VariantDictionary* properties) { brillo::VariantDictionary service_params; service_params.insert(std::make_pair( shill::kTypeProperty, brillo::Any(std::string(shill::kTypeWifi)))); service_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(ssid))); std::unique_ptr service = dbus_client_->GetMatchingServiceProxy(service_params); if (!service) { return false; } CHECK(service->GetProperties(properties, nullptr)); return true; } bool ProxyDbusShillWifiClient::SetSchedScan(bool enable) { return dbus_client_->SetSchedScan(enable); } bool ProxyDbusShillWifiClient::GetPropertyOnDevice( const std::string& interface_name, const std::string& property_name, brillo::Any* property_value) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return dbus_client_->GetPropertyValueFromDeviceProxy( device.get(), property_name, property_value); } bool ProxyDbusShillWifiClient::SetPropertyOnDevice( const std::string& interface_name, const std::string& property_name, const brillo::Any& property_value) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->SetProperty( property_name, property_value, nullptr); } bool ProxyDbusShillWifiClient::RequestRoam( const std::string& interface_name, const std::string& bssid) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->RequestRoam(bssid, nullptr); } bool ProxyDbusShillWifiClient::SetDeviceEnabled( const std::string& interface_name, bool enable) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } if (enable) { return device->Enable(nullptr); } else { return device->Disable(nullptr); } } bool ProxyDbusShillWifiClient::DiscoverTdlsLink( const std::string& interface_name, const std::string& peer_mac_address) { std::string out_params; return PerformTdlsOperation( interface_name, shill::kTDLSDiscoverOperation, peer_mac_address, &out_params); } bool ProxyDbusShillWifiClient::EstablishTdlsLink( const std::string& interface_name, const std::string& peer_mac_address) { std::string out_params; return PerformTdlsOperation( interface_name, shill::kTDLSSetupOperation, peer_mac_address, &out_params); } bool ProxyDbusShillWifiClient::QueryTdlsLink( const std::string& interface_name, const std::string& peer_mac_address, std::string* status) { return PerformTdlsOperation( interface_name, shill::kTDLSStatusOperation, peer_mac_address, status); } bool ProxyDbusShillWifiClient::AddWakePacketSource( const std::string& interface_name, const std::string& source_ip_address) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->AddWakeOnPacketConnection(source_ip_address, nullptr); } bool ProxyDbusShillWifiClient::RemoveWakePacketSource( const std::string& interface_name, const std::string& source_ip_address) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->RemoveWakeOnPacketConnection(source_ip_address, nullptr); } bool ProxyDbusShillWifiClient::RemoveAllWakePacketSources( const std::string& interface_name) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->RemoveAllWakeOnPacketConnections(nullptr); } void ProxyDbusShillWifiClient::SetAutoConnectInServiceParams( AutoConnectType autoconnect, brillo::VariantDictionary* service_params) { if (autoconnect != kAutoConnectTypeUnspecified) { service_params->insert(std::make_pair( shill::kAutoConnectProperty, brillo::Any(static_cast(autoconnect)))); } } bool ProxyDbusShillWifiClient::PerformTdlsOperation( const std::string& interface_name, const std::string& operation, const std::string& peer_mac_address, std::string* out_params) { brillo::VariantDictionary device_params; device_params.insert(std::make_pair( shill::kNameProperty, brillo::Any(interface_name))); std::unique_ptr device = dbus_client_->GetMatchingDeviceProxy(device_params); if (!device) { return false; } return device->PerformTDLSOperation( operation, peer_mac_address, out_params, nullptr); }