| Index: chromeos/network/network_connection_handler.cc
|
| diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0d98a45817973dbf8954932084676f84c5847dc2
|
| --- /dev/null
|
| +++ b/chromeos/network/network_connection_handler.cc
|
| @@ -0,0 +1,309 @@
|
| +// Copyright (c) 2013 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 "chromeos/network/network_connection_handler.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/json/json_reader.h"
|
| +#include "chromeos/dbus/dbus_thread_manager.h"
|
| +#include "chromeos/dbus/shill_manager_client.h"
|
| +#include "chromeos/dbus/shill_service_client.h"
|
| +#include "chromeos/network/cert_loader.h"
|
| +#include "chromeos/network/certificate_pattern_matcher.h"
|
| +#include "chromeos/network/managed_network_configuration_handler.h"
|
| +#include "chromeos/network/network_configuration_handler.h"
|
| +#include "chromeos/network/network_event_log.h"
|
| +#include "chromeos/network/network_handler_callbacks.h"
|
| +#include "chromeos/network/network_state.h"
|
| +#include "chromeos/network/network_state_handler.h"
|
| +#include "chromeos/network/network_ui_data.h"
|
| +#include "dbus/object_path.h"
|
| +#include "net/cert/x509_certificate.h"
|
| +#include "third_party/cros_system_api/dbus/service_constants.h"
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace {
|
| +
|
| +const char kLogModule[] = "NetworkConnectionHandler";
|
| +
|
| +void InvokeErrorCallback(
|
| + const std::string& service_path,
|
| + const network_handler::ErrorCallback& error_callback,
|
| + const std::string& error_name) {
|
| + network_handler::ShillErrorCallbackFunction(
|
| + kLogModule, service_path, error_callback, error_name, "Connect Error");
|
| +}
|
| +
|
| +bool NetworkMayNeedCredentials(const NetworkState* network) {
|
| + if (network->type() == flimflam::kTypeWifi &&
|
| + (network->security() == flimflam::kSecurity8021x ||
|
| + network->security() == flimflam::kSecurityWep /* For dynamic WEP*/))
|
| + return true;
|
| + if (network->type() == flimflam::kTypeVPN)
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| +bool NetworkRequiresActivation(const NetworkState* network) {
|
| + return (network->type() == flimflam::kTypeCellular &&
|
| + (network->activation_state() != flimflam::kActivationStateActivated ||
|
| + network->cellular_out_of_credits()));
|
| +}
|
| +
|
| +bool VPNIsConfigured(const base::DictionaryValue& properties) {
|
| + std::string provider_type;
|
| + // Note: we use Value path expansion to extract Provider.Type.
|
| + properties.GetString(flimflam::kProviderTypeProperty, &provider_type);
|
| + if (provider_type == flimflam::kProviderOpenVpn) {
|
| + std::string hostname;
|
| + properties.GetString(flimflam::kProviderHostProperty, &hostname);
|
| + if (hostname.empty())
|
| + return false;
|
| + std::string username;
|
| + properties.GetStringWithoutPathExpansion(
|
| + flimflam::kOpenVPNUserProperty, &username);
|
| + if (username.empty())
|
| + return false;
|
| + std::string client_cert_id;
|
| + properties.GetStringWithoutPathExpansion(
|
| + flimflam::kOpenVPNClientCertIdProperty, &client_cert_id);
|
| + if (client_cert_id.empty())
|
| + return false;
|
| + } else {
|
| + bool passphrase_required = false;
|
| + std::string passphrase;
|
| + properties.GetBooleanWithoutPathExpansion(
|
| + flimflam::kL2tpIpsecPskRequiredProperty, &passphrase_required);
|
| + properties.GetStringWithoutPathExpansion(
|
| + flimflam::kL2tpIpsecPskProperty, &passphrase);
|
| + if (passphrase_required && passphrase.empty())
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool CertificateIsConfigured(NetworkUIData* ui_data) {
|
| + if (ui_data->certificate_type() != CLIENT_CERT_TYPE_PATTERN)
|
| + return true; // No certificate or a reference.
|
| + if (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) {
|
| + // We skip checking certificate patterns for device policy ONC so that an
|
| + // unmanaged user can't get to the place where a cert is presented for them
|
| + // involuntarily.
|
| + return true;
|
| + }
|
| + if (ui_data->certificate_pattern().Empty())
|
| + return false;
|
| +
|
| + // Find the matching certificate.
|
| + scoped_refptr<net::X509Certificate> matching_cert =
|
| + certificate_pattern::GetCertificateMatch(
|
| + ui_data->certificate_pattern());
|
| + if (!matching_cert.get())
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +static NetworkConnectionHandler* g_connection_handler_instance = NULL;
|
| +
|
| +const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
|
| +const char NetworkConnectionHandler::kErrorConnected[] = "connected";
|
| +const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
|
| +const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
|
| +const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
|
| + "passphrase-required";
|
| +const char NetworkConnectionHandler::kErrorActivationRequired[] =
|
| + "activation-required";
|
| +const char NetworkConnectionHandler::kErrorCertificateRequired[] =
|
| + "certificate-required";
|
| +const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
|
| + "configuration-required";
|
| +const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
|
| +
|
| +// static
|
| +void NetworkConnectionHandler::Initialize() {
|
| + CHECK(!g_connection_handler_instance);
|
| + g_connection_handler_instance = new NetworkConnectionHandler;
|
| +}
|
| +
|
| +// static
|
| +void NetworkConnectionHandler::Shutdown() {
|
| + CHECK(g_connection_handler_instance);
|
| + delete g_connection_handler_instance;
|
| + g_connection_handler_instance = NULL;
|
| +}
|
| +
|
| +// static
|
| +NetworkConnectionHandler* NetworkConnectionHandler::Get() {
|
| + CHECK(g_connection_handler_instance)
|
| + << "NetworkConnectionHandler::Get() called before Initialize()";
|
| + return g_connection_handler_instance;
|
| +}
|
| +
|
| +NetworkConnectionHandler::NetworkConnectionHandler() {
|
| +}
|
| +
|
| +NetworkConnectionHandler::~NetworkConnectionHandler() {
|
| +}
|
| +
|
| +void NetworkConnectionHandler::ConnectToNetwork(
|
| + const std::string& service_path,
|
| + const base::Closure& success_callback,
|
| + const network_handler::ErrorCallback& error_callback) {
|
| + const NetworkState* network =
|
| + NetworkStateHandler::Get()->GetNetworkState(service_path);
|
| + if (!network) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
|
| + return;
|
| + }
|
| + if (network->IsConnectedState()) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorConnected);
|
| + return;
|
| + }
|
| + if (network->IsConnectingState() ||
|
| + pending_requests_.find(service_path) != pending_requests_.end()) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
|
| + return;
|
| + }
|
| + if (network->passphrase_required()) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorPassphraseRequired);
|
| + return;
|
| + }
|
| + if (NetworkRequiresActivation(network)) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorActivationRequired);
|
| + return;
|
| + }
|
| +
|
| + // All synchronous checks passed, add |service_path| to connecting list.
|
| + pending_requests_.insert(service_path);
|
| +
|
| + if (!network->connectable() && NetworkMayNeedCredentials(network)) {
|
| + // Request additional properties to check.
|
| + NetworkConfigurationHandler::Get()->GetProperties(
|
| + network->path(),
|
| + base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
|
| + AsWeakPtr(), success_callback, error_callback),
|
| + base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
|
| + AsWeakPtr(), network->path(), error_callback));
|
| + return;
|
| + }
|
| + // All checks passed, send connect request.
|
| + CallShillConnect(service_path, success_callback, error_callback);
|
| +}
|
| +
|
| +void NetworkConnectionHandler::DisconnectNetwork(
|
| + const std::string& service_path,
|
| + const base::Closure& success_callback,
|
| + const network_handler::ErrorCallback& error_callback) {
|
| + const NetworkState* network =
|
| + NetworkStateHandler::Get()->GetNetworkState(service_path);
|
| + if (!network) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
|
| + return;
|
| + }
|
| + if (!network->IsConnectedState()) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
|
| + return;
|
| + }
|
| + CallShillDisconnect(service_path, success_callback, error_callback);
|
| +}
|
| +
|
| +void NetworkConnectionHandler::CallShillConnect(
|
| + const std::string& service_path,
|
| + const base::Closure& success_callback,
|
| + const network_handler::ErrorCallback& error_callback) {
|
| + // TODO(stevenjb): Remove SetConnectingNetwork and use this class to maintain
|
| + // the connecting network(s) once NetworkLibrary path is eliminated.
|
| + NetworkStateHandler::Get()->SetConnectingNetwork(service_path);
|
| + network_event_log::AddEntry(kLogModule, "Connect Request", service_path);
|
| + DBusThreadManager::Get()->GetShillServiceClient()->Connect(
|
| + dbus::ObjectPath(service_path),
|
| + base::Bind(&NetworkConnectionHandler::HandleShillSuccess,
|
| + AsWeakPtr(), service_path, success_callback),
|
| + base::Bind(&NetworkConnectionHandler::HandleShillFailure,
|
| + AsWeakPtr(), service_path, error_callback));
|
| +}
|
| +
|
| +void NetworkConnectionHandler::CallShillDisconnect(
|
| + const std::string& service_path,
|
| + const base::Closure& success_callback,
|
| + const network_handler::ErrorCallback& error_callback) {
|
| + network_event_log::AddEntry(kLogModule, "Disconnect Request", service_path);
|
| + DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
|
| + dbus::ObjectPath(service_path),
|
| + base::Bind(&NetworkConnectionHandler::HandleShillSuccess,
|
| + AsWeakPtr(), service_path, success_callback),
|
| + base::Bind(&NetworkConnectionHandler::HandleShillFailure,
|
| + AsWeakPtr(), service_path, error_callback));
|
| +}
|
| +
|
| +void NetworkConnectionHandler::VerifyConfiguredAndConnect(
|
| + const base::Closure& success_callback,
|
| + const network_handler::ErrorCallback& error_callback,
|
| + const std::string& service_path,
|
| + const base::DictionaryValue& properties) {
|
| + const NetworkState* network =
|
| + NetworkStateHandler::Get()->GetNetworkState(service_path);
|
| + if (!network) {
|
| + InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
|
| + return;
|
| + }
|
| +
|
| + // VPN requires a host and username to be set.
|
| + if (network->type() == flimflam::kTypeVPN &&
|
| + !VPNIsConfigured(properties)) {
|
| + InvokeErrorCallback(service_path, error_callback,
|
| + kErrorConfigurationRequired);
|
| + return;
|
| + }
|
| +
|
| + // Check certificate properties in kUIDataProperty.
|
| + scoped_ptr<NetworkUIData> ui_data =
|
| + ManagedNetworkConfigurationHandler::GetUIData(properties);
|
| + if (ui_data && !CertificateIsConfigured(ui_data.get())) {
|
| + InvokeErrorCallback(service_path, error_callback,
|
| + kErrorCertificateRequired);
|
| + return;
|
| + }
|
| +
|
| + CallShillConnect(service_path, success_callback, error_callback);
|
| +}
|
| +
|
| +void NetworkConnectionHandler::HandleConfigurationFailure(
|
| + const std::string& service_path,
|
| + const network_handler::ErrorCallback& error_callback,
|
| + const std::string& error_name,
|
| + scoped_ptr<base::DictionaryValue> error_data) {
|
| + pending_requests_.erase(service_path);
|
| + if (!error_callback.is_null())
|
| + error_callback.Run(error_name, error_data.Pass());
|
| +}
|
| +
|
| +void NetworkConnectionHandler::HandleShillSuccess(
|
| + const std::string& service_path,
|
| + const base::Closure& success_callback) {
|
| + // TODO(stevenjb): Currently, this only indicates that the connect request
|
| + // succeeded. It might be preferable to wait for the actually connect
|
| + // attempt to succeed or fail here and only call |success_callback| at that
|
| + // point (or maybe call it twice, once indicating in-progress, then success
|
| + // or failure).
|
| + pending_requests_.erase(service_path);
|
| + network_event_log::AddEntry(kLogModule, "Connected", service_path);
|
| + success_callback.Run();
|
| +}
|
| +
|
| +void NetworkConnectionHandler::HandleShillFailure(
|
| + const std::string& service_path,
|
| + const network_handler::ErrorCallback& error_callback,
|
| + const std::string& error_name,
|
| + const std::string& error_message) {
|
| + pending_requests_.erase(service_path);
|
| + std::string error = "Connect Failure: " + error_name + ": " + error_message;
|
| + network_handler::ShillErrorCallbackFunction(
|
| + kLogModule, service_path, error_callback, error_name, error_message);
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|