blob: 5503d7b30a0cf2966d459a98c7275d995b50cace [file] [log] [blame]
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001// 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/cellular_capability_classic.h"
6
7#include <base/bind.h>
8#include <chromeos/dbus/service_constants.h>
9
10#include "shill/cellular.h"
11#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070012#include "shill/logging.h"
Darin Petkovc37a9c42012-09-06 15:28:22 +020013#include "shill/modem_gobi_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040014#include "shill/property_accessor.h"
15#include "shill/proxy_factory.h"
16
17using base::Bind;
18using base::Callback;
19using base::Closure;
20using std::string;
21
22namespace shill {
23
24const char CellularCapabilityClassic::kConnectPropertyApn[] = "apn";
25const char CellularCapabilityClassic::kConnectPropertyApnUsername[] =
26 "username";
27const char CellularCapabilityClassic::kConnectPropertyApnPassword[] =
28 "password";
29const char CellularCapabilityClassic::kConnectPropertyHomeOnly[] = "home_only";
30const char CellularCapabilityClassic::kConnectPropertyPhoneNumber[] = "number";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040031const char CellularCapabilityClassic::kModemPropertyEnabled[] = "Enabled";
Darin Petkovc37a9c42012-09-06 15:28:22 +020032const int CellularCapabilityClassic::kTimeoutSetCarrierMilliseconds = 120000;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040033
34static Cellular::ModemState ConvertClassicToModemState(uint32 classic_state) {
35 ModemClassicState cstate =
36 static_cast<ModemClassicState>(classic_state);
37 switch (cstate) {
38 case kModemClassicStateUnknown:
39 return Cellular::kModemStateUnknown;
40 case kModemClassicStateDisabled:
41 return Cellular::kModemStateDisabled;
42 case kModemClassicStateDisabling:
43 return Cellular::kModemStateDisabling;
44 case kModemClassicStateEnabling:
45 return Cellular::kModemStateEnabling;
46 case kModemClassicStateEnabled:
47 return Cellular::kModemStateEnabled;
48 case kModemClassicStateSearching:
49 return Cellular::kModemStateSearching;
50 case kModemClassicStateRegistered:
51 return Cellular::kModemStateRegistered;
52 case kModemClassicStateDisconnecting:
53 return Cellular::kModemStateDisconnecting;
54 case kModemClassicStateConnecting:
55 return Cellular::kModemStateConnecting;
56 case kModemClassicStateConnected:
57 return Cellular::kModemStateConnected;
58 default:
59 return Cellular::kModemStateUnknown;
60 };
61}
Jason Glasgow82f9ab32012-04-04 14:27:19 -040062
63CellularCapabilityClassic::CellularCapabilityClassic(
64 Cellular *cellular,
65 ProxyFactory *proxy_factory)
66 : CellularCapability(cellular, proxy_factory),
mukesh agrawal6b34a842012-05-30 11:16:01 -070067 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -040068 weak_ptr_factory_(this) {
69 PropertyStore *store = cellular->mutable_store();
70 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
71 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
72 &scanning_supported_);
73 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
74 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
75 &firmware_revision_);
76 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
77 &hardware_revision_);
78 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
79 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
80 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
81 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
82 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
83 store->RegisterConstString(flimflam::kMinProperty, &min_);
84 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkov1abca3e2012-09-12 11:44:07 +020085
86 // This class is currently instantiated only for Gobi modems so setup the
87 // supported carriers list appropriately and expose it over RPC.
88 supported_carriers_.push_back(shill::kCarrierGenericUMTS);
89 supported_carriers_.push_back(shill::kCarrierSprint);
90 supported_carriers_.push_back(shill::kCarrierVerizon);
91 store->RegisterConstStrings(shill::kSupportedCarriersProperty,
92 &supported_carriers_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093}
94
95CellularCapabilityClassic::~CellularCapabilityClassic() {}
96
97void CellularCapabilityClassic::InitProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070098 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040099 proxy_.reset(proxy_factory()->CreateModemProxy(
100 cellular()->dbus_path(), cellular()->dbus_owner()));
101 simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
102 cellular()->dbus_path(), cellular()->dbus_owner()));
103 proxy_->set_state_changed_callback(
104 Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
105 weak_ptr_factory_.GetWeakPtr()));
106}
107
108void CellularCapabilityClassic::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700109 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400110 proxy_.reset();
111 simple_proxy_.reset();
Darin Petkovc37a9c42012-09-06 15:28:22 +0200112 gobi_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400113}
114
115void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400116 // Normally, running the callback is the last thing done in a method.
117 // In this case, we do it first, because we want to make sure that
118 // the device is marked as Enabled before the registration state is
119 // handled. See comment in Cellular::HandleNewRegistrationState.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400120 callback.Run(Error());
121 GetRegistrationState();
122 GetSignalQuality();
123}
124
125void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
126 ReleaseProxies();
127 callback.Run(Error());
128}
129
130void CellularCapabilityClassic::OnUnsupportedOperation(
131 const char *operation,
132 Error *error) {
133 string message("The ");
134 message.append(operation).append(" operation is not supported.");
135 Error::PopulateAndLog(error, Error::kNotSupported, message);
136}
137
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400138void CellularCapabilityClassic::RunNextStep(CellularTaskList *tasks) {
139 CHECK(!tasks->empty());
140 SLOG(Cellular, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
141 Closure task = (*tasks)[0];
142 tasks->erase(tasks->begin());
143 cellular()->dispatcher()->PostTask(task);
144}
145
146void CellularCapabilityClassic::StepCompletedCallback(
147 const ResultCallback &callback,
148 bool ignore_error,
149 CellularTaskList *tasks,
150 const Error &error) {
151 if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
152 RunNextStep(tasks);
153 return;
154 }
155 delete tasks;
Ben Chan3ecdf822012-08-06 12:29:23 -0700156 if (!callback.is_null())
157 callback.Run(error);
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400158}
159
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160// always called from an async context
161void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700162 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400163 CHECK(!callback.is_null());
164 Error error;
165 proxy_->Enable(true, &error, callback, kTimeoutEnable);
166 if (error.IsFailure())
167 callback.Run(error);
168}
169
170// always called from an async context
171void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700172 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400173 CHECK(!callback.is_null());
174 Error error;
Thieu Lec8d2d962012-05-15 14:31:18 -0700175 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400176 if (error.IsFailure())
177 callback.Run(error);
178}
179
180// always called from an async context
181void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700182 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400183 CHECK(!callback.is_null());
184 DBusPropertyMapCallback cb = Bind(
185 &CellularCapabilityClassic::OnGetModemStatusReply,
186 weak_ptr_factory_.GetWeakPtr(), callback);
187 Error error;
188 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
189 if (error.IsFailure())
190 callback.Run(error);
191}
192
193// always called from an async context
194void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700195 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400196 CHECK(!callback.is_null());
197 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
198 weak_ptr_factory_.GetWeakPtr(), callback);
199 Error error;
200 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
201 if (error.IsFailure())
202 callback.Run(error);
203}
204
205void CellularCapabilityClassic::StopModem(Error *error,
206 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700207 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400208
209 CellularTaskList *tasks = new CellularTaskList();
210 ResultCallback cb =
211 Bind(&CellularCapabilityClassic::StepCompletedCallback,
212 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
213 ResultCallback cb_ignore_error =
214 Bind(&CellularCapabilityClassic::StepCompletedCallback,
215 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400216 // TODO(ers): We can skip the call to Disconnect if the modem has
217 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400218 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
219 weak_ptr_factory_.GetWeakPtr(),
220 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400221 // TODO(ers): We can skip the call to Disable if the modem has
222 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400223 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
224 weak_ptr_factory_.GetWeakPtr(), cb));
225 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
226 weak_ptr_factory_.GetWeakPtr(), cb));
227
228 RunNextStep(tasks);
229}
230
231void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
232 Error *error,
233 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700234 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400235 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400236}
237
238void CellularCapabilityClassic::Disconnect(Error *error,
239 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700240 SLOG(Cellular, 2) << __func__;
Thieu Le3d275392012-07-20 15:32:58 -0700241 if (proxy_.get())
242 proxy_->Disconnect(error, callback, kTimeoutDefault);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400243}
244
245void CellularCapabilityClassic::Activate(const string &/*carrier*/,
246 Error *error,
247 const ResultCallback &/*callback*/) {
248 OnUnsupportedOperation(__func__, error);
249}
250
251void CellularCapabilityClassic::RegisterOnNetwork(
252 const string &/*network_id*/,
253 Error *error, const ResultCallback &/*callback*/) {
254 OnUnsupportedOperation(__func__, error);
255}
256
257void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
258 bool /*require*/,
259 Error *error,
260 const ResultCallback &/*callback*/) {
261 OnUnsupportedOperation(__func__, error);
262}
263
264void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
265 Error *error,
266 const ResultCallback &/*callback*/) {
267 OnUnsupportedOperation(__func__, error);
268}
269
270void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
271 const string &/*pin*/,
272 Error *error,
273 const ResultCallback &/*callback*/) {
274 OnUnsupportedOperation(__func__, error);
275}
276
277void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
278 const string &/*new_pin*/,
279 Error *error,
280 const ResultCallback &/*callback*/) {
281 OnUnsupportedOperation(__func__, error);
282}
283
Darin Petkovc37a9c42012-09-06 15:28:22 +0200284void CellularCapabilityClassic::SetCarrier(const string &carrier,
285 Error *error,
286 const ResultCallback &callback) {
287 LOG(INFO) << __func__ << "(" << carrier << ")";
288 if (!gobi_proxy_.get()) {
289 gobi_proxy_.reset(proxy_factory()->CreateModemGobiProxy(
290 cellular()->dbus_path(), cellular()->dbus_owner()));
291 }
292 CHECK(error);
293 gobi_proxy_->SetCarrier(carrier, error, callback,
294 kTimeoutSetCarrierMilliseconds);
295}
296
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400297void CellularCapabilityClassic::Scan(Error *error,
298 const ResultCallback &callback) {
299 OnUnsupportedOperation(__func__, error);
300}
301
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400302void CellularCapabilityClassic::OnDBusPropertiesChanged(
303 const std::string &interface,
304 const DBusPropertiesMap &changed_properties,
305 const std::vector<std::string> &invalidated_properties) {
306 bool enabled;
307 // This solves a bootstrapping problem: If the modem is not yet
308 // enabled, there are no proxy objects associated with the capability
309 // object, so modem signals like StateChanged aren't seen. By monitoring
310 // changes to the Enabled property via the ModemManager, we're able to
311 // get the initialization process started, which will result in the
312 // creation of the proxy objects.
313 //
314 // The first time we see the change to Enabled (when the modem state
315 // is Unknown), we simply update the state, and rely on the Manager to
316 // enable the device when it is registered with the Manager. On subsequent
317 // changes to Enabled, we need to explicitly enable the device ourselves.
318 if (DBusProperties::GetBool(changed_properties,
319 kModemPropertyEnabled, &enabled)) {
320 Cellular::ModemState prev_modem_state = cellular()->modem_state();
321 if (enabled)
322 cellular()->set_modem_state(Cellular::kModemStateEnabled);
323 else
324 cellular()->set_modem_state(Cellular::kModemStateDisabled);
325 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
326 prev_modem_state != Cellular::kModemStateUnknown &&
327 prev_modem_state != Cellular::kModemStateEnabled) {
328 cellular()->SetEnabled(true);
329 }
330 }
331}
332
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400333void CellularCapabilityClassic::OnGetModemStatusReply(
334 const ResultCallback &callback,
335 const DBusPropertiesMap &props,
336 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700337 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
338 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400339 if (error.IsSuccess()) {
340 DBusProperties::GetString(props, "carrier", &carrier_);
341 DBusProperties::GetString(props, "meid", &meid_);
342 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400343 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400344 DBusProperties::GetString(props, "esn", &esn_);
345 DBusProperties::GetString(props, "mdn", &mdn_);
346 DBusProperties::GetString(props, "min", &min_);
347 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400348 UpdateStatus(props);
349 }
350 callback.Run(error);
351}
352
353void CellularCapabilityClassic::OnGetModemInfoReply(
354 const ResultCallback &callback,
355 const ModemHardwareInfo &info,
356 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700357 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400358 if (error.IsSuccess()) {
359 manufacturer_ = info._1;
360 model_id_ = info._2;
361 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700362 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
363 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400364 }
365 callback.Run(error);
366}
367
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400368void CellularCapabilityClassic::OnModemStateChangedSignal(
369 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700370 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
371 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400372 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
373 ConvertClassicToModemState(new_state),
374 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400375}
376
377} // namespace shill