blob: eb5dd42695b6eb7d14d6fb8f8b6c43d7ca9e3feb [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 Le43ce4d42013-10-04 16:08:55 -070067const char CellularCapabilityUniversal::kALT3100ModelId[] = "ALT3100";
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;
299 if (cellular()->model_id() == kALT3100ModelId) {
300 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,
1238 MM_MODEM_PROPERTY_REVISION,
1239 &string_value))
1240 OnModemRevisionChanged(string_value);
1241 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1242 // not needed: MM_MODEM_PROPERTY_DEVICE
1243 // not needed: MM_MODEM_PROPERTY_DRIVER
1244 // not needed: MM_MODEM_PROPERTY_PLUGIN
1245 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001246
Jason Glasgowaf583282012-04-18 15:18:22 -04001247 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001248 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001249 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001250 if (DBusProperties::GetUint32(properties,
1251 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001252 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001253 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001254 lock_status_changed = true;
1255 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001256
1257 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001258 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001259 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001260 LockRetryData lock_retries = it->second.operator LockRetryData();
1261 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001262 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001263 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001264
Arman Ugurayea5ff272013-06-25 10:28:02 -07001265 if (lock_status_changed)
1266 OnSimLockStatusChanged();
1267
Jason Glasgowaf583282012-04-18 15:18:22 -04001268 if (DBusProperties::GetUint32(properties,
1269 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1270 &uint_value))
1271 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001272
Jason Glasgowaf583282012-04-18 15:18:22 -04001273 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1274 if (it != properties.end()) {
1275 DBus::Struct<unsigned int, bool> quality = it->second;
1276 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001277 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001278 vector<string> numbers;
1279 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1280 &numbers)) {
1281 string mdn;
1282 if (numbers.size() > 0)
1283 mdn = numbers[0];
1284 OnMdnChanged(mdn);
1285 }
Ben Chan74924d82013-06-15 17:52:55 -07001286
1287 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1288 if (it != properties.end()) {
1289 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1290 vector<ModemModes> supported_modes;
1291 for (const auto &modes : mm_supported_modes) {
1292 supported_modes.push_back(
1293 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1294 }
1295 OnSupportedModesChanged(supported_modes);
1296 }
1297
1298 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1299 if (it != properties.end()) {
1300 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1301 OnCurrentModesChanged(ModemModes(
1302 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1303 }
1304
Jason Glasgowaf583282012-04-18 15:18:22 -04001305 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1306 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001307}
1308
1309void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1310 const string &interface,
1311 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001312 const vector<string> &invalidated_properties) {
Thieu Le28492142014-04-08 16:41:13 -07001313 SLOG(Cellular, 3) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001314 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001315 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001316 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001317 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1318 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001319 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001320 if (interface == MM_DBUS_INTERFACE_SIM) {
1321 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001322 }
1323}
1324
Jason Glasgow14521872012-05-07 19:12:15 -04001325bool CellularCapabilityUniversal::RetriableConnectError(
1326 const Error &error) const {
1327 if (error.type() == Error::kInvalidApn)
1328 return true;
1329
1330 // modemmanager does not ever return kInvalidApn for E362 modems
1331 // with 1.41 firmware. It remains to be seem if this will change
1332 // with 3.x firmware.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001333 if ((cellular()->model_id() == kE362ModelId) &&
1334 (error.type() == Error::kOperationFailed))
Jason Glasgow14521872012-05-07 19:12:15 -04001335 return true;
1336
1337 return false;
1338}
1339
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001340void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1341 // TODO(petkov): Implement this.
1342 NOTIMPLEMENTED();
1343}
1344
Arman Uguray6552f8c2013-02-12 15:33:18 -08001345bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1346 return !sim_path.empty() && sim_path != kRootPath;
1347}
1348
Ben Chand7592522013-02-13 16:02:01 -08001349string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1350 string normalized_mdn;
1351 for (size_t i = 0; i < mdn.size(); ++i) {
1352 if (IsAsciiDigit(mdn[i]))
1353 normalized_mdn += mdn[i];
1354 }
1355 return normalized_mdn;
1356}
1357
Jason Glasgowaf583282012-04-18 15:18:22 -04001358void CellularCapabilityUniversal::OnSimPathChanged(
1359 const string &sim_path) {
1360 if (sim_path == sim_path_)
1361 return;
1362
1363 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001364 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001365 proxy = proxy_factory()->CreateSimProxy(sim_path,
1366 cellular()->dbus_owner());
1367 sim_path_ = sim_path;
1368 sim_proxy_.reset(proxy);
1369
Arman Uguray6552f8c2013-02-12 15:33:18 -08001370 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001371 // Clear all data about the sim
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001372 cellular()->set_imsi("");
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001373 spn_ = "";
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001374 cellular()->set_sim_present(false);
Jason Glasgowaf583282012-04-18 15:18:22 -04001375 OnSimIdentifierChanged("");
1376 OnOperatorIdChanged("");
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001377 cellular()->home_provider_info()->Reset();
Jason Glasgowaf583282012-04-18 15:18:22 -04001378 } else {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001379 cellular()->set_sim_present(true);
Jason Glasgowaf583282012-04-18 15:18:22 -04001380 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1381 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1382 cellular()->dbus_owner()));
1383 // TODO(jglasgow): convert to async interface
1384 DBusPropertiesMap properties(
1385 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1386 OnSimPropertiesChanged(properties, vector<string>());
1387 }
1388}
1389
Ben Chan74924d82013-06-15 17:52:55 -07001390void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1391 const vector<uint32> &supported_capabilities) {
1392 supported_capabilities_ = supported_capabilities;
1393}
1394
Jason Glasgowaf583282012-04-18 15:18:22 -04001395void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1396 uint32 current_capabilities) {
1397 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001398
1399 // Only allow network scan when the modem's current capabilities support
1400 // GSM/UMTS.
1401 //
1402 // TODO(benchan): We should consider having the modem plugins in ModemManager
1403 // reporting whether network scan is supported.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001404 cellular()->set_scanning_supported(
1405 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
Jason Glasgowaf583282012-04-18 15:18:22 -04001406}
1407
1408void CellularCapabilityUniversal::OnMdnChanged(
1409 const string &mdn) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001410 cellular()->set_mdn(NormalizeMdn(mdn));
Arman Uguray0a3e2792013-01-17 16:31:50 -08001411 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001412}
1413
Jason Glasgowaf583282012-04-18 15:18:22 -04001414void CellularCapabilityUniversal::OnModemRevisionChanged(
1415 const string &revision) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001416 cellular()->set_firmware_revision(revision);
Jason Glasgowaf583282012-04-18 15:18:22 -04001417}
1418
1419void CellularCapabilityUniversal::OnModemStateChanged(
1420 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001421 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001422
Ben Chan539ab022014-02-03 16:34:57 -08001423 if (state == Cellular::kModemStateConnected) {
1424 // This assumes that ModemManager updates the Bearers list and the Bearer
1425 // properties before changing Modem state to Connected.
1426 SLOG(Cellular, 2) << "Update active bearer.";
1427 UpdateActiveBearer();
1428 }
1429
Arman Uguray1ee93912013-09-24 21:24:10 -07001430 cellular()->OnModemStateChanged(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001431 // TODO(armansito): Move the deferred enable logic to Cellular
1432 // (See crbug.com/279499).
1433 if (!deferred_enable_modem_callback_.is_null() &&
1434 state == Cellular::kModemStateDisabled) {
1435 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1436 deferred_enable_modem_callback_.Run();
1437 deferred_enable_modem_callback_.Reset();
mukesh agrawal510cc802013-08-15 18:31:42 -07001438 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001439}
1440
1441void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1442 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001443 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001444 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001445 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001446 const string new_type_string(GetTypeString());
1447 if (new_type_string != old_type_string) {
1448 // TODO(jglasgow): address layering violation of emitting change
1449 // signal here for a property owned by Cellular.
1450 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001451 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001452 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001453 if (cellular()->service().get()) {
1454 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1455 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001456 }
1457}
1458
Ben Chan74924d82013-06-15 17:52:55 -07001459void CellularCapabilityUniversal::OnSupportedModesChanged(
1460 const vector<ModemModes> &supported_modes) {
1461 supported_modes_ = supported_modes;
1462}
1463
1464void CellularCapabilityUniversal::OnCurrentModesChanged(
1465 const ModemModes &current_modes) {
1466 current_modes_ = current_modes;
1467}
1468
Ben Chancbef8122014-01-06 17:31:30 -08001469void CellularCapabilityUniversal::OnBearersChanged(
1470 const RpcIdentifiers &bearers) {
1471 bearer_paths_ = bearers;
1472}
1473
Jason Glasgowaf583282012-04-18 15:18:22 -04001474void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001475 const LockRetryData &lock_retries) {
Thieu Le28492142014-04-08 16:41:13 -07001476 SLOG(Cellular, 3) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001477
Arman Ugurayea5ff272013-06-25 10:28:02 -07001478 // Look for the retries left for the current lock. Try the obtain the count
1479 // that matches the current count. If no count for the current lock is
1480 // available, report the first one in the dictionary.
1481 LockRetryData::const_iterator it =
1482 lock_retries.find(sim_lock_status_.lock_type);
1483 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001484 it = lock_retries.begin();
1485 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001486 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001487 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001488 // Unknown, use 999
1489 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001490}
1491
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001492void CellularCapabilityUniversal::OnLockTypeChanged(
1493 MMModemLock lock_type) {
Thieu Le28492142014-04-08 16:41:13 -07001494 SLOG(Cellular, 3) << __func__ << ": " << lock_type;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001495 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001496
1497 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1498 // This is because the corresponding property 'EnabledFacilityLocks' is on
1499 // the 3GPP interface and the 3GPP interface is not available while the Modem
1500 // is in the 'LOCKED' state.
1501 if (lock_type != MM_MODEM_LOCK_NONE &&
1502 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1503 !sim_lock_status_.enabled)
1504 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001505}
1506
Jason Glasgowaf583282012-04-18 15:18:22 -04001507void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Thieu Le28492142014-04-08 16:41:13 -07001508 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001509 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001510 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001511
1512 // If the SIM is currently unlocked, assume that we need to refresh
1513 // carrier information, since a locked SIM prevents shill from obtaining
1514 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001515 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001516 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1517 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001518 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1519 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1520 cellular()->dbus_owner()));
1521 DBusPropertiesMap properties(
1522 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1523 OnSimPropertiesChanged(properties, vector<string>());
1524 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001525}
1526
1527void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1528 const DBusPropertiesMap &properties,
1529 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001530 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001531 uint32 uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001532 string imei;
1533 if (DBusProperties::GetString(properties,
1534 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1535 &imei))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001536 cellular()->set_imei(imei);
Jason Glasgowaf583282012-04-18 15:18:22 -04001537
1538 // Handle registration state changes as a single change
1539 string operator_code = serving_operator_.GetCode();
1540 string operator_name = serving_operator_.GetName();
1541 MMModem3gppRegistrationState state = registration_state_;
1542 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001543 if (DBusProperties::GetUint32(properties,
1544 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1545 &uint_value)) {
1546 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1547 registration_changed = true;
1548 }
1549 if (DBusProperties::GetString(properties,
1550 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1551 &operator_code))
1552 registration_changed = true;
1553 if (DBusProperties::GetString(properties,
1554 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1555 &operator_name))
1556 registration_changed = true;
1557 if (registration_changed)
1558 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001559 if (DBusProperties::GetUint32(properties,
1560 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1561 &uint_value))
1562 On3GPPSubscriptionStateChanged(
1563 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001564
Thieu Le43ce4d42013-10-04 16:08:55 -07001565 uint32 subscription_state;
1566 CellularServiceRefPtr service = cellular()->service();
1567 if (service.get() &&
1568 DBusProperties::GetUint32(properties,
1569 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1570 &subscription_state)) {
Thieu Le28492142014-04-08 16:41:13 -07001571 SLOG(Cellular, 3) << __func__ << ": Subscription state = "
Thieu Le43ce4d42013-10-04 16:08:55 -07001572 << subscription_state;
1573 service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1574 subscription_state);
1575 }
1576
Jason Glasgowaf583282012-04-18 15:18:22 -04001577 uint32 locks = 0;
1578 if (DBusProperties::GetUint32(
1579 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1580 &locks))
1581 OnFacilityLocksChanged(locks);
1582}
1583
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001584void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1585 MMModem3gppRegistrationState state,
1586 const string &operator_code,
1587 const string &operator_name) {
Thieu Le28492142014-04-08 16:41:13 -07001588 SLOG(Cellular, 3) << __func__ << ": regstate=" << state
Ben Chanfad4a0b2012-04-18 15:49:59 -07001589 << ", opercode=" << operator_code
1590 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001591
1592 // While the modem is connected, if the state changed from a registered state
1593 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001594 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1595 IsRegistered() && !IsRegisteredState(state)) {
1596 if (!registration_dropped_update_callback_.IsCancelled()) {
1597 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1598 << "Ignoring earlier notifications.";
1599 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001600 } else {
1601 // This is not a repeated post. So, count this instance of delayed drop
1602 // posted.
1603 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001604 }
1605 SLOG(Cellular, 2) << "Posted deferred registration state update";
1606 registration_dropped_update_callback_.Reset(
1607 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1608 weak_ptr_factory_.GetWeakPtr(),
1609 state,
1610 operator_code,
1611 operator_name));
1612 cellular()->dispatcher()->PostDelayedTask(
1613 registration_dropped_update_callback_.callback(),
1614 registration_dropped_update_timeout_milliseconds_);
1615 } else {
1616 if (!registration_dropped_update_callback_.IsCancelled()) {
1617 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1618 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001619 // If we cancelled the callback here, it means we had flaky network for a
1620 // small duration.
1621 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001622 }
1623 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1624 }
1625}
1626
1627void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1628 MMModem3gppRegistrationState updated_state,
1629 string updated_operator_code,
1630 string updated_operator_name) {
1631 // A finished callback does not qualify as a canceled callback.
1632 // We test for a canceled callback to check for outstanding callbacks.
1633 // So, explicitly cancel the callback here.
1634 registration_dropped_update_callback_.Cancel();
1635
Thieu Le28492142014-04-08 16:41:13 -07001636 SLOG(Cellular, 3) << __func__ << ": regstate=" << updated_state
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001637 << ", opercode=" << updated_operator_code
1638 << ", opername=" << updated_operator_name;
1639
1640 registration_state_ = updated_state;
1641 serving_operator_.SetCode(updated_operator_code);
1642 serving_operator_.SetName(updated_operator_name);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001643 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1644 cellular()->serving_operator_info()->UpdateOperatorName(
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001645 updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001646
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001647 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001648
Arman Ugurayc7b15602013-02-16 00:56:18 -08001649 // If the modem registered with the network and the current ICCID is pending
1650 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001651 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001652}
1653
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001654void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1655 MMModem3gppSubscriptionState updated_state) {
Thieu Le28492142014-04-08 16:41:13 -07001656 SLOG(Cellular, 3) << __func__ << ": Updated subscription state = "
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001657 << updated_state;
1658
1659 // A one-to-one enum mapping.
Thieu Le314581f2014-02-19 13:02:47 -08001660 SubscriptionState new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001661 switch (updated_state) {
1662 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
Thieu Le314581f2014-02-19 13:02:47 -08001663 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001664 break;
1665 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001666 new_subscription_state = kSubscriptionStateProvisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001667 break;
1668 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001669 new_subscription_state = kSubscriptionStateUnprovisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001670 break;
1671 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
Thieu Le314581f2014-02-19 13:02:47 -08001672 new_subscription_state = kSubscriptionStateOutOfData;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001673 break;
1674 default:
1675 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1676 << updated_state;
Thieu Le314581f2014-02-19 13:02:47 -08001677 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001678 return;
1679 }
Thieu Le314581f2014-02-19 13:02:47 -08001680 if (new_subscription_state == subscription_state_)
1681 return;
1682
1683 subscription_state_ = new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001684
1685 UpdateServiceActivationState();
1686 UpdatePendingActivationState();
1687}
1688
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001689void CellularCapabilityUniversal::OnModemStateChangedSignal(
1690 int32 old_state, int32 new_state, uint32 reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07001691 Cellular::ModemState old_modem_state =
1692 static_cast<Cellular::ModemState>(old_state);
1693 Cellular::ModemState new_modem_state =
1694 static_cast<Cellular::ModemState>(new_state);
Thieu Le28492142014-04-08 16:41:13 -07001695 SLOG(Cellular, 3) << __func__ << "("
Ben Chanf45b3232013-10-08 20:54:01 -07001696 << Cellular::GetModemStateString(old_modem_state) << ", "
1697 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001698 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001699}
1700
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001701void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1702 cellular()->HandleNewSignalQuality(quality);
1703}
1704
Jason Glasgowaf583282012-04-18 15:18:22 -04001705void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001706 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1707 if (sim_lock_status_.enabled != sim_enabled) {
1708 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04001709 OnSimLockStatusChanged();
1710 }
1711}
Jason Glasgowef965562012-04-10 16:12:35 -04001712
Jason Glasgowaf583282012-04-18 15:18:22 -04001713void CellularCapabilityUniversal::OnSimPropertiesChanged(
1714 const DBusPropertiesMap &props,
1715 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001716 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001717 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001718 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1719 OnSimIdentifierChanged(value);
1720 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1721 &value))
1722 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001723 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1724 OnSpnChanged(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001725 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001726 cellular()->set_imsi(value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001727 cellular()->home_provider_info()->UpdateIMSI(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001728 }
Arman Ugurayd73783f2013-01-31 16:11:21 -08001729}
Jason Glasgowaf583282012-04-18 15:18:22 -04001730
Arman Ugurayd73783f2013-01-31 16:11:21 -08001731void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1732 spn_ = spn;
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001733 cellular()->home_provider_info()->UpdateOperatorName(spn);
Jason Glasgowaf583282012-04-18 15:18:22 -04001734}
1735
1736void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -08001737 cellular()->set_sim_identifier(id);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001738 cellular()->home_provider_info()->UpdateICCID(id);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001739 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001740}
1741
1742void CellularCapabilityUniversal::OnOperatorIdChanged(
1743 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001744 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001745 cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
Jason Glasgowaf583282012-04-18 15:18:22 -04001746}
1747
Thieu Le43ce4d42013-10-04 16:08:55 -07001748OutOfCreditsDetector::OOCType
1749CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001750 const string &model_id = cellular()->model_id();
1751 if (model_id == kALT3100ModelId) {
Thieu Le43ce4d42013-10-04 16:08:55 -07001752 return OutOfCreditsDetector::OOCTypeSubscriptionState;
Thieu Le43ce4d42013-10-04 16:08:55 -07001753 } else {
1754 return OutOfCreditsDetector::OOCTypeNone;
1755 }
1756}
1757
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001758} // namespace shill