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       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