1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromeos/dbus/shill/fake_shill_device_client.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "chromeos/dbus/shill/shill_manager_client.h"
20 #include "chromeos/dbus/shill/shill_property_changed_observer.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
25 #include "dbus/values_util.h"
26 #include "net/base/ip_endpoint.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28 
29 namespace chromeos {
30 
31 namespace {
32 
33 const int kSimPinMinLength = 4;
34 const int kSimPukRetryCount = 10;
35 const char kFailedMessage[] = "Failed";
36 
ErrorFunction(const std::string & device_path,const std::string & error_name,const std::string & error_message)37 void ErrorFunction(const std::string& device_path,
38                    const std::string& error_name,
39                    const std::string& error_message) {
40   LOG(ERROR) << "Shill Error for: " << device_path << ": " << error_name
41              << " : " << error_message;
42 }
43 
PostError(const std::string & error,ShillDeviceClient::ErrorCallback error_callback)44 void PostError(const std::string& error,
45                ShillDeviceClient::ErrorCallback error_callback) {
46   base::ThreadTaskRunnerHandle::Get()->PostTask(
47       FROM_HERE,
48       base::BindOnce(std::move(error_callback), error, kFailedMessage));
49 }
50 
PostNotFoundError(ShillDeviceClient::ErrorCallback error_callback)51 void PostNotFoundError(ShillDeviceClient::ErrorCallback error_callback) {
52   PostError(shill::kErrorResultNotFound, std::move(error_callback));
53 }
54 
55 }  // namespace
56 
57 // Matches pseudomodem.
58 const char FakeShillDeviceClient::kSimPuk[] = "12345678";
59 
60 const char FakeShillDeviceClient::kDefaultSimPin[] = "1111";
61 const int FakeShillDeviceClient::kSimPinRetryCount = 3;
62 
FakeShillDeviceClient()63 FakeShillDeviceClient::FakeShillDeviceClient() {}
64 
65 FakeShillDeviceClient::~FakeShillDeviceClient() = default;
66 
67 // ShillDeviceClient overrides.
68 
AddPropertyChangedObserver(const dbus::ObjectPath & device_path,ShillPropertyChangedObserver * observer)69 void FakeShillDeviceClient::AddPropertyChangedObserver(
70     const dbus::ObjectPath& device_path,
71     ShillPropertyChangedObserver* observer) {
72   GetObserverList(device_path).AddObserver(observer);
73 }
74 
RemovePropertyChangedObserver(const dbus::ObjectPath & device_path,ShillPropertyChangedObserver * observer)75 void FakeShillDeviceClient::RemovePropertyChangedObserver(
76     const dbus::ObjectPath& device_path,
77     ShillPropertyChangedObserver* observer) {
78   GetObserverList(device_path).RemoveObserver(observer);
79 }
80 
GetProperties(const dbus::ObjectPath & device_path,DBusMethodCallback<base::Value> callback)81 void FakeShillDeviceClient::GetProperties(
82     const dbus::ObjectPath& device_path,
83     DBusMethodCallback<base::Value> callback) {
84   base::ThreadTaskRunnerHandle::Get()->PostTask(
85       FROM_HERE,
86       base::BindOnce(&FakeShillDeviceClient::PassStubDeviceProperties,
87                      weak_ptr_factory_.GetWeakPtr(), device_path,
88                      std::move(callback)));
89 }
90 
SetProperty(const dbus::ObjectPath & device_path,const std::string & name,const base::Value & value,base::OnceClosure callback,ErrorCallback error_callback)91 void FakeShillDeviceClient::SetProperty(const dbus::ObjectPath& device_path,
92                                         const std::string& name,
93                                         const base::Value& value,
94                                         base::OnceClosure callback,
95                                         ErrorCallback error_callback) {
96   SetPropertyInternal(device_path, name, value, std::move(callback),
97                       std::move(error_callback),
98                       /*notify_changed=*/true);
99 }
100 
SetPropertyInternal(const dbus::ObjectPath & device_path,const std::string & name,const base::Value & value,base::OnceClosure callback,ErrorCallback error_callback,bool notify_changed)101 void FakeShillDeviceClient::SetPropertyInternal(
102     const dbus::ObjectPath& device_path,
103     const std::string& name,
104     const base::Value& value,
105     base::OnceClosure callback,
106     ErrorCallback error_callback,
107     bool notify_changed) {
108   base::Value* device_properties =
109       stub_devices_.FindDictKey(device_path.value());
110   if (!device_properties) {
111     PostNotFoundError(std::move(error_callback));
112     return;
113   }
114   device_properties->SetKey(name, value.Clone());
115   if (notify_changed) {
116     base::ThreadTaskRunnerHandle::Get()->PostTask(
117         FROM_HERE,
118         base::BindOnce(&FakeShillDeviceClient::NotifyObserversPropertyChanged,
119                        weak_ptr_factory_.GetWeakPtr(), device_path, name));
120   }
121   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
122 }
123 
ClearProperty(const dbus::ObjectPath & device_path,const std::string & name,VoidDBusMethodCallback callback)124 void FakeShillDeviceClient::ClearProperty(const dbus::ObjectPath& device_path,
125                                           const std::string& name,
126                                           VoidDBusMethodCallback callback) {
127   base::Value* device_properties =
128       stub_devices_.FindDictKey(device_path.value());
129   if (!device_properties) {
130     PostVoidCallback(std::move(callback), false);
131     return;
132   }
133   device_properties->RemoveKey(name);
134   PostVoidCallback(std::move(callback), true);
135 }
136 
RequirePin(const dbus::ObjectPath & device_path,const std::string & pin,bool require,base::OnceClosure callback,ErrorCallback error_callback)137 void FakeShillDeviceClient::RequirePin(const dbus::ObjectPath& device_path,
138                                        const std::string& pin,
139                                        bool require,
140                                        base::OnceClosure callback,
141                                        ErrorCallback error_callback) {
142   VLOG(1) << "RequirePin: " << device_path.value();
143   if (!stub_devices_.FindKey(device_path.value())) {
144     PostNotFoundError(std::move(error_callback));
145     return;
146   }
147   if (!SimTryPin(device_path.value(), pin)) {
148     base::ThreadTaskRunnerHandle::Get()->PostTask(
149         FROM_HERE, base::BindOnce(std::move(error_callback),
150                                   shill::kErrorResultIncorrectPin, ""));
151     return;
152   }
153   SimLockStatus status = GetSimLockStatus(device_path.value());
154   status.lock_enabled = require;
155   SetSimLockStatus(device_path.value(), status);
156 
157   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
158 }
159 
EnterPin(const dbus::ObjectPath & device_path,const std::string & pin,base::OnceClosure callback,ErrorCallback error_callback)160 void FakeShillDeviceClient::EnterPin(const dbus::ObjectPath& device_path,
161                                      const std::string& pin,
162                                      base::OnceClosure callback,
163                                      ErrorCallback error_callback) {
164   VLOG(1) << "EnterPin: " << device_path.value();
165   if (!stub_devices_.FindKey(device_path.value())) {
166     PostNotFoundError(std::move(error_callback));
167     return;
168   }
169   if (!SimTryPin(device_path.value(), pin)) {
170     base::ThreadTaskRunnerHandle::Get()->PostTask(
171         FROM_HERE, base::BindOnce(std::move(error_callback),
172                                   shill::kErrorResultIncorrectPin, ""));
173     return;
174   }
175   SetSimLocked(device_path.value(), false);
176 
177   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
178 }
179 
UnblockPin(const dbus::ObjectPath & device_path,const std::string & puk,const std::string & pin,base::OnceClosure callback,ErrorCallback error_callback)180 void FakeShillDeviceClient::UnblockPin(const dbus::ObjectPath& device_path,
181                                        const std::string& puk,
182                                        const std::string& pin,
183                                        base::OnceClosure callback,
184                                        ErrorCallback error_callback) {
185   VLOG(1) << "UnblockPin: " << device_path.value();
186   if (!stub_devices_.FindKey(device_path.value())) {
187     PostNotFoundError(std::move(error_callback));
188     return;
189   }
190   if (!SimTryPuk(device_path.value(), puk)) {
191     base::ThreadTaskRunnerHandle::Get()->PostTask(
192         FROM_HERE, base::BindOnce(std::move(error_callback),
193                                   shill::kErrorResultIncorrectPin, ""));
194     return;
195   }
196   if (pin.length() < kSimPinMinLength) {
197     base::ThreadTaskRunnerHandle::Get()->PostTask(
198         FROM_HERE, base::BindOnce(std::move(error_callback),
199                                   shill::kErrorResultInvalidArguments, ""));
200     return;
201   }
202   sim_pin_[device_path.value()] = pin;
203   SetSimLocked(device_path.value(), false);
204 
205   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
206 }
207 
ChangePin(const dbus::ObjectPath & device_path,const std::string & old_pin,const std::string & new_pin,base::OnceClosure callback,ErrorCallback error_callback)208 void FakeShillDeviceClient::ChangePin(const dbus::ObjectPath& device_path,
209                                       const std::string& old_pin,
210                                       const std::string& new_pin,
211                                       base::OnceClosure callback,
212                                       ErrorCallback error_callback) {
213   VLOG(1) << "ChangePin: " << device_path.value();
214   if (!stub_devices_.FindKey(device_path.value())) {
215     PostNotFoundError(std::move(error_callback));
216     return;
217   }
218   if (!SimTryPin(device_path.value(), old_pin)) {
219     base::ThreadTaskRunnerHandle::Get()->PostTask(
220         FROM_HERE, base::BindOnce(std::move(error_callback),
221                                   shill::kErrorResultIncorrectPin, ""));
222     return;
223   }
224   if (new_pin.length() < kSimPinMinLength) {
225     base::ThreadTaskRunnerHandle::Get()->PostTask(
226         FROM_HERE, base::BindOnce(std::move(error_callback),
227                                   shill::kErrorResultInvalidArguments, ""));
228     return;
229   }
230   sim_pin_[device_path.value()] = new_pin;
231 
232   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
233 }
234 
Register(const dbus::ObjectPath & device_path,const std::string & network_id,base::OnceClosure callback,ErrorCallback error_callback)235 void FakeShillDeviceClient::Register(const dbus::ObjectPath& device_path,
236                                      const std::string& network_id,
237                                      base::OnceClosure callback,
238                                      ErrorCallback error_callback) {
239   base::Value* device_properties =
240       stub_devices_.FindDictKey(device_path.value());
241   if (!device_properties) {
242     PostNotFoundError(std::move(error_callback));
243     return;
244   }
245   base::Value* scan_results =
246       device_properties->FindKey(shill::kFoundNetworksProperty);
247   if (!scan_results) {
248     PostError("No Cellular scan results", std::move(error_callback));
249     return;
250   }
251   for (auto& network : scan_results->GetList()) {
252     std::string id = network.FindKey(shill::kNetworkIdProperty)->GetString();
253     std::string status = id == network_id ? "current" : "available";
254     network.SetKey(shill::kStatusProperty, base::Value(status));
255   }
256   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
257 }
258 
Reset(const dbus::ObjectPath & device_path,base::OnceClosure callback,ErrorCallback error_callback)259 void FakeShillDeviceClient::Reset(const dbus::ObjectPath& device_path,
260                                   base::OnceClosure callback,
261                                   ErrorCallback error_callback) {
262   if (!stub_devices_.FindKey(device_path.value())) {
263     PostNotFoundError(std::move(error_callback));
264     return;
265   }
266   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
267 }
268 
AddWakeOnPacketConnection(const dbus::ObjectPath & device_path,const net::IPEndPoint & ip_endpoint,base::OnceClosure callback,ErrorCallback error_callback)269 void FakeShillDeviceClient::AddWakeOnPacketConnection(
270     const dbus::ObjectPath& device_path,
271     const net::IPEndPoint& ip_endpoint,
272     base::OnceClosure callback,
273     ErrorCallback error_callback) {
274   if (!stub_devices_.FindKey(device_path.value())) {
275     PostNotFoundError(std::move(error_callback));
276     return;
277   }
278 
279   wake_on_packet_connections_[device_path].insert(ip_endpoint);
280 
281   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
282 }
283 
AddWakeOnPacketOfTypes(const dbus::ObjectPath & device_path,const std::vector<std::string> & types,base::OnceClosure callback,ErrorCallback error_callback)284 void FakeShillDeviceClient::AddWakeOnPacketOfTypes(
285     const dbus::ObjectPath& device_path,
286     const std::vector<std::string>& types,
287     base::OnceClosure callback,
288     ErrorCallback error_callback) {
289   if (!stub_devices_.FindKey(device_path.value())) {
290     PostNotFoundError(std::move(error_callback));
291     return;
292   }
293 
294   wake_on_packet_types_[device_path].insert(types.begin(), types.end());
295   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
296 }
297 
RemoveWakeOnPacketConnection(const dbus::ObjectPath & device_path,const net::IPEndPoint & ip_endpoint,base::OnceClosure callback,ErrorCallback error_callback)298 void FakeShillDeviceClient::RemoveWakeOnPacketConnection(
299     const dbus::ObjectPath& device_path,
300     const net::IPEndPoint& ip_endpoint,
301     base::OnceClosure callback,
302     ErrorCallback error_callback) {
303   const auto device_iter = wake_on_packet_connections_.find(device_path);
304   if (!stub_devices_.FindKey(device_path.value()) ||
305       device_iter == wake_on_packet_connections_.end()) {
306     PostNotFoundError(std::move(error_callback));
307     return;
308   }
309 
310   const auto endpoint_iter = device_iter->second.find(ip_endpoint);
311   if (endpoint_iter == device_iter->second.end()) {
312     PostNotFoundError(std::move(error_callback));
313     return;
314   }
315 
316   device_iter->second.erase(endpoint_iter);
317 
318   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
319 }
320 
RemoveWakeOnPacketOfTypes(const dbus::ObjectPath & device_path,const std::vector<std::string> & types,base::OnceClosure callback,ErrorCallback error_callback)321 void FakeShillDeviceClient::RemoveWakeOnPacketOfTypes(
322     const dbus::ObjectPath& device_path,
323     const std::vector<std::string>& types,
324     base::OnceClosure callback,
325     ErrorCallback error_callback) {
326   if (!stub_devices_.FindKey(device_path.value())) {
327     PostNotFoundError(std::move(error_callback));
328     return;
329   }
330 
331   const auto registered_types_iter = wake_on_packet_types_.find(device_path);
332   if (registered_types_iter == wake_on_packet_types_.end()) {
333     PostNotFoundError(std::move(error_callback));
334     return;
335   }
336 
337   std::set<std::string>& registered_types = registered_types_iter->second;
338   for (auto it = types.begin(); it != types.end(); it++)
339     registered_types.erase(*it);
340 
341   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
342 }
343 
RemoveAllWakeOnPacketConnections(const dbus::ObjectPath & device_path,base::OnceClosure callback,ErrorCallback error_callback)344 void FakeShillDeviceClient::RemoveAllWakeOnPacketConnections(
345     const dbus::ObjectPath& device_path,
346     base::OnceClosure callback,
347     ErrorCallback error_callback) {
348   const auto iter = wake_on_packet_connections_.find(device_path);
349   if (!stub_devices_.FindKey(device_path.value()) ||
350       iter == wake_on_packet_connections_.end()) {
351     PostNotFoundError(std::move(error_callback));
352     return;
353   }
354 
355   wake_on_packet_connections_.erase(iter);
356 
357   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
358 }
359 
SetUsbEthernetMacAddressSource(const dbus::ObjectPath & device_path,const std::string & source,base::OnceClosure callback,ErrorCallback error_callback)360 void FakeShillDeviceClient::SetUsbEthernetMacAddressSource(
361     const dbus::ObjectPath& device_path,
362     const std::string& source,
363     base::OnceClosure callback,
364     ErrorCallback error_callback) {
365   if (!stub_devices_.FindKey(device_path.value())) {
366     PostNotFoundError(std::move(error_callback));
367     return;
368   }
369 
370   const auto error_name_iter =
371       set_usb_ethernet_mac_address_source_error_names_.find(
372           device_path.value());
373   if (error_name_iter !=
374           set_usb_ethernet_mac_address_source_error_names_.end() &&
375       !error_name_iter->second.empty()) {
376     PostError(error_name_iter->second, std::move(error_callback));
377     return;
378   }
379 
380   SetDeviceProperty(device_path.value(),
381                     shill::kUsbEthernetMacAddressSourceProperty,
382                     base::Value(source), /*notify_changed=*/true);
383 
384   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
385 }
386 
GetTestInterface()387 ShillDeviceClient::TestInterface* FakeShillDeviceClient::GetTestInterface() {
388   return this;
389 }
390 
391 // ShillDeviceClient::TestInterface overrides.
392 
AddDevice(const std::string & device_path,const std::string & type,const std::string & name)393 void FakeShillDeviceClient::AddDevice(const std::string& device_path,
394                                       const std::string& type,
395                                       const std::string& name) {
396   ShillManagerClient::Get()->GetTestInterface()->AddDevice(device_path);
397 
398   base::Value* properties = GetDeviceProperties(device_path);
399   properties->SetKey(shill::kTypeProperty, base::Value(type));
400   properties->SetKey(shill::kNameProperty, base::Value(name));
401   properties->SetKey(shill::kDBusObjectProperty, base::Value(device_path));
402   properties->SetKey(shill::kDBusServiceProperty,
403                      base::Value(modemmanager::kModemManager1ServiceName));
404   if (type == shill::kTypeCellular) {
405     properties->SetKey(shill::kCellularAllowRoamingProperty,
406                        base::Value(false));
407   }
408 }
409 
RemoveDevice(const std::string & device_path)410 void FakeShillDeviceClient::RemoveDevice(const std::string& device_path) {
411   ShillManagerClient::Get()->GetTestInterface()->RemoveDevice(device_path);
412   stub_devices_.RemoveKey(device_path);
413 }
414 
ClearDevices()415 void FakeShillDeviceClient::ClearDevices() {
416   ShillManagerClient::Get()->GetTestInterface()->ClearDevices();
417   stub_devices_ = base::Value(base::Value::Type::DICTIONARY);
418 }
419 
SetDeviceProperty(const std::string & device_path,const std::string & name,const base::Value & value,bool notify_changed)420 void FakeShillDeviceClient::SetDeviceProperty(const std::string& device_path,
421                                               const std::string& name,
422                                               const base::Value& value,
423                                               bool notify_changed) {
424   VLOG(1) << "SetDeviceProperty: " << device_path << ": " << name << " = "
425           << value;
426   SetPropertyInternal(
427       dbus::ObjectPath(device_path), name, value, base::DoNothing(),
428       base::BindOnce(&ErrorFunction, device_path), notify_changed);
429 }
430 
GetDevicePathForType(const std::string & type)431 std::string FakeShillDeviceClient::GetDevicePathForType(
432     const std::string& type) {
433   for (auto iter : stub_devices_.DictItems()) {
434     if (!iter.second.is_dict())
435       continue;
436     const std::string* prop_type =
437         iter.second.FindStringKey(shill::kTypeProperty);
438     if (!prop_type || *prop_type != type)
439       continue;
440     return iter.first;
441   }
442   return std::string();
443 }
444 
SetSimLocked(const std::string & device_path,bool locked)445 void FakeShillDeviceClient::SetSimLocked(const std::string& device_path,
446                                          bool locked) {
447   SimLockStatus status = GetSimLockStatus(device_path);
448   status.type = locked ? shill::kSIMLockPin : "";
449   status.retries_left = kSimPinRetryCount;
450   SetSimLockStatus(device_path, status);
451 }
452 
AddCellularFoundNetwork(const std::string & device_path)453 void FakeShillDeviceClient::AddCellularFoundNetwork(
454     const std::string& device_path) {
455   base::Value* device_properties = stub_devices_.FindDictKey(device_path);
456   if (!device_properties) {
457     LOG(ERROR) << "Device path not found: " << device_path;
458     return;
459   }
460   std::string type =
461       device_properties->FindKey(shill::kTypeProperty)->GetString();
462   if (type != shill::kTypeCellular) {
463     LOG(ERROR) << "AddCellularNetwork called for non Cellular network: "
464                << device_path;
465     return;
466   }
467 
468   // Add a new scan result entry
469   base::Value* scan_results =
470       device_properties->FindKey(shill::kFoundNetworksProperty);
471   if (!scan_results) {
472     scan_results = device_properties->SetKey(shill::kFoundNetworksProperty,
473                                              base::ListValue());
474   }
475   base::Value new_result(base::Value::Type::DICTIONARY);
476   int idx = static_cast<int>(scan_results->GetList().size());
477   new_result.SetKey(shill::kNetworkIdProperty,
478                     base::Value(base::StringPrintf("network%d", idx)));
479   new_result.SetKey(shill::kLongNameProperty,
480                     base::Value(base::StringPrintf("Network %d", idx)));
481   new_result.SetKey(shill::kTechnologyProperty, base::Value("GSM"));
482   new_result.SetKey(shill::kStatusProperty, base::Value("available"));
483   scan_results->Append(std::move(new_result));
484   base::ThreadTaskRunnerHandle::Get()->PostTask(
485       FROM_HERE,
486       base::BindOnce(&FakeShillDeviceClient::NotifyObserversPropertyChanged,
487                      weak_ptr_factory_.GetWeakPtr(),
488                      dbus::ObjectPath(device_path),
489                      shill::kFoundNetworksProperty));
490 }
491 
SetUsbEthernetMacAddressSourceError(const std::string & device_path,const std::string & error_name)492 void FakeShillDeviceClient::SetUsbEthernetMacAddressSourceError(
493     const std::string& device_path,
494     const std::string& error_name) {
495   set_usb_ethernet_mac_address_source_error_names_[device_path] = error_name;
496 }
497 
498 // Private Methods -------------------------------------------------------------
499 
GetSimLockStatus(const std::string & device_path)500 FakeShillDeviceClient::SimLockStatus FakeShillDeviceClient::GetSimLockStatus(
501     const std::string& device_path) {
502   SimLockStatus status;
503   base::Value* device_properties = stub_devices_.FindDictKey(device_path);
504   if (!device_properties)
505     return status;
506   base::Value* simlock_dict =
507       device_properties->FindDictKey(shill::kSIMLockStatusProperty);
508   if (!simlock_dict)
509     return status;
510   const std::string* type =
511       simlock_dict->FindStringKey(shill::kSIMLockTypeProperty);
512   if (type)
513     status.type = *type;
514   status.retries_left =
515       simlock_dict->FindIntKey(shill::kSIMLockRetriesLeftProperty).value_or(0);
516   status.lock_enabled =
517       simlock_dict->FindBoolKey(shill::kSIMLockEnabledProperty).value_or(false);
518   if (status.type == shill::kSIMLockPin && status.retries_left == 0)
519     status.retries_left = kSimPinRetryCount;
520   return status;
521 }
522 
SetSimLockStatus(const std::string & device_path,const SimLockStatus & status)523 void FakeShillDeviceClient::SetSimLockStatus(const std::string& device_path,
524                                              const SimLockStatus& status) {
525   base::Value* device_properties = stub_devices_.FindDictKey(device_path);
526   if (!device_properties) {
527     NOTREACHED() << "Device not found: " << device_path;
528     return;
529   }
530 
531   base::Value* simlock_dict =
532       device_properties->SetKey(shill::kSIMLockStatusProperty,
533                                 base::Value(base::Value::Type::DICTIONARY));
534 
535   simlock_dict->SetKey(shill::kSIMLockTypeProperty, base::Value(status.type));
536   simlock_dict->SetKey(shill::kSIMLockRetriesLeftProperty,
537                        base::Value(status.retries_left));
538   simlock_dict->SetKey(shill::kSIMLockEnabledProperty,
539                        base::Value(status.lock_enabled));
540   NotifyObserversPropertyChanged(dbus::ObjectPath(device_path),
541                                  shill::kSIMLockStatusProperty);
542 }
543 
SimTryPin(const std::string & device_path,const std::string & pin)544 bool FakeShillDeviceClient::SimTryPin(const std::string& device_path,
545                                       const std::string& pin) {
546   SimLockStatus status = GetSimLockStatus(device_path);
547   if (status.type == shill::kSIMLockPuk) {
548     VLOG(1) << "SimTryPin called with PUK locked.";
549     return false;  // PUK locked, PIN won't work.
550   }
551   if (pin.length() < kSimPinMinLength)
552     return false;
553   std::string sim_pin = sim_pin_[device_path];
554   if (sim_pin.empty()) {
555     sim_pin = kDefaultSimPin;
556     sim_pin_[device_path] = sim_pin;
557   }
558   if (pin == sim_pin) {
559     status.type = "";
560     status.retries_left = kSimPinRetryCount;
561     SetSimLockStatus(device_path, status);
562     return true;
563   }
564 
565   VLOG(1) << "SIM PIN: " << pin << " != " << sim_pin
566           << " Retries left: " << (status.retries_left - 1);
567   if (--status.retries_left <= 0) {
568     status.retries_left = kSimPukRetryCount;
569     status.type = shill::kSIMLockPuk;
570     status.lock_enabled = true;
571   }
572   SetSimLockStatus(device_path, status);
573   return false;
574 }
575 
SimTryPuk(const std::string & device_path,const std::string & puk)576 bool FakeShillDeviceClient::SimTryPuk(const std::string& device_path,
577                                       const std::string& puk) {
578   SimLockStatus status = GetSimLockStatus(device_path);
579   if (status.type != shill::kSIMLockPuk) {
580     VLOG(1) << "PUK Not locked";
581     return true;  // Not PUK locked.
582   }
583   if (status.retries_left == 0) {
584     VLOG(1) << "PUK: No retries left";
585     return false;  // Permanently locked.
586   }
587 
588   if (puk == kSimPuk) {
589     status.type = "";
590     status.retries_left = kSimPinRetryCount;
591     SetSimLockStatus(device_path, status);
592     return true;
593   }
594 
595   --status.retries_left;
596   VLOG(1) << "SIM PUK: " << puk << " != " << kSimPuk
597           << " Retries left: " << status.retries_left;
598   SetSimLockStatus(device_path, status);
599   return false;
600 }
601 
PassStubDeviceProperties(const dbus::ObjectPath & device_path,DBusMethodCallback<base::Value> callback) const602 void FakeShillDeviceClient::PassStubDeviceProperties(
603     const dbus::ObjectPath& device_path,
604     DBusMethodCallback<base::Value> callback) const {
605   const base::Value* device_properties =
606       stub_devices_.FindDictKey(device_path.value());
607   if (!device_properties) {
608     std::move(callback).Run(base::nullopt);
609     return;
610   }
611   std::move(callback).Run(device_properties->Clone());
612 }
613 
614 // Posts a task to run a void callback with status code |status|.
PostVoidCallback(VoidDBusMethodCallback callback,bool result)615 void FakeShillDeviceClient::PostVoidCallback(VoidDBusMethodCallback callback,
616                                              bool result) {
617   base::ThreadTaskRunnerHandle::Get()->PostTask(
618       FROM_HERE, base::BindOnce(std::move(callback), result));
619 }
620 
NotifyObserversPropertyChanged(const dbus::ObjectPath & device_path,const std::string & property)621 void FakeShillDeviceClient::NotifyObserversPropertyChanged(
622     const dbus::ObjectPath& device_path,
623     const std::string& property) {
624   std::string path = device_path.value();
625   base::Value* device_properties = stub_devices_.FindDictKey(path);
626   if (!device_properties) {
627     LOG(ERROR) << "Notify for unknown device: " << path;
628     return;
629   }
630   base::Value* value = device_properties->FindKey(property);
631   if (!value) {
632     LOG(ERROR) << "Notify for unknown property: " << path << " : " << property;
633     return;
634   }
635   for (auto& observer : GetObserverList(device_path))
636     observer.OnPropertyChanged(property, *value);
637 }
638 
GetDeviceProperties(const std::string & device_path)639 base::Value* FakeShillDeviceClient::GetDeviceProperties(
640     const std::string& device_path) {
641   base::Value* properties = stub_devices_.FindDictKey(device_path);
642   if (!properties) {
643     properties = stub_devices_.SetKey(
644         device_path, base::Value(base::Value::Type::DICTIONARY));
645   }
646   return properties;
647 }
648 
649 FakeShillDeviceClient::PropertyObserverList&
GetObserverList(const dbus::ObjectPath & device_path)650 FakeShillDeviceClient::GetObserverList(const dbus::ObjectPath& device_path) {
651   auto iter = observer_list_.find(device_path);
652   if (iter != observer_list_.end())
653     return *(iter->second);
654   PropertyObserverList* observer_list = new PropertyObserverList();
655   observer_list_[device_path] = base::WrapUnique(observer_list);
656   return *observer_list;
657 }
658 
659 }  // namespace chromeos
660