blob: 9fcfa3820129bea25b403848e0f2cb05610ca4b9 [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>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04009#include <base/stringprintf.h>
Ben Chan6d0d1e72012-11-06 21:19:28 -080010#include <base/string_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040011#include <chromeos/dbus/service_constants.h>
12#include <mobile_provider.h>
Ben Chan5c853ef2012-10-05 00:05:37 -070013#include <ModemManager/ModemManager.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040014
15#include <string>
16#include <vector>
17
18#include "shill/adaptor_interfaces.h"
19#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"
Arman Uguray41cc6342013-03-29 16:34:39 -070023#include "shill/pending_activation_store.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040024#include "shill/property_accessor.h"
25#include "shill/proxy_factory.h"
26
27#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
28#error "Do not include mm-modem.h"
29#endif
30
Jason Glasgow82f9ab32012-04-04 14:27:19 -040031using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040032using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040033using std::string;
34using std::vector;
35
36namespace shill {
37
38// static
Jason Glasgow14521872012-05-07 19:12:15 -040039const char CellularCapabilityUniversal::kConnectPin[] = "pin";
40const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
Jason Glasgow14521872012-05-07 19:12:15 -040041const char CellularCapabilityUniversal::kConnectApn[] = "apn";
42const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
43const char CellularCapabilityUniversal::kConnectUser[] = "user";
44const char CellularCapabilityUniversal::kConnectPassword[] = "password";
45const char CellularCapabilityUniversal::kConnectNumber[] = "number";
46const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
47 "allow-roaming";
48const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Arman Uguraya14941d2013-04-12 16:58:26 -070049const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070050CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
51 20000;
52const int64
Arman Uguray1361c032013-02-11 17:53:39 -080053CellularCapabilityUniversal::kDefaultScanningOrSearchingTimeoutMilliseconds =
54 60000;
Arman Ugurayf6366ac2013-06-12 16:02:28 -070055const int64 CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
Arman Uguraya14941d2013-04-12 16:58:26 -070056const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070057CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
58 15000;
Arman Uguray2717a102013-01-29 23:36:06 -080059const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
60 "Mobile Network";
Arman Uguray6552f8c2013-02-12 15:33:18 -080061const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040062const char CellularCapabilityUniversal::kStatusProperty[] = "status";
63const char CellularCapabilityUniversal::kOperatorLongProperty[] =
64 "operator-long";
65const char CellularCapabilityUniversal::kOperatorShortProperty[] =
66 "operator-short";
67const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
68 "operator-code";
69const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
70 "access-technology";
mukesh agrawal9da07772013-05-15 14:15:17 -070071const char CellularCapabilityUniversal::kIpConfigPropertyMethod[] = "method";
Ben Chan4ffc03b2013-08-07 17:44:53 -070072const char CellularCapabilityUniversal::kALT3100ModelId[] = "ALT3100";
Jason Glasgow14521872012-05-07 19:12:15 -040073const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080074const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
75 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040076unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
77
Ben Chan07193fd2013-07-12 22:10:55 -070078namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040079
Ben Chan07193fd2013-07-12 22:10:55 -070080const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040081
Ben Chan07193fd2013-07-12 22:10:55 -070082// This identifier is specified in the cellular_operator_info file.
83const char kVzwIdentifier[] = "vzw";
84const size_t kVzwMdnLength = 10;
85
86string AccessTechnologyToString(uint32 access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040087 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
Ben Chan7ea768e2013-09-20 15:08:40 -070088 return kNetworkTechnologyLte;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040089 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
90 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
91 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
Ben Chan7ea768e2013-09-20 15:08:40 -070092 return kNetworkTechnologyEvdo;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
Ben Chan7ea768e2013-09-20 15:08:40 -070094 return kNetworkTechnology1Xrtt;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040095 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
Ben Chan7ea768e2013-09-20 15:08:40 -070096 return kNetworkTechnologyHspaPlus;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040097 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
Ben Chan7ea768e2013-09-20 15:08:40 -0700100 return kNetworkTechnologyHspa;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400101 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700102 return kNetworkTechnologyUmts;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400103 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
Ben Chan7ea768e2013-09-20 15:08:40 -0700104 return kNetworkTechnologyEdge;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400105 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700106 return kNetworkTechnologyGprs;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400107 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
108 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700109 return kNetworkTechnologyGsm;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400110 return "";
111}
112
Ben Chan07193fd2013-07-12 22:10:55 -0700113string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400114 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
118 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
119 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
120 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
121 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
122 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
123 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700124 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400125 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800126 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
127 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400128 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700129 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400130 return "";
131}
132
Ben Chan07193fd2013-07-12 22:10:55 -0700133} // namespace
134
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400135CellularCapabilityUniversal::CellularCapabilityUniversal(
136 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800137 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700138 ModemInfo *modem_info)
139 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400140 weak_ptr_factory_(this),
141 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200142 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400143 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
144 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200145 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800146 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800147 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400148 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800149 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700150 scan_interval_(0),
Arman Uguray1361c032013-02-11 17:53:39 -0800151 sim_present_(false),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800152 reset_done_(false),
Arman Uguray1361c032013-02-11 17:53:39 -0800153 scanning_or_searching_timeout_milliseconds_(
Arman Uguraya14941d2013-04-12 16:58:26 -0700154 kDefaultScanningOrSearchingTimeoutMilliseconds),
155 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700156 kActivationRegistrationTimeoutMilliseconds),
157 registration_dropped_update_timeout_milliseconds_(
158 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700159 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160 PropertyStore *store = cellular->mutable_store();
161
Ben Chan7ea768e2013-09-20 15:08:40 -0700162 store->RegisterConstString(kCarrierProperty, &carrier_);
163 store->RegisterConstBool(kSupportNetworkScanProperty, &scanning_supported_);
164 store->RegisterConstString(kEsnProperty, &esn_);
165 store->RegisterConstString(kFirmwareRevisionProperty, &firmware_revision_);
166 store->RegisterConstString(kHardwareRevisionProperty, &hardware_revision_);
167 store->RegisterConstString(kImeiProperty, &imei_);
168 store->RegisterConstString(kImsiProperty, &imsi_);
169 store->RegisterConstString(kIccidProperty, &sim_identifier_);
170 store->RegisterConstString(kManufacturerProperty, &manufacturer_);
171 store->RegisterConstString(kMdnProperty, &mdn_);
172 store->RegisterConstString(kMeidProperty, &meid_);
173 store->RegisterConstString(kMinProperty, &min_);
174 store->RegisterConstString(kModelIDProperty, &model_id_);
175 store->RegisterConstString(kSelectedNetworkProperty, &selected_network_);
176 store->RegisterConstStringmaps(kFoundNetworksProperty, &found_networks_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700177 store->RegisterConstBool(kProviderRequiresRoamingProperty,
Darin Petkovf508c822012-09-21 13:43:17 +0200178 &provider_requires_roaming_);
Ben Chan7ea768e2013-09-20 15:08:40 -0700179 store->RegisterConstBool(kScanningProperty, &scanning_or_searching_);
180 store->RegisterUint16(kScanIntervalProperty, &scan_interval_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700181 HelpRegisterConstDerivedKeyValueStore(
Ben Chan7ea768e2013-09-20 15:08:40 -0700182 kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700183 &CellularCapabilityUniversal::SimLockStatusToProperty);
Ben Chan39a7beb2013-09-21 11:28:00 -0700184 store->RegisterConstString(kSIMOperatorIdProperty, &operator_id_);
185 store->RegisterConstBool(kSIMPresentProperty, &sim_present_);
Ben Chan7ea768e2013-09-20 15:08:40 -0700186 store->RegisterConstStringmaps(kCellularApnListProperty, &apn_list_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400187}
188
189KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
190 Error */*error*/) {
191 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700192 string lock_type;
193 switch (sim_lock_status_.lock_type) {
194 case MM_MODEM_LOCK_SIM_PIN:
195 lock_type = "sim-pin";
196 break;
197 case MM_MODEM_LOCK_SIM_PUK:
198 lock_type = "sim-puk";
199 break;
200 default:
201 lock_type = "";
202 break;
203 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700204 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
205 status.SetString(kSIMLockTypeProperty, lock_type);
206 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400207 return status;
208}
209
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700210void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400211 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700212 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400213 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
214 name,
215 KeyValueStoreAccessor(
216 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700217 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400218}
219
220void CellularCapabilityUniversal::InitProxies() {
221 modem_3gpp_proxy_.reset(
222 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
223 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400224 modem_proxy_.reset(
225 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
226 cellular()->dbus_owner()));
227 modem_simple_proxy_.reset(
228 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
229 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800230
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400231 modem_proxy_->set_state_changed_callback(
232 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
233 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400234 // Do not create a SIM proxy until the device is enabled because we
235 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400236 // TODO(jglasgow): register callbacks
237}
238
239void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400240 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700241 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400242 InitProxies();
Ben Chan151d4472013-09-06 13:29:46 -0700243 deferred_enable_modem_callback_.Reset();
244 EnableModem(true, error, callback);
Gary Moraine285a842012-08-15 08:23:57 -0700245}
246
Ben Chan151d4472013-09-06 13:29:46 -0700247void CellularCapabilityUniversal::EnableModem(bool deferrable,
248 Error *error,
Gary Moraine285a842012-08-15 08:23:57 -0700249 const ResultCallback &callback) {
Ben Chan151d4472013-09-06 13:29:46 -0700250 SLOG(Cellular, 2) << __func__ << "(deferrable=" << deferrable << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400251 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700252 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700253 modem_info()->metrics()->NotifyDeviceEnableStarted(
254 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400255 modem_proxy_->Enable(
256 true,
Gary Moraine285a842012-08-15 08:23:57 -0700257 &local_error,
Ben Chan151d4472013-09-06 13:29:46 -0700258 Bind(&CellularCapabilityUniversal::EnableModemCompleted,
259 weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
Jason Glasgowef965562012-04-10 16:12:35 -0400260 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700261 if (local_error.IsFailure()) {
262 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700263 }
264 if (error) {
265 error->CopyFrom(local_error);
266 }
Jason Glasgowef965562012-04-10 16:12:35 -0400267}
268
Ben Chan151d4472013-09-06 13:29:46 -0700269void CellularCapabilityUniversal::EnableModemCompleted(
270 bool deferrable, const ResultCallback &callback, const Error &error) {
271 SLOG(Cellular, 2) << __func__ << "(deferrable=" << deferrable
272 << ", error=" << error << ")";
Thieu Leb9c05e02013-03-04 14:09:32 -0800273
Ben Chan151d4472013-09-06 13:29:46 -0700274 // If the enable operation failed with Error::kWrongState, the modem is not
275 // in the expected state (i.e. disabled). If |deferrable| indicates that the
276 // enable operation can be deferred, we defer the operation until the modem
277 // goes into the expected state (see OnModemStateChangedSignal).
278 //
279 // Note that when the SIM is locked, the enable operation also fails with
280 // Error::kWrongState. The enable operation is deferred until the modem goes
281 // into the disabled state after the SIM is unlocked. We may choose not to
282 // defer the enable operation when the SIM is locked, but the UI needs to
283 // trigger the enable operation after the SIM is unlocked, which is currently
284 // not the case.
Jason Glasgowef965562012-04-10 16:12:35 -0400285 if (error.IsFailure()) {
Ben Chan151d4472013-09-06 13:29:46 -0700286 if (!deferrable || error.type() != Error::kWrongState) {
287 callback.Run(error);
288 return;
289 }
290
291 if (deferred_enable_modem_callback_.is_null()) {
292 SLOG(Cellular, 2) << "Defer enable operation.";
293 // The Enable operation to be deferred should not be further deferrable.
294 deferred_enable_modem_callback_ =
295 Bind(&CellularCapabilityUniversal::EnableModem,
296 weak_ptr_factory_.GetWeakPtr(),
297 false, // non-deferrable
298 static_cast<Error*>(NULL),
299 callback);
300 }
Jason Glasgowef965562012-04-10 16:12:35 -0400301 return;
302 }
303
304 // After modem is enabled, it should be possible to get properties
305 // TODO(jglasgow): handle errors from GetProperties
306 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800307 // We expect the modem to start scanning after it has been enabled.
308 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700309 modem_info()->metrics()->NotifyDeviceEnableFinished(
310 cellular()->interface_index());
311 modem_info()->metrics()->NotifyDeviceScanStarted(
312 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800313 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400314}
315
316void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400317 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400318 CHECK(!callback.is_null());
319 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700320 // If there is an outstanding registration change, simply ignore it since
321 // the service will be destroyed anyway.
322 if (!registration_dropped_update_callback_.IsCancelled()) {
323 registration_dropped_update_callback_.Cancel();
324 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
325 }
326
Ben Chan9de146f2013-09-11 13:11:31 -0700327 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
328 weak_ptr_factory_.GetWeakPtr(),
329 callback);
330 cellular()->dispatcher()->PostTask(task);
Gary Moraine285a842012-08-15 08:23:57 -0700331 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400332}
333
Jason Glasgowef965562012-04-10 16:12:35 -0400334void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
335 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700336 modem_info()->metrics()->NotifyDeviceDisableStarted(
337 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400338 modem_proxy_->Enable(
339 false, &error,
340 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
341 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400342 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400343 if (error.IsFailure())
344 callback.Run(error);
345}
346
347void CellularCapabilityUniversal::Stop_DisableCompleted(
348 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700349 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400350
Thieu Lea2519bf2013-01-23 16:51:54 -0800351 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800352 // The modem has been successfully disabled, but we still need to power it
353 // down.
354 Stop_PowerDown(callback);
355 } else {
356 // An error occurred; terminate the disable sequence.
357 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800358 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800359}
360
361void CellularCapabilityUniversal::Stop_PowerDown(
362 const ResultCallback &callback) {
363 SLOG(Cellular, 2) << __func__;
364 Error error;
365 modem_proxy_->SetPowerState(
366 MM_MODEM_POWER_STATE_LOW,
367 &error,
368 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
369 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800370 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800371
372 if (error.IsFailure())
373 // This really shouldn't happen, but if it does, report success,
374 // because a stop initiated power down is only called if the
375 // modem was successfully disabled, but the failure of this
376 // operation should still be propagated up as a successful disable.
377 Stop_PowerDownCompleted(callback, error);
378}
379
380void CellularCapabilityUniversal::Stop_PowerDownCompleted(
381 const ResultCallback &callback,
382 const Error &error) {
383 SLOG(Cellular, 2) << __func__;
384
385 if (error.IsFailure())
386 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
387
388 // Since the disable succeeded, if power down fails, we currently fail
389 // silently, i.e. we need to report the disable operation as having
390 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700391 modem_info()->metrics()->NotifyDeviceDisableFinished(
392 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800393 ReleaseProxies();
394 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400395}
396
397void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
398 Error *error,
399 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700400 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400401 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
402 weak_ptr_factory_.GetWeakPtr(),
403 callback);
404 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400405}
406
407void CellularCapabilityUniversal::Disconnect(Error *error,
408 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700409 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700410 // If a deferred registration loss request exists, process it.
411 if (!registration_dropped_update_callback_.IsCancelled()) {
412 registration_dropped_update_callback_.callback().Run();
413 DCHECK(cellular()->state() != Cellular::kStateConnected &&
414 cellular()->state() != Cellular::kStateLinked);
415 SLOG(Cellular, 1) << "Processed deferred registration loss before "
416 << "disconnect request.";
417 }
Thieu Le5d6864a2012-07-20 11:43:51 -0700418 if (bearer_path_.empty()) {
419 LOG(WARNING) << "In " << __func__ << "(): "
420 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700421 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700422 modem_simple_proxy_->Disconnect(bearer_path_,
423 error,
424 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800425 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700426 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400427}
428
Christopher Wiley8a468902012-11-30 11:52:38 -0800429void CellularCapabilityUniversal::DisconnectCleanup() {
430 SLOG(Cellular, 2) << __func__;
431}
432
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400433void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400434 Error *error,
435 const ResultCallback &callback) {
436 OnUnsupportedOperation(__func__, error);
437}
438
Arman Uguraya14941d2013-04-12 16:58:26 -0700439void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
440 SLOG(Cellular, 2) << __func__;
441 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700442 modem_info()->pending_activation_store()->GetActivationState(
443 PendingActivationStore::kIdentifierICCID,
444 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700445 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
446 return;
447 }
448 if (IsMdnValid()) {
449 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
450 return;
451 }
452 if (reset_done_) {
453 SLOG(Cellular, 2) << "Already done with reset.";
454 return;
455 }
456
457 // Still not activated after timeout. Reset the modem.
458 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
459 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700460 modem_info()->pending_activation_store()->SetActivationState(
461 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700462 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700463 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700464 ResetAfterActivation();
465}
466
Arman Ugurayc7b15602013-02-16 00:56:18 -0800467void CellularCapabilityUniversal::CompleteActivation(Error *error) {
468 SLOG(Cellular, 2) << __func__;
469
470 // Persist the ICCID as "Pending Activation".
471 // We're assuming that when this function gets called, |sim_identifier_| will
472 // be non-empty. We still check here that is non-empty, though something is
473 // wrong if it is empty.
474 if (IsMdnValid()) {
475 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
476 return;
477 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800478
Arman Ugurayc7b15602013-02-16 00:56:18 -0800479 if (sim_identifier_.empty()) {
480 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
481 return;
482 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800483
484 // There should be a cellular service at this point.
485 if (cellular()->service().get())
Ben Chan7ea768e2013-09-20 15:08:40 -0700486 cellular()->service()->SetActivationState(kActivationStateActivating);
Arman Uguray41cc6342013-03-29 16:34:39 -0700487 modem_info()->pending_activation_store()->SetActivationState(
488 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800489 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700490 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700491
492 activation_wait_for_registration_callback_.Reset(
493 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
494 weak_ptr_factory_.GetWeakPtr()));
495 cellular()->dispatcher()->PostDelayedTask(
496 activation_wait_for_registration_callback_.callback(),
497 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800498}
499
500void CellularCapabilityUniversal::ResetAfterActivation() {
501 SLOG(Cellular, 2) << __func__;
502
503 // Here the initial call to Reset might fail in rare cases. Simply ignore.
504 Error error;
505 ResultCallback callback = Bind(
506 &CellularCapabilityUniversal::OnResetAfterActivationReply,
507 weak_ptr_factory_.GetWeakPtr());
508 Reset(&error, callback);
509 if (error.IsFailure())
510 SLOG(Cellular, 2) << "Failed to reset after activation.";
511}
512
513void CellularCapabilityUniversal::OnResetAfterActivationReply(
514 const Error &error) {
515 SLOG(Cellular, 2) << __func__;
516 if (error.IsFailure()) {
517 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
518 // TODO(armansito): Maybe post a delayed reset task?
519 return;
520 }
521 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700522 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800523 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800524}
525
Arman Uguray0a3e2792013-01-17 16:31:50 -0800526void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800527 SLOG(Cellular, 2) << __func__;
528
529 bool registered =
530 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
531
532 // If we have a valid MDN, the service is activated. Always try to remove
533 // the ICCID from persistence.
534 bool got_mdn = IsMdnValid();
535 if (got_mdn && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700536 modem_info()->pending_activation_store()->RemoveEntry(
537 PendingActivationStore::kIdentifierICCID,
538 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800539
Arman Ugurayefea6e02013-02-21 13:28:04 -0800540 CellularServiceRefPtr service = cellular()->service();
541
542 if (!service.get())
543 return;
544
Ben Chan7ea768e2013-09-20 15:08:40 -0700545 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800546 // Either no service or already activated. Nothing to do.
547 return;
548
549 // If we have a valid MDN or we can connect to the network, then the service
550 // is activated.
551 if (got_mdn || cellular()->state() == Cellular::kStateConnected ||
552 cellular()->state() == Cellular::kStateLinked) {
553 SLOG(Cellular, 2) << "Marking service as activated.";
Ben Chan7ea768e2013-09-20 15:08:40 -0700554 service->SetActivationState(kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800555 return;
556 }
557
558 // If the ICCID is not available, the following logic can be delayed until it
559 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800560 if (sim_identifier_.empty())
561 return;
562
Arman Uguray41cc6342013-03-29 16:34:39 -0700563 PendingActivationStore::State state =
564 modem_info()->pending_activation_store()->GetActivationState(
565 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700566 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800567 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700568 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800569 // Always mark the service as activating here, as the ICCID could have
570 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700571 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800572 if (reset_done_) {
573 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700574 modem_info()->pending_activation_store()->SetActivationState(
575 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800576 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700577 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800578 } else if (registered) {
579 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700580 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800581 ResetAfterActivation();
582 }
583 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700584 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800585 if (registered) {
586 // Trigger auto connect here.
587 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
588 << "autoconnect to force MDN to update.";
589 service->AutoConnect();
590 }
591 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700592 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700593 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
594 << "been reset at least once.";
595 if (registered) {
596 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700597 modem_info()->pending_activation_store()->SetActivationState(
598 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700599 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700600 PendingActivationStore::kStateActivated);
Ben Chan7ea768e2013-09-20 15:08:40 -0700601 service->SetActivationState(kActivationStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700602 }
603 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700604 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800605 // No entry exists for this ICCID. Nothing to do.
606 break;
607 default:
608 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800609 }
610}
611
Ben Chan07193fd2013-07-12 22:10:55 -0700612string CellularCapabilityUniversal::GetMdnForOLP(
613 const CellularOperatorInfo::CellularOperator &cellular_operator) const {
614 // TODO(benchan): This is ugly. Remove carrier specific code once we move
615 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Ben Chan200591a2013-08-07 14:39:04 -0700616 if (cellular_operator.identifier() == kVzwIdentifier) {
617 if (mdn_.empty()) {
618 return string(kVzwMdnLength, '0');
619 }
620 if (mdn_.length() > kVzwMdnLength) {
621 return mdn_.substr(mdn_.length() - kVzwMdnLength);
622 }
Ben Chan07193fd2013-07-12 22:10:55 -0700623 }
624 return mdn_;
625}
626
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400627void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700628 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400629 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400630 modem_proxy_.reset();
631 modem_simple_proxy_.reset();
632 sim_proxy_.reset();
633}
634
Arman Ugurayc9533572013-01-22 17:34:20 -0800635void CellularCapabilityUniversal::UpdateStorageIdentifier() {
636 if (!cellular()->service().get())
637 return;
638
639 // Lookup the unique identifier assigned to the current network and base the
640 // service's storage identifier on it.
Arman Ugurayc5391232013-09-23 21:30:46 -0700641 const string kPrefix =
642 string(shill::kTypeCellular) + "_" + cellular()->address() + "_";
Arman Ugurayc9533572013-01-22 17:34:20 -0800643 string storage_id;
644 if (!operator_id_.empty()) {
645 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700646 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
647 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800648 if (provider && !provider->identifier().empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700649 storage_id = kPrefix + provider->identifier();
Arman Ugurayc9533572013-01-22 17:34:20 -0800650 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400651 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800652 // If the above didn't work, append IMSI, if available.
653 if (storage_id.empty() && !imsi_.empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700654 storage_id = kPrefix + imsi_;
Arman Ugurayc9533572013-01-22 17:34:20 -0800655 }
656 if (!storage_id.empty()) {
657 cellular()->service()->SetStorageIdentifier(storage_id);
658 }
659}
660
Arman Ugurayefea6e02013-02-21 13:28:04 -0800661void CellularCapabilityUniversal::UpdateServiceActivationState() {
662 if (!cellular()->service().get())
663 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800664 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700665 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700666 PendingActivationStore::State state =
667 modem_info()->pending_activation_store()->GetActivationState(
668 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700669 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800670 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700671 (state == PendingActivationStore::kStatePending ||
672 state == PendingActivationStore::kStatePendingTimeout))
Ben Chan7ea768e2013-09-20 15:08:40 -0700673 activation_state = kActivationStateActivating;
Arman Ugurayefea6e02013-02-21 13:28:04 -0800674 else if (activation_required)
Ben Chan7ea768e2013-09-20 15:08:40 -0700675 activation_state = kActivationStateNotActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700676 else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700677 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700678
679 // Mark an activated service for auto-connect by default. Since data from
680 // the user profile will be loaded after the call to OnServiceCreated, this
681 // property will be corrected based on the user data at that time.
682 cellular()->service()->SetAutoConnect(true);
683 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800684 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800685 // TODO(benchan): For now, assume the cellular service is activated over
686 // a non-cellular network if service activation is required (i.e. a
687 // corresponding entry is found in the cellular operator info file).
688 // We will need to generalize this logic when migrating CDMA support from
689 // cromo to ModemManager.
690 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800691}
692
693void CellularCapabilityUniversal::OnServiceCreated() {
694 UpdateStorageIdentifier();
695 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800696 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400697 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800698 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700699
700 // WORKAROUND:
701 // E362 modems on Verizon network does not properly redirect when a SIM
702 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700703 //
704 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
705 // support is ready (crosbug.com/p/20461).
706 cellular()->service()->set_enforce_out_of_credits_detection(
707 ShouldDetectOutOfCredit());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700708
709 // Make sure that the network technology is set when the service gets
710 // created, just in case.
711 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400712}
713
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400714// Create the list of APNs to try, in the following order:
715// - last APN that resulted in a successful connection attempt on the
716// current network (if any)
717// - the APN, if any, that was set by the user
718// - the list of APNs found in the mobile broadband provider DB for the
719// home provider associated with the current SIM
720// - as a last resort, attempt to connect with no APN
721void CellularCapabilityUniversal::SetupApnTryList() {
722 apn_try_list_.clear();
723
724 DCHECK(cellular()->service().get());
725 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
726 if (apn_info)
727 apn_try_list_.push_back(*apn_info);
728
729 apn_info = cellular()->service()->GetUserSpecifiedApn();
730 if (apn_info)
731 apn_try_list_.push_back(*apn_info);
732
733 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
734}
735
736void CellularCapabilityUniversal::SetupConnectProperties(
737 DBusPropertiesMap *properties) {
738 SetupApnTryList();
739 FillConnectPropertyMap(properties);
740}
741
742void CellularCapabilityUniversal::FillConnectPropertyMap(
743 DBusPropertiesMap *properties) {
744
745 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400746 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400747 kPhoneNumber);
748
Jason Glasgow14521872012-05-07 19:12:15 -0400749 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400750 AllowRoaming());
751
752 if (!apn_try_list_.empty()) {
753 // Leave the APN at the front of the list, so that it can be recorded
754 // if the connect attempt succeeds.
755 Stringmap apn_info = apn_try_list_.front();
Ben Chan7ea768e2013-09-20 15:08:40 -0700756 SLOG(Cellular, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400757 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700758 apn_info[kApnProperty].c_str());
759 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400760 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700761 apn_info[kApnUsernameProperty].c_str());
762 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400763 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700764 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400765 }
766}
767
768void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400769 const DBus::Path &path,
770 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700771 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400772
Jason Glasgow7234ec32012-05-23 16:01:21 -0400773 CellularServiceRefPtr service = cellular()->service();
774 if (!service) {
775 // The service could have been deleted before our Connect() request
776 // completes if the modem was enabled and then quickly disabled.
777 apn_try_list_.clear();
778 } else if (error.IsFailure()) {
779 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400780 // The APN that was just tried (and failed) is still at the
781 // front of the list, about to be removed. If the list is empty
782 // after that, try one last time without an APN. This may succeed
783 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400784 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400785 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700786 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
787 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400788 DBusPropertiesMap props;
789 FillConnectPropertyMap(&props);
790 Error error;
791 Connect(props, &error, callback);
792 return;
793 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400794 } else {
795 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400796 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400797 apn_try_list_.clear();
798 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400799 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400800 }
801
802 if (!callback.is_null())
803 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800804
Arman Uguray0a3e2792013-01-17 16:31:50 -0800805 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400806}
807
808bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200809 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400810}
811
Arman Ugurayf84a4242013-04-09 20:01:07 -0700812bool CellularCapabilityUniversal::ShouldDetectOutOfCredit() const {
Ben Chan4ffc03b2013-08-07 17:44:53 -0700813 return model_id_ == kALT3100ModelId || model_id_ == kE362ModelId;
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700814}
815
Jason Glasgowef965562012-04-10 16:12:35 -0400816void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700817 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400818
Jason Glasgowaf583282012-04-18 15:18:22 -0400819 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
820 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
821 cellular()->dbus_owner()));
822 DBusPropertiesMap properties(
823 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
824 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400825
Jason Glasgowaf583282012-04-18 15:18:22 -0400826 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
827 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400828}
829
Arman Uguray2717a102013-01-29 23:36:06 -0800830// static
831string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
832 return base::StringPrintf("%s %u",
833 kGenericServiceNamePrefix,
834 friendly_service_name_id_++);
835}
836
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400837string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200838 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800839
840 // If |serving_operator_| does not have an operator ID, call
841 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
842 if (serving_operator_.GetCode().empty()) {
843 UpdateOperatorInfo();
844 }
845
Darin Petkova4ca3c32012-08-17 16:05:24 +0200846 string name = serving_operator_.GetName();
847 string home_provider_name = cellular()->home_provider().GetName();
848 if (!name.empty()) {
849 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
850 // rules (TS 31.102 and annex A of 122.101).
851 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
852 !home_provider_name.empty()) {
853 return home_provider_name + " | " + name;
854 }
855 return name;
856 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400857 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200858 !home_provider_name.empty()) {
859 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400860 }
Arman Uguray2717a102013-01-29 23:36:06 -0800861 if (!serving_operator_.GetCode().empty()) {
862 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400863 }
Arman Uguray2717a102013-01-29 23:36:06 -0800864 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400865}
866
867void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700868 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400869 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800870
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700871 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400872 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800873
874 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
875 // one is available. If both were reported by the SIM, use IMSI.
876 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
877 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700878 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800879 spn_.c_str(),
880 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400881 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800882 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400883 return;
884 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400885
886 // Even if provider is the same as home_provider_, it is possible
887 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200889 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400890 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800891 // If Operator ID is available, use that as network code, otherwise
892 // use what was returned from the database.
893 if (!operator_id_.empty()) {
894 oper.SetCode(operator_id_);
895 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400896 oper.SetCode(provider->networks[0]);
897 }
898 if (provider->country) {
899 oper.SetCountry(provider->country);
900 }
901 if (spn_.empty()) {
902 const char *name = mobile_provider_get_name(provider);
903 if (name) {
904 oper.SetName(name);
905 }
906 } else {
907 oper.SetName(spn_);
908 }
909 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200910 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200911 << oper.GetName() << ", " << oper.GetCountry()
912 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400913 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800914 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400915}
916
Ben Chan8a2c01e2013-01-23 10:09:14 -0800917void CellularCapabilityUniversal::UpdateScanningProperty() {
918 // Set the Scanning property to true if there is a ongoing network scan
919 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
920 // to a network.
921 //
922 // TODO(benchan): As the Device DBus interface currently does not have a
923 // State property to indicate whether the device is being enabled, set the
924 // Scanning property to true when the modem is being enabled such that
925 // the network UI can start showing the initializing/scanning animation as
926 // soon as the modem is being enabled.
927 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800928 bool is_activated_service_waiting_for_registration =
929 ((modem_state == Cellular::kModemStateEnabled ||
930 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800931 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800932 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800933 modem_state == Cellular::kModemStateEnabling ||
934 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800935 scanning_;
936 if (new_scanning_or_searching != scanning_or_searching_) {
937 scanning_or_searching_ = new_scanning_or_searching;
Ben Chan7ea768e2013-09-20 15:08:40 -0700938 cellular()->adaptor()->EmitBoolChanged(kScanningProperty,
Ben Chan8a2c01e2013-01-23 10:09:14 -0800939 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800940
941 if (!scanning_or_searching_) {
942 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
943 scanning_or_searching_timeout_callback_.Cancel();
944 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
945 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
946 scanning_or_searching_timeout_callback_.Reset(
947 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
948 weak_ptr_factory_.GetWeakPtr()));
949 cellular()->dispatcher()->PostDelayedTask(
950 scanning_or_searching_timeout_callback_.callback(),
951 scanning_or_searching_timeout_milliseconds_);
952 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800953 }
954}
955
Arman Uguray1361c032013-02-11 17:53:39 -0800956void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
957 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
Ben Chan7ea768e2013-09-20 15:08:40 -0700958 << "kScanningProperty to |false|.";
Arman Uguray1361c032013-02-11 17:53:39 -0800959 scanning_or_searching_ = false;
Ben Chan7ea768e2013-09-20 15:08:40 -0700960 cellular()->adaptor()->EmitBoolChanged(kScanningProperty, false);
Arman Uguray1361c032013-02-11 17:53:39 -0800961}
962
Ben Chan6d0d1e72012-11-06 21:19:28 -0800963void CellularCapabilityUniversal::UpdateOLP() {
Ben Chan07193fd2013-07-12 22:10:55 -0700964 SLOG(Cellular, 2) << __func__;
965
966 const CellularOperatorInfo *cellular_operator_info =
967 modem_info()->cellular_operator_info();
968 if (!cellular_operator_info)
969 return;
970
971 const CellularOperatorInfo::CellularOperator *cellular_operator =
972 cellular_operator_info->GetCellularOperatorByMCCMNC(operator_id_);
973 if (!cellular_operator)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800974 return;
975
Arman Ugurayf4c61812013-01-10 18:58:39 -0800976 const CellularService::OLP *result =
Ben Chan07193fd2013-07-12 22:10:55 -0700977 cellular_operator_info->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -0800978 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800979 return;
980
Arman Ugurayf4c61812013-01-10 18:58:39 -0800981 CellularService::OLP olp;
982 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800983 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800984 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
985 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
986 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
Ben Chan07193fd2013-07-12 22:10:55 -0700987 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
988 GetMdnForOLP(*cellular_operator));
Ben Chan6d0d1e72012-11-06 21:19:28 -0800989 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
990 olp.SetPostData(post_data);
991 cellular()->service()->SetOLP(olp);
992}
993
Arman Uguray2717a102013-01-29 23:36:06 -0800994void CellularCapabilityUniversal::UpdateServiceName() {
995 if (cellular()->service()) {
996 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
997 }
998}
999
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001000void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001001 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -08001002 // TODO(armansito): Use CellularOperatorInfo here instead of
1003 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -08001004
Arman Uguray3645c432013-01-31 15:57:26 -08001005 // Sometimes the modem fails to acquire the operator code OTA, in which case
1006 // |serving_operator_| may not have an operator ID (sometimes due to service
1007 // activation being required or broken modem firmware). Use |operator_id_| as
1008 // a fallback when available. |operator_id_| is retrieved from the SIM card.
1009 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -08001010 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
1011 << "' as serving operator.";
1012 serving_operator_.SetCode(operator_id_);
1013 }
1014
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001015 const string &network_id = serving_operator_.GetCode();
1016 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001017 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001018 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001019 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001020 network_id.c_str());
1021 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +02001022 if (serving_operator_.GetName().empty()) {
1023 const char *provider_name = mobile_provider_get_name(provider);
1024 if (provider_name && *provider_name) {
1025 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001026 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001027 }
Darin Petkova4ca3c32012-08-17 16:05:24 +02001028 if (provider->country && *provider->country) {
1029 serving_operator_.SetCountry(provider->country);
1030 }
1031 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
1032 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001033 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001034 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001035 }
1036 }
1037 UpdateServingOperator();
1038}
1039
1040void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001041 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001042 if (cellular()->service().get()) {
1043 cellular()->service()->SetServingOperator(serving_operator_);
1044 }
1045}
1046
Arman Uguray6e5639f2012-11-15 20:30:19 -08001047void CellularCapabilityUniversal::UpdateBearerPath() {
1048 SLOG(Cellular, 2) << __func__;
1049 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1050 weak_ptr_factory_.GetWeakPtr());
1051 Error error;
mukesh agrawal510cc802013-08-15 18:31:42 -07001052 if (!modem_proxy_) {
1053 // This can be a perfectly legitimate state to be in, as this
1054 // function can be called before StartModem. In particular, this
1055 // happens when a Cellular object is contructed in
1056 // Modem::CreateDeviceFromModemProperties.
1057 LOG(INFO) << "Skipping ListBearers due to uninitialized modem_proxy_.";
1058 return;
1059 }
Arman Uguray6e5639f2012-11-15 20:30:19 -08001060 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1061}
1062
1063void CellularCapabilityUniversal::OnListBearersReply(
1064 const std::vector<DBus::Path> &paths,
1065 const Error &error) {
1066 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1067 if (error.IsFailure()) {
1068 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1069 return;
1070 }
1071 // Look for the first active bearer and use its path as the connected
1072 // one. Right now, we don't allow more than one active bearer.
mukesh agrawal9da07772013-05-15 14:15:17 -07001073 DBus::Path new_bearer_path;
1074 uint32 ipconfig_method(MM_BEARER_IP_METHOD_UNKNOWN);
1075 string network_device;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001076 for (size_t i = 0; i < paths.size(); ++i) {
1077 const DBus::Path &path = paths[i];
Ben Chan5db19692013-07-09 23:07:03 -07001078
1079 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1080 proxy_factory()->CreateDBusPropertiesProxy(path,
1081 cellular()->dbus_owner()));
1082 DBusPropertiesMap properties(
1083 properties_proxy->GetAll(MM_DBUS_INTERFACE_BEARER));
1084 if (properties.empty()) {
1085 LOG(WARNING) << "Could not get properties of bearer \"" << path
1086 << "\". Bearer is likely gone and thus ignored.";
mukesh agrawal9da07772013-05-15 14:15:17 -07001087 continue;
1088 }
Ben Chan5db19692013-07-09 23:07:03 -07001089
1090 bool connected = false;
1091 if (!DBusProperties::GetBool(
1092 properties, MM_BEARER_PROPERTY_CONNECTED, &connected)) {
1093 SLOG(Cellular, 2) << "Bearer does not indicate whether it is connected "
1094 "or not. Assume it is not connected.";
1095 continue;
1096 }
1097
1098 if (!connected) {
1099 continue;
1100 }
1101
mukesh agrawal9da07772013-05-15 14:15:17 -07001102 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan5db19692013-07-09 23:07:03 -07001103 CHECK(new_bearer_path.empty()) << "Found more than one active bearer.";
1104
1105 if (DBusProperties::GetString(
1106 properties, MM_BEARER_PROPERTY_INTERFACE, &network_device)) {
1107 SLOG(Cellular, 2) << "Bearer uses network interface \"" << network_device
1108 << "\".";
1109 } else {
1110 SLOG(Cellular, 2) << "Bearer does not specify network interface.";
1111 }
1112
mukesh agrawal9da07772013-05-15 14:15:17 -07001113 // TODO(quiche): Add support for scenarios where the bearer is
1114 // IPv6 only, or where there are conflicting configuration methods
1115 // for IPv4 and IPv6. crbug.com/248360.
Ben Chan5db19692013-07-09 23:07:03 -07001116 DBusPropertiesMap bearer_ip4config;
1117 DBusProperties::GetDBusPropertiesMap(
1118 properties, MM_BEARER_PROPERTY_IP4CONFIG, &bearer_ip4config);
1119
1120 if (DBusProperties::GetUint32(
1121 bearer_ip4config, kIpConfigPropertyMethod, &ipconfig_method)) {
mukesh agrawal9da07772013-05-15 14:15:17 -07001122 SLOG(Cellular, 2) << "Bearer has IPv4 config method " << ipconfig_method;
1123 } else {
1124 SLOG(Cellular, 2) << "Bearer does not specify IPv4 config method.";
1125 for (const auto &i : bearer_ip4config) {
1126 SLOG(Cellular, 5) << "Bearer IPv4 config has key \""
1127 << i.first
1128 << "\".";
Arman Uguray6e5639f2012-11-15 20:30:19 -08001129 }
1130 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001131 new_bearer_path = path;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001132 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001133 bearer_path_ = new_bearer_path;
1134 if (new_bearer_path.empty()) {
1135 SLOG(Cellular, 2) << "No active bearer found.";
1136 return;
1137 }
1138 if (ipconfig_method == MM_BEARER_IP_METHOD_PPP) {
1139 cellular()->StartPPP(network_device);
Arman Uguray6e5639f2012-11-15 20:30:19 -08001140 }
1141}
1142
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001143void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001144 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001145 if (!home_provider_) {
1146 return;
1147 }
1148 apn_list_.clear();
1149 for (int i = 0; i < home_provider_->num_apns; ++i) {
1150 Stringmap props;
1151 mobile_apn *apn = home_provider_->apns[i];
1152 if (apn->value) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001153 props[kApnProperty] = apn->value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001154 }
1155 if (apn->username) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001156 props[kApnUsernameProperty] = apn->username;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001157 }
1158 if (apn->password) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001159 props[kApnPasswordProperty] = apn->password;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160 }
1161 // Find the first localized and non-localized name, if any.
1162 const localized_name *lname = NULL;
1163 const localized_name *name = NULL;
1164 for (int j = 0; j < apn->num_names; ++j) {
1165 if (apn->names[j]->lang) {
1166 if (!lname) {
1167 lname = apn->names[j];
1168 }
1169 } else if (!name) {
1170 name = apn->names[j];
1171 }
1172 }
1173 if (name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001174 props[kApnNameProperty] = name->name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001175 }
1176 if (lname) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001177 props[kApnLocalizedNameProperty] = lname->name;
1178 props[kApnLanguageProperty] = lname->lang;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001179 }
1180 apn_list_.push_back(props);
1181 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001182 if (cellular()->adaptor()) {
1183 cellular()->adaptor()->EmitStringmapsChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001184 kCellularApnListProperty, apn_list_);
Darin Petkovdb6083f2012-08-16 12:50:23 +02001185 } else {
1186 LOG(ERROR) << "Null RPC service adaptor.";
1187 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001188}
1189
Ben Chan15786032012-11-04 21:28:02 -08001190bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Arman Ugurayc7b15602013-02-16 00:56:18 -08001191 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001192 modem_info()->pending_activation_store()->GetActivationState(
1193 PendingActivationStore::kIdentifierICCID,
1194 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001195 return false;
1196
Ben Chan15786032012-11-04 21:28:02 -08001197 // If there is no online payment portal information, it's safer to assume
1198 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001199 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001200 return false;
1201
Arman Ugurayf4c61812013-01-10 18:58:39 -08001202 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001203 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001204 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001205 return false;
1206
Ben Chan200591a2013-08-07 14:39:04 -07001207 // If the MDN is invalid (i.e. empty or contains only zeros), the service
1208 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001209 return !IsMdnValid();
1210}
1211
1212bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001213 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001214 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001215 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001216 return true;
Ben Chan15786032012-11-04 21:28:02 -08001217 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001218 return false;
Ben Chan15786032012-11-04 21:28:02 -08001219}
1220
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001221// always called from an async context
1222void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001223 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001224 CHECK(!callback.is_null());
1225 Error error;
1226 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1227 weak_ptr_factory_.GetWeakPtr(), callback);
1228 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1229 if (error.IsFailure())
1230 callback.Run(error);
1231}
1232
1233void CellularCapabilityUniversal::RegisterOnNetwork(
1234 const string &network_id,
1235 Error *error,
1236 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001237 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001238 CHECK(error);
1239 desired_network_ = network_id;
1240 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1241 weak_ptr_factory_.GetWeakPtr(), callback);
1242 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1243}
1244
1245void CellularCapabilityUniversal::OnRegisterReply(
1246 const ResultCallback &callback,
1247 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001248 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001249
1250 if (error.IsSuccess()) {
1251 selected_network_ = desired_network_;
1252 desired_network_.clear();
1253 callback.Run(error);
1254 return;
1255 }
1256 // If registration on the desired network failed,
1257 // try to register on the home network.
1258 if (!desired_network_.empty()) {
1259 desired_network_.clear();
1260 selected_network_.clear();
1261 LOG(INFO) << "Couldn't register on selected network, trying home network";
1262 Register(callback);
1263 return;
1264 }
1265 callback.Run(error);
1266}
1267
1268bool CellularCapabilityUniversal::IsRegistered() {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001269 return IsRegisteredState(registration_state_);
1270}
1271
1272bool CellularCapabilityUniversal::IsRegisteredState(
1273 MMModem3gppRegistrationState state) {
1274 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1275 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001276}
1277
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001278void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1279 // If we're already in some non-registered state, don't override that
1280 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1281 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1282 registration_state_ =
1283 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1284 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1285 }
1286}
1287
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001288void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001289 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001290 Error *error, const ResultCallback &callback) {
1291 CHECK(error);
1292 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1293}
1294
1295void CellularCapabilityUniversal::EnterPIN(const string &pin,
1296 Error *error,
1297 const ResultCallback &callback) {
1298 CHECK(error);
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001299 SLOG(Cellular, 2) << __func__;
1300 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001301}
1302
1303void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1304 const string &pin,
1305 Error *error,
1306 const ResultCallback &callback) {
1307 CHECK(error);
1308 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1309}
1310
1311void CellularCapabilityUniversal::ChangePIN(
1312 const string &old_pin, const string &new_pin,
1313 Error *error, const ResultCallback &callback) {
1314 CHECK(error);
1315 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1316}
1317
Ben Chan5d0d32c2013-01-08 02:05:29 -08001318void CellularCapabilityUniversal::Reset(Error *error,
1319 const ResultCallback &callback) {
1320 SLOG(Cellular, 2) << __func__;
1321 CHECK(error);
1322 if (resetting_) {
1323 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1324 return;
1325 }
1326 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1327 weak_ptr_factory_.GetWeakPtr(), callback);
1328 modem_proxy_->Reset(error, cb, kTimeoutReset);
1329 if (!error->IsFailure()) {
1330 resetting_ = true;
1331 }
1332}
1333
1334void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1335 const Error &error) {
1336 SLOG(Cellular, 2) << __func__;
1337 resetting_ = false;
1338 if (!callback.is_null())
1339 callback.Run(error);
1340}
1341
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001342void CellularCapabilityUniversal::Scan(Error *error,
1343 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001344 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001345 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001346 if (scanning_) {
1347 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1348 return;
1349 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001350 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1351 weak_ptr_factory_.GetWeakPtr(), callback);
1352 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001353 if (!error->IsFailure()) {
1354 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001355 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001356 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001357}
1358
1359void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1360 const ScanResults &results,
1361 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001362 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001363
1364 // Error handling is weak. The current expectation is that on any
1365 // error, found_networks_ should be cleared and a property change
1366 // notification sent out.
1367 //
1368 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001369 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001370 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001371 found_networks_.clear();
1372 if (!error.IsFailure()) {
1373 for (ScanResults::const_iterator it = results.begin();
1374 it != results.end(); ++it) {
1375 found_networks_.push_back(ParseScanResult(*it));
1376 }
1377 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001378 cellular()->adaptor()->EmitStringmapsChanged(kFoundNetworksProperty,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001379 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001380
1381 // TODO(gmorain): This check for is_null() is a work-around because
1382 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1383 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1384 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1385 // Universal.
1386 if (!callback.is_null())
1387 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001388}
1389
1390Stringmap CellularCapabilityUniversal::ParseScanResult(
1391 const ScanResult &result) {
1392
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001393 /* ScanResults contain the following keys:
1394
1395 "status"
1396 A MMModem3gppNetworkAvailability value representing network
1397 availability status, given as an unsigned integer (signature "u").
1398 This key will always be present.
1399
1400 "operator-long"
1401 Long-format name of operator, given as a string value (signature
1402 "s"). If the name is unknown, this field should not be present.
1403
1404 "operator-short"
1405 Short-format name of operator, given as a string value
1406 (signature "s"). If the name is unknown, this field should not
1407 be present.
1408
1409 "operator-code"
1410 Mobile code of the operator, given as a string value (signature
1411 "s"). Returned in the format "MCCMNC", where MCC is the
1412 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1413 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1414
1415 "access-technology"
1416 A MMModemAccessTechnology value representing the generic access
1417 technology used by this mobile network, given as an unsigned
1418 integer (signature "u").
1419 */
1420 Stringmap parsed;
1421
1422 uint32 status;
1423 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1424 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1425 static const char * const kStatusString[] = {
1426 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1427 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1428 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1429 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1430 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001431 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001432 }
1433
1434 uint32 tech; // MMModemAccessTechnology
1435 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1436 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001437 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001438 }
1439
1440 string operator_long, operator_short, operator_code;
1441 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001442 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001443 if (DBusProperties::GetString(result, kOperatorShortProperty,
1444 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001445 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001446 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001447 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001448
1449 // If the long name is not available but the network ID is, look up the long
1450 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001451 if ((!ContainsKey(parsed, kLongNameProperty) ||
1452 parsed[kLongNameProperty].empty()) &&
1453 ContainsKey(parsed, kNetworkIdProperty)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001454 mobile_provider *provider =
1455 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001456 modem_info()->provider_db(),
Ben Chan7ea768e2013-09-20 15:08:40 -07001457 parsed[kNetworkIdProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001458 if (provider) {
1459 const char *long_name = mobile_provider_get_name(provider);
1460 if (long_name && *long_name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001461 parsed[kLongNameProperty] = long_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001462 }
1463 }
1464 }
1465 return parsed;
1466}
1467
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001468string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001469 // If we know that the modem is an E362, return LTE here to make sure that
1470 // Chrome sees LTE as the network technology even if the actual technology is
1471 // unknown.
1472 // TODO(armansito): This hack will cause the UI to display LTE even if the
1473 // modem doesn't support it at a given time. This might be problematic if we
1474 // ever want to support switching between access technologies (e.g. falling
1475 // back to 3G when LTE is not available).
1476 if (model_id_ == kE362ModelId)
Ben Chan7ea768e2013-09-20 15:08:40 -07001477 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001478
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001479 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001480 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001481 return AccessTechnologyToString(access_technologies_);
1482}
1483
1484string CellularCapabilityUniversal::GetRoamingStateString() const {
1485 switch (registration_state_) {
1486 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001487 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001488 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001489 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001490 default:
1491 break;
1492 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001493 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001494}
1495
Arman Uguray5d9a8522013-09-10 17:43:13 -07001496// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001497void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001498 // ModemManager always returns the cached value, so there is no need to
1499 // trigger an update here. The true value is updated through a property
1500 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001501}
1502
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001503string CellularCapabilityUniversal::GetTypeString() const {
1504 return AccessTechnologyToTechnologyFamily(access_technologies_);
1505}
1506
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001507void CellularCapabilityUniversal::OnModemPropertiesChanged(
1508 const DBusPropertiesMap &properties,
1509 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001510 // This solves a bootstrapping problem: If the modem is not yet
1511 // enabled, there are no proxy objects associated with the capability
1512 // object, so modem signals like StateChanged aren't seen. By monitoring
1513 // changes to the State property via the ModemManager, we're able to
1514 // get the initialization process started, which will result in the
1515 // creation of the proxy objects.
1516 //
1517 // The first time we see the change to State (when the modem state
1518 // is Unknown), we simply update the state, and rely on the Manager to
1519 // enable the device when it is registered with the Manager. On subsequent
1520 // changes to State, we need to explicitly enable the device ourselves.
1521 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001522 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001523 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001524 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001525 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001526 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001527 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001528 MM_MODEM_PROPERTY_SIM, &object_path_value))
1529 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001530
1531 DBusPropertiesMap::const_iterator it =
1532 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1533 if (it != properties.end()) {
1534 const vector<uint32> &supported_capabilities = it->second;
1535 OnSupportedCapabilitesChanged(supported_capabilities);
1536 }
1537
Jason Glasgowaf583282012-04-18 15:18:22 -04001538 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001539 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001540 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1541 &uint_value))
1542 OnModemCurrentCapabilitiesChanged(uint_value);
1543 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1544 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001545 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001546 if (DBusProperties::GetString(properties,
1547 MM_MODEM_PROPERTY_MANUFACTURER,
1548 &string_value))
1549 OnModemManufacturerChanged(string_value);
1550 if (DBusProperties::GetString(properties,
1551 MM_MODEM_PROPERTY_MODEL,
1552 &string_value))
1553 OnModemModelChanged(string_value);
1554 if (DBusProperties::GetString(properties,
1555 MM_MODEM_PROPERTY_REVISION,
1556 &string_value))
1557 OnModemRevisionChanged(string_value);
1558 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1559 // not needed: MM_MODEM_PROPERTY_DEVICE
1560 // not needed: MM_MODEM_PROPERTY_DRIVER
1561 // not needed: MM_MODEM_PROPERTY_PLUGIN
1562 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001563
Jason Glasgowaf583282012-04-18 15:18:22 -04001564 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001565 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001566 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001567 if (DBusProperties::GetUint32(properties,
1568 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001569 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001570 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001571 lock_status_changed = true;
1572 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001573
1574 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001575 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001576 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001577 LockRetryData lock_retries = it->second.operator LockRetryData();
1578 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001579 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001580 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001581
Arman Ugurayea5ff272013-06-25 10:28:02 -07001582 if (lock_status_changed)
1583 OnSimLockStatusChanged();
1584
Jason Glasgowaf583282012-04-18 15:18:22 -04001585 if (DBusProperties::GetUint32(properties,
1586 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1587 &uint_value))
1588 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001589
Jason Glasgowaf583282012-04-18 15:18:22 -04001590 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1591 if (it != properties.end()) {
1592 DBus::Struct<unsigned int, bool> quality = it->second;
1593 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001594 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001595 vector<string> numbers;
1596 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1597 &numbers)) {
1598 string mdn;
1599 if (numbers.size() > 0)
1600 mdn = numbers[0];
1601 OnMdnChanged(mdn);
1602 }
Ben Chan74924d82013-06-15 17:52:55 -07001603
1604 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1605 if (it != properties.end()) {
1606 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1607 vector<ModemModes> supported_modes;
1608 for (const auto &modes : mm_supported_modes) {
1609 supported_modes.push_back(
1610 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1611 }
1612 OnSupportedModesChanged(supported_modes);
1613 }
1614
1615 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1616 if (it != properties.end()) {
1617 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1618 OnCurrentModesChanged(ModemModes(
1619 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1620 }
1621
Jason Glasgowaf583282012-04-18 15:18:22 -04001622 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1623 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001624}
1625
1626void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1627 const string &interface,
1628 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001629 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001630 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001631 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001632 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001633 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001634 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1635 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001636 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001637 if (interface == MM_DBUS_INTERFACE_SIM) {
1638 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001639 }
1640}
1641
Jason Glasgow14521872012-05-07 19:12:15 -04001642bool CellularCapabilityUniversal::RetriableConnectError(
1643 const Error &error) const {
1644 if (error.type() == Error::kInvalidApn)
1645 return true;
1646
1647 // modemmanager does not ever return kInvalidApn for E362 modems
1648 // with 1.41 firmware. It remains to be seem if this will change
1649 // with 3.x firmware.
1650 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1651 return true;
1652
1653 return false;
1654}
1655
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001656void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1657 // TODO(petkov): Implement this.
1658 NOTIMPLEMENTED();
1659}
1660
Arman Uguray6552f8c2013-02-12 15:33:18 -08001661bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1662 return !sim_path.empty() && sim_path != kRootPath;
1663}
1664
Ben Chand7592522013-02-13 16:02:01 -08001665string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1666 string normalized_mdn;
1667 for (size_t i = 0; i < mdn.size(); ++i) {
1668 if (IsAsciiDigit(mdn[i]))
1669 normalized_mdn += mdn[i];
1670 }
1671 return normalized_mdn;
1672}
1673
Jason Glasgowaf583282012-04-18 15:18:22 -04001674void CellularCapabilityUniversal::OnSimPathChanged(
1675 const string &sim_path) {
1676 if (sim_path == sim_path_)
1677 return;
1678
1679 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001680 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001681 proxy = proxy_factory()->CreateSimProxy(sim_path,
1682 cellular()->dbus_owner());
1683 sim_path_ = sim_path;
1684 sim_proxy_.reset(proxy);
1685
Arman Uguray6552f8c2013-02-12 15:33:18 -08001686 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001687 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001688 imsi_ = "";
1689 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001690 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001691 OnSimIdentifierChanged("");
1692 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001693 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001694 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001695 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1696 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1697 cellular()->dbus_owner()));
1698 // TODO(jglasgow): convert to async interface
1699 DBusPropertiesMap properties(
1700 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1701 OnSimPropertiesChanged(properties, vector<string>());
1702 }
1703}
1704
Ben Chan74924d82013-06-15 17:52:55 -07001705void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1706 const vector<uint32> &supported_capabilities) {
1707 supported_capabilities_ = supported_capabilities;
1708}
1709
Jason Glasgowaf583282012-04-18 15:18:22 -04001710void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1711 uint32 current_capabilities) {
1712 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001713
1714 // Only allow network scan when the modem's current capabilities support
1715 // GSM/UMTS.
1716 //
1717 // TODO(benchan): We should consider having the modem plugins in ModemManager
1718 // reporting whether network scan is supported.
1719 scanning_supported_ =
1720 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1721 if (cellular()->adaptor()) {
1722 cellular()->adaptor()->EmitBoolChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001723 kSupportNetworkScanProperty, scanning_supported_);
Ben Chanfcca27b2013-01-22 15:03:44 -08001724 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001725}
1726
1727void CellularCapabilityUniversal::OnMdnChanged(
1728 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001729 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001730 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001731}
1732
1733void CellularCapabilityUniversal::OnModemManufacturerChanged(
1734 const string &manufacturer) {
1735 manufacturer_ = manufacturer;
1736}
1737
1738void CellularCapabilityUniversal::OnModemModelChanged(
1739 const string &model) {
1740 model_id_ = model;
1741}
1742
1743void CellularCapabilityUniversal::OnModemRevisionChanged(
1744 const string &revision) {
1745 firmware_revision_ = revision;
1746}
1747
1748void CellularCapabilityUniversal::OnModemStateChanged(
1749 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001750 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001751
1752 cellular()->OnModemStateChanged(state);
1753 UpdateScanningProperty();
1754 // TODO(armansito): Move the deferred enable logic to Cellular
1755 // (See crbug.com/279499).
1756 if (!deferred_enable_modem_callback_.is_null() &&
1757 state == Cellular::kModemStateDisabled) {
1758 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1759 deferred_enable_modem_callback_.Run();
1760 deferred_enable_modem_callback_.Reset();
1761 } else if (state == Cellular::kModemStateConnected) {
mukesh agrawal510cc802013-08-15 18:31:42 -07001762 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1763 UpdateBearerPath();
1764 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001765}
1766
1767void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1768 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001769 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001770 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001771 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001772 const string new_type_string(GetTypeString());
1773 if (new_type_string != old_type_string) {
1774 // TODO(jglasgow): address layering violation of emitting change
1775 // signal here for a property owned by Cellular.
1776 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001777 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001778 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001779 if (cellular()->service().get()) {
1780 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1781 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001782 }
1783}
1784
Ben Chan74924d82013-06-15 17:52:55 -07001785void CellularCapabilityUniversal::OnSupportedModesChanged(
1786 const vector<ModemModes> &supported_modes) {
1787 supported_modes_ = supported_modes;
1788}
1789
1790void CellularCapabilityUniversal::OnCurrentModesChanged(
1791 const ModemModes &current_modes) {
1792 current_modes_ = current_modes;
1793}
1794
Jason Glasgowaf583282012-04-18 15:18:22 -04001795void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001796 const LockRetryData &lock_retries) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001797 SLOG(Cellular, 2) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001798
Arman Ugurayea5ff272013-06-25 10:28:02 -07001799 // Look for the retries left for the current lock. Try the obtain the count
1800 // that matches the current count. If no count for the current lock is
1801 // available, report the first one in the dictionary.
1802 LockRetryData::const_iterator it =
1803 lock_retries.find(sim_lock_status_.lock_type);
1804 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001805 it = lock_retries.begin();
1806 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001807 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001808 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001809 // Unknown, use 999
1810 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001811}
1812
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001813void CellularCapabilityUniversal::OnLockTypeChanged(
1814 MMModemLock lock_type) {
1815 SLOG(Cellular, 2) << __func__ << ": " << lock_type;
1816 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001817
1818 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1819 // This is because the corresponding property 'EnabledFacilityLocks' is on
1820 // the 3GPP interface and the 3GPP interface is not available while the Modem
1821 // is in the 'LOCKED' state.
1822 if (lock_type != MM_MODEM_LOCK_NONE &&
1823 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1824 !sim_lock_status_.enabled)
1825 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001826}
1827
Jason Glasgowaf583282012-04-18 15:18:22 -04001828void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001829 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001830 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001831 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001832
1833 // If the SIM is currently unlocked, assume that we need to refresh
1834 // carrier information, since a locked SIM prevents shill from obtaining
1835 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001836 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001837 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1838 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001839 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1840 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1841 cellular()->dbus_owner()));
1842 DBusPropertiesMap properties(
1843 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1844 OnSimPropertiesChanged(properties, vector<string>());
1845 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001846}
1847
1848void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1849 const DBusPropertiesMap &properties,
1850 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001851 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001852 string imei;
1853 if (DBusProperties::GetString(properties,
1854 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1855 &imei))
1856 OnImeiChanged(imei);
1857
1858 // Handle registration state changes as a single change
1859 string operator_code = serving_operator_.GetCode();
1860 string operator_name = serving_operator_.GetName();
1861 MMModem3gppRegistrationState state = registration_state_;
1862 bool registration_changed = false;
1863 uint32 uint_value;
1864 if (DBusProperties::GetUint32(properties,
1865 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1866 &uint_value)) {
1867 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1868 registration_changed = true;
1869 }
1870 if (DBusProperties::GetString(properties,
1871 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1872 &operator_code))
1873 registration_changed = true;
1874 if (DBusProperties::GetString(properties,
1875 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1876 &operator_name))
1877 registration_changed = true;
1878 if (registration_changed)
1879 On3GPPRegistrationChanged(state, operator_code, operator_name);
1880
1881 uint32 locks = 0;
1882 if (DBusProperties::GetUint32(
1883 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1884 &locks))
1885 OnFacilityLocksChanged(locks);
1886}
1887
1888void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1889 imei_ = imei;
1890}
1891
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001892void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1893 MMModem3gppRegistrationState state,
1894 const string &operator_code,
1895 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001896 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1897 << ", opercode=" << operator_code
1898 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001899
1900 // While the modem is connected, if the state changed from a registered state
1901 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001902 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1903 IsRegistered() && !IsRegisteredState(state)) {
1904 if (!registration_dropped_update_callback_.IsCancelled()) {
1905 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1906 << "Ignoring earlier notifications.";
1907 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001908 } else {
1909 // This is not a repeated post. So, count this instance of delayed drop
1910 // posted.
1911 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001912 }
1913 SLOG(Cellular, 2) << "Posted deferred registration state update";
1914 registration_dropped_update_callback_.Reset(
1915 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1916 weak_ptr_factory_.GetWeakPtr(),
1917 state,
1918 operator_code,
1919 operator_name));
1920 cellular()->dispatcher()->PostDelayedTask(
1921 registration_dropped_update_callback_.callback(),
1922 registration_dropped_update_timeout_milliseconds_);
1923 } else {
1924 if (!registration_dropped_update_callback_.IsCancelled()) {
1925 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1926 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001927 // If we cancelled the callback here, it means we had flaky network for a
1928 // small duration.
1929 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001930 }
1931 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1932 }
1933}
1934
1935void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1936 MMModem3gppRegistrationState updated_state,
1937 string updated_operator_code,
1938 string updated_operator_name) {
1939 // A finished callback does not qualify as a canceled callback.
1940 // We test for a canceled callback to check for outstanding callbacks.
1941 // So, explicitly cancel the callback here.
1942 registration_dropped_update_callback_.Cancel();
1943
1944 SLOG(Cellular, 2) << __func__ << ": regstate=" << updated_state
1945 << ", opercode=" << updated_operator_code
1946 << ", opername=" << updated_operator_name;
1947
1948 registration_state_ = updated_state;
1949 serving_operator_.SetCode(updated_operator_code);
1950 serving_operator_.SetName(updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001951
1952 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001953 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08001954
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001955 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001956
1957 // Update the user facing name of the cellular service.
1958 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08001959
1960 // If the modem registered with the network and the current ICCID is pending
1961 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001962 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001963}
1964
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001965void CellularCapabilityUniversal::OnModemStateChangedSignal(
1966 int32 old_state, int32 new_state, uint32 reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07001967 Cellular::ModemState old_modem_state =
1968 static_cast<Cellular::ModemState>(old_state);
1969 Cellular::ModemState new_modem_state =
1970 static_cast<Cellular::ModemState>(new_state);
1971 SLOG(Cellular, 2) << __func__ << "("
1972 << Cellular::GetModemStateString(old_modem_state) << ", "
1973 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001974 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001975}
1976
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001977void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1978 cellular()->HandleNewSignalQuality(quality);
1979}
1980
Jason Glasgowaf583282012-04-18 15:18:22 -04001981void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001982 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1983 if (sim_lock_status_.enabled != sim_enabled) {
1984 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04001985 OnSimLockStatusChanged();
1986 }
1987}
Jason Glasgowef965562012-04-10 16:12:35 -04001988
Jason Glasgowaf583282012-04-18 15:18:22 -04001989void CellularCapabilityUniversal::OnSimPropertiesChanged(
1990 const DBusPropertiesMap &props,
1991 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001992 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001993 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001994 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1995 OnSimIdentifierChanged(value);
1996 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1997 &value))
1998 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001999 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
2000 OnSpnChanged(value);
2001 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
2002 OnImsiChanged(value);
2003 SetHomeProvider();
2004}
Jason Glasgowaf583282012-04-18 15:18:22 -04002005
Arman Ugurayd73783f2013-01-31 16:11:21 -08002006// TODO(armansito): The following methods should probably log their argument
2007// values. Need to learn if any of them need to be scrubbed.
2008void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
2009 imsi_ = imsi;
2010}
2011
2012void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
2013 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04002014}
2015
2016void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
2017 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08002018 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04002019}
2020
2021void CellularCapabilityUniversal::OnOperatorIdChanged(
2022 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002023 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04002024 operator_id_ = operator_id;
2025}
2026
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002027} // namespace shill