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