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