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