network_state.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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_type_pattern.h"
11#include "chromeos/network/network_util.h"
12#include "chromeos/network/onc/onc_utils.h"
13#include "chromeos/network/shill_property_util.h"
14#include "third_party/cros_system_api/dbus/service_constants.h"
15
16namespace {
17
18const char kErrorUnknown[] = "Unknown";
19
20bool ConvertListValueToStringVector(const base::ListValue& string_list,
21                                    std::vector<std::string>* result) {
22  for (size_t i = 0; i < string_list.GetSize(); ++i) {
23    std::string str;
24    if (!string_list.GetString(i, &str))
25      return false;
26    result->push_back(str);
27  }
28  return true;
29}
30
31bool IsCaCertNssSet(const base::DictionaryValue& properties) {
32  std::string ca_cert_nss;
33  if (properties.GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty,
34                                               &ca_cert_nss) &&
35      !ca_cert_nss.empty()) {
36    return true;
37  }
38
39  const base::DictionaryValue* provider = NULL;
40  properties.GetDictionaryWithoutPathExpansion(shill::kProviderProperty,
41                                               &provider);
42  if (!provider)
43    return false;
44  if (provider->GetStringWithoutPathExpansion(
45          shill::kL2tpIpsecCaCertNssProperty, &ca_cert_nss) &&
46      !ca_cert_nss.empty()) {
47    return true;
48  }
49  if (provider->GetStringWithoutPathExpansion(
50          shill::kOpenVPNCaCertNSSProperty, &ca_cert_nss) &&
51      !ca_cert_nss.empty()) {
52    return true;
53  }
54
55  return false;
56}
57
58}  // namespace
59
60namespace chromeos {
61
62NetworkState::NetworkState(const std::string& path)
63    : ManagedState(MANAGED_TYPE_NETWORK, path),
64      visible_(false),
65      connectable_(false),
66      prefix_length_(0),
67      signal_strength_(0),
68      cellular_out_of_credits_(false),
69      has_ca_cert_nss_(false) {
70}
71
72NetworkState::~NetworkState() {
73}
74
75bool NetworkState::PropertyChanged(const std::string& key,
76                                   const base::Value& value) {
77  // Keep care that these properties are the same as in |GetProperties|.
78  if (ManagedStatePropertyChanged(key, value))
79    return true;
80  if (key == shill::kSignalStrengthProperty) {
81    return GetIntegerValue(key, value, &signal_strength_);
82  } else if (key == shill::kStateProperty) {
83    return GetStringValue(key, value, &connection_state_);
84  } else if (key == shill::kVisibleProperty) {
85    return GetBooleanValue(key, value, &visible_);
86  } else if (key == shill::kConnectableProperty) {
87    return GetBooleanValue(key, value, &connectable_);
88  } else if (key == shill::kErrorProperty) {
89    if (!GetStringValue(key, value, &error_))
90      return false;
91    if (ErrorIsValid(error_))
92      last_error_ = error_;
93    else
94      error_.clear();
95    return true;
96  } else if (key == shill::kActivationTypeProperty) {
97    return GetStringValue(key, value, &activation_type_);
98  } else if (key == shill::kActivationStateProperty) {
99    return GetStringValue(key, value, &activation_state_);
100  } else if (key == shill::kRoamingStateProperty) {
101    return GetStringValue(key, value, &roaming_);
102  } else if (key == shill::kPaymentPortalProperty) {
103    const base::DictionaryValue* olp;
104    if (!value.GetAsDictionary(&olp))
105      return false;
106    return olp->GetStringWithoutPathExpansion(shill::kPaymentPortalURL,
107                                              &payment_url_);
108  } else if (key == shill::kSecurityProperty) {
109    return GetStringValue(key, value, &security_);
110  } else if (key == shill::kEapMethodProperty) {
111    return GetStringValue(key, value, &eap_method_);
112  } else if (key == shill::kNetworkTechnologyProperty) {
113    return GetStringValue(key, value, &network_technology_);
114  } else if (key == shill::kDeviceProperty) {
115    return GetStringValue(key, value, &device_path_);
116  } else if (key == shill::kGuidProperty) {
117    return GetStringValue(key, value, &guid_);
118  } else if (key == shill::kProfileProperty) {
119    return GetStringValue(key, value, &profile_path_);
120  } else if (key == shill::kOutOfCreditsProperty) {
121    return GetBooleanValue(key, value, &cellular_out_of_credits_);
122  } else if (key == shill::kProxyConfigProperty) {
123    std::string proxy_config_str;
124    if (!value.GetAsString(&proxy_config_str)) {
125      NET_LOG_ERROR("Failed to parse " + key, path());
126      return false;
127    }
128
129    proxy_config_.Clear();
130    if (proxy_config_str.empty())
131      return true;
132
133    scoped_ptr<base::DictionaryValue> proxy_config_dict(
134        onc::ReadDictionaryFromJson(proxy_config_str));
135    if (proxy_config_dict) {
136      // Warning: The DictionaryValue returned from
137      // ReadDictionaryFromJson/JSONParser is an optimized derived class that
138      // doesn't allow releasing ownership of nested values. A Swap in the wrong
139      // order leads to memory access errors.
140      proxy_config_.MergeDictionary(proxy_config_dict.get());
141    } else {
142      NET_LOG_ERROR("Failed to parse " + key, path());
143    }
144    return true;
145  }
146  return false;
147}
148
149bool NetworkState::InitialPropertiesReceived(
150    const base::DictionaryValue& properties) {
151  NET_LOG_DEBUG("InitialPropertiesReceived", path());
152  bool changed = false;
153  if (!properties.HasKey(shill::kTypeProperty)) {
154    NET_LOG_ERROR("NetworkState has no type",
155                  shill_property_util::GetNetworkIdFromProperties(properties));
156    return false;
157  }
158  // Ensure that the network has a valid name.
159  changed |= UpdateName(properties);
160
161  // Set the has_ca_cert_nss_ property.
162  bool had_ca_cert_nss = has_ca_cert_nss_;
163  has_ca_cert_nss_ = IsCaCertNssSet(properties);
164  changed |= had_ca_cert_nss != has_ca_cert_nss_;
165
166  // By convention, all visible WiFi and WiMAX networks have a
167  // SignalStrength > 0.
168  if ((type() == shill::kTypeWifi || type() == shill::kTypeWimax) &&
169      visible() && signal_strength_ <= 0) {
170      signal_strength_ = 1;
171  }
172
173  return changed;
174}
175
176void NetworkState::GetStateProperties(base::DictionaryValue* dictionary) const {
177  ManagedState::GetStateProperties(dictionary);
178
179  // Properties shared by all types.
180  dictionary->SetStringWithoutPathExpansion(shill::kGuidProperty, guid());
181  dictionary->SetStringWithoutPathExpansion(shill::kSecurityProperty,
182                                            security());
183
184  if (visible()) {
185    if (!error().empty())
186      dictionary->SetStringWithoutPathExpansion(shill::kErrorProperty, error());
187    dictionary->SetStringWithoutPathExpansion(shill::kStateProperty,
188                                              connection_state());
189  }
190
191  // Wireless properties
192  if (!NetworkTypePattern::Wireless().MatchesType(type()))
193    return;
194
195  if (visible()) {
196    dictionary->SetBooleanWithoutPathExpansion(shill::kConnectableProperty,
197                                               connectable());
198    dictionary->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty,
199                                               signal_strength());
200  }
201
202  // Wifi properties
203  if (NetworkTypePattern::WiFi().MatchesType(type())) {
204    dictionary->SetStringWithoutPathExpansion(shill::kEapMethodProperty,
205                                              eap_method());
206  }
207
208  // Mobile properties
209  if (NetworkTypePattern::Mobile().MatchesType(type())) {
210    dictionary->SetStringWithoutPathExpansion(
211        shill::kNetworkTechnologyProperty,
212        network_technology());
213    dictionary->SetStringWithoutPathExpansion(shill::kActivationStateProperty,
214                                              activation_state());
215    dictionary->SetStringWithoutPathExpansion(shill::kRoamingStateProperty,
216                                              roaming());
217    dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty,
218                                               cellular_out_of_credits());
219  }
220}
221
222void NetworkState::IPConfigPropertiesChanged(
223    const base::DictionaryValue& properties) {
224  for (base::DictionaryValue::Iterator iter(properties);
225       !iter.IsAtEnd(); iter.Advance()) {
226    std::string key = iter.key();
227    const base::Value& value = iter.value();
228
229    if (key == shill::kAddressProperty) {
230      GetStringValue(key, value, &ip_address_);
231    } else if (key == shill::kGatewayProperty) {
232      GetStringValue(key, value, &gateway_);
233    } else if (key == shill::kNameServersProperty) {
234      const base::ListValue* dns_servers;
235      if (value.GetAsList(&dns_servers)) {
236        dns_servers_.clear();
237        ConvertListValueToStringVector(*dns_servers, &dns_servers_);
238      }
239    } else if (key == shill::kPrefixlenProperty) {
240      GetIntegerValue(key, value, &prefix_length_);
241    } else if (key == shill::kWebProxyAutoDiscoveryUrlProperty) {
242      std::string url_string;
243      if (GetStringValue(key, value, &url_string)) {
244        if (url_string.empty()) {
245          web_proxy_auto_discovery_url_ = GURL();
246        } else {
247          GURL gurl(url_string);
248          if (gurl.is_valid()) {
249            web_proxy_auto_discovery_url_ = gurl;
250          } else {
251            NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string,
252                          path());
253            web_proxy_auto_discovery_url_ = GURL();
254          }
255        }
256      }
257    }
258  }
259}
260
261bool NetworkState::RequiresActivation() const {
262  return (type() == shill::kTypeCellular &&
263          activation_state() != shill::kActivationStateActivated &&
264          activation_state() != shill::kActivationStateUnknown);
265}
266
267std::string NetworkState::connection_state() const {
268  if (!visible())
269    return shill::kStateDisconnect;
270  return connection_state_;
271}
272
273bool NetworkState::IsConnectedState() const {
274  return visible() && StateIsConnected(connection_state_);
275}
276
277bool NetworkState::IsConnectingState() const {
278  return visible() && StateIsConnecting(connection_state_);
279}
280
281bool NetworkState::IsInProfile() const {
282  // kTypeEthernetEap is always saved. We need this check because it does
283  // not show up in the visible list, but its properties may not be available
284  // when it first shows up in ServiceCompleteList. See crbug.com/355117.
285  return !profile_path_.empty() || type() == shill::kTypeEthernetEap;
286}
287
288bool NetworkState::IsPrivate() const {
289  return !profile_path_.empty() &&
290      profile_path_ != NetworkProfileHandler::GetSharedProfilePath();
291}
292
293std::string NetworkState::GetDnsServersAsString() const {
294  std::string result;
295  for (size_t i = 0; i < dns_servers_.size(); ++i) {
296    if (i != 0)
297      result += ",";
298    result += dns_servers_[i];
299  }
300  return result;
301}
302
303std::string NetworkState::GetNetmask() const {
304  return network_util::PrefixLengthToNetmask(prefix_length_);
305}
306
307std::string NetworkState::GetSpecifier() const {
308  if (!update_received()) {
309    NET_LOG_ERROR("GetSpecifier called before update", path());
310    return std::string();
311  }
312  if (type() == shill::kTypeWifi)
313    return name() + "_" + security_;
314  if (!name().empty())
315    return name();
316  return type();  // For unnamed networks such as ethernet.
317}
318
319void NetworkState::SetGuid(const std::string& guid) {
320  guid_ = guid;
321}
322
323bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
324  std::string updated_name =
325      shill_property_util::GetNameFromProperties(path(), properties);
326  if (updated_name != name()) {
327    set_name(updated_name);
328    return true;
329  }
330  return false;
331}
332
333// static
334bool NetworkState::StateIsConnected(const std::string& connection_state) {
335  return (connection_state == shill::kStateReady ||
336          connection_state == shill::kStateOnline ||
337          connection_state == shill::kStatePortal);
338}
339
340// static
341bool NetworkState::StateIsConnecting(const std::string& connection_state) {
342  return (connection_state == shill::kStateAssociation ||
343          connection_state == shill::kStateConfiguration ||
344          connection_state == shill::kStateCarrier);
345}
346
347// static
348bool NetworkState::ErrorIsValid(const std::string& error) {
349  // Shill uses "Unknown" to indicate an unset or cleared error state.
350  return !error.empty() && error != kErrorUnknown;
351}
352
353}  // namespace chromeos
354