Less strict CHECK for DeviceCapabilities results.
[chromium-blink-merge.git] / chromeos / network / network_connection_handler.cc
blobdecccfd5f35ef0aab3ac2c26a160af2523db27c4
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.
5 #include "chromeos/network/network_connection_handler.h"
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"
31 namespace chromeos {
33 namespace {
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);
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);
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;
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;
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;
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;
85 NET_LOG_EVENT("VPN Is Configured", service_path);
87 return false;
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;
97 const NetworkProfile* profile =
98 NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
99 return profile ? profile->path : NetworkProfileHandler::kSharedProfilePath;
102 } // namespace
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";
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) {
135 enum ConnectState {
136 CONNECT_REQUESTED = 0,
137 CONNECT_STARTED = 1,
138 CONNECT_CONNECTING = 2
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;
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) {
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);
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();
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;
181 if (network_state_handler) {
182 network_state_handler_ = network_state_handler;
183 network_state_handler_->AddObserver(this, FROM_HERE);
185 network_configuration_handler_ = network_configuration_handler;
188 void NetworkConnectionHandler::LoggedInStateChanged() {
189 if (LoginState::Get()->IsUserLoggedIn()) {
190 logged_in_ = true;
191 NET_LOG_EVENT("Logged In", "");
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);
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;
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();
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;
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);
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;
246 if (network->IsConnectingState()) {
247 InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
248 return;
250 if (network->RequiresActivation()) {
251 InvokeErrorCallback(service_path, error_callback,
252 kErrorActivationRequired);
253 return;
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;
262 if (IsAuthenticationError(error)) {
263 InvokeErrorCallback(
264 service_path, error_callback, kErrorAuthenticationRequired);
265 return;
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);
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)));
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;
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));
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;
312 if (!network->IsConnectedState()) {
313 InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
314 return;
316 CallShillDisconnect(service_path, success_callback, error_callback);
319 bool NetworkConnectionHandler::HasConnectingNetwork(
320 const std::string& service_path) {
321 return pending_requests_.count(service_path) != 0;
324 bool NetworkConnectionHandler::HasPendingConnectRequest() {
325 return pending_requests_.size() > 0;
328 void NetworkConnectionHandler::NetworkListChanged() {
329 CheckAllPendingRequests();
332 void NetworkConnectionHandler::NetworkPropertiesUpdated(
333 const NetworkState* network) {
334 if (HasConnectingNetwork(network->path()))
335 CheckPendingRequest(network->path());
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;
345 // ConnectToNetwork implementation
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);
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;
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);
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;
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);
395 if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
396 ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
397 return;
401 scoped_ptr<NetworkUIData> ui_data =
402 shill_property_util::GetUIDataFromProperties(service_properties);
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.
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;
421 } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
422 client_cert_type = client_cert::CONFIG_TYPE_EAP;
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;
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;
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;
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;
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;
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;
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);
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;
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;
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;
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);
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));
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;
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());
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;
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);
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;
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);
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.
600 if (network->IsConnectingState()) {
601 request->connect_state = ConnectRequest::CONNECT_CONNECTING;
602 return;
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());
613 if (!request->success_callback.is_null())
614 request->success_callback.Run();
615 pending_requests_.erase(service_path);
616 return;
618 if (network->connection_state() == shill::kStateIdle &&
619 request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
620 // Connection hasn't started yet, keep waiting.
621 return;
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);
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);
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);
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);
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());
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;
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);
688 // Disconnect
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));
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();
711 } // namespace chromeos