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/stl_util.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/stringprintf.h"
10 #include "chromeos/network/network_profile_handler.h"
11 #include "chromeos/network/network_type_pattern.h"
12 #include "chromeos/network/network_util.h"
13 #include "chromeos/network/onc/onc_utils.h"
14 #include "chromeos/network/shill_property_util.h"
15 #include "components/device_event_log/device_event_log.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
20 const char kErrorUnknown
[] = "Unknown";
22 bool ConvertListValueToStringVector(const base::ListValue
& string_list
,
23 std::vector
<std::string
>* result
) {
24 for (size_t i
= 0; i
< string_list
.GetSize(); ++i
) {
26 if (!string_list
.GetString(i
, &str
))
28 result
->push_back(str
);
33 bool IsCaptivePortalState(const base::DictionaryValue
& properties
, bool log
) {
35 properties
.GetStringWithoutPathExpansion(shill::kStateProperty
, &state
);
36 if (state
!= shill::kStatePortal
)
38 std::string portal_detection_phase
, portal_detection_status
;
39 if (!properties
.GetStringWithoutPathExpansion(
40 shill::kPortalDetectionFailedPhaseProperty
,
41 &portal_detection_phase
) ||
42 !properties
.GetStringWithoutPathExpansion(
43 shill::kPortalDetectionFailedStatusProperty
,
44 &portal_detection_status
)) {
45 // If Shill (or a stub) has not set PortalDetectionFailedStatus
46 // or PortalDetectionFailedPhase, assume we are in captive portal state.
50 // Shill reports the phase in which it determined that the device is behind a
51 // captive portal. We only want to rely only on incorrect content being
52 // returned and ignore other reasons.
53 bool is_captive_portal
=
54 portal_detection_phase
== shill::kPortalDetectionPhaseContent
&&
55 portal_detection_status
== shill::kPortalDetectionStatusFailure
;
59 properties
.GetStringWithoutPathExpansion(shill::kNameProperty
, &name
);
61 properties
.GetStringWithoutPathExpansion(shill::kSSIDProperty
, &name
);
62 if (!is_captive_portal
) {
63 NET_LOG(EVENT
) << "State is 'portal' but not in captive portal state:"
64 << " name=" << name
<< " phase=" << portal_detection_phase
65 << " status=" << portal_detection_status
;
67 NET_LOG(EVENT
) << "Network is in captive portal state: " << name
;
71 return is_captive_portal
;
78 NetworkState::NetworkState(const std::string
& path
)
79 : ManagedState(MANAGED_TYPE_NETWORK
, path
),
83 is_captive_portal_(false),
85 cellular_out_of_credits_(false) {
88 NetworkState::~NetworkState() {
91 bool NetworkState::PropertyChanged(const std::string
& key
,
92 const base::Value
& value
) {
93 // Keep care that these properties are the same as in |GetProperties|.
94 if (ManagedStatePropertyChanged(key
, value
))
96 if (key
== shill::kSignalStrengthProperty
) {
97 return GetIntegerValue(key
, value
, &signal_strength_
);
98 } else if (key
== shill::kStateProperty
) {
99 return GetStringValue(key
, value
, &connection_state_
);
100 } else if (key
== shill::kVisibleProperty
) {
101 return GetBooleanValue(key
, value
, &visible_
);
102 } else if (key
== shill::kConnectableProperty
) {
103 return GetBooleanValue(key
, value
, &connectable_
);
104 } else if (key
== shill::kErrorProperty
) {
105 if (!GetStringValue(key
, value
, &error_
))
107 if (ErrorIsValid(error_
))
108 last_error_
= error_
;
112 } else if (key
== shill::kActivationTypeProperty
) {
113 return GetStringValue(key
, value
, &activation_type_
);
114 } else if (key
== shill::kActivationStateProperty
) {
115 return GetStringValue(key
, value
, &activation_state_
);
116 } else if (key
== shill::kRoamingStateProperty
) {
117 return GetStringValue(key
, value
, &roaming_
);
118 } else if (key
== shill::kPaymentPortalProperty
) {
119 const base::DictionaryValue
* olp
;
120 if (!value
.GetAsDictionary(&olp
))
122 return olp
->GetStringWithoutPathExpansion(shill::kPaymentPortalURL
,
124 } else if (key
== shill::kSecurityClassProperty
) {
125 return GetStringValue(key
, value
, &security_class_
);
126 } else if (key
== shill::kEapMethodProperty
) {
127 return GetStringValue(key
, value
, &eap_method_
);
128 } else if (key
== shill::kNetworkTechnologyProperty
) {
129 return GetStringValue(key
, value
, &network_technology_
);
130 } else if (key
== shill::kDeviceProperty
) {
131 return GetStringValue(key
, value
, &device_path_
);
132 } else if (key
== shill::kGuidProperty
) {
133 return GetStringValue(key
, value
, &guid_
);
134 } else if (key
== shill::kProfileProperty
) {
135 return GetStringValue(key
, value
, &profile_path_
);
136 } else if (key
== shill::kWifiHexSsid
) {
137 std::string ssid_hex
;
138 if (!GetStringValue(key
, value
, &ssid_hex
)) {
142 return base::HexStringToBytes(ssid_hex
, &raw_ssid_
);
143 } else if (key
== shill::kOutOfCreditsProperty
) {
144 return GetBooleanValue(key
, value
, &cellular_out_of_credits_
);
145 } else if (key
== shill::kProxyConfigProperty
) {
146 std::string proxy_config_str
;
147 if (!value
.GetAsString(&proxy_config_str
)) {
148 NET_LOG(ERROR
) << "Failed to parse " << path() << "." << key
;
152 proxy_config_
.Clear();
153 if (proxy_config_str
.empty())
156 scoped_ptr
<base::DictionaryValue
> proxy_config_dict(
157 onc::ReadDictionaryFromJson(proxy_config_str
));
158 if (proxy_config_dict
) {
159 // Warning: The DictionaryValue returned from
160 // ReadDictionaryFromJson/JSONParser is an optimized derived class that
161 // doesn't allow releasing ownership of nested values. A Swap in the wrong
162 // order leads to memory access errors.
163 proxy_config_
.MergeDictionary(proxy_config_dict
.get());
165 NET_LOG(ERROR
) << "Failed to parse " << path() << "." << key
;
172 bool NetworkState::InitialPropertiesReceived(
173 const base::DictionaryValue
& properties
) {
174 NET_LOG(EVENT
) << "InitialPropertiesReceived: " << path() << ": " << name()
175 << " State: " << connection_state_
<< " Visible: " << visible_
;
176 if (!properties
.HasKey(shill::kTypeProperty
)) {
177 NET_LOG(ERROR
) << "NetworkState has no type: "
178 << shill_property_util::GetNetworkIdFromProperties(
183 // By convention, all visible WiFi and WiMAX networks have a
184 // SignalStrength > 0.
185 if ((type() == shill::kTypeWifi
|| type() == shill::kTypeWimax
) &&
186 visible() && signal_strength_
<= 0) {
187 signal_strength_
= 1;
190 // Any change to connection state will trigger a complete property update,
191 // so we update is_captive_portal_ here.
192 is_captive_portal_
= IsCaptivePortalState(properties
, true /* log */);
194 // Ensure that the network has a valid name.
195 return UpdateName(properties
);
198 void NetworkState::GetStateProperties(base::DictionaryValue
* dictionary
) const {
199 ManagedState::GetStateProperties(dictionary
);
201 // Properties shared by all types.
202 dictionary
->SetStringWithoutPathExpansion(shill::kGuidProperty
, guid());
203 dictionary
->SetStringWithoutPathExpansion(shill::kSecurityClassProperty
,
205 dictionary
->SetStringWithoutPathExpansion(shill::kProfileProperty
,
209 if (!error().empty())
210 dictionary
->SetStringWithoutPathExpansion(shill::kErrorProperty
, error());
211 dictionary
->SetStringWithoutPathExpansion(shill::kStateProperty
,
215 // Wireless properties
216 if (!NetworkTypePattern::Wireless().MatchesType(type()))
220 dictionary
->SetBooleanWithoutPathExpansion(shill::kConnectableProperty
,
222 dictionary
->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty
,
227 if (NetworkTypePattern::WiFi().MatchesType(type())) {
228 dictionary
->SetStringWithoutPathExpansion(shill::kEapMethodProperty
,
233 if (NetworkTypePattern::Mobile().MatchesType(type())) {
234 dictionary
->SetStringWithoutPathExpansion(shill::kNetworkTechnologyProperty
,
235 network_technology());
236 dictionary
->SetStringWithoutPathExpansion(shill::kActivationStateProperty
,
238 dictionary
->SetStringWithoutPathExpansion(shill::kRoamingStateProperty
,
240 dictionary
->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty
,
241 cellular_out_of_credits());
245 void NetworkState::IPConfigPropertiesChanged(
246 const base::DictionaryValue
& properties
) {
247 for (base::DictionaryValue::Iterator
iter(properties
); !iter
.IsAtEnd();
249 std::string key
= iter
.key();
250 const base::Value
& value
= iter
.value();
252 if (key
== shill::kAddressProperty
) {
253 GetStringValue(key
, value
, &ip_address_
);
254 } else if (key
== shill::kGatewayProperty
) {
255 GetStringValue(key
, value
, &gateway_
);
256 } else if (key
== shill::kNameServersProperty
) {
257 const base::ListValue
* dns_servers
;
258 if (value
.GetAsList(&dns_servers
)) {
259 dns_servers_
.clear();
260 ConvertListValueToStringVector(*dns_servers
, &dns_servers_
);
262 } else if (key
== shill::kPrefixlenProperty
) {
263 GetIntegerValue(key
, value
, &prefix_length_
);
264 } else if (key
== shill::kWebProxyAutoDiscoveryUrlProperty
) {
265 std::string url_string
;
266 if (GetStringValue(key
, value
, &url_string
)) {
267 if (url_string
.empty()) {
268 web_proxy_auto_discovery_url_
= GURL();
270 GURL
gurl(url_string
);
271 if (gurl
.is_valid()) {
272 web_proxy_auto_discovery_url_
= gurl
;
274 NET_LOG(ERROR
) << "Invalid WebProxyAutoDiscoveryUrl: " << path()
275 << ": " << url_string
;
276 web_proxy_auto_discovery_url_
= GURL();
284 bool NetworkState::RequiresActivation() const {
285 return (type() == shill::kTypeCellular
&&
286 activation_state() != shill::kActivationStateActivated
&&
287 activation_state() != shill::kActivationStateUnknown
);
290 std::string
NetworkState::connection_state() const {
292 return shill::kStateDisconnect
;
293 return connection_state_
;
296 bool NetworkState::IsConnectedState() const {
297 return visible() && StateIsConnected(connection_state_
);
300 bool NetworkState::IsConnectingState() const {
301 return visible() && StateIsConnecting(connection_state_
);
304 bool NetworkState::IsInProfile() const {
305 // kTypeEthernetEap is always saved. We need this check because it does
306 // not show up in the visible list, but its properties may not be available
307 // when it first shows up in ServiceCompleteList. See crbug.com/355117.
308 return !profile_path_
.empty() || type() == shill::kTypeEthernetEap
;
311 bool NetworkState::IsPrivate() const {
312 return !profile_path_
.empty() &&
313 profile_path_
!= NetworkProfileHandler::GetSharedProfilePath();
316 std::string
NetworkState::GetHexSsid() const {
317 return base::HexEncode(vector_as_array(&raw_ssid()), raw_ssid().size());
320 std::string
NetworkState::GetDnsServersAsString() const {
322 for (size_t i
= 0; i
< dns_servers_
.size(); ++i
) {
325 result
+= dns_servers_
[i
];
330 std::string
NetworkState::GetNetmask() const {
331 return network_util::PrefixLengthToNetmask(prefix_length_
);
334 std::string
NetworkState::GetSpecifier() const {
335 if (!update_received()) {
336 NET_LOG(ERROR
) << "GetSpecifier called before update: " << path();
337 return std::string();
339 if (type() == shill::kTypeWifi
)
340 return name() + "_" + security_class_
;
343 return type(); // For unnamed networks such as ethernet.
346 void NetworkState::SetGuid(const std::string
& guid
) {
350 bool NetworkState::UpdateName(const base::DictionaryValue
& properties
) {
351 std::string updated_name
=
352 shill_property_util::GetNameFromProperties(path(), properties
);
353 if (updated_name
!= name()) {
354 set_name(updated_name
);
361 bool NetworkState::StateIsConnected(const std::string
& connection_state
) {
362 return (connection_state
== shill::kStateReady
||
363 connection_state
== shill::kStateOnline
||
364 connection_state
== shill::kStatePortal
);
368 bool NetworkState::StateIsConnecting(const std::string
& connection_state
) {
369 return (connection_state
== shill::kStateAssociation
||
370 connection_state
== shill::kStateConfiguration
||
371 connection_state
== shill::kStateCarrier
);
375 bool NetworkState::NetworkStateIsCaptivePortal(
376 const base::DictionaryValue
& shill_properties
) {
377 return IsCaptivePortalState(shill_properties
, false /* log */);
381 bool NetworkState::ErrorIsValid(const std::string
& error
) {
382 // Shill uses "Unknown" to indicate an unset or cleared error state.
383 return !error
.empty() && error
!= kErrorUnknown
;
386 } // namespace chromeos