| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/dbus/supplicant_interface_proxy.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/callback_helpers.h> |
| |
| #include "shill/logging.h" |
| #include "shill/supplicant/supplicant_event_delegate_interface.h" |
| #include "shill/supplicant/wpa_supplicant.h" |
| |
| using std::string; |
| |
| namespace shill { |
| |
| namespace Logging { |
| static auto kModuleLogScope = ScopeLogger::kDBus; |
| static string ObjectID(const dbus::ObjectPath* p) { |
| return p->value(); |
| } |
| } // namespace Logging |
| |
| const char SupplicantInterfaceProxy::kInterfaceName[] = |
| "fi.w1.wpa_supplicant1.Interface"; |
| const char SupplicantInterfaceProxy::kPropertyFastReauth[] = "FastReauth"; |
| const char SupplicantInterfaceProxy::kPropertyScan[] = "Scan"; |
| const char SupplicantInterfaceProxy::kPropertyScanInterval[] = "ScanInterval"; |
| const char SupplicantInterfaceProxy::kPropertySchedScan[] = "SchedScan"; |
| const char SupplicantInterfaceProxy::kPropertyMacAddressRandomizationMask[] = |
| "MACAddressRandomizationMask"; |
| |
| SupplicantInterfaceProxy::PropertySet::PropertySet( |
| dbus::ObjectProxy* object_proxy, |
| const std::string& interface_name, |
| const PropertyChangedCallback& callback) |
| : dbus::PropertySet(object_proxy, interface_name, callback) { |
| RegisterProperty(kPropertyFastReauth, &fast_reauth); |
| RegisterProperty(kPropertyScan, &scan); |
| RegisterProperty(kPropertyScanInterval, &scan_interval); |
| RegisterProperty(kPropertySchedScan, &sched_scan); |
| RegisterProperty(kPropertyMacAddressRandomizationMask, |
| &mac_address_randomization_mask); |
| } |
| |
| SupplicantInterfaceProxy::SupplicantInterfaceProxy( |
| const scoped_refptr<dbus::Bus>& bus, |
| const RpcIdentifier& object_path, |
| SupplicantEventDelegateInterface* delegate) |
| : interface_proxy_(new fi::w1::wpa_supplicant1::InterfaceProxy( |
| bus, WPASupplicant::kDBusAddr, object_path)), |
| delegate_(delegate) { |
| // Register properites. |
| properties_.reset( |
| new PropertySet(interface_proxy_->GetObjectProxy(), kInterfaceName, |
| base::Bind(&SupplicantInterfaceProxy::OnPropertyChanged, |
| weak_factory_.GetWeakPtr()))); |
| |
| // Register signal handlers. |
| auto on_connected_callback = base::Bind( |
| &SupplicantInterfaceProxy::OnSignalConnected, weak_factory_.GetWeakPtr()); |
| interface_proxy_->RegisterScanDoneSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::ScanDone, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterBSSAddedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::BSSAdded, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterBSSRemovedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::BSSRemoved, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterBlobAddedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::BlobAdded, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterBlobRemovedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::BlobRemoved, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterCertificationSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::Certification, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterEAPSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::EAP, weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterNetworkAddedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::NetworkAdded, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterNetworkRemovedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::NetworkRemoved, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterNetworkSelectedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::NetworkSelected, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| interface_proxy_->RegisterPropertiesChangedSignalHandler( |
| base::Bind(&SupplicantInterfaceProxy::PropertiesChanged, |
| weak_factory_.GetWeakPtr()), |
| on_connected_callback); |
| |
| // Connect property signals and initialize cached values. Based on |
| // recommendations from src/dbus/property.h. |
| properties_->ConnectSignals(); |
| properties_->GetAll(); |
| } |
| |
| SupplicantInterfaceProxy::~SupplicantInterfaceProxy() { |
| interface_proxy_->ReleaseObjectProxy(base::DoNothing()); |
| } |
| |
| bool SupplicantInterfaceProxy::AddNetwork(const KeyValueStore& args, |
| RpcIdentifier* network) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::VariantDictionary dict = |
| KeyValueStore::ConvertToVariantDictionary(args); |
| dbus::ObjectPath path; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->AddNetwork(dict, &path, &error)) { |
| LOG(ERROR) << "Failed to add network: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| *network = path; |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::EAPLogoff() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->EAPLogoff(&error)) { |
| LOG(ERROR) << "Failed to EPA logoff " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::EAPLogon() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->EAPLogon(&error)) { |
| LOG(ERROR) << "Failed to EAP logon: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::Disconnect() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->Disconnect(&error)) { |
| LOG(ERROR) << "Failed to disconnect: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::FlushBSS(const uint32_t& age) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->FlushBSS(age, &error)) { |
| LOG(ERROR) << "Failed to flush BSS: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::NetworkReply(const RpcIdentifier& network, |
| const string& field, |
| const string& value) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << " network: " << network.value() << " field: " << field |
| << " value: " << value; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->NetworkReply(network, field, value, &error)) { |
| LOG(ERROR) << "Failed to network reply: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::Roam(const string& addr) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->Roam(addr, &error)) { |
| LOG(ERROR) << "Failed to Roam: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::Reassociate() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->Reassociate(&error)) { |
| LOG(ERROR) << "Failed to reassociate: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::Reattach() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->Reattach(&error)) { |
| LOG(ERROR) << "Failed to reattach: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::RemoveAllNetworks() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->RemoveAllNetworks(&error)) { |
| LOG(ERROR) << "Failed to remove all networks: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::RemoveNetwork(const RpcIdentifier& network) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << ": " << network.value(); |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->RemoveNetwork(network, &error)) { |
| LOG(ERROR) << "Failed to remove network: " << error->GetCode() << " " |
| << error->GetMessage(); |
| // RemoveNetwork can fail with three different errors. |
| // |
| // If RemoveNetwork fails with a NetworkUnknown error, supplicant has |
| // already removed the network object, so return true as if |
| // RemoveNetwork removes the network object successfully. |
| // |
| // As shill always passes a valid network object path, RemoveNetwork |
| // should not fail with an InvalidArgs error. Return false in such case |
| // as something weird may have happened. Similarly, return false in case |
| // of an UnknownError. |
| if (error->GetCode() != WPASupplicant::kErrorNetworkUnknown) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::Scan(const KeyValueStore& args) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| brillo::VariantDictionary dict = |
| KeyValueStore::ConvertToVariantDictionary(args); |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->Scan(dict, &error)) { |
| LOG(ERROR) << "Failed to scan: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::SelectNetwork(const RpcIdentifier& network) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << ": " << network.value(); |
| brillo::ErrorPtr error; |
| if (!interface_proxy_->SelectNetwork(network, &error)) { |
| LOG(ERROR) << "Failed to select network: " << error->GetCode() << " " |
| << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::EnableMacAddressRandomization( |
| const std::vector<unsigned char>& mask, bool sched_scan) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // The MACRandomizationMask property is a map(type_string, ipmask_array) |
| // where type_string is scan type ("scan" || "sched_scan" || "pno") and |
| // ipmask specifies the corresponding mask as an array of bytes. |
| std::map<std::string, std::vector<uint8_t>> mac_randomization_args; |
| mac_randomization_args.insert( |
| std::pair<std::string, std::vector<uint8_t>>("scan", mask)); |
| if (sched_scan) |
| mac_randomization_args.insert( |
| std::pair<std::string, std::vector<uint8_t>>("sched_scan", mask)); |
| |
| if (!(properties_->mac_address_randomization_mask.SetAndBlock( |
| mac_randomization_args))) { |
| LOG(ERROR) << "Failed to enable MAC address randomization"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::DisableMacAddressRandomization() { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // Send an empty map to disable Randomization for all scan types. |
| std::map<std::string, std::vector<uint8_t>> mac_randomization_empty; |
| if (!(properties_->mac_address_randomization_mask.SetAndBlock( |
| mac_randomization_empty))) { |
| LOG(ERROR) << "Failed to disable MAC address randomization"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::SetFastReauth(bool enabled) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__ << ": " << enabled; |
| if (!properties_->fast_reauth.SetAndBlock(enabled)) { |
| LOG(ERROR) << __func__ << " failed: " << enabled; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::SetScanInterval(int32_t scan_interval) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << ": " << scan_interval; |
| if (!properties_->scan_interval.SetAndBlock(scan_interval)) { |
| LOG(ERROR) << __func__ << " failed: " << scan_interval; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SupplicantInterfaceProxy::SetScan(bool enable) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__ << ": " << enable; |
| if (!properties_->scan.SetAndBlock(enable)) { |
| LOG(ERROR) << __func__ << " failed: " << enable; |
| return false; |
| } |
| return true; |
| } |
| |
| void SupplicantInterfaceProxy::BlobAdded(const string& /*blobname*/) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // XXX |
| } |
| |
| void SupplicantInterfaceProxy::BlobRemoved(const string& /*blobname*/) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // XXX |
| } |
| |
| void SupplicantInterfaceProxy::BSSAdded( |
| const dbus::ObjectPath& BSS, const brillo::VariantDictionary& properties) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| KeyValueStore store = KeyValueStore::ConvertFromVariantDictionary(properties); |
| delegate_->BSSAdded(BSS, store); |
| } |
| |
| void SupplicantInterfaceProxy::Certification( |
| const brillo::VariantDictionary& properties) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| KeyValueStore store = KeyValueStore::ConvertFromVariantDictionary(properties); |
| delegate_->Certification(store); |
| } |
| |
| void SupplicantInterfaceProxy::EAP(const string& status, |
| const string& parameter) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << ": status " << status << ", parameter " << parameter; |
| delegate_->EAPEvent(status, parameter); |
| } |
| |
| void SupplicantInterfaceProxy::BSSRemoved(const dbus::ObjectPath& BSS) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| delegate_->BSSRemoved(BSS); |
| } |
| |
| void SupplicantInterfaceProxy::NetworkAdded( |
| const dbus::ObjectPath& /*network*/, |
| const brillo::VariantDictionary& /*properties*/) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // XXX |
| } |
| |
| void SupplicantInterfaceProxy::NetworkRemoved( |
| const dbus::ObjectPath& /*network*/) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // TODO(quiche): Pass this up to the delegate, so that it can clean its |
| // rpcid_by_service_ map. crbug.com/207648 |
| } |
| |
| void SupplicantInterfaceProxy::NetworkSelected( |
| const dbus::ObjectPath& /*network*/) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| // XXX |
| } |
| |
| void SupplicantInterfaceProxy::PropertiesChanged( |
| const brillo::VariantDictionary& properties) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; |
| KeyValueStore store = KeyValueStore::ConvertFromVariantDictionary(properties); |
| delegate_->PropertiesChanged(store); |
| } |
| |
| void SupplicantInterfaceProxy::ScanDone(bool success) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__ << ": " << success; |
| delegate_->ScanDone(success); |
| } |
| |
| void SupplicantInterfaceProxy::OnPropertyChanged( |
| const std::string& property_name) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << ": " << property_name; |
| } |
| |
| void SupplicantInterfaceProxy::OnSignalConnected(const string& interface_name, |
| const string& signal_name, |
| bool success) { |
| SLOG(&interface_proxy_->GetObjectPath(), 2) |
| << __func__ << "interface: " << interface_name |
| << " signal: " << signal_name << "success: " << success; |
| if (!success) { |
| LOG(ERROR) << "Failed to connect signal " << signal_name << " to interface " |
| << interface_name; |
| } |
| } |
| |
| } // namespace shill |