blob: 49b3b1e7bb1d255a149a5ad793ea38cfba82436c [file] [log] [blame]
Arman Uguray72fab6a2013-01-10 19:32:42 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/cellular_capability_universal.h"
6
7#include <base/bind.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04008#include <base/stl_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -08009#include <base/strings/string_util.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070010#include <base/strings/stringprintf.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040011#include <chromeos/dbus/service_constants.h>
Ben Chan5c853ef2012-10-05 00:05:37 -070012#include <ModemManager/ModemManager.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040013
14#include <string>
15#include <vector>
16
17#include "shill/adaptor_interfaces.h"
Ben Chan539ab022014-02-03 16:34:57 -080018#include "shill/cellular_bearer.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040019#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040020#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040021#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070022#include "shill/logging.h"
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -070023#include "shill/mobile_operator_info.h"
Arman Uguray41cc6342013-03-29 16:34:39 -070024#include "shill/pending_activation_store.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040025#include "shill/property_accessor.h"
26#include "shill/proxy_factory.h"
27
28#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
29#error "Do not include mm-modem.h"
30#endif
31
Jason Glasgow82f9ab32012-04-04 14:27:19 -040032using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040033using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040034using std::string;
35using std::vector;
36
37namespace shill {
38
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";
Ben Chan7fab8972014-08-10 17:14:46 -070050const int64_t
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070051CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
52 20000;
Ben Chan7fab8972014-08-10 17:14:46 -070053const int64_t CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
54const int64_t
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070055CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
56 15000;
Arman Uguray6552f8c2013-02-12 15:33:18 -080057const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040058const char CellularCapabilityUniversal::kStatusProperty[] = "status";
59const char CellularCapabilityUniversal::kOperatorLongProperty[] =
60 "operator-long";
61const char CellularCapabilityUniversal::kOperatorShortProperty[] =
62 "operator-short";
63const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
64 "operator-code";
65const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
66 "access-technology";
Thieu Lec466ccb2014-06-23 15:24:56 -070067const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE";
Jason Glasgow14521872012-05-07 19:12:15 -040068const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080069const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
70 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040071
Ben Chan07193fd2013-07-12 22:10:55 -070072namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040073
Ben Chan07193fd2013-07-12 22:10:55 -070074const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040075
Prathmesh Prabhu3b66bb92014-05-22 11:15:25 -070076// This identifier is specified in the additional_providers.prototxt file.
Prathmesh Prabhu5089a6e2014-05-07 20:49:16 -070077const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751";
Ben Chan07193fd2013-07-12 22:10:55 -070078const size_t kVzwMdnLength = 10;
79
Ben Chan7fab8972014-08-10 17:14:46 -070080string AccessTechnologyToString(uint32_t 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 Chan7fab8972014-08-10 17:14:46 -0700107string AccessTechnologyToTechnologyFamily(uint32_t access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400108 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
109 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
110 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
111 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
112 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
113 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
114 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
115 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
116 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
117 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700118 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400119 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800120 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
121 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400122 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700123 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400124 return "";
125}
126
Ben Chan07193fd2013-07-12 22:10:55 -0700127} // namespace
128
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400129CellularCapabilityUniversal::CellularCapabilityUniversal(
130 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800131 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700132 ModemInfo *modem_info)
133 : CellularCapability(cellular, proxy_factory, modem_info),
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700134 mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(),
135 "ParseScanResult")),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400136 weak_ptr_factory_(this),
137 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200138 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400139 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800140 resetting_(false),
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700141 subscription_state_(kSubscriptionStateUnknown),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800142 reset_done_(false),
Arman Uguraya14941d2013-04-12 16:58:26 -0700143 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700144 kActivationRegistrationTimeoutMilliseconds),
145 registration_dropped_update_timeout_milliseconds_(
146 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700147 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Prathmesh Prabhuafe63662014-05-20 11:03:58 -0700148 mobile_operator_info_->Init();
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700149 HelpRegisterConstDerivedKeyValueStore(
Ben Chan7ea768e2013-09-20 15:08:40 -0700150 kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700151 &CellularCapabilityUniversal::SimLockStatusToProperty);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400152}
153
Ben Chanf98f00e2014-02-05 14:48:43 -0800154CellularCapabilityUniversal::~CellularCapabilityUniversal() {}
155
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400156KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
157 Error */*error*/) {
158 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700159 string lock_type;
160 switch (sim_lock_status_.lock_type) {
161 case MM_MODEM_LOCK_SIM_PIN:
162 lock_type = "sim-pin";
163 break;
164 case MM_MODEM_LOCK_SIM_PUK:
165 lock_type = "sim-puk";
166 break;
167 default:
168 lock_type = "";
169 break;
170 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700171 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
172 status.SetString(kSIMLockTypeProperty, lock_type);
173 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400174 return status;
175}
176
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700177void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400178 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700179 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400180 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
181 name,
182 KeyValueStoreAccessor(
183 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700184 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400185}
186
187void CellularCapabilityUniversal::InitProxies() {
188 modem_3gpp_proxy_.reset(
189 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
190 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400191 modem_proxy_.reset(
192 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
193 cellular()->dbus_owner()));
194 modem_simple_proxy_.reset(
195 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
196 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800197
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400198 modem_proxy_->set_state_changed_callback(
199 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
200 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400201 // Do not create a SIM proxy until the device is enabled because we
202 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400203 // TODO(jglasgow): register callbacks
204}
205
206void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400207 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700208 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400209 InitProxies();
Ben Chan151d4472013-09-06 13:29:46 -0700210 deferred_enable_modem_callback_.Reset();
211 EnableModem(true, error, callback);
Gary Moraine285a842012-08-15 08:23:57 -0700212}
213
Ben Chan151d4472013-09-06 13:29:46 -0700214void CellularCapabilityUniversal::EnableModem(bool deferrable,
215 Error *error,
Gary Moraine285a842012-08-15 08:23:57 -0700216 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700217 SLOG(Cellular, 3) << __func__ << "(deferrable=" << deferrable << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400218 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700219 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700220 modem_info()->metrics()->NotifyDeviceEnableStarted(
221 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400222 modem_proxy_->Enable(
223 true,
Gary Moraine285a842012-08-15 08:23:57 -0700224 &local_error,
Ben Chan151d4472013-09-06 13:29:46 -0700225 Bind(&CellularCapabilityUniversal::EnableModemCompleted,
226 weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
Jason Glasgowef965562012-04-10 16:12:35 -0400227 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700228 if (local_error.IsFailure()) {
229 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700230 }
231 if (error) {
232 error->CopyFrom(local_error);
233 }
Jason Glasgowef965562012-04-10 16:12:35 -0400234}
235
Ben Chan151d4472013-09-06 13:29:46 -0700236void CellularCapabilityUniversal::EnableModemCompleted(
237 bool deferrable, const ResultCallback &callback, const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700238 SLOG(Cellular, 3) << __func__ << "(deferrable=" << deferrable
Ben Chan151d4472013-09-06 13:29:46 -0700239 << ", error=" << error << ")";
Thieu Leb9c05e02013-03-04 14:09:32 -0800240
Ben Chan151d4472013-09-06 13:29:46 -0700241 // If the enable operation failed with Error::kWrongState, the modem is not
242 // in the expected state (i.e. disabled). If |deferrable| indicates that the
243 // enable operation can be deferred, we defer the operation until the modem
244 // goes into the expected state (see OnModemStateChangedSignal).
245 //
246 // Note that when the SIM is locked, the enable operation also fails with
247 // Error::kWrongState. The enable operation is deferred until the modem goes
248 // into the disabled state after the SIM is unlocked. We may choose not to
249 // defer the enable operation when the SIM is locked, but the UI needs to
250 // trigger the enable operation after the SIM is unlocked, which is currently
251 // not the case.
Jason Glasgowef965562012-04-10 16:12:35 -0400252 if (error.IsFailure()) {
Ben Chan151d4472013-09-06 13:29:46 -0700253 if (!deferrable || error.type() != Error::kWrongState) {
254 callback.Run(error);
255 return;
256 }
257
258 if (deferred_enable_modem_callback_.is_null()) {
259 SLOG(Cellular, 2) << "Defer enable operation.";
260 // The Enable operation to be deferred should not be further deferrable.
261 deferred_enable_modem_callback_ =
262 Bind(&CellularCapabilityUniversal::EnableModem,
263 weak_ptr_factory_.GetWeakPtr(),
264 false, // non-deferrable
265 static_cast<Error*>(NULL),
266 callback);
267 }
Jason Glasgowef965562012-04-10 16:12:35 -0400268 return;
269 }
270
271 // After modem is enabled, it should be possible to get properties
272 // TODO(jglasgow): handle errors from GetProperties
273 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800274 // We expect the modem to start scanning after it has been enabled.
275 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700276 modem_info()->metrics()->NotifyDeviceEnableFinished(
277 cellular()->interface_index());
278 modem_info()->metrics()->NotifyDeviceScanStarted(
279 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800280 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400281}
282
283void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400284 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400285 CHECK(!callback.is_null());
286 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700287 // If there is an outstanding registration change, simply ignore it since
288 // the service will be destroyed anyway.
289 if (!registration_dropped_update_callback_.IsCancelled()) {
290 registration_dropped_update_callback_.Cancel();
291 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
292 }
293
Thieu Le28492142014-04-08 16:41:13 -0700294 // Some modems will implicitly disconnect the bearer when transitioning to
295 // low power state. For such modems, it's faster to let the modem disconnect
296 // the bearer. To do that, we just remove the bearer from the list so
297 // ModemManager doesn't try to disconnect it during disable.
298 Closure task;
Thieu Lec466ccb2014-06-23 15:24:56 -0700299 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le28492142014-04-08 16:41:13 -0700300 task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer,
301 weak_ptr_factory_.GetWeakPtr(),
302 callback);
303 } else {
304 task = Bind(&CellularCapabilityUniversal::Stop_Disable,
305 weak_ptr_factory_.GetWeakPtr(),
306 callback);
307 }
Ben Chan9de146f2013-09-11 13:11:31 -0700308 cellular()->dispatcher()->PostTask(task);
Gary Moraine285a842012-08-15 08:23:57 -0700309 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400310}
311
Thieu Le28492142014-04-08 16:41:13 -0700312void CellularCapabilityUniversal::Stop_DeleteActiveBearer(
313 const ResultCallback &callback) {
314 SLOG(Cellular, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700315
316 if (!active_bearer_) {
317 Stop_Disable(callback);
318 return;
319 }
320
Thieu Le28492142014-04-08 16:41:13 -0700321 Error error;
322 modem_proxy_->DeleteBearer(
323 active_bearer_->dbus_path(), &error,
324 Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted,
325 weak_ptr_factory_.GetWeakPtr(), callback),
326 kTimeoutDefault);
327 if (error.IsFailure())
328 callback.Run(error);
329}
330
331void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted(
332 const ResultCallback &callback, const Error &error) {
333 SLOG(Cellular, 3) << __func__;
Thieu Leb0074e82014-04-15 14:28:21 -0700334 // Disregard the error from the bearer deletion since the disable will clean
335 // up any remaining bearers.
336 Stop_Disable(callback);
Thieu Le28492142014-04-08 16:41:13 -0700337}
338
Jason Glasgowef965562012-04-10 16:12:35 -0400339void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700340 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400341 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700342 modem_info()->metrics()->NotifyDeviceDisableStarted(
343 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400344 modem_proxy_->Enable(
345 false, &error,
346 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
347 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400348 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400349 if (error.IsFailure())
350 callback.Run(error);
351}
352
353void CellularCapabilityUniversal::Stop_DisableCompleted(
354 const ResultCallback &callback, const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700355 SLOG(Cellular, 3) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400356
Thieu Lea2519bf2013-01-23 16:51:54 -0800357 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800358 // The modem has been successfully disabled, but we still need to power it
359 // down.
360 Stop_PowerDown(callback);
361 } else {
362 // An error occurred; terminate the disable sequence.
363 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800364 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800365}
366
367void CellularCapabilityUniversal::Stop_PowerDown(
368 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700369 SLOG(Cellular, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800370 Error error;
371 modem_proxy_->SetPowerState(
372 MM_MODEM_POWER_STATE_LOW,
373 &error,
374 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
375 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800376 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800377
378 if (error.IsFailure())
379 // This really shouldn't happen, but if it does, report success,
380 // because a stop initiated power down is only called if the
381 // modem was successfully disabled, but the failure of this
382 // operation should still be propagated up as a successful disable.
383 Stop_PowerDownCompleted(callback, error);
384}
385
mukesh agrawal28185512013-10-18 16:57:09 -0700386// Note: if we were in the middle of powering down the modem when the
387// system suspended, we might not get this event from
388// ModemManager. And we might not even get a timeout from dbus-c++,
389// because StartModem re-initializes proxies.
Arman Ugurayee464d32013-02-13 17:14:36 -0800390void CellularCapabilityUniversal::Stop_PowerDownCompleted(
391 const ResultCallback &callback,
392 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700393 SLOG(Cellular, 3) << __func__;
Arman Ugurayee464d32013-02-13 17:14:36 -0800394
395 if (error.IsFailure())
396 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
397
398 // Since the disable succeeded, if power down fails, we currently fail
399 // silently, i.e. we need to report the disable operation as having
400 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700401 modem_info()->metrics()->NotifyDeviceDisableFinished(
402 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800403 ReleaseProxies();
404 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400405}
406
407void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
408 Error *error,
409 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700410 SLOG(Cellular, 3) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400411 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
412 weak_ptr_factory_.GetWeakPtr(),
413 callback);
414 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400415}
416
417void CellularCapabilityUniversal::Disconnect(Error *error,
418 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700419 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700420 // If a deferred registration loss request exists, process it.
421 if (!registration_dropped_update_callback_.IsCancelled()) {
422 registration_dropped_update_callback_.callback().Run();
423 DCHECK(cellular()->state() != Cellular::kStateConnected &&
424 cellular()->state() != Cellular::kStateLinked);
425 SLOG(Cellular, 1) << "Processed deferred registration loss before "
426 << "disconnect request.";
427 }
Ben Chan539ab022014-02-03 16:34:57 -0800428 if (modem_simple_proxy_.get()) {
429 SLOG(Cellular, 2) << "Disconnect all bearers.";
430 // If "/" is passed as the bearer path, ModemManager will disconnect all
431 // bearers.
432 modem_simple_proxy_->Disconnect(DBus::Path(kRootPath),
Thieu Le5d6864a2012-07-20 11:43:51 -0700433 error,
434 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800435 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700436 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400437}
438
Arman Uguraya14941d2013-04-12 16:58:26 -0700439void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
Thieu Le28492142014-04-08 16:41:13 -0700440 SLOG(Cellular, 3) << __func__;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800441 const string &sim_identifier = cellular()->sim_identifier();
442 if (sim_identifier.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700443 modem_info()->pending_activation_store()->GetActivationState(
444 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800445 sim_identifier) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700446 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
447 return;
448 }
449 if (IsMdnValid()) {
450 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
451 return;
452 }
453 if (reset_done_) {
454 SLOG(Cellular, 2) << "Already done with reset.";
455 return;
456 }
457
458 // Still not activated after timeout. Reset the modem.
459 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
460 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700461 modem_info()->pending_activation_store()->SetActivationState(
462 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800463 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700464 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700465 ResetAfterActivation();
466}
467
Arman Ugurayc7b15602013-02-16 00:56:18 -0800468void CellularCapabilityUniversal::CompleteActivation(Error *error) {
Thieu Le28492142014-04-08 16:41:13 -0700469 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800470
471 // Persist the ICCID as "Pending Activation".
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800472 // We're assuming that when this function gets called,
473 // |cellular()->sim_identifier()| will be non-empty. We still check here that
474 // is non-empty, though something is wrong if it is empty.
475 const string &sim_identifier = cellular()->sim_identifier();
476 if (sim_identifier.empty()) {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800477 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
478 return;
479 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800480
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700481 if (IsMdnValid()) {
482 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
483 return;
484 }
485
Arman Ugurayefea6e02013-02-21 13:28:04 -0800486 // There should be a cellular service at this point.
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700487 if (cellular()->service().get()) {
488 if (cellular()->service()->activation_state() == kActivationStateActivated)
489 return;
490
Ben Chan7ea768e2013-09-20 15:08:40 -0700491 cellular()->service()->SetActivationState(kActivationStateActivating);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700492 }
Arman Uguray41cc6342013-03-29 16:34:39 -0700493 modem_info()->pending_activation_store()->SetActivationState(
494 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800495 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700496 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700497
498 activation_wait_for_registration_callback_.Reset(
499 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
500 weak_ptr_factory_.GetWeakPtr()));
501 cellular()->dispatcher()->PostDelayedTask(
502 activation_wait_for_registration_callback_.callback(),
503 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800504}
505
506void CellularCapabilityUniversal::ResetAfterActivation() {
Thieu Le28492142014-04-08 16:41:13 -0700507 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800508
509 // Here the initial call to Reset might fail in rare cases. Simply ignore.
510 Error error;
511 ResultCallback callback = Bind(
512 &CellularCapabilityUniversal::OnResetAfterActivationReply,
513 weak_ptr_factory_.GetWeakPtr());
514 Reset(&error, callback);
515 if (error.IsFailure())
516 SLOG(Cellular, 2) << "Failed to reset after activation.";
517}
518
519void CellularCapabilityUniversal::OnResetAfterActivationReply(
520 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700521 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800522 if (error.IsFailure()) {
523 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
524 // TODO(armansito): Maybe post a delayed reset task?
525 return;
526 }
527 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700528 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800529 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800530}
531
Arman Uguray0a3e2792013-01-17 16:31:50 -0800532void CellularCapabilityUniversal::UpdatePendingActivationState() {
Thieu Le28492142014-04-08 16:41:13 -0700533 SLOG(Cellular, 3) << __func__;
Arman Ugurayc7b15602013-02-16 00:56:18 -0800534
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800535 const string &sim_identifier = cellular()->sim_identifier();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800536 bool registered =
537 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
538
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700539 // We know a service is activated if |subscription_state_| is
540 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
541 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
542 // fallback on checking for a valid MDN.
543 bool activated =
544 ((subscription_state_ == kSubscriptionStateProvisioned) ||
545 (subscription_state_ == kSubscriptionStateOutOfData)) ||
546 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
547
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800548 if (activated && !sim_identifier.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700549 modem_info()->pending_activation_store()->RemoveEntry(
550 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800551 sim_identifier);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800552
Arman Ugurayefea6e02013-02-21 13:28:04 -0800553 CellularServiceRefPtr service = cellular()->service();
554
555 if (!service.get())
556 return;
557
Ben Chan7ea768e2013-09-20 15:08:40 -0700558 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800559 // Either no service or already activated. Nothing to do.
560 return;
561
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700562 // Besides the indicators above, a connected service also indicates an
563 // activated SIM.
564 if (activated || cellular()->state() == Cellular::kStateConnected ||
Arman Ugurayc7b15602013-02-16 00:56:18 -0800565 cellular()->state() == Cellular::kStateLinked) {
566 SLOG(Cellular, 2) << "Marking service as activated.";
Ben Chan7ea768e2013-09-20 15:08:40 -0700567 service->SetActivationState(kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800568 return;
569 }
570
571 // If the ICCID is not available, the following logic can be delayed until it
572 // becomes available.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800573 if (sim_identifier.empty())
Arman Ugurayefea6e02013-02-21 13:28:04 -0800574 return;
575
Arman Uguray41cc6342013-03-29 16:34:39 -0700576 PendingActivationStore::State state =
577 modem_info()->pending_activation_store()->GetActivationState(
578 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800579 sim_identifier);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800580 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700581 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800582 // Always mark the service as activating here, as the ICCID could have
583 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700584 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800585 if (reset_done_) {
586 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700587 modem_info()->pending_activation_store()->SetActivationState(
588 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800589 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700590 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800591 } else if (registered) {
592 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700593 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800594 ResetAfterActivation();
595 }
596 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700597 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800598 if (registered) {
599 // Trigger auto connect here.
600 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
601 << "autoconnect to force MDN to update.";
602 service->AutoConnect();
603 }
604 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700605 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700606 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
607 << "been reset at least once.";
608 if (registered) {
609 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700610 modem_info()->pending_activation_store()->SetActivationState(
611 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800612 sim_identifier,
Arman Uguray41cc6342013-03-29 16:34:39 -0700613 PendingActivationStore::kStateActivated);
Ben Chan7ea768e2013-09-20 15:08:40 -0700614 service->SetActivationState(kActivationStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700615 }
616 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700617 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800618 // No entry exists for this ICCID. Nothing to do.
619 break;
620 default:
621 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800622 }
623}
624
Ben Chan07193fd2013-07-12 22:10:55 -0700625string CellularCapabilityUniversal::GetMdnForOLP(
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700626 const MobileOperatorInfo *operator_info) const {
Ben Chan07193fd2013-07-12 22:10:55 -0700627 // TODO(benchan): This is ugly. Remove carrier specific code once we move
628 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800629 const string &mdn = cellular()->mdn();
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700630 if (!operator_info->IsMobileNetworkOperatorKnown()) {
631 // Can't make any carrier specific modifications.
632 return mdn;
633 }
634
635 if (operator_info->uuid() == kVzwIdentifier) {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700636 // subscription_state_ is the definitive indicator of whether we need
637 // activation. The OLP expects an all zero MDN in that case.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800638 if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) {
Ben Chan200591a2013-08-07 14:39:04 -0700639 return string(kVzwMdnLength, '0');
640 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800641 if (mdn.length() > kVzwMdnLength) {
642 return mdn.substr(mdn.length() - kVzwMdnLength);
Ben Chan200591a2013-08-07 14:39:04 -0700643 }
Ben Chan07193fd2013-07-12 22:10:55 -0700644 }
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800645 return mdn;
Ben Chan07193fd2013-07-12 22:10:55 -0700646}
647
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400648void CellularCapabilityUniversal::ReleaseProxies() {
Thieu Le28492142014-04-08 16:41:13 -0700649 SLOG(Cellular, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400650 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400651 modem_proxy_.reset();
652 modem_simple_proxy_.reset();
653 sim_proxy_.reset();
654}
655
Thieu Le63881a72014-07-28 17:28:36 -0700656bool CellularCapabilityUniversal::AreProxiesInitialized() const {
657 return (modem_3gpp_proxy_.get() && modem_proxy_.get() &&
658 modem_simple_proxy_.get() && sim_proxy_.get());
659}
660
Arman Ugurayefea6e02013-02-21 13:28:04 -0800661void CellularCapabilityUniversal::UpdateServiceActivationState() {
662 if (!cellular()->service().get())
663 return;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800664
665 const string &sim_identifier = cellular()->sim_identifier();
Ben Chan3d6de0e2012-12-10 12:01:34 -0800666 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700667 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700668 PendingActivationStore::State state =
669 modem_info()->pending_activation_store()->GetActivationState(
670 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800671 sim_identifier);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700672 if ((subscription_state_ == kSubscriptionStateUnknown ||
673 subscription_state_ == kSubscriptionStateUnprovisioned) &&
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800674 !sim_identifier.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700675 (state == PendingActivationStore::kStatePending ||
Alex Vakulenko8a532292014-06-16 17:18:44 -0700676 state == PendingActivationStore::kStatePendingTimeout)) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700677 activation_state = kActivationStateActivating;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700678 } else if (activation_required) {
Ben Chan7ea768e2013-09-20 15:08:40 -0700679 activation_state = kActivationStateNotActivated;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700680 } else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700681 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700682
683 // Mark an activated service for auto-connect by default. Since data from
684 // the user profile will be loaded after the call to OnServiceCreated, this
685 // property will be corrected based on the user data at that time.
Thieu Le247416e2014-02-25 18:19:53 -0800686 // NOTE: This function can be called outside the service initialization
687 // path so make sure we don't overwrite the auto-connect setting.
688 if (cellular()->service()->activation_state() != activation_state)
689 cellular()->service()->SetAutoConnect(true);
Arman Uguray6bb252d2013-05-15 14:29:53 -0700690 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800691 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800692 // TODO(benchan): For now, assume the cellular service is activated over
693 // a non-cellular network if service activation is required (i.e. a
694 // corresponding entry is found in the cellular operator info file).
695 // We will need to generalize this logic when migrating CDMA support from
696 // cromo to ModemManager.
697 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800698}
699
700void CellularCapabilityUniversal::OnServiceCreated() {
Thieu Le71f81a62014-07-11 15:17:47 -0700701 cellular()->service()->SetActivationType(CellularService::kActivationTypeOTA);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800702 UpdateServiceActivationState();
Thieu Le398b1da2013-03-11 17:31:10 -0700703
704 // WORKAROUND:
705 // E362 modems on Verizon network does not properly redirect when a SIM
706 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700707 //
708 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
709 // support is ready (crosbug.com/p/20461).
Thieu Le43ce4d42013-10-04 16:08:55 -0700710 cellular()->service()->InitOutOfCreditsDetection(
711 GetOutOfCreditsDetectionType());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700712
713 // Make sure that the network technology is set when the service gets
714 // created, just in case.
715 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400716}
717
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400718// Create the list of APNs to try, in the following order:
719// - last APN that resulted in a successful connection attempt on the
720// current network (if any)
721// - the APN, if any, that was set by the user
722// - the list of APNs found in the mobile broadband provider DB for the
723// home provider associated with the current SIM
724// - as a last resort, attempt to connect with no APN
725void CellularCapabilityUniversal::SetupApnTryList() {
726 apn_try_list_.clear();
727
728 DCHECK(cellular()->service().get());
729 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
730 if (apn_info)
731 apn_try_list_.push_back(*apn_info);
732
733 apn_info = cellular()->service()->GetUserSpecifiedApn();
734 if (apn_info)
735 apn_try_list_.push_back(*apn_info);
736
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800737 apn_try_list_.insert(apn_try_list_.end(),
738 cellular()->apn_list().begin(),
739 cellular()->apn_list().end());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400740}
741
742void CellularCapabilityUniversal::SetupConnectProperties(
743 DBusPropertiesMap *properties) {
744 SetupApnTryList();
745 FillConnectPropertyMap(properties);
746}
747
748void CellularCapabilityUniversal::FillConnectPropertyMap(
749 DBusPropertiesMap *properties) {
750
751 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400752 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400753 kPhoneNumber);
754
Jason Glasgow14521872012-05-07 19:12:15 -0400755 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400756 AllowRoaming());
757
758 if (!apn_try_list_.empty()) {
759 // Leave the APN at the front of the list, so that it can be recorded
760 // if the connect attempt succeeds.
761 Stringmap apn_info = apn_try_list_.front();
Ben Chan7ea768e2013-09-20 15:08:40 -0700762 SLOG(Cellular, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400763 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700764 apn_info[kApnProperty].c_str());
765 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400766 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700767 apn_info[kApnUsernameProperty].c_str());
768 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400769 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700770 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400771 }
772}
773
774void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400775 const DBus::Path &path,
776 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700777 SLOG(Cellular, 3) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400778
Jason Glasgow7234ec32012-05-23 16:01:21 -0400779 CellularServiceRefPtr service = cellular()->service();
780 if (!service) {
781 // The service could have been deleted before our Connect() request
782 // completes if the modem was enabled and then quickly disabled.
783 apn_try_list_.clear();
784 } else if (error.IsFailure()) {
785 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400786 // The APN that was just tried (and failed) is still at the
787 // front of the list, about to be removed. If the list is empty
788 // after that, try one last time without an APN. This may succeed
789 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400790 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400791 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700792 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
793 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400794 DBusPropertiesMap props;
795 FillConnectPropertyMap(&props);
796 Error error;
797 Connect(props, &error, callback);
798 return;
799 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400800 } else {
801 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400802 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400803 apn_try_list_.clear();
804 }
Ben Chan539ab022014-02-03 16:34:57 -0800805 SLOG(Cellular, 2) << "Connected bearer " << path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400806 }
807
808 if (!callback.is_null())
809 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800810
Arman Uguray0a3e2792013-01-17 16:31:50 -0800811 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400812}
813
814bool CellularCapabilityUniversal::AllowRoaming() {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800815 return cellular()->provider_requires_roaming() || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400816}
817
Jason Glasgowef965562012-04-10 16:12:35 -0400818void CellularCapabilityUniversal::GetProperties() {
Thieu Le28492142014-04-08 16:41:13 -0700819 SLOG(Cellular, 3) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400820
Jason Glasgowaf583282012-04-18 15:18:22 -0400821 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
822 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
823 cellular()->dbus_owner()));
824 DBusPropertiesMap properties(
825 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
826 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400827
Jason Glasgowaf583282012-04-18 15:18:22 -0400828 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
829 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400830}
831
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700832void CellularCapabilityUniversal::UpdateServiceOLP() {
Thieu Le28492142014-04-08 16:41:13 -0700833 SLOG(Cellular, 3) << __func__;
Ben Chan07193fd2013-07-12 22:10:55 -0700834
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700835 // OLP is based off of the Home Provider.
836 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
Ben Chan07193fd2013-07-12 22:10:55 -0700837 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700838 }
Ben Chan07193fd2013-07-12 22:10:55 -0700839
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700840 const vector<MobileOperatorInfo::OnlinePortal> &olp_list =
841 cellular()->home_provider_info()->olp_list();
842 if (olp_list.empty()) {
Ben Chan6d0d1e72012-11-06 21:19:28 -0800843 return;
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700844 }
Ben Chan6d0d1e72012-11-06 21:19:28 -0800845
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700846 if (olp_list.size() > 1) {
847 SLOG(Cellular, 1) << "Found multiple online portals. Choosing the first.";
848 }
849 string post_data = olp_list[0].post_data;
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800850 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}",
851 cellular()->sim_identifier());
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800852 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", cellular()->imei());
853 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", cellular()->imsi());
Ben Chan07193fd2013-07-12 22:10:55 -0700854 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700855 GetMdnForOLP(cellular()->home_provider_info()));
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800856 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", cellular()->min());
Prathmesh Prabhu92df6192014-04-29 18:08:08 -0700857 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800858}
859
Ben Chan539ab022014-02-03 16:34:57 -0800860void CellularCapabilityUniversal::UpdateActiveBearer() {
861 SLOG(Cellular, 3) << __func__;
862
Arman Uguray6e5639f2012-11-15 20:30:19 -0800863 // Look for the first active bearer and use its path as the connected
864 // one. Right now, we don't allow more than one active bearer.
Ben Chan539ab022014-02-03 16:34:57 -0800865 active_bearer_.reset();
Ben Chancbef8122014-01-06 17:31:30 -0800866 for (const auto &path : bearer_paths_) {
Ben Chan539ab022014-02-03 16:34:57 -0800867 scoped_ptr<CellularBearer> bearer(
868 new CellularBearer(proxy_factory(), path, cellular()->dbus_service()));
869 // The bearer object may have vanished before ModemManager updates the
870 // 'Bearers' property.
871 if (!bearer->Init())
mukesh agrawal9da07772013-05-15 14:15:17 -0700872 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700873
Ben Chan539ab022014-02-03 16:34:57 -0800874 if (!bearer->connected())
Ben Chan5db19692013-07-09 23:07:03 -0700875 continue;
Ben Chan5db19692013-07-09 23:07:03 -0700876
mukesh agrawal9da07772013-05-15 14:15:17 -0700877 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan539ab022014-02-03 16:34:57 -0800878 CHECK(!active_bearer_) << "Found more than one active bearer.";
879 active_bearer_ = bearer.Pass();
Arman Uguray6e5639f2012-11-15 20:30:19 -0800880 }
Ben Chan539ab022014-02-03 16:34:57 -0800881
882 if (!active_bearer_)
mukesh agrawal9da07772013-05-15 14:15:17 -0700883 SLOG(Cellular, 2) << "No active bearer found.";
Arman Uguray6e5639f2012-11-15 20:30:19 -0800884}
885
Ben Chan15786032012-11-04 21:28:02 -0800886bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800887 const string &sim_identifier = cellular()->sim_identifier();
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700888 // subscription_state_ is the definitive answer. If that does not work,
889 // fallback on MDN based logic.
890 if (subscription_state_ == kSubscriptionStateProvisioned ||
891 subscription_state_ == kSubscriptionStateOutOfData)
892 return false;
893
894 // We are in the process of activating, ignore all other clues from the
895 // network and use our own knowledge about the activation state.
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800896 if (!sim_identifier.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700897 modem_info()->pending_activation_store()->GetActivationState(
898 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -0800899 sim_identifier) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800900 return false;
901
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700902 // Network notification that the service needs to be activated.
903 if (subscription_state_ == kSubscriptionStateUnprovisioned)
904 return true;
905
Ben Chan15786032012-11-04 21:28:02 -0800906 // If there is no online payment portal information, it's safer to assume
907 // the service does not require activation.
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700908 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
909 cellular()->home_provider_info()->olp_list().empty()) {
Ben Chan15786032012-11-04 21:28:02 -0800910 return false;
Prathmesh Prabhu3ee2f412014-05-20 17:30:19 -0700911 }
Ben Chan15786032012-11-04 21:28:02 -0800912
Ben Chan200591a2013-08-07 14:39:04 -0700913 // If the MDN is invalid (i.e. empty or contains only zeros), the service
914 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -0800915 return !IsMdnValid();
916}
917
918bool CellularCapabilityUniversal::IsMdnValid() const {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800919 const string &mdn = cellular()->mdn();
920 // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
921 for (size_t i = 0; i < mdn.size(); ++i) {
922 if (mdn[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -0800923 return true;
Ben Chan15786032012-11-04 21:28:02 -0800924 }
Arman Ugurayc7b15602013-02-16 00:56:18 -0800925 return false;
Ben Chan15786032012-11-04 21:28:02 -0800926}
927
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400928// always called from an async context
929void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700930 SLOG(Cellular, 3) << __func__ << " \"" << cellular()->selected_network()
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800931 << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400932 CHECK(!callback.is_null());
933 Error error;
934 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
935 weak_ptr_factory_.GetWeakPtr(), callback);
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800936 modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
937 kTimeoutRegister);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400938 if (error.IsFailure())
939 callback.Run(error);
940}
941
942void CellularCapabilityUniversal::RegisterOnNetwork(
943 const string &network_id,
944 Error *error,
945 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -0700946 SLOG(Cellular, 3) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400947 CHECK(error);
948 desired_network_ = network_id;
949 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
950 weak_ptr_factory_.GetWeakPtr(), callback);
951 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
952}
953
954void CellularCapabilityUniversal::OnRegisterReply(
955 const ResultCallback &callback,
956 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -0700957 SLOG(Cellular, 3) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400958
959 if (error.IsSuccess()) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800960 cellular()->set_selected_network(desired_network_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400961 desired_network_.clear();
962 callback.Run(error);
963 return;
964 }
965 // If registration on the desired network failed,
966 // try to register on the home network.
967 if (!desired_network_.empty()) {
968 desired_network_.clear();
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -0800969 cellular()->set_selected_network("");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400970 LOG(INFO) << "Couldn't register on selected network, trying home network";
971 Register(callback);
972 return;
973 }
974 callback.Run(error);
975}
976
Ben Chan31ce5642013-11-14 13:37:40 -0800977bool CellularCapabilityUniversal::IsRegistered() const {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700978 return IsRegisteredState(registration_state_);
979}
980
981bool CellularCapabilityUniversal::IsRegisteredState(
982 MMModem3gppRegistrationState state) {
983 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
984 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400985}
986
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400987void CellularCapabilityUniversal::SetUnregistered(bool searching) {
988 // If we're already in some non-registered state, don't override that
989 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
990 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
991 registration_state_ =
992 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
993 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
994 }
995}
996
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400997void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400998 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400999 Error *error, const ResultCallback &callback) {
1000 CHECK(error);
1001 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1002}
1003
1004void CellularCapabilityUniversal::EnterPIN(const string &pin,
1005 Error *error,
1006 const ResultCallback &callback) {
1007 CHECK(error);
Thieu Le28492142014-04-08 16:41:13 -07001008 SLOG(Cellular, 3) << __func__;
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001009 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001010}
1011
1012void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1013 const string &pin,
1014 Error *error,
1015 const ResultCallback &callback) {
1016 CHECK(error);
1017 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1018}
1019
1020void CellularCapabilityUniversal::ChangePIN(
1021 const string &old_pin, const string &new_pin,
1022 Error *error, const ResultCallback &callback) {
1023 CHECK(error);
1024 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1025}
1026
Ben Chan5d0d32c2013-01-08 02:05:29 -08001027void CellularCapabilityUniversal::Reset(Error *error,
1028 const ResultCallback &callback) {
Thieu Le28492142014-04-08 16:41:13 -07001029 SLOG(Cellular, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -08001030 CHECK(error);
1031 if (resetting_) {
1032 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1033 return;
1034 }
1035 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1036 weak_ptr_factory_.GetWeakPtr(), callback);
1037 modem_proxy_->Reset(error, cb, kTimeoutReset);
1038 if (!error->IsFailure()) {
1039 resetting_ = true;
1040 }
1041}
1042
1043void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1044 const Error &error) {
Thieu Le28492142014-04-08 16:41:13 -07001045 SLOG(Cellular, 3) << __func__;
Ben Chan5d0d32c2013-01-08 02:05:29 -08001046 resetting_ = false;
1047 if (!callback.is_null())
1048 callback.Run(error);
1049}
1050
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001051void CellularCapabilityUniversal::Scan(
1052 Error *error,
1053 const ResultStringmapsCallback &callback) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001054 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1055 weak_ptr_factory_.GetWeakPtr(), callback);
1056 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
1057}
1058
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001059void CellularCapabilityUniversal::OnScanReply(
1060 const ResultStringmapsCallback &callback,
1061 const ScanResults &results,
1062 const Error &error) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001063 Stringmaps found_networks;
Prathmesh Prabhu49ffffd2014-01-09 18:28:55 -08001064 for (const auto &result : results)
1065 found_networks.push_back(ParseScanResult(result));
1066 callback.Run(found_networks, error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001067}
1068
1069Stringmap CellularCapabilityUniversal::ParseScanResult(
1070 const ScanResult &result) {
1071
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001072 /* ScanResults contain the following keys:
1073
1074 "status"
1075 A MMModem3gppNetworkAvailability value representing network
1076 availability status, given as an unsigned integer (signature "u").
1077 This key will always be present.
1078
1079 "operator-long"
1080 Long-format name of operator, given as a string value (signature
1081 "s"). If the name is unknown, this field should not be present.
1082
1083 "operator-short"
1084 Short-format name of operator, given as a string value
1085 (signature "s"). If the name is unknown, this field should not
1086 be present.
1087
1088 "operator-code"
1089 Mobile code of the operator, given as a string value (signature
1090 "s"). Returned in the format "MCCMNC", where MCC is the
1091 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1092 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1093
1094 "access-technology"
1095 A MMModemAccessTechnology value representing the generic access
1096 technology used by this mobile network, given as an unsigned
1097 integer (signature "u").
1098 */
1099 Stringmap parsed;
1100
Ben Chan7fab8972014-08-10 17:14:46 -07001101 uint32_t status;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001102 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1103 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1104 static const char * const kStatusString[] = {
1105 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1106 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1107 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1108 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1109 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001110 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001111 }
1112
Ben Chan7fab8972014-08-10 17:14:46 -07001113 uint32_t tech; // MMModemAccessTechnology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001114 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1115 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001116 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001117 }
1118
1119 string operator_long, operator_short, operator_code;
1120 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001121 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001122 if (DBusProperties::GetString(result, kOperatorShortProperty,
1123 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001124 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001125 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001126 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001127
1128 // If the long name is not available but the network ID is, look up the long
1129 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001130 if ((!ContainsKey(parsed, kLongNameProperty) ||
1131 parsed[kLongNameProperty].empty()) &&
1132 ContainsKey(parsed, kNetworkIdProperty)) {
Prathmesh Prabhuafe63662014-05-20 11:03:58 -07001133 mobile_operator_info_->Reset();
1134 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
1135 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
1136 !mobile_operator_info_->operator_name().empty()) {
1137 parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001138 }
1139 }
1140 return parsed;
1141}
1142
Ben Chan539ab022014-02-03 16:34:57 -08001143CellularBearer *CellularCapabilityUniversal::GetActiveBearer() const {
1144 return active_bearer_.get();
1145}
1146
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001147string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001148 // If we know that the modem is an E362, return LTE here to make sure that
1149 // Chrome sees LTE as the network technology even if the actual technology is
1150 // unknown.
1151 // TODO(armansito): This hack will cause the UI to display LTE even if the
1152 // modem doesn't support it at a given time. This might be problematic if we
1153 // ever want to support switching between access technologies (e.g. falling
1154 // back to 3G when LTE is not available).
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001155 if (cellular()->model_id() == kE362ModelId)
Ben Chan7ea768e2013-09-20 15:08:40 -07001156 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001157
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001158 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001159 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160 return AccessTechnologyToString(access_technologies_);
1161}
1162
1163string CellularCapabilityUniversal::GetRoamingStateString() const {
1164 switch (registration_state_) {
1165 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001166 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001167 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001168 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001169 default:
1170 break;
1171 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001172 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001173}
1174
Arman Uguray5d9a8522013-09-10 17:43:13 -07001175// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001176void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001177 // ModemManager always returns the cached value, so there is no need to
1178 // trigger an update here. The true value is updated through a property
1179 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001180}
1181
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001182string CellularCapabilityUniversal::GetTypeString() const {
1183 return AccessTechnologyToTechnologyFamily(access_technologies_);
1184}
1185
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001186void CellularCapabilityUniversal::OnModemPropertiesChanged(
1187 const DBusPropertiesMap &properties,
1188 const vector<string> &/* invalidated_properties */) {
Ben Chancbef8122014-01-06 17:31:30 -08001189
1190 // Update the bearers property before the modem state property as
Ben Chan539ab022014-02-03 16:34:57 -08001191 // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
1192 // property.
Ben Chancbef8122014-01-06 17:31:30 -08001193 RpcIdentifiers bearers;
1194 if (DBusProperties::GetRpcIdentifiers(properties, MM_MODEM_PROPERTY_BEARERS,
1195 &bearers)) {
1196 OnBearersChanged(bearers);
1197 }
1198
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001199 // This solves a bootstrapping problem: If the modem is not yet
1200 // enabled, there are no proxy objects associated with the capability
1201 // object, so modem signals like StateChanged aren't seen. By monitoring
1202 // changes to the State property via the ModemManager, we're able to
1203 // get the initialization process started, which will result in the
1204 // creation of the proxy objects.
1205 //
1206 // The first time we see the change to State (when the modem state
1207 // is Unknown), we simply update the state, and rely on the Manager to
1208 // enable the device when it is registered with the Manager. On subsequent
1209 // changes to State, we need to explicitly enable the device ourselves.
Ben Chan7fab8972014-08-10 17:14:46 -07001210 int32_t istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001211 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001212 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001213 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001214 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001215 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001216 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001217 MM_MODEM_PROPERTY_SIM, &object_path_value))
1218 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001219
1220 DBusPropertiesMap::const_iterator it =
1221 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1222 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001223 const vector<uint32_t> &supported_capabilities = it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001224 OnSupportedCapabilitesChanged(supported_capabilities);
1225 }
1226
Ben Chan7fab8972014-08-10 17:14:46 -07001227 uint32_t uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001228 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001229 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1230 &uint_value))
1231 OnModemCurrentCapabilitiesChanged(uint_value);
1232 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1233 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001234 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001235 if (DBusProperties::GetString(properties,
1236 MM_MODEM_PROPERTY_MANUFACTURER,
1237 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001238 cellular()->set_manufacturer(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001239 if (DBusProperties::GetString(properties,
1240 MM_MODEM_PROPERTY_MODEL,
1241 &string_value))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001242 cellular()->set_model_id(string_value);
Jason Glasgowaf583282012-04-18 15:18:22 -04001243 if (DBusProperties::GetString(properties,
Thieu Lec466ccb2014-06-23 15:24:56 -07001244 MM_MODEM_PROPERTY_PLUGIN,
1245 &string_value))
1246 cellular()->set_mm_plugin(string_value);
1247 if (DBusProperties::GetString(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001248 MM_MODEM_PROPERTY_REVISION,
1249 &string_value))
1250 OnModemRevisionChanged(string_value);
1251 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1252 // not needed: MM_MODEM_PROPERTY_DEVICE
1253 // not needed: MM_MODEM_PROPERTY_DRIVER
1254 // not needed: MM_MODEM_PROPERTY_PLUGIN
1255 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001256
Jason Glasgowaf583282012-04-18 15:18:22 -04001257 // Unlock required and SimLock
Ben Chan7fab8972014-08-10 17:14:46 -07001258 uint32_t unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001259 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001260 if (DBusProperties::GetUint32(properties,
1261 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001262 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001263 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001264 lock_status_changed = true;
1265 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001266
1267 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001268 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001269 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001270 LockRetryData lock_retries = it->second.operator LockRetryData();
1271 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001272 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001273 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001274
Arman Ugurayea5ff272013-06-25 10:28:02 -07001275 if (lock_status_changed)
1276 OnSimLockStatusChanged();
1277
Jason Glasgowaf583282012-04-18 15:18:22 -04001278 if (DBusProperties::GetUint32(properties,
1279 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1280 &uint_value))
1281 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001282
Jason Glasgowaf583282012-04-18 15:18:22 -04001283 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1284 if (it != properties.end()) {
1285 DBus::Struct<unsigned int, bool> quality = it->second;
1286 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001287 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001288 vector<string> numbers;
1289 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1290 &numbers)) {
1291 string mdn;
1292 if (numbers.size() > 0)
1293 mdn = numbers[0];
1294 OnMdnChanged(mdn);
1295 }
Ben Chan74924d82013-06-15 17:52:55 -07001296
1297 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1298 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001299 const vector<DBus::Struct<uint32_t, uint32_t>> &mm_supported_modes =
1300 it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001301 vector<ModemModes> supported_modes;
1302 for (const auto &modes : mm_supported_modes) {
1303 supported_modes.push_back(
1304 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1305 }
1306 OnSupportedModesChanged(supported_modes);
1307 }
1308
1309 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1310 if (it != properties.end()) {
Ben Chan7fab8972014-08-10 17:14:46 -07001311 const DBus::Struct<uint32_t, uint32_t> &current_modes = it->second;
Ben Chan74924d82013-06-15 17:52:55 -07001312 OnCurrentModesChanged(ModemModes(
1313 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1314 }
1315
Jason Glasgowaf583282012-04-18 15:18:22 -04001316 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1317 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001318}
1319
1320void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1321 const string &interface,
1322 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001323 const vector<string> &invalidated_properties) {
Thieu Le28492142014-04-08 16:41:13 -07001324 SLOG(Cellular, 3) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001325 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001326 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001327 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001328 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1329 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001330 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001331 if (interface == MM_DBUS_INTERFACE_SIM) {
1332 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001333 }
1334}
1335
Jason Glasgow14521872012-05-07 19:12:15 -04001336bool CellularCapabilityUniversal::RetriableConnectError(
1337 const Error &error) const {
1338 if (error.type() == Error::kInvalidApn)
1339 return true;
1340
1341 // modemmanager does not ever return kInvalidApn for E362 modems
1342 // with 1.41 firmware. It remains to be seem if this will change
1343 // with 3.x firmware.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001344 if ((cellular()->model_id() == kE362ModelId) &&
1345 (error.type() == Error::kOperationFailed))
Jason Glasgow14521872012-05-07 19:12:15 -04001346 return true;
1347
1348 return false;
1349}
1350
Ben Chan7fab8972014-08-10 17:14:46 -07001351void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001352 // TODO(petkov): Implement this.
1353 NOTIMPLEMENTED();
1354}
1355
Arman Uguray6552f8c2013-02-12 15:33:18 -08001356bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1357 return !sim_path.empty() && sim_path != kRootPath;
1358}
1359
Ben Chand7592522013-02-13 16:02:01 -08001360string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1361 string normalized_mdn;
1362 for (size_t i = 0; i < mdn.size(); ++i) {
1363 if (IsAsciiDigit(mdn[i]))
1364 normalized_mdn += mdn[i];
1365 }
1366 return normalized_mdn;
1367}
1368
Jason Glasgowaf583282012-04-18 15:18:22 -04001369void CellularCapabilityUniversal::OnSimPathChanged(
1370 const string &sim_path) {
1371 if (sim_path == sim_path_)
1372 return;
1373
1374 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001375 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001376 proxy = proxy_factory()->CreateSimProxy(sim_path,
1377 cellular()->dbus_owner());
1378 sim_path_ = sim_path;
1379 sim_proxy_.reset(proxy);
1380
Arman Uguray6552f8c2013-02-12 15:33:18 -08001381 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001382 // Clear all data about the sim
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001383 cellular()->set_imsi("");
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001384 spn_ = "";
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001385 cellular()->set_sim_present(false);
Jason Glasgowaf583282012-04-18 15:18:22 -04001386 OnSimIdentifierChanged("");
1387 OnOperatorIdChanged("");
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001388 cellular()->home_provider_info()->Reset();
Jason Glasgowaf583282012-04-18 15:18:22 -04001389 } else {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001390 cellular()->set_sim_present(true);
Jason Glasgowaf583282012-04-18 15:18:22 -04001391 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1392 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1393 cellular()->dbus_owner()));
1394 // TODO(jglasgow): convert to async interface
1395 DBusPropertiesMap properties(
1396 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1397 OnSimPropertiesChanged(properties, vector<string>());
1398 }
1399}
1400
Ben Chan74924d82013-06-15 17:52:55 -07001401void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001402 const vector<uint32_t> &supported_capabilities) {
Ben Chan74924d82013-06-15 17:52:55 -07001403 supported_capabilities_ = supported_capabilities;
1404}
1405
Jason Glasgowaf583282012-04-18 15:18:22 -04001406void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001407 uint32_t current_capabilities) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001408 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001409
1410 // Only allow network scan when the modem's current capabilities support
1411 // GSM/UMTS.
1412 //
1413 // TODO(benchan): We should consider having the modem plugins in ModemManager
1414 // reporting whether network scan is supported.
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001415 cellular()->set_scanning_supported(
1416 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
Jason Glasgowaf583282012-04-18 15:18:22 -04001417}
1418
1419void CellularCapabilityUniversal::OnMdnChanged(
1420 const string &mdn) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001421 cellular()->set_mdn(NormalizeMdn(mdn));
Arman Uguray0a3e2792013-01-17 16:31:50 -08001422 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001423}
1424
Jason Glasgowaf583282012-04-18 15:18:22 -04001425void CellularCapabilityUniversal::OnModemRevisionChanged(
1426 const string &revision) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001427 cellular()->set_firmware_revision(revision);
Jason Glasgowaf583282012-04-18 15:18:22 -04001428}
1429
1430void CellularCapabilityUniversal::OnModemStateChanged(
1431 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001432 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001433
Ben Chan539ab022014-02-03 16:34:57 -08001434 if (state == Cellular::kModemStateConnected) {
1435 // This assumes that ModemManager updates the Bearers list and the Bearer
1436 // properties before changing Modem state to Connected.
1437 SLOG(Cellular, 2) << "Update active bearer.";
1438 UpdateActiveBearer();
1439 }
1440
Arman Uguray1ee93912013-09-24 21:24:10 -07001441 cellular()->OnModemStateChanged(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001442 // TODO(armansito): Move the deferred enable logic to Cellular
1443 // (See crbug.com/279499).
1444 if (!deferred_enable_modem_callback_.is_null() &&
1445 state == Cellular::kModemStateDisabled) {
1446 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1447 deferred_enable_modem_callback_.Run();
1448 deferred_enable_modem_callback_.Reset();
mukesh agrawal510cc802013-08-15 18:31:42 -07001449 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001450}
1451
1452void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
Ben Chan7fab8972014-08-10 17:14:46 -07001453 uint32_t access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001454 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001455 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001456 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001457 const string new_type_string(GetTypeString());
1458 if (new_type_string != old_type_string) {
1459 // TODO(jglasgow): address layering violation of emitting change
1460 // signal here for a property owned by Cellular.
1461 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001462 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001463 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001464 if (cellular()->service().get()) {
1465 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1466 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001467 }
1468}
1469
Ben Chan74924d82013-06-15 17:52:55 -07001470void CellularCapabilityUniversal::OnSupportedModesChanged(
1471 const vector<ModemModes> &supported_modes) {
1472 supported_modes_ = supported_modes;
1473}
1474
1475void CellularCapabilityUniversal::OnCurrentModesChanged(
1476 const ModemModes &current_modes) {
1477 current_modes_ = current_modes;
1478}
1479
Ben Chancbef8122014-01-06 17:31:30 -08001480void CellularCapabilityUniversal::OnBearersChanged(
1481 const RpcIdentifiers &bearers) {
1482 bearer_paths_ = bearers;
1483}
1484
Jason Glasgowaf583282012-04-18 15:18:22 -04001485void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001486 const LockRetryData &lock_retries) {
Thieu Le28492142014-04-08 16:41:13 -07001487 SLOG(Cellular, 3) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001488
Arman Ugurayea5ff272013-06-25 10:28:02 -07001489 // Look for the retries left for the current lock. Try the obtain the count
1490 // that matches the current count. If no count for the current lock is
1491 // available, report the first one in the dictionary.
1492 LockRetryData::const_iterator it =
1493 lock_retries.find(sim_lock_status_.lock_type);
1494 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001495 it = lock_retries.begin();
1496 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001497 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001498 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001499 // Unknown, use 999
1500 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001501}
1502
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001503void CellularCapabilityUniversal::OnLockTypeChanged(
1504 MMModemLock lock_type) {
Thieu Le28492142014-04-08 16:41:13 -07001505 SLOG(Cellular, 3) << __func__ << ": " << lock_type;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001506 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001507
1508 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1509 // This is because the corresponding property 'EnabledFacilityLocks' is on
1510 // the 3GPP interface and the 3GPP interface is not available while the Modem
1511 // is in the 'LOCKED' state.
1512 if (lock_type != MM_MODEM_LOCK_NONE &&
1513 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1514 !sim_lock_status_.enabled)
1515 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001516}
1517
Jason Glasgowaf583282012-04-18 15:18:22 -04001518void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Thieu Le28492142014-04-08 16:41:13 -07001519 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001520 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001521 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001522
1523 // If the SIM is currently unlocked, assume that we need to refresh
1524 // carrier information, since a locked SIM prevents shill from obtaining
1525 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001526 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001527 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1528 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001529 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1530 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1531 cellular()->dbus_owner()));
1532 DBusPropertiesMap properties(
1533 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1534 OnSimPropertiesChanged(properties, vector<string>());
1535 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001536}
1537
1538void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1539 const DBusPropertiesMap &properties,
1540 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001541 SLOG(Cellular, 3) << __func__;
Ben Chan7fab8972014-08-10 17:14:46 -07001542 uint32_t uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001543 string imei;
1544 if (DBusProperties::GetString(properties,
1545 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1546 &imei))
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001547 cellular()->set_imei(imei);
Jason Glasgowaf583282012-04-18 15:18:22 -04001548
1549 // Handle registration state changes as a single change
1550 string operator_code = serving_operator_.GetCode();
1551 string operator_name = serving_operator_.GetName();
1552 MMModem3gppRegistrationState state = registration_state_;
1553 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001554 if (DBusProperties::GetUint32(properties,
1555 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1556 &uint_value)) {
1557 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1558 registration_changed = true;
1559 }
1560 if (DBusProperties::GetString(properties,
1561 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1562 &operator_code))
1563 registration_changed = true;
1564 if (DBusProperties::GetString(properties,
1565 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1566 &operator_name))
1567 registration_changed = true;
1568 if (registration_changed)
1569 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001570 if (DBusProperties::GetUint32(properties,
1571 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1572 &uint_value))
1573 On3GPPSubscriptionStateChanged(
1574 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001575
Ben Chan7fab8972014-08-10 17:14:46 -07001576 uint32_t subscription_state;
Thieu Le43ce4d42013-10-04 16:08:55 -07001577 CellularServiceRefPtr service = cellular()->service();
1578 if (service.get() &&
1579 DBusProperties::GetUint32(properties,
1580 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1581 &subscription_state)) {
Thieu Le28492142014-04-08 16:41:13 -07001582 SLOG(Cellular, 3) << __func__ << ": Subscription state = "
Thieu Le43ce4d42013-10-04 16:08:55 -07001583 << subscription_state;
1584 service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1585 subscription_state);
1586 }
1587
Ben Chan7fab8972014-08-10 17:14:46 -07001588 uint32_t locks = 0;
Jason Glasgowaf583282012-04-18 15:18:22 -04001589 if (DBusProperties::GetUint32(
1590 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1591 &locks))
1592 OnFacilityLocksChanged(locks);
1593}
1594
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001595void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1596 MMModem3gppRegistrationState state,
1597 const string &operator_code,
1598 const string &operator_name) {
Thieu Le28492142014-04-08 16:41:13 -07001599 SLOG(Cellular, 3) << __func__ << ": regstate=" << state
Ben Chanfad4a0b2012-04-18 15:49:59 -07001600 << ", opercode=" << operator_code
1601 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001602
1603 // While the modem is connected, if the state changed from a registered state
1604 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001605 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1606 IsRegistered() && !IsRegisteredState(state)) {
1607 if (!registration_dropped_update_callback_.IsCancelled()) {
1608 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1609 << "Ignoring earlier notifications.";
1610 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001611 } else {
1612 // This is not a repeated post. So, count this instance of delayed drop
1613 // posted.
1614 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001615 }
1616 SLOG(Cellular, 2) << "Posted deferred registration state update";
1617 registration_dropped_update_callback_.Reset(
1618 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1619 weak_ptr_factory_.GetWeakPtr(),
1620 state,
1621 operator_code,
1622 operator_name));
1623 cellular()->dispatcher()->PostDelayedTask(
1624 registration_dropped_update_callback_.callback(),
1625 registration_dropped_update_timeout_milliseconds_);
1626 } else {
1627 if (!registration_dropped_update_callback_.IsCancelled()) {
1628 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1629 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001630 // If we cancelled the callback here, it means we had flaky network for a
1631 // small duration.
1632 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001633 }
1634 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1635 }
1636}
1637
1638void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1639 MMModem3gppRegistrationState updated_state,
1640 string updated_operator_code,
1641 string updated_operator_name) {
1642 // A finished callback does not qualify as a canceled callback.
1643 // We test for a canceled callback to check for outstanding callbacks.
1644 // So, explicitly cancel the callback here.
1645 registration_dropped_update_callback_.Cancel();
1646
Thieu Le28492142014-04-08 16:41:13 -07001647 SLOG(Cellular, 3) << __func__ << ": regstate=" << updated_state
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001648 << ", opercode=" << updated_operator_code
1649 << ", opername=" << updated_operator_name;
1650
1651 registration_state_ = updated_state;
1652 serving_operator_.SetCode(updated_operator_code);
1653 serving_operator_.SetName(updated_operator_name);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001654 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1655 cellular()->serving_operator_info()->UpdateOperatorName(
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001656 updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001657
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001658 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001659
Arman Ugurayc7b15602013-02-16 00:56:18 -08001660 // If the modem registered with the network and the current ICCID is pending
1661 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001662 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001663}
1664
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001665void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1666 MMModem3gppSubscriptionState updated_state) {
Thieu Le28492142014-04-08 16:41:13 -07001667 SLOG(Cellular, 3) << __func__ << ": Updated subscription state = "
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001668 << updated_state;
1669
1670 // A one-to-one enum mapping.
Thieu Le314581f2014-02-19 13:02:47 -08001671 SubscriptionState new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001672 switch (updated_state) {
1673 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
Thieu Le314581f2014-02-19 13:02:47 -08001674 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001675 break;
1676 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001677 new_subscription_state = kSubscriptionStateProvisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001678 break;
1679 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
Thieu Le314581f2014-02-19 13:02:47 -08001680 new_subscription_state = kSubscriptionStateUnprovisioned;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001681 break;
1682 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
Thieu Le314581f2014-02-19 13:02:47 -08001683 new_subscription_state = kSubscriptionStateOutOfData;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001684 break;
1685 default:
1686 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1687 << updated_state;
Thieu Le314581f2014-02-19 13:02:47 -08001688 new_subscription_state = kSubscriptionStateUnknown;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001689 return;
1690 }
Thieu Le314581f2014-02-19 13:02:47 -08001691 if (new_subscription_state == subscription_state_)
1692 return;
1693
1694 subscription_state_ = new_subscription_state;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001695
1696 UpdateServiceActivationState();
1697 UpdatePendingActivationState();
1698}
1699
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001700void CellularCapabilityUniversal::OnModemStateChangedSignal(
Ben Chan7fab8972014-08-10 17:14:46 -07001701 int32_t old_state, int32_t new_state, uint32_t reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07001702 Cellular::ModemState old_modem_state =
1703 static_cast<Cellular::ModemState>(old_state);
1704 Cellular::ModemState new_modem_state =
1705 static_cast<Cellular::ModemState>(new_state);
Thieu Le28492142014-04-08 16:41:13 -07001706 SLOG(Cellular, 3) << __func__ << "("
Ben Chanf45b3232013-10-08 20:54:01 -07001707 << Cellular::GetModemStateString(old_modem_state) << ", "
1708 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001709 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001710}
1711
Ben Chan7fab8972014-08-10 17:14:46 -07001712void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001713 cellular()->HandleNewSignalQuality(quality);
1714}
1715
Ben Chan7fab8972014-08-10 17:14:46 -07001716void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001717 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1718 if (sim_lock_status_.enabled != sim_enabled) {
1719 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04001720 OnSimLockStatusChanged();
1721 }
1722}
Jason Glasgowef965562012-04-10 16:12:35 -04001723
Jason Glasgowaf583282012-04-18 15:18:22 -04001724void CellularCapabilityUniversal::OnSimPropertiesChanged(
1725 const DBusPropertiesMap &props,
1726 const vector<string> &/* invalidated_properties */) {
Thieu Le28492142014-04-08 16:41:13 -07001727 SLOG(Cellular, 3) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001728 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001729 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1730 OnSimIdentifierChanged(value);
1731 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1732 &value))
1733 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001734 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1735 OnSpnChanged(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001736 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
Prathmesh Prabhu9f06c872013-11-21 14:08:23 -08001737 cellular()->set_imsi(value);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001738 cellular()->home_provider_info()->UpdateIMSI(value);
Prathmesh Prabhuc93b6bc2014-07-28 15:20:11 -07001739 // We do not obtain IMSI OTA right now. Provide the value from the SIM to
1740 // serving operator as well, to aid in MVNO identification.
1741 cellular()->serving_operator_info()->UpdateIMSI(value);
Prathmesh Prabhu28b4a3b2014-03-28 11:52:09 -07001742 }
Arman Ugurayd73783f2013-01-31 16:11:21 -08001743}
Jason Glasgowaf583282012-04-18 15:18:22 -04001744
Arman Ugurayd73783f2013-01-31 16:11:21 -08001745void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1746 spn_ = spn;
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001747 cellular()->home_provider_info()->UpdateOperatorName(spn);
Jason Glasgowaf583282012-04-18 15:18:22 -04001748}
1749
1750void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
Prathmesh Prabhu700ff4d2014-01-16 15:59:33 -08001751 cellular()->set_sim_identifier(id);
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001752 cellular()->home_provider_info()->UpdateICCID(id);
Prathmesh Prabhuc93b6bc2014-07-28 15:20:11 -07001753 // Provide ICCID to serving operator as well to aid in MVNO identification.
1754 cellular()->serving_operator_info()->UpdateICCID(id);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001755 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001756}
1757
1758void CellularCapabilityUniversal::OnOperatorIdChanged(
1759 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001760 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Prathmesh Prabhu8599e052014-04-25 14:20:22 -07001761 cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
Jason Glasgowaf583282012-04-18 15:18:22 -04001762}
1763
Thieu Le43ce4d42013-10-04 16:08:55 -07001764OutOfCreditsDetector::OOCType
1765CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
Thieu Lec466ccb2014-06-23 15:24:56 -07001766 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
Thieu Le43ce4d42013-10-04 16:08:55 -07001767 return OutOfCreditsDetector::OOCTypeSubscriptionState;
Thieu Le43ce4d42013-10-04 16:08:55 -07001768 } else {
1769 return OutOfCreditsDetector::OOCTypeNone;
1770 }
1771}
1772
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001773} // namespace shill