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/device_state.h"
6
7#include "base/logging.h"
8#include "base/metrics/histogram.h"
9#include "base/strings/stringprintf.h"
10#include "base/values.h"
11#include "chromeos/network/network_event_log.h"
12#include "chromeos/network/shill_property_util.h"
13#include "third_party/cros_system_api/dbus/service_constants.h"
14
15namespace chromeos {
16
17DeviceState::DeviceState(const std::string& path)
18    : ManagedState(MANAGED_TYPE_DEVICE, path),
19      allow_roaming_(false),
20      provider_requires_roaming_(false),
21      support_network_scan_(false),
22      scanning_(false),
23      sim_retries_left_(0),
24      sim_lock_enabled_(false),
25      sim_present_(true),
26      eap_authentication_completed_(false) {
27}
28
29DeviceState::~DeviceState() {
30}
31
32bool DeviceState::PropertyChanged(const std::string& key,
33                                  const base::Value& value) {
34  // All property values get stored in |properties_|.
35  properties_.SetWithoutPathExpansion(key, value.DeepCopy());
36
37  if (ManagedStatePropertyChanged(key, value))
38    return true;
39  if (key == shill::kAddressProperty) {
40    return GetStringValue(key, value, &mac_address_);
41  } else if (key == shill::kScanningProperty) {
42    return GetBooleanValue(key, value, &scanning_);
43  } else if (key == shill::kSupportNetworkScanProperty) {
44    return GetBooleanValue(key, value, &support_network_scan_);
45  } else if (key == shill::kCellularAllowRoamingProperty) {
46    return GetBooleanValue(key, value, &allow_roaming_);
47  } else if (key == shill::kProviderRequiresRoamingProperty) {
48    return GetBooleanValue(key, value, &provider_requires_roaming_);
49  } else if (key == shill::kHomeProviderProperty) {
50    return shill_property_util::GetHomeProviderFromProperty(
51        value, &home_provider_id_);
52  } else if (key == shill::kTechnologyFamilyProperty) {
53    return GetStringValue(key, value, &technology_family_);
54  } else if (key == shill::kCarrierProperty) {
55    return GetStringValue(key, value, &carrier_);
56  } else if (key == shill::kFoundNetworksProperty) {
57    const base::ListValue* list = NULL;
58    if (!value.GetAsList(&list))
59      return false;
60    CellularScanResults parsed_results;
61    if (!network_util::ParseCellularScanResults(*list, &parsed_results))
62      return false;
63    scan_results_.swap(parsed_results);
64    return true;
65  } else if (key == shill::kSIMLockStatusProperty) {
66    const base::DictionaryValue* dict = NULL;
67    if (!value.GetAsDictionary(&dict))
68      return false;
69
70    // Return true if at least one of the property values changed.
71    bool property_changed = false;
72    const base::Value* out_value = NULL;
73    if (!dict->GetWithoutPathExpansion(shill::kSIMLockRetriesLeftProperty,
74                                       &out_value))
75      return false;
76    if (GetUInt32Value(shill::kSIMLockRetriesLeftProperty,
77                       *out_value, &sim_retries_left_))
78      property_changed = true;
79
80    if (!dict->GetWithoutPathExpansion(shill::kSIMLockTypeProperty,
81                                       &out_value))
82      return false;
83    if (GetStringValue(shill::kSIMLockTypeProperty,
84                       *out_value, &sim_lock_type_))
85      property_changed = true;
86
87    if (!dict->GetWithoutPathExpansion(shill::kSIMLockEnabledProperty,
88                                       &out_value))
89      return false;
90    if (GetBooleanValue(shill::kSIMLockEnabledProperty,
91                        *out_value, &sim_lock_enabled_))
92      property_changed = true;
93
94    return property_changed;
95  } else if (key == shill::kMeidProperty) {
96    return GetStringValue(key, value, &meid_);
97  } else if (key == shill::kImeiProperty) {
98    return GetStringValue(key, value, &imei_);
99  } else if (key == shill::kIccidProperty) {
100    return GetStringValue(key, value, &iccid_);
101  } else if (key == shill::kMdnProperty) {
102    return GetStringValue(key, value, &mdn_);
103  } else if (key == shill::kSIMPresentProperty) {
104    return GetBooleanValue(key, value, &sim_present_);
105  } else if (key == shill::kEapAuthenticationCompletedProperty) {
106    return GetBooleanValue(key, value, &eap_authentication_completed_);
107  } else if (key == shill::kIPConfigsProperty) {
108    // If kIPConfigsProperty changes, clear any previous ip_configs_.
109    // ShillPropertyhandler will request the IPConfig objects which will trigger
110    // calls to IPConfigPropertiesChanged.
111    ip_configs_.Clear();
112    return false;  // No actual state change.
113  }
114  return false;
115}
116
117bool DeviceState::InitialPropertiesReceived(
118    const base::DictionaryValue& properties) {
119  // Update UMA stats.
120  if (sim_present_) {
121    bool locked = !sim_lock_type_.empty();
122    UMA_HISTOGRAM_BOOLEAN("Cellular.SIMLocked", locked);
123  }
124  return false;
125}
126
127void DeviceState::IPConfigPropertiesChanged(
128    const std::string& ip_config_path,
129    const base::DictionaryValue& properties) {
130  base::DictionaryValue* ip_config = NULL;
131  if (ip_configs_.GetDictionaryWithoutPathExpansion(
132          ip_config_path, &ip_config)) {
133    NET_LOG_EVENT("IPConfig Updated: " + ip_config_path, path());
134    ip_config->Clear();
135  } else {
136    NET_LOG_EVENT("IPConfig Added: " + ip_config_path, path());
137    ip_config = new base::DictionaryValue;
138    ip_configs_.SetWithoutPathExpansion(ip_config_path, ip_config);
139  }
140  ip_config->MergeDictionary(&properties);
141}
142
143bool DeviceState::IsSimAbsent() const {
144  return technology_family_ == shill::kTechnologyFamilyGsm && !sim_present_;
145}
146
147}  // namespace chromeos
148