1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ash/system/chromeos/network/network_connect.h" 6 7#include "ash/shell.h" 8#include "ash/system/chromeos/network/network_observer.h" 9#include "ash/system/chromeos/network/network_state_notifier.h" 10#include "ash/system/tray/system_tray_delegate.h" 11#include "ash/system/tray/system_tray_notifier.h" 12#include "base/bind.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/strings/utf_string_conversions.h" 15#include "base/values.h" 16#include "chromeos/login/login_state.h" 17#include "chromeos/network/device_state.h" 18#include "chromeos/network/network_configuration_handler.h" 19#include "chromeos/network/network_connection_handler.h" 20#include "chromeos/network/network_event_log.h" 21#include "chromeos/network/network_handler_callbacks.h" 22#include "chromeos/network/network_profile.h" 23#include "chromeos/network/network_profile_handler.h" 24#include "chromeos/network/network_state.h" 25#include "chromeos/network/network_state_handler.h" 26#include "grit/ash_strings.h" 27#include "third_party/cros_system_api/dbus/service_constants.h" 28#include "ui/base/l10n/l10n_util.h" 29 30using chromeos::DeviceState; 31using chromeos::NetworkConfigurationHandler; 32using chromeos::NetworkConnectionHandler; 33using chromeos::NetworkHandler; 34using chromeos::NetworkProfile; 35using chromeos::NetworkProfileHandler; 36using chromeos::NetworkState; 37 38namespace ash { 39 40namespace { 41 42// TODO(stevenjb): This should be in service_constants.h 43const char kErrorInProgress[] = "org.chromium.flimflam.Error.InProgress"; 44 45// Returns true for carriers that can be activated through Shill instead of 46// through a WebUI dialog. 47bool IsDirectActivatedCarrier(const std::string& carrier) { 48 if (carrier == shill::kCarrierSprint) 49 return true; 50 return false; 51} 52 53void ShowErrorNotification(const std::string& error, 54 const std::string& service_path) { 55 Shell::GetInstance()->system_tray_notifier()->network_state_notifier()-> 56 ShowNetworkConnectError(error, service_path); 57} 58 59void OnConnectFailed(const std::string& service_path, 60 gfx::NativeWindow owning_window, 61 const std::string& error_name, 62 scoped_ptr<base::DictionaryValue> error_data) { 63 NET_LOG_ERROR("Connect Failed: " + error_name, service_path); 64 65 // If a new connect attempt canceled this connect, no need to notify the user. 66 if (error_name == NetworkConnectionHandler::kErrorConnectCanceled) 67 return; 68 69 if (error_name == flimflam::kErrorBadPassphrase || 70 error_name == NetworkConnectionHandler::kErrorPassphraseRequired || 71 error_name == NetworkConnectionHandler::kErrorConfigurationRequired || 72 error_name == NetworkConnectionHandler::kErrorAuthenticationRequired) { 73 ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork( 74 service_path); 75 return; 76 } 77 78 if (error_name == NetworkConnectionHandler::kErrorCertificateRequired) { 79 ash::Shell::GetInstance()->system_tray_delegate()->EnrollOrConfigureNetwork( 80 service_path, owning_window); 81 return; 82 } 83 84 if (error_name == NetworkConnectionHandler::kErrorActivationRequired) { 85 network_connect::ActivateCellular(service_path); 86 return; 87 } 88 89 if (error_name == NetworkConnectionHandler::kErrorConnected || 90 error_name == NetworkConnectionHandler::kErrorConnecting) { 91 ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings( 92 service_path); 93 return; 94 } 95 96 // ConnectFailed or unknown error; show a notification. 97 ShowErrorNotification(error_name, service_path); 98 99 // Show a configure dialog for ConnectFailed errors. 100 if (error_name != flimflam::kErrorConnectFailed) 101 return; 102 103 // If Shill reports an InProgress error, don't try to configure the network. 104 std::string dbus_error_name; 105 error_data.get()->GetString( 106 chromeos::network_handler::kDbusErrorName, &dbus_error_name); 107 if (dbus_error_name == kErrorInProgress) 108 return; 109 110 ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork( 111 service_path); 112} 113 114void OnConnectSucceeded(const std::string& service_path) { 115 NET_LOG_USER("Connect Succeeded", service_path); 116 ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage( 117 NetworkObserver::ERROR_CONNECT_FAILED); 118} 119 120// If |check_error_state| is true, error state for the network is checked, 121// otherwise any current error state is ignored (e.g. for recently configured 122// networks or repeat connect attempts). |owning_window| will be used to parent 123// any configuration UI on failure and may be NULL (in which case the default 124// window will be used). 125void CallConnectToNetwork(const std::string& service_path, 126 bool check_error_state, 127 gfx::NativeWindow owning_window) { 128 NET_LOG_USER("ConnectToNetwork", service_path); 129 130 ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage( 131 NetworkObserver::ERROR_CONNECT_FAILED); 132 133 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork( 134 service_path, 135 base::Bind(&OnConnectSucceeded, service_path), 136 base::Bind(&OnConnectFailed, service_path, owning_window), 137 check_error_state); 138} 139 140void OnActivateFailed(const std::string& service_path, 141 const std::string& error_name, 142 scoped_ptr<base::DictionaryValue> error_data) { 143 NET_LOG_ERROR("Unable to activate network", service_path); 144 ShowErrorNotification(network_connect::kErrorActivateFailed, service_path); 145} 146 147void OnActivateSucceeded(const std::string& service_path) { 148 NET_LOG_USER("Activation Succeeded", service_path); 149} 150 151void OnConfigureFailed(const std::string& error_name, 152 scoped_ptr<base::DictionaryValue> error_data) { 153 NET_LOG_ERROR("Unable to configure network", ""); 154 ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, ""); 155} 156 157void OnConfigureSucceeded(const std::string& service_path) { 158 NET_LOG_USER("Configure Succeeded", service_path); 159 // After configuring a network, ignore any (possibly stale) error state. 160 const bool check_error_state = false; 161 const gfx::NativeWindow owning_window = NULL; 162 CallConnectToNetwork(service_path, check_error_state, owning_window); 163} 164 165void SetPropertiesFailed(const std::string& desc, 166 const std::string& service_path, 167 const std::string& config_error_name, 168 scoped_ptr<base::DictionaryValue> error_data) { 169 NET_LOG_ERROR(desc + ": Failed: " + config_error_name, service_path); 170 ShowErrorNotification( 171 NetworkConnectionHandler::kErrorConfigureFailed, service_path); 172} 173 174void SetPropertiesToClear(base::DictionaryValue* properties_to_set, 175 std::vector<std::string>* properties_to_clear) { 176 // Move empty string properties to properties_to_clear. 177 for (base::DictionaryValue::Iterator iter(*properties_to_set); 178 !iter.IsAtEnd(); iter.Advance()) { 179 std::string value_str; 180 if (iter.value().GetAsString(&value_str) && value_str.empty()) 181 properties_to_clear->push_back(iter.key()); 182 } 183 // Remove cleared properties from properties_to_set. 184 for (std::vector<std::string>::iterator iter = properties_to_clear->begin(); 185 iter != properties_to_clear->end(); ++iter) { 186 properties_to_set->RemoveWithoutPathExpansion(*iter, NULL); 187 } 188} 189 190void ClearPropertiesAndConnect( 191 const std::string& service_path, 192 const std::vector<std::string>& properties_to_clear) { 193 NET_LOG_USER("ClearPropertiesAndConnect", service_path); 194 // After configuring a network, ignore any (possibly stale) error state. 195 const bool check_error_state = false; 196 const gfx::NativeWindow owning_window = NULL; 197 NetworkHandler::Get()->network_configuration_handler()->ClearProperties( 198 service_path, 199 properties_to_clear, 200 base::Bind(&CallConnectToNetwork, 201 service_path, check_error_state, 202 owning_window), 203 base::Bind(&SetPropertiesFailed, "ClearProperties", service_path)); 204} 205 206// Returns false if !shared and no valid profile is available, which will 207// trigger an error and abort. 208bool GetNetworkProfilePath(bool shared, std::string* profile_path) { 209 if (shared) { 210 *profile_path = NetworkProfileHandler::kSharedProfilePath; 211 return true; 212 } 213 214 if (!chromeos::LoginState::Get()->IsUserAuthenticated()) { 215 NET_LOG_ERROR("User profile specified before login", ""); 216 return false; 217 } 218 219 const NetworkProfile* profile = 220 NetworkHandler::Get()->network_profile_handler()-> 221 GetDefaultUserProfile(); 222 if (!profile) { 223 NET_LOG_ERROR("No user profile for unshared network configuration", ""); 224 return false; 225 } 226 227 *profile_path = profile->path; 228 return true; 229} 230 231void ConfigureSetProfileSucceeded( 232 const std::string& service_path, 233 scoped_ptr<base::DictionaryValue> properties_to_set) { 234 std::vector<std::string> properties_to_clear; 235 SetPropertiesToClear(properties_to_set.get(), &properties_to_clear); 236 NetworkHandler::Get()->network_configuration_handler()->SetProperties( 237 service_path, 238 *properties_to_set, 239 base::Bind(&ClearPropertiesAndConnect, 240 service_path, 241 properties_to_clear), 242 base::Bind(&SetPropertiesFailed, "SetProperties", service_path)); 243} 244 245} // namespace 246 247namespace network_connect { 248 249const char kErrorActivateFailed[] = "activate-failed"; 250 251void ConnectToNetwork(const std::string& service_path, 252 gfx::NativeWindow owning_window) { 253 const bool check_error_state = true; 254 CallConnectToNetwork(service_path, check_error_state, owning_window); 255} 256 257void ActivateCellular(const std::string& service_path) { 258 NET_LOG_USER("ActivateCellular", service_path); 259 const NetworkState* cellular = 260 NetworkHandler::Get()->network_state_handler()-> 261 GetNetworkState(service_path); 262 if (!cellular || cellular->type() != flimflam::kTypeCellular) { 263 NET_LOG_ERROR("ActivateCellular with no Service", service_path); 264 return; 265 } 266 const DeviceState* cellular_device = 267 NetworkHandler::Get()->network_state_handler()-> 268 GetDeviceState(cellular->device_path()); 269 if (!cellular_device) { 270 NET_LOG_ERROR("ActivateCellular with no Device", service_path); 271 return; 272 } 273 if (!IsDirectActivatedCarrier(cellular_device->carrier())) { 274 // For non direct activation, show the mobile setup dialog which can be 275 // used to activate the network. Only show the dialog, if an account 276 // management URL is available. 277 if (!cellular->payment_url().empty()) 278 ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetup( 279 service_path); 280 return; 281 } 282 if (cellular->activation_state() == flimflam::kActivationStateActivated) { 283 NET_LOG_ERROR("ActivateCellular for activated service", service_path); 284 return; 285 } 286 287 NetworkHandler::Get()->network_connection_handler()->ActivateNetwork( 288 service_path, 289 "", // carrier 290 base::Bind(&OnActivateSucceeded, service_path), 291 base::Bind(&OnActivateFailed, service_path)); 292} 293 294void ConfigureNetworkAndConnect(const std::string& service_path, 295 const base::DictionaryValue& properties, 296 bool shared) { 297 NET_LOG_USER("ConfigureNetworkAndConnect", service_path); 298 299 scoped_ptr<base::DictionaryValue> properties_to_set(properties.DeepCopy()); 300 301 std::string profile_path; 302 if (!GetNetworkProfilePath(shared, &profile_path)) { 303 ShowErrorNotification( 304 NetworkConnectionHandler::kErrorConfigureFailed, service_path); 305 return; 306 } 307 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile( 308 service_path, profile_path, 309 base::Bind(&ConfigureSetProfileSucceeded, 310 service_path, base::Passed(&properties_to_set)), 311 base::Bind(&SetPropertiesFailed, 312 "SetProfile: " + profile_path, service_path)); 313} 314 315void CreateConfigurationAndConnect(base::DictionaryValue* properties, 316 bool shared) { 317 NET_LOG_USER("CreateConfigurationAndConnect", ""); 318 std::string profile_path; 319 if (!GetNetworkProfilePath(shared, &profile_path)) { 320 ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, ""); 321 return; 322 } 323 properties->SetStringWithoutPathExpansion( 324 flimflam::kProfileProperty, profile_path); 325 NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration( 326 *properties, 327 base::Bind(&OnConfigureSucceeded), 328 base::Bind(&OnConfigureFailed)); 329} 330 331string16 ErrorString(const std::string& error) { 332 if (error.empty()) 333 return string16(); 334 if (error == flimflam::kErrorOutOfRange) 335 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE); 336 if (error == flimflam::kErrorPinMissing) 337 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING); 338 if (error == flimflam::kErrorDhcpFailed) 339 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED); 340 if (error == flimflam::kErrorConnectFailed) 341 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED); 342 if (error == flimflam::kErrorBadPassphrase) 343 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE); 344 if (error == flimflam::kErrorBadWEPKey) 345 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY); 346 if (error == flimflam::kErrorActivationFailed) { 347 return l10n_util::GetStringUTF16( 348 IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED); 349 } 350 if (error == flimflam::kErrorNeedEvdo) 351 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO); 352 if (error == flimflam::kErrorNeedHomeNetwork) { 353 return l10n_util::GetStringUTF16( 354 IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK); 355 } 356 if (error == flimflam::kErrorOtaspFailed) 357 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED); 358 if (error == flimflam::kErrorAaaFailed) 359 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED); 360 if (error == flimflam::kErrorInternal) 361 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_INTERNAL); 362 if (error == flimflam::kErrorDNSLookupFailed) { 363 return l10n_util::GetStringUTF16( 364 IDS_CHROMEOS_NETWORK_ERROR_DNS_LOOKUP_FAILED); 365 } 366 if (error == flimflam::kErrorHTTPGetFailed) { 367 return l10n_util::GetStringUTF16( 368 IDS_CHROMEOS_NETWORK_ERROR_HTTP_GET_FAILED); 369 } 370 if (error == flimflam::kErrorIpsecPskAuthFailed) { 371 return l10n_util::GetStringUTF16( 372 IDS_CHROMEOS_NETWORK_ERROR_IPSEC_PSK_AUTH_FAILED); 373 } 374 if (error == flimflam::kErrorIpsecCertAuthFailed || 375 error == shill::kErrorEapAuthenticationFailed) { 376 return l10n_util::GetStringUTF16( 377 IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED); 378 } 379 if (error == shill::kErrorEapLocalTlsFailed) { 380 return l10n_util::GetStringUTF16( 381 IDS_CHROMEOS_NETWORK_ERROR_EAP_LOCAL_TLS_FAILED); 382 } 383 if (error == shill::kErrorEapRemoteTlsFailed) { 384 return l10n_util::GetStringUTF16( 385 IDS_CHROMEOS_NETWORK_ERROR_EAP_REMOTE_TLS_FAILED); 386 } 387 if (error == flimflam::kErrorPppAuthFailed) { 388 return l10n_util::GetStringUTF16( 389 IDS_CHROMEOS_NETWORK_ERROR_PPP_AUTH_FAILED); 390 } 391 392 if (StringToLowerASCII(error) == 393 StringToLowerASCII(std::string(flimflam::kUnknownString))) { 394 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN); 395 } 396 return l10n_util::GetStringFUTF16(IDS_NETWORK_UNRECOGNIZED_ERROR, 397 UTF8ToUTF16(error)); 398} 399 400} // network_connect 401} // ash 402