Home | History | Annotate | Download | only in network
      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