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