Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / system / chromeos / network / network_connect.cc
blobfc9232e8be6134dc9dc824505298ab2769e3a49b
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"
8 #include "ash/shell.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/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chromeos/login/login_state.h"
19 #include "chromeos/network/device_state.h"
20 #include "chromeos/network/network_activation_handler.h"
21 #include "chromeos/network/network_configuration_handler.h"
22 #include "chromeos/network/network_connection_handler.h"
23 #include "chromeos/network/network_event_log.h"
24 #include "chromeos/network/network_handler_callbacks.h"
25 #include "chromeos/network/network_profile.h"
26 #include "chromeos/network/network_profile_handler.h"
27 #include "chromeos/network/network_state.h"
28 #include "chromeos/network/network_state_handler.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;
47 namespace ash {
49 namespace {
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)
58 return true;
59 return false;
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);
72 if (!network) {
73 NET_LOG_ERROR("Configuring unknown network", service_path);
74 return;
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);
83 return;
86 if (network->type() == shill::kTypeWimax ||
87 network->type() == shill::kTypeVPN) {
88 ash::Shell::GetInstance()->system_tray_delegate()->
89 ShowNetworkConfigure(service_path, parent_window);
90 return;
93 if (network->type() == shill::kTypeCellular) {
94 if (network->RequiresActivation()) {
95 ash::network_connect::ActivateCellular(service_path);
96 return;
98 if (network->cellular_out_of_credits()) {
99 ash::network_connect::ShowMobileSetup(service_path);
100 return;
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);
107 return;
109 NOTREACHED();
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) {
116 if (shared) {
117 *profile_path = NetworkProfileHandler::GetSharedProfilePath();
118 return true;
121 if (!chromeos::LoginState::Get()->UserHasNetworkProfile()) {
122 NET_LOG_ERROR("User profile specified before login", "");
123 return false;
126 const NetworkProfile* profile =
127 NetworkHandler::Get()->network_profile_handler()->
128 GetDefaultUserProfile();
129 if (!profile) {
130 NET_LOG_ERROR("No user profile for unshared network configuration", "");
131 return false;
134 *profile_path = profile->path;
135 return true;
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())
145 return;
147 // If a new connect attempt canceled this connect, no need to notify the user.
148 if (error_name == NetworkConnectionHandler::kErrorConnectCanceled)
149 return;
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);
156 return;
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);
164 return;
167 if (error_name == NetworkConnectionHandler::kErrorActivationRequired) {
168 network_connect::ActivateCellular(service_path);
169 return;
172 if (error_name == NetworkConnectionHandler::kErrorConnected ||
173 error_name == NetworkConnectionHandler::kErrorConnecting) {
174 network_connect::ShowNetworkSettings(service_path);
175 return;
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())
185 return;
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)
192 return;
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())
200 return;
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())
214 return;
215 message_center::MessageCenter::Get()->RemoveNotification(
216 network_connect::kNetworkConnectNotificationId, false /* not by user */);
218 NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
219 service_path,
220 base::Bind(&OnConnectSucceeded, service_path),
221 base::Bind(&OnConnectFailed, service_path, parent_window),
222 check_error_state);
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)
246 return;
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,
254 bool shared,
255 bool connect_on_configure) {
256 std::string profile_path;
257 if (!GetNetworkProfilePath(shared, &profile_path)) {
258 ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
259 return;
261 properties->SetStringWithoutPathExpansion(
262 shill::kProfileProperty, profile_path);
263 NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
264 *properties,
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(
302 service_path,
303 properties_to_clear,
304 base::Bind(&CallConnectToNetwork,
305 service_path, check_error_state,
306 parent_window),
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(
316 service_path,
317 *properties_to_set,
318 base::Bind(&ClearPropertiesAndConnect,
319 service_path,
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);
329 } // namespace
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) {
345 if (!network->error().empty() && !network->security().empty()) {
346 NET_LOG_USER("Configure: " + network->error(), service_path);
347 // If the network is in an error state, show the configuration UI directly
348 // to avoid a spurious notification.
349 HandleUnconfiguredNetwork(service_path, parent_window);
350 return;
351 } else if (network->RequiresActivation()) {
352 ActivateCellular(service_path);
353 return;
356 const bool check_error_state = true;
357 CallConnectToNetwork(service_path, check_error_state, parent_window);
360 void SetTechnologyEnabled(const NetworkTypePattern& technology,
361 bool enabled_state) {
362 std::string log_string =
363 base::StringPrintf("technology %s, target state: %s",
364 technology.ToDebugString().c_str(),
365 (enabled_state ? "ENABLED" : "DISABLED"));
366 NET_LOG_USER("SetTechnologyEnabled", log_string);
367 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
368 bool enabled = handler->IsTechnologyEnabled(technology);
369 if (enabled_state == enabled) {
370 NET_LOG_USER("Technology already in target state.", log_string);
371 return;
373 if (enabled) {
374 // User requested to disable the technology.
375 handler->SetTechnologyEnabled(
376 technology, false, chromeos::network_handler::ErrorCallback());
377 return;
379 // If we're dealing with a mobile network, then handle SIM lock here.
380 // SIM locking only applies to cellular, so the code below won't execute
381 // if |technology| has been explicitly set to WiMAX.
382 if (technology.MatchesPattern(NetworkTypePattern::Mobile())) {
383 const DeviceState* mobile = handler->GetDeviceStateByType(technology);
384 if (!mobile) {
385 NET_LOG_ERROR("SetTechnologyEnabled with no device", log_string);
386 return;
388 // The following only applies to cellular.
389 if (mobile->type() == shill::kTypeCellular) {
390 if (mobile->IsSimAbsent()) {
391 // If this is true, then we have a cellular device with no SIM inserted.
392 // TODO(armansito): Chrome should display a notification here, prompting
393 // the user to insert a SIM card and restart the device to enable
394 // cellular. See crbug.com/125171.
395 NET_LOG_USER("Cannot enable cellular device without SIM.", log_string);
396 return;
398 if (!mobile->sim_lock_type().empty()) {
399 // A SIM has been inserted, but it is locked. Let the user unlock it
400 // via the dialog.
401 ash::Shell::GetInstance()->system_tray_delegate()->
402 ShowMobileSimDialog();
403 return;
407 handler->SetTechnologyEnabled(
408 technology, true, chromeos::network_handler::ErrorCallback());
411 void ActivateCellular(const std::string& service_path) {
412 NET_LOG_USER("ActivateCellular", service_path);
413 const NetworkState* cellular = GetNetworkState(service_path);
414 if (!cellular || cellular->type() != shill::kTypeCellular) {
415 NET_LOG_ERROR("ActivateCellular with no Service", service_path);
416 return;
418 const DeviceState* cellular_device =
419 NetworkHandler::Get()->network_state_handler()->
420 GetDeviceState(cellular->device_path());
421 if (!cellular_device) {
422 NET_LOG_ERROR("ActivateCellular with no Device", service_path);
423 return;
425 if (!IsDirectActivatedCarrier(cellular_device->carrier())) {
426 // For non direct activation, show the mobile setup dialog which can be
427 // used to activate the network.
428 ShowMobileSetup(service_path);
429 return;
431 if (cellular->activation_state() == shill::kActivationStateActivated) {
432 NET_LOG_ERROR("ActivateCellular for activated service", service_path);
433 return;
436 NetworkHandler::Get()->network_activation_handler()->Activate(
437 service_path,
438 "", // carrier
439 base::Bind(&OnActivateSucceeded, service_path),
440 base::Bind(&OnActivateFailed, service_path));
443 void ShowMobileSetup(const std::string& service_path) {
444 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
445 const NetworkState* cellular = handler->GetNetworkState(service_path);
446 if (!cellular || cellular->type() != shill::kTypeCellular) {
447 NET_LOG_ERROR("ShowMobileSetup without Cellular network", service_path);
448 return;
450 if (cellular->activation_state() != shill::kActivationStateActivated &&
451 cellular->activation_type() == shill::kActivationTypeNonCellular &&
452 !handler->DefaultNetwork()) {
453 message_center::MessageCenter::Get()->AddNotification(
454 message_center::Notification::CreateSystemNotification(
455 kNetworkActivateNotificationId,
456 l10n_util::GetStringUTF16(IDS_NETWORK_ACTIVATION_ERROR_TITLE),
457 l10n_util::GetStringFUTF16(IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION,
458 base::UTF8ToUTF16(cellular->name())),
459 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
460 IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED),
461 ash::system_notifier::kNotifierNetworkError,
462 base::Bind(&ash::network_connect::ShowNetworkSettings,
463 service_path)));
464 return;
466 ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetupDialog(
467 service_path);
470 void ConfigureNetworkAndConnect(const std::string& service_path,
471 const base::DictionaryValue& properties,
472 bool shared) {
473 NET_LOG_USER("ConfigureNetworkAndConnect", service_path);
475 scoped_ptr<base::DictionaryValue> properties_to_set(properties.DeepCopy());
477 std::string profile_path;
478 if (!GetNetworkProfilePath(shared, &profile_path)) {
479 ShowErrorNotification(
480 NetworkConnectionHandler::kErrorConfigureFailed, service_path);
481 return;
483 NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
484 service_path, profile_path,
485 base::Bind(&ConfigureSetProfileSucceeded,
486 service_path, base::Passed(&properties_to_set)),
487 base::Bind(&SetPropertiesFailed,
488 "SetProfile: " + profile_path, service_path));
491 void CreateConfigurationAndConnect(base::DictionaryValue* properties,
492 bool shared) {
493 NET_LOG_USER("CreateConfigurationAndConnect", "");
494 CallCreateConfiguration(properties, shared, true /* connect_on_configure */);
497 void CreateConfiguration(base::DictionaryValue* properties, bool shared) {
498 NET_LOG_USER("CreateConfiguration", "");
499 CallCreateConfiguration(properties, shared, false /* connect_on_configure */);
502 base::string16 ErrorString(const std::string& error,
503 const std::string& service_path) {
504 if (error.empty())
505 return base::string16();
506 if (error == shill::kErrorOutOfRange)
507 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE);
508 if (error == shill::kErrorPinMissing)
509 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING);
510 if (error == shill::kErrorDhcpFailed)
511 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED);
512 if (error == shill::kErrorConnectFailed)
513 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
514 if (error == shill::kErrorBadPassphrase)
515 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE);
516 if (error == shill::kErrorBadWEPKey)
517 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY);
518 if (error == shill::kErrorActivationFailed) {
519 return l10n_util::GetStringUTF16(
520 IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
522 if (error == shill::kErrorNeedEvdo)
523 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO);
524 if (error == shill::kErrorNeedHomeNetwork) {
525 return l10n_util::GetStringUTF16(
526 IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK);
528 if (error == shill::kErrorOtaspFailed)
529 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED);
530 if (error == shill::kErrorAaaFailed)
531 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED);
532 if (error == shill::kErrorInternal)
533 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_INTERNAL);
534 if (error == shill::kErrorDNSLookupFailed) {
535 return l10n_util::GetStringUTF16(
536 IDS_CHROMEOS_NETWORK_ERROR_DNS_LOOKUP_FAILED);
538 if (error == shill::kErrorHTTPGetFailed) {
539 return l10n_util::GetStringUTF16(
540 IDS_CHROMEOS_NETWORK_ERROR_HTTP_GET_FAILED);
542 if (error == shill::kErrorIpsecPskAuthFailed) {
543 return l10n_util::GetStringUTF16(
544 IDS_CHROMEOS_NETWORK_ERROR_IPSEC_PSK_AUTH_FAILED);
546 if (error == shill::kErrorIpsecCertAuthFailed) {
547 return l10n_util::GetStringUTF16(
548 IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
550 if (error == shill::kErrorEapAuthenticationFailed) {
551 const NetworkState* network = GetNetworkState(service_path);
552 // TLS always requires a client certificate, so show a cert auth
553 // failed message for TLS. Other EAP methods do not generally require
554 // a client certicate.
555 if (network && network->eap_method() == shill::kEapMethodTLS) {
556 return l10n_util::GetStringUTF16(
557 IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
558 } else {
559 return l10n_util::GetStringUTF16(
560 IDS_CHROMEOS_NETWORK_ERROR_EAP_AUTH_FAILED);
563 if (error == shill::kErrorEapLocalTlsFailed) {
564 return l10n_util::GetStringUTF16(
565 IDS_CHROMEOS_NETWORK_ERROR_EAP_LOCAL_TLS_FAILED);
567 if (error == shill::kErrorEapRemoteTlsFailed) {
568 return l10n_util::GetStringUTF16(
569 IDS_CHROMEOS_NETWORK_ERROR_EAP_REMOTE_TLS_FAILED);
571 if (error == shill::kErrorPppAuthFailed) {
572 return l10n_util::GetStringUTF16(
573 IDS_CHROMEOS_NETWORK_ERROR_PPP_AUTH_FAILED);
576 if (base::StringToLowerASCII(error) ==
577 base::StringToLowerASCII(std::string(shill::kUnknownString))) {
578 return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
580 return l10n_util::GetStringFUTF16(IDS_NETWORK_UNRECOGNIZED_ERROR,
581 base::UTF8ToUTF16(error));
584 void ShowNetworkSettings(const std::string& service_path) {
585 if (!ash::Shell::HasInstance())
586 return;
587 ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
588 service_path);
591 } // network_connect
592 } // ash