blob: ccec05baabd8267ab1f5e62816e068125f5f9d82 [file] [log] [blame]
Ben Chan99c8a4d2012-05-01 08:11:53 -07001// Copyright (c) 2012 The Chromium OS 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 "shill/wimax.h"
6
Darin Petkov912f0de2012-05-16 14:12:14 +02007#include <base/bind.h>
Darin Petkov9893d9c2012-05-17 15:27:31 -07008#include <base/stringprintf.h>
Darin Petkov912f0de2012-05-16 14:12:14 +02009
Darin Petkov25665aa2012-05-21 14:08:12 +020010#include "shill/key_value_store.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020011#include "shill/manager.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020012#include "shill/proxy_factory.h"
13#include "shill/scope_logger.h"
14#include "shill/wimax_device_proxy_interface.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020015#include "shill/wimax_service.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020016
Darin Petkov912f0de2012-05-16 14:12:14 +020017using base::Bind;
Darin Petkov9893d9c2012-05-17 15:27:31 -070018using std::map;
Ben Chan99c8a4d2012-05-01 08:11:53 -070019using std::string;
20
21namespace shill {
22
Darin Petkov912f0de2012-05-16 14:12:14 +020023const int WiMax::kTimeoutDefault = 30000;
24
Ben Chan99c8a4d2012-05-01 08:11:53 -070025WiMax::WiMax(ControlInterface *control,
26 EventDispatcher *dispatcher,
27 Metrics *metrics,
28 Manager *manager,
29 const string &link_name,
Ben Chan4e64d2d2012-05-16 00:02:25 -070030 const string &address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020031 int interface_index,
32 const RpcIdentifier &path)
Ben Chan4e64d2d2012-05-16 00:02:25 -070033 : Device(control, dispatcher, metrics, manager, link_name, address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020034 interface_index, Technology::kWiMax),
35 path_(path),
Darin Petkov9893d9c2012-05-17 15:27:31 -070036 scanning_(false),
Darin Petkovb72b62e2012-05-15 16:55:36 +020037 proxy_factory_(ProxyFactory::GetInstance()) {
38 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov9893d9c2012-05-17 15:27:31 -070039 PropertyStore *store = mutable_store();
40 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
Darin Petkovb72b62e2012-05-15 16:55:36 +020041}
Ben Chan99c8a4d2012-05-01 08:11:53 -070042
Darin Petkovb72b62e2012-05-15 16:55:36 +020043WiMax::~WiMax() {
44 SLOG(WiMax, 2) << __func__ << "(" << link_name() << ", " << path_ << ")";
45}
Ben Chan99c8a4d2012-05-01 08:11:53 -070046
47void WiMax::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020048 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070049 scanning_ = false;
Darin Petkovb72b62e2012-05-15 16:55:36 +020050 proxy_.reset(proxy_factory_->CreateWiMaxDeviceProxy(path_));
Darin Petkov9893d9c2012-05-17 15:27:31 -070051 proxy_->set_networks_changed_callback(
52 Bind(&WiMax::OnNetworksChanged, Unretained(this)));
Darin Petkov912f0de2012-05-16 14:12:14 +020053 proxy_->Enable(
54 error, Bind(&WiMax::OnEnableComplete, this, callback), kTimeoutDefault);
Ben Chan99c8a4d2012-05-01 08:11:53 -070055}
56
57void WiMax::Stop(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020058 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070059 DestroyDeadServices(RpcIdentifiers());
Darin Petkov912f0de2012-05-16 14:12:14 +020060 proxy_->Disable(
61 error, Bind(&WiMax::OnDisableComplete, this, callback), kTimeoutDefault);
Ben Chan99c8a4d2012-05-01 08:11:53 -070062}
63
64bool WiMax::TechnologyIs(const Technology::Identifier type) const {
65 return type == Technology::kWiMax;
66}
67
Darin Petkov9893d9c2012-05-17 15:27:31 -070068void WiMax::Scan(Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +020069 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070070 if (scanning_) {
71 Error::PopulateAndLog(
72 error, Error::kInProgress, "Scan already in progress.");
73 return;
74 }
75 scanning_ = true;
76 proxy_->ScanNetworks(
77 error, Bind(&WiMax::OnScanNetworksComplete, this), kTimeoutDefault);
78 if (error->IsFailure()) {
79 OnScanNetworksComplete(*error);
80 }
Ben Chan99c8a4d2012-05-01 08:11:53 -070081}
82
Darin Petkov9893d9c2012-05-17 15:27:31 -070083void WiMax::ConnectTo(const WiMaxServiceRefPtr &service, Error *error) {
84 SLOG(WiMax, 2) << __func__ << "(" << service->friendly_name() << ")";
85 if (pending_service_) {
86 Error::PopulateAndLog(
87 error, Error::kInProgress,
88 base::StringPrintf(
89 "Pending connect to %s, ignoring connect request to %s.",
90 pending_service_->friendly_name().c_str(),
91 service->friendly_name().c_str()));
92 return;
93 }
94 service->SetState(Service::kStateAssociating);
95 pending_service_ = service;
Ben Chan4e5c1312012-05-18 18:45:38 -070096
Darin Petkov25665aa2012-05-21 14:08:12 +020097 KeyValueStore parameters;
Ben Chan4e5c1312012-05-18 18:45:38 -070098 service->GetConnectParameters(&parameters);
Darin Petkov9893d9c2012-05-17 15:27:31 -070099 proxy_->Connect(
Ben Chan4e5c1312012-05-18 18:45:38 -0700100 service->GetNetworkObjectPath(), parameters,
Darin Petkov9893d9c2012-05-17 15:27:31 -0700101 error, Bind(&WiMax::OnConnectComplete, this), kTimeoutDefault);
102 if (error->IsFailure()) {
103 OnConnectComplete(*error);
104 }
105}
106
107void WiMax::DisconnectFrom(const WiMaxServiceRefPtr &service, Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200108 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700109 if (pending_service_) {
110 Error::PopulateAndLog(
111 error, Error::kInProgress,
112 base::StringPrintf(
113 "Pending connect to %s, ignoring disconnect request from %s.",
114 pending_service_->friendly_name().c_str(),
115 service->friendly_name().c_str()));
116 return;
117 }
118 if (selected_service() && service != selected_service()) {
119 Error::PopulateAndLog(
120 error, Error::kNotConnected,
121 base::StringPrintf(
122 "Curent service is %s, ignoring disconnect request from %s.",
123 selected_service()->friendly_name().c_str(),
124 service->friendly_name().c_str()));
125 return;
126 }
Darin Petkov912f0de2012-05-16 14:12:14 +0200127 proxy_->Disconnect(
128 error, Bind(&WiMax::OnDisconnectComplete, this), kTimeoutDefault);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700129 if (error->IsFailure()) {
130 OnDisconnectComplete(Error());
131 }
132}
133
134void WiMax::OnScanNetworksComplete(const Error &/*error*/) {
135 SLOG(WiMax, 2) << __func__;
136 scanning_ = false;
137 // The networks are updated when the NetworksChanged signal is received.
Darin Petkov912f0de2012-05-16 14:12:14 +0200138}
139
140void WiMax::OnConnectComplete(const Error &error) {
141 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700142 if (!pending_service_) {
143 LOG(ERROR) << "Unexpected OnConnectComplete callback.";
144 return;
145 }
Darin Petkov126d5862012-05-17 14:39:11 +0200146 if (error.IsSuccess() && AcquireIPConfig()) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700147 LOG(INFO) << "Connected to " << pending_service_->friendly_name();
148 SelectService(pending_service_);
Darin Petkov126d5862012-05-17 14:39:11 +0200149 SetServiceState(Service::kStateConfiguring);
150 } else {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700151 LOG(ERROR) << "Unable to connect to " << pending_service_->friendly_name();
152 pending_service_->SetState(Service::kStateFailure);
Darin Petkov912f0de2012-05-16 14:12:14 +0200153 }
Darin Petkov9893d9c2012-05-17 15:27:31 -0700154 pending_service_ = NULL;
Darin Petkov912f0de2012-05-16 14:12:14 +0200155}
156
Darin Petkov9893d9c2012-05-17 15:27:31 -0700157void WiMax::OnDisconnectComplete(const Error &/*error*/) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200158 SLOG(WiMax, 2) << __func__;
Darin Petkov126d5862012-05-17 14:39:11 +0200159 DestroyIPConfig();
Darin Petkov912f0de2012-05-16 14:12:14 +0200160 SelectService(NULL);
161}
162
163void WiMax::OnEnableComplete(const EnabledStateChangedCallback &callback,
164 const Error &error) {
165 SLOG(WiMax, 2) << __func__;
166 if (error.IsFailure()) {
167 proxy_.reset();
168 } else {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700169 // Scan for networks to allow service creation when the network list becomes
170 // available.
171 Error e;
172 Scan(&e);
Darin Petkov912f0de2012-05-16 14:12:14 +0200173 }
174 callback.Run(error);
Darin Petkov912f0de2012-05-16 14:12:14 +0200175}
176
177void WiMax::OnDisableComplete(const EnabledStateChangedCallback &callback,
178 const Error &error) {
179 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700180 proxy_.reset();
Darin Petkov912f0de2012-05-16 14:12:14 +0200181 callback.Run(error);
Ben Chan99c8a4d2012-05-01 08:11:53 -0700182}
183
Darin Petkov9893d9c2012-05-17 15:27:31 -0700184void WiMax::OnNetworksChanged(const RpcIdentifiers &networks) {
185 SLOG(WiMax, 2) << __func__;
186 DestroyDeadServices(networks);
187 for (RpcIdentifiers::const_iterator it = networks.begin();
188 it != networks.end(); ++it) {
189 CreateService(*it);
190 }
191}
192
193void WiMax::CreateService(const RpcIdentifier &network) {
194 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
195 if (ContainsKey(services_, network)) {
196 SLOG(WiMax, 2) << "Service already exists.";
197 return;
198 }
199 WiMaxServiceRefPtr service = new WiMaxService(control_interface(),
200 dispatcher(),
201 metrics(),
202 manager(),
203 this);
204 // Creates and passes ownership of the network proxy.
205 if (service->Start(proxy_factory_->CreateWiMaxNetworkProxy(network))) {
206 manager()->RegisterService(service);
207 services_[network] = service;
208 } else {
209 LOG(ERROR) << "Unable to start service: " << network;
210 }
211}
212
213void WiMax::DestroyDeadServices(const RpcIdentifiers &live_networks) {
214 SLOG(WiMax, 2) << __func__ << "(" << live_networks.size() << ")";
215 for (map<string, WiMaxServiceRefPtr>::iterator it = services_.begin();
216 it != services_.end(); ) {
217 if (find(live_networks.begin(), live_networks.end(), it->first) ==
218 live_networks.end()) {
219 WiMaxServiceRefPtr service = it->second;
220 LOG(INFO) << "Destroying service: " << service->friendly_name();
221 if (service == selected_service()) {
222 DestroyIPConfig();
223 SelectService(NULL);
224 }
225 if (pending_service_ == service) {
226 pending_service_ = NULL;
227 }
228 manager()->DeregisterService(service);
229 services_.erase(it++);
230 } else {
231 ++it;
232 }
233 }
234}
235
Ben Chan99c8a4d2012-05-01 08:11:53 -0700236} // namespace shill