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