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 16 namespace { 17 18 const char kErrorUnknown[] = "Unknown"; 19 20 bool 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 31 bool 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 60 namespace chromeos { 61 62 NetworkState::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 72 NetworkState::~NetworkState() { 73 } 74 75 bool 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 149 bool 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 176 void 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 222 void 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 261 bool NetworkState::RequiresActivation() const { 262 return (type() == shill::kTypeCellular && 263 activation_state() != shill::kActivationStateActivated && 264 activation_state() != shill::kActivationStateUnknown); 265 } 266 267 std::string NetworkState::connection_state() const { 268 if (!visible()) 269 return shill::kStateDisconnect; 270 return connection_state_; 271 } 272 273 bool NetworkState::IsConnectedState() const { 274 return visible() && StateIsConnected(connection_state_); 275 } 276 277 bool NetworkState::IsConnectingState() const { 278 return visible() && StateIsConnecting(connection_state_); 279 } 280 281 bool 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 288 bool NetworkState::IsPrivate() const { 289 return !profile_path_.empty() && 290 profile_path_ != NetworkProfileHandler::GetSharedProfilePath(); 291 } 292 293 std::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 303 std::string NetworkState::GetNetmask() const { 304 return network_util::PrefixLengthToNetmask(prefix_length_); 305 } 306 307 std::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 319 void NetworkState::SetGuid(const std::string& guid) { 320 guid_ = guid; 321 } 322 323 bool 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 334 bool 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 341 bool 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 348 bool 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