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 activate_over_non_cellular_networks_(false), 69 cellular_out_of_credits_(false), 70 has_ca_cert_nss_(false) { 71 } 72 73 NetworkState::~NetworkState() { 74 } 75 76 bool NetworkState::PropertyChanged(const std::string& key, 77 const base::Value& value) { 78 // Keep care that these properties are the same as in |GetProperties|. 79 if (ManagedStatePropertyChanged(key, value)) 80 return true; 81 if (key == shill::kSignalStrengthProperty) { 82 return GetIntegerValue(key, value, &signal_strength_); 83 } else if (key == shill::kStateProperty) { 84 return GetStringValue(key, value, &connection_state_); 85 } else if (key == shill::kVisibleProperty) { 86 return GetBooleanValue(key, value, &visible_); 87 } else if (key == shill::kConnectableProperty) { 88 return GetBooleanValue(key, value, &connectable_); 89 } else if (key == shill::kErrorProperty) { 90 if (!GetStringValue(key, value, &error_)) 91 return false; 92 if (ErrorIsValid(error_)) 93 last_error_ = error_; 94 else 95 error_.clear(); 96 return true; 97 } else if (key == shill::kActivationStateProperty) { 98 return GetStringValue(key, value, &activation_state_); 99 } else if (key == shill::kRoamingStateProperty) { 100 return GetStringValue(key, value, &roaming_); 101 } else if (key == shill::kSecurityProperty) { 102 return GetStringValue(key, value, &security_); 103 } else if (key == shill::kEapMethodProperty) { 104 return GetStringValue(key, value, &eap_method_); 105 } else if (key == shill::kUIDataProperty) { 106 scoped_ptr<NetworkUIData> new_ui_data = 107 shill_property_util::GetUIDataFromValue(value); 108 if (!new_ui_data) { 109 NET_LOG_ERROR("Failed to parse " + key, path()); 110 return false; 111 } 112 ui_data_ = *new_ui_data; 113 return true; 114 } else if (key == shill::kNetworkTechnologyProperty) { 115 return GetStringValue(key, value, &network_technology_); 116 } else if (key == shill::kDeviceProperty) { 117 return GetStringValue(key, value, &device_path_); 118 } else if (key == shill::kGuidProperty) { 119 return GetStringValue(key, value, &guid_); 120 } else if (key == shill::kProfileProperty) { 121 return GetStringValue(key, value, &profile_path_); 122 } else if (key == shill::kActivateOverNonCellularNetworkProperty) { 123 return GetBooleanValue(key, value, &activate_over_non_cellular_networks_); 124 } else if (key == shill::kOutOfCreditsProperty) { 125 return GetBooleanValue(key, value, &cellular_out_of_credits_); 126 } else if (key == shill::kProxyConfigProperty) { 127 std::string proxy_config_str; 128 if (!value.GetAsString(&proxy_config_str)) { 129 NET_LOG_ERROR("Failed to parse " + key, path()); 130 return false; 131 } 132 133 proxy_config_.Clear(); 134 if (proxy_config_str.empty()) 135 return true; 136 137 scoped_ptr<base::DictionaryValue> proxy_config_dict( 138 onc::ReadDictionaryFromJson(proxy_config_str)); 139 if (proxy_config_dict) { 140 // Warning: The DictionaryValue returned from 141 // ReadDictionaryFromJson/JSONParser is an optimized derived class that 142 // doesn't allow releasing ownership of nested values. A Swap in the wrong 143 // order leads to memory access errors. 144 proxy_config_.MergeDictionary(proxy_config_dict.get()); 145 } else { 146 NET_LOG_ERROR("Failed to parse " + key, path()); 147 } 148 return true; 149 } 150 return false; 151 } 152 153 bool NetworkState::InitialPropertiesReceived( 154 const base::DictionaryValue& properties) { 155 NET_LOG_DEBUG("InitialPropertiesReceived", path()); 156 bool changed = false; 157 if (!properties.HasKey(shill::kTypeProperty)) { 158 NET_LOG_ERROR("NetworkState has no type", 159 shill_property_util::GetNetworkIdFromProperties(properties)); 160 return false; 161 } 162 // Ensure that the network has a valid name. 163 changed |= UpdateName(properties); 164 165 // Set the has_ca_cert_nss_ property. 166 bool had_ca_cert_nss = has_ca_cert_nss_; 167 has_ca_cert_nss_ = IsCaCertNssSet(properties); 168 changed |= had_ca_cert_nss != has_ca_cert_nss_; 169 170 // By convention, all visible WiFi networks have a SignalStrength > 0. 171 if (visible() && type() == shill::kTypeWifi) { 172 if (signal_strength_ <= 0) 173 signal_strength_ = 1; 174 } 175 176 return changed; 177 } 178 179 void NetworkState::GetStateProperties(base::DictionaryValue* dictionary) const { 180 ManagedState::GetStateProperties(dictionary); 181 182 // Properties shared by all types. 183 dictionary->SetStringWithoutPathExpansion(shill::kGuidProperty, guid()); 184 dictionary->SetStringWithoutPathExpansion(shill::kSecurityProperty, 185 security()); 186 187 if (visible()) { 188 if (!error().empty()) 189 dictionary->SetStringWithoutPathExpansion(shill::kErrorProperty, error()); 190 dictionary->SetStringWithoutPathExpansion(shill::kStateProperty, 191 connection_state()); 192 } 193 194 // Wireless properties 195 if (!NetworkTypePattern::Wireless().MatchesType(type())) 196 return; 197 198 if (visible()) { 199 dictionary->SetBooleanWithoutPathExpansion(shill::kConnectableProperty, 200 connectable()); 201 dictionary->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty, 202 signal_strength()); 203 } 204 205 // Wifi properties 206 if (NetworkTypePattern::WiFi().MatchesType(type())) { 207 dictionary->SetStringWithoutPathExpansion(shill::kEapMethodProperty, 208 eap_method()); 209 } 210 211 // Mobile properties 212 if (NetworkTypePattern::Mobile().MatchesType(type())) { 213 dictionary->SetStringWithoutPathExpansion( 214 shill::kNetworkTechnologyProperty, 215 network_technology()); 216 dictionary->SetStringWithoutPathExpansion(shill::kActivationStateProperty, 217 activation_state()); 218 dictionary->SetStringWithoutPathExpansion(shill::kRoamingStateProperty, 219 roaming()); 220 dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty, 221 cellular_out_of_credits()); 222 } 223 } 224 225 void NetworkState::IPConfigPropertiesChanged( 226 const base::DictionaryValue& properties) { 227 for (base::DictionaryValue::Iterator iter(properties); 228 !iter.IsAtEnd(); iter.Advance()) { 229 std::string key = iter.key(); 230 const base::Value& value = iter.value(); 231 232 if (key == shill::kAddressProperty) { 233 GetStringValue(key, value, &ip_address_); 234 } else if (key == shill::kGatewayProperty) { 235 GetStringValue(key, value, &gateway_); 236 } else if (key == shill::kNameServersProperty) { 237 const base::ListValue* dns_servers; 238 if (value.GetAsList(&dns_servers)) { 239 dns_servers_.clear(); 240 ConvertListValueToStringVector(*dns_servers, &dns_servers_); 241 } 242 } else if (key == shill::kPrefixlenProperty) { 243 GetIntegerValue(key, value, &prefix_length_); 244 } else if (key == shill::kWebProxyAutoDiscoveryUrlProperty) { 245 std::string url_string; 246 if (GetStringValue(key, value, &url_string)) { 247 if (url_string.empty()) { 248 web_proxy_auto_discovery_url_ = GURL(); 249 } else { 250 GURL gurl(url_string); 251 if (gurl.is_valid()) { 252 web_proxy_auto_discovery_url_ = gurl; 253 } else { 254 NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string, 255 path()); 256 web_proxy_auto_discovery_url_ = GURL(); 257 } 258 } 259 } 260 } 261 } 262 } 263 264 bool NetworkState::RequiresActivation() const { 265 return (type() == shill::kTypeCellular && 266 activation_state() != shill::kActivationStateActivated && 267 activation_state() != shill::kActivationStateUnknown); 268 } 269 270 std::string NetworkState::connection_state() const { 271 if (!visible()) 272 return shill::kStateDisconnect; 273 return connection_state_; 274 } 275 276 bool NetworkState::IsConnectedState() const { 277 return visible() && StateIsConnected(connection_state_); 278 } 279 280 bool NetworkState::IsConnectingState() const { 281 return visible() && StateIsConnecting(connection_state_); 282 } 283 284 bool NetworkState::IsInProfile() const { 285 // kTypeEthernetEap is always saved. We need this check because it does 286 // not show up in the visible list, but its properties may not be available 287 // when it first shows up in ServiceCompleteList. See crbug.com/355117. 288 return !profile_path_.empty() || type() == shill::kTypeEthernetEap; 289 } 290 291 bool NetworkState::IsPrivate() const { 292 return !profile_path_.empty() && 293 profile_path_ != NetworkProfileHandler::GetSharedProfilePath(); 294 } 295 296 std::string NetworkState::GetDnsServersAsString() const { 297 std::string result; 298 for (size_t i = 0; i < dns_servers_.size(); ++i) { 299 if (i != 0) 300 result += ","; 301 result += dns_servers_[i]; 302 } 303 return result; 304 } 305 306 std::string NetworkState::GetNetmask() const { 307 return network_util::PrefixLengthToNetmask(prefix_length_); 308 } 309 310 std::string NetworkState::GetSpecifier() const { 311 if (!update_received()) { 312 NET_LOG_ERROR("GetSpecifier called before update", path()); 313 return std::string(); 314 } 315 if (type() == shill::kTypeWifi) 316 return name() + "_" + security_; 317 if (!name().empty()) 318 return name(); 319 return type(); // For unnamed networks such as ethernet. 320 } 321 322 void NetworkState::SetGuid(const std::string& guid) { 323 guid_ = guid; 324 } 325 326 bool NetworkState::UpdateName(const base::DictionaryValue& properties) { 327 std::string updated_name = 328 shill_property_util::GetNameFromProperties(path(), properties); 329 if (updated_name != name()) { 330 set_name(updated_name); 331 return true; 332 } 333 return false; 334 } 335 336 // static 337 bool NetworkState::StateIsConnected(const std::string& connection_state) { 338 return (connection_state == shill::kStateReady || 339 connection_state == shill::kStateOnline || 340 connection_state == shill::kStatePortal); 341 } 342 343 // static 344 bool NetworkState::StateIsConnecting(const std::string& connection_state) { 345 return (connection_state == shill::kStateAssociation || 346 connection_state == shill::kStateConfiguration || 347 connection_state == shill::kStateCarrier); 348 } 349 350 // static 351 bool NetworkState::ErrorIsValid(const std::string& error) { 352 // Shill uses "Unknown" to indicate an unset or cleared error state. 353 return !error.empty() && error != kErrorUnknown; 354 } 355 356 } // namespace chromeos 357