Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / shill_property_handler.cc
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 "base/bind.h"
8 #include "base/format_macros.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_ipconfig_client.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/shill_profile_client.h"
18 #include "chromeos/dbus/shill_service_client.h"
19 #include "chromeos/network/network_event_log.h"
20 #include "chromeos/network/network_state.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 namespace {
25
26 // Limit the number of services or devices we observe. Since they are listed in
27 // priority order, it should be reasonable to ignore services past this.
28 const size_t kMaxObserved = 100;
29
30 const base::ListValue* GetListValue(const std::string& key,
31                                     const base::Value& value) {
32   const base::ListValue* vlist = NULL;
33   if (!value.GetAsList(&vlist)) {
34     LOG(ERROR) << "Error parsing key as list: " << key;
35     return NULL;
36   }
37   return vlist;
38 }
39
40 }  // namespace
41
42 namespace chromeos {
43 namespace internal {
44
45 // Class to manage Shill service property changed observers. Observers are
46 // added on construction and removed on destruction. Runs the handler when
47 // OnPropertyChanged is called.
48 class ShillPropertyObserver : public ShillPropertyChangedObserver {
49  public:
50   typedef base::Callback<void(ManagedState::ManagedType type,
51                               const std::string& service,
52                               const std::string& name,
53                               const base::Value& value)> Handler;
54
55   ShillPropertyObserver(ManagedState::ManagedType type,
56                         const std::string& path,
57                         const Handler& handler)
58       : type_(type),
59         path_(path),
60         handler_(handler) {
61     if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
62       DBusThreadManager::Get()->GetShillServiceClient()->
63           AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
64     } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
65       DBusThreadManager::Get()->GetShillDeviceClient()->
66           AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
67     } else {
68       NOTREACHED();
69     }
70   }
71
72   virtual ~ShillPropertyObserver() {
73     if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
74       DBusThreadManager::Get()->GetShillServiceClient()->
75           RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
76     } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
77       DBusThreadManager::Get()->GetShillDeviceClient()->
78           RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
79     } else {
80       NOTREACHED();
81     }
82   }
83
84   // ShillPropertyChangedObserver overrides.
85   virtual void OnPropertyChanged(const std::string& key,
86                                  const base::Value& value) OVERRIDE {
87     handler_.Run(type_, path_, key, value);
88   }
89
90  private:
91   ManagedState::ManagedType type_;
92   std::string path_;
93   Handler handler_;
94
95   DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
96 };
97
98 //------------------------------------------------------------------------------
99 // ShillPropertyHandler
100
101 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
102     : listener_(listener),
103       shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
104 }
105
106 ShillPropertyHandler::~ShillPropertyHandler() {
107   // Delete network service observers.
108   STLDeleteContainerPairSecondPointers(
109       observed_networks_.begin(), observed_networks_.end());
110   STLDeleteContainerPairSecondPointers(
111       observed_devices_.begin(), observed_devices_.end());
112   CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
113   shill_manager_->RemovePropertyChangedObserver(this);
114 }
115
116 void ShillPropertyHandler::Init() {
117   UpdateManagerProperties();
118   shill_manager_->AddPropertyChangedObserver(this);
119 }
120
121 void ShillPropertyHandler::UpdateManagerProperties() {
122   NET_LOG_EVENT("UpdateManagerProperties", "");
123   shill_manager_->GetProperties(
124       base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
125                  AsWeakPtr()));
126 }
127
128 bool ShillPropertyHandler::IsTechnologyAvailable(
129     const std::string& technology) const {
130   return available_technologies_.count(technology) != 0;
131 }
132
133 bool ShillPropertyHandler::IsTechnologyEnabled(
134     const std::string& technology) const {
135   return enabled_technologies_.count(technology) != 0;
136 }
137
138 bool ShillPropertyHandler::IsTechnologyEnabling(
139     const std::string& technology) const {
140   return enabling_technologies_.count(technology) != 0;
141 }
142
143 bool ShillPropertyHandler::IsTechnologyUninitialized(
144     const std::string& technology) const {
145   return uninitialized_technologies_.count(technology) != 0;
146 }
147
148 void ShillPropertyHandler::SetTechnologyEnabled(
149     const std::string& technology,
150     bool enabled,
151     const network_handler::ErrorCallback& error_callback) {
152   if (enabled) {
153     enabling_technologies_.insert(technology);
154     shill_manager_->EnableTechnology(
155         technology,
156         base::Bind(&base::DoNothing),
157         base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
158                    AsWeakPtr(), technology, error_callback));
159   } else {
160     // Immediately clear locally from enabled and enabling lists.
161     enabled_technologies_.erase(technology);
162     enabling_technologies_.erase(technology);
163     shill_manager_->DisableTechnology(
164         technology,
165         base::Bind(&base::DoNothing),
166         base::Bind(&network_handler::ShillErrorCallbackFunction,
167                    "SetTechnologyEnabled Failed",
168                    technology, error_callback));
169   }
170 }
171
172 void ShillPropertyHandler::SetCheckPortalList(
173     const std::string& check_portal_list) {
174   base::StringValue value(check_portal_list);
175   shill_manager_->SetProperty(
176       shill::kCheckPortalListProperty,
177       value,
178       base::Bind(&base::DoNothing),
179       base::Bind(&network_handler::ShillErrorCallbackFunction,
180                  "SetCheckPortalList Failed",
181                  "", network_handler::ErrorCallback()));
182 }
183
184 void ShillPropertyHandler::RequestScan() const {
185   shill_manager_->RequestScan(
186       "",
187       base::Bind(&base::DoNothing),
188       base::Bind(&network_handler::ShillErrorCallbackFunction,
189                  "RequestScan Failed",
190                  "", network_handler::ErrorCallback()));
191 }
192
193 void ShillPropertyHandler::ConnectToBestServices() const {
194   NET_LOG_EVENT("ConnectToBestServices", "");
195   shill_manager_->ConnectToBestServices(
196       base::Bind(&base::DoNothing),
197       base::Bind(&network_handler::ShillErrorCallbackFunction,
198                  "ConnectToBestServices Failed",
199                  "", network_handler::ErrorCallback()));
200 }
201
202 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
203                                              const std::string& path) {
204   if (pending_updates_[type].find(path) != pending_updates_[type].end())
205     return;  // Update already requested.
206
207   NET_LOG_DEBUG("Request Properties", path);
208   pending_updates_[type].insert(path);
209   if (type == ManagedState::MANAGED_TYPE_NETWORK ||
210       type == ManagedState::MANAGED_TYPE_FAVORITE) {
211     DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
212         dbus::ObjectPath(path),
213         base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
214                    AsWeakPtr(), type, path));
215   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
216     DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
217         dbus::ObjectPath(path),
218         base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
219                    AsWeakPtr(), type, path));
220   } else {
221     NOTREACHED();
222   }
223 }
224
225 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
226                                              const base::Value& value) {
227   ManagerPropertyChanged(key, value);
228   CheckPendingStateListUpdates(key);
229 }
230
231 //------------------------------------------------------------------------------
232 // Private methods
233
234 void ShillPropertyHandler::ManagerPropertiesCallback(
235     DBusMethodCallStatus call_status,
236     const base::DictionaryValue& properties) {
237   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
238     NET_LOG_ERROR("ManagerPropertiesCallback",
239                   base::StringPrintf("Failed: %d", call_status));
240     return;
241   }
242   NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
243   const base::Value* update_service_value = NULL;
244   const base::Value* update_service_complete_value = NULL;
245   for (base::DictionaryValue::Iterator iter(properties);
246        !iter.IsAtEnd(); iter.Advance()) {
247     // Defer updating Services until all other properties have been updated.
248     if (iter.key() == shill::kServicesProperty)
249       update_service_value = &iter.value();
250     else if (iter.key() == shill::kServiceCompleteListProperty)
251       update_service_complete_value = &iter.value();
252     else
253       ManagerPropertyChanged(iter.key(), iter.value());
254   }
255   // Update Services which can safely assume other properties have been set.
256   if (update_service_value)
257     ManagerPropertyChanged(shill::kServicesProperty, *update_service_value);
258   // Update ServiceCompleteList which skips entries that have already been
259   // requested for Services.
260   if (update_service_complete_value) {
261     ManagerPropertyChanged(shill::kServiceCompleteListProperty,
262                            *update_service_complete_value);
263   }
264
265   CheckPendingStateListUpdates("");
266 }
267
268 void ShillPropertyHandler::CheckPendingStateListUpdates(
269     const std::string& key) {
270   // Once there are no pending updates, signal the state list changed callbacks.
271   if ((key.empty() || key == shill::kServicesProperty) &&
272       pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
273     listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
274   }
275   // Both Network update requests and Favorite update requests will affect
276   // the list of favorites, so wait for both to complete.
277   if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
278       pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0 &&
279       pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
280     listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
281   }
282   if ((key.empty() || key == shill::kDevicesProperty) &&
283       pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
284     listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
285   }
286 }
287
288 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
289                                                   const base::Value& value) {
290   if (key == shill::kDefaultServiceProperty) {
291     std::string service_path;
292     value.GetAsString(&service_path);
293     listener_->DefaultNetworkServiceChanged(service_path);
294   } else if (key == shill::kServicesProperty) {
295     const base::ListValue* vlist = GetListValue(key, value);
296     if (vlist) {
297       listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
298       UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
299       // UpdateObserved used to use kServiceWatchListProperty for TYPE_NETWORK,
300       // however that prevents us from receiving Strength updates from inactive
301       // networks. The overhead for observing all services is not unreasonable
302       // (and we limit the max number of observed services to kMaxObserved).
303       UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
304     }
305   } else if (key == shill::kServiceCompleteListProperty) {
306     const base::ListValue* vlist = GetListValue(key, value);
307     if (vlist) {
308       listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
309       UpdateProperties(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
310     }
311   } else if (key == shill::kDevicesProperty) {
312     const base::ListValue* vlist = GetListValue(key, value);
313     if (vlist) {
314       listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
315       UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
316       UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
317     }
318   } else if (key == shill::kAvailableTechnologiesProperty) {
319     const base::ListValue* vlist = GetListValue(key, value);
320     if (vlist)
321       UpdateAvailableTechnologies(*vlist);
322   } else if (key == shill::kEnabledTechnologiesProperty) {
323     const base::ListValue* vlist = GetListValue(key, value);
324     if (vlist)
325       UpdateEnabledTechnologies(*vlist);
326   } else if (key == shill::kUninitializedTechnologiesProperty) {
327     const base::ListValue* vlist = GetListValue(key, value);
328     if (vlist)
329       UpdateUninitializedTechnologies(*vlist);
330   } else if (key == shill::kProfilesProperty) {
331     listener_->ProfileListChanged();
332   } else if (key == shill::kCheckPortalListProperty) {
333     std::string check_portal_list;
334     if (value.GetAsString(&check_portal_list))
335       listener_->CheckPortalListChanged(check_portal_list);
336   } else {
337     VLOG(2) << "Ignored Manager Property: " << key;
338   }
339 }
340
341 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
342                                             const base::ListValue& entries) {
343   std::set<std::string>& requested_updates = requested_updates_[type];
344   std::set<std::string>& requested_service_updates =
345       requested_updates_[ManagedState::MANAGED_TYPE_NETWORK];  // For favorites
346   std::set<std::string> new_requested_updates;
347   NET_LOG_DEBUG(
348       base::StringPrintf("UpdateProperties: %" PRIuS, entries.GetSize()),
349       ManagedState::TypeToString(type));
350   for (base::ListValue::const_iterator iter = entries.begin();
351        iter != entries.end(); ++iter) {
352     std::string path;
353     (*iter)->GetAsString(&path);
354     if (path.empty())
355       continue;
356     if (type == ManagedState::MANAGED_TYPE_FAVORITE &&
357         requested_service_updates.count(path) > 0)
358       continue;  // Update already requested
359
360     // We add a special case for devices here to work around an issue in shill
361     // that prevents it from sending property changed signals for cellular
362     // devices (see crbug.com/321854).
363     if (type == ManagedState::MANAGED_TYPE_DEVICE ||
364         requested_updates.find(path) == requested_updates.end())
365       RequestProperties(type, path);
366     new_requested_updates.insert(path);
367   }
368   requested_updates.swap(new_requested_updates);
369 }
370
371 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
372                                           const base::ListValue& entries) {
373   DCHECK(type == ManagedState::MANAGED_TYPE_NETWORK ||
374          type == ManagedState::MANAGED_TYPE_DEVICE);
375   ShillPropertyObserverMap& observer_map =
376       (type == ManagedState::MANAGED_TYPE_NETWORK)
377       ? observed_networks_ : observed_devices_;
378   ShillPropertyObserverMap new_observed;
379   for (base::ListValue::const_iterator iter1 = entries.begin();
380        iter1 != entries.end(); ++iter1) {
381     std::string path;
382     (*iter1)->GetAsString(&path);
383     if (path.empty())
384       continue;
385     ShillPropertyObserverMap::iterator iter2 = observer_map.find(path);
386     if (iter2 != observer_map.end()) {
387       new_observed[path] = iter2->second;
388     } else {
389       // Create an observer for future updates.
390       new_observed[path] = new ShillPropertyObserver(
391           type, path, base::Bind(
392               &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
393     }
394     observer_map.erase(path);
395     // Limit the number of observed services.
396     if (new_observed.size() >= kMaxObserved)
397       break;
398   }
399   // Delete network service observers still in observer_map.
400   for (ShillPropertyObserverMap::iterator iter =  observer_map.begin();
401        iter != observer_map.end(); ++iter) {
402     delete iter->second;
403   }
404   observer_map.swap(new_observed);
405 }
406
407 void ShillPropertyHandler::UpdateAvailableTechnologies(
408     const base::ListValue& technologies) {
409   available_technologies_.clear();
410   NET_LOG_EVENT("AvailableTechnologiesChanged",
411                 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
412   for (base::ListValue::const_iterator iter = technologies.begin();
413        iter != technologies.end(); ++iter) {
414     std::string technology;
415     (*iter)->GetAsString(&technology);
416     DCHECK(!technology.empty());
417     available_technologies_.insert(technology);
418   }
419   listener_->TechnologyListChanged();
420 }
421
422 void ShillPropertyHandler::UpdateEnabledTechnologies(
423     const base::ListValue& technologies) {
424   enabled_technologies_.clear();
425   NET_LOG_EVENT("EnabledTechnologiesChanged",
426                 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
427   for (base::ListValue::const_iterator iter = technologies.begin();
428        iter != technologies.end(); ++iter) {
429     std::string technology;
430     (*iter)->GetAsString(&technology);
431     DCHECK(!technology.empty());
432     enabled_technologies_.insert(technology);
433     enabling_technologies_.erase(technology);
434   }
435   listener_->TechnologyListChanged();
436 }
437
438 void ShillPropertyHandler::UpdateUninitializedTechnologies(
439     const base::ListValue& technologies) {
440   uninitialized_technologies_.clear();
441   NET_LOG_EVENT("UninitializedTechnologiesChanged",
442                 base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
443   for (base::ListValue::const_iterator iter = technologies.begin();
444        iter != technologies.end(); ++iter) {
445     std::string technology;
446     (*iter)->GetAsString(&technology);
447     DCHECK(!technology.empty());
448     uninitialized_technologies_.insert(technology);
449   }
450   listener_->TechnologyListChanged();
451 }
452
453 void ShillPropertyHandler::EnableTechnologyFailed(
454     const std::string& technology,
455     const network_handler::ErrorCallback& error_callback,
456     const std::string& dbus_error_name,
457     const std::string& dbus_error_message) {
458   enabling_technologies_.erase(technology);
459   network_handler::ShillErrorCallbackFunction(
460       "EnableTechnology Failed",
461       technology, error_callback,
462       dbus_error_name, dbus_error_message);
463 }
464
465 void ShillPropertyHandler::GetPropertiesCallback(
466     ManagedState::ManagedType type,
467     const std::string& path,
468     DBusMethodCallStatus call_status,
469     const base::DictionaryValue& properties) {
470   NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
471                 path);
472   pending_updates_[type].erase(path);
473   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
474     // The shill service no longer exists.  This can happen when a network
475     // has been removed.
476     NET_LOG_DEBUG("Failed to get properties",
477                   base::StringPrintf("%s: %d", path.c_str(), call_status));
478     return;
479   }
480   // Update Favorite properties for networks in the Services list.
481   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
482     // Only networks with a ProfilePath set are Favorites.
483     std::string profile_path;
484     properties.GetStringWithoutPathExpansion(
485         shill::kProfileProperty, &profile_path);
486     if (!profile_path.empty()) {
487       listener_->UpdateManagedStateProperties(
488           ManagedState::MANAGED_TYPE_FAVORITE, path, properties);
489     }
490   }
491   listener_->UpdateManagedStateProperties(type, path, properties);
492
493   if (type == ManagedState::MANAGED_TYPE_NETWORK) {
494     // Request IPConfig properties.
495     const base::Value* value;
496     if (properties.GetWithoutPathExpansion(shill::kIPConfigProperty, &value))
497       RequestIPConfig(type, path, *value);
498   } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
499     // Clear and request IPConfig properties for each entry in IPConfigs.
500     const base::Value* value;
501     if (properties.GetWithoutPathExpansion(shill::kIPConfigsProperty, &value))
502       RequestIPConfigsList(type, path, *value);
503   }
504
505   // Notify the listener only when all updates for that type have completed.
506   if (pending_updates_[type].size() == 0) {
507     listener_->ManagedStateListChanged(type);
508     // Notify that Favorites have changed when notifying for Networks if there
509     // are no additional Favorite updates pending.
510     if (type == ManagedState::MANAGED_TYPE_NETWORK &&
511         pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
512       listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
513     }
514   }
515 }
516
517 void ShillPropertyHandler::PropertyChangedCallback(
518     ManagedState::ManagedType type,
519     const std::string& path,
520     const std::string& key,
521     const base::Value& value) {
522   if (type == ManagedState::MANAGED_TYPE_NETWORK &&
523       key == shill::kIPConfigProperty) {
524     RequestIPConfig(type, path, value);
525   } else if (type == ManagedState::MANAGED_TYPE_DEVICE &&
526       key == shill::kIPConfigsProperty) {
527     RequestIPConfigsList(type, path, value);
528   }
529
530   if (type == ManagedState::MANAGED_TYPE_NETWORK)
531     listener_->UpdateNetworkServiceProperty(path, key, value);
532   else if (type == ManagedState::MANAGED_TYPE_DEVICE)
533     listener_->UpdateDeviceProperty(path, key, value);
534   else
535     NOTREACHED();
536 }
537
538 void ShillPropertyHandler::RequestIPConfig(
539     ManagedState::ManagedType type,
540     const std::string& path,
541     const base::Value& ip_config_path_value) {
542   std::string ip_config_path;
543   if (!ip_config_path_value.GetAsString(&ip_config_path) ||
544       ip_config_path.empty()) {
545     NET_LOG_ERROR("Invalid IPConfig", path);
546     return;
547   }
548   DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
549       dbus::ObjectPath(ip_config_path),
550       base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
551                  AsWeakPtr(), type, path, ip_config_path));
552 }
553
554 void ShillPropertyHandler::RequestIPConfigsList(
555     ManagedState::ManagedType type,
556     const std::string& path,
557     const base::Value& ip_config_list_value) {
558   const base::ListValue* ip_configs;
559   if (!ip_config_list_value.GetAsList(&ip_configs))
560     return;
561   for (base::ListValue::const_iterator iter = ip_configs->begin();
562        iter != ip_configs->end(); ++iter) {
563     RequestIPConfig(type, path, **iter);
564   }
565 }
566
567 void ShillPropertyHandler::GetIPConfigCallback(
568     ManagedState::ManagedType type,
569     const std::string& path,
570     const std::string& ip_config_path,
571     DBusMethodCallStatus call_status,
572     const base::DictionaryValue& properties)  {
573   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
574     NET_LOG_ERROR("Failed to get IP Config properties",
575                   base::StringPrintf("%s: %d", path.c_str(), call_status));
576     return;
577   }
578   NET_LOG_EVENT("IP Config properties received", path);
579   listener_->UpdateIPConfigProperties(type, path, ip_config_path, properties);
580 }
581
582 }  // namespace internal
583 }  // namespace chromeos