Home | History | Annotate | Download | only in network
      1 // Copyright 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 "chromeos/network/network_device_handler_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/message_loop/message_loop_proxy.h"
     10 #include "base/time/time.h"
     11 #include "base/values.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 #include "chromeos/dbus/shill_device_client.h"
     14 #include "chromeos/dbus/shill_ipconfig_client.h"
     15 #include "chromeos/network/device_state.h"
     16 #include "chromeos/network/network_event_log.h"
     17 #include "chromeos/network/network_handler_callbacks.h"
     18 #include "chromeos/network/network_state_handler.h"
     19 #include "dbus/object_path.h"
     20 #include "third_party/cros_system_api/dbus/service_constants.h"
     21 
     22 namespace chromeos {
     23 
     24 namespace {
     25 
     26 std::string GetErrorNameForShillError(const std::string& shill_error_name) {
     27   if (shill_error_name == shill::kErrorResultFailure)
     28     return NetworkDeviceHandler::kErrorFailure;
     29   if (shill_error_name == shill::kErrorResultNotSupported)
     30     return NetworkDeviceHandler::kErrorNotSupported;
     31   if (shill_error_name == shill::kErrorResultIncorrectPin)
     32     return NetworkDeviceHandler::kErrorIncorrectPin;
     33   if (shill_error_name == shill::kErrorResultPinBlocked)
     34     return NetworkDeviceHandler::kErrorPinBlocked;
     35   if (shill_error_name == shill::kErrorResultPinRequired)
     36     return NetworkDeviceHandler::kErrorPinRequired;
     37   if (shill_error_name == shill::kErrorResultNotFound)
     38     return NetworkDeviceHandler::kErrorDeviceMissing;
     39   return NetworkDeviceHandler::kErrorUnknown;
     40 }
     41 
     42 void InvokeErrorCallback(const std::string& service_path,
     43                          const network_handler::ErrorCallback& error_callback,
     44                          const std::string& error_name) {
     45   std::string error_msg = "Device Error: " + error_name;
     46   NET_LOG_ERROR(error_msg, service_path);
     47   network_handler::RunErrorCallback(
     48       error_callback, service_path, error_name, error_msg);
     49 }
     50 
     51 void HandleShillCallFailure(
     52     const std::string& device_path,
     53     const network_handler::ErrorCallback& error_callback,
     54     const std::string& shill_error_name,
     55     const std::string& shill_error_message) {
     56   network_handler::ShillErrorCallbackFunction(
     57       GetErrorNameForShillError(shill_error_name),
     58       device_path,
     59       error_callback,
     60       shill_error_name,
     61       shill_error_message);
     62 }
     63 
     64 void IPConfigRefreshCallback(const std::string& ipconfig_path,
     65                              DBusMethodCallStatus call_status) {
     66   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
     67     NET_LOG_ERROR(
     68         base::StringPrintf("IPConfigs.Refresh Failed: %d", call_status),
     69         ipconfig_path);
     70   } else {
     71     NET_LOG_EVENT("IPConfigs.Refresh Succeeded", ipconfig_path);
     72   }
     73 }
     74 
     75 void RefreshIPConfigsCallback(
     76     const base::Closure& callback,
     77     const network_handler::ErrorCallback& error_callback,
     78     const std::string& device_path,
     79     const base::DictionaryValue& properties) {
     80   const base::ListValue* ip_configs;
     81   if (!properties.GetListWithoutPathExpansion(
     82           shill::kIPConfigsProperty, &ip_configs)) {
     83     NET_LOG_ERROR("RequestRefreshIPConfigs Failed", device_path);
     84     network_handler::ShillErrorCallbackFunction(
     85         "RequestRefreshIPConfigs Failed",
     86         device_path,
     87         error_callback,
     88         std::string("Missing ") + shill::kIPConfigsProperty, "");
     89     return;
     90   }
     91 
     92   for (size_t i = 0; i < ip_configs->GetSize(); i++) {
     93     std::string ipconfig_path;
     94     if (!ip_configs->GetString(i, &ipconfig_path))
     95       continue;
     96     DBusThreadManager::Get()->GetShillIPConfigClient()->Refresh(
     97         dbus::ObjectPath(ipconfig_path),
     98         base::Bind(&IPConfigRefreshCallback, ipconfig_path));
     99   }
    100   // It is safe to invoke |callback| here instead of waiting for the
    101   // IPConfig.Refresh callbacks to complete because the Refresh DBus calls will
    102   // be executed in order and thus before any further DBus requests that
    103   // |callback| may issue.
    104   if (!callback.is_null())
    105     callback.Run();
    106 }
    107 
    108 void ProposeScanCallback(
    109     const std::string& device_path,
    110     const base::Closure& callback,
    111     const network_handler::ErrorCallback& error_callback,
    112     DBusMethodCallStatus call_status) {
    113   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
    114     network_handler::ShillErrorCallbackFunction(
    115         "Device.ProposeScan Failed",
    116         device_path,
    117         error_callback,
    118         base::StringPrintf("DBus call failed: %d", call_status), "");
    119     return;
    120   }
    121   NET_LOG_EVENT("Device.ProposeScan succeeded.", device_path);
    122   if (!callback.is_null())
    123     callback.Run();
    124 }
    125 
    126 void SetDevicePropertyInternal(
    127     const std::string& device_path,
    128     const std::string& property_name,
    129     const base::Value& value,
    130     const base::Closure& callback,
    131     const network_handler::ErrorCallback& error_callback) {
    132   DBusThreadManager::Get()->GetShillDeviceClient()->SetProperty(
    133       dbus::ObjectPath(device_path),
    134       property_name,
    135       value,
    136       callback,
    137       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    138 }
    139 
    140 // Struct containing TDLS Operation parameters.
    141 struct TDLSOperationParams {
    142   TDLSOperationParams() : retry_count(0) {}
    143   std::string operation;
    144   std::string ip_or_mac_address;
    145   int retry_count;
    146 };
    147 
    148 // Forward declare for PostDelayedTask.
    149 void CallPerformTDLSOperation(
    150     const std::string& device_path,
    151     const TDLSOperationParams& params,
    152     const network_handler::StringResultCallback& callback,
    153     const network_handler::ErrorCallback& error_callback);
    154 
    155 void TDLSSuccessCallback(
    156     const std::string& device_path,
    157     const TDLSOperationParams& params,
    158     const network_handler::StringResultCallback& callback,
    159     const network_handler::ErrorCallback& error_callback,
    160     const std::string& result) {
    161   std::string event_desc = "TDLSSuccessCallback: " + params.operation;
    162   if (!result.empty())
    163     event_desc += ": " + result;
    164   NET_LOG_EVENT(event_desc, device_path);
    165   if (params.operation != shill::kTDLSSetupOperation) {
    166     if (!callback.is_null())
    167       callback.Run(result);
    168     return;
    169   }
    170 
    171   if (!result.empty())
    172     NET_LOG_ERROR("Unexpected TDLS result: " + result, device_path);
    173 
    174   // Send a delayed Status request after a successful Setup call.
    175   TDLSOperationParams status_params;
    176   status_params.operation = shill::kTDLSStatusOperation;
    177   status_params.ip_or_mac_address = params.ip_or_mac_address;
    178 
    179   const int64 kRequestStatusDelayMs = 500;
    180   base::TimeDelta request_delay;
    181   if (!DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface())
    182     request_delay = base::TimeDelta::FromMilliseconds(kRequestStatusDelayMs);
    183 
    184   base::MessageLoopProxy::current()->PostDelayedTask(
    185       FROM_HERE,
    186       base::Bind(&CallPerformTDLSOperation,
    187                  device_path, status_params, callback, error_callback),
    188       request_delay);
    189 }
    190 
    191 void TDLSErrorCallback(
    192     const std::string& device_path,
    193     const TDLSOperationParams& params,
    194     const network_handler::StringResultCallback& callback,
    195     const network_handler::ErrorCallback& error_callback,
    196     const std::string& dbus_error_name,
    197     const std::string& dbus_error_message) {
    198   // If a Setup operation receives an InProgress error, retry.
    199   const int kMaxRetries = 5;
    200   if (params.operation == shill::kTDLSSetupOperation &&
    201       dbus_error_name == shill::kErrorResultInProgress &&
    202       params.retry_count < kMaxRetries) {
    203     TDLSOperationParams retry_params = params;
    204     ++retry_params.retry_count;
    205     NET_LOG_EVENT(base::StringPrintf("TDLS Retry: %d", params.retry_count),
    206                   device_path);
    207     const int64 kReRequestDelayMs = 1000;
    208     base::TimeDelta request_delay;
    209     if (!DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface())
    210       request_delay = base::TimeDelta::FromMilliseconds(kReRequestDelayMs);
    211 
    212     base::MessageLoopProxy::current()->PostDelayedTask(
    213         FROM_HERE,
    214         base::Bind(&CallPerformTDLSOperation,
    215                    device_path, retry_params, callback, error_callback),
    216         request_delay);
    217     return;
    218   }
    219 
    220   NET_LOG_ERROR("TDLS Error:" + dbus_error_name + ":" + dbus_error_message,
    221                 device_path);
    222   if (error_callback.is_null())
    223     return;
    224 
    225   const std::string error_name =
    226       dbus_error_name == shill::kErrorResultInProgress ?
    227       NetworkDeviceHandler::kErrorTimeout : NetworkDeviceHandler::kErrorUnknown;
    228   const std::string& error_detail = params.ip_or_mac_address;
    229   scoped_ptr<base::DictionaryValue> error_data(
    230       network_handler::CreateDBusErrorData(
    231           device_path, error_name, error_detail,
    232           dbus_error_name, dbus_error_message));
    233   error_callback.Run(error_name, error_data.Pass());
    234 }
    235 
    236 void CallPerformTDLSOperation(
    237     const std::string& device_path,
    238     const TDLSOperationParams& params,
    239     const network_handler::StringResultCallback& callback,
    240     const network_handler::ErrorCallback& error_callback) {
    241   NET_LOG_EVENT("CallPerformTDLSOperation: " + params.operation, device_path);
    242   DBusThreadManager::Get()->GetShillDeviceClient()->PerformTDLSOperation(
    243       dbus::ObjectPath(device_path),
    244       params.operation,
    245       params.ip_or_mac_address,
    246       base::Bind(&TDLSSuccessCallback,
    247                  device_path, params, callback, error_callback),
    248       base::Bind(&TDLSErrorCallback,
    249                  device_path, params, callback, error_callback));
    250 }
    251 
    252 }  // namespace
    253 
    254 NetworkDeviceHandlerImpl::~NetworkDeviceHandlerImpl() {
    255   network_state_handler_->RemoveObserver(this, FROM_HERE);
    256 }
    257 
    258 void NetworkDeviceHandlerImpl::GetDeviceProperties(
    259     const std::string& device_path,
    260     const network_handler::DictionaryResultCallback& callback,
    261     const network_handler::ErrorCallback& error_callback) const {
    262   DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
    263       dbus::ObjectPath(device_path),
    264       base::Bind(&network_handler::GetPropertiesCallback,
    265                  callback, error_callback, device_path));
    266 }
    267 
    268 void NetworkDeviceHandlerImpl::SetDeviceProperty(
    269     const std::string& device_path,
    270     const std::string& property_name,
    271     const base::Value& value,
    272     const base::Closure& callback,
    273     const network_handler::ErrorCallback& error_callback) {
    274   const char* const property_blacklist[] = {
    275       // Must only be changed by policy/owner through.
    276       shill::kCellularAllowRoamingProperty
    277   };
    278 
    279   for (size_t i = 0; i < arraysize(property_blacklist); ++i) {
    280     if (property_name == property_blacklist[i]) {
    281       InvokeErrorCallback(
    282           device_path,
    283           error_callback,
    284           "SetDeviceProperty called on blacklisted property " + property_name);
    285       return;
    286     }
    287   }
    288 
    289   SetDevicePropertyInternal(
    290       device_path, property_name, value, callback, error_callback);
    291 }
    292 
    293 void NetworkDeviceHandlerImpl::RequestRefreshIPConfigs(
    294     const std::string& device_path,
    295     const base::Closure& callback,
    296     const network_handler::ErrorCallback& error_callback) {
    297   GetDeviceProperties(device_path,
    298                       base::Bind(&RefreshIPConfigsCallback,
    299                                  callback, error_callback),
    300                       error_callback);
    301 }
    302 
    303 void NetworkDeviceHandlerImpl::ProposeScan(
    304     const std::string& device_path,
    305     const base::Closure& callback,
    306     const network_handler::ErrorCallback& error_callback) {
    307   DBusThreadManager::Get()->GetShillDeviceClient()->ProposeScan(
    308       dbus::ObjectPath(device_path),
    309       base::Bind(&ProposeScanCallback, device_path, callback, error_callback));
    310 }
    311 
    312 void NetworkDeviceHandlerImpl::RegisterCellularNetwork(
    313     const std::string& device_path,
    314     const std::string& network_id,
    315     const base::Closure& callback,
    316     const network_handler::ErrorCallback& error_callback) {
    317   DBusThreadManager::Get()->GetShillDeviceClient()->Register(
    318       dbus::ObjectPath(device_path),
    319       network_id,
    320       callback,
    321       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    322 }
    323 
    324 void NetworkDeviceHandlerImpl::SetCarrier(
    325     const std::string& device_path,
    326     const std::string& carrier,
    327     const base::Closure& callback,
    328     const network_handler::ErrorCallback& error_callback) {
    329   DBusThreadManager::Get()->GetShillDeviceClient()->SetCarrier(
    330       dbus::ObjectPath(device_path),
    331       carrier,
    332       callback,
    333       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    334 }
    335 
    336 void NetworkDeviceHandlerImpl::RequirePin(
    337     const std::string& device_path,
    338     bool require_pin,
    339     const std::string& pin,
    340     const base::Closure& callback,
    341     const network_handler::ErrorCallback& error_callback) {
    342   DBusThreadManager::Get()->GetShillDeviceClient()->RequirePin(
    343       dbus::ObjectPath(device_path),
    344       pin,
    345       require_pin,
    346       callback,
    347       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    348 }
    349 
    350 void NetworkDeviceHandlerImpl::EnterPin(
    351     const std::string& device_path,
    352     const std::string& pin,
    353     const base::Closure& callback,
    354     const network_handler::ErrorCallback& error_callback) {
    355   DBusThreadManager::Get()->GetShillDeviceClient()->EnterPin(
    356       dbus::ObjectPath(device_path),
    357       pin,
    358       callback,
    359       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    360 }
    361 
    362 void NetworkDeviceHandlerImpl::UnblockPin(
    363     const std::string& device_path,
    364     const std::string& puk,
    365     const std::string& new_pin,
    366     const base::Closure& callback,
    367     const network_handler::ErrorCallback& error_callback) {
    368   DBusThreadManager::Get()->GetShillDeviceClient()->UnblockPin(
    369       dbus::ObjectPath(device_path),
    370       puk,
    371       new_pin,
    372       callback,
    373       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    374 }
    375 
    376 void NetworkDeviceHandlerImpl::ChangePin(
    377     const std::string& device_path,
    378     const std::string& old_pin,
    379     const std::string& new_pin,
    380     const base::Closure& callback,
    381     const network_handler::ErrorCallback& error_callback) {
    382   DBusThreadManager::Get()->GetShillDeviceClient()->ChangePin(
    383       dbus::ObjectPath(device_path),
    384       old_pin,
    385       new_pin,
    386       callback,
    387       base::Bind(&HandleShillCallFailure, device_path, error_callback));
    388 }
    389 
    390 void NetworkDeviceHandlerImpl::SetCellularAllowRoaming(
    391     const bool allow_roaming) {
    392   cellular_allow_roaming_ = allow_roaming;
    393   ApplyCellularAllowRoamingToShill();
    394 }
    395 
    396 void NetworkDeviceHandlerImpl::SetWifiTDLSEnabled(
    397     const std::string& ip_or_mac_address,
    398     bool enabled,
    399     const network_handler::StringResultCallback& callback,
    400     const network_handler::ErrorCallback& error_callback) {
    401   const DeviceState* device_state =
    402       network_state_handler_->GetDeviceStateByType(NetworkTypePattern::WiFi());
    403   if (!device_state) {
    404     if (error_callback.is_null())
    405       return;
    406     scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue);
    407     error_data->SetString(network_handler::kErrorName, kErrorDeviceMissing);
    408     error_callback.Run(kErrorDeviceMissing, error_data.Pass());
    409     return;
    410   }
    411   TDLSOperationParams params;
    412   params.operation = enabled ? shill::kTDLSSetupOperation
    413       : shill::kTDLSTeardownOperation;
    414   params.ip_or_mac_address = ip_or_mac_address;
    415   CallPerformTDLSOperation(
    416       device_state->path(), params, callback, error_callback);
    417 }
    418 
    419 void NetworkDeviceHandlerImpl::GetWifiTDLSStatus(
    420     const std::string& ip_or_mac_address,
    421     const network_handler::StringResultCallback& callback,
    422     const network_handler::ErrorCallback& error_callback) {
    423   const DeviceState* device_state =
    424       network_state_handler_->GetDeviceStateByType(NetworkTypePattern::WiFi());
    425   if (!device_state) {
    426     if (error_callback.is_null())
    427       return;
    428     scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue);
    429     error_data->SetString(network_handler::kErrorName, kErrorDeviceMissing);
    430     error_callback.Run(kErrorDeviceMissing, error_data.Pass());
    431     return;
    432   }
    433   TDLSOperationParams params;
    434   params.operation = shill::kTDLSStatusOperation;
    435   params.ip_or_mac_address = ip_or_mac_address;
    436   CallPerformTDLSOperation(
    437       device_state->path(), params, callback, error_callback);
    438 }
    439 
    440 void NetworkDeviceHandlerImpl::DeviceListChanged() {
    441   ApplyCellularAllowRoamingToShill();
    442 }
    443 
    444 NetworkDeviceHandlerImpl::NetworkDeviceHandlerImpl()
    445     : network_state_handler_(NULL),
    446       cellular_allow_roaming_(false) {}
    447 
    448 void NetworkDeviceHandlerImpl::Init(
    449     NetworkStateHandler* network_state_handler) {
    450   DCHECK(network_state_handler);
    451   network_state_handler_ = network_state_handler;
    452   network_state_handler_->AddObserver(this, FROM_HERE);
    453 }
    454 
    455 void NetworkDeviceHandlerImpl::ApplyCellularAllowRoamingToShill() {
    456   NetworkStateHandler::DeviceStateList list;
    457   network_state_handler_->GetDeviceListByType(NetworkTypePattern::Cellular(),
    458                                               &list);
    459   if (list.empty()) {
    460     NET_LOG_DEBUG("No cellular device is available",
    461                   "Roaming is only supported by cellular devices.");
    462     return;
    463   }
    464   for (NetworkStateHandler::DeviceStateList::const_iterator it = list.begin();
    465       it != list.end(); ++it) {
    466     const DeviceState* device_state = *it;
    467     bool current_allow_roaming = device_state->allow_roaming();
    468 
    469     // If roaming is required by the provider, always try to set to true.
    470     bool new_device_value =
    471         device_state->provider_requires_roaming() || cellular_allow_roaming_;
    472 
    473     // Only set the value if the current value is different from
    474     // |new_device_value|.
    475     if (new_device_value == current_allow_roaming)
    476       continue;
    477 
    478     SetDevicePropertyInternal(device_state->path(),
    479                               shill::kCellularAllowRoamingProperty,
    480                               base::FundamentalValue(new_device_value),
    481                               base::Bind(&base::DoNothing),
    482                               network_handler::ErrorCallback());
    483   }
    484 }
    485 
    486 }  // namespace chromeos
    487