network_connection_handler.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// Use of this source code is governed by a BSD-style license that can be
3cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com// found in the LICENSE file.
4cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
5cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "chromeos/network/network_connection_handler.h"
6cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com
7cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "base/bind.h"
8cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "base/json/json_reader.h"
9cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com#include "base/location.h"
108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/message_loop/message_loop_proxy.h"
118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "base/strings/string_number_conversions.h"
128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/cert_loader.h"
138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/dbus/dbus_thread_manager.h"
148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/dbus/shill_manager_client.h"
158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/dbus/shill_service_client.h"
168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/certificate_pattern.h"
178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/client_cert_resolver.h"
188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/client_cert_util.h"
198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/managed_network_configuration_handler.h"
208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_configuration_handler.h"
218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_event_log.h"
228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_handler_callbacks.h"
238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_profile_handler.h"
248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_state.h"
258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/network_state_handler.h"
268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "chromeos/network/shill_property_util.h"
278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "dbus/object_path.h"
288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "net/cert/x509_certificate.h"
298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com#include "third_party/cros_system_api/dbus/service_constants.h"
308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace chromeos {
328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comnamespace {
348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid InvokeErrorCallback(const std::string& service_path,
368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                         const network_handler::ErrorCallback& error_callback,
378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                         const std::string& error_name) {
388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_ERROR("Connect Error: " + error_name, service_path);
398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  network_handler::RunErrorCallback(
408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      error_callback, service_path, error_name, "");
418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool IsAuthenticationError(const std::string& error) {
448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return (error == shill::kErrorBadWEPKey ||
458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          error == shill::kErrorPppAuthFailed ||
468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          error == shill::kErrorEapLocalTlsFailed ||
478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          error == shill::kErrorEapRemoteTlsFailed ||
488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          error == shill::kErrorEapAuthenticationFailed);
498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool VPNRequiresCredentials(const std::string& service_path,
528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                           const std::string& provider_type,
538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                           const base::DictionaryValue& provider_properties) {
548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (provider_type == shill::kProviderOpenVpn) {
558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    std::string username;
568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    provider_properties.GetStringWithoutPathExpansion(
578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        shill::kOpenVPNUserProperty, &username);
588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (username.empty()) {
598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("OpenVPN: No username", service_path);
608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return true;
618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bool passphrase_required = false;
638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    provider_properties.GetBooleanWithoutPathExpansion(
648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        shill::kPassphraseRequiredProperty, &passphrase_required);
658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (passphrase_required) {
668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return true;
688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NET_LOG_EVENT("OpenVPN Is Configured", service_path);
708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  } else {
718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bool passphrase_required = false;
728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    provider_properties.GetBooleanWithoutPathExpansion(
738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (passphrase_required) {
758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("VPN: PSK Required", service_path);
768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return true;
778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    provider_properties.GetBooleanWithoutPathExpansion(
798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        shill::kPassphraseRequiredProperty, &passphrase_required);
808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (passphrase_required) {
818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("VPN: Passphrase Required", service_path);
828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return true;
838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NET_LOG_EVENT("VPN Is Configured", service_path);
858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return false;
878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstd::string GetDefaultUserProfilePath(const NetworkState* network) {
908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!NetworkHandler::IsInitialized() ||
918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      (LoginState::IsInitialized() &&
928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       !LoginState::Get()->UserHasNetworkProfile()) ||
938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      (network && network->type() == shill::kTypeWifi &&
948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com       network->security() == shill::kSecurityNone)) {
958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return NetworkProfileHandler::GetSharedProfilePath();
968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  const NetworkProfile* profile  =
988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return profile ? profile->path
1008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 : NetworkProfileHandler::GetSharedProfilePath();
1018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}  // namespace
1048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
1068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorConnected[] = "connected";
1078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
1088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
1098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorPassphraseRequired[] =
1108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "passphrase-required";
1118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorActivationRequired[] =
1128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "activation-required";
1138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorCertificateRequired[] =
1148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "certificate-required";
1158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorConfigurationRequired[] =
1168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "configuration-required";
1178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
1188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "authentication-required";
1198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
1208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorConfigureFailed[] =
1218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "configure-failed";
1228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorConnectCanceled[] =
1238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "connect-canceled";
1248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comconst char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
1258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    "cert-load-timeout";
1268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comstruct NetworkConnectionHandler::ConnectRequest {
1288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ConnectRequest(const std::string& service_path,
1298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 const std::string& profile_path,
1308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 const base::Closure& success,
1318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 const network_handler::ErrorCallback& error)
1328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      : service_path(service_path),
1338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        profile_path(profile_path),
1348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        connect_state(CONNECT_REQUESTED),
1358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        success_callback(success),
1368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        error_callback(error) {
1378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  enum ConnectState {
1398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CONNECT_REQUESTED = 0,
1408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CONNECT_STARTED = 1,
1418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CONNECT_CONNECTING = 2
1428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  };
1438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string service_path;
1448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string profile_path;
1458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  ConnectState connect_state;
1468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::Closure success_callback;
1478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  network_handler::ErrorCallback error_callback;
1488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com};
1498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comNetworkConnectionHandler::NetworkConnectionHandler()
1518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    : cert_loader_(NULL),
1528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      network_state_handler_(NULL),
1538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      configuration_handler_(NULL),
1548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      logged_in_(false),
1558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      certificates_loaded_(false),
1568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      applied_autoconnect_policy_(false),
1578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      requested_connect_to_best_network_(false) {
1588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comNetworkConnectionHandler::~NetworkConnectionHandler() {
1618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (network_state_handler_)
1628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    network_state_handler_->RemoveObserver(this, FROM_HERE);
1638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (cert_loader_)
1648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    cert_loader_->RemoveObserver(this);
1658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (LoginState::IsInitialized())
1668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    LoginState::Get()->RemoveObserver(this);
1678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
1688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::Init(
1708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NetworkStateHandler* network_state_handler,
1718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NetworkConfigurationHandler* network_configuration_handler,
1728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
1738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (LoginState::IsInitialized())
1748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    LoginState::Get()->AddObserver(this);
1758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (CertLoader::IsInitialized()) {
1778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    cert_loader_ = CertLoader::Get();
1788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    cert_loader_->AddObserver(this);
1798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (cert_loader_->certificates_loaded()) {
1808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("Certificates Loaded", "");
1818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      certificates_loaded_ = true;
1828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
1838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  } else {
1848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // TODO(tbarzic): Require a mock or stub cert_loader in tests.
1858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NET_LOG_EVENT("Certificate Loader not initialized", "");
1868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    certificates_loaded_ = true;
1878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (network_state_handler) {
1908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    network_state_handler_ = network_state_handler;
1918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    network_state_handler_->AddObserver(this, FROM_HERE);
1928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  configuration_handler_ = network_configuration_handler;
1948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
1958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (managed_network_configuration_handler) {
1968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    managed_configuration_handler_ = managed_network_configuration_handler;
1978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    managed_configuration_handler_->AddObserver(this);
1988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
1998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // After this point, the NetworkConnectionHandler is fully initialized (all
2018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // handler references set, observers registered, ...).
2028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (LoginState::IsInitialized())
2048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    LoggedInStateChanged();
2058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::LoggedInStateChanged() {
2088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  LoginState* login_state = LoginState::Get();
2098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (logged_in_ || !login_state->IsUserLoggedIn())
2108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
2118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_EVENT("Logged In", "");
2138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  logged_in_ = true;
2148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  logged_in_time_ = base::TimeTicks::Now();
2158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DisconnectIfPolicyRequires();
2178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::OnCertificatesLoaded(
2208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const net::CertificateList& cert_list,
2218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bool initial_load) {
2228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  certificates_loaded_ = true;
2238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_EVENT("Certificates Loaded", "");
2248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (queued_connect_) {
2258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    ConnectToQueuedNetwork();
2268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  } else if (initial_load) {
2278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // Connecting to the "best" available network requires certificates to be
2288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // loaded. Try to connect now.
2298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    ConnectToBestNetworkAfterLogin();
2308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::PolicyChanged(const std::string& userhash) {
2348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Ignore user policies.
2358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!userhash.empty())
2368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
2378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  DisconnectIfPolicyRequires();
2388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
2398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::ConnectToNetwork(
2418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const std::string& service_path,
2428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const base::Closure& success_callback,
2438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const network_handler::ErrorCallback& error_callback,
2448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bool check_error_state) {
2458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_USER("ConnectToNetwork", service_path);
2468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Clear any existing queued connect request.
2478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  queued_connect_.reset();
2488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (HasConnectingNetwork(service_path)) {
2498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NET_LOG_USER("Connect Request While Pending", service_path);
2508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
2518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
2528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Check cached network state for connected, connecting, or unactivated
2558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // networks. These states will not be affected by a recent configuration.
2568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Note: NetworkState may not exist for a network that was recently
2578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // configured, in which case these checks do not apply anyway.
2588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  const NetworkState* network =
2598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      network_state_handler_->GetNetworkState(service_path);
2608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (network) {
2628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // For existing networks, perform some immediate consistency checks.
2638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (network->IsConnectedState()) {
2648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      InvokeErrorCallback(service_path, error_callback, kErrorConnected);
2658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
2668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
2678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (network->IsConnectingState()) {
2688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
2698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
2708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
2718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (check_error_state) {
2738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      const std::string& error = network->last_error();
2748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (error == shill::kErrorBadPassphrase) {
2758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        InvokeErrorCallback(service_path, error_callback, error);
2768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        return;
2778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
2788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (IsAuthenticationError(error)) {
2798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        InvokeErrorCallback(
2808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com            service_path, error_callback, kErrorAuthenticationRequired);
2818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        return;
2828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
2838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
2848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
2858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // If the network does not have a profile path, specify the correct default
2878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // profile here and set it once connected. Otherwise leave it empty to
2888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // indicate that it does not need to be set.
2898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string profile_path;
2908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!network || network->profile_path().empty())
2918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    profile_path = GetDefaultUserProfilePath(network);
2928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // All synchronous checks passed, add |service_path| to connecting list.
2948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  pending_requests_.insert(std::make_pair(
2958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      service_path,
2968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ConnectRequest(service_path, profile_path,
2978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                     success_callback, error_callback)));
2988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
2998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Connect immediately to 'connectable' networks.
3008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
3018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (network && network->connectable() && network->type() != shill::kTypeVPN) {
3028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CallShillConnect(service_path);
3038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
3048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Request additional properties to check. VerifyConfiguredAndConnect will
3078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // use only these properties, not cached properties, to ensure that they
3088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // are up to date after any recent configuration.
3098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  configuration_handler_->GetProperties(
3108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      service_path,
3118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
3128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 AsWeakPtr(), check_error_state),
3138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
3148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                 AsWeakPtr(), service_path));
3158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::DisconnectNetwork(
3188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const std::string& service_path,
3198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const base::Closure& success_callback,
3208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const network_handler::ErrorCallback& error_callback) {
3218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_USER("DisconnectNetwork", service_path);
3228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  const NetworkState* network =
3238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      network_state_handler_->GetNetworkState(service_path);
3248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!network) {
3258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
3268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
3278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!network->IsConnectedState()) {
3298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
3308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
3318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  CallShillDisconnect(service_path, success_callback, error_callback);
3338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool NetworkConnectionHandler::HasConnectingNetwork(
3368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const std::string& service_path) {
3378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return pending_requests_.count(service_path) != 0;
3388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.combool NetworkConnectionHandler::HasPendingConnectRequest() {
3418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return pending_requests_.size() > 0;
3428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::NetworkListChanged() {
3458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  CheckAllPendingRequests();
3468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::NetworkPropertiesUpdated(
3498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const NetworkState* network) {
3508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (HasConnectingNetwork(network->path()))
3518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CheckPendingRequest(network->path());
3528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comNetworkConnectionHandler::ConnectRequest*
3558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comNetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
3568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::map<std::string, ConnectRequest>::iterator iter =
3578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      pending_requests_.find(service_path);
3588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  return iter != pending_requests_.end() ? &(iter->second) : NULL;
3598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com}
3608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com// ConnectToNetwork implementation
3628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.comvoid NetworkConnectionHandler::VerifyConfiguredAndConnect(
3648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    bool check_error_state,
3658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const std::string& service_path,
3668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    const base::DictionaryValue& service_properties) {
3678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
3688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // If 'passphrase_required' is still true, then the 'Passphrase' property
3708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // has not been set to a minimum length value.
3718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bool passphrase_required = false;
3728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetBooleanWithoutPathExpansion(
3738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      shill::kPassphraseRequiredProperty, &passphrase_required);
3748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (passphrase_required) {
3758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
3768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
3778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string type, security;
3808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
3818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetStringWithoutPathExpansion(
3828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      shill::kSecurityProperty, &security);
3838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  bool connectable = false;
3848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetBooleanWithoutPathExpansion(
3858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      shill::kConnectableProperty, &connectable);
3868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // In case NetworkState was not available in ConnectToNetwork (e.g. it had
3888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // been recently configured), we need to check Connectable again.
3898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (connectable && type != shill::kTypeVPN) {
3908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
3918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    CallShillConnect(service_path);
3928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
3938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
3948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
3958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Get VPN provider type and host (required for configuration) and ensure
3968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // that required VPN non-cert properties are set.
3978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  const base::DictionaryValue* provider_properties = NULL;
3988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
3998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (type == shill::kTypeVPN) {
4008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // VPN Provider values are read from the "Provider" dictionary, not the
4018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // "Provider.Type", etc keys (which are used only to set the values).
4028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (service_properties.GetDictionaryWithoutPathExpansion(
4038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com            shill::kProviderProperty, &provider_properties)) {
4048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      provider_properties->GetStringWithoutPathExpansion(
4058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          shill::kTypeProperty, &vpn_provider_type);
4068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      provider_properties->GetStringWithoutPathExpansion(
4078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          shill::kHostProperty, &vpn_provider_host);
4088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      provider_properties->GetStringWithoutPathExpansion(
4098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
4108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
4128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
4138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
4148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string guid;
4188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
4198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  std::string profile;
4208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
4218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                                   &profile);
4228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  const base::DictionaryValue* user_policy =
4238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
4248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  client_cert::ClientCertConfig cert_config_from_policy;
4268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (user_policy)
4278cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
4288cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4298cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
4308cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (type == shill::kTypeVPN) {
4318cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (vpn_provider_type == shill::kProviderOpenVpn) {
4328cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
4338cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    } else {
4348cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // L2TP/IPSec only requires a certificate if one is specified in ONC
4358cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // or one was configured by the UI. Otherwise it is L2TP/IPSec with
4368cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // PSK and doesn't require a certificate.
4378cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      //
4388cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // TODO(benchan): Modify shill to specify the authentication type via
4398cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
4408cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // to deduce the authentication type based on the
4418cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
4428cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!vpn_client_cert_id.empty() ||
4438cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com          cert_config_from_policy.client_cert_type !=
4448cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              onc::client_cert::kClientCertTypeNone) {
4458cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
4468cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
4478cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4488cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
4498cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    client_cert_type = client_cert::CONFIG_TYPE_EAP;
4508cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4518cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4528cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  base::DictionaryValue config_properties;
4538cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
4548cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // Note: if we get here then a certificate *may* be required, so we want
4558cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // to ensure that certificates have loaded successfully before attempting
4568cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // to connect.
4578cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4588cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // User must be logged in to connect to a network requiring a certificate.
4598cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (!logged_in_ || !cert_loader_) {
4608cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_ERROR("User not logged in", "");
4618cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
4628cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
4638cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4648cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // If certificates have not been loaded yet, queue the connect request.
4658cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (!certificates_loaded_) {
4668cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_EVENT("Certificates not loaded", "");
4678cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      QueueConnectRequest(service_path);
4688cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
4698cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4708cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4718cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // Check certificate properties from policy.
4728cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (cert_config_from_policy.client_cert_type ==
4738cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        onc::client_cert::kPattern) {
4748cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      if (!ClientCertResolver::ResolveCertificatePatternSync(
4758cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              client_cert_type,
4768cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              cert_config_from_policy.pattern,
4778cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com              &config_properties)) {
4788cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
4798cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        return;
4808cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      }
4818cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    } else if (check_error_state &&
4828cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com               !client_cert::IsCertificateConfigured(client_cert_type,
4838cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                                                     service_properties)) {
4848cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      // Network may not be configured.
4858cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
4868cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
4878cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
4888cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
4898cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
4908cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (type == shill::kTypeVPN) {
4918cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // VPN may require a username, and/or passphrase to be set. (Check after
4928cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // ensuring that any required certificates are configured).
4938cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    DCHECK(provider_properties);
4948cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (VPNRequiresCredentials(
4958cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com            service_path, vpn_provider_type, *provider_properties)) {
4968cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      NET_LOG_USER("VPN Requires Credentials", service_path);
4978cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
4988cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
4998cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
5008cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5018cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
5028cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    // to connect.
5038cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
5048cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      CallShillConnect(service_path);
5058cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com      return;
5068cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    }
5078cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
5088cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5098cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  if (!config_properties.empty()) {
5108cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    NET_LOG_EVENT("Configuring Network", service_path);
5118cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    configuration_handler_->SetProperties(
5128cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        service_path,
5138cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        config_properties,
5148cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        base::Bind(&NetworkConnectionHandler::CallShillConnect,
5158cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                   AsWeakPtr(),
5168cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                   service_path),
5178cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com        base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
5188cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                   AsWeakPtr(),
5198cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com                   service_path));
5208cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com    return;
5218cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  }
5228cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com
5238cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // Otherwise, we probably still need to configure the network since
5248cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // 'Connectable' is false. If |check_error_state| is true, signal an
5258cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // error, otherwise attempt to connect to possibly gain additional error
5268cee797901763ab0922eb9ef484cfdcbc94bee54edisonn@google.com  // state from Shill (or in case 'Connectable' is improperly unset).
527cf2cfa174ca878c144e17e9fc60ca8e9070d7dededisonn@google.com  if (check_error_state)
528    ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
529  else
530    CallShillConnect(service_path);
531}
532
533void 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
567void 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
582void 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
597void 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
609void 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
625void 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
642void 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
659void 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
718void 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
725void 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
742void 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
755void 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
763void 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
773void 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