1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
1699c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
17c3d707d1ae4198d5538ff4deccd729a83f1bc805Ben Chan#include "shill/wimax/wimax.h"
1899c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
198a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko#include <string>
208a5322984f2d81bcbfd8d44c59747a11bd9b904bAlex Vakulenko
21912f0de92ca103568821e20412b7dc2529494f98Darin Petkov#include <base/bind.h>
22a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_util.h>
23a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/stringprintf.h>
24912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
25608ec29525f553d51f0a92e84176e3d4b45930a9Peter Qiu#include "shill/control_interface.h"
2625665aa52da9f6e08a23fc462b09c2ae63a8a5f2Darin Petkov#include "shill/key_value_store.h"
27b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
28912f0de92ca103568821e20412b7dc2529494f98Darin Petkov#include "shill/manager.h"
29c3d707d1ae4198d5538ff4deccd729a83f1bc805Ben Chan#include "shill/wimax/wimax_device_proxy_interface.h"
30c3d707d1ae4198d5538ff4deccd729a83f1bc805Ben Chan#include "shill/wimax/wimax_service.h"
31b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov
32912f0de92ca103568821e20412b7dc2529494f98Darin Petkovusing base::Bind;
33d1cd79736d7a9969c966a76a5906ea408bad3731Darin Petkovusing std::set;
3499c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chanusing std::string;
3599c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
3699c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Channamespace shill {
3799c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
38c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
39c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kWiMax;
4093d817916f4cac344b6985c867a85f65711a1486Paul Stewartstatic string ObjectID(WiMax* w) { return w->GetRpcIdentifier(); }
41c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
42c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
4392ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Channamespace {
4492ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan
4593d817916f4cac344b6985c867a85f65711a1486Paul Stewartconst char* DeviceStatusToString(wimax_manager::DeviceStatus status) {
4692ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan  switch (status) {
4792ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusUninitialized:
4892ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Uninitialized";
4992ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusDisabled:
5092ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Disabled";
5192ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusReady:
5292ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Ready";
5392ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusScanning:
5492ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Scanning";
5592ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusConnecting:
5692ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Connecting";
5792ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    case wimax_manager::kDeviceStatusConnected:
5892ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Connected";
5992ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan    default:
6092ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan      return "Unknown";
6192ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan  }
6292ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan}
6392ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan
6492ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan}  // namespace
6592ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan
663a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovconst int WiMax::kDefaultConnectTimeoutSeconds = 60;
673a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovconst int WiMax::kDefaultRPCTimeoutSeconds = 30;
68912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
6993d817916f4cac344b6985c867a85f65711a1486Paul StewartWiMax::WiMax(ControlInterface* control,
7093d817916f4cac344b6985c867a85f65711a1486Paul Stewart             EventDispatcher* dispatcher,
7193d817916f4cac344b6985c867a85f65711a1486Paul Stewart             Metrics* metrics,
7293d817916f4cac344b6985c867a85f65711a1486Paul Stewart             Manager* manager,
7393d817916f4cac344b6985c867a85f65711a1486Paul Stewart             const string& link_name,
7493d817916f4cac344b6985c867a85f65711a1486Paul Stewart             const string& address,
75b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov             int interface_index,
7693d817916f4cac344b6985c867a85f65711a1486Paul Stewart             const RpcIdentifier& path)
774e64d2d72eed1947ab1d15e6ce25a47c37a9e10cBen Chan    : Device(control, dispatcher, metrics, manager, link_name, address,
78b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov             interface_index, Technology::kWiMax),
79b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov      path_(path),
803a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      weak_ptr_factory_(this),
819893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov      scanning_(false),
823a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      status_(wimax_manager::kDeviceStatusUninitialized),
833a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      connect_timeout_seconds_(kDefaultConnectTimeoutSeconds) {
84b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  LOG(INFO) << "WiMAX device created: " << link_name << " @ " << path;
8593d817916f4cac344b6985c867a85f65711a1486Paul Stewart  PropertyStore* store = mutable_store();
864276ccab7a3bdf1c2e2e69cf79b859733d7404a0Ben Chan  store->RegisterConstBool(kScanningProperty, &scanning_);
87b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov}
8899c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
89b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin PetkovWiMax::~WiMax() {
90b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  LOG(INFO) << "WiMAX device destroyed: " << link_name();
91b72b62ec23d13c8e84a1499a04231b79d4bd74bbDarin Petkov}
9299c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
9393d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::Start(Error* error, const EnabledStateChangedCallback& callback) {
94c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
959893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  scanning_ = false;
96608ec29525f553d51f0a92e84176e3d4b45930a9Peter Qiu  proxy_.reset(control_interface()->CreateWiMaxDeviceProxy(path_));
979893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  proxy_->set_networks_changed_callback(
989893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov      Bind(&WiMax::OnNetworksChanged, Unretained(this)));
998ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov  proxy_->set_status_changed_callback(
1008ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      Bind(&WiMax::OnStatusChanged, Unretained(this)));
101912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  proxy_->Enable(
1023a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      error, Bind(&WiMax::OnEnableComplete, this, callback),
1033a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      kDefaultRPCTimeoutSeconds * 1000);
10499c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan}
10599c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
10693d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::Stop(Error* error, const EnabledStateChangedCallback& callback) {
107c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
1083a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  StopConnectTimeout();
1093a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  if (pending_service_) {
1103a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov    pending_service_->SetState(Service::kStateIdle);
11153cc894f1ca677f930da7fce1564db44a7b02791Ben Chan    pending_service_ = nullptr;
1123a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  }
113c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  if (selected_service()) {
114c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov    Error error;
115c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov    DisconnectFrom(selected_service(), &error);
116c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  }
117b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  scanning_ = false;
118d1cd79736d7a9969c966a76a5906ea408bad3731Darin Petkov  networks_.clear();
119c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  manager()->wimax_provider()->OnNetworksChanged();
120b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  if (proxy_.get()) {
121b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    proxy_->Disable(
122b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov        error, Bind(&WiMax::OnDisableComplete, this, callback),
1233a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov        kDefaultRPCTimeoutSeconds * 1000);
124b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  } else {
125b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    OnDisableComplete(callback, Error());
126b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  }
12799c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan}
12899c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
12993d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::Scan(ScanType /*scan_type*/, Error* error,
13093d817916f4cac344b6985c867a85f65711a1486Paul Stewart                 const string& /*reason*/) {
131c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
1329893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (scanning_) {
1339893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    Error::PopulateAndLog(
13434f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kInProgress, "Scan already in progress.");
1359893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    return;
1369893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
1379893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  scanning_ = true;
1389893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  proxy_->ScanNetworks(
1393a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      error, Bind(&WiMax::OnScanNetworksComplete, this),
1403a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      kDefaultRPCTimeoutSeconds * 1000);
1419893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (error->IsFailure()) {
1429893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    OnScanNetworksComplete(*error);
1439893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
1449893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov}
1459893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov
14693d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::ConnectTo(const WiMaxServiceRefPtr& service, Error* error) {
147c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
1489893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (pending_service_) {
1499893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    Error::PopulateAndLog(
15034f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kInProgress,
1519893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov        base::StringPrintf(
152457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            "Pending connect to service %s, ignoring connect request to %s.",
153457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            pending_service_->unique_name().c_str(),
154c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov            service->GetStorageIdentifier().c_str()));
1559893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    return;
1569893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
1579893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  service->SetState(Service::kStateAssociating);
1589893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  pending_service_ = service;
1594e5c1310a1c70445a473653bd37d06604c5d5f47Ben Chan
1603a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // We use the RPC device status to determine the outcome of the connect
1613a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // operation by listening for status updates in OnStatusChanged. A transition
1623a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // to Connected means success. A transition to Connecting and then to a status
1633a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // different than Connected means failure. Also, schedule a connect timeout to
1643a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // guard against the RPC device never transitioning to a Connecting or a
1653a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  // Connected state.
1663a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  status_ = wimax_manager::kDeviceStatusUninitialized;
1673a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  StartConnectTimeout();
1683a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov
16925665aa52da9f6e08a23fc462b09c2ae63a8a5f2Darin Petkov  KeyValueStore parameters;
1704e5c1310a1c70445a473653bd37d06604c5d5f47Ben Chan  service->GetConnectParameters(&parameters);
171912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  proxy_->Connect(
1724e5c1310a1c70445a473653bd37d06604c5d5f47Ben Chan      service->GetNetworkObjectPath(), parameters,
1733a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      error, Bind(&WiMax::OnConnectComplete, this),
1743a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      kDefaultRPCTimeoutSeconds * 1000);
1759893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (error->IsFailure()) {
1769893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    OnConnectComplete(*error);
1779893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
17899c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan}
17999c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
18093d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::DisconnectFrom(const ServiceRefPtr& service, Error* error) {
181c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
1829893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (pending_service_) {
1839893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    Error::PopulateAndLog(
18434f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kInProgress,
1859893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov        base::StringPrintf(
186457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            "Pending connect to service %s, "
187457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            "ignoring disconnect request from %s.",
188457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            pending_service_->unique_name().c_str(),
189c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov            service->GetStorageIdentifier().c_str()));
1909893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    return;
1919893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
1929893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (selected_service() && service != selected_service()) {
1939893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    Error::PopulateAndLog(
19434f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kNotConnected,
1959893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov        base::StringPrintf(
196457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            "Current service is %s, ignoring disconnect request from %s.",
197457728b3eeb2d67c980e0d20675f0a0f750903e1Darin Petkov            selected_service()->unique_name().c_str(),
198c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov            service->GetStorageIdentifier().c_str()));
1999893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    return;
2009893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
201c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  DropConnection();
202912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  proxy_->Disconnect(
2033a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      error, Bind(&WiMax::OnDisconnectComplete, this),
2043a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      kDefaultRPCTimeoutSeconds * 1000);
2059893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  if (error->IsFailure()) {
206c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov    OnDisconnectComplete(*error);
207c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  }
208c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov}
209c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov
2106b9b2e18088f22b79ea5d87f575b67632fb5770aDarin Petkovbool WiMax::IsIdle() const {
2116b9b2e18088f22b79ea5d87f575b67632fb5770aDarin Petkov  return !pending_service_ && !selected_service();
2126b9b2e18088f22b79ea5d87f575b67632fb5770aDarin Petkov}
2136b9b2e18088f22b79ea5d87f575b67632fb5770aDarin Petkov
21493d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnServiceStopped(const WiMaxServiceRefPtr& service) {
215c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
216c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  if (service == selected_service()) {
217c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov    DropConnection();
218c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  }
219c1e5273c8c52bb3e5c20364d5c172d57417d3c4cDarin Petkov  if (service == pending_service_) {
22053cc894f1ca677f930da7fce1564db44a7b02791Ben Chan    pending_service_ = nullptr;
2219893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
2229893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov}
2239893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov
224b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkovvoid WiMax::OnDeviceVanished() {
225b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  LOG(INFO) << "WiMAX device vanished: " << link_name();
226b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  proxy_.reset();
227b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  DropService(Service::kStateIdle);
228b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  // Disable the device. This will also clear any relevant properties such as
229b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  // the live network set.
230b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  SetEnabled(false);
231b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov}
232b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov
23393d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnScanNetworksComplete(const Error& /*error*/) {
234c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
2359893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  scanning_ = false;
2369893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  // The networks are updated when the NetworksChanged signal is received.
237912f0de92ca103568821e20412b7dc2529494f98Darin Petkov}
238912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
23993d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnConnectComplete(const Error& error) {
240c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
2418ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov  if (error.IsSuccess()) {
2428ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov    // Nothing to do -- the connection process is resumed on the StatusChanged
2438ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov    // signal.
2449893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    return;
2459893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  }
246b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  DropService(Service::kStateFailure);
247912f0de92ca103568821e20412b7dc2529494f98Darin Petkov}
248912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
24993d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnDisconnectComplete(const Error& /*error*/) {
250c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
251912f0de92ca103568821e20412b7dc2529494f98Darin Petkov}
252912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
25393d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnEnableComplete(const EnabledStateChangedCallback& callback,
25493d817916f4cac344b6985c867a85f65711a1486Paul Stewart                             const Error& error) {
255c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
256912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  if (error.IsFailure()) {
257912f0de92ca103568821e20412b7dc2529494f98Darin Petkov    proxy_.reset();
258912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  } else {
25959f2d69a15abf0a1ceb4eff58adcf815f2a0ff92Darin Petkov    LOG(INFO) << "WiMAX device " << link_name() << " enabled.";
26059f2d69a15abf0a1ceb4eff58adcf815f2a0ff92Darin Petkov    // Updates the live networks based on the current WiMaxManager.Device
26159f2d69a15abf0a1ceb4eff58adcf815f2a0ff92Darin Petkov    // networks. The RPC device will signal when the network set changes.
2629893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov    Error e;
26359f2d69a15abf0a1ceb4eff58adcf815f2a0ff92Darin Petkov    OnNetworksChanged(proxy_->Networks(&e));
264912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  }
265912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  callback.Run(error);
266912f0de92ca103568821e20412b7dc2529494f98Darin Petkov}
267912f0de92ca103568821e20412b7dc2529494f98Darin Petkov
26893d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnDisableComplete(const EnabledStateChangedCallback& callback,
26993d817916f4cac344b6985c867a85f65711a1486Paul Stewart                              const Error& error) {
270b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  LOG(INFO) << "WiMAX device " << link_name() << " disabled.";
2719893d9c59f596e621463c8e97bb3933f8fa7edf6Darin Petkov  proxy_.reset();
272912f0de92ca103568821e20412b7dc2529494f98Darin Petkov  callback.Run(error);
27399c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan}
27499c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan
27593d817916f4cac344b6985c867a85f65711a1486Paul Stewartvoid WiMax::OnNetworksChanged(const RpcIdentifiers& networks) {
276c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
277c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  networks_.clear();
278c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  networks_.insert(networks.begin(), networks.end());
279c63dcf0b428ea99e8a9a88bc964a51e65b6dddf0Darin Petkov  manager()->wimax_provider()->OnNetworksChanged();
280d1cd79736d7a9969c966a76a5906ea408bad3731Darin Petkov}
281d1cd79736d7a9969c966a76a5906ea408bad3731Darin Petkov
2828ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkovvoid WiMax::OnStatusChanged(wimax_manager::DeviceStatus status) {
283c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << "WiMAX device " << link_name()
284c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << " status: " << DeviceStatusToString(status);
2853a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  wimax_manager::DeviceStatus old_status = status_;
2863a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  status_ = status;
2878ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov  switch (status) {
2888ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov    case wimax_manager::kDeviceStatusConnected:
2898ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      if (!pending_service_) {
2908ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov        LOG(WARNING) << "Unexpected status change; ignored.";
2918ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov        return;
2928ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      }
2933a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      // Stops the connect timeout -- the DHCP provider has a separate timeout.
2943a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      StopConnectTimeout();
2958ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      if (AcquireIPConfig()) {
296b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov        LOG(INFO) << "WiMAX device " << link_name() << " connected to "
2978ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov                  << pending_service_->GetStorageIdentifier();
2988ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov        SelectService(pending_service_);
29953cc894f1ca677f930da7fce1564db44a7b02791Ben Chan        pending_service_ = nullptr;
3008ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov        SetServiceState(Service::kStateConfiguring);
3018ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      } else {
302b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov        DropService(Service::kStateFailure);
3038ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      }
3048ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      break;
3058ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov    case wimax_manager::kDeviceStatusConnecting:
3063a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      LOG(INFO) << "WiMAX device " << link_name() << " connecting...";
3078ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      // Nothing to do.
3088ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      break;
3098ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov    default:
3103a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      // We may receive a queued up status update (e.g., to Scanning) before
3113a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      // receiving the status update to Connecting, so be careful to fail the
3123a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      // service only on the right status transition.
3133a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      if (old_status == wimax_manager::kDeviceStatusConnecting ||
3143a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov          old_status == wimax_manager::kDeviceStatusConnected) {
3153a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov        LOG(INFO) << "WiMAX device " << link_name()
31692ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan                  << " status: " << DeviceStatusToString(old_status)
31792ca56c5f434beaf2ba4270e5beb8c1c551e401dBen Chan                  << " -> " << DeviceStatusToString(status);
318e494e313d474b91b4b5a5f6ad783e7d0bc343dc8Ben Chan        // TODO(benchan): Investigate a method to determine if the connection
319e494e313d474b91b4b5a5f6ad783e7d0bc343dc8Ben Chan        // failure is due to incorrect EAP credentials and indicate that via
320e494e313d474b91b4b5a5f6ad783e7d0bc343dc8Ben Chan        // Service::kFailureBadPassphrase (crosbug.com/p/16324).
3213a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov        DropService(Service::kStateFailure);
3228ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      }
3238ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov      break;
3248ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov  }
3258ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov}
3268ea0eaf6fb42aa7d959a131e43ea1d06635d6da2Darin Petkov
327b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkovvoid WiMax::DropService(Service::ConnectState state) {
328c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__
329c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << "(" << Service::ConnectStateToString(state) << ")";
3303a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  StopConnectTimeout();
331b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  if (pending_service_) {
332b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    LOG(WARNING) << "Unable to initiate connection to: "
333b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov                 << pending_service_->GetStorageIdentifier();
334b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    pending_service_->SetState(state);
33553cc894f1ca677f930da7fce1564db44a7b02791Ben Chan    pending_service_ = nullptr;
336b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  }
337b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  if (selected_service()) {
338b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    LOG(WARNING) << "Service disconnected: "
339b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov                 << selected_service()->GetStorageIdentifier();
340b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    selected_service()->SetState(state);
341b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov    DropConnection();
342b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov  }
343b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov}
344b96a4515c8cc4432a87c70cbae2865e1445eb86eDarin Petkov
3453a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovvoid WiMax::StartConnectTimeout() {
346c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
3473a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  if (IsConnectTimeoutStarted()) {
3483a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov    return;
3493a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  }
3503a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  connect_timeout_callback_.Reset(
3513a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      Bind(&WiMax::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
3523a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  dispatcher()->PostDelayedTask(
3533a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov      connect_timeout_callback_.callback(), connect_timeout_seconds_ * 1000);
3543a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov}
3553a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov
3563a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovvoid WiMax::StopConnectTimeout() {
357c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
3583a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  connect_timeout_callback_.Cancel();
3593a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov}
3603a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov
3613a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovbool WiMax::IsConnectTimeoutStarted() const {
3623a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  return !connect_timeout_callback_.IsCancelled();
3633a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov}
3643a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov
3653a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkovvoid WiMax::OnConnectTimeout() {
3663a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  LOG(ERROR) << "WiMAX device " << link_name() << ": connect timeout.";
3673a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  StopConnectTimeout();
3683a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov  DropService(Service::kStateFailure);
3693a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov}
3703a4100c44c9676f17829de5bcb23e883bd970ef7Darin Petkov
37199c8a4d2e6b81b1c395b2e1054111b29c20a5189Ben Chan}  // namespace shill
372