blob: 6726bd845b3e932a0d244b601e115b221e51ea27 [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/stringprintf.h>
10#include <base/strings/string_util.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
39// static
Jason Glasgow14521872012-05-07 19:12:15 -040040const char CellularCapabilityUniversal::kConnectPin[] = "pin";
41const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
Jason Glasgow14521872012-05-07 19:12:15 -040042const char CellularCapabilityUniversal::kConnectApn[] = "apn";
43const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
44const char CellularCapabilityUniversal::kConnectUser[] = "user";
45const char CellularCapabilityUniversal::kConnectPassword[] = "password";
46const char CellularCapabilityUniversal::kConnectNumber[] = "number";
47const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
48 "allow-roaming";
49const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Arman Uguraya14941d2013-04-12 16:58:26 -070050const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070051CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
52 20000;
Arman Ugurayf6366ac2013-06-12 16:02:28 -070053const int64 CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
Arman Uguraya14941d2013-04-12 16:58:26 -070054const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070055CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
56 15000;
Arman Uguray6552f8c2013-02-12 15:33:18 -080057const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040058const char CellularCapabilityUniversal::kStatusProperty[] = "status";
59const char CellularCapabilityUniversal::kOperatorLongProperty[] =
60 "operator-long";
61const char CellularCapabilityUniversal::kOperatorShortProperty[] =
62 "operator-short";
63const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
64 "operator-code";
65const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
66 "access-technology";
Thieu Lec466ccb2014-06-23 15:24:56 -070067const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE";
Jason Glasgow14521872012-05-07 19:12:15 -040068const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080069const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
70 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040071
Ben Chan07193fd2013-07-12 22:10:55 -070072namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040073
Ben Chan07193fd2013-07-12 22:10:55 -070074const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040075
Prathmesh Prabhu3b66bb92014-05-22 11:15:25 -070076// This identifier is specified in the additional_providers.prototxt file.
Prathmesh Prabhu5089a6e2014-05-07 20:49:16 -070077const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751";
Ben Chan07193fd2013-07-12 22:10:55 -070078const size_t kVzwMdnLength = 10;
79
80string AccessTechnologyToString(uint32 access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040081 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
Ben Chan7ea768e2013-09-20 15:08:40 -070082 return kNetworkTechnologyLte;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040083 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
84 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
85 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
Ben Chan7ea768e2013-09-20 15:08:40 -070086 return kNetworkTechnologyEvdo;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040087 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
Ben Chan7ea768e2013-09-20 15:08:40 -070088 return kNetworkTechnology1Xrtt;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040089 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
Ben Chan7ea768e2013-09-20 15:08:40 -070090 return kNetworkTechnologyHspaPlus;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040091 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
92 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
93 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
Ben Chan7ea768e2013-09-20 15:08:40 -070094 return kNetworkTechnologyHspa;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040095 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
Ben Chan7ea768e2013-09-20 15:08:40 -070096 return kNetworkTechnologyUmts;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040097 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
Ben Chan7ea768e2013-09-20 15:08:40 -070098 return kNetworkTechnologyEdge;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040099 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700100 return kNetworkTechnologyGprs;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400101 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
102 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700103 return kNetworkTechnologyGsm;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400104 return "";
105}
106
Ben Chan07193fd2013-07-12 22:10:55 -0700107string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400108 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
109 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
110 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
111 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
112 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
113 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
114 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
115 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
116 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
117 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700118 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400119 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800120 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
121 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400122 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700123 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400124 return "";
125}
126
Ben Chan07193fd2013-07-12 22:10:55 -0700127} // namespace
128
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400129CellularCapabilityUniversal::CellularCapabilityUniversal(
130 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800131 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700132 ModemInfo *modem_info)
133 : CellularCapability(cellular, proxy_factory, modem_info),
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700134 mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(),
135 "ParseScanResult")),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400136 weak_ptr_factory_(this),
137 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200138 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400139 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800140 resetting_(false),
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700141 subscription_state_(kSubscriptionStateUnknown),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800142 reset_done_(false),
Arman Uguraya14941d2013-04-12 16:58:26 -0700143 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700144 kActivationRegistrationTimeoutMilliseconds),
145 registration_dropped_update_timeout_milliseconds_(
146 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700147 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700148 mobile_operator_info_->Init();
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700149 HelpRegisterConstDerivedKeyValueStore(
Ben Chan7ea768e2013-09-20 15:08:40 -0700150 kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700151 &CellularCapabilityUniversal::SimLockStatusToProperty);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400152}
153
Ben Chanf98f00e2014-02-05 14:48:43 -0800154CellularCapabilityUniversal::~CellularCapabilityUniversal() {}
155
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400156KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
157 Error */*error*/) {
158 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700159 string lock_type;
160 switch (sim_lock_status_.lock_type) {
161 case MM_MODEM_LOCK_SIM_PIN:
162 lock_type = "sim-pin";
163 break;
164 case MM_MODEM_LOCK_SIM_PUK:
165 lock_type = "sim-puk";
166 break;
167 default:
168 lock_type = "";
169 break;
170 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700171 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
172 status.SetString(kSIMLockTypeProperty, lock_type);
173 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400174 return status;
175}
176
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700177void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400178 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700179 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400180 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
181 name,
182 KeyValueStoreAccessor(
183 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700184 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400185}
186
187void CellularCapabilityUniversal::InitProxies() {
188 modem_3gpp_proxy_.reset(
189 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
190 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400191 modem_proxy_.reset(
192 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
193 cellular()->dbus_owner()));
194 modem_simple_proxy_.reset(
195 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
196 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800197
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400198 modem_proxy_->set_state_changed_callback(
199 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
200 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400201 // Do not create a SIM proxy until the device is enabled because we
202 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400203 // TODO(jglasgow): register callbacks
204}
205
206void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400207 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700208 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400209 InitProxies();
Ben Chan151d4472013-09-06 13:29:46 -0700210 deferred_enable_modem_callback_.Reset();
211 EnableModem(true, error, callback);
Gary Moraine285a842012-08-15 08:23:57 -0700212}
213
Ben Chan151d4472013-09-06 13:29:46 -0700214void CellularCapabilityUniversal::EnableModem(bool deferrable,
215 Error *error,
Gary Moraine285a842012-08-15 08:23:57 -0700216 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700217 SLOG(Cellular, 3) << __func__ << "(deferrable=" << deferrable << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400218 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700219 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700220 modem_info()->metrics()->NotifyDeviceEnableStarted(
221 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400222 modem_proxy_->Enable(
223 true,
Gary Moraine285a842012-08-15 08:23:57 -0700224 &local_error,
Ben Chan151d4472013-09-06 13:29:46 -0700225 Bind(&CellularCapabilityUniversal::EnableModemCompleted,
226 weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
Jason Glasgowef965562012-04-10 16:12:35 -0400227 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700228 if (local_error.IsFailure()) {
229 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700230 }
231 if (error) {
232 error->CopyFrom(local_error);
233 }
Jason Glasgowef965562012-04-10 16:12:35 -0400234}
235
Ben Chan151d4472013-09-06 13:29:46 -0700236void CellularCapabilityUniversal::EnableModemCompleted(
237 bool deferrable, const ResultCallback &callback, const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700238 SLOG(Cellular, 3) << __func__ << "(deferrable=" << deferrable
Ben Chan151d4472013-09-06 13:29:46 -0700239 << ", error=" << error << ")";
Thieu Leb9c05e02013-03-04 14:09:32 -0800240
Ben Chan151d4472013-09-06 13:29:46 -0700241 // If the enable operation failed with Error::kWrongState, the modem is not
242 // in the expected state (i.e. disabled). If |deferrable| indicates that the
243 // enable operation can be deferred, we defer the operation until the modem
244 // goes into the expected state (see OnModemStateChangedSignal).
245 //
246 // Note that when the SIM is locked, the enable operation also fails with
247 // Error::kWrongState. The enable operation is deferred until the modem goes
248 // into the disabled state after the SIM is unlocked. We may choose not to
249 // defer the enable operation when the SIM is locked, but the UI needs to
250 // trigger the enable operation after the SIM is unlocked, which is currently
251 // not the case.
Jason Glasgowef965562012-04-10 16:12:35 -0400252 if (error.IsFailure()) {
Ben Chan151d4472013-09-06 13:29:46 -0700253 if (!deferrable || error.type() != Error::kWrongState) {
254 callback.Run(error);
255 return;
256 }
257
258 if (deferred_enable_modem_callback_.is_null()) {
259 SLOG(Cellular, 2) << "Defer enable operation.";
260 // The Enable operation to be deferred should not be further deferrable.
261 deferred_enable_modem_callback_ =
262 Bind(&CellularCapabilityUniversal::EnableModem,
263 weak_ptr_factory_.GetWeakPtr(),
264 false, // non-deferrable
265 static_cast<Error*>(NULL),
266 callback);
267 }
Jason Glasgowef965562012-04-10 16:12:35 -0400268 return;
269 }
270
271 // After modem is enabled, it should be possible to get properties
272 // TODO(jglasgow): handle errors from GetProperties
273 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800274 // We expect the modem to start scanning after it has been enabled.
275 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700276 modem_info()->metrics()->NotifyDeviceEnableFinished(
277 cellular()->interface_index());
278 modem_info()->metrics()->NotifyDeviceScanStarted(
279 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800280 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400281}
282
283void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400284 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400285 CHECK(!callback.is_null());
286 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700287 // If there is an outstanding registration change, simply ignore it since
288 // the service will be destroyed anyway.
289 if (!registration_dropped_update_callback_.IsCancelled()) {
290 registration_dropped_update_callback_.Cancel();
291 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
292 }
293
Thieu Le28492142014-04-08 16:41:13 -0700294 // Some modems will implicitly disconnect the bearer when transitioning to
295 // low power state. For such modems, it's faster to let the modem disconnect
296 // the bearer. To do that, we just remove the bearer from the list so
297 // ModemManager doesn't try to disconnect it during disable.
298 Closure task;
Thieu Lec466ccb2014-06-23 15:24:56 -0700299 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le28492142014-04-08 16:41:13 -0700300 task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer,
301 weak_ptr_factory_.GetWeakPtr(),
302 callback);
303 } else {
304 task = Bind(&CellularCapabilityUniversal::Stop_Disable,
305 weak_ptr_factory_.GetWeakPtr(),
306 callback);
307 }
Ben Chan9de146f2013-09-11 13:11:31 -0700308 cellular()->dispatcher()->PostTask(task);
Gary Moraine285a842012-08-15 08:23:57 -0700309 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400310}
311
Thieu Le28492142014-04-08 16:41:13 -0700312void CellularCapabilityUniversal::Stop_DeleteActiveBearer(
313 const ResultCallback &callback) {
314 SLOG(Cellular, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700315
316 if (!active_bearer_) {
317 Stop_Disable(callback);
318 return;
319 }
320
Thieu Le28492142014-04-08 16:41:13 -0700321 Error error;
322 modem_proxy_->DeleteBearer(
323 active_bearer_->dbus_path(), &error,
324 Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted,
325 weak_ptr_factory_.GetWeakPtr(), callback),
326 kTimeoutDefault);
327 if (error.IsFailure())
328 callback.Run(error);
329}
330
331void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted(
332 const ResultCallback &callback, const Error &error) {
333 SLOG(Cellular, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700334 // Disregard the error from the bearer deletion since the disable will clean
335 // up any remaining bearers.
336 Stop_Disable(callback);
Thieu Le28492142014-04-08 16:41:13 -0700337}
338
Jason Glasgowef965562012-04-10 16:12:35 -0400339void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700340 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400341 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700342 modem_info()->metrics()->NotifyDeviceDisableStarted(
343 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400344 modem_proxy_->Enable(
345 false, &error,
346 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
347 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400348 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400349 if (error.IsFailure())
350 callback.Run(error);
351}
352
353void CellularCapabilityUniversal::Stop_DisableCompleted(
354 const ResultCallback &callback, const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700355 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400356
Thieu Lea2519bf2013-01-23 16:51:54 -0800357 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800358 // The modem has been successfully disabled, but we still need to power it
359 // down.
360 Stop_PowerDown(callback);
361 } else {
362 // An error occurred; terminate the disable sequence.
363 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800364 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800365}
366
367void CellularCapabilityUniversal::Stop_PowerDown(
368 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700369 SLOG(Cellular, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800370 Error error;
371 modem_proxy_->SetPowerState(
372 MM_MODEM_POWER_STATE_LOW,
373 &error,
374 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
375 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800376 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800377
378 if (error.IsFailure())
379 // This really shouldn't happen, but if it does, report success,
380 // because a stop initiated power down is only called if the
381 // modem was successfully disabled, but the failure of this
382 // operation should still be propagated up as a successful disable.
383 Stop_PowerDownCompleted(callback, error);
384}
385
mukesh agrawal28185512013-10-18 16:57:09 -0700386// Note: if we were in the middle of powering down the modem when the
387// system suspended, we might not get this event from
388// ModemManager. And we might not even get a timeout from dbus-c++,
389// because StartModem re-initializes proxies.
Arman Ugurayee464d32013-02-13 17:14:36 -0800390void CellularCapabilityUniversal::Stop_PowerDownCompleted(
391 const ResultCallback &callback,
392 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700393 SLOG(Cellular, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800394
395 if (error.IsFailure())
396 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
397
398 // Since the disable succeeded, if power down fails, we currently fail
399 // silently, i.e. we need to report the disable operation as having
400 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700401 modem_info()->metrics()->NotifyDeviceDisableFinished(
402 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800403 ReleaseProxies();
404 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400405}
406
407void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
408 Error *error,
409 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700410 SLOG(Cellular, 3) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400411 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
412 weak_ptr_factory_.GetWeakPtr(),
413 callback);
414 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400415}
416
417void CellularCapabilityUniversal::Disconnect(Error *error,
418 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700419 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700420 // If a deferred registration loss request exists, process it.
421 if (!registration_dropped_update_callback_.IsCancelled()) {
422 registration_dropped_update_callback_.callback().Run();
423 DCHECK(cellular()->state() != Cellular::kStateConnected &&
424 cellular()->state() != Cellular::kStateLinked);
425 SLOG(Cellular, 1) << "Processed deferred registration loss before "
426 << "disconnect request.";
427 }
Ben Chan539ab022014-02-03 16:34:57 -0800428 if (modem_simple_proxy_.get()) {
429 SLOG(Cellular, 2) << "Disconnect all bearers.";
430 // If "/" is passed as the bearer path, ModemManager will disconnect all
431 // bearers.
432 modem_simple_proxy_->Disconnect(DBus::Path(kRootPath),
Thieu Le5d6864a2012-07-20 11:43:51 -0700433 error,
434 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800435 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700436 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400437}
438
Arman Uguraya14941d2013-04-12 16:58:26 -0700439void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
Thieu Le28492142014-04-08 16:41:13 -0700440 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800441 const string &sim_identifier = cellular()->sim_identifier();
442 if (sim_identifier.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700443 modem_info()->pending_activation_store()->GetActivationState(
444 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800445 sim_identifier) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700446 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
447 return;
448 }
449 if (IsMdnValid()) {
450 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
451 return;
452 }
453 if (reset_done_) {
454 SLOG(Cellular, 2) << "Already done with reset.";
455 return;
456 }
457
458 // Still not activated after timeout. Reset the modem.
459 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
460 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700461 modem_info()->pending_activation_store()->SetActivationState(
462 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800463 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700464 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700465 ResetAfterActivation();
466}
467
Arman Ugurayc7b15602013-02-16 00:56:18 -0800468void CellularCapabilityUniversal::CompleteActivation(Error *error) {
Thieu Le28492142014-04-08 16:41:13 -0700469 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800470
471 // Persist the ICCID as "Pending Activation".
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800472 // We're assuming that when this function gets called,
473 // |cellular()->sim_identifier()| will be non-empty. We still check here that
474 // is non-empty, though something is wrong if it is empty.
475 const string &sim_identifier = cellular()->sim_identifier();
476 if (sim_identifier.empty()) {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800477 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
478 return;
479 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800480
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700481 if (IsMdnValid()) {
482 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
483 return;
484 }
485
Arman Ugurayefea6e02013-02-21 13:28:04 -0800486 // There should be a cellular service at this point.
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700487 if (cellular()->service().get()) {
488 if (cellular()->service()->activation_state() == kActivationStateActivated)
489 return;
490
Ben Chan7ea768e2013-09-20 15:08:40 -0700491 cellular()->service()->SetActivationState(kActivationStateActivating);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700492 }
Arman Uguray41cc6342013-03-29 16:34:39 -0700493 modem_info()->pending_activation_store()->SetActivationState(
494 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800495 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700496 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700497
498 activation_wait_for_registration_callback_.Reset(
499 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
500 weak_ptr_factory_.GetWeakPtr()));
501 cellular()->dispatcher()->PostDelayedTask(
502 activation_wait_for_registration_callback_.callback(),
503 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800504}
505
506void CellularCapabilityUniversal::ResetAfterActivation() {
Thieu Le28492142014-04-08 16:41:13 -0700507 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800508
509 // Here the initial call to Reset might fail in rare cases. Simply ignore.
510 Error error;
511 ResultCallback callback = Bind(
512 &CellularCapabilityUniversal::OnResetAfterActivationReply,
513 weak_ptr_factory_.GetWeakPtr());
514 Reset(&error, callback);
515 if (error.IsFailure())
516 SLOG(Cellular, 2) << "Failed to reset after activation.";
517}
518
519void CellularCapabilityUniversal::OnResetAfterActivationReply(
520 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700521 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800522 if (error.IsFailure()) {
523 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
524 // TODO(armansito): Maybe post a delayed reset task?
525 return;
526 }
527 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700528 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800529 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800530}
531
Arman Uguray0a3e2792013-01-17 16:31:50 -0800532void CellularCapabilityUniversal::UpdatePendingActivationState() {
Thieu Le28492142014-04-08 16:41:13 -0700533 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800534
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800535 const string &sim_identifier = cellular()->sim_identifier();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800536 bool registered =
537 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
538
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700539 // We know a service is activated if |subscription_state_| is
540 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
541 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
542 // fallback on checking for a valid MDN.
543 bool activated =
544 ((subscription_state_ == kSubscriptionStateProvisioned) ||
545 (subscription_state_ == kSubscriptionStateOutOfData)) ||
546 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
547
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800548 if (activated && !sim_identifier.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700549 modem_info()->pending_activation_store()->RemoveEntry(
550 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800551 sim_identifier);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800552
Arman Ugurayefea6e02013-02-21 13:28:04 -0800553 CellularServiceRefPtr service = cellular()->service();
554
555 if (!service.get())
556 return;
557
Ben Chan7ea768e2013-09-20 15:08:40 -0700558 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800559 // Either no service or already activated. Nothing to do.
560 return;
561
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700562 // Besides the indicators above, a connected service also indicates an
563 // activated SIM.
564 if (activated || cellular()->state() == Cellular::kStateConnected ||
Arman Ugurayc7b15602013-02-16 00:56:18 -0800565 cellular()->state() == Cellular::kStateLinked) {
566 SLOG(Cellular, 2) << "Marking service as activated.";
Ben Chan7ea768e2013-09-20 15:08:40 -0700567 service->SetActivationState(kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800568 return;
569 }
570
571 // If the ICCID is not available, the following logic can be delayed until it
572 // becomes available.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800573 if (sim_identifier.empty())
Arman Ugurayefea6e02013-02-21 13:28:04 -0800574 return;
575
Arman Uguray41cc6342013-03-29 16:34:39 -0700576 PendingActivationStore::State state =
577 modem_info()->pending_activation_store()->GetActivationState(
578 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800579 sim_identifier);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800580 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700581 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800582 // Always mark the service as activating here, as the ICCID could have
583 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700584 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800585 if (reset_done_) {
586 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700587 modem_info()->pending_activation_store()->SetActivationState(
588 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800589 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700590 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800591 } else if (registered) {
592 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700593 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800594 ResetAfterActivation();
595 }
596 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700597 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800598 if (registered) {
599 // Trigger auto connect here.
600 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
601 << "autoconnect to force MDN to update.";
602 service->AutoConnect();
603 }
604 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700605 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700606 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
607 << "been reset at least once.";
608 if (registered) {
609 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700610 modem_info()->pending_activation_store()->SetActivationState(
611 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800612 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700613 PendingActivationStore::kStateActivated);
Ben Chan7ea768e2013-09-20 15:08:40 -0700614 service->SetActivationState(kActivationStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700615 }
616 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700617 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800618 // No entry exists for this ICCID. Nothing to do.
619 break;
620 default:
621 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800622 }
623}
624
Ben Chan07193fd2013-07-12 22:10:55 -0700625string CellularCapabilityUniversal::GetMdnForOLP(
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700626 const MobileOperatorInfo *operator_info) const {
Ben Chan07193fd2013-07-12 22:10:55 -0700627 // TODO(benchan): This is ugly. Remove carrier specific code once we move
628 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800629 const string &mdn = cellular()->mdn();
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700630 if (!operator_info->IsMobileNetworkOperatorKnown()) {
631 // Can't make any carrier specific modifications.
632 return mdn;
633 }
634
635 if (operator_info->uuid() == kVzwIdentifier) {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700636 // subscription_state_ is the definitive indicator of whether we need
637 // activation. The OLP expects an all zero MDN in that case.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800638 if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) {
Ben Chan200591a2013-08-07 14:39:04 -0700639 return string(kVzwMdnLength, '0');
640 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800641 if (mdn.length() > kVzwMdnLength) {
642 return mdn.substr(mdn.length() - kVzwMdnLength);
Ben Chan200591a2013-08-07 14:39:04 -0700643 }
Ben Chan07193fd2013-07-12 22:10:55 -0700644 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800645 return mdn;
Ben Chan07193fd2013-07-12 22:10:55 -0700646}
647
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400648void CellularCapabilityUniversal::ReleaseProxies() {
Thieu Le28492142014-04-08 16:41:13 -0700649 SLOG(Cellular, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400650 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400651 modem_proxy_.reset();
652 modem_simple_proxy_.reset();
653 sim_proxy_.reset();
654}
655
Arman Ugurayefea6e02013-02-21 13:28:04 -0800656void CellularCapabilityUniversal::UpdateServiceActivationState() {
657 if (!cellular()->service().get())
658 return;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800659
660 const string &sim_identifier = cellular()->sim_identifier();
Ben Chan3d6de0e2012-12-10 12:01:34 -0800661 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700662 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700663 PendingActivationStore::State state =
664 modem_info()->pending_activation_store()->GetActivationState(
665 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800666 sim_identifier);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700667 if ((subscription_state_ == kSubscriptionStateUnknown ||
668 subscription_state_ == kSubscriptionStateUnprovisioned) &&
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800669 !sim_identifier.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700670 (state == PendingActivationStore::kStatePending ||
Alex Vakulenko8a532292014-06-16 17:18:44 -0700671 state == PendingActivationStore::kStatePendingTimeout)) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700672 activation_state = kActivationStateActivating;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700673 } else if (activation_required) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700674 activation_state = kActivationStateNotActivated;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700675 } else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700676 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700677
678 // Mark an activated service for auto-connect by default. Since data from
679 // the user profile will be loaded after the call to OnServiceCreated, this
680 // property will be corrected based on the user data at that time.
Thieu Le247416e2014-02-25 18:19:53 -0800681 // NOTE: This function can be called outside the service initialization
682 // path so make sure we don't overwrite the auto-connect setting.
683 if (cellular()->service()->activation_state() != activation_state)
684 cellular()->service()->SetAutoConnect(true);
Arman Uguray6bb252d2013-05-15 14:29:53 -0700685 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800686 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800687 // TODO(benchan): For now, assume the cellular service is activated over
688 // a non-cellular network if service activation is required (i.e. a
689 // corresponding entry is found in the cellular operator info file).
690 // We will need to generalize this logic when migrating CDMA support from
691 // cromo to ModemManager.
692 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800693}
694
695void CellularCapabilityUniversal::OnServiceCreated() {
Arman Ugurayefea6e02013-02-21 13:28:04 -0800696 UpdateServiceActivationState();
Thieu Le398b1da2013-03-11 17:31:10 -0700697
698 // WORKAROUND:
699 // E362 modems on Verizon network does not properly redirect when a SIM
700 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700701 //
702 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
703 // support is ready (crosbug.com/p/20461).
Thieu Le43ce4d42013-10-04 16:08:55 -0700704 cellular()->service()->InitOutOfCreditsDetection(
705 GetOutOfCreditsDetectionType());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700706
707 // Make sure that the network technology is set when the service gets
708 // created, just in case.
709 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400710}
711
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400712// Create the list of APNs to try, in the following order:
713// - last APN that resulted in a successful connection attempt on the
714// current network (if any)
715// - the APN, if any, that was set by the user
716// - the list of APNs found in the mobile broadband provider DB for the
717// home provider associated with the current SIM
718// - as a last resort, attempt to connect with no APN
719void CellularCapabilityUniversal::SetupApnTryList() {
720 apn_try_list_.clear();
721
722 DCHECK(cellular()->service().get());
723 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
724 if (apn_info)
725 apn_try_list_.push_back(*apn_info);
726
727 apn_info = cellular()->service()->GetUserSpecifiedApn();
728 if (apn_info)
729 apn_try_list_.push_back(*apn_info);
730
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800731 apn_try_list_.insert(apn_try_list_.end(),
732 cellular()->apn_list().begin(),
733 cellular()->apn_list().end());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400734}
735
736void CellularCapabilityUniversal::SetupConnectProperties(
737 DBusPropertiesMap *properties) {
738 SetupApnTryList();
739 FillConnectPropertyMap(properties);
740}
741
742void CellularCapabilityUniversal::FillConnectPropertyMap(
743 DBusPropertiesMap *properties) {
744
745 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400746 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400747 kPhoneNumber);
748
Jason Glasgow14521872012-05-07 19:12:15 -0400749 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400750 AllowRoaming());
751
752 if (!apn_try_list_.empty()) {
753 // Leave the APN at the front of the list, so that it can be recorded
754 // if the connect attempt succeeds.
755 Stringmap apn_info = apn_try_list_.front();
Ben Chan7ea768e2013-09-20 15:08:40 -0700756 SLOG(Cellular, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400757 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700758 apn_info[kApnProperty].c_str());
759 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400760 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700761 apn_info[kApnUsernameProperty].c_str());
762 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400763 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700764 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400765 }
766}
767
768void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400769 const DBus::Path &path,
770 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700771 SLOG(Cellular, 3) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400772
Jason Glasgow7234ec32012-05-23 16:01:21 -0400773 CellularServiceRefPtr service = cellular()->service();
774 if (!service) {
775 // The service could have been deleted before our Connect() request
776 // completes if the modem was enabled and then quickly disabled.
777 apn_try_list_.clear();
778 } else if (error.IsFailure()) {
779 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400780 // The APN that was just tried (and failed) is still at the
781 // front of the list, about to be removed. If the list is empty
782 // after that, try one last time without an APN. This may succeed
783 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400784 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400785 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700786 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
787 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400788 DBusPropertiesMap props;
789 FillConnectPropertyMap(&props);
790 Error error;
791 Connect(props, &error, callback);
792 return;
793 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400794 } else {
795 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400796 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400797 apn_try_list_.clear();
798 }
Ben Chan539ab022014-02-03 16:34:57 -0800799 SLOG(Cellular, 2) << "Connected bearer " << path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400800 }
801
802 if (!callback.is_null())
803 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800804
Arman Uguray0a3e2792013-01-17 16:31:50 -0800805 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400806}
807
808bool CellularCapabilityUniversal::AllowRoaming() {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800809 return cellular()->provider_requires_roaming() || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400810}
811
Jason Glasgowef965562012-04-10 16:12:35 -0400812void CellularCapabilityUniversal::GetProperties() {
Thieu Le28492142014-04-08 16:41:13 -0700813 SLOG(Cellular, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400814
Jason Glasgowaf583282012-04-18 15:18:22 -0400815 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
816 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
817 cellular()->dbus_owner()));
818 DBusPropertiesMap properties(
819 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
820 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400821
Jason Glasgowaf583282012-04-18 15:18:22 -0400822 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
823 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400824}
825
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700826void CellularCapabilityUniversal::UpdateServiceOLP() {
Thieu Le28492142014-04-08 16:41:13 -0700827 SLOG(Cellular, 3) << __func__;
Ben Chan07193fd2013-07-12 22:10:55 -0700828
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700829 // OLP is based off of the Home Provider.
830 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
Ben Chan07193fd2013-07-12 22:10:55 -0700831 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700832 }
Ben Chan07193fd2013-07-12 22:10:55 -0700833
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700834 const vector<MobileOperatorInfo::OnlinePortal> &olp_list =
835 cellular()->home_provider_info()->olp_list();
836 if (olp_list.empty()) {
Ben Chan6d0d1e72012-11-06 21:19:28 -0800837 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700838 }
Ben Chan6d0d1e72012-11-06 21:19:28 -0800839
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700840 if (olp_list.size() > 1) {
841 SLOG(Cellular, 1) << "Found multiple online portals. Choosing the first.";
842 }
843 string post_data = olp_list[0].post_data;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800844 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}",
845 cellular()->sim_identifier());
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800846 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", cellular()->imei());
847 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", cellular()->imsi());
Ben Chan07193fd2013-07-12 22:10:55 -0700848 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700849 GetMdnForOLP(cellular()->home_provider_info()));
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800850 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", cellular()->min());
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700851 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800852}
853
Ben Chan539ab022014-02-03 16:34:57 -0800854void CellularCapabilityUniversal::UpdateActiveBearer() {
855 SLOG(Cellular, 3) << __func__;
856
Arman Uguray6e5639f2012-11-15 20:30:19 -0800857 // Look for the first active bearer and use its path as the connected
858 // one. Right now, we don't allow more than one active bearer.
Ben Chan539ab022014-02-03 16:34:57 -0800859 active_bearer_.reset();
Ben Chancbef8122014-01-06 17:31:30 -0800860 for (const auto &path : bearer_paths_) {
Ben Chan539ab022014-02-03 16:34:57 -0800861 scoped_ptr<CellularBearer> bearer(
862 new CellularBearer(proxy_factory(), path, cellular()->dbus_service()));
863 // The bearer object may have vanished before ModemManager updates the
864 // 'Bearers' property.
865 if (!bearer->Init())
mukesh agrawal9da07772013-05-15 14:15:17 -0700866 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700867
Ben Chan539ab022014-02-03 16:34:57 -0800868 if (!bearer->connected())
Ben Chan5db19692013-07-09 23:07:03 -0700869 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700870
mukesh agrawal9da07772013-05-15 14:15:17 -0700871 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan539ab022014-02-03 16:34:57 -0800872 CHECK(!active_bearer_) << "Found more than one active bearer.";
873 active_bearer_ = bearer.Pass();
Arman Uguray6e5639f2012-11-15 20:30:19 -0800874 }
Ben Chan539ab022014-02-03 16:34:57 -0800875
876 if (!active_bearer_)
mukesh agrawal9da07772013-05-15 14:15:17 -0700877 SLOG(Cellular, 2) << "No active bearer found.";
Arman Uguray6e5639f2012-11-15 20:30:19 -0800878}
879
Ben Chan15786032012-11-04 21:28:02 -0800880bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800881 const string &sim_identifier = cellular()->sim_identifier();
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700882 // subscription_state_ is the definitive answer. If that does not work,
883 // fallback on MDN based logic.
884 if (subscription_state_ == kSubscriptionStateProvisioned ||
885 subscription_state_ == kSubscriptionStateOutOfData)
886 return false;
887
888 // We are in the process of activating, ignore all other clues from the
889 // network and use our own knowledge about the activation state.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800890 if (!sim_identifier.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700891 modem_info()->pending_activation_store()->GetActivationState(
892 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800893 sim_identifier) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800894 return false;
895
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700896 // Network notification that the service needs to be activated.
897 if (subscription_state_ == kSubscriptionStateUnprovisioned)
898 return true;
899
Ben Chan15786032012-11-04 21:28:02 -0800900 // If there is no online payment portal information, it's safer to assume
901 // the service does not require activation.
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700902 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
903 cellular()->home_provider_info()->olp_list().empty()) {
Ben Chan15786032012-11-04 21:28:02 -0800904 return false;
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700905 }
Ben Chan15786032012-11-04 21:28:02 -0800906
Ben Chan200591a2013-08-07 14:39:04 -0700907 // If the MDN is invalid (i.e. empty or contains only zeros), the service
908 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -0800909 return !IsMdnValid();
910}
911
912bool CellularCapabilityUniversal::IsMdnValid() const {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800913 const string &mdn = cellular()->mdn();
914 // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
915 for (size_t i = 0; i < mdn.size(); ++i) {
916 if (mdn[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -0800917 return true;
Ben Chan15786032012-11-04 21:28:02 -0800918 }
Arman Ugurayc7b15602013-02-16 00:56:18 -0800919 return false;
Ben Chan15786032012-11-04 21:28:02 -0800920}
921
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400922// always called from an async context
923void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700924 SLOG(Cellular, 3) << __func__ << " \"" << cellular()->selected_network()
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800925 << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400926 CHECK(!callback.is_null());
927 Error error;
928 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
929 weak_ptr_factory_.GetWeakPtr(), callback);
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800930 modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
931 kTimeoutRegister);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400932 if (error.IsFailure())
933 callback.Run(error);
934}
935
936void CellularCapabilityUniversal::RegisterOnNetwork(
937 const string &network_id,
938 Error *error,
939 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700940 SLOG(Cellular, 3) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400941 CHECK(error);
942 desired_network_ = network_id;
943 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
944 weak_ptr_factory_.GetWeakPtr(), callback);
945 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
946}
947
948void CellularCapabilityUniversal::OnRegisterReply(
949 const ResultCallback &callback,
950 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700951 SLOG(Cellular, 3) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400952
953 if (error.IsSuccess()) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800954 cellular()->set_selected_network(desired_network_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400955 desired_network_.clear();
956 callback.Run(error);
957 return;
958 }
959 // If registration on the desired network failed,
960 // try to register on the home network.
961 if (!desired_network_.empty()) {
962 desired_network_.clear();
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800963 cellular()->set_selected_network("");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400964 LOG(INFO) << "Couldn't register on selected network, trying home network";
965 Register(callback);
966 return;
967 }
968 callback.Run(error);
969}
970
Ben Chan31ce5642013-11-14 13:37:40 -0800971bool CellularCapabilityUniversal::IsRegistered() const {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700972 return IsRegisteredState(registration_state_);
973}
974
975bool CellularCapabilityUniversal::IsRegisteredState(
976 MMModem3gppRegistrationState state) {
977 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
978 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400979}
980
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400981void CellularCapabilityUniversal::SetUnregistered(bool searching) {
982 // If we're already in some non-registered state, don't override that
983 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
984 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
985 registration_state_ =
986 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
987 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
988 }
989}
990
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400991void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400992 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400993 Error *error, const ResultCallback &callback) {
994 CHECK(error);
995 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
996}
997
998void CellularCapabilityUniversal::EnterPIN(const string &pin,
999 Error *error,
1000 const ResultCallback &callback) {
1001 CHECK(error);
Thieu Le28492142014-04-08 16:41:13 -07001002 SLOG(Cellular, 3) << __func__;
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001003 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001004}
1005
1006void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1007 const string &pin,
1008 Error *error,
1009 const ResultCallback &callback) {
1010 CHECK(error);
1011 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1012}
1013
1014void CellularCapabilityUniversal::ChangePIN(
1015 const string &old_pin, const string &new_pin,
1016 Error *error, const ResultCallback &callback) {
1017 CHECK(error);
1018 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1019}
1020
Ben Chan5d0d32c2013-01-08 02:05:29 -08001021void CellularCapabilityUniversal::Reset(Error *error,
1022 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -07001023 SLOG(Cellular, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -08001024 CHECK(error);
1025 if (resetting_) {
1026 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1027 return;
1028 }
1029 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1030 weak_ptr_factory_.GetWeakPtr(), callback);
1031 modem_proxy_->Reset(error, cb, kTimeoutReset);
1032 if (!error->IsFailure()) {
1033 resetting_ = true;
1034 }
1035}
1036
1037void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1038 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -07001039 SLOG(Cellular, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -08001040 resetting_ = false;
1041 if (!callback.is_null())
1042 callback.Run(error);
1043}
1044
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001045void CellularCapabilityUniversal::Scan(
1046 Error *error,
1047 const ResultStringmapsCallback &callback) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001048 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1049 weak_ptr_factory_.GetWeakPtr(), callback);
1050 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
1051}
1052
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001053void CellularCapabilityUniversal::OnScanReply(
1054 const ResultStringmapsCallback &callback,
1055 const ScanResults &results,
1056 const Error &error) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001057 Stringmaps found_networks;
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001058 for (const auto &result : results)
1059 found_networks.push_back(ParseScanResult(result));
1060 callback.Run(found_networks, error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001061}
1062
1063Stringmap CellularCapabilityUniversal::ParseScanResult(
1064 const ScanResult &result) {
1065
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001066 /* ScanResults contain the following keys:
1067
1068 "status"
1069 A MMModem3gppNetworkAvailability value representing network
1070 availability status, given as an unsigned integer (signature "u").
1071 This key will always be present.
1072
1073 "operator-long"
1074 Long-format name of operator, given as a string value (signature
1075 "s"). If the name is unknown, this field should not be present.
1076
1077 "operator-short"
1078 Short-format name of operator, given as a string value
1079 (signature "s"). If the name is unknown, this field should not
1080 be present.
1081
1082 "operator-code"
1083 Mobile code of the operator, given as a string value (signature
1084 "s"). Returned in the format "MCCMNC", where MCC is the
1085 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1086 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1087
1088 "access-technology"
1089 A MMModemAccessTechnology value representing the generic access
1090 technology used by this mobile network, given as an unsigned
1091 integer (signature "u").
1092 */
1093 Stringmap parsed;
1094
1095 uint32 status;
1096 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1097 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1098 static const char * const kStatusString[] = {
1099 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1100 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1101 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1102 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1103 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001104 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001105 }
1106
1107 uint32 tech; // MMModemAccessTechnology
1108 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1109 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001110 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001111 }
1112
1113 string operator_long, operator_short, operator_code;
1114 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001115 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001116 if (DBusProperties::GetString(result, kOperatorShortProperty,
1117 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001118 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001119 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001120 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001121
1122 // If the long name is not available but the network ID is, look up the long
1123 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001124 if ((!ContainsKey(parsed, kLongNameProperty) ||
1125 parsed[kLongNameProperty].empty()) &&
1126 ContainsKey(parsed, kNetworkIdProperty)) {
Prathmesh Prabhuafe63662014-05-20 11:03:58 -07001127 mobile_operator_info_->Reset();
1128 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
1129 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
1130 !mobile_operator_info_->operator_name().empty()) {
1131 parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001132 }
1133 }
1134 return parsed;
1135}
1136
Ben Chan539ab022014-02-03 16:34:57 -08001137CellularBearer *CellularCapabilityUniversal::GetActiveBearer() const {
1138 return active_bearer_.get();
1139}
1140
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001141string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001142 // If we know that the modem is an E362, return LTE here to make sure that
1143 // Chrome sees LTE as the network technology even if the actual technology is
1144 // unknown.
1145 // TODO(armansito): This hack will cause the UI to display LTE even if the
1146 // modem doesn't support it at a given time. This might be problematic if we
1147 // ever want to support switching between access technologies (e.g. falling
1148 // back to 3G when LTE is not available).
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001149 if (cellular()->model_id() == kE362ModelId)
Ben Chan7ea768e2013-09-20 15:08:40 -07001150 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001151
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001152 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001153 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001154 return AccessTechnologyToString(access_technologies_);
1155}
1156
1157string CellularCapabilityUniversal::GetRoamingStateString() const {
1158 switch (registration_state_) {
1159 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001160 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001161 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001162 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001163 default:
1164 break;
1165 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001166 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001167}
1168
Arman Uguray5d9a8522013-09-10 17:43:13 -07001169// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001170void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001171 // ModemManager always returns the cached value, so there is no need to
1172 // trigger an update here. The true value is updated through a property
1173 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001174}
1175
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001176string CellularCapabilityUniversal::GetTypeString() const {
1177 return AccessTechnologyToTechnologyFamily(access_technologies_);
1178}
1179
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001180void CellularCapabilityUniversal::OnModemPropertiesChanged(
1181 const DBusPropertiesMap &properties,
1182 const vector<string> &/* invalidated_properties */) {
Ben Chancbef8122014-01-06 17:31:30 -08001183
1184 // Update the bearers property before the modem state property as
Ben Chan539ab022014-02-03 16:34:57 -08001185 // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
1186 // property.
Ben Chancbef8122014-01-06 17:31:30 -08001187 RpcIdentifiers bearers;
1188 if (DBusProperties::GetRpcIdentifiers(properties, MM_MODEM_PROPERTY_BEARERS,
1189 &bearers)) {
1190 OnBearersChanged(bearers);
1191 }
1192
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001193 // This solves a bootstrapping problem: If the modem is not yet
1194 // enabled, there are no proxy objects associated with the capability
1195 // object, so modem signals like StateChanged aren't seen. By monitoring
1196 // changes to the State property via the ModemManager, we're able to
1197 // get the initialization process started, which will result in the
1198 // creation of the proxy objects.
1199 //
1200 // The first time we see the change to State (when the modem state
1201 // is Unknown), we simply update the state, and rely on the Manager to
1202 // enable the device when it is registered with the Manager. On subsequent
1203 // changes to State, we need to explicitly enable the device ourselves.
1204 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001205 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001206 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001207 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001208 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001209 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001210 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001211 MM_MODEM_PROPERTY_SIM, &object_path_value))
1212 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001213
1214 DBusPropertiesMap::const_iterator it =
1215 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1216 if (it != properties.end()) {
1217 const vector<uint32> &supported_capabilities = it->second;
1218 OnSupportedCapabilitesChanged(supported_capabilities);
1219 }
1220
Jason Glasgowaf583282012-04-18 15:18:22 -04001221 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001222 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001223 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1224 &uint_value))
1225 OnModemCurrentCapabilitiesChanged(uint_value);
1226 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1227 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001228 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001229 if (DBusProperties::GetString(properties,
1230 MM_MODEM_PROPERTY_MANUFACTURER,
1231 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001232 cellular()->set_manufacturer(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001233 if (DBusProperties::GetString(properties,
1234 MM_MODEM_PROPERTY_MODEL,
1235 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001236 cellular()->set_model_id(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001237 if (DBusProperties::GetString(properties,
Thieu Lec466ccb2014-06-23 15:24:56 -07001238 MM_MODEM_PROPERTY_PLUGIN,
1239 &string_value))
1240 cellular()->set_mm_plugin(string_value);
1241 if (DBusProperties::GetString(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001242 MM_MODEM_PROPERTY_REVISION,
1243 &string_value))
1244 OnModemRevisionChanged(string_value);
1245 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1246 // not needed: MM_MODEM_PROPERTY_DEVICE
1247 // not needed: MM_MODEM_PROPERTY_DRIVER
1248 // not needed: MM_MODEM_PROPERTY_PLUGIN
1249 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001250
Jason Glasgowaf583282012-04-18 15:18:22 -04001251 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001252 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001253 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001254 if (DBusProperties::GetUint32(properties,
1255 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001256 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001257 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001258 lock_status_changed = true;
1259 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001260
1261 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001262 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001263 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001264 LockRetryData lock_retries = it->second.operator LockRetryData();
1265 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001266 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001267 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001268
Arman Ugurayea5ff272013-06-25 10:28:02 -07001269 if (lock_status_changed)
1270 OnSimLockStatusChanged();
1271
Jason Glasgowaf583282012-04-18 15:18:22 -04001272 if (DBusProperties::GetUint32(properties,
1273 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1274 &uint_value))
1275 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001276
Jason Glasgowaf583282012-04-18 15:18:22 -04001277 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1278 if (it != properties.end()) {
1279 DBus::Struct<unsigned int, bool> quality = it->second;
1280 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001281 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001282 vector<string> numbers;
1283 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1284 &numbers)) {
1285 string mdn;
1286 if (numbers.size() > 0)
1287 mdn = numbers[0];
1288 OnMdnChanged(mdn);
1289 }
Ben Chan74924d82013-06-15 17:52:55 -07001290
1291 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1292 if (it != properties.end()) {
1293 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1294 vector<ModemModes> supported_modes;
1295 for (const auto &modes : mm_supported_modes) {
1296 supported_modes.push_back(
1297 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1298 }
1299 OnSupportedModesChanged(supported_modes);
1300 }
1301
1302 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1303 if (it != properties.end()) {
1304 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1305 OnCurrentModesChanged(ModemModes(
1306 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1307 }
1308
Jason Glasgowaf583282012-04-18 15:18:22 -04001309 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1310 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001311}
1312
1313void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1314 const string &interface,
1315 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001316 const vector<string> &invalidated_properties) {
Thieu Le28492142014-04-08 16:41:13 -07001317 SLOG(Cellular, 3) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001318 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001319 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001320 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001321 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1322 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001323 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001324 if (interface == MM_DBUS_INTERFACE_SIM) {
1325 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001326 }
1327}
1328
Jason Glasgow14521872012-05-07 19:12:15 -04001329bool CellularCapabilityUniversal::RetriableConnectError(
1330 const Error &error) const {
1331 if (error.type() == Error::kInvalidApn)
1332 return true;
1333
1334 // modemmanager does not ever return kInvalidApn for E362 modems
1335 // with 1.41 firmware. It remains to be seem if this will change
1336 // with 3.x firmware.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001337 if ((cellular()->model_id() == kE362ModelId) &&
1338 (error.type() == Error::kOperationFailed))
Jason Glasgow14521872012-05-07 19:12:15 -04001339 return true;
1340
1341 return false;
1342}
1343
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001344void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1345 // TODO(petkov): Implement this.
1346 NOTIMPLEMENTED();
1347}
1348
Arman Uguray6552f8c2013-02-12 15:33:18 -08001349bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1350 return !sim_path.empty() && sim_path != kRootPath;
1351}
1352
Ben Chand7592522013-02-13 16:02:01 -08001353string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1354 string normalized_mdn;
1355 for (size_t i = 0; i < mdn.size(); ++i) {
1356 if (IsAsciiDigit(mdn[i]))
1357 normalized_mdn += mdn[i];
1358 }
1359 return normalized_mdn;
1360}
1361
Jason Glasgowaf583282012-04-18 15:18:22 -04001362void CellularCapabilityUniversal::OnSimPathChanged(
1363 const string &sim_path) {
1364 if (sim_path == sim_path_)
1365 return;
1366
1367 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001368 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001369 proxy = proxy_factory()->CreateSimProxy(sim_path,
1370 cellular()->dbus_owner());
1371 sim_path_ = sim_path;
1372 sim_proxy_.reset(proxy);
1373
Arman Uguray6552f8c2013-02-12 15:33:18 -08001374 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001375 // Clear all data about the sim
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001376 cellular()->set_imsi("");
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001377 spn_ = "";
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001378 cellular()->set_sim_present(false);
Jason Glasgowaf583282012-04-18 15:18:22 -04001379 OnSimIdentifierChanged("");
1380 OnOperatorIdChanged("");
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001381 cellular()->home_provider_info()->Reset();
Jason Glasgowaf583282012-04-18 15:18:22 -04001382 } else {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001383 cellular()->set_sim_present(true);
Jason Glasgowaf583282012-04-18 15:18:22 -04001384 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1385 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1386 cellular()->dbus_owner()));
1387 // TODO(jglasgow): convert to async interface
1388 DBusPropertiesMap properties(
1389 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1390 OnSimPropertiesChanged(properties, vector<string>());
1391 }
1392}
1393
Ben Chan74924d82013-06-15 17:52:55 -07001394void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1395 const vector<uint32> &supported_capabilities) {
1396 supported_capabilities_ = supported_capabilities;
1397}
1398
Jason Glasgowaf583282012-04-18 15:18:22 -04001399void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1400 uint32 current_capabilities) {
1401 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001402
1403 // Only allow network scan when the modem's current capabilities support
1404 // GSM/UMTS.
1405 //
1406 // TODO(benchan): We should consider having the modem plugins in ModemManager
1407 // reporting whether network scan is supported.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001408 cellular()->set_scanning_supported(
1409 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
Jason Glasgowaf583282012-04-18 15:18:22 -04001410}
1411
1412void CellularCapabilityUniversal::OnMdnChanged(
1413 const string &mdn) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001414 cellular()->set_mdn(NormalizeMdn(mdn));
Arman Uguray0a3e2792013-01-17 16:31:50 -08001415 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001416}
1417
Jason Glasgowaf583282012-04-18 15:18:22 -04001418void CellularCapabilityUniversal::OnModemRevisionChanged(
1419 const string &revision) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001420 cellular()->set_firmware_revision(revision);
Jason Glasgowaf583282012-04-18 15:18:22 -04001421}
1422
1423void CellularCapabilityUniversal::OnModemStateChanged(
1424 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001425 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001426
Ben Chan539ab022014-02-03 16:34:57 -08001427 if (state == Cellular::kModemStateConnected) {
1428 // This assumes that ModemManager updates the Bearers list and the Bearer
1429 // properties before changing Modem state to Connected.
1430 SLOG(Cellular, 2) << "Update active bearer.";
1431 UpdateActiveBearer();
1432 }
1433
Arman Uguray1ee93912013-09-24 21:24:10 -07001434 cellular()->OnModemStateChanged(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001435 // TODO(armansito): Move the deferred enable logic to Cellular
1436 // (See crbug.com/279499).
1437 if (!deferred_enable_modem_callback_.is_null() &&
1438 state == Cellular::kModemStateDisabled) {
1439 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1440 deferred_enable_modem_callback_.Run();
1441 deferred_enable_modem_callback_.Reset();
mukesh agrawal510cc802013-08-15 18:31:42 -07001442 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001443}
1444
1445void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1446 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001447 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001448 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001449 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001450 const string new_type_string(GetTypeString());
1451 if (new_type_string != old_type_string) {
1452 // TODO(jglasgow): address layering violation of emitting change
1453 // signal here for a property owned by Cellular.
1454 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001455 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001456 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001457 if (cellular()->service().get()) {
1458 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1459 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001460 }
1461}
1462
Ben Chan74924d82013-06-15 17:52:55 -07001463void CellularCapabilityUniversal::OnSupportedModesChanged(
1464 const vector<ModemModes> &supported_modes) {
1465 supported_modes_ = supported_modes;
1466}
1467
1468void CellularCapabilityUniversal::OnCurrentModesChanged(
1469 const ModemModes &current_modes) {
1470 current_modes_ = current_modes;
1471}
1472
Ben Chancbef8122014-01-06 17:31:30 -08001473void CellularCapabilityUniversal::OnBearersChanged(
1474 const RpcIdentifiers &bearers) {
1475 bearer_paths_ = bearers;
1476}
1477
Jason Glasgowaf583282012-04-18 15:18:22 -04001478void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001479 const LockRetryData &lock_retries) {
Thieu Le28492142014-04-08 16:41:13 -07001480 SLOG(Cellular, 3) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001481
Arman Ugurayea5ff272013-06-25 10:28:02 -07001482 // Look for the retries left for the current lock. Try the obtain the count
1483 // that matches the current count. If no count for the current lock is
1484 // available, report the first one in the dictionary.
1485 LockRetryData::const_iterator it =
1486 lock_retries.find(sim_lock_status_.lock_type);
1487 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001488 it = lock_retries.begin();
1489 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001490 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001491 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001492 // Unknown, use 999
1493 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001494}
1495
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001496void CellularCapabilityUniversal::OnLockTypeChanged(
1497 MMModemLock lock_type) {
Thieu Le28492142014-04-08 16:41:13 -07001498 SLOG(Cellular, 3) << __func__ << ": " << lock_type;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001499 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001500
1501 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1502 // This is because the corresponding property 'EnabledFacilityLocks' is on
1503 // the 3GPP interface and the 3GPP interface is not available while the Modem
1504 // is in the 'LOCKED' state.
1505 if (lock_type != MM_MODEM_LOCK_NONE &&
1506 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1507 !sim_lock_status_.enabled)
1508 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001509}
1510
Jason Glasgowaf583282012-04-18 15:18:22 -04001511void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Thieu Le28492142014-04-08 16:41:13 -07001512 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001513 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001514 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001515
1516 // If the SIM is currently unlocked, assume that we need to refresh
1517 // carrier information, since a locked SIM prevents shill from obtaining
1518 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001519 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001520 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1521 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001522 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1523 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1524 cellular()->dbus_owner()));
1525 DBusPropertiesMap properties(
1526 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1527 OnSimPropertiesChanged(properties, vector<string>());
1528 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001529}
1530
1531void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1532 const DBusPropertiesMap &properties,
1533 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001534 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001535 uint32 uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001536 string imei;
1537 if (DBusProperties::GetString(properties,
1538 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1539 &imei))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001540 cellular()->set_imei(imei);
Jason Glasgowaf583282012-04-18 15:18:22 -04001541
1542 // Handle registration state changes as a single change
1543 string operator_code = serving_operator_.GetCode();
1544 string operator_name = serving_operator_.GetName();
1545 MMModem3gppRegistrationState state = registration_state_;
1546 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001547 if (DBusProperties::GetUint32(properties,
1548 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1549 &uint_value)) {
1550 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1551 registration_changed = true;
1552 }
1553 if (DBusProperties::GetString(properties,
1554 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1555 &operator_code))
1556 registration_changed = true;
1557 if (DBusProperties::GetString(properties,
1558 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1559 &operator_name))
1560 registration_changed = true;
1561 if (registration_changed)
1562 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001563 if (DBusProperties::GetUint32(properties,
1564 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1565 &uint_value))
1566 On3GPPSubscriptionStateChanged(
1567 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001568
Thieu Le43ce4d42013-10-04 16:08:55 -07001569 uint32 subscription_state;
1570 CellularServiceRefPtr service = cellular()->service();
1571 if (service.get() &&
1572 DBusProperties::GetUint32(properties,
1573 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1574 &subscription_state)) {
Thieu Le28492142014-04-08 16:41:13 -07001575 SLOG(Cellular, 3) << __func__ << ": Subscription state = "
Thieu Le43ce4d42013-10-04 16:08:55 -07001576 << subscription_state;
1577 service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1578 subscription_state);
1579 }
1580
Jason Glasgowaf583282012-04-18 15:18:22 -04001581 uint32 locks = 0;
1582 if (DBusProperties::GetUint32(
1583 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1584 &locks))
1585 OnFacilityLocksChanged(locks);
1586}
1587
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001588void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1589 MMModem3gppRegistrationState state,
1590 const string &operator_code,
1591 const string &operator_name) {
Thieu Le28492142014-04-08 16:41:13 -07001592 SLOG(Cellular, 3) << __func__ << ": regstate=" << state
Ben Chanfad4a0b2012-04-18 15:49:59 -07001593 << ", opercode=" << operator_code
1594 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001595
1596 // While the modem is connected, if the state changed from a registered state
1597 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001598 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1599 IsRegistered() && !IsRegisteredState(state)) {
1600 if (!registration_dropped_update_callback_.IsCancelled()) {
1601 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1602 << "Ignoring earlier notifications.";
1603 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001604 } else {
1605 // This is not a repeated post. So, count this instance of delayed drop
1606 // posted.
1607 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001608 }
1609 SLOG(Cellular, 2) << "Posted deferred registration state update";
1610 registration_dropped_update_callback_.Reset(
1611 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1612 weak_ptr_factory_.GetWeakPtr(),
1613 state,
1614 operator_code,
1615 operator_name));
1616 cellular()->dispatcher()->PostDelayedTask(
1617 registration_dropped_update_callback_.callback(),
1618 registration_dropped_update_timeout_milliseconds_);
1619 } else {
1620 if (!registration_dropped_update_callback_.IsCancelled()) {
1621 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1622 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001623 // If we cancelled the callback here, it means we had flaky network for a
1624 // small duration.
1625 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001626 }
1627 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1628 }
1629}
1630
1631void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1632 MMModem3gppRegistrationState updated_state,
1633 string updated_operator_code,
1634 string updated_operator_name) {
1635 // A finished callback does not qualify as a canceled callback.
1636 // We test for a canceled callback to check for outstanding callbacks.
1637 // So, explicitly cancel the callback here.
1638 registration_dropped_update_callback_.Cancel();
1639
Thieu Le28492142014-04-08 16:41:13 -07001640 SLOG(Cellular, 3) << __func__ << ": regstate=" << updated_state
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001641 << ", opercode=" << updated_operator_code
1642 << ", opername=" << updated_operator_name;
1643
1644 registration_state_ = updated_state;
1645 serving_operator_.SetCode(updated_operator_code);
1646 serving_operator_.SetName(updated_operator_name);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001647 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1648 cellular()->serving_operator_info()->UpdateOperatorName(
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001649 updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001650
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001651 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001652
Arman Ugurayc7b15602013-02-16 00:56:18 -08001653 // If the modem registered with the network and the current ICCID is pending
1654 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001655 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001656}
1657
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001658void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1659 MMModem3gppSubscriptionState updated_state) {
Thieu Le28492142014-04-08 16:41:13 -07001660 SLOG(Cellular, 3) << __func__ << ": Updated subscription state = "
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001661 << updated_state;
1662
1663 // A one-to-one enum mapping.
Thieu Le314581f2014-02-19 13:02:47 -08001664 SubscriptionState new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001665 switch (updated_state) {
1666 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
Thieu Le314581f2014-02-19 13:02:47 -08001667 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001668 break;
1669 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001670 new_subscription_state = kSubscriptionStateProvisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001671 break;
1672 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001673 new_subscription_state = kSubscriptionStateUnprovisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001674 break;
1675 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
Thieu Le314581f2014-02-19 13:02:47 -08001676 new_subscription_state = kSubscriptionStateOutOfData;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001677 break;
1678 default:
1679 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1680 << updated_state;
Thieu Le314581f2014-02-19 13:02:47 -08001681 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001682 return;
1683 }
Thieu Le314581f2014-02-19 13:02:47 -08001684 if (new_subscription_state == subscription_state_)
1685 return;
1686
1687 subscription_state_ = new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001688
1689 UpdateServiceActivationState();
1690 UpdatePendingActivationState();
1691}
1692
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001693void CellularCapabilityUniversal::OnModemStateChangedSignal(
1694 int32 old_state, int32 new_state, uint32 reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07001695 Cellular::ModemState old_modem_state =
1696 static_cast<Cellular::ModemState>(old_state);
1697 Cellular::ModemState new_modem_state =
1698 static_cast<Cellular::ModemState>(new_state);
Thieu Le28492142014-04-08 16:41:13 -07001699 SLOG(Cellular, 3) << __func__ << "("
Ben Chanf45b3232013-10-08 20:54:01 -07001700 << Cellular::GetModemStateString(old_modem_state) << ", "
1701 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001702 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001703}
1704
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001705void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1706 cellular()->HandleNewSignalQuality(quality);
1707}
1708
Jason Glasgowaf583282012-04-18 15:18:22 -04001709void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001710 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1711 if (sim_lock_status_.enabled != sim_enabled) {
1712 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04001713 OnSimLockStatusChanged();
1714 }
1715}
Jason Glasgowef965562012-04-10 16:12:35 -04001716
Jason Glasgowaf583282012-04-18 15:18:22 -04001717void CellularCapabilityUniversal::OnSimPropertiesChanged(
1718 const DBusPropertiesMap &props,
1719 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001720 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001721 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001722 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1723 OnSimIdentifierChanged(value);
1724 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1725 &value))
1726 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001727 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1728 OnSpnChanged(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001729 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001730 cellular()->set_imsi(value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001731 cellular()->home_provider_info()->UpdateIMSI(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001732 }
Arman Ugurayd73783f2013-01-31 16:11:21 -08001733}
Jason Glasgowaf583282012-04-18 15:18:22 -04001734
Arman Ugurayd73783f2013-01-31 16:11:21 -08001735void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1736 spn_ = spn;
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001737 cellular()->home_provider_info()->UpdateOperatorName(spn);
Jason Glasgowaf583282012-04-18 15:18:22 -04001738}
1739
1740void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -08001741 cellular()->set_sim_identifier(id);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001742 cellular()->home_provider_info()->UpdateICCID(id);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001743 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001744}
1745
1746void CellularCapabilityUniversal::OnOperatorIdChanged(
1747 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001748 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001749 cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
Jason Glasgowaf583282012-04-18 15:18:22 -04001750}
1751
Thieu Le43ce4d42013-10-04 16:08:55 -07001752OutOfCreditsDetector::OOCType
1753CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
Thieu Lec466ccb2014-06-23 15:24:56 -07001754 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le43ce4d42013-10-04 16:08:55 -07001755 return OutOfCreditsDetector::OOCTypeSubscriptionState;
Thieu Le43ce4d42013-10-04 16:08:55 -07001756 } else {
1757 return OutOfCreditsDetector::OOCTypeNone;
1758 }
1759}
1760
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001761} // namespace shill