Home | History | Annotate | Download | only in network
      1 // Copyright (c) 2013 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_connection_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/json/json_reader.h"
      9 #include "base/location.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "chromeos/cert_loader.h"
     13 #include "chromeos/dbus/dbus_thread_manager.h"
     14 #include "chromeos/dbus/shill_manager_client.h"
     15 #include "chromeos/dbus/shill_service_client.h"
     16 #include "chromeos/network/certificate_pattern.h"
     17 #include "chromeos/network/client_cert_resolver.h"
     18 #include "chromeos/network/client_cert_util.h"
     19 #include "chromeos/network/managed_network_configuration_handler.h"
     20 #include "chromeos/network/network_configuration_handler.h"
     21 #include "chromeos/network/network_event_log.h"
     22 #include "chromeos/network/network_handler_callbacks.h"
     23 #include "chromeos/network/network_profile_handler.h"
     24 #include "chromeos/network/network_state.h"
     25 #include "chromeos/network/network_state_handler.h"
     26 #include "chromeos/network/shill_property_util.h"
     27 #include "dbus/object_path.h"
     28 #include "net/cert/x509_certificate.h"
     29 #include "third_party/cros_system_api/dbus/service_constants.h"
     30 
     31 namespace chromeos {
     32 
     33 namespace {
     34 
     35 void InvokeErrorCallback(const std::string& service_path,
     36                          const network_handler::ErrorCallback& error_callback,
     37                          const std::string& error_name) {
     38   NET_LOG_ERROR("Connect Error: " + error_name, service_path);
     39   network_handler::RunErrorCallback(
     40       error_callback, service_path, error_name, "");
     41 }
     42 
     43 bool IsAuthenticationError(const std::string& error) {
     44   return (error == shill::kErrorBadWEPKey ||
     45           error == shill::kErrorPppAuthFailed ||
     46           error == shill::kErrorEapLocalTlsFailed ||
     47           error == shill::kErrorEapRemoteTlsFailed ||
     48           error == shill::kErrorEapAuthenticationFailed);
     49 }
     50 
     51 bool VPNRequiresCredentials(const std::string& service_path,
     52                            const std::string& provider_type,
     53                            const base::DictionaryValue& provider_properties) {
     54   if (provider_type == shill::kProviderOpenVpn) {
     55     std::string username;
     56     provider_properties.GetStringWithoutPathExpansion(
     57         shill::kOpenVPNUserProperty, &username);
     58     if (username.empty()) {
     59       NET_LOG_EVENT("OpenVPN: No username", service_path);
     60       return true;
     61     }
     62     bool passphrase_required = false;
     63     provider_properties.GetBooleanWithoutPathExpansion(
     64         shill::kPassphraseRequiredProperty, &passphrase_required);
     65     if (passphrase_required) {
     66       NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
     67       return true;
     68     }
     69     NET_LOG_EVENT("OpenVPN Is Configured", service_path);
     70   } else {
     71     bool passphrase_required = false;
     72     provider_properties.GetBooleanWithoutPathExpansion(
     73         shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
     74     if (passphrase_required) {
     75       NET_LOG_EVENT("VPN: PSK Required", service_path);
     76       return true;
     77     }
     78     provider_properties.GetBooleanWithoutPathExpansion(
     79         shill::kPassphraseRequiredProperty, &passphrase_required);
     80     if (passphrase_required) {
     81       NET_LOG_EVENT("VPN: Passphrase Required", service_path);
     82       return true;
     83     }
     84     NET_LOG_EVENT("VPN Is Configured", service_path);
     85   }
     86   return false;
     87 }
     88 
     89 std::string GetDefaultUserProfilePath(const NetworkState* network) {
     90   if (!NetworkHandler::IsInitialized() ||
     91       (LoginState::IsInitialized() &&
     92        !LoginState::Get()->UserHasNetworkProfile()) ||
     93       (network && network->type() == shill::kTypeWifi &&
     94        network->security() == shill::kSecurityNone)) {
     95     return NetworkProfileHandler::GetSharedProfilePath();
     96   }
     97   const NetworkProfile* profile  =
     98       NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
     99   return profile ? profile->path
    100                  : NetworkProfileHandler::GetSharedProfilePath();
    101 }
    102 
    103 }  // namespace
    104 
    105 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
    106 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
    107 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
    108 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
    109 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
    110     "passphrase-required";
    111 const char NetworkConnectionHandler::kErrorActivationRequired[] =
    112     "activation-required";
    113 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
    114     "certificate-required";
    115 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
    116     "configuration-required";
    117 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
    118     "authentication-required";
    119 const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
    120 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
    121     "configure-failed";
    122 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
    123     "connect-canceled";
    124 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
    125     "cert-load-timeout";
    126 
    127 struct NetworkConnectionHandler::ConnectRequest {
    128   ConnectRequest(const std::string& service_path,
    129                  const std::string& profile_path,
    130                  const base::Closure& success,
    131                  const network_handler::ErrorCallback& error)
    132       : service_path(service_path),
    133         profile_path(profile_path),
    134         connect_state(CONNECT_REQUESTED),
    135         success_callback(success),
    136         error_callback(error) {
    137   }
    138   enum ConnectState {
    139     CONNECT_REQUESTED = 0,
    140     CONNECT_STARTED = 1,
    141     CONNECT_CONNECTING = 2
    142   };
    143   std::string service_path;
    144   std::string profile_path;
    145   ConnectState connect_state;
    146   base::Closure success_callback;
    147   network_handler::ErrorCallback error_callback;
    148 };
    149 
    150 NetworkConnectionHandler::NetworkConnectionHandler()
    151     : cert_loader_(NULL),
    152       network_state_handler_(NULL),
    153       configuration_handler_(NULL),
    154       logged_in_(false),
    155       certificates_loaded_(false),
    156       applied_autoconnect_policy_(false),
    157       requested_connect_to_best_network_(false) {
    158 }
    159 
    160 NetworkConnectionHandler::~NetworkConnectionHandler() {
    161   if (network_state_handler_)
    162     network_state_handler_->RemoveObserver(this, FROM_HERE);
    163   if (cert_loader_)
    164     cert_loader_->RemoveObserver(this);
    165   if (LoginState::IsInitialized())
    166     LoginState::Get()->RemoveObserver(this);
    167 }
    168 
    169 void NetworkConnectionHandler::Init(
    170     NetworkStateHandler* network_state_handler,
    171     NetworkConfigurationHandler* network_configuration_handler,
    172     ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
    173   if (LoginState::IsInitialized())
    174     LoginState::Get()->AddObserver(this);
    175 
    176   if (CertLoader::IsInitialized()) {
    177     cert_loader_ = CertLoader::Get();
    178     cert_loader_->AddObserver(this);
    179     if (cert_loader_->certificates_loaded()) {
    180       NET_LOG_EVENT("Certificates Loaded", "");
    181       certificates_loaded_ = true;
    182     }
    183   } else {
    184     // TODO(tbarzic): Require a mock or stub cert_loader in tests.
    185     NET_LOG_EVENT("Certificate Loader not initialized", "");
    186     certificates_loaded_ = true;
    187   }
    188 
    189   if (network_state_handler) {
    190     network_state_handler_ = network_state_handler;
    191     network_state_handler_->AddObserver(this, FROM_HERE);
    192   }
    193   configuration_handler_ = network_configuration_handler;
    194 
    195   if (managed_network_configuration_handler) {
    196     managed_configuration_handler_ = managed_network_configuration_handler;
    197     managed_configuration_handler_->AddObserver(this);
    198   }
    199 
    200   // After this point, the NetworkConnectionHandler is fully initialized (all
    201   // handler references set, observers registered, ...).
    202 
    203   if (LoginState::IsInitialized())
    204     LoggedInStateChanged();
    205 }
    206 
    207 void NetworkConnectionHandler::LoggedInStateChanged() {
    208   LoginState* login_state = LoginState::Get();
    209   if (logged_in_ || !login_state->IsUserLoggedIn())
    210     return;
    211 
    212   NET_LOG_EVENT("Logged In", "");
    213   logged_in_ = true;
    214   logged_in_time_ = base::TimeTicks::Now();
    215 
    216   DisconnectIfPolicyRequires();
    217 }
    218 
    219 void NetworkConnectionHandler::OnCertificatesLoaded(
    220     const net::CertificateList& cert_list,
    221     bool initial_load) {
    222   certificates_loaded_ = true;
    223   NET_LOG_EVENT("Certificates Loaded", "");
    224   if (queued_connect_) {
    225     ConnectToQueuedNetwork();
    226   } else if (initial_load) {
    227     // Connecting to the "best" available network requires certificates to be
    228     // loaded. Try to connect now.
    229     ConnectToBestNetworkAfterLogin();
    230   }
    231 }
    232 
    233 void NetworkConnectionHandler::PolicyChanged(const std::string& userhash) {
    234   // Ignore user policies.
    235   if (!userhash.empty())
    236     return;
    237   DisconnectIfPolicyRequires();
    238 }
    239 
    240 void NetworkConnectionHandler::ConnectToNetwork(
    241     const std::string& service_path,
    242     const base::Closure& success_callback,
    243     const network_handler::ErrorCallback& error_callback,
    244     bool check_error_state) {
    245   NET_LOG_USER("ConnectToNetwork", service_path);
    246   // Clear any existing queued connect request.
    247   queued_connect_.reset();
    248   if (HasConnectingNetwork(service_path)) {
    249     NET_LOG_USER("Connect Request While Pending", service_path);
    250     InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    251     return;
    252   }
    253 
    254   // Check cached network state for connected, connecting, or unactivated
    255   // networks. These states will not be affected by a recent configuration.
    256   // Note: NetworkState may not exist for a network that was recently
    257   // configured, in which case these checks do not apply anyway.
    258   const NetworkState* network =
    259       network_state_handler_->GetNetworkState(service_path);
    260 
    261   if (network) {
    262     // For existing networks, perform some immediate consistency checks.
    263     if (network->IsConnectedState()) {
    264       InvokeErrorCallback(service_path, error_callback, kErrorConnected);
    265       return;
    266     }
    267     if (network->IsConnectingState()) {
    268       InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    269       return;
    270     }
    271 
    272     if (check_error_state) {
    273       const std::string& error = network->last_error();
    274       if (error == shill::kErrorBadPassphrase) {
    275         InvokeErrorCallback(service_path, error_callback, error);
    276         return;
    277       }
    278       if (IsAuthenticationError(error)) {
    279         InvokeErrorCallback(
    280             service_path, error_callback, kErrorAuthenticationRequired);
    281         return;
    282       }
    283     }
    284   }
    285 
    286   // If the network does not have a profile path, specify the correct default
    287   // profile here and set it once connected. Otherwise leave it empty to
    288   // indicate that it does not need to be set.
    289   std::string profile_path;
    290   if (!network || network->profile_path().empty())
    291     profile_path = GetDefaultUserProfilePath(network);
    292 
    293   // All synchronous checks passed, add |service_path| to connecting list.
    294   pending_requests_.insert(std::make_pair(
    295       service_path,
    296       ConnectRequest(service_path, profile_path,
    297                      success_callback, error_callback)));
    298 
    299   // Connect immediately to 'connectable' networks.
    300   // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    301   if (network && network->connectable() && network->type() != shill::kTypeVPN) {
    302     CallShillConnect(service_path);
    303     return;
    304   }
    305 
    306   // Request additional properties to check. VerifyConfiguredAndConnect will
    307   // use only these properties, not cached properties, to ensure that they
    308   // are up to date after any recent configuration.
    309   configuration_handler_->GetProperties(
    310       service_path,
    311       base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
    312                  AsWeakPtr(), check_error_state),
    313       base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    314                  AsWeakPtr(), service_path));
    315 }
    316 
    317 void NetworkConnectionHandler::DisconnectNetwork(
    318     const std::string& service_path,
    319     const base::Closure& success_callback,
    320     const network_handler::ErrorCallback& error_callback) {
    321   NET_LOG_USER("DisconnectNetwork", service_path);
    322   const NetworkState* network =
    323       network_state_handler_->GetNetworkState(service_path);
    324   if (!network) {
    325     InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
    326     return;
    327   }
    328   if (!network->IsConnectedState()) {
    329     InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
    330     return;
    331   }
    332   CallShillDisconnect(service_path, success_callback, error_callback);
    333 }
    334 
    335 bool NetworkConnectionHandler::HasConnectingNetwork(
    336     const std::string& service_path) {
    337   return pending_requests_.count(service_path) != 0;
    338 }
    339 
    340 bool NetworkConnectionHandler::HasPendingConnectRequest() {
    341   return pending_requests_.size() > 0;
    342 }
    343 
    344 void NetworkConnectionHandler::NetworkListChanged() {
    345   CheckAllPendingRequests();
    346 }
    347 
    348 void NetworkConnectionHandler::NetworkPropertiesUpdated(
    349     const NetworkState* network) {
    350   if (HasConnectingNetwork(network->path()))
    351     CheckPendingRequest(network->path());
    352 }
    353 
    354 NetworkConnectionHandler::ConnectRequest*
    355 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
    356   std::map<std::string, ConnectRequest>::iterator iter =
    357       pending_requests_.find(service_path);
    358   return iter != pending_requests_.end() ? &(iter->second) : NULL;
    359 }
    360 
    361 // ConnectToNetwork implementation
    362 
    363 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
    364     bool check_error_state,
    365     const std::string& service_path,
    366     const base::DictionaryValue& service_properties) {
    367   NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
    368 
    369   // If 'passphrase_required' is still true, then the 'Passphrase' property
    370   // has not been set to a minimum length value.
    371   bool passphrase_required = false;
    372   service_properties.GetBooleanWithoutPathExpansion(
    373       shill::kPassphraseRequiredProperty, &passphrase_required);
    374   if (passphrase_required) {
    375     ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
    376     return;
    377   }
    378 
    379   std::string type, security;
    380   service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
    381   service_properties.GetStringWithoutPathExpansion(
    382       shill::kSecurityProperty, &security);
    383   bool connectable = false;
    384   service_properties.GetBooleanWithoutPathExpansion(
    385       shill::kConnectableProperty, &connectable);
    386 
    387   // In case NetworkState was not available in ConnectToNetwork (e.g. it had
    388   // been recently configured), we need to check Connectable again.
    389   if (connectable && type != shill::kTypeVPN) {
    390     // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    391     CallShillConnect(service_path);
    392     return;
    393   }
    394 
    395   // Get VPN provider type and host (required for configuration) and ensure
    396   // that required VPN non-cert properties are set.
    397   const base::DictionaryValue* provider_properties = NULL;
    398   std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
    399   if (type == shill::kTypeVPN) {
    400     // VPN Provider values are read from the "Provider" dictionary, not the
    401     // "Provider.Type", etc keys (which are used only to set the values).
    402     if (service_properties.GetDictionaryWithoutPathExpansion(
    403             shill::kProviderProperty, &provider_properties)) {
    404       provider_properties->GetStringWithoutPathExpansion(
    405           shill::kTypeProperty, &vpn_provider_type);
    406       provider_properties->GetStringWithoutPathExpansion(
    407           shill::kHostProperty, &vpn_provider_host);
    408       provider_properties->GetStringWithoutPathExpansion(
    409           shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
    410     }
    411     if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
    412       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    413       return;
    414     }
    415   }
    416 
    417   std::string guid;
    418   service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
    419   std::string profile;
    420   service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
    421                                                    &profile);
    422   const base::DictionaryValue* user_policy =
    423       managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
    424 
    425   client_cert::ClientCertConfig cert_config_from_policy;
    426   if (user_policy)
    427     client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
    428 
    429   client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
    430   if (type == shill::kTypeVPN) {
    431     if (vpn_provider_type == shill::kProviderOpenVpn) {
    432       client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
    433     } else {
    434       // L2TP/IPSec only requires a certificate if one is specified in ONC
    435       // or one was configured by the UI. Otherwise it is L2TP/IPSec with
    436       // PSK and doesn't require a certificate.
    437       //
    438       // TODO(benchan): Modify shill to specify the authentication type via
    439       // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
    440       // to deduce the authentication type based on the
    441       // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
    442       if (!vpn_client_cert_id.empty() ||
    443           cert_config_from_policy.client_cert_type !=
    444               onc::client_cert::kClientCertTypeNone) {
    445         client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
    446       }
    447     }
    448   } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
    449     client_cert_type = client_cert::CONFIG_TYPE_EAP;
    450   }
    451 
    452   base::DictionaryValue config_properties;
    453   if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
    454     // Note: if we get here then a certificate *may* be required, so we want
    455     // to ensure that certificates have loaded successfully before attempting
    456     // to connect.
    457 
    458     // User must be logged in to connect to a network requiring a certificate.
    459     if (!logged_in_ || !cert_loader_) {
    460       NET_LOG_ERROR("User not logged in", "");
    461       ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    462       return;
    463     }
    464     // If certificates have not been loaded yet, queue the connect request.
    465     if (!certificates_loaded_) {
    466       NET_LOG_EVENT("Certificates not loaded", "");
    467       QueueConnectRequest(service_path);
    468       return;
    469     }
    470 
    471     // Check certificate properties from policy.
    472     if (cert_config_from_policy.client_cert_type ==
    473         onc::client_cert::kPattern) {
    474       if (!ClientCertResolver::ResolveCertificatePatternSync(
    475               client_cert_type,
    476               cert_config_from_policy.pattern,
    477               &config_properties)) {
    478         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    479         return;
    480       }
    481     } else if (check_error_state &&
    482                !client_cert::IsCertificateConfigured(client_cert_type,
    483                                                      service_properties)) {
    484       // Network may not be configured.
    485       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    486       return;
    487     }
    488   }
    489 
    490   if (type == shill::kTypeVPN) {
    491     // VPN may require a username, and/or passphrase to be set. (Check after
    492     // ensuring that any required certificates are configured).
    493     DCHECK(provider_properties);
    494     if (VPNRequiresCredentials(
    495             service_path, vpn_provider_type, *provider_properties)) {
    496       NET_LOG_USER("VPN Requires Credentials", service_path);
    497       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    498       return;
    499     }
    500 
    501     // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
    502     // to connect.
    503     if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
    504       CallShillConnect(service_path);
    505       return;
    506     }
    507   }
    508 
    509   if (!config_properties.empty()) {
    510     NET_LOG_EVENT("Configuring Network", service_path);
    511     configuration_handler_->SetProperties(
    512         service_path,
    513         config_properties,
    514         base::Bind(&NetworkConnectionHandler::CallShillConnect,
    515                    AsWeakPtr(),
    516                    service_path),
    517         base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    518                    AsWeakPtr(),
    519                    service_path));
    520     return;
    521   }
    522 
    523   // Otherwise, we probably still need to configure the network since
    524   // 'Connectable' is false. If |check_error_state| is true, signal an
    525   // error, otherwise attempt to connect to possibly gain additional error
    526   // state from Shill (or in case 'Connectable' is improperly unset).
    527   if (check_error_state)
    528     ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    529   else
    530     CallShillConnect(service_path);
    531 }
    532 
    533 void NetworkConnectionHandler::QueueConnectRequest(
    534     const std::string& service_path) {
    535   ConnectRequest* request = GetPendingRequest(service_path);
    536   if (!request) {
    537     NET_LOG_ERROR("No pending request to queue", service_path);
    538     return;
    539   }
    540 
    541   const int kMaxCertLoadTimeSeconds = 15;
    542   base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
    543   if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
    544     NET_LOG_ERROR("Certificate load timeout", service_path);
    545     InvokeErrorCallback(service_path,
    546                         request->error_callback,
    547                         kErrorCertLoadTimeout);
    548     return;
    549   }
    550 
    551   NET_LOG_EVENT("Connect Request Queued", service_path);
    552   queued_connect_.reset(new ConnectRequest(
    553       service_path, request->profile_path,
    554       request->success_callback, request->error_callback));
    555   pending_requests_.erase(service_path);
    556 
    557   // Post a delayed task to check to see if certificates have loaded. If they
    558   // haven't, and queued_connect_ has not been cleared (e.g. by a successful
    559   // connect request), cancel the request and notify the user.
    560   base::MessageLoopProxy::current()->PostDelayedTask(
    561       FROM_HERE,
    562       base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
    563                  AsWeakPtr()),
    564       base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
    565 }
    566 
    567 void NetworkConnectionHandler::CheckCertificatesLoaded() {
    568   if (certificates_loaded_)
    569     return;
    570   // If queued_connect_ has been cleared (e.g. another connect request occurred
    571   // and wasn't queued), do nothing here.
    572   if (!queued_connect_)
    573     return;
    574   // Otherwise, notify the user.
    575   NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
    576   InvokeErrorCallback(queued_connect_->service_path,
    577                       queued_connect_->error_callback,
    578                       kErrorCertLoadTimeout);
    579   queued_connect_.reset();
    580 }
    581 
    582 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
    583   DCHECK(queued_connect_);
    584 
    585   // Make a copy of |queued_connect_| parameters, because |queued_connect_|
    586   // will get reset at the beginning of |ConnectToNetwork|.
    587   std::string service_path = queued_connect_->service_path;
    588   base::Closure success_callback = queued_connect_->success_callback;
    589   network_handler::ErrorCallback error_callback =
    590       queued_connect_->error_callback;
    591 
    592   NET_LOG_EVENT("Connecting to Queued Network", service_path);
    593   ConnectToNetwork(service_path, success_callback, error_callback,
    594                    false /* check_error_state */);
    595 }
    596 
    597 void NetworkConnectionHandler::CallShillConnect(
    598     const std::string& service_path) {
    599   NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
    600   network_state_handler_->ClearLastErrorForNetwork(service_path);
    601   DBusThreadManager::Get()->GetShillServiceClient()->Connect(
    602       dbus::ObjectPath(service_path),
    603       base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
    604                  AsWeakPtr(), service_path),
    605       base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
    606                  AsWeakPtr(), service_path));
    607 }
    608 
    609 void NetworkConnectionHandler::HandleConfigurationFailure(
    610     const std::string& service_path,
    611     const std::string& error_name,
    612     scoped_ptr<base::DictionaryValue> error_data) {
    613   ConnectRequest* request = GetPendingRequest(service_path);
    614   if (!request) {
    615     NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
    616                   service_path);
    617     return;
    618   }
    619   network_handler::ErrorCallback error_callback = request->error_callback;
    620   pending_requests_.erase(service_path);
    621   if (!error_callback.is_null())
    622     error_callback.Run(kErrorConfigureFailed, error_data.Pass());
    623 }
    624 
    625 void NetworkConnectionHandler::HandleShillConnectSuccess(
    626     const std::string& service_path) {
    627   ConnectRequest* request = GetPendingRequest(service_path);
    628   if (!request) {
    629     NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
    630                   service_path);
    631     return;
    632   }
    633   request->connect_state = ConnectRequest::CONNECT_STARTED;
    634   NET_LOG_EVENT("Connect Request Acknowledged", service_path);
    635   // Do not call success_callback here, wait for one of the following
    636   // conditions:
    637   // * State transitions to a non connecting state indicating success or failure
    638   // * Network is no longer in the visible list, indicating failure
    639   CheckPendingRequest(service_path);
    640 }
    641 
    642 void NetworkConnectionHandler::HandleShillConnectFailure(
    643     const std::string& service_path,
    644     const std::string& dbus_error_name,
    645     const std::string& dbus_error_message) {
    646   ConnectRequest* request = GetPendingRequest(service_path);
    647   if (!request) {
    648     NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
    649                   service_path);
    650     return;
    651   }
    652   network_handler::ErrorCallback error_callback = request->error_callback;
    653   pending_requests_.erase(service_path);
    654   network_handler::ShillErrorCallbackFunction(
    655       shill::kErrorConnectFailed, service_path, error_callback,
    656       dbus_error_name, dbus_error_message);
    657 }
    658 
    659 void NetworkConnectionHandler::CheckPendingRequest(
    660     const std::string service_path) {
    661   ConnectRequest* request = GetPendingRequest(service_path);
    662   DCHECK(request);
    663   if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
    664     return;  // Request has not started, ignore update
    665   const NetworkState* network =
    666       network_state_handler_->GetNetworkState(service_path);
    667   if (!network)
    668     return;  // NetworkState may not be be updated yet.
    669 
    670   if (network->IsConnectingState()) {
    671     request->connect_state = ConnectRequest::CONNECT_CONNECTING;
    672     return;
    673   }
    674   if (network->IsConnectedState()) {
    675     NET_LOG_EVENT("Connect Request Succeeded", service_path);
    676     if (!request->profile_path.empty()) {
    677       // If a profile path was specified, set it on a successful connection.
    678       configuration_handler_->SetNetworkProfile(
    679           service_path,
    680           request->profile_path,
    681           base::Bind(&base::DoNothing),
    682           chromeos::network_handler::ErrorCallback());
    683     }
    684     if (!request->success_callback.is_null())
    685       request->success_callback.Run();
    686     pending_requests_.erase(service_path);
    687     return;
    688   }
    689   if (network->connection_state() == shill::kStateIdle &&
    690       request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
    691     // Connection hasn't started yet, keep waiting.
    692     return;
    693   }
    694 
    695   // Network is neither connecting or connected; an error occurred.
    696   std::string error_name;  // 'Canceled' or 'Failed'
    697   if (network->connection_state() == shill::kStateIdle &&
    698       pending_requests_.size() > 1) {
    699     // Another connect request canceled this one.
    700     error_name = kErrorConnectCanceled;
    701   } else {
    702     error_name = shill::kErrorConnectFailed;
    703     if (network->connection_state() != shill::kStateFailure) {
    704       NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
    705                     service_path);
    706     }
    707   }
    708 
    709   network_handler::ErrorCallback error_callback = request->error_callback;
    710   pending_requests_.erase(service_path);
    711   if (error_callback.is_null()) {
    712     NET_LOG_ERROR("Connect Error, no callback: " + error_name, service_path);
    713     return;
    714   }
    715   InvokeErrorCallback(service_path, error_callback, error_name);
    716 }
    717 
    718 void NetworkConnectionHandler::CheckAllPendingRequests() {
    719   for (std::map<std::string, ConnectRequest>::iterator iter =
    720            pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
    721     CheckPendingRequest(iter->first);
    722   }
    723 }
    724 
    725 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
    726     const std::string& service_path,
    727     const std::string& error_name) {
    728   ConnectRequest* request = GetPendingRequest(service_path);
    729   if (!request) {
    730     NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
    731                   service_path);
    732     return;
    733   }
    734   // Remove the entry before invoking the callback in case it triggers a retry.
    735   network_handler::ErrorCallback error_callback = request->error_callback;
    736   pending_requests_.erase(service_path);
    737   InvokeErrorCallback(service_path, error_callback, error_name);
    738 }
    739 
    740 // Disconnect
    741 
    742 void NetworkConnectionHandler::CallShillDisconnect(
    743     const std::string& service_path,
    744     const base::Closure& success_callback,
    745     const network_handler::ErrorCallback& error_callback) {
    746   NET_LOG_USER("Disconnect Request", service_path);
    747   DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
    748       dbus::ObjectPath(service_path),
    749       base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
    750                  AsWeakPtr(), service_path, success_callback),
    751       base::Bind(&network_handler::ShillErrorCallbackFunction,
    752                  kErrorShillError, service_path, error_callback));
    753 }
    754 
    755 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
    756     const std::string& service_path,
    757     const base::Closure& success_callback) {
    758   NET_LOG_EVENT("Disconnect Request Sent", service_path);
    759   if (!success_callback.is_null())
    760     success_callback.Run();
    761 }
    762 
    763 void NetworkConnectionHandler::ConnectToBestNetworkAfterLogin() {
    764   if (requested_connect_to_best_network_ || !applied_autoconnect_policy_ ||
    765       !certificates_loaded_) {
    766     return;
    767   }
    768 
    769   requested_connect_to_best_network_ = true;
    770   network_state_handler_->ConnectToBestWifiNetwork();
    771 }
    772 
    773 void NetworkConnectionHandler::DisconnectIfPolicyRequires() {
    774   if (applied_autoconnect_policy_ || !LoginState::Get()->IsUserLoggedIn())
    775     return;
    776 
    777   const base::DictionaryValue* global_network_config =
    778       managed_configuration_handler_->GetGlobalConfigFromPolicy(std::string());
    779   if (!global_network_config)
    780     return;
    781 
    782   applied_autoconnect_policy_ = true;
    783 
    784   bool only_policy_autoconnect = false;
    785   global_network_config->GetBooleanWithoutPathExpansion(
    786       ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
    787       &only_policy_autoconnect);
    788 
    789   if (!only_policy_autoconnect)
    790     return;
    791 
    792   NET_LOG_DEBUG("DisconnectIfPolicyRequires",
    793                 "Disconnecting unmanaged and shared networks if any exist.");
    794 
    795   // Get the list of unmanaged & shared networks that are connected or
    796   // connecting.
    797   NetworkStateHandler::NetworkStateList networks;
    798   network_state_handler_->GetVisibleNetworkListByType(
    799       NetworkTypePattern::Wireless(), &networks);
    800   for (NetworkStateHandler::NetworkStateList::const_iterator it =
    801            networks.begin();
    802        it != networks.end();
    803        ++it) {
    804     const NetworkState* network = *it;
    805     if (!(network->IsConnectingState() || network->IsConnectedState()))
    806       break;  // Connected and connecting networks are listed first.
    807 
    808     if (network->IsPrivate())
    809       continue;
    810 
    811     const bool network_is_policy_managed =
    812         !network->profile_path().empty() && !network->guid().empty() &&
    813         managed_configuration_handler_->FindPolicyByGuidAndProfile(
    814             network->guid(), network->profile_path());
    815     if (network_is_policy_managed)
    816       continue;
    817 
    818     NET_LOG_EVENT("Disconnect Forced by Policy", network->path());
    819     CallShillDisconnect(
    820         network->path(), base::Closure(), network_handler::ErrorCallback());
    821   }
    822 
    823   ConnectToBestNetworkAfterLogin();
    824 }
    825 
    826 }  // namespace chromeos
    827