1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "shill/dbus/chromeos_supplicant_process_proxy.h"
18 
19 #include <string>
20 
21 #include "shill/event_dispatcher.h"
22 #include "shill/logging.h"
23 #include "shill/supplicant/wpa_supplicant.h"
24 
25 using std::string;
26 
27 namespace shill {
28 
29 namespace Logging {
30 static auto kModuleLogScope = ScopeLogger::kDBus;
ObjectID(const dbus::ObjectPath * p)31 static string ObjectID(const dbus::ObjectPath* p) { return p->value(); }
32 }
33 
34 const char ChromeosSupplicantProcessProxy::kInterfaceName[] =
35     "fi.w1.wpa_supplicant1";
36 const char ChromeosSupplicantProcessProxy::kPropertyDebugLevel[] =
37     "DebugLevel";
38 const char ChromeosSupplicantProcessProxy::kPropertyDebugTimestamp[] =
39     "DebugTimestamp";
40 const char ChromeosSupplicantProcessProxy::kPropertyDebugShowKeys[] =
41     "DebugShowKeys";
42 const char ChromeosSupplicantProcessProxy::kPropertyInterfaces[] =
43     "Interfaces";
44 const char ChromeosSupplicantProcessProxy::kPropertyEapMethods[] =
45     "EapMethods";
46 
PropertySet(dbus::ObjectProxy * object_proxy,const std::string & interface_name,const PropertyChangedCallback & callback)47 ChromeosSupplicantProcessProxy::PropertySet::PropertySet(
48     dbus::ObjectProxy* object_proxy,
49     const std::string& interface_name,
50     const PropertyChangedCallback& callback)
51     : dbus::PropertySet(object_proxy, interface_name, callback) {
52   RegisterProperty(kPropertyDebugLevel, &debug_level);
53   RegisterProperty(kPropertyDebugTimestamp, &debug_timestamp);
54   RegisterProperty(kPropertyDebugShowKeys, &debug_show_keys);
55   RegisterProperty(kPropertyInterfaces, &interfaces);
56   RegisterProperty(kPropertyEapMethods, &eap_methods);
57 }
58 
ChromeosSupplicantProcessProxy(EventDispatcher * dispatcher,const scoped_refptr<dbus::Bus> & bus,const base::Closure & service_appeared_callback,const base::Closure & service_vanished_callback)59 ChromeosSupplicantProcessProxy::ChromeosSupplicantProcessProxy(
60     EventDispatcher* dispatcher,
61     const scoped_refptr<dbus::Bus>& bus,
62     const base::Closure& service_appeared_callback,
63     const base::Closure& service_vanished_callback)
64     : supplicant_proxy_(
65         new fi::w1::wpa_supplicant1Proxy(
66             bus,
67             WPASupplicant::kDBusAddr,
68             dbus::ObjectPath(WPASupplicant::kDBusPath))),
69       dispatcher_(dispatcher),
70       service_appeared_callback_(service_appeared_callback),
71       service_vanished_callback_(service_vanished_callback),
72       service_available_(false) {
73   // Register properties.
74   properties_.reset(
75       new PropertySet(
76           supplicant_proxy_->GetObjectProxy(),
77           kInterfaceName,
78           base::Bind(&ChromeosSupplicantProcessProxy::OnPropertyChanged,
79                      weak_factory_.GetWeakPtr())));
80 
81   // Register signal handlers.
82   dbus::ObjectProxy::OnConnectedCallback on_connected_callback =
83       base::Bind(&ChromeosSupplicantProcessProxy::OnSignalConnected,
84                  weak_factory_.GetWeakPtr());
85   supplicant_proxy_->RegisterInterfaceAddedSignalHandler(
86       base::Bind(&ChromeosSupplicantProcessProxy::InterfaceAdded,
87                  weak_factory_.GetWeakPtr()),
88       on_connected_callback);
89   supplicant_proxy_->RegisterInterfaceRemovedSignalHandler(
90       base::Bind(&ChromeosSupplicantProcessProxy::InterfaceRemoved,
91                  weak_factory_.GetWeakPtr()),
92       on_connected_callback);
93   supplicant_proxy_->RegisterPropertiesChangedSignalHandler(
94       base::Bind(&ChromeosSupplicantProcessProxy::PropertiesChanged,
95                  weak_factory_.GetWeakPtr()),
96       on_connected_callback);
97 
98   // Connect property signals and initialize cached values. Based on
99   // recommendations from src/dbus/property.h.
100   properties_->ConnectSignals();
101   properties_->GetAll();
102 
103   // Monitor service owner changes. This callback lives for the lifetime of
104   // the ObjectProxy.
105   supplicant_proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
106       base::Bind(&ChromeosSupplicantProcessProxy::OnServiceOwnerChanged,
107                  weak_factory_.GetWeakPtr()));
108 
109   // One time callback when service becomes available.
110   supplicant_proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
111       base::Bind(&ChromeosSupplicantProcessProxy::OnServiceAvailable,
112                  weak_factory_.GetWeakPtr()));
113 }
114 
~ChromeosSupplicantProcessProxy()115 ChromeosSupplicantProcessProxy::~ChromeosSupplicantProcessProxy() {}
116 
CreateInterface(const KeyValueStore & args,string * rpc_identifier)117 bool ChromeosSupplicantProcessProxy::CreateInterface(
118     const KeyValueStore& args, string* rpc_identifier) {
119   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
120   if (!service_available_) {
121     LOG(ERROR) << "Supplicant process not present";
122     return false;
123   }
124   brillo::VariantDictionary dict;
125   KeyValueStore::ConvertToVariantDictionary(args, &dict);
126   dbus::ObjectPath path;
127   brillo::ErrorPtr error;
128   if (!supplicant_proxy_->CreateInterface(dict, &path, &error)) {
129     // Interface might already been created by wpasupplicant.
130     LOG(ERROR) << "Failed to create interface: "
131                << error->GetCode() << " " << error->GetMessage();
132     return false;
133   }
134   *rpc_identifier = path.value();
135   return true;
136 }
137 
RemoveInterface(const string & rpc_identifier)138 bool ChromeosSupplicantProcessProxy::RemoveInterface(
139     const string& rpc_identifier) {
140   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__ << ": "
141                                                << rpc_identifier;
142   if (!service_available_) {
143     LOG(ERROR) << "Supplicant process not present";
144     return false;
145   }
146 
147   brillo::ErrorPtr error;
148   if (!supplicant_proxy_->RemoveInterface(dbus::ObjectPath(rpc_identifier),
149                                           &error)) {
150     LOG(FATAL) << "Failed to remove interface " << rpc_identifier << ": "
151                << error->GetCode() << " " << error->GetMessage();
152     return false;  // Make the compiler happy.
153   }
154   return true;
155 }
156 
GetInterface(const std::string & ifname,string * rpc_identifier)157 bool ChromeosSupplicantProcessProxy::GetInterface(
158     const std::string& ifname, string* rpc_identifier) {
159   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__ << ": " << ifname;
160   if (!service_available_) {
161     LOG(ERROR) << "Supplicant process not present";
162     return false;
163   }
164 
165   dbus::ObjectPath path;
166   brillo::ErrorPtr error;
167   if (!supplicant_proxy_->GetInterface(ifname, &path, &error)) {
168     LOG(FATAL) << "Failed to get interface " << ifname << ": "
169                << error->GetCode() << " " << error->GetMessage();
170     return false;  // Make the compiler happy.
171   }
172   *rpc_identifier = path.value();
173   return rpc_identifier;
174 }
175 
SetDebugLevel(const std::string & level)176 bool ChromeosSupplicantProcessProxy::SetDebugLevel(const std::string& level) {
177   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__ << ": " << level;
178   if (!service_available_) {
179     LOG(ERROR) << "Supplicant process not present";
180     return false;
181   }
182 
183   if (!properties_->debug_level.SetAndBlock(level)) {
184     LOG(ERROR) << __func__ << " failed: " << level;
185     return false;
186   }
187   return true;
188 }
189 
GetDebugLevel(string * level)190 bool ChromeosSupplicantProcessProxy::GetDebugLevel(string* level) {
191   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
192   if (!service_available_) {
193     LOG(ERROR) << "Supplicant process not present";
194     return false;
195   }
196   if (!properties_->debug_level.GetAndBlock()) {
197     LOG(ERROR) << "Failed to get DebugLevel";
198     return false;
199   }
200   *level = properties_->debug_level.value();
201   return true;
202 }
203 
ExpectDisconnect()204 bool ChromeosSupplicantProcessProxy::ExpectDisconnect() {
205   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
206   if (!service_available_) {
207     LOG(ERROR) << "Supplicant process not present";
208     return false;
209   }
210   brillo::ErrorPtr error;
211   supplicant_proxy_->ExpectDisconnect(&error);
212   return true;
213 }
214 
InterfaceAdded(const dbus::ObjectPath &,const brillo::VariantDictionary &)215 void ChromeosSupplicantProcessProxy::InterfaceAdded(
216     const dbus::ObjectPath& /*path*/,
217     const brillo::VariantDictionary& /*properties*/) {
218   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
219 }
220 
InterfaceRemoved(const dbus::ObjectPath &)221 void ChromeosSupplicantProcessProxy::InterfaceRemoved(
222     const dbus::ObjectPath& /*path*/) {
223   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
224 }
225 
PropertiesChanged(const brillo::VariantDictionary &)226 void ChromeosSupplicantProcessProxy::PropertiesChanged(
227     const brillo::VariantDictionary& /*properties*/) {
228   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__;
229 }
230 
OnServiceAvailable(bool available)231 void ChromeosSupplicantProcessProxy::OnServiceAvailable(bool available) {
232   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__ << ": " << available;
233 
234   // The callback might invoke calls to the ObjectProxy, so defer the callback
235   // to event loop.
236   if (available && !service_appeared_callback_.is_null()) {
237     dispatcher_->PostTask(service_appeared_callback_);
238   } else if (!available && !service_vanished_callback_.is_null()) {
239     dispatcher_->PostTask(service_vanished_callback_);
240   }
241   service_available_ = available;
242 }
243 
OnServiceOwnerChanged(const string & old_owner,const string & new_owner)244 void ChromeosSupplicantProcessProxy::OnServiceOwnerChanged(
245     const string& old_owner, const string& new_owner) {
246   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__
247       << "old: " << old_owner << " new: " << new_owner;
248   if (new_owner.empty()) {
249     OnServiceAvailable(false);
250   } else {
251     OnServiceAvailable(true);
252   }
253 }
254 
OnPropertyChanged(const std::string & property_name)255 void ChromeosSupplicantProcessProxy::OnPropertyChanged(
256     const std::string& property_name) {
257   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__ << ": "
258       << property_name;
259 }
260 
OnSignalConnected(const string & interface_name,const string & signal_name,bool success)261 void ChromeosSupplicantProcessProxy::OnSignalConnected(
262     const string& interface_name, const string& signal_name, bool success) {
263   SLOG(&supplicant_proxy_->GetObjectPath(), 2) << __func__
264       << "interface: " << interface_name << " signal: " << signal_name
265       << "success: " << success;
266   if (!success) {
267     LOG(ERROR) << "Failed to connect signal " << signal_name
268         << " to interface " << interface_name;
269   }
270 }
271 
272 }  // namespace shill
273