blob: 1ea9f649b2d960e8f69fb18a9e0b5c56bb3e984b [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 "chrome/browser/chromeos/cros/network_library_impl_base.h"
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_vector.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chromeos/cros/network_constants.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/net/onc_utils.h"
#include "chrome/browser/chromeos/network_login_observer.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_ui_data.h"
#include "chromeos/network/onc/onc_constants.h"
#include "chromeos/network/onc/onc_normalizer.h"
#include "chromeos/network/onc/onc_signature.h"
#include "chromeos/network/onc/onc_translator.h"
#include "chromeos/network/onc/onc_utils.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/nss_util.h" // crypto::GetTPMTokenInfo() for 802.1X and VPN.
#include "third_party/cros_system_api/dbus/service_constants.h"
using content::BrowserThread;
namespace chromeos {
namespace {
// Only send network change notifications to observers once every 50ms.
const int kNetworkNotifyDelayMs = 50;
// How long we should remember that cellular plan payment was received.
const int kRecentPlanPaymentHours = 6;
NetworkProfileType GetProfileTypeForSource(onc::ONCSource source) {
switch (source) {
case onc::ONC_SOURCE_DEVICE_POLICY:
return PROFILE_SHARED;
case onc::ONC_SOURCE_USER_POLICY:
return PROFILE_USER;
case onc::ONC_SOURCE_NONE:
case onc::ONC_SOURCE_USER_IMPORT:
return PROFILE_NONE;
}
NOTREACHED() << "Unknown ONC source " << source;
return PROFILE_NONE;
}
} // namespace
NetworkLibraryImplBase::NetworkLibraryImplBase()
: ethernet_(NULL),
active_wifi_(NULL),
active_cellular_(NULL),
active_wimax_(NULL),
active_virtual_(NULL),
available_devices_(0),
uninitialized_devices_(0),
enabled_devices_(0),
busy_devices_(0),
wifi_scanning_(false),
is_locked_(false),
sim_operation_(SIM_OPERATION_NONE),
notify_manager_weak_factory_(this) {
network_login_observer_.reset(new NetworkLoginObserver());
AddNetworkManagerObserver(network_login_observer_.get());
}
NetworkLibraryImplBase::~NetworkLibraryImplBase() {
network_profile_observers_.Clear();
network_manager_observers_.Clear();
pin_operation_observers_.Clear();
STLDeleteValues(&network_map_);
ClearNetworks();
DeleteRememberedNetworks();
STLDeleteValues(&device_map_);
STLDeleteValues(&network_device_observers_);
STLDeleteValues(&network_observers_);
STLDeleteValues(&network_onc_map_);
}
//////////////////////////////////////////////////////////////////////////////
// NetworkLibrary implementation.
void NetworkLibraryImplBase::AddNetworkProfileObserver(
NetworkProfileObserver* observer) {
network_profile_observers_.AddObserver(observer);
}
void NetworkLibraryImplBase::RemoveNetworkProfileObserver(
NetworkProfileObserver* observer) {
network_profile_observers_.RemoveObserver(observer);
}
void NetworkLibraryImplBase::AddNetworkManagerObserver(
NetworkManagerObserver* observer) {
if (!network_manager_observers_.HasObserver(observer))
network_manager_observers_.AddObserver(observer);
}
void NetworkLibraryImplBase::RemoveNetworkManagerObserver(
NetworkManagerObserver* observer) {
network_manager_observers_.RemoveObserver(observer);
}
void NetworkLibraryImplBase::AddNetworkObserver(
const std::string& service_path, NetworkObserver* observer) {
// First, add the observer to the callback map.
NetworkObserverMap::iterator iter = network_observers_.find(service_path);
NetworkObserverList* oblist;
if (iter != network_observers_.end()) {
oblist = iter->second;
} else {
oblist = new NetworkObserverList();
network_observers_[service_path] = oblist;
}
if (observer && !oblist->HasObserver(observer))
oblist->AddObserver(observer);
MonitorNetworkStart(service_path);
}
void NetworkLibraryImplBase::RemoveNetworkObserver(
const std::string& service_path, NetworkObserver* observer) {
DCHECK(service_path.size());
NetworkObserverMap::iterator map_iter =
network_observers_.find(service_path);
if (map_iter != network_observers_.end()) {
map_iter->second->RemoveObserver(observer);
if (!map_iter->second->size()) {
MonitorNetworkStop(service_path);
delete map_iter->second;
network_observers_.erase(map_iter);
}
}
}
void NetworkLibraryImplBase::RemoveObserverForAllNetworks(
NetworkObserver* observer) {
DCHECK(observer);
NetworkObserverMap::iterator map_iter = network_observers_.begin();
while (map_iter != network_observers_.end()) {
map_iter->second->RemoveObserver(observer);
if (!map_iter->second->size()) {
MonitorNetworkStop(map_iter->first);
delete map_iter->second;
network_observers_.erase(map_iter++);
} else {
++map_iter;
}
}
}
void NetworkLibraryImplBase::AddNetworkDeviceObserver(
const std::string& device_path, NetworkDeviceObserver* observer) {
// First, add the observer to the callback map.
NetworkDeviceObserverMap::iterator iter =
network_device_observers_.find(device_path);
NetworkDeviceObserverList* oblist;
if (iter != network_device_observers_.end()) {
oblist = iter->second;
} else {
oblist = new NetworkDeviceObserverList();
network_device_observers_[device_path] = oblist;
}
if (!oblist->HasObserver(observer))
oblist->AddObserver(observer);
MonitorNetworkDeviceStart(device_path);
}
void NetworkLibraryImplBase::RemoveNetworkDeviceObserver(
const std::string& device_path, NetworkDeviceObserver* observer) {
DCHECK(device_path.size());
NetworkDeviceObserverMap::iterator map_iter =
network_device_observers_.find(device_path);
if (map_iter != network_device_observers_.end()) {
map_iter->second->RemoveObserver(observer);
}
}
void NetworkLibraryImplBase::DeleteDeviceFromDeviceObserversMap(
const std::string& device_path) {
// Delete all device observers associated with this device.
NetworkDeviceObserverMap::iterator map_iter =
network_device_observers_.find(device_path);
if (map_iter != network_device_observers_.end()) {
delete map_iter->second;
network_device_observers_.erase(map_iter);
}
}
//////////////////////////////////////////////////////////////////////////////
void NetworkLibraryImplBase::AddPinOperationObserver(
PinOperationObserver* observer) {
if (!pin_operation_observers_.HasObserver(observer))
pin_operation_observers_.AddObserver(observer);
}
void NetworkLibraryImplBase::RemovePinOperationObserver(
PinOperationObserver* observer) {
pin_operation_observers_.RemoveObserver(observer);
}
const EthernetNetwork* NetworkLibraryImplBase::ethernet_network() const {
return ethernet_;
}
bool NetworkLibraryImplBase::ethernet_connecting() const {
return ethernet_ ? ethernet_->connecting() : false;
}
bool NetworkLibraryImplBase::ethernet_connected() const {
return ethernet_ ? ethernet_->connected() : false;
}
const WifiNetwork* NetworkLibraryImplBase::wifi_network() const {
return active_wifi_;
}
bool NetworkLibraryImplBase::wifi_connecting() const {
return active_wifi_ ? active_wifi_->connecting() : false;
}
bool NetworkLibraryImplBase::wifi_connected() const {
return active_wifi_ ? active_wifi_->connected() : false;
}
const CellularNetwork* NetworkLibraryImplBase::cellular_network() const {
return active_cellular_;
}
bool NetworkLibraryImplBase::cellular_connecting() const {
return active_cellular_ ? active_cellular_->connecting() : false;
}
bool NetworkLibraryImplBase::cellular_connected() const {
return active_cellular_ ? active_cellular_->connected() : false;
}
const WimaxNetwork* NetworkLibraryImplBase::wimax_network() const {
return active_wimax_;
}
bool NetworkLibraryImplBase::wimax_connecting() const {
return active_wimax_ ? active_wimax_->connecting() : false;
}
bool NetworkLibraryImplBase::wimax_connected() const {
return active_wimax_ ? active_wimax_->connected() : false;
}
const VirtualNetwork* NetworkLibraryImplBase::virtual_network() const {
return active_virtual_;
}
bool NetworkLibraryImplBase::virtual_network_connecting() const {
return active_virtual_ ? active_virtual_->connecting() : false;
}
bool NetworkLibraryImplBase::virtual_network_connected() const {
return active_virtual_ ? active_virtual_->connected() : false;
}
bool NetworkLibraryImplBase::Connected() const {
return ethernet_connected() || wifi_connected() ||
cellular_connected() || wimax_connected();
}
bool NetworkLibraryImplBase::Connecting() const {
return ethernet_connecting() || wifi_connecting() ||
cellular_connecting() || wimax_connecting();
}
const WifiNetworkVector& NetworkLibraryImplBase::wifi_networks() const {
return wifi_networks_;
}
const WifiNetworkVector&
NetworkLibraryImplBase::remembered_wifi_networks() const {
return remembered_wifi_networks_;
}
const CellularNetworkVector& NetworkLibraryImplBase::cellular_networks() const {
return cellular_networks_;
}
const WimaxNetworkVector& NetworkLibraryImplBase::wimax_networks() const {
return wimax_networks_;
}
const VirtualNetworkVector& NetworkLibraryImplBase::virtual_networks() const {
return virtual_networks_;
}
const VirtualNetworkVector&
NetworkLibraryImplBase::remembered_virtual_networks() const {
return remembered_virtual_networks_;
}
namespace {
// Use shill's ordering of the services to determine which type of
// network to return (i.e. don't assume priority of network types).
// Note: This does not include any virtual networks.
const Network* highest_priority(const Network* a, const Network*b) {
if (!a)
return b;
if (!b)
return a;
if (b->priority_order() < a->priority_order())
return b;
return a;
}
} // namespace
const Network* NetworkLibraryImplBase::active_network() const {
const Network* result = active_nonvirtual_network();
if (active_virtual_ && active_virtual_->is_active())
result = highest_priority(result, active_virtual_);
return result;
}
const Network* NetworkLibraryImplBase::active_nonvirtual_network() const {
const Network* result = NULL;
if (ethernet_ && ethernet_->is_active())
result = ethernet_;
if (active_wifi_ && active_wifi_->is_active())
result = highest_priority(result, active_wifi_);
if (active_cellular_ && active_cellular_->is_active())
result = highest_priority(result, active_cellular_);
if (active_wimax_ && active_wimax_->is_active())
result = highest_priority(result, active_wimax_);
return result;
}
const Network* NetworkLibraryImplBase::connected_network() const {
const Network* result = NULL;
if (ethernet_ && ethernet_->connected())
result = ethernet_;
if (active_wifi_ && active_wifi_->connected())
result = highest_priority(result, active_wifi_);
if (active_cellular_ && active_cellular_->connected())
result = highest_priority(result, active_cellular_);
if (active_wimax_ && active_wimax_->connected())
result = highest_priority(result, active_wimax_);
return result;
}
// Connecting order in logical preference.
const Network* NetworkLibraryImplBase::connecting_network() const {
if (ethernet_connecting())
return ethernet_network();
else if (wifi_connecting())
return wifi_network();
else if (cellular_connecting())
return cellular_network();
else if (wimax_connecting())
return wimax_network();
return NULL;
}
bool NetworkLibraryImplBase::ethernet_available() const {
return available_devices_ & (1 << TYPE_ETHERNET);
}
bool NetworkLibraryImplBase::wifi_available() const {
return available_devices_ & (1 << TYPE_WIFI);
}
bool NetworkLibraryImplBase::wimax_available() const {
return available_devices_ & (1 << TYPE_WIMAX);
}
bool NetworkLibraryImplBase::cellular_available() const {
return available_devices_ & (1 << TYPE_CELLULAR);
}
bool NetworkLibraryImplBase::ethernet_enabled() const {
return enabled_devices_ & (1 << TYPE_ETHERNET);
}
bool NetworkLibraryImplBase::wifi_enabled() const {
return enabled_devices_ & (1 << TYPE_WIFI);
}
bool NetworkLibraryImplBase::wimax_enabled() const {
return enabled_devices_ & (1 << TYPE_WIMAX);
}
bool NetworkLibraryImplBase::cellular_enabled() const {
return enabled_devices_ & (1 << TYPE_CELLULAR);
}
bool NetworkLibraryImplBase::wifi_scanning() const {
return wifi_scanning_;
}
bool NetworkLibraryImplBase::cellular_initializing() const {
if (uninitialized_devices_ & (1 << TYPE_CELLULAR))
return true;
const NetworkDevice* device = FindDeviceByType(TYPE_CELLULAR);
if (device && device->scanning())
return true;
return false;
}
/////////////////////////////////////////////////////////////////////////////
const NetworkDevice* NetworkLibraryImplBase::FindNetworkDeviceByPath(
const std::string& path) const {
NetworkDeviceMap::const_iterator iter = device_map_.find(path);
if (iter != device_map_.end())
return iter->second;
LOG(WARNING) << "Device path not found: " << path;
return NULL;
}
NetworkDevice* NetworkLibraryImplBase::FindNetworkDeviceByPath(
const std::string& path) {
NetworkDeviceMap::iterator iter = device_map_.find(path);
if (iter != device_map_.end())
return iter->second;
LOG(WARNING) << "Device path not found: " << path;
return NULL;
}
const NetworkDevice* NetworkLibraryImplBase::FindCellularDevice() const {
return FindDeviceByType(TYPE_CELLULAR);
}
const NetworkDevice* NetworkLibraryImplBase::FindMobileDevice() const {
const NetworkDevice* device = FindDeviceByType(TYPE_CELLULAR);
if (device)
return device;
return FindDeviceByType(TYPE_WIMAX);
}
Network* NetworkLibraryImplBase::FindNetworkByPath(
const std::string& path) const {
NetworkMap::const_iterator iter = network_map_.find(path);
if (iter != network_map_.end())
return iter->second;
return NULL;
}
Network* NetworkLibraryImplBase::FindNetworkByUniqueId(
const std::string& unique_id) const {
NetworkMap::const_iterator found = network_unique_id_map_.find(unique_id);
if (found != network_unique_id_map_.end())
return found->second;
return NULL;
}
WirelessNetwork* NetworkLibraryImplBase::FindWirelessNetworkByPath(
const std::string& path) const {
Network* network = FindNetworkByPath(path);
if (network &&
(network->type() == TYPE_WIFI || network->type() == TYPE_WIMAX ||
network->type() == TYPE_CELLULAR))
return static_cast<WirelessNetwork*>(network);
return NULL;
}
WifiNetwork* NetworkLibraryImplBase::FindWifiNetworkByPath(
const std::string& path) const {
Network* network = FindNetworkByPath(path);
if (network && network->type() == TYPE_WIFI)
return static_cast<WifiNetwork*>(network);
return NULL;
}
WimaxNetwork* NetworkLibraryImplBase::FindWimaxNetworkByPath(
const std::string& path) const {
Network* network = FindNetworkByPath(path);
if (network && (network->type() == TYPE_WIMAX))
return static_cast<WimaxNetwork*>(network);
return NULL;
}
CellularNetwork* NetworkLibraryImplBase::FindCellularNetworkByPath(
const std::string& path) const {
Network* network = FindNetworkByPath(path);
if (network && network->type() == TYPE_CELLULAR)
return static_cast<CellularNetwork*>(network);
return NULL;
}
VirtualNetwork* NetworkLibraryImplBase::FindVirtualNetworkByPath(
const std::string& path) const {
Network* network = FindNetworkByPath(path);
if (network && network->type() == TYPE_VPN)
return static_cast<VirtualNetwork*>(network);
return NULL;
}
Network* NetworkLibraryImplBase::FindRememberedFromNetwork(
const Network* network) const {
for (NetworkMap::const_iterator iter = remembered_network_map_.begin();
iter != remembered_network_map_.end(); ++iter) {
if (iter->second->unique_id() == network->unique_id())
return iter->second;
}
return NULL;
}
Network* NetworkLibraryImplBase::FindRememberedNetworkByPath(
const std::string& path) const {
NetworkMap::const_iterator iter = remembered_network_map_.find(path);
if (iter != remembered_network_map_.end())
return iter->second;
return NULL;
}
const base::DictionaryValue* NetworkLibraryImplBase::FindOncForNetwork(
const std::string& unique_id) const {
NetworkOncMap::const_iterator iter = network_onc_map_.find(unique_id);
return iter != network_onc_map_.end() ? iter->second : NULL;
}
void NetworkLibraryImplBase::SignalCellularPlanPayment() {
DCHECK(!HasRecentCellularPlanPayment());
cellular_plan_payment_time_ = base::Time::Now();
}
bool NetworkLibraryImplBase::HasRecentCellularPlanPayment() {
return (base::Time::Now() -
cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours;
}
const std::string& NetworkLibraryImplBase::GetCellularHomeCarrierId() const {
const NetworkDevice* cellular = FindCellularDevice();
if (cellular)
return cellular->home_provider_id();
return EmptyString();
}
bool NetworkLibraryImplBase::CellularDeviceUsesDirectActivation() const {
const NetworkDevice* cellular = FindCellularDevice();
return cellular && (cellular->carrier() == shill::kCarrierSprint);
}
/////////////////////////////////////////////////////////////////////////////
// Profiles.
bool NetworkLibraryImplBase::HasProfileType(NetworkProfileType type) const {
for (NetworkProfileList::const_iterator iter = profile_list_.begin();
iter != profile_list_.end(); ++iter) {
if ((*iter).type == type)
return true;
}
return false;
}
NetworkLibraryImplBase::NetworkProfile::NetworkProfile(const std::string& p,
NetworkProfileType t)
: path(p),
type(t) {
}
NetworkLibraryImplBase::NetworkProfile::~NetworkProfile() {}
NetworkLibraryImplBase::ConnectData::ConnectData()
: security(SECURITY_NONE),
eap_method(EAP_METHOD_UNKNOWN),
eap_auth(EAP_PHASE_2_AUTH_AUTO),
eap_use_system_cas(false),
save_credentials(false),
profile_type(PROFILE_NONE) {
}
NetworkLibraryImplBase::ConnectData::~ConnectData() {}
const NetworkDevice* NetworkLibraryImplBase::FindDeviceByType(
ConnectionType type) const {
for (NetworkDeviceMap::const_iterator iter = device_map_.begin();
iter != device_map_.end(); ++iter) {
if (iter->second && iter->second->type() == type)
return iter->second;
}
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// Connect to an existing network.
bool NetworkLibraryImplBase::CanConnectToNetwork(const Network* network) const {
if (!HasProfileType(PROFILE_USER) && network->RequiresUserProfile())
return false;
return true;
}
// 1. Request a connection to an existing wifi network.
// Use |shared| to pass along the desired profile type.
void NetworkLibraryImplBase::ConnectToWifiNetwork(
WifiNetwork* wifi, bool shared) {
NetworkConnectStartWifi(wifi, shared ? PROFILE_SHARED : PROFILE_USER);
}
// 1. Request a connection to an existing wifi network.
void NetworkLibraryImplBase::ConnectToWifiNetwork(WifiNetwork* wifi) {
NetworkConnectStartWifi(wifi, PROFILE_NONE);
}
// 1. Request a connection to an existing wimax network.
// Use |shared| to pass along the desired profile type.
void NetworkLibraryImplBase::ConnectToWimaxNetwork(
WimaxNetwork* wimax, bool shared) {
NetworkConnectStart(wimax, shared ? PROFILE_SHARED : PROFILE_USER);
}
// 1. Request a connection to an existing wimax network.
void NetworkLibraryImplBase::ConnectToWimaxNetwork(WimaxNetwork* wimax) {
NetworkConnectStart(wimax, PROFILE_NONE);
}
// 1. Connect to a cellular network.
void NetworkLibraryImplBase::ConnectToCellularNetwork(
CellularNetwork* cellular) {
NetworkConnectStart(cellular, PROFILE_NONE);
}
// 1. Connect to an existing virtual network.
void NetworkLibraryImplBase::ConnectToVirtualNetwork(VirtualNetwork* vpn) {
NetworkConnectStartVPN(vpn);
}
// 2. Start the connection.
void NetworkLibraryImplBase::NetworkConnectStartWifi(
WifiNetwork* wifi, NetworkProfileType profile_type) {
DCHECK(!wifi->connection_started());
// This will happen if a network resets, gets out of range or is forgotten.
if (wifi->user_passphrase_ != wifi->passphrase_ ||
wifi->passphrase_required())
wifi->SetPassphrase(wifi->user_passphrase_);
// For enterprise 802.1X networks, always provide TPM PIN when available.
// shill uses the PIN if it needs to access certificates in the TPM and
// ignores it otherwise.
if (wifi->encryption() == SECURITY_8021X) {
// If the TPM initialization has not completed, GetTpmPin() will return
// an empty value, in which case we do not want to clear the PIN since
// that will cause shill to flag the network as unconfigured.
// TODO(stevenjb): We may want to delay attempting to connect, or fail
// immediately, rather than let the network layer attempt a connection.
std::string tpm_pin = GetTpmPin();
if (!tpm_pin.empty())
wifi->SetCertificatePin(tpm_pin);
}
NetworkConnectStart(wifi, profile_type);
}
void NetworkLibraryImplBase::NetworkConnectStartVPN(VirtualNetwork* vpn) {
// shill needs the TPM PIN for some VPN networks to access client
// certificates, and ignores the PIN if it doesn't need them. Only set this
// if the TPM is ready (see comment in NetworkConnectStartWifi).
std::string tpm_pin = GetTpmPin();
if (!tpm_pin.empty()) {
std::string tpm_slot = GetTpmSlot();
vpn->SetCertificateSlotAndPin(tpm_slot, tpm_pin);
}
NetworkConnectStart(vpn, PROFILE_NONE);
}
void NetworkLibraryImplBase::NetworkConnectStart(
Network* network, NetworkProfileType profile_type) {
DCHECK(network);
DCHECK(!network->connection_started());
// In order to be certain to trigger any notifications, set the connecting
// state locally and notify observers. Otherwise there might be a state
// change without a forced notify.
network->set_connecting();
// Distinguish between user-initiated connection attempts
// and auto-connect.
network->set_user_connect_state(USER_CONNECT_STARTED);
NotifyNetworkManagerChanged(true); // Forced update.
VLOG(1) << "Requesting connect to network: " << network->name()
<< " profile type: " << profile_type;
// Specify the correct profile for wifi networks (if specified or unset).
if ((network->type() == TYPE_WIFI || network->type() == TYPE_WIMAX) &&
(profile_type != PROFILE_NONE ||
network->profile_type() == PROFILE_NONE)) {
if (network->RequiresUserProfile())
profile_type = PROFILE_USER; // Networks with certs can not be shared.
else if (profile_type == PROFILE_NONE)
profile_type = PROFILE_SHARED; // Other networks are shared by default.
std::string profile_path = GetProfilePath(profile_type);
if (!profile_path.empty()) {
if (profile_path != network->profile_path())
SetProfileType(network, profile_type);
} else if (profile_type == PROFILE_USER) {
// The user profile was specified but is not available (i.e. pre-login).
// Add this network to the list of networks to move to the user profile
// when it becomes available.
VLOG(1) << "Queuing: " << network->name() << " to user_networks list.";
user_networks_.push_back(network->service_path());
}
}
CallConnectToNetwork(network);
}
// 3. Start the connection attempt for Network.
// Must Call NetworkConnectCompleted when the connection attempt completes.
// virtual void CallConnectToNetwork(Network* network) = 0;
// 4. Complete the connection.
void NetworkLibraryImplBase::NetworkConnectCompleted(
Network* network, NetworkConnectStatus status) {
DCHECK(network);
if (status != CONNECT_SUCCESS) {
// This will trigger the connection failed notification.
// TODO(stevenjb): Remove if chromium-os:13203 gets fixed.
network->SetState(STATE_FAILURE);
if (status == CONNECT_BAD_PASSPHRASE) {
network->SetError(ERROR_BAD_PASSPHRASE);
} else {
network->SetError(ERROR_CONNECT_FAILED);
}
NotifyNetworkManagerChanged(true); // Forced update.
NotifyNetworkChanged(network);
VLOG(1) << "Error connecting to network: " << network->name()
<< " Status: " << status;
return;
}
VLOG(1) << "Connected to network: " << network->name()
<< " State: " << network->state()
<< " Status: " << status;
// If the user asked not to save credentials, shill will have
// forgotten them. Wipe our cache as well.
if (!network->save_credentials())
network->EraseCredentials();
ClearActiveNetwork(network->type());
UpdateActiveNetwork(network);
// Notify observers.
NotifyNetworkManagerChanged(true); // Forced update.
NotifyNetworkChanged(network);
}
/////////////////////////////////////////////////////////////////////////////
// Request a network and connect to it.
// 1. Connect to an unconfigured or unlisted wifi network.
// This needs to request information about the named service.
// The connection attempt will occur in the callback.
void NetworkLibraryImplBase::ConnectToUnconfiguredWifiNetwork(
const std::string& ssid,
ConnectionSecurity security,
const std::string& passphrase,
const EAPConfigData* eap_config,
bool save_credentials,
bool shared) {
// Store the connection data to be used by the callback.
connect_data_.security = security;
connect_data_.service_name = ssid;
connect_data_.passphrase = passphrase;
connect_data_.save_credentials = save_credentials;
connect_data_.profile_type = shared ? PROFILE_SHARED : PROFILE_USER;
if (security == SECURITY_8021X) {
DCHECK(eap_config);
connect_data_.service_name = ssid;
connect_data_.eap_method = eap_config->method;
connect_data_.eap_auth = eap_config->auth;
connect_data_.server_ca_cert_pem = eap_config->server_ca_cert_pem;
connect_data_.eap_use_system_cas = eap_config->use_system_cas;
connect_data_.client_cert_pkcs11_id =
eap_config->client_cert_pkcs11_id;
connect_data_.eap_identity = eap_config->identity;
connect_data_.eap_anonymous_identity = eap_config->anonymous_identity;
}
CallRequestWifiNetworkAndConnect(ssid, security);
}
// 1. Connect to a virtual network with a PSK.
void NetworkLibraryImplBase::ConnectToUnconfiguredVirtualNetwork(
const std::string& service_name,
const std::string& server_hostname,
ProviderType provider_type,
const VPNConfigData& config) {
// Store the connection data to be used by the callback.
connect_data_.service_name = service_name;
connect_data_.server_hostname = server_hostname;
connect_data_.psk_key = config.psk;
connect_data_.server_ca_cert_pem = config.server_ca_cert_pem;
connect_data_.client_cert_pkcs11_id = config.client_cert_pkcs11_id;
connect_data_.username = config.username;
connect_data_.passphrase = config.user_passphrase;
connect_data_.otp = config.otp;
connect_data_.group_name = config.group_name;
connect_data_.save_credentials = config.save_credentials;
CallRequestVirtualNetworkAndConnect(
service_name, server_hostname, provider_type);
}
// 2. Requests a WiFi Network by SSID and security.
// Calls ConnectToWifiNetworkUsingConnectData if network request succeeds.
// virtual void CallRequestWifiNetworkAndConnect(
// const std::string& ssid, ConnectionSecurity security) = 0;
// 2. Requests a Virtual Network by service name, etc.
// Calls ConnectToVirtualNetworkUsingConnectData if network request succeeds.
// virtual void CallRequestVirtualNetworkAndConnect(
// const std::string& service_name,
// const std::string& server_hostname,
// ProviderType provider_type) = 0;
// 3. Sets network properties stored in ConnectData and calls
// NetworkConnectStart.
void NetworkLibraryImplBase::ConnectToWifiNetworkUsingConnectData(
WifiNetwork* wifi) {
ConnectData& data = connect_data_;
if (wifi->name() != data.service_name) {
LOG(WARNING) << "WiFi network name does not match ConnectData: "
<< wifi->name() << " != " << data.service_name;
return;
}
wifi->set_added(true);
if (data.security == SECURITY_8021X) {
// Enterprise 802.1X EAP network.
wifi->SetEAPMethod(data.eap_method);
wifi->SetEAPPhase2Auth(data.eap_auth);
wifi->SetEAPServerCaCertPEM(data.server_ca_cert_pem);
wifi->SetEAPUseSystemCAs(data.eap_use_system_cas);
wifi->SetEAPClientCertPkcs11Id(data.client_cert_pkcs11_id);
wifi->SetEAPIdentity(data.eap_identity);
wifi->SetEAPAnonymousIdentity(data.eap_anonymous_identity);
wifi->SetEAPPassphrase(data.passphrase);
wifi->SetSaveCredentials(data.save_credentials);
} else {
// Ordinary, non-802.1X network.
wifi->SetPassphrase(data.passphrase);
}
NetworkConnectStartWifi(wifi, data.profile_type);
}
// 3. Sets network properties stored in ConnectData and calls
// ConnectToVirtualNetwork.
void NetworkLibraryImplBase::ConnectToVirtualNetworkUsingConnectData(
VirtualNetwork* vpn) {
ConnectData& data = connect_data_;
if (vpn->name() != data.service_name) {
LOG(WARNING) << "Virtual network name does not match ConnectData: "
<< vpn->name() << " != " << data.service_name;
return;
}
// When a L2TP/IPsec certificate-based VPN is created, the VirtualNetwork
// instance is created by NativeNetworkParser::CreateNetworkFromInfo().
// At that point, the provider type is deduced based on the value of
// client_cert_id_ of the VirtualNetwork instance, which hasn't been
// updated to the value of connect_data_.client_cert_pkcs11_id. Thus,
// the provider type is always incorrectly set to L2TP_IPSEC_PSK when
// L2TP_IPSEC_USER_CERT is expected. Here we fix the provider type based
// on connect_data_.client_cert_pkcs11_id.
//
// TODO(benchan): This is a quick and dirty workaround, we should refactor
// the code to make the flow more straightforward. See crosbug.com/24636
if (vpn->provider_type() == PROVIDER_TYPE_L2TP_IPSEC_PSK &&
!connect_data_.client_cert_pkcs11_id.empty()) {
vpn->set_provider_type(PROVIDER_TYPE_L2TP_IPSEC_USER_CERT);
}
vpn->set_added(true);
if (!data.server_hostname.empty())
vpn->set_server_hostname(data.server_hostname);
vpn->SetCACertPEM(data.server_ca_cert_pem);
switch (vpn->provider_type()) {
case PROVIDER_TYPE_L2TP_IPSEC_PSK:
vpn->SetL2TPIPsecPSKCredentials(
data.psk_key, data.username, data.passphrase, data.group_name);
break;
case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: {
vpn->SetL2TPIPsecCertCredentials(
data.client_cert_pkcs11_id,
data.username, data.passphrase, data.group_name);
break;
}
case PROVIDER_TYPE_OPEN_VPN: {
vpn->SetOpenVPNCredentials(
data.client_cert_pkcs11_id,
data.username, data.passphrase, data.otp);
break;
}
case PROVIDER_TYPE_MAX:
NOTREACHED();
break;
}
vpn->SetSaveCredentials(data.save_credentials);
NetworkConnectStartVPN(vpn);
}
/////////////////////////////////////////////////////////////////////////////
void NetworkLibraryImplBase::ForgetNetwork(const std::string& service_path) {
// Remove network from remembered list and notify observers.
DeleteRememberedNetwork(service_path);
NotifyNetworkManagerChanged(true); // Forced update.
}
/////////////////////////////////////////////////////////////////////////////
void NetworkLibraryImplBase::EnableEthernetNetworkDevice(bool enable) {
if (is_locked_)
return;
CallEnableNetworkDeviceType(TYPE_ETHERNET, enable);
}
void NetworkLibraryImplBase::EnableWifiNetworkDevice(bool enable) {
if (is_locked_)
return;
CallEnableNetworkDeviceType(TYPE_WIFI, enable);
}
void NetworkLibraryImplBase::EnableWimaxNetworkDevice(bool enable) {
if (is_locked_)
return;
CallEnableNetworkDeviceType(TYPE_WIMAX, enable);
}
void NetworkLibraryImplBase::EnableCellularNetworkDevice(bool enable) {
if (is_locked_)
return;
CallEnableNetworkDeviceType(TYPE_CELLULAR, enable);
}
void NetworkLibraryImplBase::SwitchToPreferredNetwork() {
// If current network (if any) is not preferred, check network service list to
// see if the first not connected network is preferred and set to autoconnect.
// If so, connect to it.
if (!wifi_enabled() || (active_wifi_ && active_wifi_->preferred()))
return;
for (WifiNetworkVector::const_iterator it = wifi_networks_.begin();
it != wifi_networks_.end(); ++it) {
WifiNetwork* wifi = *it;
if (wifi->connected() || wifi->connecting()) // Skip connected/connecting.
continue;
if (!wifi->preferred()) // All preferred networks are sorted in front.
break;
if (wifi->auto_connect()) {
ConnectToWifiNetwork(wifi);
break;
}
}
}
namespace {
class UserStringSubstitution : public onc::StringSubstitution {
public:
UserStringSubstitution() {}
virtual bool GetSubstitute(const std::string& placeholder,
std::string* substitute) const OVERRIDE {
if (!UserManager::Get()->IsUserLoggedIn())
return false;
const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
if (placeholder == onc::substitutes::kLoginIDField)
*substitute = logged_in_user->GetAccountName(false);
else if (placeholder == onc::substitutes::kEmailField)
*substitute = logged_in_user->email();
else
return false;
return true;
}
};
} // namespace
void NetworkLibraryImplBase::LoadOncNetworks(
const base::ListValue& network_configs,
onc::ONCSource source) {
VLOG(2) << __func__ << ": called on " << network_configs;
NetworkProfile* profile = NULL;
bool from_policy = (source == onc::ONC_SOURCE_USER_POLICY ||
source == onc::ONC_SOURCE_DEVICE_POLICY);
// Policies are applied to a specific Shill profile. User ONC import however
// is applied to whatever profile Shill chooses. This should be the profile
// that is already associated with a network and if no profile is associated
// yet, it should be the user profile.
if (from_policy) {
profile = GetProfileForType(GetProfileTypeForSource(source));
if (profile == NULL) {
VLOG(2) << "Profile for ONC source " << onc::GetSourceAsString(source)
<< " doesn't exist.";
return;
}
}
std::set<std::string> removal_ids;
std::set<std::string>& network_ids(network_source_map_[source]);
network_ids.clear();
VLOG(2) << "ONC file has " << network_configs.GetSize() << " networks";
for (base::ListValue::const_iterator it(network_configs.begin());
it != network_configs.end(); ++it) {
const base::DictionaryValue* network;
(*it)->GetAsDictionary(&network);
bool marked_for_removal = false;
network->GetBooleanWithoutPathExpansion(onc::kRemove,
&marked_for_removal);
std::string type;
network->GetStringWithoutPathExpansion(onc::network_config::kType, &type);
std::string guid;
network->GetStringWithoutPathExpansion(onc::network_config::kGUID, &guid);
if (source == onc::ONC_SOURCE_USER_IMPORT && marked_for_removal) {
// User import supports the removal of networks by ID.
removal_ids.insert(guid);
continue;
}
// Don't configure a network that is supposed to be removed. For
// policy-managed networks, the "remove" functionality of ONC is
// irrelevant. Instead, in general, all previously configured networks
// that are no longer configured are removed.
if (marked_for_removal)
continue;
// Store the network's identifier. The identifiers are later used to clean
// out any previously-existing networks that had been configured through
// policy but are no longer specified in the updated ONC blob.
network_ids.insert(guid);
// Expand strings like LoginID
base::DictionaryValue* expanded_network = network->DeepCopy();
UserStringSubstitution substitution;
onc::ExpandStringsInOncObject(onc::kNetworkConfigurationSignature,
substitution,
expanded_network);
// Update the ONC map.
const base::DictionaryValue*& entry = network_onc_map_[guid];
if (entry && entry->Equals(expanded_network))
continue;
delete entry;
entry = expanded_network;
// Normalize the ONC: Remove irrelevant fields.
onc::Normalizer normalizer(true /* remove recommended fields */);
scoped_ptr<base::DictionaryValue> normalized_network =
normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
*expanded_network);
// Configure the network.
scoped_ptr<base::DictionaryValue> shill_dict =
onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
*normalized_network);
// Set the UIData.
scoped_ptr<NetworkUIData> ui_data =
NetworkUIData::CreateFromONC(source, *normalized_network);
base::DictionaryValue ui_data_dict;
ui_data->FillDictionary(&ui_data_dict);
std::string ui_data_json;
base::JSONWriter::Write(&ui_data_dict, &ui_data_json);
shill_dict->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
ui_data_json);
// Set the appropriate profile for |source|.
if (profile != NULL) {
shill_dict->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
profile->path);
}
// For Ethernet networks, apply them to the current Ethernet service.
if (type == onc::network_type::kEthernet) {
const EthernetNetwork* ethernet = ethernet_network();
if (ethernet) {
CallConfigureService(ethernet->unique_id(), shill_dict.get());
} else {
LOG(WARNING) << "Tried to import ONC with an Ethernet network when "
<< "there is no active Ethernet connection.";
}
} else {
CallConfigureService(guid, shill_dict.get());
}
}
if (from_policy) {
// For policy-managed networks, go through the list of existing remembered
// networks and clean out the ones that no longer have a definition in the
// ONC blob. We first collect the networks and do the actual deletion later
// because ForgetNetwork() changes the remembered network vectors.
ForgetNetworksById(source, network_ids, false);
} else if (source == onc::ONC_SOURCE_USER_IMPORT && !removal_ids.empty()) {
ForgetNetworksById(source, removal_ids, true);
}
// Ensure NetworkStateHandler properties are up-to-date.
if (NetworkHandler::IsInitialized()) {
NetworkHandler::Get()->network_state_handler()->
RequestUpdateForAllNetworks();
}
}
////////////////////////////////////////////////////////////////////////////
// Testing functions.
bool NetworkLibraryImplBase::SetActiveNetwork(
ConnectionType type, const std::string& service_path) {
Network* network = NULL;
if (!service_path.empty())
network = FindNetworkByPath(service_path);
if (network && network->type() != type) {
LOG(WARNING) << "SetActiveNetwork type mismatch for: " << network->name();
return false;
}
ClearActiveNetwork(type);
if (!network)
return true;
// Set |network| to active.
UpdateActiveNetwork(network);
return true;
}
////////////////////////////////////////////////////////////////////////////
// Network list management functions.
// Note: sometimes shill still returns networks when the device type is
// disabled. Always check the appropriate enabled() state before adding
// networks to a list or setting an active network so that we do not show them
// in the UI.
// This relies on services being requested from shill in priority order,
// and the updates getting processed and received in order.
void NetworkLibraryImplBase::UpdateActiveNetwork(Network* network) {
network->set_is_active(true);
ConnectionType type(network->type());
if (type == TYPE_ETHERNET) {
if (ethernet_enabled()) {
// Set ethernet_ to the first connected ethernet service, or the first
// disconnected ethernet service if none are connected.
if (ethernet_ == NULL || !ethernet_->connected()) {
ethernet_ = static_cast<EthernetNetwork*>(network);
VLOG(2) << "Active ethernet -> " << ethernet_->name();
}
}
} else if (type == TYPE_WIFI) {
if (wifi_enabled()) {
// Set active_wifi_ to the first connected or connecting wifi service.
if (active_wifi_ == NULL && network->connecting_or_connected()) {
active_wifi_ = static_cast<WifiNetwork*>(network);
VLOG(2) << "Active wifi -> " << active_wifi_->name();
}
}
} else if (type == TYPE_CELLULAR) {
if (cellular_enabled()) {
// Set active_cellular_ to first connected/connecting celluar service.
if (active_cellular_ == NULL && network->connecting_or_connected()) {
active_cellular_ = static_cast<CellularNetwork*>(network);
VLOG(2) << "Active cellular -> " << active_cellular_->name();
}
}
} else if (type == TYPE_WIMAX) {
if (wimax_enabled()) {
// Set active_wimax_ to first connected/connecting wimax service.
if (active_wimax_ == NULL && network->connecting_or_connected()) {
active_wimax_ = static_cast<WimaxNetwork*>(network);
VLOG(2) << "Active wimax -> " << active_wimax_->name();
}
}
} else if (type == TYPE_VPN) {
// Set active_virtual_ to the first connected or connecting vpn service. {
if (active_virtual_ == NULL && network->connecting_or_connected()) {
active_virtual_ = static_cast<VirtualNetwork*>(network);
VLOG(2) << "Active virtual -> " << active_virtual_->name();
}
}
}
void NetworkLibraryImplBase::ClearActiveNetwork(ConnectionType type) {
// Clear any existing active network matching |type|.
for (NetworkMap::iterator iter = network_map_.begin();
iter != network_map_.end(); ++iter) {
Network* other = iter->second;
if (other->type() == type)
other->set_is_active(false);
}
switch (type) {
case TYPE_ETHERNET:
ethernet_ = NULL;
break;
case TYPE_WIFI:
active_wifi_ = NULL;
break;
case TYPE_CELLULAR:
active_cellular_ = NULL;
break;
case TYPE_WIMAX:
active_wimax_ = NULL;
break;
case TYPE_VPN:
active_virtual_ = NULL;
break;
default:
break;
}
}
void NetworkLibraryImplBase::AddNetwork(Network* network) {
std::pair<NetworkMap::iterator, bool> result =
network_map_.insert(std::make_pair(network->service_path(), network));
DCHECK(result.second); // Should only get called with new network.
VLOG(2) << "Adding Network: " << network->service_path()
<< " (" << network->name() << ")";
ConnectionType type(network->type());
if (type == TYPE_WIFI) {
if (wifi_enabled())
wifi_networks_.push_back(static_cast<WifiNetwork*>(network));
} else if (type == TYPE_CELLULAR) {
if (cellular_enabled())
cellular_networks_.push_back(static_cast<CellularNetwork*>(network));
} else if (type == TYPE_WIMAX) {
if (wimax_enabled())
wimax_networks_.push_back(static_cast<WimaxNetwork*>(network));
} else if (type == TYPE_VPN) {
virtual_networks_.push_back(static_cast<VirtualNetwork*>(network));
}
// Do not set the active network here. Wait until we parse the network.
}
// Deletes a network. It must already be removed from any lists.
void NetworkLibraryImplBase::DeleteNetwork(Network* network) {
CHECK(network_map_.find(network->service_path()) == network_map_.end());
delete network;
}
void NetworkLibraryImplBase::ForgetNetworksById(
onc::ONCSource source,
std::set<std::string> ids,
bool if_found) {
std::vector<std::string> to_be_forgotten;
for (WifiNetworkVector::iterator i = remembered_wifi_networks_.begin();
i != remembered_wifi_networks_.end(); ++i) {
WifiNetwork* wifi_network = *i;
if (wifi_network->ui_data().onc_source() == source &&
if_found == (ids.find(wifi_network->unique_id()) != ids.end()))
to_be_forgotten.push_back(wifi_network->service_path());
}
for (VirtualNetworkVector::iterator i = remembered_virtual_networks_.begin();
i != remembered_virtual_networks_.end(); ++i) {
VirtualNetwork* virtual_network = *i;
if (virtual_network->ui_data().onc_source() == source &&
if_found == (ids.find(virtual_network->unique_id()) != ids.end()))
to_be_forgotten.push_back(virtual_network->service_path());
}
for (std::vector<std::string>::const_iterator i = to_be_forgotten.begin();
i != to_be_forgotten.end(); ++i) {
ForgetNetwork(*i);
}
}
bool NetworkLibraryImplBase::ValidateRememberedNetwork(Network* network) {
std::pair<NetworkMap::iterator, bool> result =
remembered_network_map_.insert(
std::make_pair(network->service_path(), network));
DCHECK(result.second); // Should only get called with new network.
// See if this is a policy-configured network that has meanwhile been removed.
// This situation may arise when the full list of remembered networks is not
// available to LoadOncNetworks(), which can happen due to the asynchronous
// communication between shill and NetworkLibrary. Just tell shill to
// delete the network now.
const onc::ONCSource source = network->ui_data().onc_source();
if (source == onc::ONC_SOURCE_USER_POLICY ||
source == onc::ONC_SOURCE_DEVICE_POLICY) {
NetworkSourceMap::const_iterator network_id_set(
network_source_map_.find(source));
if (network_id_set != network_source_map_.end() &&
network_id_set->second.find(network->unique_id()) ==
network_id_set->second.end()) {
DeleteRememberedNetwork(network->service_path());
return false;
}
}
return true;
}
bool NetworkLibraryImplBase::ValidateAndAddRememberedNetwork(Network* network) {
if (!ValidateRememberedNetwork(network))
return false;
if (network->type() == TYPE_WIFI) {
remembered_wifi_networks_.push_back(
static_cast<WifiNetwork*>(network));
} else if (network->type() == TYPE_VPN) {
remembered_virtual_networks_.push_back(
static_cast<VirtualNetwork*>(network));
} else {
NOTREACHED();
}
VLOG(1) << "ValidateAndAddRememberedNetwork: " << network->service_path();
return true;
}
void NetworkLibraryImplBase::DeleteRememberedNetwork(
const std::string& service_path) {
NetworkMap::iterator found = remembered_network_map_.find(service_path);
if (found == remembered_network_map_.end()) {
LOG(WARNING) << "Attempt to delete non-existent remembered network: "
<< service_path;
return;
}
Network* remembered_network = found->second;
VLOG(1) << "Deleting remembered network: "
<< remembered_network->service_path();
// Update any associated network service before removing from profile
// so that shill doesn't recreate the service (e.g. when we disconenct it).
Network* network = FindNetworkByUniqueId(remembered_network->unique_id());
if (network) {
// Clear the stored credentials for any forgotten networks.
network->EraseCredentials();
network->ClearUIData();
SetProfileType(network, PROFILE_NONE);
// Remove VPN from list of networks.
if (network->type() == TYPE_VPN)
CallRemoveNetwork(network);
} else {
// Network is not in service list.
VLOG(2) << "Remembered Network not in service list: "
<< remembered_network->unique_id();
}
// Delete remembered network from lists.
remembered_network_map_.erase(found);
if (remembered_network->type() == TYPE_WIFI) {
WifiNetworkVector::iterator iter = std::find(
remembered_wifi_networks_.begin(),
remembered_wifi_networks_.end(),
remembered_network);
if (iter != remembered_wifi_networks_.end())
remembered_wifi_networks_.erase(iter);
} else if (remembered_network->type() == TYPE_VPN) {
VirtualNetworkVector::iterator iter = std::find(
remembered_virtual_networks_.begin(),
remembered_virtual_networks_.end(),
remembered_network);
if (iter != remembered_virtual_networks_.end())
remembered_virtual_networks_.erase(iter);
}
// Delete remembered network from all profiles it is in.
for (NetworkProfileList::iterator iter = profile_list_.begin();
iter != profile_list_.end(); ++iter) {
NetworkProfile& profile = *iter;
NetworkProfile::ServiceList::iterator found =
profile.services.find(remembered_network->service_path());
if (found != profile.services.end()) {
VLOG(1) << "Deleting: " << remembered_network->service_path()
<< " From: " << profile.path;
CallDeleteRememberedNetwork(profile.path,
remembered_network->service_path());
profile.services.erase(found);
}
}
// Remove the ONC blob for the network, if present.
NetworkOncMap::iterator onc_map_entry =
network_onc_map_.find(remembered_network->unique_id());
if (onc_map_entry != network_onc_map_.end()) {
delete onc_map_entry->second;
network_onc_map_.erase(onc_map_entry);
}
delete remembered_network;
}
////////////////////////////////////////////////////////////////////////////
void NetworkLibraryImplBase::ClearNetworks() {
network_map_.clear();
network_unique_id_map_.clear();
ethernet_ = NULL;
active_wifi_ = NULL;
active_cellular_ = NULL;
active_wimax_ = NULL;
active_virtual_ = NULL;
wifi_networks_.clear();
cellular_networks_.clear();
wimax_networks_.clear();
virtual_networks_.clear();
}
void NetworkLibraryImplBase::DeleteRememberedNetworks() {
STLDeleteValues(&remembered_network_map_);
remembered_network_map_.clear();
remembered_wifi_networks_.clear();
remembered_virtual_networks_.clear();
}
void NetworkLibraryImplBase::DeleteDevice(const std::string& device_path) {
NetworkDeviceMap::iterator found = device_map_.find(device_path);
if (found == device_map_.end()) {
LOG(WARNING) << "Attempt to delete non-existent device: "
<< device_path;
return;
}
VLOG(2) << " Deleting device: " << device_path;
NetworkDevice* device = found->second;
device_map_.erase(found);
delete device;
DeleteDeviceFromDeviceObserversMap(device_path);
}
////////////////////////////////////////////////////////////////////////////
void NetworkLibraryImplBase::AddProfile(const std::string& profile_path,
NetworkProfileType profile_type) {
VLOG(1) << "Adding profile " << profile_path;
profile_list_.push_back(NetworkProfile(profile_path, profile_type));
// Check to see if we connected to any networks before a user profile was
// available (i.e. before login), but unchecked the "Share" option (i.e.
// the desired pofile is the user profile). Move these networks to the
// user profile when it becomes available.
if (profile_type == PROFILE_USER && !user_networks_.empty()) {
for (std::list<std::string>::iterator iter2 = user_networks_.begin();
iter2 != user_networks_.end(); ++iter2) {
Network* network = FindNetworkByPath(*iter2);
if (network && network->profile_path() != profile_path)
network->SetProfilePath(profile_path);
}
user_networks_.clear();
}
}
NetworkLibraryImplBase::NetworkProfile*
NetworkLibraryImplBase::GetProfileForType(NetworkProfileType type) {
for (NetworkProfileList::iterator iter = profile_list_.begin();
iter != profile_list_.end(); ++iter) {
NetworkProfile& profile = *iter;
if (profile.type == type)
return &profile;
}
return NULL;
}
void NetworkLibraryImplBase::SetProfileType(
Network* network, NetworkProfileType type) {
if (type == PROFILE_NONE) {
network->SetProfilePath(std::string());
network->set_profile_type(PROFILE_NONE);
} else {
std::string profile_path = GetProfilePath(type);
if (!profile_path.empty()) {
network->SetProfilePath(profile_path);
network->set_profile_type(type);
} else {
LOG(WARNING) << "Profile type not found: " << type;
network->set_profile_type(PROFILE_NONE);
}
}
}
void NetworkLibraryImplBase::SetProfileTypeFromPath(Network* network) {
if (network->profile_path().empty()) {
network->set_profile_type(PROFILE_NONE);
return;
}
for (NetworkProfileList::iterator iter = profile_list_.begin();
iter != profile_list_.end(); ++iter) {
NetworkProfile& profile = *iter;
if (profile.path == network->profile_path()) {
network->set_profile_type(profile.type);
return;
}
}
LOG(WARNING) << "Profile path not found: " << network->profile_path();
network->set_profile_type(PROFILE_NONE);
}
std::string NetworkLibraryImplBase::GetProfilePath(NetworkProfileType type) {
std::string profile_path;
NetworkProfile* profile = GetProfileForType(type);
if (profile)
profile_path = profile->path;
return profile_path;
}
////////////////////////////////////////////////////////////////////////////
// Notifications.
void NetworkLibraryImplBase::NotifyNetworkProfileObservers() {
FOR_EACH_OBSERVER(NetworkProfileObserver,
network_profile_observers_,
OnProfileListChanged());
}
// We call this any time something in NetworkLibrary changes.
// TODO(stevenjb): We should consider breaking this into multiple
// notifications, e.g. connection state, devices, services, etc.
void NetworkLibraryImplBase::NotifyNetworkManagerChanged(bool force_update) {
// Cancel any pending signals.
notify_manager_weak_factory_.InvalidateWeakPtrs();
if (force_update) {
// Signal observers now.
SignalNetworkManagerObservers();
} else {
// Schedule a delayed signal to limit the frequency of notifications.
BrowserThread::PostDelayedTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&NetworkLibraryImplBase::SignalNetworkManagerObservers,
notify_manager_weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kNetworkNotifyDelayMs));
}
}
void NetworkLibraryImplBase::SignalNetworkManagerObservers() {
FOR_EACH_OBSERVER(NetworkManagerObserver,
network_manager_observers_,
OnNetworkManagerChanged(this));
// Clear notification flags.
for (NetworkMap::iterator iter = network_map_.begin();
iter != network_map_.end(); ++iter) {
iter->second->set_notify_failure(false);
}
}
void NetworkLibraryImplBase::NotifyNetworkChanged(const Network* network) {
DCHECK(network);
VLOG(2) << "Network changed: " << network->name();
NetworkObserverMap::const_iterator iter = network_observers_.find(
network->service_path());
if (iter != network_observers_.end()) {
FOR_EACH_OBSERVER(NetworkObserver,
*(iter->second),
OnNetworkChanged(this, network));
} else if (IsCros()) {
LOG(ERROR) << "Unexpected signal for unobserved network: "
<< network->name();
}
}
void NetworkLibraryImplBase::NotifyNetworkDeviceChanged(
NetworkDevice* device, PropertyIndex index) {
DCHECK(device);
VLOG(2) << "Network device changed: " << device->name();
NetworkDeviceObserverMap::const_iterator iter =
network_device_observers_.find(device->device_path());
if (iter != network_device_observers_.end()) {
NetworkDeviceObserverList* device_observer_list = iter->second;
if (index == PROPERTY_INDEX_FOUND_NETWORKS) {
FOR_EACH_OBSERVER(NetworkDeviceObserver,
*device_observer_list,
OnNetworkDeviceFoundNetworks(this, device));
} else if (index == PROPERTY_INDEX_SIM_LOCK) {
FOR_EACH_OBSERVER(NetworkDeviceObserver,
*device_observer_list,
OnNetworkDeviceSimLockChanged(this, device));
}
} else {
LOG(ERROR) << "Unexpected signal for unobserved device: "
<< device->name();
}
}
void NetworkLibraryImplBase::NotifyPinOperationCompleted(
PinOperationError error) {
FOR_EACH_OBSERVER(PinOperationObserver,
pin_operation_observers_,
OnPinOperationCompleted(this, error));
sim_operation_ = SIM_OPERATION_NONE;
}
//////////////////////////////////////////////////////////////////////////////
// Pin related functions.
void NetworkLibraryImplBase::GetTpmInfo() {
// Avoid making multiple synchronous D-Bus calls to cryptohome by caching
// the TPM PIN, which does not change during a session.
if (tpm_pin_.empty()) {
if (crypto::IsTPMTokenReady()) {
std::string tpm_label;
crypto::GetTPMTokenInfo(&tpm_label, &tpm_pin_);
// VLOG(1) << "TPM Label: " << tpm_label << ", PIN: " << tpm_pin_;
// TODO(stevenjb): GetTPMTokenInfo returns a label, but the network
// code expects a slot ID. See chromium-os:17998.
// For now, use a hard coded, well known slot instead.
const char kHardcodedTpmSlot[] = "0";
tpm_slot_ = kHardcodedTpmSlot;
} else if (IsCros()) {
LOG(WARNING) << "TPM token not ready";
}
}
}
const std::string& NetworkLibraryImplBase::GetTpmSlot() {
GetTpmInfo();
return tpm_slot_;
}
const std::string& NetworkLibraryImplBase::GetTpmPin() {
GetTpmInfo();
return tpm_pin_;
}
} // namespace chromeos