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