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