blob: bf40872079a9d9c65ac99ac2a7ca0371dcf9b0a9 [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,
Thieu Lece4483e2013-01-23 15:12:03 -080065 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070066 ModemInfo *modem_info)
67 : CellularCapability(cellular, proxy_factory, modem_info),
mukesh agrawal6b34a842012-05-30 11:16:01 -070068 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -040069 weak_ptr_factory_(this) {
70 PropertyStore *store = cellular->mutable_store();
71 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
72 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
73 &scanning_supported_);
74 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
75 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
76 &firmware_revision_);
77 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
78 &hardware_revision_);
79 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
80 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
81 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
82 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
83 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
84 store->RegisterConstString(flimflam::kMinProperty, &min_);
85 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkov1abca3e2012-09-12 11:44:07 +020086
87 // This class is currently instantiated only for Gobi modems so setup the
88 // supported carriers list appropriately and expose it over RPC.
89 supported_carriers_.push_back(shill::kCarrierGenericUMTS);
90 supported_carriers_.push_back(shill::kCarrierSprint);
91 supported_carriers_.push_back(shill::kCarrierVerizon);
92 store->RegisterConstStrings(shill::kSupportedCarriersProperty,
93 &supported_carriers_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -040094}
95
96CellularCapabilityClassic::~CellularCapabilityClassic() {}
97
98void CellularCapabilityClassic::InitProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070099 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400100 proxy_.reset(proxy_factory()->CreateModemProxy(
101 cellular()->dbus_path(), cellular()->dbus_owner()));
102 simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
103 cellular()->dbus_path(), cellular()->dbus_owner()));
104 proxy_->set_state_changed_callback(
105 Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
106 weak_ptr_factory_.GetWeakPtr()));
107}
108
109void CellularCapabilityClassic::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700110 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400111 proxy_.reset();
112 simple_proxy_.reset();
Darin Petkovc37a9c42012-09-06 15:28:22 +0200113 gobi_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400114}
115
116void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400117 // Normally, running the callback is the last thing done in a method.
118 // In this case, we do it first, because we want to make sure that
119 // the device is marked as Enabled before the registration state is
120 // handled. See comment in Cellular::HandleNewRegistrationState.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400121 callback.Run(Error());
122 GetRegistrationState();
123 GetSignalQuality();
Thieu Le18c11072013-01-28 17:21:37 -0800124 // We expect the modem to start scanning after it has been enabled.
125 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700126 modem_info()->metrics()->NotifyDeviceEnableFinished(
127 cellular()->interface_index());
128 modem_info()->metrics()->NotifyDeviceScanStarted(
129 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400130}
131
132void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700133 modem_info()->metrics()->NotifyDeviceDisableFinished(
134 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400135 ReleaseProxies();
136 callback.Run(Error());
137}
138
139void CellularCapabilityClassic::OnUnsupportedOperation(
140 const char *operation,
141 Error *error) {
142 string message("The ");
143 message.append(operation).append(" operation is not supported.");
144 Error::PopulateAndLog(error, Error::kNotSupported, message);
145}
146
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400147void CellularCapabilityClassic::RunNextStep(CellularTaskList *tasks) {
148 CHECK(!tasks->empty());
149 SLOG(Cellular, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
150 Closure task = (*tasks)[0];
151 tasks->erase(tasks->begin());
152 cellular()->dispatcher()->PostTask(task);
153}
154
155void CellularCapabilityClassic::StepCompletedCallback(
156 const ResultCallback &callback,
157 bool ignore_error,
158 CellularTaskList *tasks,
159 const Error &error) {
160 if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
161 RunNextStep(tasks);
162 return;
163 }
164 delete tasks;
Ben Chan3ecdf822012-08-06 12:29:23 -0700165 if (!callback.is_null())
166 callback.Run(error);
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400167}
168
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400169// always called from an async context
170void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700171 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400172 CHECK(!callback.is_null());
173 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700174 modem_info()->metrics()->NotifyDeviceEnableStarted(
175 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400176 proxy_->Enable(true, &error, callback, kTimeoutEnable);
177 if (error.IsFailure())
178 callback.Run(error);
179}
180
181// always called from an async context
182void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700183 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400184 CHECK(!callback.is_null());
185 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700186 modem_info()->metrics()->NotifyDeviceDisableStarted(
187 cellular()->interface_index());
Thieu Lec8d2d962012-05-15 14:31:18 -0700188 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400189 if (error.IsFailure())
190 callback.Run(error);
191}
192
193// always called from an async context
194void CellularCapabilityClassic::GetModemStatus(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 DBusPropertyMapCallback cb = Bind(
198 &CellularCapabilityClassic::OnGetModemStatusReply,
199 weak_ptr_factory_.GetWeakPtr(), callback);
200 Error error;
201 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
202 if (error.IsFailure())
203 callback.Run(error);
204}
205
206// always called from an async context
207void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700208 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400209 CHECK(!callback.is_null());
210 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
211 weak_ptr_factory_.GetWeakPtr(), callback);
212 Error error;
213 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
214 if (error.IsFailure())
215 callback.Run(error);
216}
217
218void CellularCapabilityClassic::StopModem(Error *error,
219 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700220 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400221
222 CellularTaskList *tasks = new CellularTaskList();
223 ResultCallback cb =
224 Bind(&CellularCapabilityClassic::StepCompletedCallback,
225 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
226 ResultCallback cb_ignore_error =
227 Bind(&CellularCapabilityClassic::StepCompletedCallback,
228 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400229 // TODO(ers): We can skip the call to Disconnect if the modem has
230 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400231 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
232 weak_ptr_factory_.GetWeakPtr(),
233 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400234 // TODO(ers): We can skip the call to Disable if the modem has
235 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400236 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
237 weak_ptr_factory_.GetWeakPtr(), cb));
238 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
239 weak_ptr_factory_.GetWeakPtr(), cb));
240
241 RunNextStep(tasks);
242}
243
244void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
245 Error *error,
246 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700247 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400248 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400249}
250
251void CellularCapabilityClassic::Disconnect(Error *error,
252 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700253 SLOG(Cellular, 2) << __func__;
Thieu Le3d275392012-07-20 15:32:58 -0700254 if (proxy_.get())
Thieu Le049adb52012-11-12 17:14:51 -0800255 proxy_->Disconnect(error, callback, kTimeoutDisconnect);
Christopher Wiley7d0953e2012-11-16 00:37:10 -0800256 else
257 LOG(ERROR) << "No proxy found in disconnect.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400258}
259
Christopher Wiley8a468902012-11-30 11:52:38 -0800260void CellularCapabilityClassic::DisconnectCleanup() {
261 SLOG(Cellular, 2) << __func__;
262}
263
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400264void CellularCapabilityClassic::Activate(const string &/*carrier*/,
265 Error *error,
266 const ResultCallback &/*callback*/) {
267 OnUnsupportedOperation(__func__, error);
268}
269
270void CellularCapabilityClassic::RegisterOnNetwork(
271 const string &/*network_id*/,
272 Error *error, const ResultCallback &/*callback*/) {
273 OnUnsupportedOperation(__func__, error);
274}
275
276void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
277 bool /*require*/,
278 Error *error,
279 const ResultCallback &/*callback*/) {
280 OnUnsupportedOperation(__func__, error);
281}
282
283void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
284 Error *error,
285 const ResultCallback &/*callback*/) {
286 OnUnsupportedOperation(__func__, error);
287}
288
289void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
290 const string &/*pin*/,
291 Error *error,
292 const ResultCallback &/*callback*/) {
293 OnUnsupportedOperation(__func__, error);
294}
295
296void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
297 const string &/*new_pin*/,
298 Error *error,
299 const ResultCallback &/*callback*/) {
300 OnUnsupportedOperation(__func__, error);
301}
302
Darin Petkovc37a9c42012-09-06 15:28:22 +0200303void CellularCapabilityClassic::SetCarrier(const string &carrier,
304 Error *error,
305 const ResultCallback &callback) {
306 LOG(INFO) << __func__ << "(" << carrier << ")";
307 if (!gobi_proxy_.get()) {
308 gobi_proxy_.reset(proxy_factory()->CreateModemGobiProxy(
309 cellular()->dbus_path(), cellular()->dbus_owner()));
310 }
311 CHECK(error);
312 gobi_proxy_->SetCarrier(carrier, error, callback,
313 kTimeoutSetCarrierMilliseconds);
314}
315
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400316void CellularCapabilityClassic::Scan(Error *error,
Wade Guthrie4823f4f2013-07-25 10:03:03 -0700317 const ResultCallback &callback) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400318 OnUnsupportedOperation(__func__, error);
319}
320
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400321void CellularCapabilityClassic::OnDBusPropertiesChanged(
322 const std::string &interface,
323 const DBusPropertiesMap &changed_properties,
324 const std::vector<std::string> &invalidated_properties) {
325 bool enabled;
326 // This solves a bootstrapping problem: If the modem is not yet
327 // enabled, there are no proxy objects associated with the capability
328 // object, so modem signals like StateChanged aren't seen. By monitoring
329 // changes to the Enabled property via the ModemManager, we're able to
330 // get the initialization process started, which will result in the
331 // creation of the proxy objects.
332 //
333 // The first time we see the change to Enabled (when the modem state
334 // is Unknown), we simply update the state, and rely on the Manager to
335 // enable the device when it is registered with the Manager. On subsequent
336 // changes to Enabled, we need to explicitly enable the device ourselves.
337 if (DBusProperties::GetBool(changed_properties,
338 kModemPropertyEnabled, &enabled)) {
339 Cellular::ModemState prev_modem_state = cellular()->modem_state();
340 if (enabled)
341 cellular()->set_modem_state(Cellular::kModemStateEnabled);
342 else
343 cellular()->set_modem_state(Cellular::kModemStateDisabled);
344 if (enabled && cellular()->state() == Cellular::kStateDisabled &&
345 prev_modem_state != Cellular::kModemStateUnknown &&
346 prev_modem_state != Cellular::kModemStateEnabled) {
347 cellular()->SetEnabled(true);
348 }
349 }
350}
351
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400352void CellularCapabilityClassic::OnGetModemStatusReply(
353 const ResultCallback &callback,
354 const DBusPropertiesMap &props,
355 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700356 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
357 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400358 if (error.IsSuccess()) {
359 DBusProperties::GetString(props, "carrier", &carrier_);
360 DBusProperties::GetString(props, "meid", &meid_);
361 DBusProperties::GetString(props, "imei", &imei_);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400362 DBusProperties::GetString(props, kModemPropertyIMSI, &imsi_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400363 DBusProperties::GetString(props, "esn", &esn_);
364 DBusProperties::GetString(props, "mdn", &mdn_);
365 DBusProperties::GetString(props, "min", &min_);
366 DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400367 UpdateStatus(props);
368 }
369 callback.Run(error);
370}
371
372void CellularCapabilityClassic::OnGetModemInfoReply(
373 const ResultCallback &callback,
374 const ModemHardwareInfo &info,
375 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700376 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400377 if (error.IsSuccess()) {
378 manufacturer_ = info._1;
379 model_id_ = info._2;
380 hardware_revision_ = info._3;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700381 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
382 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400383 }
384 callback.Run(error);
385}
386
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400387void CellularCapabilityClassic::OnModemStateChangedSignal(
388 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700389 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
390 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400391 cellular()->OnModemStateChanged(ConvertClassicToModemState(old_state),
392 ConvertClassicToModemState(new_state),
393 reason);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400394}
395
396} // namespace shill