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