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