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