managed_network_configuration_handler_impl.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/network/managed_network_configuration_handler_impl.h"
6
7#include <set>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/guid.h"
12#include "base/location.h"
13#include "base/logging.h"
14#include "base/memory/ref_counted.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/stl_util.h"
17#include "base/values.h"
18#include "chromeos/dbus/shill_manager_client.h"
19#include "chromeos/dbus/shill_profile_client.h"
20#include "chromeos/dbus/shill_service_client.h"
21#include "chromeos/network/device_state.h"
22#include "chromeos/network/network_configuration_handler.h"
23#include "chromeos/network/network_device_handler.h"
24#include "chromeos/network/network_event_log.h"
25#include "chromeos/network/network_policy_observer.h"
26#include "chromeos/network/network_profile.h"
27#include "chromeos/network/network_profile_handler.h"
28#include "chromeos/network/network_state.h"
29#include "chromeos/network/network_state_handler.h"
30#include "chromeos/network/network_ui_data.h"
31#include "chromeos/network/onc/onc_merger.h"
32#include "chromeos/network/onc/onc_signature.h"
33#include "chromeos/network/onc/onc_translator.h"
34#include "chromeos/network/onc/onc_validator.h"
35#include "chromeos/network/policy_util.h"
36#include "chromeos/network/shill_property_util.h"
37#include "components/onc/onc_constants.h"
38#include "third_party/cros_system_api/dbus/service_constants.h"
39
40namespace chromeos {
41
42namespace {
43
44typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
45
46// These are error strings used for error callbacks. None of these error
47// messages are user-facing: they should only appear in logs.
48const char kInvalidUserSettings[] = "InvalidUserSettings";
49const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
50const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
51const char kProfileNotInitialized[] = "ProflieNotInitialized";
52const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
53const char kUnknownProfilePath[] = "UnknownProfilePath";
54const char kUnknownNetwork[] = "UnknownNetwork";
55
56std::string ToDebugString(::onc::ONCSource source,
57                          const std::string& userhash) {
58  return source == ::onc::ONC_SOURCE_USER_POLICY ?
59      ("user policy of " + userhash) : "device policy";
60}
61
62void InvokeErrorCallback(const std::string& service_path,
63                         const network_handler::ErrorCallback& error_callback,
64                         const std::string& error_name) {
65  std::string error_msg = "ManagedConfig Error: " + error_name;
66  NET_LOG_ERROR(error_msg, service_path);
67  network_handler::RunErrorCallback(
68      error_callback, service_path, error_name, error_msg);
69}
70
71void LogErrorWithDict(const tracked_objects::Location& from_where,
72                      const std::string& error_name,
73                      scoped_ptr<base::DictionaryValue> error_data) {
74  network_event_log::internal::AddEntry(
75       from_where.file_name(), from_where.line_number(),
76       network_event_log::LOG_LEVEL_ERROR,
77       error_name, "");
78}
79
80const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
81                                       const std::string& guid) {
82  GuidToPolicyMap::const_iterator it = policies.find(guid);
83  if (it == policies.end())
84    return NULL;
85  return it->second;
86}
87
88}  // namespace
89
90struct ManagedNetworkConfigurationHandlerImpl::Policies {
91  ~Policies();
92
93  GuidToPolicyMap per_network_config;
94  base::DictionaryValue global_network_config;
95};
96
97ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
98  STLDeleteValues(&per_network_config);
99}
100
101void ManagedNetworkConfigurationHandlerImpl::AddObserver(
102    NetworkPolicyObserver* observer) {
103  observers_.AddObserver(observer);
104}
105
106void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
107    NetworkPolicyObserver* observer) {
108  observers_.RemoveObserver(observer);
109}
110
111// GetManagedProperties
112
113void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
114    const std::string& userhash,
115    const std::string& service_path,
116    const network_handler::DictionaryResultCallback& callback,
117    const network_handler::ErrorCallback& error_callback) {
118  if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
119    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
120    return;
121  }
122  network_configuration_handler_->GetProperties(
123      service_path,
124      base::Bind(
125          &ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback,
126          weak_ptr_factory_.GetWeakPtr(),
127          base::Bind(
128              &ManagedNetworkConfigurationHandlerImpl::SendManagedProperties,
129              weak_ptr_factory_.GetWeakPtr(),
130              userhash,
131              callback,
132              error_callback)),
133      error_callback);
134}
135
136void ManagedNetworkConfigurationHandlerImpl::SendManagedProperties(
137    const std::string& userhash,
138    const network_handler::DictionaryResultCallback& callback,
139    const network_handler::ErrorCallback& error_callback,
140    const std::string& service_path,
141    scoped_ptr<base::DictionaryValue> shill_properties) {
142  std::string profile_path;
143  shill_properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
144                                                  &profile_path);
145  const NetworkProfile* profile =
146      network_profile_handler_->GetProfileForPath(profile_path);
147  if (!profile)
148    NET_LOG_ERROR("No profile for service: " + profile_path, service_path);
149
150  scoped_ptr<NetworkUIData> ui_data =
151      shill_property_util::GetUIDataFromProperties(*shill_properties);
152
153  const base::DictionaryValue* user_settings = NULL;
154
155  if (ui_data && profile) {
156    user_settings = ui_data->user_settings();
157  } else if (profile) {
158    NET_LOG_ERROR("Service contains empty or invalid UIData", service_path);
159    // TODO(pneubeck): add a conversion of user configured entries of old
160    // ChromeOS versions. We will have to use a heuristic to determine which
161    // properties _might_ be user configured.
162  }
163
164  std::string guid;
165  shill_properties->GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
166
167  ::onc::ONCSource onc_source;
168  FindPolicyByGUID(userhash, guid, &onc_source);
169  scoped_ptr<base::DictionaryValue> active_settings(
170      onc::TranslateShillServiceToONCPart(
171          *shill_properties, onc_source, &onc::kNetworkWithStateSignature));
172
173  const base::DictionaryValue* network_policy = NULL;
174  const base::DictionaryValue* global_policy = NULL;
175  if (profile) {
176    const Policies* policies = GetPoliciesForProfile(*profile);
177    if (!policies) {
178      InvokeErrorCallback(
179          service_path, error_callback, kPoliciesNotInitialized);
180      return;
181    }
182    if (!guid.empty())
183      network_policy = GetByGUID(policies->per_network_config, guid);
184    global_policy = &policies->global_network_config;
185  }
186
187  scoped_ptr<base::DictionaryValue> augmented_properties(
188      policy_util::CreateManagedONC(global_policy,
189                                    network_policy,
190                                    user_settings,
191                                    active_settings.get(),
192                                    profile));
193  callback.Run(service_path, *augmented_properties);
194}
195
196// GetProperties
197
198void ManagedNetworkConfigurationHandlerImpl::GetProperties(
199    const std::string& service_path,
200    const network_handler::DictionaryResultCallback& callback,
201    const network_handler::ErrorCallback& error_callback) {
202  network_configuration_handler_->GetProperties(
203      service_path,
204      base::Bind(
205          &ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback,
206          weak_ptr_factory_.GetWeakPtr(),
207          base::Bind(&ManagedNetworkConfigurationHandlerImpl::SendProperties,
208                     weak_ptr_factory_.GetWeakPtr(),
209                     callback,
210                     error_callback)),
211      error_callback);
212}
213
214void ManagedNetworkConfigurationHandlerImpl::SendProperties(
215    const network_handler::DictionaryResultCallback& callback,
216    const network_handler::ErrorCallback& error_callback,
217    const std::string& service_path,
218    scoped_ptr<base::DictionaryValue> shill_properties) {
219  scoped_ptr<base::DictionaryValue> onc_network(
220      onc::TranslateShillServiceToONCPart(
221          *shill_properties, ::onc::ONC_SOURCE_UNKNOWN,
222          &onc::kNetworkWithStateSignature));
223  callback.Run(service_path, *onc_network);
224}
225
226// SetProperties
227
228void ManagedNetworkConfigurationHandlerImpl::SetProperties(
229    const std::string& service_path,
230    const base::DictionaryValue& user_settings,
231    const base::Closure& callback,
232    const network_handler::ErrorCallback& error_callback) const {
233  const NetworkState* state =
234      network_state_handler_->GetNetworkStateFromServicePath(
235          service_path, true /* configured_only */);
236  if (!state) {
237    InvokeErrorCallback(service_path, error_callback, kUnknownNetwork);
238    return;
239  }
240
241  std::string guid = state->guid();
242  if (guid.empty()) {
243    // TODO(pneubeck): create an initial configuration in this case. As for
244    // CreateConfiguration, user settings from older ChromeOS versions have to
245    // determined here.
246    InvokeErrorCallback(
247        service_path, error_callback, kSetOnUnconfiguredNetwork);
248    return;
249  }
250
251  const std::string& profile_path = state->profile_path();
252  const NetworkProfile *profile =
253      network_profile_handler_->GetProfileForPath(profile_path);
254  if (!profile) {
255    InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
256    return;
257  }
258
259  VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
260          << profile->ToDebugString();
261
262  const Policies* policies = GetPoliciesForProfile(*profile);
263  if (!policies) {
264    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
265    return;
266  }
267
268  // Validate the ONC dictionary. We are liberal and ignore unknown field
269  // names. User settings are only partial ONC, thus we ignore missing fields.
270  onc::Validator validator(false,  // Ignore unknown fields.
271                           false,  // Ignore invalid recommended field names.
272                           false,  // Ignore missing fields.
273                           false);  // This ONC does not come from policy.
274
275  onc::Validator::Result validation_result;
276  scoped_ptr<base::DictionaryValue> validated_user_settings =
277      validator.ValidateAndRepairObject(
278          &onc::kNetworkConfigurationSignature,
279          user_settings,
280          &validation_result);
281
282  if (validation_result == onc::Validator::INVALID) {
283    InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
284    return;
285  }
286  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
287    LOG(WARNING) << "Validation of ONC user settings produced warnings.";
288
289  const base::DictionaryValue* network_policy =
290      GetByGUID(policies->per_network_config, guid);
291  VLOG(2) << "This configuration is " << (network_policy ? "" : "not ")
292          << "managed.";
293
294  scoped_ptr<base::DictionaryValue> shill_dictionary(
295      policy_util::CreateShillConfiguration(*profile,
296                                            guid,
297                                            &policies->global_network_config,
298                                            network_policy,
299                                            validated_user_settings.get()));
300
301  network_configuration_handler_->SetProperties(
302      service_path, *shill_dictionary, callback, error_callback);
303}
304
305void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
306    const std::string& userhash,
307    const base::DictionaryValue& properties,
308    const network_handler::StringResultCallback& callback,
309    const network_handler::ErrorCallback& error_callback) const {
310  const Policies* policies = GetPoliciesForUser(userhash);
311  if (!policies) {
312    InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
313    return;
314  }
315
316  if (policy_util::FindMatchingPolicy(policies->per_network_config,
317                                      properties)) {
318    InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
319    return;
320  }
321
322  const NetworkProfile* profile =
323      network_profile_handler_->GetProfileForUserhash(userhash);
324  if (!profile) {
325    InvokeErrorCallback("", error_callback, kProfileNotInitialized);
326    return;
327  }
328
329  // TODO(pneubeck): In case of WiFi, check that no other configuration for the
330  // same {SSID, mode, security} exists. We don't support such multiple
331  // configurations, yet.
332
333  // Generate a new GUID for this configuration. Ignore the maybe provided GUID
334  // in |properties| as it is not our own and from an untrusted source.
335  std::string guid = base::GenerateGUID();
336  scoped_ptr<base::DictionaryValue> shill_dictionary(
337      policy_util::CreateShillConfiguration(*profile,
338                                            guid,
339                                            NULL,  // no global policy
340                                            NULL,  // no network policy
341                                            &properties));
342
343  network_configuration_handler_->CreateConfiguration(
344      *shill_dictionary, callback, error_callback);
345}
346
347void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
348    const std::string& service_path,
349    const base::Closure& callback,
350    const network_handler::ErrorCallback& error_callback) const {
351  network_configuration_handler_->RemoveConfiguration(
352      service_path, callback, error_callback);
353}
354
355void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
356    ::onc::ONCSource onc_source,
357    const std::string& userhash,
358    const base::ListValue& network_configs_onc,
359    const base::DictionaryValue& global_network_config) {
360  VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
361          << ".";
362
363  // |userhash| must be empty for device policies.
364  DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
365         userhash.empty());
366  Policies* policies = NULL;
367  if (ContainsKey(policies_by_user_, userhash)) {
368    policies = policies_by_user_[userhash].get();
369  } else {
370    policies = new Policies;
371    policies_by_user_[userhash] = make_linked_ptr(policies);
372  }
373
374  policies->global_network_config.MergeDictionary(&global_network_config);
375
376  GuidToPolicyMap old_per_network_config;
377  policies->per_network_config.swap(old_per_network_config);
378
379  // This stores all GUIDs of policies that have changed or are new.
380  std::set<std::string> modified_policies;
381
382  for (base::ListValue::const_iterator it = network_configs_onc.begin();
383       it != network_configs_onc.end(); ++it) {
384    const base::DictionaryValue* network = NULL;
385    (*it)->GetAsDictionary(&network);
386    DCHECK(network);
387
388    std::string guid;
389    network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
390    DCHECK(!guid.empty());
391
392    if (policies->per_network_config.count(guid) > 0) {
393      NET_LOG_ERROR("ONC from " + ToDebugString(onc_source, userhash) +
394                    " contains several entries for the same GUID ", guid);
395      delete policies->per_network_config[guid];
396    }
397    const base::DictionaryValue* new_entry = network->DeepCopy();
398    policies->per_network_config[guid] = new_entry;
399
400    const base::DictionaryValue* old_entry = old_per_network_config[guid];
401    if (!old_entry || !old_entry->Equals(new_entry))
402      modified_policies.insert(guid);
403  }
404
405  STLDeleteValues(&old_per_network_config);
406
407  const NetworkProfile* profile =
408      network_profile_handler_->GetProfileForUserhash(userhash);
409  if (profile) {
410    scoped_refptr<PolicyApplicator> applicator =
411        new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
412                             *profile,
413                             policies->per_network_config,
414                             policies->global_network_config,
415                             &modified_policies);
416    applicator->Run();
417  } else {
418    VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
419            << "policy application.";
420    // See OnProfileAdded.
421  }
422
423  FOR_EACH_OBSERVER(NetworkPolicyObserver, observers_, PolicyChanged(userhash));
424}
425
426void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
427    const NetworkProfile& profile) {
428  VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
429
430  const Policies* policies = GetPoliciesForProfile(profile);
431  if (!policies) {
432    VLOG(1) << "The relevant policy is not initialized, "
433            << "postponing policy application.";
434    // See SetPolicy.
435    return;
436  }
437
438  std::set<std::string> policy_guids;
439  for (GuidToPolicyMap::const_iterator it =
440           policies->per_network_config.begin();
441       it != policies->per_network_config.end(); ++it) {
442    policy_guids.insert(it->first);
443  }
444
445  scoped_refptr<PolicyApplicator> applicator =
446      new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
447                           profile,
448                           policies->per_network_config,
449                           policies->global_network_config,
450                           &policy_guids);
451  applicator->Run();
452}
453
454void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
455    const NetworkProfile& profile) {
456  // Nothing to do in this case.
457}
458
459void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
460    const base::DictionaryValue& shill_properties) {
461  network_configuration_handler_->CreateConfiguration(
462      shill_properties,
463      base::Bind(
464          &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
465          weak_ptr_factory_.GetWeakPtr()),
466      base::Bind(&LogErrorWithDict, FROM_HERE));
467}
468
469void ManagedNetworkConfigurationHandlerImpl::
470    UpdateExistingConfigurationWithPropertiesFromPolicy(
471        const base::DictionaryValue& existing_properties,
472        const base::DictionaryValue& new_properties) {
473  base::DictionaryValue shill_properties;
474
475  std::string profile;
476  existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
477                                                    &profile);
478  if (profile.empty()) {
479    NET_LOG_ERROR("Missing profile property",
480                  shill_property_util::GetNetworkIdFromProperties(
481                      existing_properties));
482    return;
483  }
484  shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
485                                                 profile);
486
487  if (!shill_property_util::CopyIdentifyingProperties(
488          existing_properties,
489          true /* properties were read from Shill */,
490          &shill_properties)) {
491    NET_LOG_ERROR("Missing identifying properties",
492                  shill_property_util::GetNetworkIdFromProperties(
493                      existing_properties));
494  }
495
496  shill_properties.MergeDictionary(&new_properties);
497
498  network_configuration_handler_->CreateConfiguration(
499      shill_properties,
500      base::Bind(
501          &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
502          weak_ptr_factory_.GetWeakPtr()),
503      base::Bind(&LogErrorWithDict, FROM_HERE));
504}
505
506void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
507}
508
509const base::DictionaryValue*
510ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
511    const std::string userhash,
512    const std::string& guid,
513    ::onc::ONCSource* onc_source) const {
514  *onc_source = ::onc::ONC_SOURCE_NONE;
515
516  if (!userhash.empty()) {
517    const Policies* user_policies = GetPoliciesForUser(userhash);
518    if (user_policies) {
519      const base::DictionaryValue* policy =
520          GetByGUID(user_policies->per_network_config, guid);
521      if (policy) {
522        *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
523        return policy;
524      }
525    }
526  }
527
528  const Policies* device_policies = GetPoliciesForUser(std::string());
529  if (device_policies) {
530    const base::DictionaryValue* policy =
531        GetByGUID(device_policies->per_network_config, guid);
532    if (policy) {
533      *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
534      return policy;
535    }
536  }
537
538  return NULL;
539}
540
541const base::DictionaryValue*
542ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
543    const std::string userhash) const {
544  const Policies* policies = GetPoliciesForUser(userhash);
545  if (!policies)
546    return NULL;
547
548  return &policies->global_network_config;
549}
550const base::DictionaryValue*
551ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
552    const std::string& guid,
553    const std::string& profile_path) const {
554  const NetworkProfile* profile =
555      network_profile_handler_->GetProfileForPath(profile_path);
556  if (!profile) {
557    NET_LOG_ERROR("Profile path unknown:" + profile_path, guid);
558    return NULL;
559  }
560
561  const Policies* policies = GetPoliciesForProfile(*profile);
562  if (!policies)
563    return NULL;
564
565  return GetByGUID(policies->per_network_config, guid);
566}
567
568const ManagedNetworkConfigurationHandlerImpl::Policies*
569ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
570    const std::string& userhash) const {
571  UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
572  if (it == policies_by_user_.end())
573    return NULL;
574  return it->second.get();
575}
576
577const ManagedNetworkConfigurationHandlerImpl::Policies*
578ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
579    const NetworkProfile& profile) const {
580  DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
581         profile.userhash.empty());
582  return GetPoliciesForUser(profile.userhash);
583}
584
585ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
586    : network_state_handler_(NULL),
587      network_profile_handler_(NULL),
588      network_configuration_handler_(NULL),
589      network_device_handler_(NULL),
590      weak_ptr_factory_(this) {}
591
592ManagedNetworkConfigurationHandlerImpl::
593    ~ManagedNetworkConfigurationHandlerImpl() {
594  network_profile_handler_->RemoveObserver(this);
595}
596
597void ManagedNetworkConfigurationHandlerImpl::Init(
598    NetworkStateHandler* network_state_handler,
599    NetworkProfileHandler* network_profile_handler,
600    NetworkConfigurationHandler* network_configuration_handler,
601    NetworkDeviceHandler* network_device_handler) {
602  network_state_handler_ = network_state_handler;
603  network_profile_handler_ = network_profile_handler;
604  network_configuration_handler_ = network_configuration_handler;
605  network_device_handler_ = network_device_handler;
606  network_profile_handler_->AddObserver(this);
607}
608
609void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
610    const std::string& service_path) {
611  if (service_path.empty())
612    return;
613  FOR_EACH_OBSERVER(
614      NetworkPolicyObserver, observers_, PolicyApplied(service_path));
615}
616
617// Get{Managed}Properties helpers
618
619void ManagedNetworkConfigurationHandlerImpl::GetDeviceStateProperties(
620    const std::string& service_path,
621    base::DictionaryValue* properties) {
622  std::string connection_state;
623  properties->GetStringWithoutPathExpansion(
624      shill::kStateProperty, &connection_state);
625  if (!NetworkState::StateIsConnected(connection_state))
626    return;
627
628  // Get the IPConfig properties from the device and store them in "IPConfigs"
629  // (plural) in the properties dictionary. (Note: Shill only provides a single
630  // "IPConfig" property for a network service, but a consumer of this API may
631  // want information about all ipv4 and ipv6 IPConfig properties.
632  std::string device;
633  properties->GetStringWithoutPathExpansion(shill::kDeviceProperty, &device);
634  const DeviceState* device_state =
635      network_state_handler_->GetDeviceState(device);
636  if (!device_state) {
637    NET_LOG_ERROR("GetDeviceProperties: no device: " + device, service_path);
638    return;
639  }
640
641  // Get the hardware MAC address from the DeviceState.
642  if (!device_state->mac_address().empty()) {
643    properties->SetStringWithoutPathExpansion(
644        shill::kAddressProperty, device_state->mac_address());
645  }
646
647  // Convert IPConfig dictionary to a ListValue.
648  base::ListValue* ip_configs = new base::ListValue;
649  for (base::DictionaryValue::Iterator iter(device_state->ip_configs());
650       !iter.IsAtEnd(); iter.Advance()) {
651    ip_configs->Append(iter.value().DeepCopy());
652  }
653  properties->SetWithoutPathExpansion(shill::kIPConfigsProperty, ip_configs);
654}
655
656void ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback(
657    GetDevicePropertiesCallback send_callback,
658    const std::string& service_path,
659    const base::DictionaryValue& shill_properties) {
660  scoped_ptr<base::DictionaryValue> shill_properties_copy(
661      shill_properties.DeepCopy());
662
663  // Add associated Device properties before the ONC translation.
664  GetDeviceStateProperties(service_path, shill_properties_copy.get());
665
666  // Only request Device properties for Cellular networks with a valid device.
667  std::string type, device_path;
668  if (!network_device_handler_ ||
669      !shill_properties_copy->GetStringWithoutPathExpansion(
670          shill::kTypeProperty, &type) ||
671      type != shill::kTypeCellular ||
672      !shill_properties_copy->GetStringWithoutPathExpansion(
673          shill::kDeviceProperty, &device_path) ||
674      device_path.empty()) {
675    send_callback.Run(service_path, shill_properties_copy.Pass());
676    return;
677  }
678
679  // Request the device properties. On success or failure pass (a possibly
680  // modified) |shill_properties| to |send_callback|.
681  scoped_ptr<base::DictionaryValue> shill_properties_copy_error_copy(
682      shill_properties_copy->DeepCopy());
683  network_device_handler_->GetDeviceProperties(
684      device_path,
685      base::Bind(&ManagedNetworkConfigurationHandlerImpl::
686                     GetDevicePropertiesSuccess,
687                 weak_ptr_factory_.GetWeakPtr(),
688                 service_path,
689                 base::Passed(&shill_properties_copy),
690                 send_callback),
691      base::Bind(&ManagedNetworkConfigurationHandlerImpl::
692                     GetDevicePropertiesFailure,
693                 weak_ptr_factory_.GetWeakPtr(),
694                 service_path,
695                 base::Passed(&shill_properties_copy_error_copy),
696                 send_callback));
697}
698
699void ManagedNetworkConfigurationHandlerImpl::GetDevicePropertiesSuccess(
700    const std::string& service_path,
701    scoped_ptr<base::DictionaryValue> network_properties,
702    GetDevicePropertiesCallback send_callback,
703    const std::string& device_path,
704    const base::DictionaryValue& device_properties) {
705  // Create a "Device" dictionary in |network_properties|.
706  network_properties->SetWithoutPathExpansion(
707      shill::kDeviceProperty, device_properties.DeepCopy());
708  send_callback.Run(service_path, network_properties.Pass());
709}
710
711void ManagedNetworkConfigurationHandlerImpl::GetDevicePropertiesFailure(
712    const std::string& service_path,
713    scoped_ptr<base::DictionaryValue> network_properties,
714    GetDevicePropertiesCallback send_callback,
715    const std::string& error_name,
716    scoped_ptr<base::DictionaryValue> error_data) {
717  NET_LOG_ERROR("Error getting device properties", service_path);
718  send_callback.Run(service_path, network_properties.Pass());
719}
720
721
722}  // namespace chromeos
723