network_connection_handler.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
31namespace chromeos {
32
33namespace {
34
35void 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
44bool 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
52bool 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
90std::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
104const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
105const char NetworkConnectionHandler::kErrorConnected[] = "connected";
106const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
107const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
108const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
109    "passphrase-required";
110const char NetworkConnectionHandler::kErrorActivationRequired[] =
111    "activation-required";
112const char NetworkConnectionHandler::kErrorCertificateRequired[] =
113    "certificate-required";
114const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
115    "configuration-required";
116const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
117    "authentication-required";
118const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
119const char NetworkConnectionHandler::kErrorConfigureFailed[] =
120    "configure-failed";
121const char NetworkConnectionHandler::kErrorConnectCanceled[] =
122    "connect-canceled";
123
124struct 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
147NetworkConnectionHandler::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
155NetworkConnectionHandler::~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
164void 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
188void NetworkConnectionHandler::LoggedInStateChanged() {
189  if (LoginState::Get()->IsUserLoggedIn()) {
190    logged_in_ = true;
191    NET_LOG_EVENT("Logged In", "");
192  }
193}
194
195void 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
219void 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
301void 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
319bool NetworkConnectionHandler::HasConnectingNetwork(
320    const std::string& service_path) {
321  return pending_requests_.count(service_path) != 0;
322}
323
324bool NetworkConnectionHandler::HasPendingConnectRequest() {
325  return pending_requests_.size() > 0;
326}
327
328void NetworkConnectionHandler::NetworkListChanged() {
329  CheckAllPendingRequests();
330}
331
332void NetworkConnectionHandler::NetworkPropertiesUpdated(
333    const NetworkState* network) {
334  if (HasConnectingNetwork(network->path()))
335    CheckPendingRequest(network->path());
336}
337
338NetworkConnectionHandler::ConnectRequest*
339NetworkConnectionHandler::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
347void 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
528void 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
539void 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
555void 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
572void 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
589void 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
653void 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
660std::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
673void 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
690void 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
703void 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
712