1 // Copyright (c) 2012 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/network/shill_property_handler.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <sstream>
11 
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/format_macros.h"
15 #include "base/macros.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "chromeos/dbus/shill/shill_device_client.h"
20 #include "chromeos/dbus/shill/shill_ipconfig_client.h"
21 #include "chromeos/dbus/shill/shill_manager_client.h"
22 #include "chromeos/dbus/shill/shill_profile_client.h"
23 #include "chromeos/dbus/shill/shill_service_client.h"
24 #include "chromeos/network/network_event_log.h"
25 #include "chromeos/network/network_state.h"
26 #include "dbus/object_path.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28 
29 namespace {
30 
31 // Limit the number of services or devices we observe. Since they are listed in
32 // priority order, it should be reasonable to ignore services past this.
33 const size_t kMaxObserved = 100;
34 
GetListValue(const std::string & key,const base::Value & value)35 const base::ListValue* GetListValue(const std::string& key,
36                                     const base::Value& value) {
37   const base::ListValue* vlist = nullptr;
38   if (!value.GetAsList(&vlist)) {
39     NET_LOG(ERROR) << "Error parsing key as list: " << key;
40     return nullptr;
41   }
42   return vlist;
43 }
44 
45 }  // namespace
46 
47 namespace chromeos {
48 namespace internal {
49 
50 // Class to manage Shill service property changed observers. Observers are
51 // added on construction and removed on destruction. Runs the handler when
52 // OnPropertyChanged is called.
53 class ShillPropertyObserver : public ShillPropertyChangedObserver {
54  public:
55   using Handler = base::RepeatingCallback<void(ManagedState::ManagedType type,
56                                                const std::string& service,
57                                                const std::string& name,
58                                                const base::Value& value)>;
59 
ShillPropertyObserver(ManagedState::ManagedType type,const std::string & path,const Handler & handler)60   ShillPropertyObserver(ManagedState::ManagedType type,
61                         const std::string& path,
62                         const Handler& handler)
63       : type_(type), path_(path), handler_(handler) {
64     switch (type_) {
65       case ManagedState::MANAGED_TYPE_NETWORK:
66         DVLOG(2) << "ShillPropertyObserver: Network: " << path;
67         ShillServiceClient::Get()->AddPropertyChangedObserver(
68             dbus::ObjectPath(path_), this);
69         break;
70       case ManagedState::MANAGED_TYPE_DEVICE:
71         DVLOG(2) << "ShillPropertyObserver: Device: " << path;
72         ShillDeviceClient::Get()->AddPropertyChangedObserver(
73             dbus::ObjectPath(path_), this);
74         break;
75     }
76   }
77 
~ShillPropertyObserver()78   ~ShillPropertyObserver() override {
79     switch (type_) {
80       case ManagedState::MANAGED_TYPE_NETWORK:
81         ShillServiceClient::Get()->RemovePropertyChangedObserver(
82             dbus::ObjectPath(path_), this);
83         break;
84       case ManagedState::MANAGED_TYPE_DEVICE:
85         ShillDeviceClient::Get()->RemovePropertyChangedObserver(
86             dbus::ObjectPath(path_), this);
87         break;
88     }
89   }
90 
91   // ShillPropertyChangedObserver overrides.
OnPropertyChanged(const std::string & key,const base::Value & value)92   void OnPropertyChanged(const std::string& key,
93                          const base::Value& value) override {
94     handler_.Run(type_, path_, key, value);
95   }
96 
97  private:
98   ManagedState::ManagedType type_;
99   std::string path_;
100   Handler handler_;
101 
102   DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
103 };
104 
105 //------------------------------------------------------------------------------
106 // ShillPropertyHandler
107 
ShillPropertyHandler(Listener * listener)108 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
109     : listener_(listener), shill_manager_(ShillManagerClient::Get()) {}
110 
~ShillPropertyHandler()111 ShillPropertyHandler::~ShillPropertyHandler() {
112   // Delete network service observers.
113   CHECK(shill_manager_ == ShillManagerClient::Get());
114   shill_manager_->RemovePropertyChangedObserver(this);
115 }
116 
Init()117 void ShillPropertyHandler::Init() {
118   UpdateManagerProperties();
119   shill_manager_->AddPropertyChangedObserver(this);
120 }
121 
UpdateManagerProperties()122 void ShillPropertyHandler::UpdateManagerProperties() {
123   NET_LOG(EVENT) << "UpdateManagerProperties";
124   shill_manager_->GetProperties(base::BindOnce(
125       &ShillPropertyHandler::ManagerPropertiesCallback, AsWeakPtr()));
126 }
127 
IsTechnologyAvailable(const std::string & technology) const128 bool ShillPropertyHandler::IsTechnologyAvailable(
129     const std::string& technology) const {
130   return available_technologies_.count(technology) != 0;
131 }
132 
IsTechnologyEnabled(const std::string & technology) const133 bool ShillPropertyHandler::IsTechnologyEnabled(
134     const std::string& technology) const {
135   return enabled_technologies_.count(technology) != 0;
136 }
137 
IsTechnologyEnabling(const std::string & technology) const138 bool ShillPropertyHandler::IsTechnologyEnabling(
139     const std::string& technology) const {
140   return enabling_technologies_.count(technology) != 0;
141 }
142 
IsTechnologyDisabling(const std::string & technology) const143 bool ShillPropertyHandler::IsTechnologyDisabling(
144     const std::string& technology) const {
145   return disabling_technologies_.count(technology) != 0;
146 }
147 
IsTechnologyProhibited(const std::string & technology) const148 bool ShillPropertyHandler::IsTechnologyProhibited(
149     const std::string& technology) const {
150   return prohibited_technologies_.count(technology) != 0;
151 }
152 
IsTechnologyUninitialized(const std::string & technology) const153 bool ShillPropertyHandler::IsTechnologyUninitialized(
154     const std::string& technology) const {
155   return uninitialized_technologies_.count(technology) != 0;
156 }
157 
SetTechnologyEnabled(const std::string & technology,bool enabled,network_handler::ErrorCallback error_callback)158 void ShillPropertyHandler::SetTechnologyEnabled(
159     const std::string& technology,
160     bool enabled,
161     network_handler::ErrorCallback error_callback) {
162   if (enabled) {
163     if (prohibited_technologies_.find(technology) !=
164         prohibited_technologies_.end()) {
165       chromeos::network_handler::RunErrorCallback(
166           std::move(error_callback), "", "prohibited_technologies",
167           "Ignored: Attempt to enable prohibited network technology " +
168               technology);
169       return;
170     }
171     enabling_technologies_.insert(technology);
172     disabling_technologies_.erase(technology);
173     shill_manager_->EnableTechnology(
174         technology, base::DoNothing(),
175         base::BindOnce(&ShillPropertyHandler::EnableTechnologyFailed,
176                        AsWeakPtr(), technology, std::move(error_callback)));
177   } else {
178     // Clear locally from enabling lists and add to the disabling list.
179     enabling_technologies_.erase(technology);
180     disabling_technologies_.insert(technology);
181     shill_manager_->DisableTechnology(
182         technology, base::DoNothing(),
183         base::BindOnce(&ShillPropertyHandler::DisableTechnologyFailed,
184                        AsWeakPtr(), technology, std::move(error_callback)));
185   }
186 }
187 
SetProhibitedTechnologies(const std::vector<std::string> & prohibited_technologies)188 void ShillPropertyHandler::SetProhibitedTechnologies(
189     const std::vector<std::string>& prohibited_technologies) {
190   prohibited_technologies_.clear();
191   prohibited_technologies_.insert(prohibited_technologies.begin(),
192                                   prohibited_technologies.end());
193 
194   // Remove technologies from the other lists.
195   // And manually disable them.
196   for (const auto& technology : prohibited_technologies) {
197     enabling_technologies_.erase(technology);
198     enabled_technologies_.erase(technology);
199     shill_manager_->DisableTechnology(
200         technology, base::DoNothing(),
201         base::BindOnce(&network_handler::ShillErrorCallbackFunction,
202                        "DisableTechnology Failed", technology,
203                        network_handler::ErrorCallback()));
204   }
205 
206   // Send updated prohibited technology list to shill.
207   const std::string prohibited_list =
208       base::JoinString(prohibited_technologies, ",");
209   base::Value value(prohibited_list);
210   shill_manager_->SetProperty(
211       "ProhibitedTechnologies", value, base::DoNothing(),
212       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
213                      "SetTechnologiesProhibited Failed", prohibited_list,
214                      network_handler::ErrorCallback()));
215 }
216 
SetCheckPortalList(const std::string & check_portal_list)217 void ShillPropertyHandler::SetCheckPortalList(
218     const std::string& check_portal_list) {
219   base::Value value(check_portal_list);
220   shill_manager_->SetProperty(
221       shill::kCheckPortalListProperty, value, base::DoNothing(),
222       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
223                      "SetCheckPortalList Failed", "Manager",
224                      network_handler::ErrorCallback()));
225 }
226 
SetWakeOnLanEnabled(bool enabled)227 void ShillPropertyHandler::SetWakeOnLanEnabled(bool enabled) {
228   base::Value value(enabled);
229   shill_manager_->SetProperty(
230       shill::kWakeOnLanEnabledProperty, value, base::DoNothing(),
231       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
232                      "SetWakeOnLanEnabled Failed", "Manager",
233                      network_handler::ErrorCallback()));
234 }
235 
SetHostname(const std::string & hostname)236 void ShillPropertyHandler::SetHostname(const std::string& hostname) {
237   base::Value value(hostname);
238   shill_manager_->SetProperty(
239       shill::kDhcpPropertyHostnameProperty, value, base::DoNothing(),
240       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
241                      "SetHostname Failed", "Manager",
242                      network_handler::ErrorCallback()));
243 }
244 
SetNetworkThrottlingStatus(bool throttling_enabled,uint32_t upload_rate_kbits,uint32_t download_rate_kbits)245 void ShillPropertyHandler::SetNetworkThrottlingStatus(
246     bool throttling_enabled,
247     uint32_t upload_rate_kbits,
248     uint32_t download_rate_kbits) {
249   shill_manager_->SetNetworkThrottlingStatus(
250       ShillManagerClient::NetworkThrottlingStatus{
251           throttling_enabled,
252           upload_rate_kbits,
253           download_rate_kbits,
254       },
255       base::DoNothing(),
256       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
257                      "SetNetworkThrottlingStatus failed", "Manager",
258                      network_handler::ErrorCallback()));
259 }
260 
SetFastTransitionStatus(bool enabled)261 void ShillPropertyHandler::SetFastTransitionStatus(bool enabled) {
262   base::Value value(enabled);
263   shill_manager_->SetProperty(
264       shill::kWifiGlobalFTEnabledProperty, value, base::DoNothing(),
265       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
266                      "SetFastTransitionStatus failed", "Manager",
267                      network_handler::ErrorCallback()));
268 }
269 
RequestScanByType(const std::string & type) const270 void ShillPropertyHandler::RequestScanByType(const std::string& type) const {
271   shill_manager_->RequestScan(
272       type, base::DoNothing(),
273       base::BindOnce(&network_handler::ShillErrorCallbackFunction,
274                      "RequestScan Failed", type,
275                      network_handler::ErrorCallback()));
276 }
277 
RequestProperties(ManagedState::ManagedType type,const std::string & path)278 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
279                                              const std::string& path) {
280   if (pending_updates_[type].find(path) != pending_updates_[type].end())
281     return;  // Update already requested.
282 
283   NET_LOG(DEBUG) << "Request Properties for: " << NetworkPathId(path);
284   pending_updates_[type].insert(path);
285   switch (type) {
286     case ManagedState::MANAGED_TYPE_NETWORK:
287       ShillServiceClient::Get()->GetProperties(
288           dbus::ObjectPath(path),
289           base::BindOnce(&ShillPropertyHandler::GetPropertiesCallback,
290                          AsWeakPtr(), type, path));
291       return;
292     case ManagedState::MANAGED_TYPE_DEVICE:
293       ShillDeviceClient::Get()->GetProperties(
294           dbus::ObjectPath(path),
295           base::BindOnce(&ShillPropertyHandler::GetPropertiesCallback,
296                          AsWeakPtr(), type, path));
297       return;
298   }
299   NOTREACHED();
300 }
301 
OnPropertyChanged(const std::string & key,const base::Value & value)302 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
303                                              const base::Value& value) {
304   ManagerPropertyChanged(key, value);
305   CheckPendingStateListUpdates(key);
306 }
307 
308 //------------------------------------------------------------------------------
309 // Private methods
310 
ManagerPropertiesCallback(base::Optional<base::Value> properties)311 void ShillPropertyHandler::ManagerPropertiesCallback(
312     base::Optional<base::Value> properties) {
313   if (!properties) {
314     NET_LOG(ERROR) << "ManagerPropertiesCallback Failed";
315     return;
316   }
317   NET_LOG(EVENT) << "ManagerPropertiesCallback: Success";
318   for (const auto& item : properties->DictItems()) {
319     ManagerPropertyChanged(item.first, item.second);
320   }
321 
322   CheckPendingStateListUpdates("");
323 }
324 
CheckPendingStateListUpdates(const std::string & key)325 void ShillPropertyHandler::CheckPendingStateListUpdates(
326     const std::string& key) {
327   // Once there are no pending updates, signal the state list changed
328   // callbacks.
329   if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
330       pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
331     listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
332   }
333   if ((key.empty() || key == shill::kDevicesProperty) &&
334       pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
335     listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
336   }
337 }
338 
ManagerPropertyChanged(const std::string & key,const base::Value & value)339 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
340                                                   const base::Value& value) {
341   if (key == shill::kDefaultServiceProperty) {
342     std::string service_path;
343     value.GetAsString(&service_path);
344     NET_LOG(EVENT) << "Manager.DefaultService = "
345                    << NetworkPathId(service_path);
346     listener_->DefaultNetworkServiceChanged(service_path);
347     return;
348   }
349   NET_LOG(DEBUG) << "ManagerPropertyChanged: " << key << " = " << value;
350   if (key == shill::kServiceCompleteListProperty) {
351     const base::ListValue* vlist = GetListValue(key, value);
352     if (vlist) {
353       listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
354       UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
355       UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
356     }
357   } else if (key == shill::kDevicesProperty) {
358     const base::ListValue* vlist = GetListValue(key, value);
359     if (vlist) {
360       listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
361       UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
362       UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
363     }
364   } else if (key == shill::kAvailableTechnologiesProperty) {
365     const base::ListValue* vlist = GetListValue(key, value);
366     if (vlist)
367       UpdateAvailableTechnologies(*vlist);
368   } else if (key == shill::kEnabledTechnologiesProperty) {
369     const base::ListValue* vlist = GetListValue(key, value);
370     if (vlist)
371       UpdateEnabledTechnologies(*vlist);
372   } else if (key == shill::kUninitializedTechnologiesProperty) {
373     const base::ListValue* vlist = GetListValue(key, value);
374     if (vlist)
375       UpdateUninitializedTechnologies(*vlist);
376   } else if (key == shill::kProhibitedTechnologiesProperty) {
377     std::string prohibited_technologies;
378     if (value.GetAsString(&prohibited_technologies))
379       UpdateProhibitedTechnologies(prohibited_technologies);
380   } else if (key == shill::kProfilesProperty) {
381     listener_->ProfileListChanged();
382   } else if (key == shill::kCheckPortalListProperty) {
383     std::string check_portal_list;
384     if (value.GetAsString(&check_portal_list))
385       listener_->CheckPortalListChanged(check_portal_list);
386   } else if (key == shill::kDhcpPropertyHostnameProperty) {
387     std::string hostname;
388     if (value.GetAsString(&hostname))
389       listener_->HostnameChanged(hostname);
390   } else {
391     VLOG(2) << "Ignored Manager Property: " << key;
392   }
393 }
394 
UpdateProperties(ManagedState::ManagedType type,const base::ListValue & entries)395 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
396                                             const base::ListValue& entries) {
397   std::set<std::string>& requested_updates = requested_updates_[type];
398   std::set<std::string> new_requested_updates;
399   NET_LOG(DEBUG) << "UpdateProperties: " << ManagedState::TypeToString(type)
400                  << ": " << entries.GetSize();
401   for (base::ListValue::const_iterator iter = entries.begin();
402        iter != entries.end(); ++iter) {
403     std::string path;
404     iter->GetAsString(&path);
405     if (path.empty())
406       continue;
407 
408     // We add a special case for devices here to work around an issue in shill
409     // that prevents it from sending property changed signals for cellular
410     // devices (see crbug.com/321854).
411     if (type == ManagedState::MANAGED_TYPE_DEVICE ||
412         requested_updates.find(path) == requested_updates.end()) {
413       RequestProperties(type, path);
414     }
415     new_requested_updates.insert(path);
416   }
417   requested_updates.swap(new_requested_updates);
418 }
419 
UpdateObserved(ManagedState::ManagedType type,const base::ListValue & entries)420 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
421                                           const base::ListValue& entries) {
422   ShillPropertyObserverMap& observer_map =
423       (type == ManagedState::MANAGED_TYPE_NETWORK) ? observed_networks_
424                                                    : observed_devices_;
425   ShillPropertyObserverMap new_observed;
426   for (const auto& entry : entries) {
427     std::string path;
428     entry.GetAsString(&path);
429     if (path.empty())
430       continue;
431     auto iter = observer_map.find(path);
432     std::unique_ptr<ShillPropertyObserver> observer;
433     if (iter != observer_map.end()) {
434       observer = std::move(iter->second);
435     } else {
436       // Create an observer for future updates.
437       observer = std::make_unique<ShillPropertyObserver>(
438           type, path,
439           base::BindRepeating(&ShillPropertyHandler::PropertyChangedCallback,
440                               AsWeakPtr()));
441     }
442     auto result =
443         new_observed.insert(std::make_pair(path, std::move(observer)));
444     if (!result.second) {
445       NET_LOG(ERROR) << path << " is duplicated in the list.";
446     }
447     observer_map.erase(path);
448     // Limit the number of observed services.
449     if (new_observed.size() >= kMaxObserved)
450       break;
451   }
452   observer_map.swap(new_observed);
453 }
454 
UpdateAvailableTechnologies(const base::ListValue & technologies)455 void ShillPropertyHandler::UpdateAvailableTechnologies(
456     const base::ListValue& technologies) {
457   NET_LOG(EVENT) << "AvailableTechnologies:" << technologies;
458   std::set<std::string> new_available_technologies;
459   for (const base::Value& technology : technologies.GetList())
460     new_available_technologies.insert(technology.GetString());
461   if (new_available_technologies == available_technologies_)
462     return;
463   available_technologies_.swap(new_available_technologies);
464   // If any entries in |enabling_technologies_| are no longer available,
465   // remove them from the enabling list.
466   for (auto iter = enabling_technologies_.begin();
467        iter != enabling_technologies_.end();) {
468     if (!available_technologies_.count(*iter))
469       iter = enabling_technologies_.erase(iter);
470     else
471       ++iter;
472   }
473   listener_->TechnologyListChanged();
474 }
475 
UpdateEnabledTechnologies(const base::ListValue & technologies)476 void ShillPropertyHandler::UpdateEnabledTechnologies(
477     const base::ListValue& technologies) {
478   NET_LOG(EVENT) << "EnabledTechnologies:" << technologies;
479   std::set<std::string> new_enabled_technologies;
480   for (const base::Value& technology : technologies.GetList())
481     new_enabled_technologies.insert(technology.GetString());
482   if (new_enabled_technologies == enabled_technologies_)
483     return;
484   enabled_technologies_.swap(new_enabled_technologies);
485 
486   // If any entries in |disabling_technologies_| are disabled, remove them
487   // from the disabling list.
488   for (auto it = disabling_technologies_.begin();
489        it != disabling_technologies_.end();) {
490     base::Value technology_value(*it);
491     if (!base::Contains(technologies.GetList(), technology_value))
492       it = disabling_technologies_.erase(it);
493     else
494       ++it;
495   }
496 
497   // If any entries in |enabling_technologies_| are enabled, remove them from
498   // the enabling list.
499   for (auto iter = enabling_technologies_.begin();
500        iter != enabling_technologies_.end();) {
501     if (enabled_technologies_.count(*iter))
502       iter = enabling_technologies_.erase(iter);
503     else
504       ++iter;
505   }
506   listener_->TechnologyListChanged();
507 }
508 
UpdateUninitializedTechnologies(const base::ListValue & technologies)509 void ShillPropertyHandler::UpdateUninitializedTechnologies(
510     const base::ListValue& technologies) {
511   NET_LOG(EVENT) << "UninitializedTechnologies:" << technologies;
512   std::set<std::string> new_uninitialized_technologies;
513   for (const base::Value& technology : technologies.GetList())
514     new_uninitialized_technologies.insert(technology.GetString());
515   if (new_uninitialized_technologies == uninitialized_technologies_)
516     return;
517   uninitialized_technologies_.swap(new_uninitialized_technologies);
518   listener_->TechnologyListChanged();
519 }
520 
UpdateProhibitedTechnologies(const std::string & technologies)521 void ShillPropertyHandler::UpdateProhibitedTechnologies(
522     const std::string& technologies) {
523   std::vector<std::string> prohibited_list = base::SplitString(
524       technologies, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
525   std::set<std::string> new_prohibited_technologies(prohibited_list.begin(),
526                                                     prohibited_list.end());
527   if (new_prohibited_technologies == prohibited_technologies_)
528     return;
529   prohibited_technologies_.swap(new_prohibited_technologies);
530   listener_->TechnologyListChanged();
531 }
532 
EnableTechnologyFailed(const std::string & technology,network_handler::ErrorCallback error_callback,const std::string & dbus_error_name,const std::string & dbus_error_message)533 void ShillPropertyHandler::EnableTechnologyFailed(
534     const std::string& technology,
535     network_handler::ErrorCallback error_callback,
536     const std::string& dbus_error_name,
537     const std::string& dbus_error_message) {
538   enabling_technologies_.erase(technology);
539   network_handler::ShillErrorCallbackFunction(
540       "EnableTechnology Failed", technology, std::move(error_callback),
541       dbus_error_name, dbus_error_message);
542   listener_->TechnologyListChanged();
543 }
544 
DisableTechnologyFailed(const std::string & technology,network_handler::ErrorCallback error_callback,const std::string & dbus_error_name,const std::string & dbus_error_message)545 void ShillPropertyHandler::DisableTechnologyFailed(
546     const std::string& technology,
547     network_handler::ErrorCallback error_callback,
548     const std::string& dbus_error_name,
549     const std::string& dbus_error_message) {
550   disabling_technologies_.erase(technology);
551   network_handler::ShillErrorCallbackFunction(
552       "DisableTechnology Failed", technology, std::move(error_callback),
553       dbus_error_name, dbus_error_message);
554   listener_->TechnologyListChanged();
555 }
556 
GetPropertiesCallback(ManagedState::ManagedType type,const std::string & path,base::Optional<base::Value> properties)557 void ShillPropertyHandler::GetPropertiesCallback(
558     ManagedState::ManagedType type,
559     const std::string& path,
560     base::Optional<base::Value> properties) {
561   pending_updates_[type].erase(path);
562   if (!properties) {
563     // The shill service no longer exists.  This can happen when a network
564     // has been removed.
565     return;
566   }
567   NET_LOG(DEBUG) << "GetProperties received for " << NetworkPathId(path);
568   listener_->UpdateManagedStateProperties(type, path, *properties);
569 
570   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
571     // Request IPConfig properties.
572     const base::Value* value = properties->FindKey(shill::kIPConfigProperty);
573     if (value)
574       RequestIPConfig(type, path, *value);
575   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
576     // Clear and request IPConfig properties for each entry in IPConfigs.
577     const base::Value* value = properties->FindKey(shill::kIPConfigsProperty);
578     if (value)
579       RequestIPConfigsList(type, path, *value);
580   }
581 
582   // Notify the listener only when all updates for that type have completed.
583   if (pending_updates_[type].size() == 0)
584     listener_->ManagedStateListChanged(type);
585 }
586 
PropertyChangedCallback(ManagedState::ManagedType type,const std::string & path,const std::string & key,const base::Value & value)587 void ShillPropertyHandler::PropertyChangedCallback(
588     ManagedState::ManagedType type,
589     const std::string& path,
590     const std::string& key,
591     const base::Value& value) {
592   if (type == ManagedState::MANAGED_TYPE_NETWORK &&
593       key == shill::kIPConfigProperty) {
594     RequestIPConfig(type, path, value);
595   } else if (type == ManagedState::MANAGED_TYPE_DEVICE &&
596              key == shill::kIPConfigsProperty) {
597     RequestIPConfigsList(type, path, value);
598   }
599 
600   switch (type) {
601     case ManagedState::MANAGED_TYPE_NETWORK:
602       listener_->UpdateNetworkServiceProperty(path, key, value);
603       return;
604     case ManagedState::MANAGED_TYPE_DEVICE:
605       listener_->UpdateDeviceProperty(path, key, value);
606       return;
607   }
608   NOTREACHED();
609 }
610 
RequestIPConfig(ManagedState::ManagedType type,const std::string & path,const base::Value & ip_config_path_value)611 void ShillPropertyHandler::RequestIPConfig(
612     ManagedState::ManagedType type,
613     const std::string& path,
614     const base::Value& ip_config_path_value) {
615   std::string ip_config_path;
616   if (!ip_config_path_value.GetAsString(&ip_config_path) ||
617       ip_config_path.empty()) {
618     NET_LOG(ERROR) << "Invalid IPConfig: " << path;
619     return;
620   }
621   ShillIPConfigClient::Get()->GetProperties(
622       dbus::ObjectPath(ip_config_path),
623       base::BindOnce(&ShillPropertyHandler::GetIPConfigCallback, AsWeakPtr(),
624                      type, path, ip_config_path));
625 }
626 
RequestIPConfigsList(ManagedState::ManagedType type,const std::string & path,const base::Value & ip_config_list_value)627 void ShillPropertyHandler::RequestIPConfigsList(
628     ManagedState::ManagedType type,
629     const std::string& path,
630     const base::Value& ip_config_list_value) {
631   const base::ListValue* ip_configs;
632   if (!ip_config_list_value.GetAsList(&ip_configs))
633     return;
634   for (base::ListValue::const_iterator iter = ip_configs->begin();
635        iter != ip_configs->end(); ++iter) {
636     RequestIPConfig(type, path, *iter);
637   }
638 }
639 
GetIPConfigCallback(ManagedState::ManagedType type,const std::string & path,const std::string & ip_config_path,base::Optional<base::Value> properties)640 void ShillPropertyHandler::GetIPConfigCallback(
641     ManagedState::ManagedType type,
642     const std::string& path,
643     const std::string& ip_config_path,
644     base::Optional<base::Value> properties) {
645   if (!properties) {
646     // IP Config properties not available. Shill will emit a property change
647     // when they are.
648     NET_LOG(EVENT) << "Failed to get IP Config properties: " << ip_config_path
649                    << ", For: " << NetworkPathId(path);
650     return;
651   }
652   NET_LOG(EVENT) << "IP Config properties received: " << NetworkPathId(path);
653   listener_->UpdateIPConfigProperties(type, path, ip_config_path, *properties);
654 }
655 
656 }  // namespace internal
657 }  // namespace chromeos
658