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/command_line.h"
      9 #include "base/json/json_reader.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "chromeos/chromeos_switches.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 #include "chromeos/dbus/shill_manager_client.h"
     14 #include "chromeos/dbus/shill_service_client.h"
     15 #include "chromeos/network/client_cert_util.h"
     16 #include "chromeos/network/network_configuration_handler.h"
     17 #include "chromeos/network/network_event_log.h"
     18 #include "chromeos/network/network_handler_callbacks.h"
     19 #include "chromeos/network/network_profile_handler.h"
     20 #include "chromeos/network/network_state.h"
     21 #include "chromeos/network/network_state_handler.h"
     22 #include "chromeos/network/network_ui_data.h"
     23 #include "chromeos/network/shill_property_util.h"
     24 #include "dbus/object_path.h"
     25 #include "net/cert/x509_certificate.h"
     26 #include "third_party/cros_system_api/dbus/service_constants.h"
     27 
     28 namespace chromeos {
     29 
     30 namespace {
     31 
     32 void InvokeErrorCallback(const std::string& service_path,
     33                          const network_handler::ErrorCallback& error_callback,
     34                          const std::string& error_name) {
     35   std::string error_msg = "Connect Error: " + error_name;
     36   NET_LOG_ERROR(error_msg, service_path);
     37   network_handler::RunErrorCallback(
     38       error_callback, service_path, error_name, error_msg);
     39 }
     40 
     41 bool IsAuthenticationError(const std::string& error) {
     42   return (error == shill::kErrorBadWEPKey ||
     43           error == shill::kErrorPppAuthFailed ||
     44           error == shill::kErrorEapLocalTlsFailed ||
     45           error == shill::kErrorEapRemoteTlsFailed ||
     46           error == shill::kErrorEapAuthenticationFailed);
     47 }
     48 
     49 bool VPNRequiresCredentials(const std::string& service_path,
     50                            const std::string& provider_type,
     51                            const base::DictionaryValue& provider_properties) {
     52   if (provider_type == shill::kProviderOpenVpn) {
     53     std::string username;
     54     provider_properties.GetStringWithoutPathExpansion(
     55         shill::kOpenVPNUserProperty, &username);
     56     if (username.empty()) {
     57       NET_LOG_EVENT("OpenVPN: No username", service_path);
     58       return true;
     59     }
     60     bool passphrase_required = false;
     61     provider_properties.GetBooleanWithoutPathExpansion(
     62         shill::kPassphraseRequiredProperty, &passphrase_required);
     63     if (passphrase_required) {
     64       NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
     65       return true;
     66     }
     67     NET_LOG_EVENT("OpenVPN Is Configured", service_path);
     68   } else {
     69     bool passphrase_required = false;
     70     provider_properties.GetBooleanWithoutPathExpansion(
     71         shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
     72     if (passphrase_required) {
     73       NET_LOG_EVENT("VPN: PSK Required", service_path);
     74       return true;
     75     }
     76     provider_properties.GetBooleanWithoutPathExpansion(
     77         shill::kPassphraseRequiredProperty, &passphrase_required);
     78     if (passphrase_required) {
     79       NET_LOG_EVENT("VPN: Passphrase Required", service_path);
     80       return true;
     81     }
     82     NET_LOG_EVENT("VPN Is Configured", service_path);
     83   }
     84   return false;
     85 }
     86 
     87 std::string GetDefaultUserProfilePath(const NetworkState* network) {
     88   if (!NetworkHandler::IsInitialized() ||
     89       !LoginState::Get()->IsUserAuthenticated() ||
     90       (network && network->type() == shill::kTypeWifi &&
     91        network->security() == shill::kSecurityNone)) {
     92     return NetworkProfileHandler::kSharedProfilePath;
     93   }
     94   const NetworkProfile* profile  =
     95       NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
     96   return profile ? profile->path : NetworkProfileHandler::kSharedProfilePath;
     97 }
     98 
     99 }  // namespace
    100 
    101 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
    102 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
    103 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
    104 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
    105 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
    106     "passphrase-required";
    107 const char NetworkConnectionHandler::kErrorActivationRequired[] =
    108     "activation-required";
    109 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
    110     "certificate-required";
    111 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
    112     "configuration-required";
    113 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
    114     "authentication-required";
    115 const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
    116 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
    117     "configure-failed";
    118 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
    119     "connect-canceled";
    120 
    121 struct NetworkConnectionHandler::ConnectRequest {
    122   ConnectRequest(const std::string& service_path,
    123                  const std::string& profile_path,
    124                  const base::Closure& success,
    125                  const network_handler::ErrorCallback& error)
    126       : service_path(service_path),
    127         profile_path(profile_path),
    128         connect_state(CONNECT_REQUESTED),
    129         success_callback(success),
    130         error_callback(error) {
    131   }
    132   enum ConnectState {
    133     CONNECT_REQUESTED = 0,
    134     CONNECT_STARTED = 1,
    135     CONNECT_CONNECTING = 2
    136   };
    137   std::string service_path;
    138   std::string profile_path;
    139   ConnectState connect_state;
    140   base::Closure success_callback;
    141   network_handler::ErrorCallback error_callback;
    142 };
    143 
    144 NetworkConnectionHandler::NetworkConnectionHandler()
    145     : cert_loader_(NULL),
    146       network_state_handler_(NULL),
    147       network_configuration_handler_(NULL),
    148       logged_in_(false),
    149       certificates_loaded_(false) {
    150 }
    151 
    152 NetworkConnectionHandler::~NetworkConnectionHandler() {
    153   if (network_state_handler_)
    154     network_state_handler_->RemoveObserver(this, FROM_HERE);
    155   if (cert_loader_)
    156     cert_loader_->RemoveObserver(this);
    157   if (LoginState::IsInitialized())
    158     LoginState::Get()->RemoveObserver(this);
    159 }
    160 
    161 void NetworkConnectionHandler::Init(
    162     NetworkStateHandler* network_state_handler,
    163     NetworkConfigurationHandler* network_configuration_handler) {
    164   if (LoginState::IsInitialized()) {
    165     LoginState::Get()->AddObserver(this);
    166     logged_in_ = LoginState::Get()->IsUserLoggedIn();
    167   }
    168   if (CertLoader::IsInitialized()) {
    169     cert_loader_ = CertLoader::Get();
    170     cert_loader_->AddObserver(this);
    171     certificates_loaded_ = cert_loader_->certificates_loaded();
    172   } else {
    173     // TODO(stevenjb): Require a mock or stub cert_loader in tests.
    174     certificates_loaded_ = true;
    175   }
    176   if (network_state_handler) {
    177     network_state_handler_ = network_state_handler;
    178     network_state_handler_->AddObserver(this, FROM_HERE);
    179   }
    180   network_configuration_handler_ = network_configuration_handler;
    181 }
    182 
    183 void NetworkConnectionHandler::LoggedInStateChanged() {
    184   if (LoginState::Get()->IsUserLoggedIn()) {
    185     logged_in_ = true;
    186     NET_LOG_EVENT("Logged In", "");
    187   }
    188 }
    189 
    190 void NetworkConnectionHandler::OnCertificatesLoaded(
    191     const net::CertificateList& cert_list,
    192     bool initial_load) {
    193   certificates_loaded_ = true;
    194   NET_LOG_EVENT("Certificates Loaded", "");
    195   if (queued_connect_) {
    196     NET_LOG_EVENT("Connecting to Queued Network",
    197                   queued_connect_->service_path);
    198     ConnectToNetwork(queued_connect_->service_path,
    199                      queued_connect_->success_callback,
    200                      queued_connect_->error_callback,
    201                      false /* check_error_state */);
    202   } else if (initial_load) {
    203     // Once certificates have loaded, connect to the "best" available network.
    204     network_state_handler_->ConnectToBestWifiNetwork();
    205   }
    206 }
    207 
    208 void NetworkConnectionHandler::ConnectToNetwork(
    209     const std::string& service_path,
    210     const base::Closure& success_callback,
    211     const network_handler::ErrorCallback& error_callback,
    212     bool check_error_state) {
    213   NET_LOG_USER("ConnectToNetwork", service_path);
    214   // Clear any existing queued connect request.
    215   queued_connect_.reset();
    216   if (HasConnectingNetwork(service_path)) {
    217     NET_LOG_USER("Connect Request While Pending", service_path);
    218     InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    219     return;
    220   }
    221 
    222   // Check cached network state for connected, connecting, or unactivated
    223   // networks. These states will not be affected by a recent configuration.
    224   // Note: NetworkState may not exist for a network that was recently
    225   // configured, in which case these checks do not apply anyway.
    226   const NetworkState* network =
    227       network_state_handler_->GetNetworkState(service_path);
    228 
    229   if (network) {
    230     // For existing networks, perform some immediate consistency checks.
    231     if (network->IsConnectedState()) {
    232       InvokeErrorCallback(service_path, error_callback, kErrorConnected);
    233       return;
    234     }
    235     if (network->IsConnectingState()) {
    236       InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    237       return;
    238     }
    239     if (network->RequiresActivation()) {
    240       InvokeErrorCallback(service_path, error_callback,
    241                           kErrorActivationRequired);
    242       return;
    243     }
    244 
    245     if (check_error_state) {
    246       const std::string& error = network->error();
    247       if (error == shill::kErrorBadPassphrase) {
    248         InvokeErrorCallback(service_path, error_callback, error);
    249         return;
    250       }
    251       if (IsAuthenticationError(error)) {
    252         InvokeErrorCallback(
    253             service_path, error_callback, kErrorAuthenticationRequired);
    254         return;
    255       }
    256     }
    257   }
    258 
    259   // If the network does not have a profile path, specify the correct default
    260   // profile here and set it once connected. Otherwise leave it empty to
    261   // indicate that it does not need to be set.
    262   std::string profile_path;
    263   if (!network || network->profile_path().empty())
    264     profile_path = GetDefaultUserProfilePath(network);
    265 
    266   // All synchronous checks passed, add |service_path| to connecting list.
    267   pending_requests_.insert(std::make_pair(
    268       service_path,
    269       ConnectRequest(service_path, profile_path,
    270                      success_callback, error_callback)));
    271 
    272   // Connect immediately to 'connectable' networks.
    273   // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    274   if (network && network->connectable() && network->type() != shill::kTypeVPN) {
    275     CallShillConnect(service_path);
    276     return;
    277   }
    278 
    279   // Request additional properties to check. VerifyConfiguredAndConnect will
    280   // use only these properties, not cached properties, to ensure that they
    281   // are up to date after any recent configuration.
    282   network_configuration_handler_->GetProperties(
    283       service_path,
    284       base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
    285                  AsWeakPtr(), check_error_state),
    286       base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    287                  AsWeakPtr(), service_path));
    288 }
    289 
    290 void NetworkConnectionHandler::DisconnectNetwork(
    291     const std::string& service_path,
    292     const base::Closure& success_callback,
    293     const network_handler::ErrorCallback& error_callback) {
    294   NET_LOG_USER("DisconnectNetwork", service_path);
    295   const NetworkState* network =
    296       network_state_handler_->GetNetworkState(service_path);
    297   if (!network) {
    298     InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
    299     return;
    300   }
    301   if (!network->IsConnectedState()) {
    302     InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
    303     return;
    304   }
    305   CallShillDisconnect(service_path, success_callback, error_callback);
    306 }
    307 
    308 bool NetworkConnectionHandler::HasConnectingNetwork(
    309     const std::string& service_path) {
    310   return pending_requests_.count(service_path) != 0;
    311 }
    312 
    313 bool NetworkConnectionHandler::HasPendingConnectRequest() {
    314   return pending_requests_.size() > 0;
    315 }
    316 
    317 void NetworkConnectionHandler::NetworkListChanged() {
    318   CheckAllPendingRequests();
    319 }
    320 
    321 void NetworkConnectionHandler::NetworkPropertiesUpdated(
    322     const NetworkState* network) {
    323   if (HasConnectingNetwork(network->path()))
    324     CheckPendingRequest(network->path());
    325 }
    326 
    327 NetworkConnectionHandler::ConnectRequest*
    328 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
    329   std::map<std::string, ConnectRequest>::iterator iter =
    330       pending_requests_.find(service_path);
    331   return iter != pending_requests_.end() ? &(iter->second) : NULL;
    332 }
    333 
    334 // ConnectToNetwork implementation
    335 
    336 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
    337     bool check_error_state,
    338     const std::string& service_path,
    339     const base::DictionaryValue& service_properties) {
    340   NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
    341 
    342   // If 'passphrase_required' is still true, then the 'Passphrase' property
    343   // has not been set to a minimum length value.
    344   bool passphrase_required = false;
    345   service_properties.GetBooleanWithoutPathExpansion(
    346       shill::kPassphraseRequiredProperty, &passphrase_required);
    347   if (passphrase_required) {
    348     ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
    349     return;
    350   }
    351 
    352   std::string type, security;
    353   service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
    354   service_properties.GetStringWithoutPathExpansion(
    355       shill::kSecurityProperty, &security);
    356   bool connectable = false;
    357   service_properties.GetBooleanWithoutPathExpansion(
    358       shill::kConnectableProperty, &connectable);
    359 
    360   // In case NetworkState was not available in ConnectToNetwork (e.g. it had
    361   // been recently configured), we need to check Connectable again.
    362   if (connectable && type != shill::kTypeVPN) {
    363     // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    364     CallShillConnect(service_path);
    365     return;
    366   }
    367 
    368   // Get VPN provider type and host (required for configuration) and ensure
    369   // that required VPN non-cert properties are set.
    370   const base::DictionaryValue* provider_properties = NULL;
    371   std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
    372   if (type == shill::kTypeVPN) {
    373     // VPN Provider values are read from the "Provider" dictionary, not the
    374     // "Provider.Type", etc keys (which are used only to set the values).
    375     if (service_properties.GetDictionaryWithoutPathExpansion(
    376             shill::kProviderProperty, &provider_properties)) {
    377       provider_properties->GetStringWithoutPathExpansion(
    378           shill::kTypeProperty, &vpn_provider_type);
    379       provider_properties->GetStringWithoutPathExpansion(
    380           shill::kHostProperty, &vpn_provider_host);
    381       provider_properties->GetStringWithoutPathExpansion(
    382           shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
    383     }
    384     if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
    385       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    386       return;
    387     }
    388   }
    389 
    390   scoped_ptr<NetworkUIData> ui_data =
    391       shill_property_util::GetUIDataFromProperties(service_properties);
    392 
    393   client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
    394   if (type == shill::kTypeVPN) {
    395     if (vpn_provider_type == shill::kProviderOpenVpn) {
    396       client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
    397     } else {
    398       // L2TP/IPSec only requires a certificate if one is specified in ONC
    399       // or one was configured by the UI. Otherwise it is L2TP/IPSec with
    400       // PSK and doesn't require a certificate.
    401       //
    402       // TODO(benchan): Modify shill to specify the authentication type via
    403       // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
    404       // to deduce the authentication type based on the
    405       // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
    406       if (!vpn_client_cert_id.empty() ||
    407           (ui_data && ui_data->certificate_type() != CLIENT_CERT_TYPE_NONE))
    408         client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
    409     }
    410   } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
    411     client_cert_type = client_cert::CONFIG_TYPE_EAP;
    412   }
    413 
    414   base::DictionaryValue config_properties;
    415   if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
    416     // If the client certificate must be configured, this will be set to a
    417     // non-empty string.
    418     std::string pkcs11_id;
    419 
    420     // Check certificate properties in kUIDataProperty if configured.
    421     // Note: Wifi/VPNConfigView set these properties explicitly, in which case
    422     //   only the TPM must be configured.
    423     if (ui_data && ui_data->certificate_type() == CLIENT_CERT_TYPE_PATTERN) {
    424       // User must be logged in to connect to a network requiring a certificate.
    425       if (!logged_in_ || !cert_loader_) {
    426         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    427         return;
    428       }
    429 
    430       // If certificates have not been loaded yet, queue the connect request.
    431       if (!certificates_loaded_) {
    432         ConnectRequest* request = GetPendingRequest(service_path);
    433         if (!request) {
    434           NET_LOG_ERROR("No pending request to queue", service_path);
    435           return;
    436         }
    437         NET_LOG_EVENT("Connect Request Queued", service_path);
    438         queued_connect_.reset(new ConnectRequest(
    439             service_path, request->profile_path,
    440             request->success_callback, request->error_callback));
    441         pending_requests_.erase(service_path);
    442         return;
    443       }
    444 
    445       pkcs11_id = CertificateIsConfigured(ui_data.get());
    446       // Ensure the certificate is available and configured.
    447       if (!cert_loader_->IsHardwareBacked() || pkcs11_id.empty()) {
    448         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    449         return;
    450       }
    451     } else if (check_error_state &&
    452                !client_cert::IsCertificateConfigured(client_cert_type,
    453                                                      service_properties)) {
    454       // Network may not be configured.
    455       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    456       return;
    457     }
    458 
    459     // The network may not be 'Connectable' because the TPM properties are not
    460     // set up, so configure tpm slot/pin before connecting.
    461     if (cert_loader_ && cert_loader_->IsHardwareBacked()) {
    462       // Pass NULL if pkcs11_id is empty, so that it doesn't clear any
    463       // previously configured client cert.
    464       client_cert::SetShillProperties(
    465           client_cert_type,
    466           base::IntToString(cert_loader_->tpm_token_slot_id()),
    467           cert_loader_->tpm_user_pin(),
    468           pkcs11_id.empty() ? NULL : &pkcs11_id,
    469           &config_properties);
    470     }
    471   }
    472 
    473   if (type == shill::kTypeVPN) {
    474     // VPN may require a username, and/or passphrase to be set. (Check after
    475     // ensuring that any required certificates are configured).
    476     DCHECK(provider_properties);
    477     if (VPNRequiresCredentials(
    478             service_path, vpn_provider_type, *provider_properties)) {
    479       NET_LOG_USER("VPN Requires Credentials", service_path);
    480       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    481       return;
    482     }
    483 
    484     // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
    485     // to connect.
    486     if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
    487       CallShillConnect(service_path);
    488       return;
    489     }
    490   }
    491 
    492   if (!config_properties.empty()) {
    493     NET_LOG_EVENT("Configuring Network", service_path);
    494     network_configuration_handler_->SetProperties(
    495         service_path,
    496         config_properties,
    497         base::Bind(&NetworkConnectionHandler::CallShillConnect,
    498                    AsWeakPtr(),
    499                    service_path),
    500         base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    501                    AsWeakPtr(),
    502                    service_path));
    503     return;
    504   }
    505 
    506   // Otherwise, we probably still need to configure the network since
    507   // 'Connectable' is false. If |check_error_state| is true, signal an
    508   // error, otherwise attempt to connect to possibly gain additional error
    509   // state from Shill (or in case 'Connectable' is improperly unset).
    510   if (check_error_state)
    511     ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    512   else
    513     CallShillConnect(service_path);
    514 }
    515 
    516 void NetworkConnectionHandler::CallShillConnect(
    517     const std::string& service_path) {
    518   NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
    519   DBusThreadManager::Get()->GetShillServiceClient()->Connect(
    520       dbus::ObjectPath(service_path),
    521       base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
    522                  AsWeakPtr(), service_path),
    523       base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
    524                  AsWeakPtr(), service_path));
    525 }
    526 
    527 void NetworkConnectionHandler::HandleConfigurationFailure(
    528     const std::string& service_path,
    529     const std::string& error_name,
    530     scoped_ptr<base::DictionaryValue> error_data) {
    531   ConnectRequest* request = GetPendingRequest(service_path);
    532   if (!request) {
    533     NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
    534                   service_path);
    535     return;
    536   }
    537   network_handler::ErrorCallback error_callback = request->error_callback;
    538   pending_requests_.erase(service_path);
    539   if (!error_callback.is_null())
    540     error_callback.Run(kErrorConfigureFailed, error_data.Pass());
    541 }
    542 
    543 void NetworkConnectionHandler::HandleShillConnectSuccess(
    544     const std::string& service_path) {
    545   ConnectRequest* request = GetPendingRequest(service_path);
    546   if (!request) {
    547     NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
    548                   service_path);
    549     return;
    550   }
    551   request->connect_state = ConnectRequest::CONNECT_STARTED;
    552   NET_LOG_EVENT("Connect Request Acknowledged", service_path);
    553   // Do not call success_callback here, wait for one of the following
    554   // conditions:
    555   // * State transitions to a non connecting state indicating succes or failure
    556   // * Network is no longer in the visible list, indicating failure
    557   CheckPendingRequest(service_path);
    558 }
    559 
    560 void NetworkConnectionHandler::HandleShillConnectFailure(
    561     const std::string& service_path,
    562     const std::string& dbus_error_name,
    563     const std::string& dbus_error_message) {
    564   ConnectRequest* request = GetPendingRequest(service_path);
    565   if (!request) {
    566     NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
    567                   service_path);
    568     return;
    569   }
    570   network_handler::ErrorCallback error_callback = request->error_callback;
    571   pending_requests_.erase(service_path);
    572   network_handler::ShillErrorCallbackFunction(
    573       shill::kErrorConnectFailed, service_path, error_callback,
    574       dbus_error_name, dbus_error_message);
    575 }
    576 
    577 void NetworkConnectionHandler::CheckPendingRequest(
    578     const std::string service_path) {
    579   ConnectRequest* request = GetPendingRequest(service_path);
    580   DCHECK(request);
    581   if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
    582     return;  // Request has not started, ignore update
    583   const NetworkState* network =
    584       network_state_handler_->GetNetworkState(service_path);
    585   if (!network)
    586     return;  // NetworkState may not be be updated yet.
    587 
    588   if (network->IsConnectingState()) {
    589     request->connect_state = ConnectRequest::CONNECT_CONNECTING;
    590     return;
    591   }
    592   if (network->IsConnectedState()) {
    593     NET_LOG_EVENT("Connect Request Succeeded", service_path);
    594     if (!request->profile_path.empty()) {
    595       // If a profile path was specified, set it on a successful connection.
    596       network_configuration_handler_->SetNetworkProfile(
    597           service_path, request->profile_path,
    598           base::Bind(&base::DoNothing),
    599           chromeos::network_handler::ErrorCallback());
    600     }
    601     if (!request->success_callback.is_null())
    602       request->success_callback.Run();
    603     pending_requests_.erase(service_path);
    604     return;
    605   }
    606   if (network->connection_state() == shill::kStateIdle &&
    607       request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
    608     // Connection hasn't started yet, keep waiting.
    609     return;
    610   }
    611 
    612   // Network is neither connecting or connected; an error occurred.
    613   std::string error_name;  // 'Canceled' or 'Failed'
    614   // If network->error() is empty here, we will look it up later, but we
    615   // need to preserve it in case Shill clears it before then. crbug.com/302020.
    616   std::string shill_error = network->error();
    617   if (network->connection_state() == shill::kStateIdle &&
    618       pending_requests_.size() > 1) {
    619     // Another connect request canceled this one.
    620     error_name = kErrorConnectCanceled;
    621   } else {
    622     error_name = shill::kErrorConnectFailed;
    623     if (network->connection_state() != shill::kStateFailure) {
    624       NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
    625                     service_path);
    626     }
    627   }
    628   std::string error_msg = error_name;
    629   if (!shill_error.empty())
    630     error_msg += ": " + shill_error;
    631   NET_LOG_ERROR(error_msg, service_path);
    632 
    633   network_handler::ErrorCallback error_callback = request->error_callback;
    634   pending_requests_.erase(service_path);
    635   if (error_callback.is_null())
    636     return;
    637   network_handler::RunErrorCallback(
    638       error_callback, service_path, error_name, shill_error);
    639 }
    640 
    641 void NetworkConnectionHandler::CheckAllPendingRequests() {
    642   for (std::map<std::string, ConnectRequest>::iterator iter =
    643            pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
    644     CheckPendingRequest(iter->first);
    645   }
    646 }
    647 
    648 std::string NetworkConnectionHandler::CertificateIsConfigured(
    649     NetworkUIData* ui_data) {
    650   if (ui_data->certificate_pattern().Empty())
    651     return std::string();
    652   // Find the matching certificate.
    653   scoped_refptr<net::X509Certificate> matching_cert =
    654       client_cert::GetCertificateMatch(ui_data->certificate_pattern());
    655   if (!matching_cert.get())
    656     return std::string();
    657   return CertLoader::GetPkcs11IdForCert(*matching_cert.get());
    658 }
    659 
    660 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
    661     const std::string& service_path,
    662     const std::string& error_name) {
    663   ConnectRequest* request = GetPendingRequest(service_path);
    664   if (!request) {
    665     NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
    666                   service_path);
    667     return;
    668   }
    669   // Remove the entry before invoking the callback in case it triggers a retry.
    670   network_handler::ErrorCallback error_callback = request->error_callback;
    671   pending_requests_.erase(service_path);
    672   InvokeErrorCallback(service_path, error_callback, error_name);
    673 }
    674 
    675 // Disconnect
    676 
    677 void NetworkConnectionHandler::CallShillDisconnect(
    678     const std::string& service_path,
    679     const base::Closure& success_callback,
    680     const network_handler::ErrorCallback& error_callback) {
    681   NET_LOG_USER("Disconnect Request", service_path);
    682   DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
    683       dbus::ObjectPath(service_path),
    684       base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
    685                  AsWeakPtr(), service_path, success_callback),
    686       base::Bind(&network_handler::ShillErrorCallbackFunction,
    687                  kErrorShillError, service_path, error_callback));
    688 }
    689 
    690 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
    691     const std::string& service_path,
    692     const base::Closure& success_callback) {
    693   NET_LOG_EVENT("Disconnect Request Sent", service_path);
    694   if (!success_callback.is_null())
    695     success_callback.Run();
    696 }
    697 
    698 }  // namespace chromeos
    699