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.
5 #include "ash/system/chromeos/network/network_connect.h"
7 #include "ash/session/session_state_delegate.h"
9 #include "ash/system/chromeos/network/network_state_notifier.h"
10 #include "ash/system/system_notifier.h"
11 #include "ash/system/tray/system_tray_delegate.h"
12 #include "ash/system/tray/system_tray_notifier.h"
13 #include "base/bind.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "chromeos/login/login_state.h"
18 #include "chromeos/network/device_state.h"
19 #include "chromeos/network/network_activation_handler.h"
20 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_connection_handler.h"
22 #include "chromeos/network/network_event_log.h"
23 #include "chromeos/network/network_handler_callbacks.h"
24 #include "chromeos/network/network_profile.h"
25 #include "chromeos/network/network_profile_handler.h"
26 #include "chromeos/network/network_state.h"
27 #include "chromeos/network/network_state_handler.h"
28 #include "chromeos/network/shill_property_util.h"
29 #include "grit/ash_resources.h"
30 #include "grit/ash_strings.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/resource/resource_bundle.h"
34 #include "ui/message_center/message_center.h"
35 #include "ui/message_center/notification.h"
37 using chromeos::DeviceState;
38 using chromeos::NetworkConfigurationHandler;
39 using chromeos::NetworkConnectionHandler;
40 using chromeos::NetworkHandler;
41 using chromeos::NetworkProfile;
42 using chromeos::NetworkProfileHandler;
43 using chromeos::NetworkState;
44 using chromeos::NetworkStateHandler;
45 using chromeos::NetworkTypePattern;
51 // TODO(stevenjb): This should be in service_constants.h
52 const char kErrorInProgress[] = "org.chromium.flimflam.Error.InProgress";
54 // Returns true for carriers that can be activated through Shill instead of
55 // through a WebUI dialog.
56 bool IsDirectActivatedCarrier(const std::string& carrier) {
57 if (carrier == shill::kCarrierSprint)
62 void ShowErrorNotification(const std::string& error_name,
63 const std::string& service_path) {
64 Shell::GetInstance()->system_tray_notifier()->network_state_notifier()->
65 ShowNetworkConnectError(error_name, service_path);
68 void HandleUnconfiguredNetwork(const std::string& service_path,
69 gfx::NativeWindow parent_window) {
70 const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
71 GetNetworkState(service_path);
73 NET_LOG_ERROR("Configuring unknown network", service_path);
77 if (network->type() == shill::kTypeWifi) {
78 // Only show the config view for secure networks, otherwise do nothing.
79 if (network->security() != shill::kSecurityNone) {
80 ash::Shell::GetInstance()->system_tray_delegate()->
81 ShowNetworkConfigure(service_path, parent_window);
86 if (network->type() == shill::kTypeWimax ||
87 network->type() == shill::kTypeVPN) {
88 ash::Shell::GetInstance()->system_tray_delegate()->
89 ShowNetworkConfigure(service_path, parent_window);
93 if (network->type() == shill::kTypeCellular) {
94 if (network->RequiresActivation()) {
95 ash::network_connect::ActivateCellular(service_path);
98 if (network->cellular_out_of_credits()) {
99 ash::network_connect::ShowMobileSetup(service_path);
102 // No special configure or setup for |network|, show the settings UI.
103 if (chromeos::LoginState::Get()->IsUserLoggedIn()) {
104 ash::Shell::GetInstance()->system_tray_delegate()->
105 ShowNetworkSettings(service_path);
112 // If |shared| is true, sets |profile_path| to the shared profile path.
113 // Otherwise sets |profile_path| to the user profile path if authenticated and
114 // available. Returns 'false' if unable to set |profile_path|.
115 bool GetNetworkProfilePath(bool shared, std::string* profile_path) {
117 *profile_path = NetworkProfileHandler::GetSharedProfilePath();
121 if (!chromeos::LoginState::Get()->UserHasNetworkProfile()) {
122 NET_LOG_ERROR("User profile specified before login", "");
126 const NetworkProfile* profile =
127 NetworkHandler::Get()->network_profile_handler()->
128 GetDefaultUserProfile();
130 NET_LOG_ERROR("No user profile for unshared network configuration", "");
134 *profile_path = profile->path;
138 void OnConnectFailed(const std::string& service_path,
139 gfx::NativeWindow parent_window,
140 const std::string& error_name,
141 scoped_ptr<base::DictionaryValue> error_data) {
142 NET_LOG_ERROR("Connect Failed: " + error_name, service_path);
144 if (!ash::Shell::HasInstance())
147 // If a new connect attempt canceled this connect, no need to notify the user.
148 if (error_name == NetworkConnectionHandler::kErrorConnectCanceled)
151 if (error_name == shill::kErrorBadPassphrase ||
152 error_name == NetworkConnectionHandler::kErrorPassphraseRequired ||
153 error_name == NetworkConnectionHandler::kErrorConfigurationRequired ||
154 error_name == NetworkConnectionHandler::kErrorAuthenticationRequired) {
155 HandleUnconfiguredNetwork(service_path, parent_window);
159 if (error_name == NetworkConnectionHandler::kErrorCertificateRequired) {
160 if (!ash::Shell::GetInstance()->system_tray_delegate()->EnrollNetwork(
161 service_path, parent_window)) {
162 HandleUnconfiguredNetwork(service_path, parent_window);
167 if (error_name == NetworkConnectionHandler::kErrorActivationRequired) {
168 network_connect::ActivateCellular(service_path);
172 if (error_name == NetworkConnectionHandler::kErrorConnected ||
173 error_name == NetworkConnectionHandler::kErrorConnecting) {
174 network_connect::ShowNetworkSettings(service_path);
178 // ConnectFailed or unknown error; show a notification.
179 ShowErrorNotification(error_name, service_path);
181 // Only show a configure dialog if there was a ConnectFailed error and the
182 // screen is not locked.
183 if (error_name != shill::kErrorConnectFailed ||
184 Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
187 // If Shill reports an InProgress error, don't try to configure the network.
188 std::string dbus_error_name;
189 error_data.get()->GetString(
190 chromeos::network_handler::kDbusErrorName, &dbus_error_name);
191 if (dbus_error_name == kErrorInProgress)
194 HandleUnconfiguredNetwork(service_path, parent_window);
197 void OnConnectSucceeded(const std::string& service_path) {
198 NET_LOG_USER("Connect Succeeded", service_path);
199 if (!ash::Shell::HasInstance())
201 message_center::MessageCenter::Get()->RemoveNotification(
202 network_connect::kNetworkConnectNotificationId, false /* not by user */);
205 // If |check_error_state| is true, error state for the network is checked,
206 // otherwise any current error state is ignored (e.g. for recently configured
207 // networks or repeat connect attempts). |parent_window| will be used to parent
208 // any configuration UI on failure and may be NULL (in which case the default
209 // window will be used).
210 void CallConnectToNetwork(const std::string& service_path,
211 bool check_error_state,
212 gfx::NativeWindow parent_window) {
213 if (!ash::Shell::HasInstance())
215 message_center::MessageCenter::Get()->RemoveNotification(
216 network_connect::kNetworkConnectNotificationId, false /* not by user */);
218 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
220 base::Bind(&OnConnectSucceeded, service_path),
221 base::Bind(&OnConnectFailed, service_path, parent_window),
225 void OnActivateFailed(const std::string& service_path,
226 const std::string& error_name,
227 scoped_ptr<base::DictionaryValue> error_data) {
228 NET_LOG_ERROR("Unable to activate network", service_path);
229 ShowErrorNotification(network_connect::kErrorActivateFailed, service_path);
232 void OnActivateSucceeded(const std::string& service_path) {
233 NET_LOG_USER("Activation Succeeded", service_path);
236 void OnConfigureFailed(const std::string& error_name,
237 scoped_ptr<base::DictionaryValue> error_data) {
238 NET_LOG_ERROR("Unable to configure network", "");
239 ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
242 void OnConfigureSucceeded(bool connect_on_configure,
243 const std::string& service_path) {
244 NET_LOG_USER("Configure Succeeded", service_path);
245 if (!connect_on_configure)
247 // After configuring a network, ignore any (possibly stale) error state.
248 const bool check_error_state = false;
249 const gfx::NativeWindow parent_window = NULL;
250 CallConnectToNetwork(service_path, check_error_state, parent_window);
253 void CallCreateConfiguration(base::DictionaryValue* properties,
255 bool connect_on_configure) {
256 std::string profile_path;
257 if (!GetNetworkProfilePath(shared, &profile_path)) {
258 ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
261 properties->SetStringWithoutPathExpansion(
262 shill::kProfileProperty, profile_path);
263 NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
265 base::Bind(&OnConfigureSucceeded, connect_on_configure),
266 base::Bind(&OnConfigureFailed));
269 void SetPropertiesFailed(const std::string& desc,
270 const std::string& service_path,
271 const std::string& config_error_name,
272 scoped_ptr<base::DictionaryValue> error_data) {
273 NET_LOG_ERROR(desc + ": Failed: " + config_error_name, service_path);
274 ShowErrorNotification(
275 NetworkConnectionHandler::kErrorConfigureFailed, service_path);
278 void SetPropertiesToClear(base::DictionaryValue* properties_to_set,
279 std::vector<std::string>* properties_to_clear) {
280 // Move empty string properties to properties_to_clear.
281 for (base::DictionaryValue::Iterator iter(*properties_to_set);
282 !iter.IsAtEnd(); iter.Advance()) {
283 std::string value_str;
284 if (iter.value().GetAsString(&value_str) && value_str.empty())
285 properties_to_clear->push_back(iter.key());
287 // Remove cleared properties from properties_to_set.
288 for (std::vector<std::string>::iterator iter = properties_to_clear->begin();
289 iter != properties_to_clear->end(); ++iter) {
290 properties_to_set->RemoveWithoutPathExpansion(*iter, NULL);
294 void ClearPropertiesAndConnect(
295 const std::string& service_path,
296 const std::vector<std::string>& properties_to_clear) {
297 NET_LOG_USER("ClearPropertiesAndConnect", service_path);
298 // After configuring a network, ignore any (possibly stale) error state.
299 const bool check_error_state = false;
300 const gfx::NativeWindow parent_window = NULL;
301 NetworkHandler::Get()->network_configuration_handler()->ClearProperties(
304 base::Bind(&CallConnectToNetwork,
305 service_path, check_error_state,
307 base::Bind(&SetPropertiesFailed, "ClearProperties", service_path));
310 void ConfigureSetProfileSucceeded(
311 const std::string& service_path,
312 scoped_ptr<base::DictionaryValue> properties_to_set) {
313 std::vector<std::string> properties_to_clear;
314 SetPropertiesToClear(properties_to_set.get(), &properties_to_clear);
315 NetworkHandler::Get()->network_configuration_handler()->SetProperties(
318 base::Bind(&ClearPropertiesAndConnect,
320 properties_to_clear),
321 base::Bind(&SetPropertiesFailed, "SetProperties", service_path));
324 const NetworkState* GetNetworkState(const std::string& service_path) {
325 return NetworkHandler::Get()->network_state_handler()->
326 GetNetworkState(service_path);
331 namespace network_connect {
333 const char kNetworkConnectNotificationId[] =
334 "chrome://settings/internet/connect";
335 const char kNetworkActivateNotificationId[] =
336 "chrome://settings/internet/activate";
338 const char kErrorActivateFailed[] = "activate-failed";
340 void ConnectToNetwork(const std::string& service_path,
341 gfx::NativeWindow parent_window) {
342 NET_LOG_USER("ConnectToNetwork", service_path);
343 const NetworkState* network = GetNetworkState(service_path);
344 if (network && !network->error().empty() && !network->security().empty()) {
345 NET_LOG_USER("Configure: " + network->error(), service_path);
346 // If the network is in an error state, show the configuration UI directly
347 // to avoid a spurious notification.
348 HandleUnconfiguredNetwork(service_path, parent_window);
351 const bool check_error_state = true;
352 CallConnectToNetwork(service_path, check_error_state, parent_window);
355 void SetTechnologyEnabled(const NetworkTypePattern& technology,
356 bool enabled_state) {
357 std::string log_string =
358 base::StringPrintf("technology %s, target state: %s",
359 technology.ToDebugString().c_str(),
360 (enabled_state ? "ENABLED" : "DISABLED"));
361 NET_LOG_USER("SetTechnologyEnabled", log_string);
362 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
363 bool enabled = handler->IsTechnologyEnabled(technology);
364 if (enabled_state == enabled) {
365 NET_LOG_USER("Technology already in target state.", log_string);
369 // User requested to disable the technology.
370 handler->SetTechnologyEnabled(
371 technology, false, chromeos::network_handler::ErrorCallback());
374 // If we're dealing with a mobile network, then handle SIM lock here.
375 // SIM locking only applies to cellular, so the code below won't execute
376 // if |technology| has been explicitly set to WiMAX.
377 if (technology.MatchesPattern(NetworkTypePattern::Mobile())) {
378 const DeviceState* mobile = handler->GetDeviceStateByType(technology);
380 NET_LOG_ERROR("SetTechnologyEnabled with no device", log_string);
383 // The following only applies to cellular.
384 if (mobile->type() == shill::kTypeCellular) {
385 if (mobile->IsSimAbsent()) {
386 // If this is true, then we have a cellular device with no SIM inserted.
387 // TODO(armansito): Chrome should display a notification here, prompting
388 // the user to insert a SIM card and restart the device to enable
389 // cellular. See crbug.com/125171.
390 NET_LOG_USER("Cannot enable cellular device without SIM.", log_string);
393 if (!mobile->sim_lock_type().empty()) {
394 // A SIM has been inserted, but it is locked. Let the user unlock it
396 ash::Shell::GetInstance()->system_tray_delegate()->
397 ShowMobileSimDialog();
402 handler->SetTechnologyEnabled(
403 technology, true, chromeos::network_handler::ErrorCallback());
406 void ActivateCellular(const std::string& service_path) {
407 NET_LOG_USER("ActivateCellular", service_path);
408 const NetworkState* cellular = GetNetworkState(service_path);
409 if (!cellular || cellular->type() != shill::kTypeCellular) {
410 NET_LOG_ERROR("ActivateCellular with no Service", service_path);
413 const DeviceState* cellular_device =
414 NetworkHandler::Get()->network_state_handler()->
415 GetDeviceState(cellular->device_path());
416 if (!cellular_device) {
417 NET_LOG_ERROR("ActivateCellular with no Device", service_path);
420 if (!IsDirectActivatedCarrier(cellular_device->carrier())) {
421 // For non direct activation, show the mobile setup dialog which can be
422 // used to activate the network.
423 ShowMobileSetup(service_path);
426 if (cellular->activation_state() == shill::kActivationStateActivated) {
427 NET_LOG_ERROR("ActivateCellular for activated service", service_path);
431 NetworkHandler::Get()->network_activation_handler()->Activate(
434 base::Bind(&OnActivateSucceeded, service_path),
435 base::Bind(&OnActivateFailed, service_path));
438 void ShowMobileSetup(const std::string& service_path) {
439 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
440 const NetworkState* cellular = handler->GetNetworkState(service_path);
441 if (!cellular || cellular->type() != shill::kTypeCellular) {
442 NET_LOG_ERROR("ShowMobileSetup without Cellular network", service_path);
445 if (cellular->activation_state() != shill::kActivationStateActivated &&
446 cellular->activate_over_non_cellular_networks() &&
447 !handler->DefaultNetwork()) {
448 message_center::MessageCenter::Get()->AddNotification(
449 message_center::Notification::CreateSystemNotification(
450 kNetworkActivateNotificationId,
451 l10n_util::GetStringUTF16(IDS_NETWORK_ACTIVATION_ERROR_TITLE),
452 l10n_util::GetStringFUTF16(IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION,
453 base::UTF8ToUTF16(cellular->name())),
454 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
455 IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED),
456 ash::system_notifier::kNotifierNetworkError,
457 base::Bind(&ash::network_connect::ShowNetworkSettings,
461 ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetupDialog(
465 void ConfigureNetworkAndConnect(const std::string& service_path,
466 const base::DictionaryValue& properties,
468 NET_LOG_USER("ConfigureNetworkAndConnect", service_path);
470 scoped_ptr<base::DictionaryValue> properties_to_set(properties.DeepCopy());
472 std::string profile_path;
473 if (!GetNetworkProfilePath(shared, &profile_path)) {
474 ShowErrorNotification(
475 NetworkConnectionHandler::kErrorConfigureFailed, service_path);
478 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
479 service_path, profile_path,
480 base::Bind(&ConfigureSetProfileSucceeded,
481 service_path, base::Passed(&properties_to_set)),
482 base::Bind(&SetPropertiesFailed,
483 "SetProfile: " + profile_path, service_path));
486 void CreateConfigurationAndConnect(base::DictionaryValue* properties,
488 NET_LOG_USER("CreateConfigurationAndConnect", "");
489 CallCreateConfiguration(properties, shared, true /* connect_on_configure */);
492 void CreateConfiguration(base::DictionaryValue* properties, bool shared) {
493 NET_LOG_USER("CreateConfiguration", "");
494 CallCreateConfiguration(properties, shared, false /* connect_on_configure */);
497 base::string16 ErrorString(const std::string& error,
498 const std::string& service_path) {
500 return base::string16();
501 if (error == shill::kErrorOutOfRange)
502 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE);
503 if (error == shill::kErrorPinMissing)
504 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING);
505 if (error == shill::kErrorDhcpFailed)
506 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED);
507 if (error == shill::kErrorConnectFailed)
508 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
509 if (error == shill::kErrorBadPassphrase)
510 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE);
511 if (error == shill::kErrorBadWEPKey)
512 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY);
513 if (error == shill::kErrorActivationFailed) {
514 return l10n_util::GetStringUTF16(
515 IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
517 if (error == shill::kErrorNeedEvdo)
518 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO);
519 if (error == shill::kErrorNeedHomeNetwork) {
520 return l10n_util::GetStringUTF16(
521 IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK);
523 if (error == shill::kErrorOtaspFailed)
524 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED);
525 if (error == shill::kErrorAaaFailed)
526 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED);
527 if (error == shill::kErrorInternal)
528 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_INTERNAL);
529 if (error == shill::kErrorDNSLookupFailed) {
530 return l10n_util::GetStringUTF16(
531 IDS_CHROMEOS_NETWORK_ERROR_DNS_LOOKUP_FAILED);
533 if (error == shill::kErrorHTTPGetFailed) {
534 return l10n_util::GetStringUTF16(
535 IDS_CHROMEOS_NETWORK_ERROR_HTTP_GET_FAILED);
537 if (error == shill::kErrorIpsecPskAuthFailed) {
538 return l10n_util::GetStringUTF16(
539 IDS_CHROMEOS_NETWORK_ERROR_IPSEC_PSK_AUTH_FAILED);
541 if (error == shill::kErrorIpsecCertAuthFailed) {
542 return l10n_util::GetStringUTF16(
543 IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
545 if (error == shill::kErrorEapAuthenticationFailed) {
546 const NetworkState* network = GetNetworkState(service_path);
547 // TLS always requires a client certificate, so show a cert auth
548 // failed message for TLS. Other EAP methods do not generally require
549 // a client certicate.
550 if (network && network->eap_method() == shill::kEapMethodTLS) {
551 return l10n_util::GetStringUTF16(
552 IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
554 return l10n_util::GetStringUTF16(
555 IDS_CHROMEOS_NETWORK_ERROR_EAP_AUTH_FAILED);
558 if (error == shill::kErrorEapLocalTlsFailed) {
559 return l10n_util::GetStringUTF16(
560 IDS_CHROMEOS_NETWORK_ERROR_EAP_LOCAL_TLS_FAILED);
562 if (error == shill::kErrorEapRemoteTlsFailed) {
563 return l10n_util::GetStringUTF16(
564 IDS_CHROMEOS_NETWORK_ERROR_EAP_REMOTE_TLS_FAILED);
566 if (error == shill::kErrorPppAuthFailed) {
567 return l10n_util::GetStringUTF16(
568 IDS_CHROMEOS_NETWORK_ERROR_PPP_AUTH_FAILED);
571 if (StringToLowerASCII(error) ==
572 StringToLowerASCII(std::string(shill::kUnknownString))) {
573 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
575 return l10n_util::GetStringFUTF16(IDS_NETWORK_UNRECOGNIZED_ERROR,
576 base::UTF8ToUTF16(error));
579 void ShowNetworkSettings(const std::string& service_path) {
580 if (!ash::Shell::HasInstance())
582 ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(