blob: 39265c3e2ca81269eed41439f1ad0d224f5d94f8 [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) {
Ben Chanf98f00e2014-02-05 14:48:43 -080035 ModemClassicState cstate = static_cast<ModemClassicState>(classic_state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040036 switch (cstate) {
37 case kModemClassicStateUnknown:
38 return Cellular::kModemStateUnknown;
39 case kModemClassicStateDisabled:
40 return Cellular::kModemStateDisabled;
41 case kModemClassicStateDisabling:
42 return Cellular::kModemStateDisabling;
43 case kModemClassicStateEnabling:
44 return Cellular::kModemStateEnabling;
45 case kModemClassicStateEnabled:
46 return Cellular::kModemStateEnabled;
47 case kModemClassicStateSearching:
48 return Cellular::kModemStateSearching;
49 case kModemClassicStateRegistered:
50 return Cellular::kModemStateRegistered;
51 case kModemClassicStateDisconnecting:
52 return Cellular::kModemStateDisconnecting;
53 case kModemClassicStateConnecting:
54 return Cellular::kModemStateConnecting;
55 case kModemClassicStateConnected:
56 return Cellular::kModemStateConnected;
57 default:
58 return Cellular::kModemStateUnknown;
59 };
60}
Jason Glasgow82f9ab32012-04-04 14:27:19 -040061
62CellularCapabilityClassic::CellularCapabilityClassic(
63 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -080064 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070065 ModemInfo *modem_info)
66 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -040067 weak_ptr_factory_(this) {
Darin Petkov1abca3e2012-09-12 11:44:07 +020068 // This class is currently instantiated only for Gobi modems so setup the
69 // supported carriers list appropriately and expose it over RPC.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -080070 cellular->set_supported_carriers({kCarrierGenericUMTS,
71 kCarrierSprint,
72 kCarrierVerizon});
Jason Glasgow82f9ab32012-04-04 14:27:19 -040073}
74
75CellularCapabilityClassic::~CellularCapabilityClassic() {}
76
77void CellularCapabilityClassic::InitProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070078 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040079 proxy_.reset(proxy_factory()->CreateModemProxy(
80 cellular()->dbus_path(), cellular()->dbus_owner()));
81 simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
82 cellular()->dbus_path(), cellular()->dbus_owner()));
83 proxy_->set_state_changed_callback(
84 Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
85 weak_ptr_factory_.GetWeakPtr()));
86}
87
88void CellularCapabilityClassic::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070089 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040090 proxy_.reset();
91 simple_proxy_.reset();
Darin Petkovc37a9c42012-09-06 15:28:22 +020092 gobi_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093}
94
95void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -040096 // Normally, running the callback is the last thing done in a method.
97 // In this case, we do it first, because we want to make sure that
98 // the device is marked as Enabled before the registration state is
99 // handled. See comment in Cellular::HandleNewRegistrationState.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400100 callback.Run(Error());
101 GetRegistrationState();
102 GetSignalQuality();
Thieu Le18c11072013-01-28 17:21:37 -0800103 // We expect the modem to start scanning after it has been enabled.
104 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700105 modem_info()->metrics()->NotifyDeviceEnableFinished(
106 cellular()->interface_index());
107 modem_info()->metrics()->NotifyDeviceScanStarted(
108 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400109}
110
111void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700112 modem_info()->metrics()->NotifyDeviceDisableFinished(
113 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400114 ReleaseProxies();
115 callback.Run(Error());
116}
117
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400118void CellularCapabilityClassic::RunNextStep(CellularTaskList *tasks) {
119 CHECK(!tasks->empty());
120 SLOG(Cellular, 2) << __func__ << ": " << tasks->size() << " remaining tasks";
121 Closure task = (*tasks)[0];
122 tasks->erase(tasks->begin());
123 cellular()->dispatcher()->PostTask(task);
124}
125
126void CellularCapabilityClassic::StepCompletedCallback(
127 const ResultCallback &callback,
128 bool ignore_error,
129 CellularTaskList *tasks,
130 const Error &error) {
131 if ((ignore_error || error.IsSuccess()) && !tasks->empty()) {
132 RunNextStep(tasks);
133 return;
134 }
135 delete tasks;
Ben Chan3ecdf822012-08-06 12:29:23 -0700136 if (!callback.is_null())
137 callback.Run(error);
Jason Glasgowa0caabf2012-05-04 11:31:41 -0400138}
139
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400140// always called from an async context
141void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700142 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400143 CHECK(!callback.is_null());
144 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700145 modem_info()->metrics()->NotifyDeviceEnableStarted(
146 cellular()->interface_index());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400147 proxy_->Enable(true, &error, callback, kTimeoutEnable);
148 if (error.IsFailure())
149 callback.Run(error);
150}
151
152// always called from an async context
153void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700154 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400155 CHECK(!callback.is_null());
156 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700157 modem_info()->metrics()->NotifyDeviceDisableStarted(
158 cellular()->interface_index());
Thieu Lec8d2d962012-05-15 14:31:18 -0700159 proxy_->Enable(false, &error, callback, kTimeoutEnable);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160 if (error.IsFailure())
161 callback.Run(error);
162}
163
164// always called from an async context
165void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700166 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400167 CHECK(!callback.is_null());
168 DBusPropertyMapCallback cb = Bind(
169 &CellularCapabilityClassic::OnGetModemStatusReply,
170 weak_ptr_factory_.GetWeakPtr(), callback);
171 Error error;
172 simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
173 if (error.IsFailure())
174 callback.Run(error);
175}
176
177// always called from an async context
178void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700179 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400180 CHECK(!callback.is_null());
181 ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
182 weak_ptr_factory_.GetWeakPtr(), callback);
183 Error error;
184 proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
185 if (error.IsFailure())
186 callback.Run(error);
187}
188
189void CellularCapabilityClassic::StopModem(Error *error,
Ben Chanf98f00e2014-02-05 14:48:43 -0800190 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700191 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400192
193 CellularTaskList *tasks = new CellularTaskList();
194 ResultCallback cb =
195 Bind(&CellularCapabilityClassic::StepCompletedCallback,
196 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
197 ResultCallback cb_ignore_error =
198 Bind(&CellularCapabilityClassic::StepCompletedCallback,
199 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400200 // TODO(ers): We can skip the call to Disconnect if the modem has
201 // told us that the modem state is Disabled or Registered.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400202 tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
203 weak_ptr_factory_.GetWeakPtr(),
204 static_cast<Error *>(NULL), cb_ignore_error));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400205 // TODO(ers): We can skip the call to Disable if the modem has
206 // told us that the modem state is Disabled.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400207 tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
208 weak_ptr_factory_.GetWeakPtr(), cb));
209 tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
210 weak_ptr_factory_.GetWeakPtr(), cb));
211
212 RunNextStep(tasks);
213}
214
215void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
Ben Chanf98f00e2014-02-05 14:48:43 -0800216 Error *error,
217 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700218 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400219 simple_proxy_->Connect(properties, error, callback, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400220}
221
222void CellularCapabilityClassic::Disconnect(Error *error,
Ben Chanf98f00e2014-02-05 14:48:43 -0800223 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700224 SLOG(Cellular, 2) << __func__;
Thieu Le3d275392012-07-20 15:32:58 -0700225 if (proxy_.get())
Thieu Le049adb52012-11-12 17:14:51 -0800226 proxy_->Disconnect(error, callback, kTimeoutDisconnect);
Christopher Wiley7d0953e2012-11-16 00:37:10 -0800227 else
228 LOG(ERROR) << "No proxy found in disconnect.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400229}
230
Darin Petkovc37a9c42012-09-06 15:28:22 +0200231void CellularCapabilityClassic::SetCarrier(const string &carrier,
232 Error *error,
233 const ResultCallback &callback) {
234 LOG(INFO) << __func__ << "(" << carrier << ")";
235 if (!gobi_proxy_.get()) {
236 gobi_proxy_.reset(proxy_factory()->CreateModemGobiProxy(
237 cellular()->dbus_path(), cellular()->dbus_owner()));
238 }
239 CHECK(error);
240 gobi_proxy_->SetCarrier(carrier, error, callback,
241 kTimeoutSetCarrierMilliseconds);
242}
243
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400244void CellularCapabilityClassic::OnDBusPropertiesChanged(
245 const std::string &interface,
246 const DBusPropertiesMap &changed_properties,
247 const std::vector<std::string> &invalidated_properties) {
Arman Uguray1ee93912013-09-24 21:24:10 -0700248 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400249 bool enabled;
250 // This solves a bootstrapping problem: If the modem is not yet
251 // enabled, there are no proxy objects associated with the capability
252 // object, so modem signals like StateChanged aren't seen. By monitoring
253 // changes to the Enabled property via the ModemManager, we're able to
254 // get the initialization process started, which will result in the
255 // creation of the proxy objects.
256 //
Arman Uguray1ee93912013-09-24 21:24:10 -0700257 // We handle all state changes to ENABLED from a disabled state (including,
258 // UNKNOWN) through Cellular::OnModemStateChanged. This will try to enable
259 // the device regardless of whether it has been registered with the Manager.
260 //
261 // All other state changes are handled from OnModemStateChangedSignal.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400262 if (DBusProperties::GetBool(changed_properties,
263 kModemPropertyEnabled, &enabled)) {
Arman Uguray1ee93912013-09-24 21:24:10 -0700264 SLOG(Cellular, 2) << "Property \"Enabled\" changed: " << enabled;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400265 Cellular::ModemState prev_modem_state = cellular()->modem_state();
Arman Uguray1ee93912013-09-24 21:24:10 -0700266 if (!Cellular::IsEnabledModemState(prev_modem_state)) {
267 cellular()->OnModemStateChanged(
268 enabled ? Cellular::kModemStateEnabled :
269 Cellular::kModemStateDisabled);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400270 }
271 }
272}
273
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400274void CellularCapabilityClassic::OnGetModemStatusReply(
275 const ResultCallback &callback,
276 const DBusPropertiesMap &props,
277 const Error &error) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800278 string prop_value;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700279 SLOG(Cellular, 2) << __func__ << " " << props.size() << " props. error "
280 << error;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400281 if (error.IsSuccess()) {
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700282 if (DBusProperties::GetString(props, "carrier", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800283 cellular()->set_carrier(prop_value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -0700284 cellular()->home_provider_info()->UpdateOperatorName(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700285 }
286 if (DBusProperties::GetString(props, "meid", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800287 cellular()->set_meid(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700288 }
289 if (DBusProperties::GetString(props, "imei", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800290 cellular()->set_imei(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700291 }
292 if (DBusProperties::GetString(props, kModemPropertyIMSI, &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800293 cellular()->set_imsi(prop_value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -0700294 cellular()->home_provider_info()->UpdateIMSI(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700295 }
296 if (DBusProperties::GetString(props, "esn", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800297 cellular()->set_esn(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700298 }
299 if (DBusProperties::GetString(props, "mdn", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800300 cellular()->set_mdn(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700301 }
302 if (DBusProperties::GetString(props, "min", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800303 cellular()->set_min(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700304 }
305 if (DBusProperties::GetString(props, "firmware_revision", &prop_value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800306 cellular()->set_firmware_revision(prop_value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -0700307 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400308 UpdateStatus(props);
309 }
310 callback.Run(error);
311}
312
Prathmesh Prabhu6e0a8ef2014-05-05 22:30:07 -0700313void CellularCapabilityClassic::UpdateStatus(
314 const DBusPropertiesMap &properties) {
315 SLOG(Cellular, 3) << __func__;
316}
317
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400318void CellularCapabilityClassic::OnGetModemInfoReply(
319 const ResultCallback &callback,
320 const ModemHardwareInfo &info,
321 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700322 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400323 if (error.IsSuccess()) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800324 cellular()->set_manufacturer(info._1);
325 cellular()->set_model_id(info._2);
326 cellular()->set_hardware_revision(info._3);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700327 SLOG(Cellular, 2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
328 << info._3;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400329 }
330 callback.Run(error);
331}
332
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400333void CellularCapabilityClassic::OnModemStateChangedSignal(
334 uint32 old_state, uint32 new_state, uint32 reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700335 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
336 << reason << ")";
Arman Uguray1ee93912013-09-24 21:24:10 -0700337 cellular()->OnModemStateChanged(ConvertClassicToModemState(new_state));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400338}
339
340} // namespace shill