1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// found in the LICENSE file. 4010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/shell/browser/shell_network_controller_chromeos.h" 6010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/bind.h" 8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/location.h" 9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/logging.h" 10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/strings/stringprintf.h" 11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/time/time.h" 12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_connection_handler.h" 13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_handler.h" 14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_handler_callbacks.h" 15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_state.h" 16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chromeos/network/network_state_handler.h" 17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h" 18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace extensions { 20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace { 22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Frequency at which networks should be scanned when not connected to a network 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// or when connected to a non-preferred network. 25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const int kScanIntervalSec = 10; 26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void HandleEnableWifiError(const std::string& error_name, 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_ptr<base::DictionaryValue> error_data) { 29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) LOG(WARNING) << "Unable to enable wifi: " << error_name; 30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Returns a human-readable name for the network described by |network|. 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::string GetNetworkName(const chromeos::NetworkState& network) { 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return !network.name().empty() 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ? network.name() 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : base::StringPrintf("[%s]", network.type().c_str()); 37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Returns true if shill is either connected or connecting to a network. 40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool IsConnectedOrConnecting() { 41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkStateHandler* state_handler = 42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkHandler::Get()->network_state_handler(); 43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return state_handler->ConnectedNetworkByType( 44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkTypePattern::Default()) || 45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) state_handler->ConnectingNetworkByType( 46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkTypePattern::Default()); 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} // namespace 50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 51116680a4aac90f2aa7413d9095a592090648e557Ben MurdochShellNetworkController::ShellNetworkController( 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const std::string& preferred_network_name) 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : state_(STATE_IDLE), 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch preferred_network_name_(preferred_network_name), 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch preferred_network_is_active_(false), 56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) weak_ptr_factory_(this) { 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkStateHandler* state_handler = 58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkHandler::Get()->network_state_handler(); 59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) state_handler->AddObserver(this, FROM_HERE); 60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) state_handler->SetTechnologyEnabled( 61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi), 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) true, 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&HandleEnableWifiError)); 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // If we're unconnected, trigger a connection attempt and start scanning. 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch NetworkConnectionStateChanged(NULL); 67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ShellNetworkController::~ShellNetworkController() { 70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( 71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) this, FROM_HERE); 72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::NetworkListChanged() { 75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Network list changed"; 76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ConnectIfUnconnected(); 77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ShellNetworkController::NetworkConnectionStateChanged( 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const chromeos::NetworkState* network) { 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (network) { 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Network connection state changed:" 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << " name=" << GetNetworkName(*network) 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << " type=" << network->type() << " path=" << network->path() 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << " state=" << network->connection_state(); 86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Network connection state changed: [none]"; 88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const chromeos::NetworkState* wifi_network = GetActiveWiFiNetwork(); 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch preferred_network_is_active_ = 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch wifi_network && wifi_network->name() == preferred_network_name_; 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Active WiFi network is " 94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << (wifi_network ? wifi_network->name() : std::string("[none]")); 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (preferred_network_is_active_ || 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch (preferred_network_name_.empty() && wifi_network)) { 98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetScanningEnabled(false); 99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetScanningEnabled(true); 101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ConnectIfUnconnected(); 102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const chromeos::NetworkState* ShellNetworkController::GetActiveWiFiNetwork() { 106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkStateHandler* state_handler = 107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkHandler::Get()->network_state_handler(); 108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const chromeos::NetworkState* network = state_handler->FirstNetworkByType( 109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi)); 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return network && 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (network->IsConnectedState() || network->IsConnectingState()) 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ? network 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : NULL; 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::SetScanningEnabled(bool enabled) { 117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const bool currently_enabled = scan_timer_.IsRunning(); 118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (enabled == currently_enabled) 119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning"; 122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (enabled) { 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch RequestScan(); 124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scan_timer_.Start(FROM_HERE, 125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::TimeDelta::FromSeconds(kScanIntervalSec), 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this, 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &ShellNetworkController::RequestScan); 128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scan_timer_.Stop(); 130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 131010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::RequestScan() { 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Requesting scan"; 135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan(); 136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::ConnectIfUnconnected() { 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Don't do anything if the default network is already the preferred one or if 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // we have a pending request to connect to it. 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (preferred_network_is_active_ || 142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state_ == STATE_WAITING_FOR_PREFERRED_RESULT) 143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const chromeos::NetworkState* best_network = NULL; 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool can_connect_to_preferred_network = false; 147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkStateHandler::NetworkStateList network_list; 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) handler->network_state_handler()->GetVisibleNetworkListByType( 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch chromeos::NetworkTypePattern::WiFi(), &network_list); 152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = 1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) network_list.begin(); 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) it != network_list.end(); 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ++it) { 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const chromeos::NetworkState* network = *it; 157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!network->connectable()) 158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) continue; 159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!preferred_network_name_.empty() && 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch network->name() == preferred_network_name_) { 162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch best_network = network; 163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch can_connect_to_preferred_network = true; 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch break; 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } else if (!best_network) { 166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch best_network = network; 167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Don't switch networks if we're already connecting/connected and wouldn't be 171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // switching to the preferred network. 172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if ((IsConnectedOrConnecting() || state_ != STATE_IDLE) && 173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch !can_connect_to_preferred_network) 174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return; 175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!best_network) { 177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Didn't find any connectable networks"; 178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Connecting to network " << GetNetworkName(*best_network) 182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << " with path " << best_network->path() << " and strength " 183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << best_network->signal_strength(); 1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) state_ = can_connect_to_preferred_network 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ? STATE_WAITING_FOR_PREFERRED_RESULT 1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : STATE_WAITING_FOR_NON_PREFERRED_RESULT; 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch handler->network_connection_handler()->ConnectToNetwork( 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch best_network->path(), 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&ShellNetworkController::HandleConnectionSuccess, 190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr()), 191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(&ShellNetworkController::HandleConnectionError, 192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch weak_ptr_factory_.GetWeakPtr()), 193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch false /* check_error_state */); 194010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 195010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 196010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::HandleConnectionSuccess() { 197010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) VLOG(1) << "Successfully connected to network"; 198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state_ = STATE_IDLE; 199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void ShellNetworkController::HandleConnectionError( 202010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const std::string& error_name, 203010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scoped_ptr<base::DictionaryValue> error_data) { 204010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) LOG(WARNING) << "Unable to connect to network: " << error_name; 205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch state_ = STATE_IDLE; 206010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 207010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // namespace extensions 209