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