blob: 297b569fb9fea47deeab26a0c7fd84016ffb22de [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"
12#include "shill/property_accessor.h"
13#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070014#include "shill/scope_logger.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040015
16using base::Bind;
17using base::Callback;
18using base::Closure;
19using std::string;
20
21namespace shill {
22
23const char CellularCapabilityClassic::kConnectPropertyApn[] = "apn";
24const char CellularCapabilityClassic::kConnectPropertyApnUsername[] =
25 "username";
26const char CellularCapabilityClassic::kConnectPropertyApnPassword[] =
27 "password";
28const char CellularCapabilityClassic::kConnectPropertyHomeOnly[] = "home_only";
29const char CellularCapabilityClassic::kConnectPropertyPhoneNumber[] = "number";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040030const char CellularCapabilityClassic::kModemPropertyEnabled[] = "Enabled";
31
32static Cellular::ModemState ConvertClassicToModemState(uint32 classic_state) {
33 ModemClassicState cstate =
34 static_cast<ModemClassicState>(classic_state);
35 switch (cstate) {
36 case kModemClassicStateUnknown:
37 return Cellular::kModemStateUnknown;
38 case kModemClassicStateDisabled:
39 return Cellular::kModemStateDisabled;
40 case kModemClassicStateDisabling:
41 return Cellular::kModemStateDisabling;
42 case kModemClassicStateEnabling:
43 return Cellular::kModemStateEnabling;
44 case kModemClassicStateEnabled:
45 return Cellular::kModemStateEnabled;
46 case kModemClassicStateSearching:
47 return Cellular::kModemStateSearching;
48 case kModemClassicStateRegistered:
49 return Cellular::kModemStateRegistered;
50 case kModemClassicStateDisconnecting:
51 return Cellular::kModemStateDisconnecting;
52 case kModemClassicStateConnecting:
53 return Cellular::kModemStateConnecting;
54 case kModemClassicStateConnected:
55 return Cellular::kModemStateConnected;
56 default:
57 return Cellular::kModemStateUnknown;
58 };
59}
Jason Glasgow82f9ab32012-04-04 14:27:19 -040060
61CellularCapabilityClassic::CellularCapabilityClassic(
62 Cellular *cellular,
63 ProxyFactory *proxy_factory)
64 : CellularCapability(cellular, proxy_factory),
65 weak_ptr_factory_(this) {
66 PropertyStore *store = cellular->mutable_store();
67 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
68 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
69 &scanning_supported_);
70 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
71 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
72 &firmware_revision_);
73 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
74 &hardware_revision_);
75 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
76 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
77 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
78 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
79 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
80 store->RegisterConstString(flimflam::kMinProperty, &min_);
81 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
82}
83
84CellularCapabilityClassic::~CellularCapabilityClassic() {}
85
86void CellularCapabilityClassic::InitProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070087 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040088 proxy_.reset(proxy_factory()->CreateModemProxy(
89 cellular()->dbus_path(), cellular()->dbus_owner()));
90 simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
91 cellular()->dbus_path(), cellular()->dbus_owner()));
92 proxy_->set_state_changed_callback(
93 Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
94 weak_ptr_factory_.GetWeakPtr()));
95}
96
97void CellularCapabilityClassic::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070098 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040099 proxy_.reset();
100 simple_proxy_.reset();
101}
102
103void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400104 // Normally, running the callback is the last thing done in a method.
105 // In this case, we do it first, because we want to make sure that
106 // the device is marked as Enabled before the registration state is
107 // handled. See comment in Cellular::HandleNewRegistrationState.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400108 callback.Run(Error());
109 GetRegistrationState();
110 GetSignalQuality();
111}
112
113void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
114 ReleaseProxies();
115 callback.Run(Error());
116}
117
118void CellularCapabilityClassic::OnUnsupportedOperation(
119 const char *operation,
120 Error *error) {
121 string message("The ");
122 message.append(operation).append(" operation is not supported.");
123 Error::PopulateAndLog(error, Error::kNotSupported, message);
124}
125
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400126void CellularCapabilityClassic::RunNextStep(CellularTaskList *tasks) {
127 CHECK(!tasks->empty());
128 SLOG(Cellular, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
129 Closure task = (*tasks)[0];
130 tasks->erase(tasks->begin());
131 cellular()->dispatcher()->PostTask(task);
132}
133
134void CellularCapabilityClassic::StepCompletedCallback(
135 const ResultCallback &callback,
136 bool ignore_error,
137 CellularTaskList *tasks,
138 const Error &error) {
139 if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
140 RunNextStep(tasks);
141 return;
142 }
143 delete tasks;
144 callback.Run(error);
145}
146
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400147// always called from an async context
148void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700149 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400150 CHECK(!callback.is_null());
151 Error error;
152 proxy_->Enable(true, &error, callback, kTimeoutEnable);
153 if (error.IsFailure())
154 callback.Run(error);
155}
156
157// always called from an async context
158void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700159 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160 CHECK(!callback.is_null());
161 Error error;
Thieu Lec8d2d962012-05-15 14:31:18 -0700162 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400163 if (error.IsFailure())
164 callback.Run(error);
165}
166
167// always called from an async context
168void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700169 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400170 CHECK(!callback.is_null());
171 DBusPropertyMapCallback cb = Bind(
172 &CellularCapabilityClassic::OnGetModemStatusReply,
173 weak_ptr_factory_.GetWeakPtr(), callback);
174 Error error;
175 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
176 if (error.IsFailure())
177 callback.Run(error);
178}
179
180// always called from an async context
181void CellularCapabilityClassic::GetModemInfo(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 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
185 weak_ptr_factory_.GetWeakPtr(), callback);
186 Error error;
187 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
188 if (error.IsFailure())
189 callback.Run(error);
190}
191
192void CellularCapabilityClassic::StopModem(Error *error,
193 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700194 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400195
196 CellularTaskList *tasks = new CellularTaskList();
197 ResultCallback cb =
198 Bind(&CellularCapabilityClassic::StepCompletedCallback,
199 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
200 ResultCallback cb_ignore_error =
201 Bind(&CellularCapabilityClassic::StepCompletedCallback,
202 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400203 // TODO(ers): We can skip the call to Disconnect if the modem has
204 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400205 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
206 weak_ptr_factory_.GetWeakPtr(),
207 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400208 // TODO(ers): We can skip the call to Disable if the modem has
209 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400210 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
211 weak_ptr_factory_.GetWeakPtr(), cb));
212 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
213 weak_ptr_factory_.GetWeakPtr(), cb));
214
215 RunNextStep(tasks);
216}
217
218void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
219 Error *error,
220 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700221 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400222 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400223}
224
225void CellularCapabilityClassic::Disconnect(Error *error,
226 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700227 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400228 proxy_->Disconnect(error, callback, kTimeoutDefault);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400229}
230
231void CellularCapabilityClassic::Activate(const string &/*carrier*/,
232 Error *error,
233 const ResultCallback &/*callback*/) {
234 OnUnsupportedOperation(__func__, error);
235}
236
237void CellularCapabilityClassic::RegisterOnNetwork(
238 const string &/*network_id*/,
239 Error *error, const ResultCallback &/*callback*/) {
240 OnUnsupportedOperation(__func__, error);
241}
242
243void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
244 bool /*require*/,
245 Error *error,
246 const ResultCallback &/*callback*/) {
247 OnUnsupportedOperation(__func__, error);
248}
249
250void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
251 Error *error,
252 const ResultCallback &/*callback*/) {
253 OnUnsupportedOperation(__func__, error);
254}
255
256void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
257 const string &/*pin*/,
258 Error *error,
259 const ResultCallback &/*callback*/) {
260 OnUnsupportedOperation(__func__, error);
261}
262
263void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
264 const string &/*new_pin*/,
265 Error *error,
266 const ResultCallback &/*callback*/) {
267 OnUnsupportedOperation(__func__, error);
268}
269
270void CellularCapabilityClassic::Scan(Error *error,
271 const ResultCallback &callback) {
272 OnUnsupportedOperation(__func__, error);
273}
274
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400275void CellularCapabilityClassic::OnDBusPropertiesChanged(
276 const std::string &interface,
277 const DBusPropertiesMap &changed_properties,
278 const std::vector<std::string> &invalidated_properties) {
279 bool enabled;
280 // This solves a bootstrapping problem: If the modem is not yet
281 // enabled, there are no proxy objects associated with the capability
282 // object, so modem signals like StateChanged aren't seen. By monitoring
283 // changes to the Enabled property via the ModemManager, we're able to
284 // get the initialization process started, which will result in the
285 // creation of the proxy objects.
286 //
287 // The first time we see the change to Enabled (when the modem state
288 // is Unknown), we simply update the state, and rely on the Manager to
289 // enable the device when it is registered with the Manager. On subsequent
290 // changes to Enabled, we need to explicitly enable the device ourselves.
291 if (DBusProperties::GetBool(changed_properties,
292 kModemPropertyEnabled, &enabled)) {
293 Cellular::ModemState prev_modem_state = cellular()->modem_state();
294 if (enabled)
295 cellular()->set_modem_state(Cellular::kModemStateEnabled);
296 else
297 cellular()->set_modem_state(Cellular::kModemStateDisabled);
298 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
299 prev_modem_state != Cellular::kModemStateUnknown &&
300 prev_modem_state != Cellular::kModemStateEnabled) {
301 cellular()->SetEnabled(true);
302 }
303 }
304}
305
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400306void CellularCapabilityClassic::OnGetModemStatusReply(
307 const ResultCallback &callback,
308 const DBusPropertiesMap &props,
309 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700310 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
311 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400312 if (error.IsSuccess()) {
313 DBusProperties::GetString(props, "carrier", &carrier_);
314 DBusProperties::GetString(props, "meid", &meid_);
315 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400316 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400317 DBusProperties::GetString(props, "esn", &esn_);
318 DBusProperties::GetString(props, "mdn", &mdn_);
319 DBusProperties::GetString(props, "min", &min_);
320 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400321 UpdateStatus(props);
322 }
323 callback.Run(error);
324}
325
326void CellularCapabilityClassic::OnGetModemInfoReply(
327 const ResultCallback &callback,
328 const ModemHardwareInfo &info,
329 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700330 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400331 if (error.IsSuccess()) {
332 manufacturer_ = info._1;
333 model_id_ = info._2;
334 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700335 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
336 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400337 }
338 callback.Run(error);
339}
340
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400341void CellularCapabilityClassic::OnModemStateChangedSignal(
342 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700343 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
344 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400345 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
346 ConvertClassicToModemState(new_state),
347 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400348}
349
350} // namespace shill