network_state.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/network_state.h"
6
7#include "base/strings/stringprintf.h"
8#include "chromeos/network/network_event_log.h"
9#include "chromeos/network/network_profile_handler.h"
10#include "chromeos/network/network_util.h"
11#include "chromeos/network/onc/onc_utils.h"
12#include "chromeos/network/shill_property_util.h"
13#include "third_party/cros_system_api/dbus/service_constants.h"
14
15namespace {
16
17const char kErrorUnknown[] = "Unknown";
18
19bool ConvertListValueToStringVector(const base::ListValue& string_list,
20                                    std::vector<std::string>* result) {
21  for (size_t i = 0; i < string_list.GetSize(); ++i) {
22    std::string str;
23    if (!string_list.GetString(i, &str))
24      return false;
25    result->push_back(str);
26  }
27  return true;
28}
29
30bool IsCaCertNssSet(const base::DictionaryValue& properties) {
31  std::string ca_cert_nss;
32  if (properties.GetStringWithoutPathExpansion(flimflam::kEapCaCertNssProperty,
33                                               &ca_cert_nss) &&
34      !ca_cert_nss.empty()) {
35    return true;
36  }
37
38  const base::DictionaryValue* provider = NULL;
39  properties.GetDictionaryWithoutPathExpansion(flimflam::kProviderProperty,
40                                               &provider);
41  if (!provider)
42    return false;
43  if (provider->GetStringWithoutPathExpansion(
44          flimflam::kL2tpIpsecCaCertNssProperty, &ca_cert_nss) &&
45      !ca_cert_nss.empty()) {
46    return true;
47  }
48  if (provider->GetStringWithoutPathExpansion(
49          flimflam::kOpenVPNCaCertNSSProperty, &ca_cert_nss) &&
50      !ca_cert_nss.empty()) {
51    return true;
52  }
53
54  return false;
55}
56
57}  // namespace
58
59namespace chromeos {
60
61NetworkState::NetworkState(const std::string& path)
62    : ManagedState(MANAGED_TYPE_NETWORK, path),
63      connectable_(false),
64      prefix_length_(0),
65      signal_strength_(0),
66      activate_over_non_cellular_networks_(false),
67      cellular_out_of_credits_(false),
68      has_ca_cert_nss_(false) {
69}
70
71NetworkState::~NetworkState() {
72}
73
74bool NetworkState::PropertyChanged(const std::string& key,
75                                   const base::Value& value) {
76  // Keep care that these properties are the same as in |GetProperties|.
77  if (ManagedStatePropertyChanged(key, value))
78    return true;
79  if (key == flimflam::kSignalStrengthProperty) {
80    return GetIntegerValue(key, value, &signal_strength_);
81  } else if (key == flimflam::kStateProperty) {
82    return GetStringValue(key, value, &connection_state_);
83  } else if (key == flimflam::kConnectableProperty) {
84    return GetBooleanValue(key, value, &connectable_);
85  } else if (key == flimflam::kErrorProperty) {
86    if (!GetStringValue(key, value, &error_))
87      return false;
88    // Shill uses "Unknown" to indicate an unset error state.
89    if (error_ == kErrorUnknown)
90      error_.clear();
91    return true;
92  } else if (key == IPConfigProperty(flimflam::kAddressProperty)) {
93    return GetStringValue(key, value, &ip_address_);
94  } else if (key == IPConfigProperty(flimflam::kGatewayProperty)) {
95    return GetStringValue(key, value, &gateway_);
96  } else if (key == IPConfigProperty(flimflam::kNameServersProperty)) {
97    const base::ListValue* dns_servers;
98    if (!value.GetAsList(&dns_servers))
99      return false;
100    dns_servers_.clear();
101    ConvertListValueToStringVector(*dns_servers, &dns_servers_);
102    return true;
103  } else if (key == IPConfigProperty(flimflam::kPrefixlenProperty)) {
104    return GetIntegerValue(key, value, &prefix_length_);
105  } else if (key == IPConfigProperty(
106      shill::kWebProxyAutoDiscoveryUrlProperty)) {
107    std::string url_string;
108    if (!GetStringValue(key, value, &url_string))
109      return false;
110    if (url_string.empty()) {
111      web_proxy_auto_discovery_url_ = GURL();
112    } else {
113      GURL gurl(url_string);
114      if (!gurl.is_valid()) {
115        web_proxy_auto_discovery_url_ = gurl;
116      } else {
117        NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string,
118                      path());
119        web_proxy_auto_discovery_url_ = GURL();
120      }
121    }
122    return true;
123  } else if (key == flimflam::kActivationStateProperty) {
124    return GetStringValue(key, value, &activation_state_);
125  } else if (key == flimflam::kRoamingStateProperty) {
126    return GetStringValue(key, value, &roaming_);
127  } else if (key == flimflam::kSecurityProperty) {
128    return GetStringValue(key, value, &security_);
129  } else if (key == flimflam::kProxyConfigProperty) {
130    std::string proxy_config_str;
131    if (!value.GetAsString(&proxy_config_str)) {
132      NET_LOG_ERROR("Failed to parse " + key, path());
133      return false;
134    }
135
136    proxy_config_.Clear();
137    if (proxy_config_str.empty())
138      return true;
139
140    scoped_ptr<base::DictionaryValue> proxy_config_dict(
141        onc::ReadDictionaryFromJson(proxy_config_str));
142    if (proxy_config_dict) {
143      // Warning: The DictionaryValue returned from
144      // ReadDictionaryFromJson/JSONParser is an optimized derived class that
145      // doesn't allow releasing ownership of nested values. A Swap in the wrong
146      // order leads to memory access errors.
147      proxy_config_.MergeDictionary(proxy_config_dict.get());
148    } else {
149      NET_LOG_ERROR("Failed to parse " + key, path());
150    }
151    return true;
152  } else if (key == flimflam::kUIDataProperty) {
153    scoped_ptr<NetworkUIData> new_ui_data =
154        shill_property_util::GetUIDataFromValue(value);
155    if (!new_ui_data) {
156      NET_LOG_ERROR("Failed to parse " + key, path());
157      return false;
158    }
159    ui_data_ = *new_ui_data;
160    return true;
161  } else if (key == flimflam::kNetworkTechnologyProperty) {
162    return GetStringValue(key, value, &network_technology_);
163  } else if (key == flimflam::kDeviceProperty) {
164    return GetStringValue(key, value, &device_path_);
165  } else if (key == flimflam::kGuidProperty) {
166    return GetStringValue(key, value, &guid_);
167  } else if (key == flimflam::kProfileProperty) {
168    return GetStringValue(key, value, &profile_path_);
169  } else if (key == shill::kActivateOverNonCellularNetworkProperty) {
170    return GetBooleanValue(key, value, &activate_over_non_cellular_networks_);
171  } else if (key == shill::kOutOfCreditsProperty) {
172    return GetBooleanValue(key, value, &cellular_out_of_credits_);
173  }
174  return false;
175}
176
177bool NetworkState::InitialPropertiesReceived(
178    const base::DictionaryValue& properties) {
179  NET_LOG_DEBUG("InitialPropertiesReceived", path());
180  bool changed = UpdateName(properties);
181  bool had_ca_cert_nss = has_ca_cert_nss_;
182  has_ca_cert_nss_ = IsCaCertNssSet(properties);
183  changed |= had_ca_cert_nss != has_ca_cert_nss_;
184  return changed;
185}
186
187void NetworkState::GetProperties(base::DictionaryValue* dictionary) const {
188  // Keep care that these properties are the same as in |PropertyChanged|.
189  dictionary->SetStringWithoutPathExpansion(flimflam::kNameProperty, name());
190  dictionary->SetStringWithoutPathExpansion(flimflam::kTypeProperty, type());
191  dictionary->SetIntegerWithoutPathExpansion(flimflam::kSignalStrengthProperty,
192                                             signal_strength_);
193  dictionary->SetStringWithoutPathExpansion(flimflam::kStateProperty,
194                                            connection_state_);
195  dictionary->SetBooleanWithoutPathExpansion(flimflam::kConnectableProperty,
196                                             connectable_);
197
198  dictionary->SetStringWithoutPathExpansion(flimflam::kErrorProperty,
199                                            error_);
200
201  // IPConfig properties
202  base::DictionaryValue* ipconfig_properties = new base::DictionaryValue;
203  ipconfig_properties->SetStringWithoutPathExpansion(flimflam::kAddressProperty,
204                                                     ip_address_);
205  ipconfig_properties->SetStringWithoutPathExpansion(flimflam::kGatewayProperty,
206                                                     gateway_);
207  base::ListValue* name_servers = new base::ListValue;
208  name_servers->AppendStrings(dns_servers_);
209  ipconfig_properties->SetWithoutPathExpansion(flimflam::kNameServersProperty,
210                                               name_servers);
211  ipconfig_properties->SetStringWithoutPathExpansion(
212      shill::kWebProxyAutoDiscoveryUrlProperty,
213      web_proxy_auto_discovery_url_.spec());
214  dictionary->SetWithoutPathExpansion(shill::kIPConfigProperty,
215                                      ipconfig_properties);
216
217  dictionary->SetStringWithoutPathExpansion(flimflam::kActivationStateProperty,
218                                            activation_state_);
219  dictionary->SetStringWithoutPathExpansion(flimflam::kRoamingStateProperty,
220                                            roaming_);
221  dictionary->SetStringWithoutPathExpansion(flimflam::kSecurityProperty,
222                                            security_);
223  // Proxy config and ONC source are intentionally omitted: These properties are
224  // placed in NetworkState to transition ProxyConfigServiceImpl from
225  // NetworkLibrary to the new network stack. The networking extension API
226  // shouldn't depend on this member. Once ManagedNetworkConfigurationHandler
227  // is used instead of NetworkLibrary, we can remove them again.
228  dictionary->SetStringWithoutPathExpansion(
229      flimflam::kNetworkTechnologyProperty,
230      network_technology_);
231  dictionary->SetStringWithoutPathExpansion(flimflam::kDeviceProperty,
232                                            device_path_);
233  dictionary->SetStringWithoutPathExpansion(flimflam::kGuidProperty, guid_);
234  dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
235                                            profile_path_);
236  dictionary->SetBooleanWithoutPathExpansion(
237      shill::kActivateOverNonCellularNetworkProperty,
238      activate_over_non_cellular_networks_);
239  dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty,
240                                             cellular_out_of_credits_);
241}
242
243bool NetworkState::IsConnectedState() const {
244  return StateIsConnected(connection_state_);
245}
246
247bool NetworkState::IsConnectingState() const {
248  return StateIsConnecting(connection_state_);
249}
250
251bool NetworkState::IsManaged() const {
252  return ui_data_.onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
253         ui_data_.onc_source() == onc::ONC_SOURCE_USER_POLICY;
254}
255
256bool NetworkState::IsPrivate() const {
257  return !profile_path_.empty() &&
258      profile_path_ != NetworkProfileHandler::kSharedProfilePath;
259}
260
261std::string NetworkState::GetDnsServersAsString() const {
262  std::string result;
263  for (size_t i = 0; i < dns_servers_.size(); ++i) {
264    if (i != 0)
265      result += ",";
266    result += dns_servers_[i];
267  }
268  return result;
269}
270
271std::string NetworkState::GetNetmask() const {
272  return network_util::PrefixLengthToNetmask(prefix_length_);
273}
274
275bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
276  std::string updated_name =
277      shill_property_util::GetNameFromProperties(path(), properties);
278  if (updated_name != name()) {
279    set_name(updated_name);
280    return true;
281  }
282  return false;
283}
284
285// static
286bool NetworkState::StateIsConnected(const std::string& connection_state) {
287  return (connection_state == flimflam::kStateReady ||
288          connection_state == flimflam::kStateOnline ||
289          connection_state == flimflam::kStatePortal);
290}
291
292// static
293bool NetworkState::StateIsConnecting(const std::string& connection_state) {
294  return (connection_state == flimflam::kStateAssociation ||
295          connection_state == flimflam::kStateConfiguration ||
296          connection_state == flimflam::kStateCarrier);
297}
298
299// static
300std::string NetworkState::IPConfigProperty(const char* key) {
301  return base::StringPrintf("%s.%s", shill::kIPConfigProperty, key);
302}
303
304}  // namespace chromeos
305