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 <stddef.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/metrics/histogram_functions.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/values.h"
17 #include "chromeos/network/network_event_log.h"
18 #include "chromeos/network/network_profile_handler.h"
19 #include "chromeos/network/network_type_pattern.h"
20 #include "chromeos/network/network_ui_data.h"
21 #include "chromeos/network/network_util.h"
22 #include "chromeos/network/onc/onc_utils.h"
23 #include "chromeos/network/shill_property_util.h"
24 #include "chromeos/network/tether_constants.h"
25 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
26 #include "net/http/http_status_code.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28
29 namespace {
30
31 const char kDefaultCellularNetworkPath[] = "/cellular";
32
33 // TODO(tbarzic): Add payment portal method values to shill/dbus-constants.
34 constexpr char kPaymentPortalMethodPost[] = "POST";
35
36 // TODO(b/169939319): Use shill constant once it lands.
37 const char kPortalDetectionFailedStatusCodeProperty[] =
38 "PortalDetectionFailedStatusCode";
39
40 // |dict| may be an empty value, in which case return an empty string.
GetStringFromDictionary(const base::Value & dict,const char * key)41 std::string GetStringFromDictionary(const base::Value& dict, const char* key) {
42 const std::string* stringp =
43 dict.is_none() ? nullptr : dict.FindStringKey(key);
44 return stringp ? *stringp : std::string();
45 }
46
47 } // namespace
48
49 namespace chromeos {
50
NetworkState(const std::string & path)51 NetworkState::NetworkState(const std::string& path)
52 : ManagedState(MANAGED_TYPE_NETWORK, path) {}
53
54 NetworkState::~NetworkState() = default;
55
PropertyChanged(const std::string & key,const base::Value & value)56 bool NetworkState::PropertyChanged(const std::string& key,
57 const base::Value& value) {
58 // Keep care that these properties are the same as in |GetProperties|.
59 if (ManagedStatePropertyChanged(key, value))
60 return true;
61 if (key == shill::kSignalStrengthProperty) {
62 int signal_strength = signal_strength_;
63 if (!GetIntegerValue(key, value, &signal_strength))
64 return false;
65 if (signal_strength_ > 0 && abs(signal_strength - signal_strength_) <
66 kSignalStrengthChangeThreshold) {
67 return false;
68 }
69 signal_strength_ = signal_strength;
70 return true;
71 } else if (key == shill::kStateProperty) {
72 std::string connection_state;
73 if (!GetStringValue(key, value, &connection_state))
74 return false;
75 SetConnectionState(connection_state);
76 return true;
77 } else if (key == shill::kVisibleProperty) {
78 return GetBooleanValue(key, value, &visible_);
79 } else if (key == shill::kConnectableProperty) {
80 return GetBooleanValue(key, value, &connectable_);
81 } else if (key == shill::kErrorProperty) {
82 std::string error;
83 if (!GetStringValue(key, value, &error))
84 return false;
85 if (ErrorIsValid(error))
86 last_error_ = error;
87 return true;
88 } else if (key == shill::kWifiFrequency) {
89 return GetIntegerValue(key, value, &frequency_);
90 } else if (key == shill::kActivationTypeProperty) {
91 return GetStringValue(key, value, &activation_type_);
92 } else if (key == shill::kActivationStateProperty) {
93 return GetStringValue(key, value, &activation_state_);
94 } else if (key == shill::kRoamingStateProperty) {
95 return GetStringValue(key, value, &roaming_);
96 } else if (key == shill::kPaymentPortalProperty) {
97 if (!value.is_dict())
98 return false;
99 const base::Value* portal_url_value = value.FindKeyOfType(
100 shill::kPaymentPortalURL, base::Value::Type::STRING);
101 if (!portal_url_value)
102 return false;
103 payment_url_ = portal_url_value->GetString();
104 // If payment portal uses post method, set up post data.
105 const base::Value* portal_method_value = value.FindKeyOfType(
106 shill::kPaymentPortalMethod, base::Value::Type::STRING);
107 const base::Value* portal_post_data_value = value.FindKeyOfType(
108 shill::kPaymentPortalPostData, base::Value::Type::STRING);
109 if (portal_method_value &&
110 portal_method_value->GetString() == kPaymentPortalMethodPost &&
111 portal_post_data_value) {
112 payment_post_data_ = portal_post_data_value->GetString();
113 }
114 return true;
115 } else if (key == shill::kSecurityClassProperty) {
116 return GetStringValue(key, value, &security_class_);
117 } else if (key == shill::kEapMethodProperty) {
118 return GetStringValue(key, value, &eap_method_);
119 } else if (key == shill::kEapKeyMgmtProperty) {
120 return GetStringValue(key, value, &eap_key_mgmt_);
121 } else if (key == shill::kNetworkTechnologyProperty) {
122 return GetStringValue(key, value, &network_technology_);
123 } else if (key == shill::kDeviceProperty) {
124 return GetStringValue(key, value, &device_path_);
125 } else if (key == shill::kGuidProperty) {
126 return GetStringValue(key, value, &guid_);
127 } else if (key == shill::kProfileProperty) {
128 return GetStringValue(key, value, &profile_path_);
129 } else if (key == shill::kWifiHexSsid) {
130 std::string ssid_hex;
131 if (!GetStringValue(key, value, &ssid_hex))
132 return false;
133 raw_ssid_.clear();
134 return base::HexStringToBytes(ssid_hex, &raw_ssid_);
135 } else if (key == shill::kWifiBSsid) {
136 return GetStringValue(key, value, &bssid_);
137 } else if (key == shill::kPriorityProperty) {
138 return GetIntegerValue(key, value, &priority_);
139 } else if (key == shill::kOutOfCreditsProperty) {
140 return GetBooleanValue(key, value, &cellular_out_of_credits_);
141 } else if (key == shill::kProxyConfigProperty) {
142 std::string proxy_config_str;
143 if (!value.GetAsString(&proxy_config_str)) {
144 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
145 return false;
146 }
147
148 if (proxy_config_str.empty()) {
149 proxy_config_ = base::Value();
150 return true;
151 }
152 base::Value proxy_config = onc::ReadDictionaryFromJson(proxy_config_str);
153 if (!proxy_config.is_dict()) {
154 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
155 proxy_config_ = base::Value();
156 } else {
157 proxy_config_ = std::move(proxy_config);
158 }
159 return true;
160 } else if (key == shill::kProviderProperty) {
161 const base::Value* type_value =
162 value.is_dict() ? value.FindKeyOfType(shill::kTypeProperty,
163 base::Value::Type::STRING)
164 : nullptr;
165 if (!type_value) {
166 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
167 return false;
168 }
169 std::string vpn_provider_type = type_value->GetString();
170 std::string vpn_provider_id;
171 if (vpn_provider_type == shill::kProviderThirdPartyVpn ||
172 vpn_provider_type == shill::kProviderArcVpn) {
173 // If the network uses a third-party or Arc VPN provider,
174 // |shill::kHostProperty| contains the extension ID or Arc package name.
175 const base::Value* host_value =
176 value.FindKeyOfType(shill::kHostProperty, base::Value::Type::STRING);
177 if (!host_value) {
178 NET_LOG(ERROR) << "Failed to parse " << path() << "." << key;
179 return false;
180 }
181 vpn_provider_id = host_value->GetString();
182 }
183 SetVpnProvider(vpn_provider_id, vpn_provider_type);
184 return true;
185 } else if (key == shill::kTetheringProperty) {
186 return GetStringValue(key, value, &tethering_state_);
187 } else if (key == shill::kUIDataProperty) {
188 std::unique_ptr<NetworkUIData> ui_data =
189 chromeos::shill_property_util::GetUIDataFromValue(value);
190 if (!ui_data)
191 return false;
192 onc_source_ = ui_data->onc_source();
193 return true;
194 } else if (key == shill::kProbeUrlProperty) {
195 std::string probe_url_string;
196 if (!GetStringValue(key, value, &probe_url_string))
197 return false;
198 probe_url_ = GURL(probe_url_string);
199 return true;
200 }
201 return false;
202 }
203
InitialPropertiesReceived(const base::Value & properties)204 bool NetworkState::InitialPropertiesReceived(const base::Value& properties) {
205 NET_LOG(EVENT) << "InitialPropertiesReceived: " << NetworkId(this)
206 << " State: " << connection_state_ << " Visible: " << visible_;
207 if (!properties.FindKey(shill::kTypeProperty)) {
208 NET_LOG(ERROR) << "NetworkState has no type: " << NetworkId(this);
209 return false;
210 }
211
212 // By convention, all visible WiFi networks have a SignalStrength > 0.
213 if (type() == shill::kTypeWifi && visible() && signal_strength_ <= 0) {
214 signal_strength_ = 1;
215 }
216
217 // Any change to connection state or portal properties will trigger a complete
218 // property update, so we update captive portal state here.
219 UpdateCaptivePortalState(properties);
220
221 // Ensure that the network has a valid name.
222 return UpdateName(properties);
223 }
224
GetStateProperties(base::Value * dictionary) const225 void NetworkState::GetStateProperties(base::Value* dictionary) const {
226 ManagedState::GetStateProperties(dictionary);
227
228 // Properties shared by all types.
229 dictionary->SetKey(shill::kGuidProperty, base::Value(guid()));
230 dictionary->SetKey(shill::kSecurityClassProperty,
231 base::Value(security_class()));
232 dictionary->SetKey(shill::kProfileProperty, base::Value(profile_path()));
233 dictionary->SetKey(shill::kPriorityProperty, base::Value(priority_));
234
235 if (visible())
236 dictionary->SetKey(shill::kStateProperty, base::Value(connection_state()));
237 if (!device_path().empty())
238 dictionary->SetKey(shill::kDeviceProperty, base::Value(device_path()));
239
240 // VPN properties.
241 if (NetworkTypePattern::VPN().MatchesType(type()) && vpn_provider()) {
242 // Shill sends VPN provider properties in a nested dictionary. |dictionary|
243 // must replicate that nested structure.
244 std::string provider_type = vpn_provider()->type;
245 base::Value provider_property(base::Value::Type::DICTIONARY);
246 provider_property.SetKey(shill::kTypeProperty, base::Value(provider_type));
247 if (provider_type == shill::kProviderThirdPartyVpn ||
248 provider_type == shill::kProviderArcVpn) {
249 provider_property.SetKey(shill::kHostProperty,
250 base::Value(vpn_provider()->id));
251 }
252 dictionary->SetKey(shill::kProviderProperty, std::move(provider_property));
253 }
254
255 // Tether properties
256 if (NetworkTypePattern::Tether().MatchesType(type())) {
257 dictionary->SetKey(kTetherBatteryPercentage,
258 base::Value(battery_percentage()));
259 dictionary->SetKey(kTetherCarrier, base::Value(tether_carrier()));
260 dictionary->SetKey(kTetherHasConnectedToHost,
261 base::Value(tether_has_connected_to_host()));
262 dictionary->SetKey(kTetherSignalStrength, base::Value(signal_strength()));
263
264 // All Tether networks are connectable.
265 dictionary->SetKey(shill::kConnectableProperty, base::Value(connectable()));
266
267 // Tether networks do not share some of the wireless/mobile properties added
268 // below; exit early to avoid having these properties applied.
269 return;
270 }
271
272 // Wireless properties
273 if (!NetworkTypePattern::Wireless().MatchesType(type()))
274 return;
275
276 if (visible()) {
277 dictionary->SetKey(shill::kConnectableProperty, base::Value(connectable()));
278 dictionary->SetKey(shill::kSignalStrengthProperty,
279 base::Value(signal_strength()));
280 }
281
282 // Wifi properties
283 if (NetworkTypePattern::WiFi().MatchesType(type())) {
284 dictionary->SetKey(shill::kWifiBSsid, base::Value(bssid_));
285 dictionary->SetKey(shill::kEapMethodProperty, base::Value(eap_method()));
286 dictionary->SetKey(shill::kWifiFrequency, base::Value(frequency_));
287 dictionary->SetKey(shill::kWifiHexSsid, base::Value(GetHexSsid()));
288 dictionary->SetKey(shill::kTetheringProperty,
289 base::Value(tethering_state_));
290 }
291
292 // Mobile properties
293 if (NetworkTypePattern::Mobile().MatchesType(type())) {
294 dictionary->SetKey(shill::kNetworkTechnologyProperty,
295 base::Value(network_technology()));
296 dictionary->SetKey(shill::kActivationStateProperty,
297 base::Value(activation_state()));
298 dictionary->SetKey(shill::kRoamingStateProperty, base::Value(roaming_));
299 dictionary->SetKey(shill::kOutOfCreditsProperty,
300 base::Value(cellular_out_of_credits()));
301 }
302 }
303
IsActive() const304 bool NetworkState::IsActive() const {
305 return IsConnectingOrConnected() ||
306 activation_state() == shill::kActivationStateActivating;
307 }
308
IPConfigPropertiesChanged(const base::Value & properties)309 void NetworkState::IPConfigPropertiesChanged(const base::Value& properties) {
310 if (properties.DictEmpty()) {
311 ipv4_config_ = base::Value();
312 return;
313 }
314 ipv4_config_ = properties.Clone();
315 }
316
GetIpAddress() const317 std::string NetworkState::GetIpAddress() const {
318 return GetStringFromDictionary(ipv4_config_, shill::kAddressProperty);
319 }
320
GetGateway() const321 std::string NetworkState::GetGateway() const {
322 return GetStringFromDictionary(ipv4_config_, shill::kGatewayProperty);
323 }
324
GetWebProxyAutoDiscoveryUrl() const325 GURL NetworkState::GetWebProxyAutoDiscoveryUrl() const {
326 std::string url = GetStringFromDictionary(
327 ipv4_config_, shill::kWebProxyAutoDiscoveryUrlProperty);
328 if (url.empty())
329 return GURL();
330 GURL gurl(url);
331 if (!gurl.is_valid()) {
332 NET_LOG(ERROR) << "Invalid WebProxyAutoDiscoveryUrl: " << NetworkId(this)
333 << ": " << url;
334 return GURL();
335 }
336 return gurl;
337 }
338
GetVpnProviderType() const339 std::string NetworkState::GetVpnProviderType() const {
340 return vpn_provider_ ? vpn_provider_->type : std::string();
341 }
342
RequiresActivation() const343 bool NetworkState::RequiresActivation() const {
344 return type() == shill::kTypeCellular &&
345 activation_state() != shill::kActivationStateActivated &&
346 activation_state() != shill::kActivationStateUnknown;
347 }
348
SecurityRequiresPassphraseOnly() const349 bool NetworkState::SecurityRequiresPassphraseOnly() const {
350 return type() == shill::kTypeWifi &&
351 (security_class_ == shill::kSecurityPsk ||
352 security_class_ == shill::kSecurityWep);
353 }
354
GetError() const355 const std::string& NetworkState::GetError() const {
356 return last_error_;
357 }
358
ClearError()359 void NetworkState::ClearError() {
360 last_error_.clear();
361 }
362
connection_state() const363 std::string NetworkState::connection_state() const {
364 if (!visible())
365 return shill::kStateIdle;
366 DCHECK(connection_state_ == shill::kStateIdle ||
367 connection_state_ == shill::kStateAssociation ||
368 connection_state_ == shill::kStateConfiguration ||
369 connection_state_ == shill::kStateReady ||
370 connection_state_ == shill::kStatePortal ||
371 connection_state_ == shill::kStateNoConnectivity ||
372 connection_state_ == shill::kStateRedirectFound ||
373 connection_state_ == shill::kStatePortalSuspected ||
374 // TODO(https://crbug.com/552190): Remove kStateOffline from this list
375 // when occurrences in chromium code have been eliminated.
376 connection_state_ == shill::kStateOffline ||
377 connection_state_ == shill::kStateOnline ||
378 connection_state_ == shill::kStateFailure ||
379 connection_state_ == shill::kStateDisconnect ||
380 // TODO(https://crbug.com/552190): Remove kStateActivationFailure from
381 // this list when occurrences in chromium code have been eliminated.
382 connection_state_ == shill::kStateActivationFailure ||
383 // TODO(https://crbug.com/552190): Empty should not be a valid state,
384 // but e.g. new tether NetworkStates and unit tests use it currently.
385 connection_state_.empty());
386
387 return connection_state_;
388 }
389
SetConnectionState(const std::string & connection_state)390 void NetworkState::SetConnectionState(const std::string& connection_state) {
391 if (connection_state == connection_state_)
392 return;
393 last_connection_state_ = connection_state_;
394 connection_state_ = connection_state;
395 if (StateIsConnected(connection_state_) ||
396 StateIsConnecting(last_connection_state_)) {
397 // If connected or previously connecting, clear |connect_requested_|.
398 connect_requested_ = false;
399 } else if (StateIsConnected(last_connection_state_) &&
400 StateIsConnecting(connection_state_)) {
401 // If transitioning from a connected state to a connecting state, set
402 // |connect_requested_| so that the UI knows the connecting state is
403 // important (i.e. not a normal auto connect).
404 connect_requested_ = true;
405 }
406 }
407
IsManagedByPolicy() const408 bool NetworkState::IsManagedByPolicy() const {
409 return onc_source_ == ::onc::ONCSource::ONC_SOURCE_DEVICE_POLICY ||
410 onc_source_ == ::onc::ONCSource::ONC_SOURCE_USER_POLICY;
411 }
412
IndicateRoaming() const413 bool NetworkState::IndicateRoaming() const {
414 return type() == shill::kTypeCellular &&
415 roaming_ == shill::kRoamingStateRoaming && !provider_requires_roaming_;
416 }
417
IsDynamicWep() const418 bool NetworkState::IsDynamicWep() const {
419 return security_class_ == shill::kSecurityWep &&
420 eap_key_mgmt_ == shill::kKeyManagementIEEE8021X;
421 }
422
IsConnectedState() const423 bool NetworkState::IsConnectedState() const {
424 return visible() && StateIsConnected(connection_state_);
425 }
426
IsConnectingState() const427 bool NetworkState::IsConnectingState() const {
428 return visible() &&
429 (connect_requested_ || StateIsConnecting(connection_state_));
430 }
431
IsConnectingOrConnected() const432 bool NetworkState::IsConnectingOrConnected() const {
433 return visible() &&
434 (connect_requested_ || StateIsConnecting(connection_state_) ||
435 StateIsConnected(connection_state_));
436 }
437
IsOnline() const438 bool NetworkState::IsOnline() const {
439 return connection_state() == shill::kStateOnline;
440 }
441
IsInProfile() const442 bool NetworkState::IsInProfile() const {
443 // kTypeEthernetEap is always saved. We need this check because it does
444 // not show up in the visible list, but its properties may not be available
445 // when it first shows up in ServiceCompleteList. See crbug.com/355117.
446 return !profile_path_.empty() || type() == shill::kTypeEthernetEap;
447 }
448
IsNonProfileType() const449 bool NetworkState::IsNonProfileType() const {
450 return type() == kTypeTether || IsDefaultCellular();
451 }
452
IsPrivate() const453 bool NetworkState::IsPrivate() const {
454 return !profile_path_.empty() &&
455 profile_path_ != NetworkProfileHandler::GetSharedProfilePath();
456 }
457
IsDefaultCellular() const458 bool NetworkState::IsDefaultCellular() const {
459 return type() == shill::kTypeCellular &&
460 path() == kDefaultCellularNetworkPath;
461 }
462
IsShillCaptivePortal() const463 bool NetworkState::IsShillCaptivePortal() const {
464 switch (portal_state_) {
465 case PortalState::kUnknown:
466 case PortalState::kOnline:
467 return false;
468 case PortalState::kPortalSuspected:
469 case PortalState::kPortal:
470 case PortalState::kProxyAuthRequired:
471 case PortalState::kNoInternet:
472 return true;
473 }
474 NOTREACHED();
475 return false;
476 }
477
IsCaptivePortal() const478 bool NetworkState::IsCaptivePortal() const {
479 return is_chrome_captive_portal_ || IsShillCaptivePortal();
480 }
481
IsSecure() const482 bool NetworkState::IsSecure() const {
483 return !security_class_.empty() && security_class_ != shill::kSecurityNone;
484 }
485
GetHexSsid() const486 std::string NetworkState::GetHexSsid() const {
487 return base::HexEncode(raw_ssid().data(), raw_ssid().size());
488 }
489
GetDnsServersAsString() const490 std::string NetworkState::GetDnsServersAsString() const {
491 const base::Value* listv =
492 ipv4_config_.is_none()
493 ? nullptr
494 : ipv4_config_.FindListKey(shill::kNameServersProperty);
495 if (!listv)
496 return std::string();
497 std::string result;
498 for (const auto& v : listv->GetList()) {
499 if (!result.empty())
500 result += ",";
501 result += v.GetString();
502 }
503 return result;
504 }
505
GetNetmask() const506 std::string NetworkState::GetNetmask() const {
507 int prefixlen =
508 ipv4_config_.FindIntKey(shill::kPrefixlenProperty).value_or(-1);
509 return network_util::PrefixLengthToNetmask(prefixlen);
510 }
511
GetSpecifier() const512 std::string NetworkState::GetSpecifier() const {
513 if (!update_received()) {
514 NET_LOG(ERROR) << "GetSpecifier called before update: " << NetworkId(this);
515 return std::string();
516 }
517 if (type() == shill::kTypeWifi)
518 return name() + "_" + security_class_;
519 // TODO(b/154014577): Use IMSI for Cellular once available.
520 if (!name().empty())
521 return type() + "_" + name();
522 return type(); // For unnamed networks, i.e. Ethernet.
523 }
524
SetGuid(const std::string & guid)525 void NetworkState::SetGuid(const std::string& guid) {
526 guid_ = guid;
527 }
528
529 network_config::mojom::ActivationStateType
GetMojoActivationState() const530 NetworkState::GetMojoActivationState() const {
531 using network_config::mojom::ActivationStateType;
532 if (IsDefaultCellular())
533 return ActivationStateType::kNoService;
534 if (activation_state_.empty())
535 return ActivationStateType::kUnknown;
536 if (activation_state_ == shill::kActivationStateActivated)
537 return ActivationStateType::kActivated;
538 if (activation_state_ == shill::kActivationStateActivating)
539 return ActivationStateType::kActivating;
540 if (activation_state_ == shill::kActivationStateNotActivated)
541 return ActivationStateType::kNotActivated;
542 if (activation_state_ == shill::kActivationStatePartiallyActivated)
543 return ActivationStateType::kPartiallyActivated;
544 NET_LOG(ERROR) << "Unexpected shill activation state: " << activation_state_;
545 return ActivationStateType::kUnknown;
546 }
547
GetMojoSecurity() const548 network_config::mojom::SecurityType NetworkState::GetMojoSecurity() const {
549 using network_config::mojom::SecurityType;
550 if (!IsSecure())
551 return SecurityType::kNone;
552 if (IsDynamicWep())
553 return SecurityType::kWep8021x;
554
555 if (security_class_ == shill::kSecurityWep)
556 return SecurityType::kWepPsk;
557 if (security_class_ == shill::kSecurityPsk)
558 return SecurityType::kWpaPsk;
559 if (security_class_ == shill::kSecurity8021x)
560 return SecurityType::kWpaEap;
561 NET_LOG(ERROR) << "Unsupported shill security class: " << security_class_;
562 return SecurityType::kNone;
563 }
564
GetNetworkTechnologyType() const565 NetworkState::NetworkTechnologyType NetworkState::GetNetworkTechnologyType()
566 const {
567 const std::string& network_type = type();
568 if (network_type == shill::kTypeCellular)
569 return NetworkTechnologyType::kCellular;
570 if (network_type == shill::kTypeEthernet)
571 return NetworkTechnologyType::kEthernet;
572 if (network_type == shill::kTypeEthernetEap)
573 return NetworkTechnologyType::kEthernet;
574 if (network_type == kTypeTether)
575 return NetworkTechnologyType::kTether;
576 if (network_type == shill::kTypeVPN)
577 return NetworkTechnologyType::kVPN;
578 if (network_type == shill::kTypeWifi)
579 return NetworkTechnologyType::kWiFi;
580 NOTREACHED() << "Unknown network type: " << network_type;
581 return NetworkTechnologyType::kUnknown;
582 }
583
584 // static
StateIsConnected(const std::string & connection_state)585 bool NetworkState::StateIsConnected(const std::string& connection_state) {
586 return (connection_state == shill::kStateReady ||
587 connection_state == shill::kStateOnline ||
588 StateIsPortalled(connection_state));
589 }
590
591 // static
StateIsConnecting(const std::string & connection_state)592 bool NetworkState::StateIsConnecting(const std::string& connection_state) {
593 return (connection_state == shill::kStateAssociation ||
594 connection_state == shill::kStateConfiguration);
595 }
596
597 // static
StateIsPortalled(const std::string & connection_state)598 bool NetworkState::StateIsPortalled(const std::string& connection_state) {
599 return (connection_state == shill::kStatePortal ||
600 connection_state == shill::kStateNoConnectivity ||
601 connection_state == shill::kStateRedirectFound ||
602 connection_state == shill::kStatePortalSuspected);
603 }
604
605 // static
ErrorIsValid(const std::string & error)606 bool NetworkState::ErrorIsValid(const std::string& error) {
607 return !error.empty() && error != shill::kErrorNoFailure;
608 }
609
610 // static
CreateDefaultCellular(const std::string & device_path)611 std::unique_ptr<NetworkState> NetworkState::CreateDefaultCellular(
612 const std::string& device_path) {
613 auto new_state = std::make_unique<NetworkState>(kDefaultCellularNetworkPath);
614 new_state->set_type(shill::kTypeCellular);
615 new_state->set_update_received();
616 new_state->set_visible(true);
617 new_state->device_path_ = device_path;
618 return new_state;
619 }
620
621 // Private methods.
622
UpdateName(const base::Value & properties)623 bool NetworkState::UpdateName(const base::Value& properties) {
624 std::string updated_name =
625 shill_property_util::GetNameFromProperties(path(), properties);
626 if (updated_name != name()) {
627 set_name(updated_name);
628 return true;
629 }
630 return false;
631 }
632
UpdateCaptivePortalState(const base::Value & properties)633 void NetworkState::UpdateCaptivePortalState(const base::Value& properties) {
634 int status_code =
635 properties.FindIntKey(kPortalDetectionFailedStatusCodeProperty)
636 .value_or(0);
637 if (connection_state_ == shill::kStateNoConnectivity) {
638 portal_state_ = PortalState::kNoInternet;
639 } else if (connection_state_ == shill::kStatePortal ||
640 connection_state_ == shill::kStateRedirectFound) {
641 portal_state_ = status_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED
642 ? PortalState::kProxyAuthRequired
643 : PortalState::kPortal;
644 } else if (connection_state_ == shill::kStatePortalSuspected) {
645 portal_state_ = PortalState::kPortalSuspected;
646 } else {
647 portal_state_ = PortalState::kOnline;
648 }
649
650 UMA_HISTOGRAM_ENUMERATION("CaptivePortal.NetworkStateResult", portal_state_);
651 if (portal_state_ != PortalState::kOnline) {
652 portal_status_code_ = status_code;
653 NET_LOG(EVENT) << "Network is in captive portal state: " << NetworkId(this)
654 << " status_code=" << portal_status_code_;
655 base::UmaHistogramSparse("CaptivePortal.NetworkStateStatusCode",
656 std::abs(portal_status_code_));
657 } else {
658 portal_status_code_ = 0;
659 }
660 }
661
SetVpnProvider(const std::string & id,const std::string & type)662 void NetworkState::SetVpnProvider(const std::string& id,
663 const std::string& type) {
664 // |type| is required but |id| is only set for ThirdParty and Arc VPNs.
665 if (type.empty()) {
666 vpn_provider_ = nullptr;
667 return;
668 }
669 if (!vpn_provider_)
670 vpn_provider_ = std::make_unique<VpnProviderInfo>();
671 vpn_provider_->id = id;
672 vpn_provider_->type = type;
673 }
674
675 } // namespace chromeos
676