blob: 16b0f1f881be804931705bef9feff55378b04393 [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())
Thieu Le049adb52012-11-12 17:14:51 -0800242 proxy_->Disconnect(error, callback, kTimeoutDisconnect);
Christopher Wiley7d0953e2012-11-16 00:37:10 -0800243 else
244 LOG(ERROR) << "No proxy found in disconnect.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400245}
246
Christopher Wiley8a468902012-11-30 11:52:38 -0800247void CellularCapabilityClassic::DisconnectCleanup() {
248 SLOG(Cellular, 2) << __func__;
249}
250
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400251void CellularCapabilityClassic::Activate(const string &/*carrier*/,
252 Error *error,
253 const ResultCallback &/*callback*/) {
254 OnUnsupportedOperation(__func__, error);
255}
256
257void CellularCapabilityClassic::RegisterOnNetwork(
258 const string &/*network_id*/,
259 Error *error, const ResultCallback &/*callback*/) {
260 OnUnsupportedOperation(__func__, error);
261}
262
263void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
264 bool /*require*/,
265 Error *error,
266 const ResultCallback &/*callback*/) {
267 OnUnsupportedOperation(__func__, error);
268}
269
270void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
271 Error *error,
272 const ResultCallback &/*callback*/) {
273 OnUnsupportedOperation(__func__, error);
274}
275
276void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
277 const string &/*pin*/,
278 Error *error,
279 const ResultCallback &/*callback*/) {
280 OnUnsupportedOperation(__func__, error);
281}
282
283void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
284 const string &/*new_pin*/,
285 Error *error,
286 const ResultCallback &/*callback*/) {
287 OnUnsupportedOperation(__func__, error);
288}
289
Darin Petkovc37a9c42012-09-06 15:28:22 +0200290void CellularCapabilityClassic::SetCarrier(const string &carrier,
291 Error *error,
292 const ResultCallback &callback) {
293 LOG(INFO) << __func__ << "(" << carrier << ")";
294 if (!gobi_proxy_.get()) {
295 gobi_proxy_.reset(proxy_factory()->CreateModemGobiProxy(
296 cellular()->dbus_path(), cellular()->dbus_owner()));
297 }
298 CHECK(error);
299 gobi_proxy_->SetCarrier(carrier, error, callback,
300 kTimeoutSetCarrierMilliseconds);
301}
302
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400303void CellularCapabilityClassic::Scan(Error *error,
304 const ResultCallback &callback) {
305 OnUnsupportedOperation(__func__, error);
306}
307
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400308void CellularCapabilityClassic::OnDBusPropertiesChanged(
309 const std::string &interface,
310 const DBusPropertiesMap &changed_properties,
311 const std::vector<std::string> &invalidated_properties) {
312 bool enabled;
313 // This solves a bootstrapping problem: If the modem is not yet
314 // enabled, there are no proxy objects associated with the capability
315 // object, so modem signals like StateChanged aren't seen. By monitoring
316 // changes to the Enabled property via the ModemManager, we're able to
317 // get the initialization process started, which will result in the
318 // creation of the proxy objects.
319 //
320 // The first time we see the change to Enabled (when the modem state
321 // is Unknown), we simply update the state, and rely on the Manager to
322 // enable the device when it is registered with the Manager. On subsequent
323 // changes to Enabled, we need to explicitly enable the device ourselves.
324 if (DBusProperties::GetBool(changed_properties,
325 kModemPropertyEnabled, &enabled)) {
326 Cellular::ModemState prev_modem_state = cellular()->modem_state();
327 if (enabled)
328 cellular()->set_modem_state(Cellular::kModemStateEnabled);
329 else
330 cellular()->set_modem_state(Cellular::kModemStateDisabled);
331 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
332 prev_modem_state != Cellular::kModemStateUnknown &&
333 prev_modem_state != Cellular::kModemStateEnabled) {
334 cellular()->SetEnabled(true);
335 }
336 }
337}
338
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400339void CellularCapabilityClassic::OnGetModemStatusReply(
340 const ResultCallback &callback,
341 const DBusPropertiesMap &props,
342 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700343 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
344 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400345 if (error.IsSuccess()) {
346 DBusProperties::GetString(props, "carrier", &carrier_);
347 DBusProperties::GetString(props, "meid", &meid_);
348 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400349 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400350 DBusProperties::GetString(props, "esn", &esn_);
351 DBusProperties::GetString(props, "mdn", &mdn_);
352 DBusProperties::GetString(props, "min", &min_);
353 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400354 UpdateStatus(props);
355 }
356 callback.Run(error);
357}
358
359void CellularCapabilityClassic::OnGetModemInfoReply(
360 const ResultCallback &callback,
361 const ModemHardwareInfo &info,
362 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700363 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400364 if (error.IsSuccess()) {
365 manufacturer_ = info._1;
366 model_id_ = info._2;
367 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700368 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
369 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400370 }
371 callback.Run(error);
372}
373
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400374void CellularCapabilityClassic::OnModemStateChangedSignal(
375 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700376 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
377 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400378 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
379 ConvertClassicToModemState(new_state),
380 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400381}
382
383} // namespace shill