blob: cda10d9aaa319298f780ebe51f42e72d8ddf7f7e [file] [log] [blame]
Arman Uguray72fab6a2013-01-10 19:32:42 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002// 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_universal.h"
6
7#include <base/bind.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04008#include <base/stl_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -08009#include <base/strings/string_util.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070010#include <base/strings/stringprintf.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040011#include <chromeos/dbus/service_constants.h>
Ben Chan5c853ef2012-10-05 00:05:37 -070012#include <ModemManager/ModemManager.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040013
14#include <string>
15#include <vector>
16
17#include "shill/adaptor_interfaces.h"
Ben Chan539ab022014-02-03 16:34:57 -080018#include "shill/cellular_bearer.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040019#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040020#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040021#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070022#include "shill/logging.h"
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -070023#include "shill/mobile_operator_info.h"
Arman Uguray41cc6342013-03-29 16:34:39 -070024#include "shill/pending_activation_store.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040025#include "shill/property_accessor.h"
26#include "shill/proxy_factory.h"
27
28#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
29#error "Do not include mm-modem.h"
30#endif
31
Jason Glasgow82f9ab32012-04-04 14:27:19 -040032using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040033using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040034using std::string;
35using std::vector;
36
37namespace shill {
38
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070039namespace Logging {
40static auto kModuleLogScope = ScopeLogger::kCellular;
41static string ObjectID(CellularCapabilityUniversal *c) {
42 return c->cellular()->GetRpcIdentifier();
43}
44}
45
Jason Glasgow82f9ab32012-04-04 14:27:19 -040046// static
Jason Glasgow14521872012-05-07 19:12:15 -040047const char CellularCapabilityUniversal::kConnectPin[] = "pin";
48const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
Jason Glasgow14521872012-05-07 19:12:15 -040049const char CellularCapabilityUniversal::kConnectApn[] = "apn";
50const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
51const char CellularCapabilityUniversal::kConnectUser[] = "user";
52const char CellularCapabilityUniversal::kConnectPassword[] = "password";
53const char CellularCapabilityUniversal::kConnectNumber[] = "number";
54const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
55 "allow-roaming";
56const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Ben Chan7fab8972014-08-10 17:14:46 -070057const int64_t CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
58const int64_t
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070059CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
60 15000;
Arman Uguray6552f8c2013-02-12 15:33:18 -080061const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040062const char CellularCapabilityUniversal::kStatusProperty[] = "status";
63const char CellularCapabilityUniversal::kOperatorLongProperty[] =
64 "operator-long";
65const char CellularCapabilityUniversal::kOperatorShortProperty[] =
66 "operator-short";
67const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
68 "operator-code";
69const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
70 "access-technology";
Thieu Lec466ccb2014-06-23 15:24:56 -070071const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE";
Ben Chan3dddd042014-10-19 14:08:10 -070072const char CellularCapabilityUniversal::kNovatelLTEMMPlugin[] = "Novatel LTE";
Thieu Le2cac2942013-03-05 18:41:08 -080073const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
74 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040075
Ben Chan07193fd2013-07-12 22:10:55 -070076namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040077
Ben Chan07193fd2013-07-12 22:10:55 -070078const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040079
Ben Chan09b8bfc2014-10-19 13:52:47 -070080// This identifier is specified in the serviceproviders.prototxt file.
Prathmesh Prabhu5089a6e2014-05-07 20:49:16 -070081const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751";
Ben Chan07193fd2013-07-12 22:10:55 -070082const size_t kVzwMdnLength = 10;
83
Ben Chan7fab8972014-08-10 17:14:46 -070084string AccessTechnologyToString(uint32_t access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040085 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
Ben Chan7ea768e2013-09-20 15:08:40 -070086 return kNetworkTechnologyLte;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040087 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
88 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
89 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
Ben Chan7ea768e2013-09-20 15:08:40 -070090 return kNetworkTechnologyEvdo;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040091 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
Ben Chan7ea768e2013-09-20 15:08:40 -070092 return kNetworkTechnology1Xrtt;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
Ben Chan7ea768e2013-09-20 15:08:40 -070094 return kNetworkTechnologyHspaPlus;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040095 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
96 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
Ben Chan7ea768e2013-09-20 15:08:40 -070098 return kNetworkTechnologyHspa;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040099 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700100 return kNetworkTechnologyUmts;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400101 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
Ben Chan7ea768e2013-09-20 15:08:40 -0700102 return kNetworkTechnologyEdge;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400103 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700104 return kNetworkTechnologyGprs;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400105 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
106 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700107 return kNetworkTechnologyGsm;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400108 return "";
109}
110
Ben Chan7fab8972014-08-10 17:14:46 -0700111string AccessTechnologyToTechnologyFamily(uint32_t access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400112 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
113 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
114 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
118 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
119 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
120 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
121 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700122 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400123 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800124 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
125 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400126 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700127 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400128 return "";
129}
130
Ben Chan07193fd2013-07-12 22:10:55 -0700131} // namespace
132
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400133CellularCapabilityUniversal::CellularCapabilityUniversal(
134 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800135 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700136 ModemInfo *modem_info)
137 : CellularCapability(cellular, proxy_factory, modem_info),
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700138 mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(),
139 "ParseScanResult")),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400140 weak_ptr_factory_(this),
141 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200142 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400143 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800144 resetting_(false),
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700145 subscription_state_(kSubscriptionStateUnknown),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800146 reset_done_(false),
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700147 registration_dropped_update_timeout_milliseconds_(
148 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700149 SLOG(this, 2) << "Cellular capability constructed: Universal";
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700150 mobile_operator_info_->Init();
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700151 HelpRegisterConstDerivedKeyValueStore(
Ben Chan7ea768e2013-09-20 15:08:40 -0700152 kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700153 &CellularCapabilityUniversal::SimLockStatusToProperty);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400154}
155
Ben Chanf98f00e2014-02-05 14:48:43 -0800156CellularCapabilityUniversal::~CellularCapabilityUniversal() {}
157
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400158KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
159 Error */*error*/) {
160 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700161 string lock_type;
162 switch (sim_lock_status_.lock_type) {
163 case MM_MODEM_LOCK_SIM_PIN:
164 lock_type = "sim-pin";
165 break;
166 case MM_MODEM_LOCK_SIM_PUK:
167 lock_type = "sim-puk";
168 break;
169 default:
170 lock_type = "";
171 break;
172 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700173 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
174 status.SetString(kSIMLockTypeProperty, lock_type);
175 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400176 return status;
177}
178
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700179void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400180 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700181 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400182 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
183 name,
184 KeyValueStoreAccessor(
185 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
Ben Chanea18c6c2014-09-30 13:08:26 -0700186 this, get, nullptr)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400187}
188
189void CellularCapabilityUniversal::InitProxies() {
190 modem_3gpp_proxy_.reset(
191 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
192 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400193 modem_proxy_.reset(
194 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
195 cellular()->dbus_owner()));
196 modem_simple_proxy_.reset(
197 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
198 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800199
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400200 modem_proxy_->set_state_changed_callback(
201 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
202 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400203 // Do not create a SIM proxy until the device is enabled because we
204 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400205 // TODO(jglasgow): register callbacks
206}
207
208void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400209 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700210 SLOG(this, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400211 InitProxies();
Ben Chan151d4472013-09-06 13:29:46 -0700212 deferred_enable_modem_callback_.Reset();
213 EnableModem(true, error, callback);
Gary Moraine285a842012-08-15 08:23:57 -0700214}
215
Ben Chan151d4472013-09-06 13:29:46 -0700216void CellularCapabilityUniversal::EnableModem(bool deferrable,
217 Error *error,
Gary Moraine285a842012-08-15 08:23:57 -0700218 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700219 SLOG(this, 3) << __func__ << "(deferrable=" << deferrable << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400220 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700221 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700222 modem_info()->metrics()->NotifyDeviceEnableStarted(
223 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400224 modem_proxy_->Enable(
225 true,
Gary Moraine285a842012-08-15 08:23:57 -0700226 &local_error,
Ben Chan151d4472013-09-06 13:29:46 -0700227 Bind(&CellularCapabilityUniversal::EnableModemCompleted,
228 weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
Jason Glasgowef965562012-04-10 16:12:35 -0400229 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700230 if (local_error.IsFailure()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700231 SLOG(this, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700232 }
233 if (error) {
234 error->CopyFrom(local_error);
235 }
Jason Glasgowef965562012-04-10 16:12:35 -0400236}
237
Ben Chan151d4472013-09-06 13:29:46 -0700238void CellularCapabilityUniversal::EnableModemCompleted(
239 bool deferrable, const ResultCallback &callback, const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700240 SLOG(this, 3) << __func__ << "(deferrable=" << deferrable
241 << ", error=" << error << ")";
Thieu Leb9c05e02013-03-04 14:09:32 -0800242
Ben Chan151d4472013-09-06 13:29:46 -0700243 // If the enable operation failed with Error::kWrongState, the modem is not
244 // in the expected state (i.e. disabled). If |deferrable| indicates that the
245 // enable operation can be deferred, we defer the operation until the modem
246 // goes into the expected state (see OnModemStateChangedSignal).
247 //
248 // Note that when the SIM is locked, the enable operation also fails with
249 // Error::kWrongState. The enable operation is deferred until the modem goes
250 // into the disabled state after the SIM is unlocked. We may choose not to
251 // defer the enable operation when the SIM is locked, but the UI needs to
252 // trigger the enable operation after the SIM is unlocked, which is currently
253 // not the case.
Jason Glasgowef965562012-04-10 16:12:35 -0400254 if (error.IsFailure()) {
Ben Chan151d4472013-09-06 13:29:46 -0700255 if (!deferrable || error.type() != Error::kWrongState) {
256 callback.Run(error);
257 return;
258 }
259
260 if (deferred_enable_modem_callback_.is_null()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700261 SLOG(this, 2) << "Defer enable operation.";
Ben Chan151d4472013-09-06 13:29:46 -0700262 // The Enable operation to be deferred should not be further deferrable.
263 deferred_enable_modem_callback_ =
264 Bind(&CellularCapabilityUniversal::EnableModem,
265 weak_ptr_factory_.GetWeakPtr(),
266 false, // non-deferrable
Ben Chanea18c6c2014-09-30 13:08:26 -0700267 nullptr,
Ben Chan151d4472013-09-06 13:29:46 -0700268 callback);
269 }
Jason Glasgowef965562012-04-10 16:12:35 -0400270 return;
271 }
272
273 // After modem is enabled, it should be possible to get properties
274 // TODO(jglasgow): handle errors from GetProperties
275 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800276 // We expect the modem to start scanning after it has been enabled.
277 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700278 modem_info()->metrics()->NotifyDeviceEnableFinished(
279 cellular()->interface_index());
280 modem_info()->metrics()->NotifyDeviceScanStarted(
281 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800282 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400283}
284
285void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400286 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400287 CHECK(!callback.is_null());
288 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700289 // If there is an outstanding registration change, simply ignore it since
290 // the service will be destroyed anyway.
291 if (!registration_dropped_update_callback_.IsCancelled()) {
292 registration_dropped_update_callback_.Cancel();
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700293 SLOG(this, 2) << __func__ << " Cancelled delayed deregister.";
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700294 }
295
Thieu Le28492142014-04-08 16:41:13 -0700296 // Some modems will implicitly disconnect the bearer when transitioning to
297 // low power state. For such modems, it's faster to let the modem disconnect
298 // the bearer. To do that, we just remove the bearer from the list so
299 // ModemManager doesn't try to disconnect it during disable.
300 Closure task;
Thieu Lec466ccb2014-06-23 15:24:56 -0700301 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le28492142014-04-08 16:41:13 -0700302 task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer,
303 weak_ptr_factory_.GetWeakPtr(),
304 callback);
305 } else {
306 task = Bind(&CellularCapabilityUniversal::Stop_Disable,
307 weak_ptr_factory_.GetWeakPtr(),
308 callback);
309 }
Ben Chan9de146f2013-09-11 13:11:31 -0700310 cellular()->dispatcher()->PostTask(task);
Gary Moraine285a842012-08-15 08:23:57 -0700311 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400312}
313
Thieu Le28492142014-04-08 16:41:13 -0700314void CellularCapabilityUniversal::Stop_DeleteActiveBearer(
315 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700316 SLOG(this, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700317
318 if (!active_bearer_) {
319 Stop_Disable(callback);
320 return;
321 }
322
Thieu Le28492142014-04-08 16:41:13 -0700323 Error error;
324 modem_proxy_->DeleteBearer(
325 active_bearer_->dbus_path(), &error,
326 Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted,
327 weak_ptr_factory_.GetWeakPtr(), callback),
328 kTimeoutDefault);
329 if (error.IsFailure())
330 callback.Run(error);
331}
332
333void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted(
334 const ResultCallback &callback, const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700335 SLOG(this, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700336 // Disregard the error from the bearer deletion since the disable will clean
337 // up any remaining bearers.
338 Stop_Disable(callback);
Thieu Le28492142014-04-08 16:41:13 -0700339}
340
Jason Glasgowef965562012-04-10 16:12:35 -0400341void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700342 SLOG(this, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400343 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700344 modem_info()->metrics()->NotifyDeviceDisableStarted(
345 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400346 modem_proxy_->Enable(
347 false, &error,
348 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
349 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400350 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400351 if (error.IsFailure())
352 callback.Run(error);
353}
354
355void CellularCapabilityUniversal::Stop_DisableCompleted(
356 const ResultCallback &callback, const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700357 SLOG(this, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400358
Thieu Lea2519bf2013-01-23 16:51:54 -0800359 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800360 // The modem has been successfully disabled, but we still need to power it
361 // down.
362 Stop_PowerDown(callback);
363 } else {
364 // An error occurred; terminate the disable sequence.
365 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800366 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800367}
368
369void CellularCapabilityUniversal::Stop_PowerDown(
370 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700371 SLOG(this, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800372 Error error;
373 modem_proxy_->SetPowerState(
374 MM_MODEM_POWER_STATE_LOW,
375 &error,
376 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
377 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800378 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800379
380 if (error.IsFailure())
381 // This really shouldn't happen, but if it does, report success,
382 // because a stop initiated power down is only called if the
383 // modem was successfully disabled, but the failure of this
384 // operation should still be propagated up as a successful disable.
385 Stop_PowerDownCompleted(callback, error);
386}
387
mukesh agrawal28185512013-10-18 16:57:09 -0700388// Note: if we were in the middle of powering down the modem when the
389// system suspended, we might not get this event from
390// ModemManager. And we might not even get a timeout from dbus-c++,
391// because StartModem re-initializes proxies.
Arman Ugurayee464d32013-02-13 17:14:36 -0800392void CellularCapabilityUniversal::Stop_PowerDownCompleted(
393 const ResultCallback &callback,
394 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700395 SLOG(this, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800396
397 if (error.IsFailure())
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700398 SLOG(this, 2) << "Ignoring error returned by SetPowerState: " << error;
Arman Ugurayee464d32013-02-13 17:14:36 -0800399
400 // Since the disable succeeded, if power down fails, we currently fail
401 // silently, i.e. we need to report the disable operation as having
402 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700403 modem_info()->metrics()->NotifyDeviceDisableFinished(
404 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800405 ReleaseProxies();
406 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400407}
408
409void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
410 Error *error,
411 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700412 SLOG(this, 3) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400413 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
414 weak_ptr_factory_.GetWeakPtr(),
415 callback);
416 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400417}
418
419void CellularCapabilityUniversal::Disconnect(Error *error,
420 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700421 SLOG(this, 3) << __func__;
Ben Chan539ab022014-02-03 16:34:57 -0800422 if (modem_simple_proxy_.get()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700423 SLOG(this, 2) << "Disconnect all bearers.";
Ben Chan539ab022014-02-03 16:34:57 -0800424 // If "/" is passed as the bearer path, ModemManager will disconnect all
425 // bearers.
426 modem_simple_proxy_->Disconnect(DBus::Path(kRootPath),
Thieu Le5d6864a2012-07-20 11:43:51 -0700427 error,
428 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800429 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700430 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400431}
432
Arman Ugurayc7b15602013-02-16 00:56:18 -0800433void CellularCapabilityUniversal::CompleteActivation(Error *error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700434 SLOG(this, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800435
436 // Persist the ICCID as "Pending Activation".
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800437 // We're assuming that when this function gets called,
438 // |cellular()->sim_identifier()| will be non-empty. We still check here that
439 // is non-empty, though something is wrong if it is empty.
440 const string &sim_identifier = cellular()->sim_identifier();
441 if (sim_identifier.empty()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700442 SLOG(this, 2) << "SIM identifier not available. Nothing to do.";
Arman Ugurayc7b15602013-02-16 00:56:18 -0800443 return;
444 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800445
Arman Uguray41cc6342013-03-29 16:34:39 -0700446 modem_info()->pending_activation_store()->SetActivationState(
447 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800448 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700449 PendingActivationStore::kStatePending);
Thieu Le7de12f52014-07-11 15:30:43 -0700450 UpdatePendingActivationState();
Arman Uguraya14941d2013-04-12 16:58:26 -0700451
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700452 SLOG(this, 2) << "Resetting modem for activation.";
Thieu Le7de12f52014-07-11 15:30:43 -0700453 ResetAfterActivation();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800454}
455
456void CellularCapabilityUniversal::ResetAfterActivation() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700457 SLOG(this, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800458
459 // Here the initial call to Reset might fail in rare cases. Simply ignore.
460 Error error;
461 ResultCallback callback = Bind(
462 &CellularCapabilityUniversal::OnResetAfterActivationReply,
463 weak_ptr_factory_.GetWeakPtr());
464 Reset(&error, callback);
465 if (error.IsFailure())
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700466 SLOG(this, 2) << "Failed to reset after activation.";
Arman Ugurayc7b15602013-02-16 00:56:18 -0800467}
468
469void CellularCapabilityUniversal::OnResetAfterActivationReply(
470 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700471 SLOG(this, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800472 if (error.IsFailure()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700473 SLOG(this, 2) << "Failed to reset after activation. Try again later.";
Arman Ugurayc7b15602013-02-16 00:56:18 -0800474 // TODO(armansito): Maybe post a delayed reset task?
475 return;
476 }
477 reset_done_ = true;
Arman Uguray0a3e2792013-01-17 16:31:50 -0800478 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800479}
480
Arman Uguray0a3e2792013-01-17 16:31:50 -0800481void CellularCapabilityUniversal::UpdatePendingActivationState() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700482 SLOG(this, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800483
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800484 const string &sim_identifier = cellular()->sim_identifier();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800485 bool registered =
486 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
487
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700488 // We know a service is activated if |subscription_state_| is
489 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
490 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
491 // fallback on checking for a valid MDN.
492 bool activated =
493 ((subscription_state_ == kSubscriptionStateProvisioned) ||
494 (subscription_state_ == kSubscriptionStateOutOfData)) ||
495 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
496
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800497 if (activated && !sim_identifier.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700498 modem_info()->pending_activation_store()->RemoveEntry(
499 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800500 sim_identifier);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800501
Arman Ugurayefea6e02013-02-21 13:28:04 -0800502 CellularServiceRefPtr service = cellular()->service();
503
504 if (!service.get())
505 return;
506
Ben Chan7ea768e2013-09-20 15:08:40 -0700507 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800508 // Either no service or already activated. Nothing to do.
509 return;
510
Arman Ugurayc7b15602013-02-16 00:56:18 -0800511 // If the ICCID is not available, the following logic can be delayed until it
512 // becomes available.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800513 if (sim_identifier.empty())
Arman Ugurayefea6e02013-02-21 13:28:04 -0800514 return;
515
Arman Uguray41cc6342013-03-29 16:34:39 -0700516 PendingActivationStore::State state =
517 modem_info()->pending_activation_store()->GetActivationState(
518 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800519 sim_identifier);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800520 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700521 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800522 // Always mark the service as activating here, as the ICCID could have
523 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700524 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800525 if (reset_done_) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700526 SLOG(this, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700527 modem_info()->pending_activation_store()->SetActivationState(
528 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800529 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700530 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800531 }
532 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700533 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800534 if (registered) {
535 // Trigger auto connect here.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700536 SLOG(this, 2) << "Modem has been reset at least once, try to "
537 << "autoconnect to force MDN to update.";
Arman Ugurayefea6e02013-02-21 13:28:04 -0800538 service->AutoConnect();
539 }
540 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700541 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800542 // No entry exists for this ICCID. Nothing to do.
543 break;
544 default:
545 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800546 }
547}
548
Ben Chan07193fd2013-07-12 22:10:55 -0700549string CellularCapabilityUniversal::GetMdnForOLP(
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700550 const MobileOperatorInfo *operator_info) const {
Ben Chan07193fd2013-07-12 22:10:55 -0700551 // TODO(benchan): This is ugly. Remove carrier specific code once we move
552 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800553 const string &mdn = cellular()->mdn();
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700554 if (!operator_info->IsMobileNetworkOperatorKnown()) {
555 // Can't make any carrier specific modifications.
556 return mdn;
557 }
558
559 if (operator_info->uuid() == kVzwIdentifier) {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700560 // subscription_state_ is the definitive indicator of whether we need
561 // activation. The OLP expects an all zero MDN in that case.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800562 if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) {
Ben Chan200591a2013-08-07 14:39:04 -0700563 return string(kVzwMdnLength, '0');
564 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800565 if (mdn.length() > kVzwMdnLength) {
566 return mdn.substr(mdn.length() - kVzwMdnLength);
Ben Chan200591a2013-08-07 14:39:04 -0700567 }
Ben Chan07193fd2013-07-12 22:10:55 -0700568 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800569 return mdn;
Ben Chan07193fd2013-07-12 22:10:55 -0700570}
571
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400572void CellularCapabilityUniversal::ReleaseProxies() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700573 SLOG(this, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400574 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400575 modem_proxy_.reset();
576 modem_simple_proxy_.reset();
577 sim_proxy_.reset();
578}
579
Thieu Le63881a72014-07-28 17:28:36 -0700580bool CellularCapabilityUniversal::AreProxiesInitialized() const {
581 return (modem_3gpp_proxy_.get() && modem_proxy_.get() &&
582 modem_simple_proxy_.get() && sim_proxy_.get());
583}
584
Arman Ugurayefea6e02013-02-21 13:28:04 -0800585void CellularCapabilityUniversal::UpdateServiceActivationState() {
586 if (!cellular()->service().get())
587 return;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800588
589 const string &sim_identifier = cellular()->sim_identifier();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700590 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700591 PendingActivationStore::State state =
592 modem_info()->pending_activation_store()->GetActivationState(
593 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800594 sim_identifier);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700595 if ((subscription_state_ == kSubscriptionStateUnknown ||
596 subscription_state_ == kSubscriptionStateUnprovisioned) &&
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800597 !sim_identifier.empty() &&
Thieu Le7de12f52014-07-11 15:30:43 -0700598 state == PendingActivationStore::kStatePending) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700599 activation_state = kActivationStateActivating;
Thieu Le29007182014-08-13 18:02:39 -0700600 } else if (IsServiceActivationRequired()) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700601 activation_state = kActivationStateNotActivated;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700602 } else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700603 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700604
605 // Mark an activated service for auto-connect by default. Since data from
606 // the user profile will be loaded after the call to OnServiceCreated, this
607 // property will be corrected based on the user data at that time.
Thieu Le247416e2014-02-25 18:19:53 -0800608 // NOTE: This function can be called outside the service initialization
609 // path so make sure we don't overwrite the auto-connect setting.
610 if (cellular()->service()->activation_state() != activation_state)
611 cellular()->service()->SetAutoConnect(true);
Arman Uguray6bb252d2013-05-15 14:29:53 -0700612 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800613 cellular()->service()->SetActivationState(activation_state);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800614}
615
616void CellularCapabilityUniversal::OnServiceCreated() {
Thieu Le71f81a62014-07-11 15:17:47 -0700617 cellular()->service()->SetActivationType(CellularService::kActivationTypeOTA);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800618 UpdateServiceActivationState();
Thieu Le398b1da2013-03-11 17:31:10 -0700619
620 // WORKAROUND:
621 // E362 modems on Verizon network does not properly redirect when a SIM
622 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700623 //
624 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
625 // support is ready (crosbug.com/p/20461).
Thieu Le43ce4d42013-10-04 16:08:55 -0700626 cellular()->service()->InitOutOfCreditsDetection(
627 GetOutOfCreditsDetectionType());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700628
629 // Make sure that the network technology is set when the service gets
630 // created, just in case.
631 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400632}
633
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400634// Create the list of APNs to try, in the following order:
635// - last APN that resulted in a successful connection attempt on the
636// current network (if any)
637// - the APN, if any, that was set by the user
638// - the list of APNs found in the mobile broadband provider DB for the
639// home provider associated with the current SIM
640// - as a last resort, attempt to connect with no APN
641void CellularCapabilityUniversal::SetupApnTryList() {
642 apn_try_list_.clear();
643
644 DCHECK(cellular()->service().get());
645 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
646 if (apn_info)
647 apn_try_list_.push_back(*apn_info);
648
649 apn_info = cellular()->service()->GetUserSpecifiedApn();
650 if (apn_info)
651 apn_try_list_.push_back(*apn_info);
652
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800653 apn_try_list_.insert(apn_try_list_.end(),
654 cellular()->apn_list().begin(),
655 cellular()->apn_list().end());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400656}
657
658void CellularCapabilityUniversal::SetupConnectProperties(
659 DBusPropertiesMap *properties) {
660 SetupApnTryList();
661 FillConnectPropertyMap(properties);
662}
663
664void CellularCapabilityUniversal::FillConnectPropertyMap(
665 DBusPropertiesMap *properties) {
666
667 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400668 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400669 kPhoneNumber);
670
Jason Glasgow14521872012-05-07 19:12:15 -0400671 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400672 AllowRoaming());
673
674 if (!apn_try_list_.empty()) {
675 // Leave the APN at the front of the list, so that it can be recorded
676 // if the connect attempt succeeds.
677 Stringmap apn_info = apn_try_list_.front();
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700678 SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400679 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700680 apn_info[kApnProperty].c_str());
681 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400682 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700683 apn_info[kApnUsernameProperty].c_str());
684 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400685 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700686 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400687 }
688}
689
690void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400691 const DBus::Path &path,
692 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700693 SLOG(this, 3) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400694
Jason Glasgow7234ec32012-05-23 16:01:21 -0400695 CellularServiceRefPtr service = cellular()->service();
696 if (!service) {
697 // The service could have been deleted before our Connect() request
698 // completes if the modem was enabled and then quickly disabled.
699 apn_try_list_.clear();
700 } else if (error.IsFailure()) {
701 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400702 // The APN that was just tried (and failed) is still at the
703 // front of the list, about to be removed. If the list is empty
704 // after that, try one last time without an APN. This may succeed
705 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400706 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400707 apn_try_list_.pop_front();
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700708 SLOG(this, 2) << "Connect failed with invalid APN, "
709 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400710 DBusPropertiesMap props;
711 FillConnectPropertyMap(&props);
712 Error error;
713 Connect(props, &error, callback);
714 return;
715 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400716 } else {
717 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400718 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400719 apn_try_list_.clear();
720 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700721 SLOG(this, 2) << "Connected bearer " << path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400722 }
723
724 if (!callback.is_null())
725 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800726
Arman Uguray0a3e2792013-01-17 16:31:50 -0800727 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400728}
729
730bool CellularCapabilityUniversal::AllowRoaming() {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800731 return cellular()->provider_requires_roaming() || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400732}
733
Jason Glasgowef965562012-04-10 16:12:35 -0400734void CellularCapabilityUniversal::GetProperties() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700735 SLOG(this, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400736
Ben Chanc20ed132014-10-16 12:25:03 -0700737 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
Jason Glasgowaf583282012-04-18 15:18:22 -0400738 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
739 cellular()->dbus_owner()));
740 DBusPropertiesMap properties(
741 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
742 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400743
Jason Glasgowaf583282012-04-18 15:18:22 -0400744 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
745 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400746}
747
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700748void CellularCapabilityUniversal::UpdateServiceOLP() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700749 SLOG(this, 3) << __func__;
Ben Chan07193fd2013-07-12 22:10:55 -0700750
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700751 // OLP is based off of the Home Provider.
752 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
Ben Chan07193fd2013-07-12 22:10:55 -0700753 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700754 }
Ben Chan07193fd2013-07-12 22:10:55 -0700755
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700756 const vector<MobileOperatorInfo::OnlinePortal> &olp_list =
757 cellular()->home_provider_info()->olp_list();
758 if (olp_list.empty()) {
Ben Chan6d0d1e72012-11-06 21:19:28 -0800759 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700760 }
Ben Chan6d0d1e72012-11-06 21:19:28 -0800761
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700762 if (olp_list.size() > 1) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700763 SLOG(this, 1) << "Found multiple online portals. Choosing the first.";
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700764 }
765 string post_data = olp_list[0].post_data;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800766 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}",
767 cellular()->sim_identifier());
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800768 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", cellular()->imei());
769 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", cellular()->imsi());
Ben Chan07193fd2013-07-12 22:10:55 -0700770 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700771 GetMdnForOLP(cellular()->home_provider_info()));
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800772 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", cellular()->min());
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700773 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800774}
775
Ben Chan539ab022014-02-03 16:34:57 -0800776void CellularCapabilityUniversal::UpdateActiveBearer() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700777 SLOG(this, 3) << __func__;
Ben Chan539ab022014-02-03 16:34:57 -0800778
Arman Uguray6e5639f2012-11-15 20:30:19 -0800779 // Look for the first active bearer and use its path as the connected
780 // one. Right now, we don't allow more than one active bearer.
Ben Chan539ab022014-02-03 16:34:57 -0800781 active_bearer_.reset();
Ben Chancbef8122014-01-06 17:31:30 -0800782 for (const auto &path : bearer_paths_) {
Ben Chanc20ed132014-10-16 12:25:03 -0700783 std::unique_ptr<CellularBearer> bearer(
Ben Chan539ab022014-02-03 16:34:57 -0800784 new CellularBearer(proxy_factory(), path, cellular()->dbus_service()));
785 // The bearer object may have vanished before ModemManager updates the
786 // 'Bearers' property.
787 if (!bearer->Init())
mukesh agrawal9da07772013-05-15 14:15:17 -0700788 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700789
Ben Chan539ab022014-02-03 16:34:57 -0800790 if (!bearer->connected())
Ben Chan5db19692013-07-09 23:07:03 -0700791 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700792
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700793 SLOG(this, 2) << "Found active bearer \"" << path << "\".";
Ben Chan539ab022014-02-03 16:34:57 -0800794 CHECK(!active_bearer_) << "Found more than one active bearer.";
Ben Chanc20ed132014-10-16 12:25:03 -0700795 active_bearer_ = std::move(bearer);
Arman Uguray6e5639f2012-11-15 20:30:19 -0800796 }
Ben Chan539ab022014-02-03 16:34:57 -0800797
798 if (!active_bearer_)
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700799 SLOG(this, 2) << "No active bearer found.";
Arman Uguray6e5639f2012-11-15 20:30:19 -0800800}
801
Ben Chan15786032012-11-04 21:28:02 -0800802bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800803 const string &sim_identifier = cellular()->sim_identifier();
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700804 // subscription_state_ is the definitive answer. If that does not work,
805 // fallback on MDN based logic.
806 if (subscription_state_ == kSubscriptionStateProvisioned ||
807 subscription_state_ == kSubscriptionStateOutOfData)
808 return false;
809
810 // We are in the process of activating, ignore all other clues from the
811 // network and use our own knowledge about the activation state.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800812 if (!sim_identifier.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700813 modem_info()->pending_activation_store()->GetActivationState(
814 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800815 sim_identifier) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800816 return false;
817
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700818 // Network notification that the service needs to be activated.
819 if (subscription_state_ == kSubscriptionStateUnprovisioned)
820 return true;
821
Ben Chan15786032012-11-04 21:28:02 -0800822 // If there is no online payment portal information, it's safer to assume
823 // the service does not require activation.
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700824 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
825 cellular()->home_provider_info()->olp_list().empty()) {
Ben Chan15786032012-11-04 21:28:02 -0800826 return false;
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700827 }
Ben Chan15786032012-11-04 21:28:02 -0800828
Ben Chan200591a2013-08-07 14:39:04 -0700829 // If the MDN is invalid (i.e. empty or contains only zeros), the service
830 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -0800831 return !IsMdnValid();
832}
833
834bool CellularCapabilityUniversal::IsMdnValid() const {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800835 const string &mdn = cellular()->mdn();
836 // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
837 for (size_t i = 0; i < mdn.size(); ++i) {
838 if (mdn[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -0800839 return true;
Ben Chan15786032012-11-04 21:28:02 -0800840 }
Arman Ugurayc7b15602013-02-16 00:56:18 -0800841 return false;
Ben Chan15786032012-11-04 21:28:02 -0800842}
843
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400844// always called from an async context
845void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700846 SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network()
847 << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400848 CHECK(!callback.is_null());
849 Error error;
850 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
851 weak_ptr_factory_.GetWeakPtr(), callback);
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800852 modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
853 kTimeoutRegister);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400854 if (error.IsFailure())
855 callback.Run(error);
856}
857
858void CellularCapabilityUniversal::RegisterOnNetwork(
859 const string &network_id,
860 Error *error,
861 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700862 SLOG(this, 3) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400863 CHECK(error);
864 desired_network_ = network_id;
865 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
866 weak_ptr_factory_.GetWeakPtr(), callback);
867 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
868}
869
870void CellularCapabilityUniversal::OnRegisterReply(
871 const ResultCallback &callback,
872 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700873 SLOG(this, 3) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400874
875 if (error.IsSuccess()) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800876 cellular()->set_selected_network(desired_network_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400877 desired_network_.clear();
878 callback.Run(error);
879 return;
880 }
881 // If registration on the desired network failed,
882 // try to register on the home network.
883 if (!desired_network_.empty()) {
884 desired_network_.clear();
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800885 cellular()->set_selected_network("");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400886 LOG(INFO) << "Couldn't register on selected network, trying home network";
887 Register(callback);
888 return;
889 }
890 callback.Run(error);
891}
892
Ben Chan31ce5642013-11-14 13:37:40 -0800893bool CellularCapabilityUniversal::IsRegistered() const {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700894 return IsRegisteredState(registration_state_);
895}
896
897bool CellularCapabilityUniversal::IsRegisteredState(
898 MMModem3gppRegistrationState state) {
899 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
900 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400901}
902
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400903void CellularCapabilityUniversal::SetUnregistered(bool searching) {
904 // If we're already in some non-registered state, don't override that
905 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
906 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
907 registration_state_ =
908 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
909 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
910 }
911}
912
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400913void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400914 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400915 Error *error, const ResultCallback &callback) {
916 CHECK(error);
917 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
918}
919
920void CellularCapabilityUniversal::EnterPIN(const string &pin,
921 Error *error,
922 const ResultCallback &callback) {
923 CHECK(error);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700924 SLOG(this, 3) << __func__;
Arman Ugurayf6366ac2013-06-12 16:02:28 -0700925 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400926}
927
928void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
929 const string &pin,
930 Error *error,
931 const ResultCallback &callback) {
932 CHECK(error);
933 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
934}
935
936void CellularCapabilityUniversal::ChangePIN(
937 const string &old_pin, const string &new_pin,
938 Error *error, const ResultCallback &callback) {
939 CHECK(error);
940 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
941}
942
Ben Chan5d0d32c2013-01-08 02:05:29 -0800943void CellularCapabilityUniversal::Reset(Error *error,
944 const ResultCallback &callback) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700945 SLOG(this, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -0800946 CHECK(error);
947 if (resetting_) {
948 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
949 return;
950 }
951 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
952 weak_ptr_factory_.GetWeakPtr(), callback);
953 modem_proxy_->Reset(error, cb, kTimeoutReset);
954 if (!error->IsFailure()) {
955 resetting_ = true;
956 }
957}
958
959void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
960 const Error &error) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700961 SLOG(this, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -0800962 resetting_ = false;
963 if (!callback.is_null())
964 callback.Run(error);
965}
966
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -0800967void CellularCapabilityUniversal::Scan(
968 Error *error,
969 const ResultStringmapsCallback &callback) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400970 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
971 weak_ptr_factory_.GetWeakPtr(), callback);
972 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
973}
974
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -0800975void CellularCapabilityUniversal::OnScanReply(
976 const ResultStringmapsCallback &callback,
977 const ScanResults &results,
978 const Error &error) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800979 Stringmaps found_networks;
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -0800980 for (const auto &result : results)
981 found_networks.push_back(ParseScanResult(result));
982 callback.Run(found_networks, error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400983}
984
985Stringmap CellularCapabilityUniversal::ParseScanResult(
986 const ScanResult &result) {
987
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400988 /* ScanResults contain the following keys:
989
990 "status"
991 A MMModem3gppNetworkAvailability value representing network
992 availability status, given as an unsigned integer (signature "u").
993 This key will always be present.
994
995 "operator-long"
996 Long-format name of operator, given as a string value (signature
997 "s"). If the name is unknown, this field should not be present.
998
999 "operator-short"
1000 Short-format name of operator, given as a string value
1001 (signature "s"). If the name is unknown, this field should not
1002 be present.
1003
1004 "operator-code"
1005 Mobile code of the operator, given as a string value (signature
1006 "s"). Returned in the format "MCCMNC", where MCC is the
1007 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1008 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1009
1010 "access-technology"
1011 A MMModemAccessTechnology value representing the generic access
1012 technology used by this mobile network, given as an unsigned
1013 integer (signature "u").
1014 */
1015 Stringmap parsed;
1016
Ben Chan7fab8972014-08-10 17:14:46 -07001017 uint32_t status;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001018 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1019 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1020 static const char * const kStatusString[] = {
1021 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1022 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1023 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1024 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1025 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001026 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001027 }
1028
Ben Chan7fab8972014-08-10 17:14:46 -07001029 uint32_t tech; // MMModemAccessTechnology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001030 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1031 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001032 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001033 }
1034
1035 string operator_long, operator_short, operator_code;
1036 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001037 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001038 if (DBusProperties::GetString(result, kOperatorShortProperty,
1039 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001040 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001041 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001042 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001043
1044 // If the long name is not available but the network ID is, look up the long
1045 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001046 if ((!ContainsKey(parsed, kLongNameProperty) ||
1047 parsed[kLongNameProperty].empty()) &&
1048 ContainsKey(parsed, kNetworkIdProperty)) {
Prathmesh Prabhuafe63662014-05-20 11:03:58 -07001049 mobile_operator_info_->Reset();
1050 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
1051 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
1052 !mobile_operator_info_->operator_name().empty()) {
1053 parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001054 }
1055 }
1056 return parsed;
1057}
1058
Ben Chan539ab022014-02-03 16:34:57 -08001059CellularBearer *CellularCapabilityUniversal::GetActiveBearer() const {
1060 return active_bearer_.get();
1061}
1062
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001063string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Ben Chan3dddd042014-10-19 14:08:10 -07001064 // If we know that the modem is an E362 modem supported by the Novatel LTE
1065 // plugin, return LTE here to make sure that Chrome sees LTE as the network
1066 // technology even if the actual technology is unknown.
1067 //
1068 // This hack will cause the UI to display LTE even if the modem doesn't
1069 // support it at a given time. This might be problematic if we ever want to
1070 // support switching between access technologies (e.g. falling back to 3G
1071 // when LTE is not available).
1072 if (cellular()->mm_plugin() == kNovatelLTEMMPlugin)
Ben Chan7ea768e2013-09-20 15:08:40 -07001073 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001074
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001075 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001076 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001077 return AccessTechnologyToString(access_technologies_);
1078}
1079
1080string CellularCapabilityUniversal::GetRoamingStateString() const {
1081 switch (registration_state_) {
1082 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001083 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001084 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001085 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001086 default:
1087 break;
1088 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001089 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001090}
1091
Arman Uguray5d9a8522013-09-10 17:43:13 -07001092// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001093void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001094 // ModemManager always returns the cached value, so there is no need to
1095 // trigger an update here. The true value is updated through a property
1096 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001097}
1098
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001099string CellularCapabilityUniversal::GetTypeString() const {
1100 return AccessTechnologyToTechnologyFamily(access_technologies_);
1101}
1102
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001103void CellularCapabilityUniversal::OnModemPropertiesChanged(
1104 const DBusPropertiesMap &properties,
1105 const vector<string> &/* invalidated_properties */) {
Ben Chancbef8122014-01-06 17:31:30 -08001106
1107 // Update the bearers property before the modem state property as
Ben Chan539ab022014-02-03 16:34:57 -08001108 // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
1109 // property.
Ben Chancbef8122014-01-06 17:31:30 -08001110 RpcIdentifiers bearers;
1111 if (DBusProperties::GetRpcIdentifiers(properties, MM_MODEM_PROPERTY_BEARERS,
1112 &bearers)) {
1113 OnBearersChanged(bearers);
1114 }
1115
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001116 // This solves a bootstrapping problem: If the modem is not yet
1117 // enabled, there are no proxy objects associated with the capability
1118 // object, so modem signals like StateChanged aren't seen. By monitoring
1119 // changes to the State property via the ModemManager, we're able to
1120 // get the initialization process started, which will result in the
1121 // creation of the proxy objects.
1122 //
1123 // The first time we see the change to State (when the modem state
1124 // is Unknown), we simply update the state, and rely on the Manager to
1125 // enable the device when it is registered with the Manager. On subsequent
1126 // changes to State, we need to explicitly enable the device ourselves.
Ben Chan7fab8972014-08-10 17:14:46 -07001127 int32_t istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001128 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001129 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001130 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001131 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001132 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001133 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001134 MM_MODEM_PROPERTY_SIM, &object_path_value))
1135 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001136
1137 DBusPropertiesMap::const_iterator it =
1138 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1139 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001140 const vector<uint32_t> &supported_capabilities = it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001141 OnSupportedCapabilitesChanged(supported_capabilities);
1142 }
1143
Ben Chan7fab8972014-08-10 17:14:46 -07001144 uint32_t uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001145 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001146 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1147 &uint_value))
1148 OnModemCurrentCapabilitiesChanged(uint_value);
1149 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1150 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001151 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001152 if (DBusProperties::GetString(properties,
1153 MM_MODEM_PROPERTY_MANUFACTURER,
1154 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001155 cellular()->set_manufacturer(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001156 if (DBusProperties::GetString(properties,
1157 MM_MODEM_PROPERTY_MODEL,
1158 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001159 cellular()->set_model_id(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001160 if (DBusProperties::GetString(properties,
Thieu Lec466ccb2014-06-23 15:24:56 -07001161 MM_MODEM_PROPERTY_PLUGIN,
1162 &string_value))
1163 cellular()->set_mm_plugin(string_value);
1164 if (DBusProperties::GetString(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001165 MM_MODEM_PROPERTY_REVISION,
1166 &string_value))
1167 OnModemRevisionChanged(string_value);
1168 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1169 // not needed: MM_MODEM_PROPERTY_DEVICE
1170 // not needed: MM_MODEM_PROPERTY_DRIVER
1171 // not needed: MM_MODEM_PROPERTY_PLUGIN
1172 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001173
Jason Glasgowaf583282012-04-18 15:18:22 -04001174 // Unlock required and SimLock
Ben Chan7fab8972014-08-10 17:14:46 -07001175 uint32_t unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001176 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001177 if (DBusProperties::GetUint32(properties,
1178 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001179 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001180 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001181 lock_status_changed = true;
1182 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001183
1184 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001185 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001186 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001187 LockRetryData lock_retries = it->second.operator LockRetryData();
1188 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001189 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001190 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001191
Arman Ugurayea5ff272013-06-25 10:28:02 -07001192 if (lock_status_changed)
1193 OnSimLockStatusChanged();
1194
Jason Glasgowaf583282012-04-18 15:18:22 -04001195 if (DBusProperties::GetUint32(properties,
1196 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1197 &uint_value))
1198 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001199
Jason Glasgowaf583282012-04-18 15:18:22 -04001200 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1201 if (it != properties.end()) {
1202 DBus::Struct<unsigned int, bool> quality = it->second;
1203 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001204 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001205 vector<string> numbers;
1206 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1207 &numbers)) {
1208 string mdn;
1209 if (numbers.size() > 0)
1210 mdn = numbers[0];
1211 OnMdnChanged(mdn);
1212 }
Ben Chan74924d82013-06-15 17:52:55 -07001213
1214 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1215 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001216 const vector<DBus::Struct<uint32_t, uint32_t>> &mm_supported_modes =
1217 it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001218 vector<ModemModes> supported_modes;
1219 for (const auto &modes : mm_supported_modes) {
1220 supported_modes.push_back(
1221 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1222 }
1223 OnSupportedModesChanged(supported_modes);
1224 }
1225
1226 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1227 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001228 const DBus::Struct<uint32_t, uint32_t> &current_modes = it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001229 OnCurrentModesChanged(ModemModes(
1230 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1231 }
1232
Jason Glasgowaf583282012-04-18 15:18:22 -04001233 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1234 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001235}
1236
1237void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1238 const string &interface,
1239 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001240 const vector<string> &invalidated_properties) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001241 SLOG(this, 3) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001242 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001243 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001244 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001245 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1246 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001247 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001248 if (interface == MM_DBUS_INTERFACE_SIM) {
1249 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001250 }
1251}
1252
Jason Glasgow14521872012-05-07 19:12:15 -04001253bool CellularCapabilityUniversal::RetriableConnectError(
1254 const Error &error) const {
1255 if (error.type() == Error::kInvalidApn)
1256 return true;
1257
Ben Chan3dddd042014-10-19 14:08:10 -07001258 // ModemManager does not ever return kInvalidApn for an E362 modem (with
1259 // firmware version 1.41) supported by the Novatel LTE plugin.
1260 if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) &&
1261 (error.type() == Error::kOperationFailed)) {
Jason Glasgow14521872012-05-07 19:12:15 -04001262 return true;
Ben Chan3dddd042014-10-19 14:08:10 -07001263 }
Jason Glasgow14521872012-05-07 19:12:15 -04001264 return false;
1265}
1266
Ben Chan7fab8972014-08-10 17:14:46 -07001267void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001268 // TODO(petkov): Implement this.
1269 NOTIMPLEMENTED();
1270}
1271
Arman Uguray6552f8c2013-02-12 15:33:18 -08001272bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1273 return !sim_path.empty() && sim_path != kRootPath;
1274}
1275
Ben Chand7592522013-02-13 16:02:01 -08001276string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1277 string normalized_mdn;
1278 for (size_t i = 0; i < mdn.size(); ++i) {
1279 if (IsAsciiDigit(mdn[i]))
1280 normalized_mdn += mdn[i];
1281 }
1282 return normalized_mdn;
1283}
1284
Jason Glasgowaf583282012-04-18 15:18:22 -04001285void CellularCapabilityUniversal::OnSimPathChanged(
1286 const string &sim_path) {
1287 if (sim_path == sim_path_)
1288 return;
1289
Ben Chanea18c6c2014-09-30 13:08:26 -07001290 mm1::SimProxyInterface *proxy = nullptr;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001291 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001292 proxy = proxy_factory()->CreateSimProxy(sim_path,
1293 cellular()->dbus_owner());
1294 sim_path_ = sim_path;
1295 sim_proxy_.reset(proxy);
1296
Arman Uguray6552f8c2013-02-12 15:33:18 -08001297 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001298 // Clear all data about the sim
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001299 cellular()->set_imsi("");
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001300 spn_ = "";
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001301 cellular()->set_sim_present(false);
Jason Glasgowaf583282012-04-18 15:18:22 -04001302 OnSimIdentifierChanged("");
1303 OnOperatorIdChanged("");
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001304 cellular()->home_provider_info()->Reset();
Jason Glasgowaf583282012-04-18 15:18:22 -04001305 } else {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001306 cellular()->set_sim_present(true);
Ben Chanc20ed132014-10-16 12:25:03 -07001307 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
Jason Glasgowaf583282012-04-18 15:18:22 -04001308 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1309 cellular()->dbus_owner()));
1310 // TODO(jglasgow): convert to async interface
1311 DBusPropertiesMap properties(
1312 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1313 OnSimPropertiesChanged(properties, vector<string>());
1314 }
1315}
1316
Ben Chan74924d82013-06-15 17:52:55 -07001317void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001318 const vector<uint32_t> &supported_capabilities) {
Ben Chan74924d82013-06-15 17:52:55 -07001319 supported_capabilities_ = supported_capabilities;
1320}
1321
Jason Glasgowaf583282012-04-18 15:18:22 -04001322void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001323 uint32_t current_capabilities) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001324 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001325
1326 // Only allow network scan when the modem's current capabilities support
1327 // GSM/UMTS.
1328 //
1329 // TODO(benchan): We should consider having the modem plugins in ModemManager
1330 // reporting whether network scan is supported.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001331 cellular()->set_scanning_supported(
1332 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
Jason Glasgowaf583282012-04-18 15:18:22 -04001333}
1334
1335void CellularCapabilityUniversal::OnMdnChanged(
1336 const string &mdn) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001337 cellular()->set_mdn(NormalizeMdn(mdn));
Arman Uguray0a3e2792013-01-17 16:31:50 -08001338 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001339}
1340
Jason Glasgowaf583282012-04-18 15:18:22 -04001341void CellularCapabilityUniversal::OnModemRevisionChanged(
1342 const string &revision) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001343 cellular()->set_firmware_revision(revision);
Jason Glasgowaf583282012-04-18 15:18:22 -04001344}
1345
1346void CellularCapabilityUniversal::OnModemStateChanged(
1347 Cellular::ModemState state) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001348 SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001349
Ben Chan539ab022014-02-03 16:34:57 -08001350 if (state == Cellular::kModemStateConnected) {
1351 // This assumes that ModemManager updates the Bearers list and the Bearer
1352 // properties before changing Modem state to Connected.
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001353 SLOG(this, 2) << "Update active bearer.";
Ben Chan539ab022014-02-03 16:34:57 -08001354 UpdateActiveBearer();
1355 }
1356
Arman Uguray1ee93912013-09-24 21:24:10 -07001357 cellular()->OnModemStateChanged(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001358 // TODO(armansito): Move the deferred enable logic to Cellular
1359 // (See crbug.com/279499).
1360 if (!deferred_enable_modem_callback_.is_null() &&
1361 state == Cellular::kModemStateDisabled) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001362 SLOG(this, 2) << "Enabling modem after deferring.";
Arman Uguray1ee93912013-09-24 21:24:10 -07001363 deferred_enable_modem_callback_.Run();
1364 deferred_enable_modem_callback_.Reset();
mukesh agrawal510cc802013-08-15 18:31:42 -07001365 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001366}
1367
1368void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001369 uint32_t access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001370 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001371 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001372 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001373 const string new_type_string(GetTypeString());
1374 if (new_type_string != old_type_string) {
1375 // TODO(jglasgow): address layering violation of emitting change
1376 // signal here for a property owned by Cellular.
1377 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001378 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001379 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001380 if (cellular()->service().get()) {
1381 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1382 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001383 }
1384}
1385
Ben Chan74924d82013-06-15 17:52:55 -07001386void CellularCapabilityUniversal::OnSupportedModesChanged(
1387 const vector<ModemModes> &supported_modes) {
1388 supported_modes_ = supported_modes;
1389}
1390
1391void CellularCapabilityUniversal::OnCurrentModesChanged(
1392 const ModemModes &current_modes) {
1393 current_modes_ = current_modes;
1394}
1395
Ben Chancbef8122014-01-06 17:31:30 -08001396void CellularCapabilityUniversal::OnBearersChanged(
1397 const RpcIdentifiers &bearers) {
1398 bearer_paths_ = bearers;
1399}
1400
Jason Glasgowaf583282012-04-18 15:18:22 -04001401void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001402 const LockRetryData &lock_retries) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001403 SLOG(this, 3) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001404
Arman Ugurayea5ff272013-06-25 10:28:02 -07001405 // Look for the retries left for the current lock. Try the obtain the count
1406 // that matches the current count. If no count for the current lock is
1407 // available, report the first one in the dictionary.
1408 LockRetryData::const_iterator it =
1409 lock_retries.find(sim_lock_status_.lock_type);
1410 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001411 it = lock_retries.begin();
1412 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001413 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001414 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001415 // Unknown, use 999
1416 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001417}
1418
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001419void CellularCapabilityUniversal::OnLockTypeChanged(
1420 MMModemLock lock_type) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001421 SLOG(this, 3) << __func__ << ": " << lock_type;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001422 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001423
1424 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1425 // This is because the corresponding property 'EnabledFacilityLocks' is on
1426 // the 3GPP interface and the 3GPP interface is not available while the Modem
1427 // is in the 'LOCKED' state.
1428 if (lock_type != MM_MODEM_LOCK_NONE &&
1429 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1430 !sim_lock_status_.enabled)
1431 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001432}
1433
Jason Glasgowaf583282012-04-18 15:18:22 -04001434void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001435 SLOG(this, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001436 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chanea18c6c2014-09-30 13:08:26 -07001437 kSIMLockStatusProperty, SimLockStatusToProperty(nullptr));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001438
1439 // If the SIM is currently unlocked, assume that we need to refresh
1440 // carrier information, since a locked SIM prevents shill from obtaining
1441 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001442 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001443 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1444 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Ben Chanc20ed132014-10-16 12:25:03 -07001445 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
Arman Ugurayab9364e2012-12-19 20:45:25 -08001446 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1447 cellular()->dbus_owner()));
1448 DBusPropertiesMap properties(
1449 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1450 OnSimPropertiesChanged(properties, vector<string>());
1451 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001452}
1453
1454void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1455 const DBusPropertiesMap &properties,
1456 const vector<string> &/* invalidated_properties */) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001457 SLOG(this, 3) << __func__;
Ben Chan7fab8972014-08-10 17:14:46 -07001458 uint32_t uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001459 string imei;
1460 if (DBusProperties::GetString(properties,
1461 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1462 &imei))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001463 cellular()->set_imei(imei);
Jason Glasgowaf583282012-04-18 15:18:22 -04001464
1465 // Handle registration state changes as a single change
Roshan Pius4aef4062014-10-30 15:38:02 -07001466 Stringmap::const_iterator it;
1467 string operator_code;
1468 string operator_name;
1469 it = serving_operator_.find(kOperatorCodeKey);
1470 if (it != serving_operator_.end())
1471 operator_code = it->second;
1472 it = serving_operator_.find(kOperatorNameKey);
1473 if (it != serving_operator_.end())
1474 operator_name = it->second;
1475
Jason Glasgowaf583282012-04-18 15:18:22 -04001476 MMModem3gppRegistrationState state = registration_state_;
1477 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001478 if (DBusProperties::GetUint32(properties,
1479 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1480 &uint_value)) {
1481 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1482 registration_changed = true;
1483 }
1484 if (DBusProperties::GetString(properties,
1485 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1486 &operator_code))
1487 registration_changed = true;
1488 if (DBusProperties::GetString(properties,
1489 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1490 &operator_name))
1491 registration_changed = true;
1492 if (registration_changed)
1493 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001494 if (DBusProperties::GetUint32(properties,
1495 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1496 &uint_value))
1497 On3GPPSubscriptionStateChanged(
1498 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001499
Ben Chan7fab8972014-08-10 17:14:46 -07001500 uint32_t subscription_state;
Thieu Le43ce4d42013-10-04 16:08:55 -07001501 CellularServiceRefPtr service = cellular()->service();
1502 if (service.get() &&
1503 DBusProperties::GetUint32(properties,
1504 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1505 &subscription_state)) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001506 SLOG(this, 3) << __func__ << ": Subscription state = "
1507 << subscription_state;
Thieu Le43ce4d42013-10-04 16:08:55 -07001508 service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1509 subscription_state);
1510 }
1511
Ben Chan7fab8972014-08-10 17:14:46 -07001512 uint32_t locks = 0;
Jason Glasgowaf583282012-04-18 15:18:22 -04001513 if (DBusProperties::GetUint32(
1514 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1515 &locks))
1516 OnFacilityLocksChanged(locks);
1517}
1518
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001519void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1520 MMModem3gppRegistrationState state,
1521 const string &operator_code,
1522 const string &operator_name) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001523 SLOG(this, 3) << __func__ << ": regstate=" << state
1524 << ", opercode=" << operator_code
1525 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001526
1527 // While the modem is connected, if the state changed from a registered state
1528 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001529 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1530 IsRegistered() && !IsRegisteredState(state)) {
1531 if (!registration_dropped_update_callback_.IsCancelled()) {
1532 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1533 << "Ignoring earlier notifications.";
1534 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001535 } else {
1536 // This is not a repeated post. So, count this instance of delayed drop
1537 // posted.
1538 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001539 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001540 SLOG(this, 2) << "Posted deferred registration state update";
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001541 registration_dropped_update_callback_.Reset(
1542 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1543 weak_ptr_factory_.GetWeakPtr(),
1544 state,
1545 operator_code,
1546 operator_name));
1547 cellular()->dispatcher()->PostDelayedTask(
1548 registration_dropped_update_callback_.callback(),
1549 registration_dropped_update_timeout_milliseconds_);
1550 } else {
1551 if (!registration_dropped_update_callback_.IsCancelled()) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001552 SLOG(this, 2) << "Cancelled a deferred registration state update";
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001553 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001554 // If we cancelled the callback here, it means we had flaky network for a
1555 // small duration.
1556 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001557 }
1558 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1559 }
1560}
1561
1562void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1563 MMModem3gppRegistrationState updated_state,
1564 string updated_operator_code,
1565 string updated_operator_name) {
1566 // A finished callback does not qualify as a canceled callback.
1567 // We test for a canceled callback to check for outstanding callbacks.
1568 // So, explicitly cancel the callback here.
1569 registration_dropped_update_callback_.Cancel();
1570
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001571 SLOG(this, 3) << __func__ << ": regstate=" << updated_state
1572 << ", opercode=" << updated_operator_code
1573 << ", opername=" << updated_operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001574
1575 registration_state_ = updated_state;
Roshan Pius4aef4062014-10-30 15:38:02 -07001576 serving_operator_[kOperatorCodeKey] = updated_operator_code;
1577 serving_operator_[kOperatorNameKey] = updated_operator_name;
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001578 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1579 cellular()->serving_operator_info()->UpdateOperatorName(
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001580 updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001581
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001582 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001583
Arman Ugurayc7b15602013-02-16 00:56:18 -08001584 // If the modem registered with the network and the current ICCID is pending
1585 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001586 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001587}
1588
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001589void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1590 MMModem3gppSubscriptionState updated_state) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001591 SLOG(this, 3) << __func__ << ": Updated subscription state = "
1592 << updated_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001593
1594 // A one-to-one enum mapping.
Thieu Le314581f2014-02-19 13:02:47 -08001595 SubscriptionState new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001596 switch (updated_state) {
1597 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
Thieu Le314581f2014-02-19 13:02:47 -08001598 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001599 break;
1600 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001601 new_subscription_state = kSubscriptionStateProvisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001602 break;
1603 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001604 new_subscription_state = kSubscriptionStateUnprovisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001605 break;
1606 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
Thieu Le314581f2014-02-19 13:02:47 -08001607 new_subscription_state = kSubscriptionStateOutOfData;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001608 break;
1609 default:
1610 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1611 << updated_state;
Thieu Le314581f2014-02-19 13:02:47 -08001612 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001613 return;
1614 }
Thieu Le314581f2014-02-19 13:02:47 -08001615 if (new_subscription_state == subscription_state_)
1616 return;
1617
1618 subscription_state_ = new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001619
1620 UpdateServiceActivationState();
1621 UpdatePendingActivationState();
1622}
1623
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001624void CellularCapabilityUniversal::OnModemStateChangedSignal(
Ben Chan7fab8972014-08-10 17:14:46 -07001625 int32_t old_state, int32_t new_state, uint32_t reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07001626 Cellular::ModemState old_modem_state =
1627 static_cast<Cellular::ModemState>(old_state);
1628 Cellular::ModemState new_modem_state =
1629 static_cast<Cellular::ModemState>(new_state);
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001630 SLOG(this, 3) << __func__ << "("
1631 << Cellular::GetModemStateString(old_modem_state)
1632 << ", "
1633 << Cellular::GetModemStateString(new_modem_state)
1634 << ", "
1635 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001636}
1637
Ben Chan7fab8972014-08-10 17:14:46 -07001638void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001639 cellular()->HandleNewSignalQuality(quality);
1640}
1641
Ben Chan7fab8972014-08-10 17:14:46 -07001642void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001643 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1644 if (sim_lock_status_.enabled != sim_enabled) {
1645 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04001646 OnSimLockStatusChanged();
1647 }
1648}
Jason Glasgowef965562012-04-10 16:12:35 -04001649
Jason Glasgowaf583282012-04-18 15:18:22 -04001650void CellularCapabilityUniversal::OnSimPropertiesChanged(
1651 const DBusPropertiesMap &props,
1652 const vector<string> &/* invalidated_properties */) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001653 SLOG(this, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001654 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001655 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1656 OnSimIdentifierChanged(value);
1657 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1658 &value))
1659 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001660 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1661 OnSpnChanged(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001662 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001663 cellular()->set_imsi(value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001664 cellular()->home_provider_info()->UpdateIMSI(value);
Prathmesh Prabhuc93b6bc2014-07-28 15:20:11 -07001665 // We do not obtain IMSI OTA right now. Provide the value from the SIM to
1666 // serving operator as well, to aid in MVNO identification.
1667 cellular()->serving_operator_info()->UpdateIMSI(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001668 }
Arman Ugurayd73783f2013-01-31 16:11:21 -08001669}
Jason Glasgowaf583282012-04-18 15:18:22 -04001670
Arman Ugurayd73783f2013-01-31 16:11:21 -08001671void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1672 spn_ = spn;
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001673 cellular()->home_provider_info()->UpdateOperatorName(spn);
Jason Glasgowaf583282012-04-18 15:18:22 -04001674}
1675
1676void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -08001677 cellular()->set_sim_identifier(id);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001678 cellular()->home_provider_info()->UpdateICCID(id);
Prathmesh Prabhuc93b6bc2014-07-28 15:20:11 -07001679 // Provide ICCID to serving operator as well to aid in MVNO identification.
1680 cellular()->serving_operator_info()->UpdateICCID(id);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001681 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001682}
1683
1684void CellularCapabilityUniversal::OnOperatorIdChanged(
1685 const string &operator_id) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -07001686 SLOG(this, 2) << "Operator ID = '" << operator_id << "'";
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001687 cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
Jason Glasgowaf583282012-04-18 15:18:22 -04001688}
1689
Thieu Le43ce4d42013-10-04 16:08:55 -07001690OutOfCreditsDetector::OOCType
1691CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
Thieu Lec466ccb2014-06-23 15:24:56 -07001692 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le43ce4d42013-10-04 16:08:55 -07001693 return OutOfCreditsDetector::OOCTypeSubscriptionState;
Thieu Le43ce4d42013-10-04 16:08:55 -07001694 } else {
1695 return OutOfCreditsDetector::OOCTypeNone;
1696 }
1697}
1698
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001699} // namespace shill