Home | History | Annotate | Download | only in network
      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 
     30 using chromeos::DeviceState;
     31 using chromeos::NetworkConfigurationHandler;
     32 using chromeos::NetworkConnectionHandler;
     33 using chromeos::NetworkHandler;
     34 using chromeos::NetworkProfile;
     35 using chromeos::NetworkProfileHandler;
     36 using chromeos::NetworkState;
     37 
     38 namespace ash {
     39 
     40 namespace {
     41 
     42 // TODO(stevenjb): This should be in service_constants.h
     43 const 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.
     47 bool IsDirectActivatedCarrier(const std::string& carrier) {
     48   if (carrier == shill::kCarrierSprint)
     49     return true;
     50   return false;
     51 }
     52 
     53 void 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 
     59 void 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 
    114 void 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).
    125 void 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 
    140 void 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 
    147 void OnActivateSucceeded(const std::string& service_path) {
    148   NET_LOG_USER("Activation Succeeded", service_path);
    149 }
    150 
    151 void 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 
    157 void 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 
    165 void 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 
    174 void 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 
    190 void 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.
    208 bool 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 
    231 void 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 
    247 namespace network_connect {
    248 
    249 const char kErrorActivateFailed[] = "activate-failed";
    250 
    251 void 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 
    257 void 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 
    294 void 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 
    315 void 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 
    331 string16 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