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"
8 #include "base/json/json_reader.h"
9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chromeos/cert_loader.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_manager_client.h"
15 #include "chromeos/dbus/shill_service_client.h"
16 #include "chromeos/network/certificate_pattern.h"
17 #include "chromeos/network/client_cert_resolver.h"
18 #include "chromeos/network/client_cert_util.h"
19 #include "chromeos/network/managed_network_configuration_handler.h"
20 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_event_log.h"
22 #include "chromeos/network/network_handler_callbacks.h"
23 #include "chromeos/network/network_profile_handler.h"
24 #include "chromeos/network/network_state.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/shill_property_util.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"
35 void InvokeErrorCallback(const std::string
& service_path
,
36 const network_handler::ErrorCallback
& error_callback
,
37 const std::string
& error_name
) {
38 NET_LOG_ERROR("Connect Error: " + error_name
, service_path
);
39 network_handler::RunErrorCallback(
40 error_callback
, service_path
, error_name
, "");
43 bool IsAuthenticationError(const std::string
& error
) {
44 return (error
== shill::kErrorBadWEPKey
||
45 error
== shill::kErrorPppAuthFailed
||
46 error
== shill::kErrorEapLocalTlsFailed
||
47 error
== shill::kErrorEapRemoteTlsFailed
||
48 error
== shill::kErrorEapAuthenticationFailed
);
51 bool VPNRequiresCredentials(const std::string
& service_path
,
52 const std::string
& provider_type
,
53 const base::DictionaryValue
& provider_properties
) {
54 if (provider_type
== shill::kProviderOpenVpn
) {
56 provider_properties
.GetStringWithoutPathExpansion(
57 shill::kOpenVPNUserProperty
, &username
);
58 if (username
.empty()) {
59 NET_LOG_EVENT("OpenVPN: No username", service_path
);
62 bool passphrase_required
= false;
63 provider_properties
.GetBooleanWithoutPathExpansion(
64 shill::kPassphraseRequiredProperty
, &passphrase_required
);
65 if (passphrase_required
) {
66 NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path
);
69 NET_LOG_EVENT("OpenVPN Is Configured", service_path
);
71 bool passphrase_required
= false;
72 provider_properties
.GetBooleanWithoutPathExpansion(
73 shill::kL2tpIpsecPskRequiredProperty
, &passphrase_required
);
74 if (passphrase_required
) {
75 NET_LOG_EVENT("VPN: PSK Required", service_path
);
78 provider_properties
.GetBooleanWithoutPathExpansion(
79 shill::kPassphraseRequiredProperty
, &passphrase_required
);
80 if (passphrase_required
) {
81 NET_LOG_EVENT("VPN: Passphrase Required", service_path
);
84 NET_LOG_EVENT("VPN Is Configured", service_path
);
89 std::string
GetDefaultUserProfilePath(const NetworkState
* network
) {
90 if (!NetworkHandler::IsInitialized() ||
91 (LoginState::IsInitialized() &&
92 !LoginState::Get()->UserHasNetworkProfile()) ||
93 (network
&& network
->type() == shill::kTypeWifi
&&
94 network
->security() == shill::kSecurityNone
)) {
95 return NetworkProfileHandler::GetSharedProfilePath();
97 const NetworkProfile
* profile
=
98 NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
99 return profile
? profile
->path
100 : NetworkProfileHandler::GetSharedProfilePath();
105 const char NetworkConnectionHandler::kErrorNotFound
[] = "not-found";
106 const char NetworkConnectionHandler::kErrorConnected
[] = "connected";
107 const char NetworkConnectionHandler::kErrorConnecting
[] = "connecting";
108 const char NetworkConnectionHandler::kErrorNotConnected
[] = "not-connected";
109 const char NetworkConnectionHandler::kErrorPassphraseRequired
[] =
110 "passphrase-required";
111 const char NetworkConnectionHandler::kErrorActivationRequired
[] =
112 "activation-required";
113 const char NetworkConnectionHandler::kErrorCertificateRequired
[] =
114 "certificate-required";
115 const char NetworkConnectionHandler::kErrorConfigurationRequired
[] =
116 "configuration-required";
117 const char NetworkConnectionHandler::kErrorAuthenticationRequired
[] =
118 "authentication-required";
119 const char NetworkConnectionHandler::kErrorShillError
[] = "shill-error";
120 const char NetworkConnectionHandler::kErrorConfigureFailed
[] =
122 const char NetworkConnectionHandler::kErrorConnectCanceled
[] =
124 const char NetworkConnectionHandler::kErrorCertLoadTimeout
[] =
127 struct NetworkConnectionHandler::ConnectRequest
{
128 ConnectRequest(const std::string
& service_path
,
129 const std::string
& profile_path
,
130 const base::Closure
& success
,
131 const network_handler::ErrorCallback
& error
)
132 : service_path(service_path
),
133 profile_path(profile_path
),
134 connect_state(CONNECT_REQUESTED
),
135 success_callback(success
),
136 error_callback(error
) {
139 CONNECT_REQUESTED
= 0,
141 CONNECT_CONNECTING
= 2
143 std::string service_path
;
144 std::string profile_path
;
145 ConnectState connect_state
;
146 base::Closure success_callback
;
147 network_handler::ErrorCallback error_callback
;
150 NetworkConnectionHandler::NetworkConnectionHandler()
151 : cert_loader_(NULL
),
152 network_state_handler_(NULL
),
153 configuration_handler_(NULL
),
155 certificates_loaded_(false) {
158 NetworkConnectionHandler::~NetworkConnectionHandler() {
159 if (network_state_handler_
)
160 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
162 cert_loader_
->RemoveObserver(this);
163 if (LoginState::IsInitialized())
164 LoginState::Get()->RemoveObserver(this);
167 void NetworkConnectionHandler::Init(
168 NetworkStateHandler
* network_state_handler
,
169 NetworkConfigurationHandler
* network_configuration_handler
,
170 ManagedNetworkConfigurationHandler
* managed_network_configuration_handler
) {
171 if (LoginState::IsInitialized())
172 LoginState::Get()->AddObserver(this);
174 if (CertLoader::IsInitialized()) {
175 cert_loader_
= CertLoader::Get();
176 cert_loader_
->AddObserver(this);
177 if (cert_loader_
->certificates_loaded()) {
178 NET_LOG_EVENT("Certificates Loaded", "");
179 certificates_loaded_
= true;
182 // TODO(tbarzic): Require a mock or stub cert_loader in tests.
183 NET_LOG_EVENT("Certificate Loader not initialized", "");
184 certificates_loaded_
= true;
187 if (network_state_handler
) {
188 network_state_handler_
= network_state_handler
;
189 network_state_handler_
->AddObserver(this, FROM_HERE
);
191 configuration_handler_
= network_configuration_handler
;
192 managed_configuration_handler_
= managed_network_configuration_handler
;
194 // After this point, the NetworkConnectionHandler is fully initialized (all
195 // handler references set, observers registered, ...).
197 if (LoginState::IsInitialized())
198 LoggedInStateChanged();
201 void NetworkConnectionHandler::AddObserver(Observer
* observer
) {
202 observers_
.AddObserver(observer
);
205 void NetworkConnectionHandler::RemoveObserver(Observer
* observer
) {
206 observers_
.RemoveObserver(observer
);
209 void NetworkConnectionHandler::LoggedInStateChanged() {
210 LoginState
* login_state
= LoginState::Get();
211 if (logged_in_
|| !login_state
->IsUserLoggedIn())
214 NET_LOG_EVENT("Logged In", "");
216 logged_in_time_
= base::TimeTicks::Now();
219 void NetworkConnectionHandler::OnCertificatesLoaded(
220 const net::CertificateList
& cert_list
,
222 certificates_loaded_
= true;
223 NET_LOG_EVENT("Certificates Loaded", "");
225 ConnectToQueuedNetwork();
228 void NetworkConnectionHandler::ConnectToNetwork(
229 const std::string
& service_path
,
230 const base::Closure
& success_callback
,
231 const network_handler::ErrorCallback
& error_callback
,
232 bool check_error_state
) {
233 NET_LOG_USER("ConnectToNetwork", service_path
);
234 FOR_EACH_OBSERVER(Observer
, observers_
,
235 ConnectToNetworkRequested(service_path
));
237 // Clear any existing queued connect request.
238 queued_connect_
.reset();
239 if (HasConnectingNetwork(service_path
)) {
240 NET_LOG_USER("Connect Request While Pending", service_path
);
241 InvokeErrorCallback(service_path
, error_callback
, kErrorConnecting
);
245 // Check cached network state for connected, connecting, or unactivated
246 // networks. These states will not be affected by a recent configuration.
247 // Note: NetworkState may not exist for a network that was recently
248 // configured, in which case these checks do not apply anyway.
249 const NetworkState
* network
=
250 network_state_handler_
->GetNetworkState(service_path
);
253 // For existing networks, perform some immediate consistency checks.
254 if (network
->IsConnectedState()) {
255 InvokeErrorCallback(service_path
, error_callback
, kErrorConnected
);
258 if (network
->IsConnectingState()) {
259 InvokeErrorCallback(service_path
, error_callback
, kErrorConnecting
);
263 if (check_error_state
) {
264 const std::string
& error
= network
->last_error();
265 if (error
== shill::kErrorBadPassphrase
) {
266 InvokeErrorCallback(service_path
, error_callback
, error
);
269 if (IsAuthenticationError(error
)) {
271 service_path
, error_callback
, kErrorAuthenticationRequired
);
277 // If the network does not have a profile path, specify the correct default
278 // profile here and set it once connected. Otherwise leave it empty to
279 // indicate that it does not need to be set.
280 std::string profile_path
;
281 if (!network
|| network
->profile_path().empty())
282 profile_path
= GetDefaultUserProfilePath(network
);
284 // All synchronous checks passed, add |service_path| to connecting list.
285 pending_requests_
.insert(std::make_pair(
287 ConnectRequest(service_path
, profile_path
,
288 success_callback
, error_callback
)));
290 // Connect immediately to 'connectable' networks.
291 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
292 if (network
&& network
->connectable() && network
->type() != shill::kTypeVPN
) {
293 CallShillConnect(service_path
);
297 // Request additional properties to check. VerifyConfiguredAndConnect will
298 // use only these properties, not cached properties, to ensure that they
299 // are up to date after any recent configuration.
300 configuration_handler_
->GetProperties(
302 base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect
,
303 AsWeakPtr(), check_error_state
),
304 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure
,
305 AsWeakPtr(), service_path
));
308 void NetworkConnectionHandler::DisconnectNetwork(
309 const std::string
& service_path
,
310 const base::Closure
& success_callback
,
311 const network_handler::ErrorCallback
& error_callback
) {
312 NET_LOG_USER("DisconnectNetwork", service_path
);
313 const NetworkState
* network
=
314 network_state_handler_
->GetNetworkState(service_path
);
316 InvokeErrorCallback(service_path
, error_callback
, kErrorNotFound
);
319 if (!network
->IsConnectedState() && !network
->IsConnectingState()) {
320 InvokeErrorCallback(service_path
, error_callback
, kErrorNotConnected
);
323 pending_requests_
.erase(service_path
);
324 CallShillDisconnect(service_path
, success_callback
, error_callback
);
327 bool NetworkConnectionHandler::HasConnectingNetwork(
328 const std::string
& service_path
) {
329 return pending_requests_
.count(service_path
) != 0;
332 bool NetworkConnectionHandler::HasPendingConnectRequest() {
333 return pending_requests_
.size() > 0;
336 void NetworkConnectionHandler::NetworkListChanged() {
337 CheckAllPendingRequests();
340 void NetworkConnectionHandler::NetworkPropertiesUpdated(
341 const NetworkState
* network
) {
342 if (HasConnectingNetwork(network
->path()))
343 CheckPendingRequest(network
->path());
346 NetworkConnectionHandler::ConnectRequest
*
347 NetworkConnectionHandler::GetPendingRequest(const std::string
& service_path
) {
348 std::map
<std::string
, ConnectRequest
>::iterator iter
=
349 pending_requests_
.find(service_path
);
350 return iter
!= pending_requests_
.end() ? &(iter
->second
) : NULL
;
353 // ConnectToNetwork implementation
355 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
356 bool check_error_state
,
357 const std::string
& service_path
,
358 const base::DictionaryValue
& service_properties
) {
359 NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path
);
361 // If 'passphrase_required' is still true, then the 'Passphrase' property
362 // has not been set to a minimum length value.
363 bool passphrase_required
= false;
364 service_properties
.GetBooleanWithoutPathExpansion(
365 shill::kPassphraseRequiredProperty
, &passphrase_required
);
366 if (passphrase_required
) {
367 ErrorCallbackForPendingRequest(service_path
, kErrorPassphraseRequired
);
371 std::string type
, security
;
372 service_properties
.GetStringWithoutPathExpansion(shill::kTypeProperty
, &type
);
373 service_properties
.GetStringWithoutPathExpansion(
374 shill::kSecurityProperty
, &security
);
375 bool connectable
= false;
376 service_properties
.GetBooleanWithoutPathExpansion(
377 shill::kConnectableProperty
, &connectable
);
379 // In case NetworkState was not available in ConnectToNetwork (e.g. it had
380 // been recently configured), we need to check Connectable again.
381 if (connectable
&& type
!= shill::kTypeVPN
) {
382 // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
383 CallShillConnect(service_path
);
387 // Get VPN provider type and host (required for configuration) and ensure
388 // that required VPN non-cert properties are set.
389 const base::DictionaryValue
* provider_properties
= NULL
;
390 std::string vpn_provider_type
, vpn_provider_host
, vpn_client_cert_id
;
391 if (type
== shill::kTypeVPN
) {
392 // VPN Provider values are read from the "Provider" dictionary, not the
393 // "Provider.Type", etc keys (which are used only to set the values).
394 if (service_properties
.GetDictionaryWithoutPathExpansion(
395 shill::kProviderProperty
, &provider_properties
)) {
396 provider_properties
->GetStringWithoutPathExpansion(
397 shill::kTypeProperty
, &vpn_provider_type
);
398 provider_properties
->GetStringWithoutPathExpansion(
399 shill::kHostProperty
, &vpn_provider_host
);
400 provider_properties
->GetStringWithoutPathExpansion(
401 shill::kL2tpIpsecClientCertIdProperty
, &vpn_client_cert_id
);
403 if (vpn_provider_type
.empty() || vpn_provider_host
.empty()) {
404 ErrorCallbackForPendingRequest(service_path
, kErrorConfigurationRequired
);
410 service_properties
.GetStringWithoutPathExpansion(shill::kGuidProperty
, &guid
);
412 service_properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
414 const base::DictionaryValue
* user_policy
=
415 managed_configuration_handler_
->FindPolicyByGuidAndProfile(guid
, profile
);
417 client_cert::ClientCertConfig cert_config_from_policy
;
419 client_cert::OncToClientCertConfig(*user_policy
, &cert_config_from_policy
);
421 client_cert::ConfigType client_cert_type
= client_cert::CONFIG_TYPE_NONE
;
422 if (type
== shill::kTypeVPN
) {
423 if (vpn_provider_type
== shill::kProviderOpenVpn
) {
424 client_cert_type
= client_cert::CONFIG_TYPE_OPENVPN
;
426 // L2TP/IPSec only requires a certificate if one is specified in ONC
427 // or one was configured by the UI. Otherwise it is L2TP/IPSec with
428 // PSK and doesn't require a certificate.
430 // TODO(benchan): Modify shill to specify the authentication type via
431 // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
432 // to deduce the authentication type based on the
433 // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
434 if (!vpn_client_cert_id
.empty() ||
435 cert_config_from_policy
.client_cert_type
!=
436 onc::client_cert::kClientCertTypeNone
) {
437 client_cert_type
= client_cert::CONFIG_TYPE_IPSEC
;
440 } else if (type
== shill::kTypeWifi
&& security
== shill::kSecurity8021x
) {
441 client_cert_type
= client_cert::CONFIG_TYPE_EAP
;
444 base::DictionaryValue config_properties
;
445 if (client_cert_type
!= client_cert::CONFIG_TYPE_NONE
) {
446 // Note: if we get here then a certificate *may* be required, so we want
447 // to ensure that certificates have loaded successfully before attempting
450 // User must be logged in to connect to a network requiring a certificate.
451 if (!logged_in_
|| !cert_loader_
) {
452 NET_LOG_ERROR("User not logged in", "");
453 ErrorCallbackForPendingRequest(service_path
, kErrorCertificateRequired
);
456 // If certificates have not been loaded yet, queue the connect request.
457 if (!certificates_loaded_
) {
458 NET_LOG_EVENT("Certificates not loaded", "");
459 QueueConnectRequest(service_path
);
463 // Check certificate properties from policy.
464 if (cert_config_from_policy
.client_cert_type
==
465 onc::client_cert::kPattern
) {
466 if (!ClientCertResolver::ResolveCertificatePatternSync(
468 cert_config_from_policy
.pattern
,
469 &config_properties
)) {
470 ErrorCallbackForPendingRequest(service_path
, kErrorCertificateRequired
);
473 } else if (check_error_state
&&
474 !client_cert::IsCertificateConfigured(client_cert_type
,
475 service_properties
)) {
476 // Network may not be configured.
477 ErrorCallbackForPendingRequest(service_path
, kErrorConfigurationRequired
);
482 if (type
== shill::kTypeVPN
) {
483 // VPN may require a username, and/or passphrase to be set. (Check after
484 // ensuring that any required certificates are configured).
485 DCHECK(provider_properties
);
486 if (VPNRequiresCredentials(
487 service_path
, vpn_provider_type
, *provider_properties
)) {
488 NET_LOG_USER("VPN Requires Credentials", service_path
);
489 ErrorCallbackForPendingRequest(service_path
, kErrorConfigurationRequired
);
493 // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
495 if (client_cert_type
== client_cert::CONFIG_TYPE_NONE
) {
496 CallShillConnect(service_path
);
501 if (!config_properties
.empty()) {
502 NET_LOG_EVENT("Configuring Network", service_path
);
503 configuration_handler_
->SetProperties(
506 NetworkConfigurationObserver::SOURCE_USER_ACTION
,
507 base::Bind(&NetworkConnectionHandler::CallShillConnect
,
510 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure
,
516 // Otherwise, we probably still need to configure the network since
517 // 'Connectable' is false. If |check_error_state| is true, signal an
518 // error, otherwise attempt to connect to possibly gain additional error
519 // state from Shill (or in case 'Connectable' is improperly unset).
520 if (check_error_state
)
521 ErrorCallbackForPendingRequest(service_path
, kErrorConfigurationRequired
);
523 CallShillConnect(service_path
);
526 void NetworkConnectionHandler::QueueConnectRequest(
527 const std::string
& service_path
) {
528 ConnectRequest
* request
= GetPendingRequest(service_path
);
530 NET_LOG_ERROR("No pending request to queue", service_path
);
534 const int kMaxCertLoadTimeSeconds
= 15;
535 base::TimeDelta dtime
= base::TimeTicks::Now() - logged_in_time_
;
536 if (dtime
> base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds
)) {
537 NET_LOG_ERROR("Certificate load timeout", service_path
);
538 InvokeErrorCallback(service_path
,
539 request
->error_callback
,
540 kErrorCertLoadTimeout
);
544 NET_LOG_EVENT("Connect Request Queued", service_path
);
545 queued_connect_
.reset(new ConnectRequest(
546 service_path
, request
->profile_path
,
547 request
->success_callback
, request
->error_callback
));
548 pending_requests_
.erase(service_path
);
550 // Post a delayed task to check to see if certificates have loaded. If they
551 // haven't, and queued_connect_ has not been cleared (e.g. by a successful
552 // connect request), cancel the request and notify the user.
553 base::MessageLoopProxy::current()->PostDelayedTask(
555 base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded
,
557 base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds
) - dtime
);
560 void NetworkConnectionHandler::CheckCertificatesLoaded() {
561 if (certificates_loaded_
)
563 // If queued_connect_ has been cleared (e.g. another connect request occurred
564 // and wasn't queued), do nothing here.
565 if (!queued_connect_
)
567 // Otherwise, notify the user.
568 NET_LOG_ERROR("Certificate load timeout", queued_connect_
->service_path
);
569 InvokeErrorCallback(queued_connect_
->service_path
,
570 queued_connect_
->error_callback
,
571 kErrorCertLoadTimeout
);
572 queued_connect_
.reset();
575 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
576 DCHECK(queued_connect_
);
578 // Make a copy of |queued_connect_| parameters, because |queued_connect_|
579 // will get reset at the beginning of |ConnectToNetwork|.
580 std::string service_path
= queued_connect_
->service_path
;
581 base::Closure success_callback
= queued_connect_
->success_callback
;
582 network_handler::ErrorCallback error_callback
=
583 queued_connect_
->error_callback
;
585 NET_LOG_EVENT("Connecting to Queued Network", service_path
);
586 ConnectToNetwork(service_path
, success_callback
, error_callback
,
587 false /* check_error_state */);
590 void NetworkConnectionHandler::CallShillConnect(
591 const std::string
& service_path
) {
592 NET_LOG_EVENT("Sending Connect Request to Shill", service_path
);
593 network_state_handler_
->ClearLastErrorForNetwork(service_path
);
594 DBusThreadManager::Get()->GetShillServiceClient()->Connect(
595 dbus::ObjectPath(service_path
),
596 base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess
,
597 AsWeakPtr(), service_path
),
598 base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure
,
599 AsWeakPtr(), service_path
));
602 void NetworkConnectionHandler::HandleConfigurationFailure(
603 const std::string
& service_path
,
604 const std::string
& error_name
,
605 scoped_ptr
<base::DictionaryValue
> error_data
) {
606 ConnectRequest
* request
= GetPendingRequest(service_path
);
608 NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
612 network_handler::ErrorCallback error_callback
= request
->error_callback
;
613 pending_requests_
.erase(service_path
);
614 if (!error_callback
.is_null())
615 error_callback
.Run(kErrorConfigureFailed
, error_data
.Pass());
618 void NetworkConnectionHandler::HandleShillConnectSuccess(
619 const std::string
& service_path
) {
620 ConnectRequest
* request
= GetPendingRequest(service_path
);
622 NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
626 request
->connect_state
= ConnectRequest::CONNECT_STARTED
;
627 NET_LOG_EVENT("Connect Request Acknowledged", service_path
);
628 // Do not call success_callback here, wait for one of the following
630 // * State transitions to a non connecting state indicating success or failure
631 // * Network is no longer in the visible list, indicating failure
632 CheckPendingRequest(service_path
);
635 void NetworkConnectionHandler::HandleShillConnectFailure(
636 const std::string
& service_path
,
637 const std::string
& dbus_error_name
,
638 const std::string
& dbus_error_message
) {
639 ConnectRequest
* request
= GetPendingRequest(service_path
);
641 NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
645 network_handler::ErrorCallback error_callback
= request
->error_callback
;
646 pending_requests_
.erase(service_path
);
647 network_handler::ShillErrorCallbackFunction(
648 shill::kErrorConnectFailed
, service_path
, error_callback
,
649 dbus_error_name
, dbus_error_message
);
652 void NetworkConnectionHandler::CheckPendingRequest(
653 const std::string service_path
) {
654 ConnectRequest
* request
= GetPendingRequest(service_path
);
656 if (request
->connect_state
== ConnectRequest::CONNECT_REQUESTED
)
657 return; // Request has not started, ignore update
658 const NetworkState
* network
=
659 network_state_handler_
->GetNetworkState(service_path
);
661 return; // NetworkState may not be be updated yet.
663 if (network
->IsConnectingState()) {
664 request
->connect_state
= ConnectRequest::CONNECT_CONNECTING
;
667 if (network
->IsConnectedState()) {
668 NET_LOG_EVENT("Connect Request Succeeded", service_path
);
669 if (!request
->profile_path
.empty()) {
670 // If a profile path was specified, set it on a successful connection.
671 configuration_handler_
->SetNetworkProfile(
673 request
->profile_path
,
674 NetworkConfigurationObserver::SOURCE_USER_ACTION
,
675 base::Bind(&base::DoNothing
),
676 chromeos::network_handler::ErrorCallback());
678 if (!request
->success_callback
.is_null())
679 request
->success_callback
.Run();
680 pending_requests_
.erase(service_path
);
683 if (network
->connection_state() == shill::kStateIdle
&&
684 request
->connect_state
!= ConnectRequest::CONNECT_CONNECTING
) {
685 // Connection hasn't started yet, keep waiting.
689 // Network is neither connecting or connected; an error occurred.
690 std::string error_name
; // 'Canceled' or 'Failed'
691 if (network
->connection_state() == shill::kStateIdle
&&
692 pending_requests_
.size() > 1) {
693 // Another connect request canceled this one.
694 error_name
= kErrorConnectCanceled
;
696 error_name
= shill::kErrorConnectFailed
;
697 if (network
->connection_state() != shill::kStateFailure
) {
698 NET_LOG_ERROR("Unexpected State: " + network
->connection_state(),
703 network_handler::ErrorCallback error_callback
= request
->error_callback
;
704 pending_requests_
.erase(service_path
);
705 if (error_callback
.is_null()) {
706 NET_LOG_ERROR("Connect Error, no callback: " + error_name
, service_path
);
709 InvokeErrorCallback(service_path
, error_callback
, error_name
);
712 void NetworkConnectionHandler::CheckAllPendingRequests() {
713 for (std::map
<std::string
, ConnectRequest
>::iterator iter
=
714 pending_requests_
.begin(); iter
!= pending_requests_
.end(); ++iter
) {
715 CheckPendingRequest(iter
->first
);
719 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
720 const std::string
& service_path
,
721 const std::string
& error_name
) {
722 ConnectRequest
* request
= GetPendingRequest(service_path
);
724 NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
728 // Remove the entry before invoking the callback in case it triggers a retry.
729 network_handler::ErrorCallback error_callback
= request
->error_callback
;
730 pending_requests_
.erase(service_path
);
731 InvokeErrorCallback(service_path
, error_callback
, error_name
);
736 void NetworkConnectionHandler::CallShillDisconnect(
737 const std::string
& service_path
,
738 const base::Closure
& success_callback
,
739 const network_handler::ErrorCallback
& error_callback
) {
740 NET_LOG_USER("Disconnect Request", service_path
);
741 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
742 dbus::ObjectPath(service_path
),
743 base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess
,
744 AsWeakPtr(), service_path
, success_callback
),
745 base::Bind(&network_handler::ShillErrorCallbackFunction
,
746 kErrorShillError
, service_path
, error_callback
));
749 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
750 const std::string
& service_path
,
751 const base::Closure
& success_callback
) {
752 NET_LOG_EVENT("Disconnect Request Sent", service_path
);
753 if (!success_callback
.is_null())
754 success_callback
.Run();
757 } // namespace chromeos