// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chromeos/network/network_state.h" #include "base/strings/stringprintf.h" #include "base/values.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_profile_handler.h" #include "chromeos/network/network_util.h" #include "chromeos/network/shill_property_util.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace { const char kErrorUnknown[] = "Unknown"; bool ConvertListValueToStringVector(const base::ListValue& string_list, std::vector<std::string>* result) { for (size_t i = 0; i < string_list.GetSize(); ++i) { std::string str; if (!string_list.GetString(i, &str)) return false; result->push_back(str); } return true; } bool IsCaCertNssSet(const base::DictionaryValue& properties) { std::string ca_cert_nss; if (properties.GetStringWithoutPathExpansion(shill::kEapCaCertNssProperty, &ca_cert_nss) && !ca_cert_nss.empty()) { return true; } const base::DictionaryValue* provider = NULL; properties.GetDictionaryWithoutPathExpansion(shill::kProviderProperty, &provider); if (!provider) return false; if (provider->GetStringWithoutPathExpansion( shill::kL2tpIpsecCaCertNssProperty, &ca_cert_nss) && !ca_cert_nss.empty()) { return true; } if (provider->GetStringWithoutPathExpansion( shill::kOpenVPNCaCertNSSProperty, &ca_cert_nss) && !ca_cert_nss.empty()) { return true; } return false; } } // namespace namespace chromeos { NetworkState::NetworkState(const std::string& path) : ManagedState(MANAGED_TYPE_NETWORK, path), connectable_(false), prefix_length_(0), signal_strength_(0), activate_over_non_cellular_networks_(false), cellular_out_of_credits_(false), has_ca_cert_nss_(false) { } NetworkState::~NetworkState() { } bool NetworkState::PropertyChanged(const std::string& key, const base::Value& value) { // Keep care that these properties are the same as in |GetProperties|. if (ManagedStatePropertyChanged(key, value)) return true; if (key == shill::kSignalStrengthProperty) { return GetIntegerValue(key, value, &signal_strength_); } else if (key == shill::kStateProperty) { return GetStringValue(key, value, &connection_state_); } else if (key == shill::kConnectableProperty) { return GetBooleanValue(key, value, &connectable_); } else if (key == shill::kErrorProperty) { if (!GetStringValue(key, value, &error_)) return false; // Shill uses "Unknown" to indicate an unset error state. if (error_ == kErrorUnknown) error_.clear(); return true; } else if (key == IPConfigProperty(shill::kAddressProperty)) { return GetStringValue(key, value, &ip_address_); } else if (key == IPConfigProperty(shill::kGatewayProperty)) { return GetStringValue(key, value, &gateway_); } else if (key == IPConfigProperty(shill::kNameServersProperty)) { const base::ListValue* dns_servers; if (!value.GetAsList(&dns_servers)) return false; dns_servers_.clear(); ConvertListValueToStringVector(*dns_servers, &dns_servers_); return true; } else if (key == IPConfigProperty(shill::kPrefixlenProperty)) { return GetIntegerValue(key, value, &prefix_length_); } else if (key == IPConfigProperty( shill::kWebProxyAutoDiscoveryUrlProperty)) { std::string url_string; if (!GetStringValue(key, value, &url_string)) return false; if (url_string.empty()) { web_proxy_auto_discovery_url_ = GURL(); } else { GURL gurl(url_string); if (!gurl.is_valid()) { web_proxy_auto_discovery_url_ = gurl; } else { NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string, path()); web_proxy_auto_discovery_url_ = GURL(); } } return true; } else if (key == shill::kActivationStateProperty) { return GetStringValue(key, value, &activation_state_); } else if (key == shill::kRoamingStateProperty) { return GetStringValue(key, value, &roaming_); } else if (key == shill::kSecurityProperty) { return GetStringValue(key, value, &security_); } else if (key == shill::kEapMethodProperty) { return GetStringValue(key, value, &eap_method_); } else if (key == shill::kUIDataProperty) { scoped_ptr<NetworkUIData> new_ui_data = shill_property_util::GetUIDataFromValue(value); if (!new_ui_data) { NET_LOG_ERROR("Failed to parse " + key, path()); return false; } ui_data_ = *new_ui_data; return true; } else if (key == shill::kNetworkTechnologyProperty) { return GetStringValue(key, value, &network_technology_); } else if (key == shill::kDeviceProperty) { return GetStringValue(key, value, &device_path_); } else if (key == shill::kGuidProperty) { return GetStringValue(key, value, &guid_); } else if (key == shill::kProfileProperty) { return GetStringValue(key, value, &profile_path_); } else if (key == shill::kActivateOverNonCellularNetworkProperty) { return GetBooleanValue(key, value, &activate_over_non_cellular_networks_); } else if (key == shill::kOutOfCreditsProperty) { return GetBooleanValue(key, value, &cellular_out_of_credits_); } return false; } bool NetworkState::InitialPropertiesReceived( const base::DictionaryValue& properties) { NET_LOG_DEBUG("InitialPropertiesReceived", path()); bool changed = UpdateName(properties); bool had_ca_cert_nss = has_ca_cert_nss_; has_ca_cert_nss_ = IsCaCertNssSet(properties); changed |= had_ca_cert_nss != has_ca_cert_nss_; return changed; } void NetworkState::GetProperties(base::DictionaryValue* dictionary) const { // Keep care that these properties are the same as in |PropertyChanged|. dictionary->SetStringWithoutPathExpansion(shill::kNameProperty, name()); dictionary->SetStringWithoutPathExpansion(shill::kTypeProperty, type()); dictionary->SetIntegerWithoutPathExpansion(shill::kSignalStrengthProperty, signal_strength_); dictionary->SetStringWithoutPathExpansion(shill::kStateProperty, connection_state_); dictionary->SetBooleanWithoutPathExpansion(shill::kConnectableProperty, connectable_); dictionary->SetStringWithoutPathExpansion(shill::kErrorProperty, error_); // IPConfig properties base::DictionaryValue* ipconfig_properties = new base::DictionaryValue; ipconfig_properties->SetStringWithoutPathExpansion(shill::kAddressProperty, ip_address_); ipconfig_properties->SetStringWithoutPathExpansion(shill::kGatewayProperty, gateway_); base::ListValue* name_servers = new base::ListValue; name_servers->AppendStrings(dns_servers_); ipconfig_properties->SetWithoutPathExpansion(shill::kNameServersProperty, name_servers); ipconfig_properties->SetStringWithoutPathExpansion( shill::kWebProxyAutoDiscoveryUrlProperty, web_proxy_auto_discovery_url_.spec()); dictionary->SetWithoutPathExpansion(shill::kIPConfigProperty, ipconfig_properties); dictionary->SetStringWithoutPathExpansion(shill::kActivationStateProperty, activation_state_); dictionary->SetStringWithoutPathExpansion(shill::kRoamingStateProperty, roaming_); dictionary->SetStringWithoutPathExpansion(shill::kSecurityProperty, security_); dictionary->SetStringWithoutPathExpansion(shill::kEapMethodProperty, eap_method_); // Proxy config and ONC source are intentionally omitted: These properties are // placed in NetworkState to transition ProxyConfigServiceImpl from // NetworkLibrary to the new network stack. The networking extension API // shouldn't depend on this member. Once ManagedNetworkConfigurationHandler // is used instead of NetworkLibrary, we can remove them again. dictionary->SetStringWithoutPathExpansion( shill::kNetworkTechnologyProperty, network_technology_); dictionary->SetStringWithoutPathExpansion(shill::kDeviceProperty, device_path_); dictionary->SetStringWithoutPathExpansion(shill::kGuidProperty, guid_); dictionary->SetStringWithoutPathExpansion(shill::kProfileProperty, profile_path_); dictionary->SetBooleanWithoutPathExpansion( shill::kActivateOverNonCellularNetworkProperty, activate_over_non_cellular_networks_); dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty, cellular_out_of_credits_); } bool NetworkState::RequiresActivation() const { return (type() == shill::kTypeCellular && activation_state() != shill::kActivationStateActivated && activation_state() != shill::kActivationStateUnknown); } bool NetworkState::IsConnectedState() const { return StateIsConnected(connection_state_); } bool NetworkState::IsConnectingState() const { return StateIsConnecting(connection_state_); } bool NetworkState::IsPrivate() const { return !profile_path_.empty() && profile_path_ != NetworkProfileHandler::kSharedProfilePath; } std::string NetworkState::GetDnsServersAsString() const { std::string result; for (size_t i = 0; i < dns_servers_.size(); ++i) { if (i != 0) result += ","; result += dns_servers_[i]; } return result; } std::string NetworkState::GetNetmask() const { return network_util::PrefixLengthToNetmask(prefix_length_); } bool NetworkState::UpdateName(const base::DictionaryValue& properties) { std::string updated_name = shill_property_util::GetNameFromProperties(path(), properties); if (updated_name != name()) { set_name(updated_name); return true; } return false; } // static bool NetworkState::StateIsConnected(const std::string& connection_state) { return (connection_state == shill::kStateReady || connection_state == shill::kStateOnline || connection_state == shill::kStatePortal); } // static bool NetworkState::StateIsConnecting(const std::string& connection_state) { return (connection_state == shill::kStateAssociation || connection_state == shill::kStateConfiguration || connection_state == shill::kStateCarrier); } // static std::string NetworkState::IPConfigProperty(const char* key) { return base::StringPrintf("%s.%s", shill::kIPConfigProperty, key); } } // namespace chromeos