Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chromeos / network / network_state.cc
blobf86902a494fafeb24bd158f232ed3588d28166b2
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.
5 #include "chromeos/network/network_state.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/stringprintf.h"
11 #include "chromeos/network/network_profile_handler.h"
12 #include "chromeos/network/network_type_pattern.h"
13 #include "chromeos/network/network_util.h"
14 #include "chromeos/network/onc/onc_utils.h"
15 #include "chromeos/network/shill_property_util.h"
16 #include "components/device_event_log/device_event_log.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
19 namespace {
21 const char kErrorUnknown[] = "Unknown";
23 bool ConvertListValueToStringVector(const base::ListValue& string_list,
24 std::vector<std::string>* result) {
25 for (size_t i = 0; i < string_list.GetSize(); ++i) {
26 std::string str;
27 if (!string_list.GetString(i, &str))
28 return false;
29 result->push_back(str);
31 return true;
34 bool IsCaptivePortalState(const base::DictionaryValue& properties, bool log) {
35 std::string state;
36 properties.GetStringWithoutPathExpansion(shill::kStateProperty, &state);
37 if (state != shill::kStatePortal)
38 return false;
39 std::string portal_detection_phase, portal_detection_status;
40 if (!properties.GetStringWithoutPathExpansion(
41 shill::kPortalDetectionFailedPhaseProperty,
42 &portal_detection_phase) ||
43 !properties.GetStringWithoutPathExpansion(
44 shill::kPortalDetectionFailedStatusProperty,
45 &portal_detection_status)) {
46 // If Shill (or a stub) has not set PortalDetectionFailedStatus
47 // or PortalDetectionFailedPhase, assume we are in captive portal state.
48 return true;
51 // Shill reports the phase in which it determined that the device is behind a
52 // captive portal. We only want to rely only on incorrect content being
53 // returned and ignore other reasons.
54 bool is_captive_portal =
55 portal_detection_phase == shill::kPortalDetectionPhaseContent &&
56 portal_detection_status == shill::kPortalDetectionStatusFailure;
58 if (log) {
59 std::string name;
60 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
61 if (name.empty())
62 properties.GetStringWithoutPathExpansion(shill::kSSIDProperty, &name);
63 if (!is_captive_portal) {
64 NET_LOG(EVENT) << "State is 'portal' but not in captive portal state:"
65 << " name=" << name << " phase=" << portal_detection_phase
66 << " status=" << portal_detection_status;
67 } else {
68 NET_LOG(EVENT) << "Network is in captive portal state: " << name;
72 return is_captive_portal;
75 } // namespace
77 namespace chromeos {
79 NetworkState::NetworkState(const std::string& path)
80 : ManagedState(MANAGED_TYPE_NETWORK, path),
81 visible_(false),
82 priority_(0),
83 prefix_length_(0),
84 connectable_(false),
85 is_captive_portal_(false),
86 signal_strength_(0),
87 cellular_out_of_credits_(false) {}
89 NetworkState::~NetworkState() {
92 bool NetworkState::PropertyChanged(const std::string& key,
93 const base::Value& value) {
94 // Keep care that these properties are the same as in |GetProperties|.
95 if (ManagedStatePropertyChanged(key, value))
96 return true;
97 if (key == shill::kSignalStrengthProperty) {
98 return GetIntegerValue(key, value, &signal_strength_);
99 } else if (key == shill::kStateProperty) {
100 return GetStringValue(key, value, &connection_state_);
101 } else if (key == shill::kVisibleProperty) {
102 return GetBooleanValue(key, value, &visible_);
103 } else if (key == shill::kConnectableProperty) {
104 return GetBooleanValue(key, value, &connectable_);
105 } else if (key == shill::kErrorProperty) {
106 if (!GetStringValue(key, value, &error_))
107 return false;
108 if (ErrorIsValid(error_))
109 last_error_ = error_;
110 else
111 error_.clear();
112 return true;
113 } else if (key == shill::kActivationTypeProperty) {
114 return GetStringValue(key, value, &activation_type_);
115 } else if (key == shill::kActivationStateProperty) {
116 return GetStringValue(key, value, &activation_state_);
117 } else if (key == shill::kRoamingStateProperty) {
118 return GetStringValue(key, value, &roaming_);
119 } else if (key == shill::kPaymentPortalProperty) {
120 const base::DictionaryValue* olp;
121 if (!value.GetAsDictionary(&olp))
122 return false;
123 return olp->GetStringWithoutPathExpansion(shill::kPaymentPortalURL,
124 &payment_url_);
125 } else if (key == shill::kSecurityClassProperty) {
126 return GetStringValue(key, value, &security_class_);
127 } else if (key == shill::kEapMethodProperty) {
128 return GetStringValue(key, value, &eap_method_);
129 } else if (key == shill::kNetworkTechnologyProperty) {
130 return GetStringValue(key, value, &network_technology_);
131 } else if (key == shill::kDeviceProperty) {
132 return GetStringValue(key, value, &device_path_);
133 } else if (key == shill::kGuidProperty) {
134 return GetStringValue(key, value, &guid_);
135 } else if (key == shill::kProfileProperty) {
136 return GetStringValue(key, value, &profile_path_);
137 } else if (key == shill::kWifiHexSsid) {
138 std::string ssid_hex;
139 if (!GetStringValue(key, value, &ssid_hex)) {
140 return false;
142 raw_ssid_.clear();
143 return base::HexStringToBytes(ssid_hex, &raw_ssid_);
144 } else if (key == shill::kPriorityProperty) {
145 return GetIntegerValue(key, value, &priority_);
146 } else if (key == shill::kOutOfCreditsProperty) {
147 return GetBooleanValue(key, value, &cellular_out_of_credits_);
148 } else if (key == shill::kProxyConfigProperty) {
149 std::string proxy_config_str;
150 if (!value.GetAsString(&proxy_config_str)) {
151 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
152 return false;
155 proxy_config_.Clear();
156 if (proxy_config_str.empty())
157 return true;
159 scoped_ptr<base::DictionaryValue> proxy_config_dict(
160 onc::ReadDictionaryFromJson(proxy_config_str));
161 if (proxy_config_dict) {
162 // Warning: The DictionaryValue returned from
163 // ReadDictionaryFromJson/JSONParser is an optimized derived class that
164 // doesn't allow releasing ownership of nested values. A Swap in the wrong
165 // order leads to memory access errors.
166 proxy_config_.MergeDictionary(proxy_config_dict.get());
167 } else {
168 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
170 return true;
171 } else if (key == shill::kProviderProperty) {
172 std::string vpn_provider_type;
173 const base::DictionaryValue* dict;
174 if (!value.GetAsDictionary(&dict) ||
175 !dict->GetStringWithoutPathExpansion(shill::kTypeProperty,
176 &vpn_provider_type)) {
177 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
178 return false;
181 if (vpn_provider_type == shill::kProviderThirdPartyVpn) {
182 // If the network uses a third-party VPN provider, copy over the
183 // provider's extension ID, which is held in |shill::kHostProperty|.
184 if (!dict->GetStringWithoutPathExpansion(
185 shill::kHostProperty, &third_party_vpn_provider_extension_id_)) {
186 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
187 return false;
189 } else {
190 third_party_vpn_provider_extension_id_.clear();
193 vpn_provider_type_ = vpn_provider_type;
194 return true;
196 return false;
199 bool NetworkState::InitialPropertiesReceived(
200 const base::DictionaryValue& properties) {
201 NET_LOG(EVENT) << "InitialPropertiesReceived: " << path() << ": " << name()
202 << " State: " << connection_state_ << " Visible: " << visible_;
203 if (!properties.HasKey(shill::kTypeProperty)) {
204 NET_LOG(ERROR) << "NetworkState has no type: "
205 << shill_property_util::GetNetworkIdFromProperties(
206 properties);
207 return false;
210 // By convention, all visible WiFi and WiMAX networks have a
211 // SignalStrength > 0.
212 if ((type() == shill::kTypeWifi || type() == shill::kTypeWimax) &&
213 visible() && signal_strength_ <= 0) {
214 signal_strength_ = 1;
217 // Any change to connection state will trigger a complete property update,
218 // so we update is_captive_portal_ here.
219 is_captive_portal_ = IsCaptivePortalState(properties, true /* log */);
221 // Ensure that the network has a valid name.
222 return UpdateName(properties);
225 void NetworkState::GetStateProperties(base::DictionaryValue* dictionary) const {
226 ManagedState::GetStateProperties(dictionary);
228 // Properties shared by all types.
229 dictionary->SetStringWithoutPathExpansion(shill::kGuidProperty, guid());
230 dictionary->SetStringWithoutPathExpansion(shill::kSecurityClassProperty,
231 security_class());
232 dictionary->SetStringWithoutPathExpansion(shill::kProfileProperty,
233 profile_path());
234 dictionary->SetIntegerWithoutPathExpansion(shill::kPriorityProperty,
235 priority_);
237 if (visible()) {
238 dictionary->SetStringWithoutPathExpansion(shill::kStateProperty,
239 connection_state());
242 // VPN properties.
243 if (NetworkTypePattern::VPN().MatchesType(type())) {
244 // Shill sends VPN provider properties in a nested dictionary. |dictionary|
245 // must replicate that nested structure.
246 scoped_ptr<base::DictionaryValue> provider_property(
247 new base::DictionaryValue);
248 provider_property->SetStringWithoutPathExpansion(shill::kTypeProperty,
249 vpn_provider_type_);
250 if (vpn_provider_type_ == shill::kProviderThirdPartyVpn) {
251 provider_property->SetStringWithoutPathExpansion(
252 shill::kHostProperty, third_party_vpn_provider_extension_id_);
254 dictionary->SetWithoutPathExpansion(shill::kProviderProperty,
255 provider_property.release());
258 // Wireless properties
259 if (!NetworkTypePattern::Wireless().MatchesType(type()))
260 return;
262 if (visible()) {
263 dictionary->SetBooleanWithoutPathExpansion(shill::kConnectableProperty,
264 connectable());
265 dictionary->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty,
266 signal_strength());
269 // Wifi properties
270 if (NetworkTypePattern::WiFi().MatchesType(type())) {
271 dictionary->SetStringWithoutPathExpansion(shill::kEapMethodProperty,
272 eap_method());
275 // Mobile properties
276 if (NetworkTypePattern::Mobile().MatchesType(type())) {
277 dictionary->SetStringWithoutPathExpansion(shill::kNetworkTechnologyProperty,
278 network_technology());
279 dictionary->SetStringWithoutPathExpansion(shill::kActivationStateProperty,
280 activation_state());
281 dictionary->SetStringWithoutPathExpansion(shill::kRoamingStateProperty,
282 roaming());
283 dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty,
284 cellular_out_of_credits());
288 void NetworkState::IPConfigPropertiesChanged(
289 const base::DictionaryValue& properties) {
290 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
291 iter.Advance()) {
292 std::string key = iter.key();
293 const base::Value& value = iter.value();
295 if (key == shill::kAddressProperty) {
296 GetStringValue(key, value, &ip_address_);
297 } else if (key == shill::kGatewayProperty) {
298 GetStringValue(key, value, &gateway_);
299 } else if (key == shill::kNameServersProperty) {
300 const base::ListValue* dns_servers;
301 if (value.GetAsList(&dns_servers)) {
302 dns_servers_.clear();
303 ConvertListValueToStringVector(*dns_servers, &dns_servers_);
305 } else if (key == shill::kPrefixlenProperty) {
306 GetIntegerValue(key, value, &prefix_length_);
307 } else if (key == shill::kWebProxyAutoDiscoveryUrlProperty) {
308 std::string url_string;
309 if (GetStringValue(key, value, &url_string)) {
310 if (url_string.empty()) {
311 web_proxy_auto_discovery_url_ = GURL();
312 } else {
313 GURL gurl(url_string);
314 if (gurl.is_valid()) {
315 web_proxy_auto_discovery_url_ = gurl;
316 } else {
317 NET_LOG(ERROR) << "Invalid WebProxyAutoDiscoveryUrl: " << path()
318 << ": " << url_string;
319 web_proxy_auto_discovery_url_ = GURL();
327 bool NetworkState::RequiresActivation() const {
328 return (type() == shill::kTypeCellular &&
329 activation_state() != shill::kActivationStateActivated &&
330 activation_state() != shill::kActivationStateUnknown);
333 std::string NetworkState::connection_state() const {
334 if (!visible())
335 return shill::kStateDisconnect;
336 return connection_state_;
339 bool NetworkState::IsConnectedState() const {
340 return visible() && StateIsConnected(connection_state_);
343 bool NetworkState::IsConnectingState() const {
344 return visible() && StateIsConnecting(connection_state_);
347 bool NetworkState::IsInProfile() const {
348 // kTypeEthernetEap is always saved. We need this check because it does
349 // not show up in the visible list, but its properties may not be available
350 // when it first shows up in ServiceCompleteList. See crbug.com/355117.
351 return !profile_path_.empty() || type() == shill::kTypeEthernetEap;
354 bool NetworkState::IsPrivate() const {
355 return !profile_path_.empty() &&
356 profile_path_ != NetworkProfileHandler::GetSharedProfilePath();
359 std::string NetworkState::GetHexSsid() const {
360 return base::HexEncode(vector_as_array(&raw_ssid()), raw_ssid().size());
363 std::string NetworkState::GetDnsServersAsString() const {
364 std::string result;
365 for (size_t i = 0; i < dns_servers_.size(); ++i) {
366 if (i != 0)
367 result += ",";
368 result += dns_servers_[i];
370 return result;
373 std::string NetworkState::GetNetmask() const {
374 return network_util::PrefixLengthToNetmask(prefix_length_);
377 std::string NetworkState::GetSpecifier() const {
378 if (!update_received()) {
379 NET_LOG(ERROR) << "GetSpecifier called before update: " << path();
380 return std::string();
382 if (type() == shill::kTypeWifi)
383 return name() + "_" + security_class_;
384 if (!name().empty())
385 return name();
386 return type(); // For unnamed networks such as ethernet.
389 void NetworkState::SetGuid(const std::string& guid) {
390 guid_ = guid;
393 bool NetworkState::UpdateName(const base::DictionaryValue& properties) {
394 std::string updated_name =
395 shill_property_util::GetNameFromProperties(path(), properties);
396 if (updated_name != name()) {
397 set_name(updated_name);
398 return true;
400 return false;
403 std::string NetworkState::GetErrorState() const {
404 if (ErrorIsValid(error()))
405 return error();
406 return last_error();
409 // static
410 bool NetworkState::StateIsConnected(const std::string& connection_state) {
411 return (connection_state == shill::kStateReady ||
412 connection_state == shill::kStateOnline ||
413 connection_state == shill::kStatePortal);
416 // static
417 bool NetworkState::StateIsConnecting(const std::string& connection_state) {
418 return (connection_state == shill::kStateAssociation ||
419 connection_state == shill::kStateConfiguration ||
420 connection_state == shill::kStateCarrier);
423 // static
424 bool NetworkState::NetworkStateIsCaptivePortal(
425 const base::DictionaryValue& shill_properties) {
426 return IsCaptivePortalState(shill_properties, false /* log */);
429 // static
430 bool NetworkState::ErrorIsValid(const std::string& error) {
431 // Shill uses "Unknown" to indicate an unset or cleared error state.
432 return !error.empty() && error != kErrorUnknown;
435 } // namespace chromeos