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