blob: 77db56ff010894c38c22f247042f8ad846d786ae [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <set>
#include <string>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chromeos/cert_loader.h"
#include "chromeos/chromeos_export.h"
#include "chromeos/dbus/dbus_method_call_status.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_policy_observer.h"
#include "chromeos/network/network_state_handler_observer.h"
namespace chromeos {
class NetworkState;
class NetworkUIData;
// The NetworkConnectionHandler class is used to manage network connection
// requests. This is the only class that should make Shill Connect calls.
// It handles the following steps:
// 1. Determine whether or not sufficient information (e.g. passphrase) is
// known to be available to connect to the network.
// 2. Request additional information (e.g. user data which contains certificate
// information) and determine whether sufficient information is available.
// 3. Possibly configure the network certificate info (tpm slot and pkcs11 id).
// 4. Send the connect request.
// 5. Wait for the network state to change to a non connecting state.
// 6. Invoke the appropriate callback (always) on success or failure.
// NetworkConnectionHandler depends on NetworkStateHandler for immediately
// available State information, and NetworkConfigurationHandler for any
// configuration calls.
class CHROMEOS_EXPORT NetworkConnectionHandler
: public LoginState::Observer,
public CertLoader::Observer,
public NetworkStateHandlerObserver,
public NetworkPolicyObserver,
public base::SupportsWeakPtr<NetworkConnectionHandler> {
// Constants for |error_name| from |error_callback| for Connect.
// No network matching |service_path| is found (hidden networks must be
// configured before connecting).
static const char kErrorNotFound[];
// Already connected to the network.
static const char kErrorConnected[];
// Already connecting to the network.
static const char kErrorConnecting[];
// The passphrase is missing or invalid.
static const char kErrorPassphraseRequired[];
static const char kErrorActivationRequired[];
// The network requires a cert and none exists.
static const char kErrorCertificateRequired[];
// The network had an authentication error, indicating that additional or
// different authentication information is required.
static const char kErrorAuthenticationRequired[];
// Additional configuration is required.
static const char kErrorConfigurationRequired[];
// Configuration failed during the configure stage of the connect flow.
static const char kErrorConfigureFailed[];
// For Disconnect or Activate, an unexpected DBus or Shill error occurred.
static const char kErrorShillError[];
// A new network connect request canceled this one.
static const char kErrorConnectCanceled[];
// Constants for |error_name| from |error_callback| for Disconnect.
static const char kErrorNotConnected[];
// Certificate load timed out.
static const char kErrorCertLoadTimeout[];
virtual ~NetworkConnectionHandler();
// ConnectToNetwork() will start an asynchronous connection attempt.
// On success, |success_callback| will be called.
// On failure, |error_callback| will be called with |error_name| one of the
// constants defined above, or shill::kErrorConnectFailed or
// shill::kErrorBadPassphrase if the Shill Error property (from a
// previous connect attempt) was set to one of those.
// |error_message| will contain an additional error string for debugging.
// If |check_error_state| is true, the current state of the network is
// checked for errors, otherwise current state is ignored (e.g. for recently
// configured networks or repeat attempts).
void ConnectToNetwork(const std::string& service_path,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback,
bool check_error_state);
// DisconnectNetwork() will send a Disconnect request to Shill.
// On success, |success_callback| will be called.
// On failure, |error_callback| will be called with |error_name| one of:
// kErrorNotFound if no network matching |service_path| is found.
// kErrorNotConnected if not connected to the network.
// kErrorShillError if a DBus or Shill error occurred.
// |error_message| will contain and additional error string for debugging.
void DisconnectNetwork(const std::string& service_path,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback);
// Returns true if ConnectToNetwork has been called with |service_path| and
// has not completed (i.e. success or error callback has been called).
bool HasConnectingNetwork(const std::string& service_path);
// Returns true if there are any pending connect requests.
bool HasPendingConnectRequest();
// NetworkStateHandlerObserver
virtual void NetworkListChanged() OVERRIDE;
virtual void NetworkPropertiesUpdated(const NetworkState* network) OVERRIDE;
// LoginState::Observer
virtual void LoggedInStateChanged() OVERRIDE;
// CertLoader::Observer
virtual void OnCertificatesLoaded(const net::CertificateList& cert_list,
bool initial_load) OVERRIDE;
// NetworkPolicyObserver
virtual void PolicyChanged(const std::string& userhash) OVERRIDE;
friend class NetworkHandler;
friend class NetworkConnectionHandlerTest;
struct ConnectRequest;
void Init(NetworkStateHandler* network_state_handler,
NetworkConfigurationHandler* network_configuration_handler,
ConnectRequest* GetPendingRequest(const std::string& service_path);
// Callback from Shill.Service.GetProperties. Parses |properties| to verify
// whether or not the network appears to be configured. If configured,
// attempts a connection, otherwise invokes error_callback from
// pending_requests_[service_path]. |check_error_state| is passed from
// ConnectToNetwork(), see comment for info.
void VerifyConfiguredAndConnect(bool check_error_state,
const std::string& service_path,
const base::DictionaryValue& properties);
// Queues a connect request until certificates have loaded.
void QueueConnectRequest(const std::string& service_path);
// Checks to see if certificates have loaded and if not, cancels any queued
// connect request and notifies the user.
void CheckCertificatesLoaded();
// Handles connecting to a queued network after certificates are loaded or
// handle cert load timeout.
void ConnectToQueuedNetwork();
// Calls Shill.Manager.Connect asynchronously.
void CallShillConnect(const std::string& service_path);
// Handles failure from ConfigurationHandler calls.
void HandleConfigurationFailure(
const std::string& service_path,
const std::string& error_name,
scoped_ptr<base::DictionaryValue> error_data);
// Handles success or failure from Shill.Service.Connect.
void HandleShillConnectSuccess(const std::string& service_path);
void HandleShillConnectFailure(const std::string& service_path,
const std::string& error_name,
const std::string& error_message);
void CheckPendingRequest(const std::string service_path);
void CheckAllPendingRequests();
// Returns the PKCS#11 ID of a cert matching the certificate pattern in
// |ui_data|. Returns empty string otherwise.
std::string CertificateIsConfigured(NetworkUIData* ui_data);
void ErrorCallbackForPendingRequest(const std::string& service_path,
const std::string& error_name);
// Calls Shill.Manager.Disconnect asynchronously.
void CallShillDisconnect(
const std::string& service_path,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback);
// Handle success from Shill.Service.Disconnect.
void HandleShillDisconnectSuccess(const std::string& service_path,
const base::Closure& success_callback);
// If the policy to prevent unmanaged & shared networks to autoconnect is
// enabled, then disconnect all such networks except wired networks. Does
// nothing on consecutive calls.
// This is enforced once after a user logs in 1) to allow mananged networks to
// autoconnect and 2) to prevent a previous user from foisting a network on
// the new user. Therefore, this function is called on startup, at login and
// when the device policy is changed.
void DisconnectIfPolicyRequires();
// Requests a connect to the 'best' available network once after login and
// after any disconnect required by policy is executed (see
// DisconnectIfPolicyRequires()). To include networks with client
// certificates, no request is sent until certificates are loaded. Therefore,
// this function is called on the initial certificate load and by
// DisconnectIfPolicyRequires().
void ConnectToBestNetworkAfterLogin();
// Local references to the associated handler instances.
CertLoader* cert_loader_;
NetworkStateHandler* network_state_handler_;
NetworkConfigurationHandler* configuration_handler_;
ManagedNetworkConfigurationHandler* managed_configuration_handler_;
// Map of pending connect requests, used to prevent repeated attempts while
// waiting for Shill and to trigger callbacks on eventual success or failure.
std::map<std::string, ConnectRequest> pending_requests_;
scoped_ptr<ConnectRequest> queued_connect_;
// Track certificate loading state.
bool logged_in_;
bool certificates_loaded_;
base::TimeTicks logged_in_time_;
// Whether the autoconnect policy was applied already, see
// DisconnectIfPolicyRequires().
bool applied_autoconnect_policy_;
// Whether the handler already requested a 'ConnectToBestNetwork' after login,
// see ConnectToBestNetworkAfterLogin().
bool requested_connect_to_best_network_;
} // namespace chromeos