blob: f7107943a0feb6a85c8ae05f1026b8a88d5f9eb9 [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";
Jason Glasgow14521872012-05-07 19:12:15 -040072const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080073const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
74 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040075unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
76
Ben Chan07193fd2013-07-12 22:10:55 -070077namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040078
Ben Chan07193fd2013-07-12 22:10:55 -070079const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040080
Ben Chan07193fd2013-07-12 22:10:55 -070081// This identifier is specified in the cellular_operator_info file.
82const char kVzwIdentifier[] = "vzw";
83const size_t kVzwMdnLength = 10;
84
85string AccessTechnologyToString(uint32 access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040086 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
Ben Chan7ea768e2013-09-20 15:08:40 -070087 return kNetworkTechnologyLte;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040088 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
89 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
90 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
Ben Chan7ea768e2013-09-20 15:08:40 -070091 return kNetworkTechnologyEvdo;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040092 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
Ben Chan7ea768e2013-09-20 15:08:40 -070093 return kNetworkTechnology1Xrtt;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040094 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
Ben Chan7ea768e2013-09-20 15:08:40 -070095 return kNetworkTechnologyHspaPlus;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040096 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
Ben Chan7ea768e2013-09-20 15:08:40 -070099 return kNetworkTechnologyHspa;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400100 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700101 return kNetworkTechnologyUmts;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400102 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
Ben Chan7ea768e2013-09-20 15:08:40 -0700103 return kNetworkTechnologyEdge;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400104 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700105 return kNetworkTechnologyGprs;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400106 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
107 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700108 return kNetworkTechnologyGsm;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400109 return "";
110}
111
Ben Chan07193fd2013-07-12 22:10:55 -0700112string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400113 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
114 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
118 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
119 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
120 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
121 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
122 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700123 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400124 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800125 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
126 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400127 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700128 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400129 return "";
130}
131
Ben Chan07193fd2013-07-12 22:10:55 -0700132} // namespace
133
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400134CellularCapabilityUniversal::CellularCapabilityUniversal(
135 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800136 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700137 ModemInfo *modem_info)
138 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400139 weak_ptr_factory_(this),
140 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200141 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400142 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
143 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200144 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800145 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800146 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400147 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800148 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700149 scan_interval_(0),
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700150 subscription_state_(kSubscriptionStateUnknown),
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
mukesh agrawal28185512013-10-18 16:57:09 -0700380// Note: if we were in the middle of powering down the modem when the
381// system suspended, we might not get this event from
382// ModemManager. And we might not even get a timeout from dbus-c++,
383// because StartModem re-initializes proxies.
Arman Ugurayee464d32013-02-13 17:14:36 -0800384void CellularCapabilityUniversal::Stop_PowerDownCompleted(
385 const ResultCallback &callback,
386 const Error &error) {
387 SLOG(Cellular, 2) << __func__;
388
389 if (error.IsFailure())
390 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
391
392 // Since the disable succeeded, if power down fails, we currently fail
393 // silently, i.e. we need to report the disable operation as having
394 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700395 modem_info()->metrics()->NotifyDeviceDisableFinished(
396 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800397 ReleaseProxies();
398 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400399}
400
401void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
402 Error *error,
403 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700404 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400405 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
406 weak_ptr_factory_.GetWeakPtr(),
407 callback);
408 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400409}
410
411void CellularCapabilityUniversal::Disconnect(Error *error,
412 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700413 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700414 // If a deferred registration loss request exists, process it.
415 if (!registration_dropped_update_callback_.IsCancelled()) {
416 registration_dropped_update_callback_.callback().Run();
417 DCHECK(cellular()->state() != Cellular::kStateConnected &&
418 cellular()->state() != Cellular::kStateLinked);
419 SLOG(Cellular, 1) << "Processed deferred registration loss before "
420 << "disconnect request.";
421 }
Thieu Le5d6864a2012-07-20 11:43:51 -0700422 if (bearer_path_.empty()) {
423 LOG(WARNING) << "In " << __func__ << "(): "
424 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700425 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700426 modem_simple_proxy_->Disconnect(bearer_path_,
427 error,
428 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800429 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700430 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400431}
432
Christopher Wiley8a468902012-11-30 11:52:38 -0800433void CellularCapabilityUniversal::DisconnectCleanup() {
434 SLOG(Cellular, 2) << __func__;
435}
436
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400437void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400438 Error *error,
439 const ResultCallback &callback) {
440 OnUnsupportedOperation(__func__, error);
441}
442
Arman Uguraya14941d2013-04-12 16:58:26 -0700443void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
444 SLOG(Cellular, 2) << __func__;
445 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700446 modem_info()->pending_activation_store()->GetActivationState(
447 PendingActivationStore::kIdentifierICCID,
448 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700449 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
450 return;
451 }
452 if (IsMdnValid()) {
453 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
454 return;
455 }
456 if (reset_done_) {
457 SLOG(Cellular, 2) << "Already done with reset.";
458 return;
459 }
460
461 // Still not activated after timeout. Reset the modem.
462 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
463 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700464 modem_info()->pending_activation_store()->SetActivationState(
465 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700466 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700467 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700468 ResetAfterActivation();
469}
470
Arman Ugurayc7b15602013-02-16 00:56:18 -0800471void CellularCapabilityUniversal::CompleteActivation(Error *error) {
472 SLOG(Cellular, 2) << __func__;
473
474 // Persist the ICCID as "Pending Activation".
475 // We're assuming that when this function gets called, |sim_identifier_| will
476 // be non-empty. We still check here that is non-empty, though something is
477 // wrong if it is empty.
Arman Ugurayc7b15602013-02-16 00:56:18 -0800478 if (sim_identifier_.empty()) {
479 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
480 return;
481 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800482
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700483 if (IsMdnValid()) {
484 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
485 return;
486 }
487
Arman Ugurayefea6e02013-02-21 13:28:04 -0800488 // There should be a cellular service at this point.
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700489 if (cellular()->service().get()) {
490 if (cellular()->service()->activation_state() == kActivationStateActivated)
491 return;
492
Ben Chan7ea768e2013-09-20 15:08:40 -0700493 cellular()->service()->SetActivationState(kActivationStateActivating);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700494 }
Arman Uguray41cc6342013-03-29 16:34:39 -0700495 modem_info()->pending_activation_store()->SetActivationState(
496 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800497 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700498 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700499
500 activation_wait_for_registration_callback_.Reset(
501 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
502 weak_ptr_factory_.GetWeakPtr()));
503 cellular()->dispatcher()->PostDelayedTask(
504 activation_wait_for_registration_callback_.callback(),
505 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800506}
507
508void CellularCapabilityUniversal::ResetAfterActivation() {
509 SLOG(Cellular, 2) << __func__;
510
511 // Here the initial call to Reset might fail in rare cases. Simply ignore.
512 Error error;
513 ResultCallback callback = Bind(
514 &CellularCapabilityUniversal::OnResetAfterActivationReply,
515 weak_ptr_factory_.GetWeakPtr());
516 Reset(&error, callback);
517 if (error.IsFailure())
518 SLOG(Cellular, 2) << "Failed to reset after activation.";
519}
520
521void CellularCapabilityUniversal::OnResetAfterActivationReply(
522 const Error &error) {
523 SLOG(Cellular, 2) << __func__;
524 if (error.IsFailure()) {
525 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
526 // TODO(armansito): Maybe post a delayed reset task?
527 return;
528 }
529 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700530 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800531 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800532}
533
Arman Uguray0a3e2792013-01-17 16:31:50 -0800534void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800535 SLOG(Cellular, 2) << __func__;
536
537 bool registered =
538 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
539
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700540 // We know a service is activated if |subscription_state_| is
541 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
542 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
543 // fallback on checking for a valid MDN.
544 bool activated =
545 ((subscription_state_ == kSubscriptionStateProvisioned) ||
546 (subscription_state_ == kSubscriptionStateOutOfData)) ||
547 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
548
549 if (activated && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700550 modem_info()->pending_activation_store()->RemoveEntry(
551 PendingActivationStore::kIdentifierICCID,
552 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800553
Arman Ugurayefea6e02013-02-21 13:28:04 -0800554 CellularServiceRefPtr service = cellular()->service();
555
556 if (!service.get())
557 return;
558
Ben Chan7ea768e2013-09-20 15:08:40 -0700559 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800560 // Either no service or already activated. Nothing to do.
561 return;
562
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700563 // Besides the indicators above, a connected service also indicates an
564 // activated SIM.
565 if (activated || cellular()->state() == Cellular::kStateConnected ||
Arman Ugurayc7b15602013-02-16 00:56:18 -0800566 cellular()->state() == Cellular::kStateLinked) {
567 SLOG(Cellular, 2) << "Marking service as activated.";
Ben Chan7ea768e2013-09-20 15:08:40 -0700568 service->SetActivationState(kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800569 return;
570 }
571
572 // If the ICCID is not available, the following logic can be delayed until it
573 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800574 if (sim_identifier_.empty())
575 return;
576
Arman Uguray41cc6342013-03-29 16:34:39 -0700577 PendingActivationStore::State state =
578 modem_info()->pending_activation_store()->GetActivationState(
579 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700580 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800581 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700582 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800583 // Always mark the service as activating here, as the ICCID could have
584 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700585 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800586 if (reset_done_) {
587 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700588 modem_info()->pending_activation_store()->SetActivationState(
589 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800590 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700591 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800592 } else if (registered) {
593 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700594 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800595 ResetAfterActivation();
596 }
597 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700598 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800599 if (registered) {
600 // Trigger auto connect here.
601 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
602 << "autoconnect to force MDN to update.";
603 service->AutoConnect();
604 }
605 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700606 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700607 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
608 << "been reset at least once.";
609 if (registered) {
610 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700611 modem_info()->pending_activation_store()->SetActivationState(
612 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700613 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700614 PendingActivationStore::kStateActivated);
Ben Chan7ea768e2013-09-20 15:08:40 -0700615 service->SetActivationState(kActivationStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700616 }
617 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700618 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800619 // No entry exists for this ICCID. Nothing to do.
620 break;
621 default:
622 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800623 }
624}
625
Ben Chan07193fd2013-07-12 22:10:55 -0700626string CellularCapabilityUniversal::GetMdnForOLP(
627 const CellularOperatorInfo::CellularOperator &cellular_operator) const {
628 // TODO(benchan): This is ugly. Remove carrier specific code once we move
629 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Ben Chan200591a2013-08-07 14:39:04 -0700630 if (cellular_operator.identifier() == kVzwIdentifier) {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700631 // subscription_state_ is the definitive indicator of whether we need
632 // activation. The OLP expects an all zero MDN in that case.
633 if (subscription_state_ == kSubscriptionStateUnprovisioned ||
634 mdn_.empty()) {
Ben Chan200591a2013-08-07 14:39:04 -0700635 return string(kVzwMdnLength, '0');
636 }
637 if (mdn_.length() > kVzwMdnLength) {
638 return mdn_.substr(mdn_.length() - kVzwMdnLength);
639 }
Ben Chan07193fd2013-07-12 22:10:55 -0700640 }
641 return mdn_;
642}
643
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400644void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700645 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400646 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400647 modem_proxy_.reset();
648 modem_simple_proxy_.reset();
649 sim_proxy_.reset();
650}
651
Arman Ugurayc9533572013-01-22 17:34:20 -0800652void CellularCapabilityUniversal::UpdateStorageIdentifier() {
653 if (!cellular()->service().get())
654 return;
655
656 // Lookup the unique identifier assigned to the current network and base the
657 // service's storage identifier on it.
Arman Ugurayc5391232013-09-23 21:30:46 -0700658 const string kPrefix =
659 string(shill::kTypeCellular) + "_" + cellular()->address() + "_";
Arman Ugurayc9533572013-01-22 17:34:20 -0800660 string storage_id;
661 if (!operator_id_.empty()) {
662 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700663 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
664 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800665 if (provider && !provider->identifier().empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700666 storage_id = kPrefix + provider->identifier();
Arman Ugurayc9533572013-01-22 17:34:20 -0800667 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400668 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800669 // If the above didn't work, append IMSI, if available.
670 if (storage_id.empty() && !imsi_.empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700671 storage_id = kPrefix + imsi_;
Arman Ugurayc9533572013-01-22 17:34:20 -0800672 }
673 if (!storage_id.empty()) {
674 cellular()->service()->SetStorageIdentifier(storage_id);
675 }
676}
677
Arman Ugurayefea6e02013-02-21 13:28:04 -0800678void CellularCapabilityUniversal::UpdateServiceActivationState() {
679 if (!cellular()->service().get())
680 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800681 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700682 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700683 PendingActivationStore::State state =
684 modem_info()->pending_activation_store()->GetActivationState(
685 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700686 sim_identifier_);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700687 if ((subscription_state_ == kSubscriptionStateUnknown ||
688 subscription_state_ == kSubscriptionStateUnprovisioned) &&
689 !sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700690 (state == PendingActivationStore::kStatePending ||
691 state == PendingActivationStore::kStatePendingTimeout))
Ben Chan7ea768e2013-09-20 15:08:40 -0700692 activation_state = kActivationStateActivating;
Arman Ugurayefea6e02013-02-21 13:28:04 -0800693 else if (activation_required)
Ben Chan7ea768e2013-09-20 15:08:40 -0700694 activation_state = kActivationStateNotActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700695 else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700696 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700697
698 // Mark an activated service for auto-connect by default. Since data from
699 // the user profile will be loaded after the call to OnServiceCreated, this
700 // property will be corrected based on the user data at that time.
701 cellular()->service()->SetAutoConnect(true);
702 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800703 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800704 // TODO(benchan): For now, assume the cellular service is activated over
705 // a non-cellular network if service activation is required (i.e. a
706 // corresponding entry is found in the cellular operator info file).
707 // We will need to generalize this logic when migrating CDMA support from
708 // cromo to ModemManager.
709 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800710}
711
712void CellularCapabilityUniversal::OnServiceCreated() {
713 UpdateStorageIdentifier();
714 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800715 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400716 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800717 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700718
719 // WORKAROUND:
720 // E362 modems on Verizon network does not properly redirect when a SIM
721 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700722 //
723 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
724 // support is ready (crosbug.com/p/20461).
725 cellular()->service()->set_enforce_out_of_credits_detection(
726 ShouldDetectOutOfCredit());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700727
728 // Make sure that the network technology is set when the service gets
729 // created, just in case.
730 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400731}
732
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400733// Create the list of APNs to try, in the following order:
734// - last APN that resulted in a successful connection attempt on the
735// current network (if any)
736// - the APN, if any, that was set by the user
737// - the list of APNs found in the mobile broadband provider DB for the
738// home provider associated with the current SIM
739// - as a last resort, attempt to connect with no APN
740void CellularCapabilityUniversal::SetupApnTryList() {
741 apn_try_list_.clear();
742
743 DCHECK(cellular()->service().get());
744 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
745 if (apn_info)
746 apn_try_list_.push_back(*apn_info);
747
748 apn_info = cellular()->service()->GetUserSpecifiedApn();
749 if (apn_info)
750 apn_try_list_.push_back(*apn_info);
751
752 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
753}
754
755void CellularCapabilityUniversal::SetupConnectProperties(
756 DBusPropertiesMap *properties) {
757 SetupApnTryList();
758 FillConnectPropertyMap(properties);
759}
760
761void CellularCapabilityUniversal::FillConnectPropertyMap(
762 DBusPropertiesMap *properties) {
763
764 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400765 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400766 kPhoneNumber);
767
Jason Glasgow14521872012-05-07 19:12:15 -0400768 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400769 AllowRoaming());
770
771 if (!apn_try_list_.empty()) {
772 // Leave the APN at the front of the list, so that it can be recorded
773 // if the connect attempt succeeds.
774 Stringmap apn_info = apn_try_list_.front();
Ben Chan7ea768e2013-09-20 15:08:40 -0700775 SLOG(Cellular, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400776 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700777 apn_info[kApnProperty].c_str());
778 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400779 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700780 apn_info[kApnUsernameProperty].c_str());
781 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400782 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700783 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400784 }
785}
786
787void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400788 const DBus::Path &path,
789 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700790 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400791
Jason Glasgow7234ec32012-05-23 16:01:21 -0400792 CellularServiceRefPtr service = cellular()->service();
793 if (!service) {
794 // The service could have been deleted before our Connect() request
795 // completes if the modem was enabled and then quickly disabled.
796 apn_try_list_.clear();
797 } else if (error.IsFailure()) {
798 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400799 // The APN that was just tried (and failed) is still at the
800 // front of the list, about to be removed. If the list is empty
801 // after that, try one last time without an APN. This may succeed
802 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400803 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400804 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700805 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
806 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400807 DBusPropertiesMap props;
808 FillConnectPropertyMap(&props);
809 Error error;
810 Connect(props, &error, callback);
811 return;
812 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400813 } else {
814 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400815 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400816 apn_try_list_.clear();
817 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400818 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400819 }
820
821 if (!callback.is_null())
822 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800823
Arman Uguray0a3e2792013-01-17 16:31:50 -0800824 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400825}
826
827bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200828 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400829}
830
Arman Ugurayf84a4242013-04-09 20:01:07 -0700831bool CellularCapabilityUniversal::ShouldDetectOutOfCredit() const {
Prathmesh Prabhuffe5dcb2013-10-14 17:21:40 -0700832 return model_id_ == kE362ModelId;
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700833}
834
Jason Glasgowef965562012-04-10 16:12:35 -0400835void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700836 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400837
Jason Glasgowaf583282012-04-18 15:18:22 -0400838 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
839 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
840 cellular()->dbus_owner()));
841 DBusPropertiesMap properties(
842 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
843 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400844
Jason Glasgowaf583282012-04-18 15:18:22 -0400845 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
846 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400847}
848
Arman Uguray2717a102013-01-29 23:36:06 -0800849// static
850string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
851 return base::StringPrintf("%s %u",
852 kGenericServiceNamePrefix,
853 friendly_service_name_id_++);
854}
855
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400856string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200857 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800858
859 // If |serving_operator_| does not have an operator ID, call
860 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
861 if (serving_operator_.GetCode().empty()) {
862 UpdateOperatorInfo();
863 }
864
Darin Petkova4ca3c32012-08-17 16:05:24 +0200865 string name = serving_operator_.GetName();
866 string home_provider_name = cellular()->home_provider().GetName();
867 if (!name.empty()) {
868 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
869 // rules (TS 31.102 and annex A of 122.101).
870 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
871 !home_provider_name.empty()) {
872 return home_provider_name + " | " + name;
873 }
874 return name;
875 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400876 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200877 !home_provider_name.empty()) {
878 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400879 }
Arman Uguray2717a102013-01-29 23:36:06 -0800880 if (!serving_operator_.GetCode().empty()) {
881 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400882 }
Arman Uguray2717a102013-01-29 23:36:06 -0800883 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400884}
885
886void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700887 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800889
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700890 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400891 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800892
893 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
894 // one is available. If both were reported by the SIM, use IMSI.
895 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
896 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700897 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800898 spn_.c_str(),
899 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400900 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800901 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400902 return;
903 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400904
905 // Even if provider is the same as home_provider_, it is possible
906 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400907 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200908 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400909 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800910 // If Operator ID is available, use that as network code, otherwise
911 // use what was returned from the database.
912 if (!operator_id_.empty()) {
913 oper.SetCode(operator_id_);
914 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400915 oper.SetCode(provider->networks[0]);
916 }
917 if (provider->country) {
918 oper.SetCountry(provider->country);
919 }
920 if (spn_.empty()) {
921 const char *name = mobile_provider_get_name(provider);
922 if (name) {
923 oper.SetName(name);
924 }
925 } else {
926 oper.SetName(spn_);
927 }
928 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200929 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200930 << oper.GetName() << ", " << oper.GetCountry()
931 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400932 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800933 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400934}
935
Ben Chan8a2c01e2013-01-23 10:09:14 -0800936void CellularCapabilityUniversal::UpdateScanningProperty() {
937 // Set the Scanning property to true if there is a ongoing network scan
938 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
939 // to a network.
940 //
941 // TODO(benchan): As the Device DBus interface currently does not have a
942 // State property to indicate whether the device is being enabled, set the
943 // Scanning property to true when the modem is being enabled such that
944 // the network UI can start showing the initializing/scanning animation as
945 // soon as the modem is being enabled.
946 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800947 bool is_activated_service_waiting_for_registration =
948 ((modem_state == Cellular::kModemStateEnabled ||
949 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800950 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800951 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800952 modem_state == Cellular::kModemStateEnabling ||
953 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800954 scanning_;
955 if (new_scanning_or_searching != scanning_or_searching_) {
956 scanning_or_searching_ = new_scanning_or_searching;
Ben Chan7ea768e2013-09-20 15:08:40 -0700957 cellular()->adaptor()->EmitBoolChanged(kScanningProperty,
Ben Chan8a2c01e2013-01-23 10:09:14 -0800958 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800959
960 if (!scanning_or_searching_) {
961 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
962 scanning_or_searching_timeout_callback_.Cancel();
963 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
964 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
965 scanning_or_searching_timeout_callback_.Reset(
966 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
967 weak_ptr_factory_.GetWeakPtr()));
968 cellular()->dispatcher()->PostDelayedTask(
969 scanning_or_searching_timeout_callback_.callback(),
970 scanning_or_searching_timeout_milliseconds_);
971 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800972 }
973}
974
Arman Uguray1361c032013-02-11 17:53:39 -0800975void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
976 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
Ben Chan7ea768e2013-09-20 15:08:40 -0700977 << "kScanningProperty to |false|.";
Arman Uguray1361c032013-02-11 17:53:39 -0800978 scanning_or_searching_ = false;
Ben Chan7ea768e2013-09-20 15:08:40 -0700979 cellular()->adaptor()->EmitBoolChanged(kScanningProperty, false);
Arman Uguray1361c032013-02-11 17:53:39 -0800980}
981
Ben Chan6d0d1e72012-11-06 21:19:28 -0800982void CellularCapabilityUniversal::UpdateOLP() {
Ben Chan07193fd2013-07-12 22:10:55 -0700983 SLOG(Cellular, 2) << __func__;
984
Arman Ugurayf87fa2f2013-10-16 14:24:56 -0700985 // TODO(armansito): Do this mapping in MobileOperator (See crbug.com/298408).
Ben Chan07193fd2013-07-12 22:10:55 -0700986 const CellularOperatorInfo *cellular_operator_info =
987 modem_info()->cellular_operator_info();
988 if (!cellular_operator_info)
989 return;
990
991 const CellularOperatorInfo::CellularOperator *cellular_operator =
992 cellular_operator_info->GetCellularOperatorByMCCMNC(operator_id_);
993 if (!cellular_operator)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800994 return;
995
Arman Ugurayf4c61812013-01-10 18:58:39 -0800996 const CellularService::OLP *result =
Ben Chan07193fd2013-07-12 22:10:55 -0700997 cellular_operator_info->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -0800998 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800999 return;
1000
Arman Ugurayf4c61812013-01-10 18:58:39 -08001001 CellularService::OLP olp;
1002 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -08001003 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -08001004 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
1005 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
1006 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
Ben Chan07193fd2013-07-12 22:10:55 -07001007 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
1008 GetMdnForOLP(*cellular_operator));
Ben Chan6d0d1e72012-11-06 21:19:28 -08001009 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
Arman Ugurayf87fa2f2013-10-16 14:24:56 -07001010
1011 // TODO(armansito): Define constants for the OEM IDs in MobileOperator
1012 // (See crbug.com/298408).
1013 string oem_id = (model_id_ == kE362ModelId) ? "GOG3" : "QUA";
1014 ReplaceSubstringsAfterOffset(&post_data, 0, "${oem}", oem_id);
Ben Chan6d0d1e72012-11-06 21:19:28 -08001015 olp.SetPostData(post_data);
1016 cellular()->service()->SetOLP(olp);
1017}
1018
Arman Uguray2717a102013-01-29 23:36:06 -08001019void CellularCapabilityUniversal::UpdateServiceName() {
1020 if (cellular()->service()) {
1021 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
1022 }
1023}
1024
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001025void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001026 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -08001027 // TODO(armansito): Use CellularOperatorInfo here instead of
1028 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -08001029
Arman Uguray3645c432013-01-31 15:57:26 -08001030 // Sometimes the modem fails to acquire the operator code OTA, in which case
1031 // |serving_operator_| may not have an operator ID (sometimes due to service
1032 // activation being required or broken modem firmware). Use |operator_id_| as
1033 // a fallback when available. |operator_id_| is retrieved from the SIM card.
1034 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -08001035 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
1036 << "' as serving operator.";
1037 serving_operator_.SetCode(operator_id_);
Arman Uguray41c64712013-10-11 18:12:31 -07001038 } else if (!serving_operator_.GetCode().empty() && operator_id_.empty()) {
1039 // Sometimes the SIM may fail to report an operator code. Since we build
1040 // the APN list based on home provider, report that the serving operator
1041 // is the home provider.
1042 // TODO(armansito): This is clearly not the best behavior for the roaming
1043 // case: we are now reporting that the roaming carrier is the same as the
1044 // home carrier. While this is not preferable, we don't have any home
1045 // provider to report either way, so this won't hurt the user experience.
1046 // This is a quick fix needed for the M31 release (crbug.com/306310).
1047 // Remove it with a better approach for M32 (crbug.com/298408).
1048 SLOG(Cellular, 2) << "Home provider is unknown but serving operator is. "
1049 << "Reporting serving operator as home provider.";
1050 operator_id_ = serving_operator_.GetCode();
1051 SetHomeProvider();
Ben Chan092b12b2012-11-07 22:04:05 -08001052 }
1053
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001054 const string &network_id = serving_operator_.GetCode();
1055 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001056 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001057 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001058 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001059 network_id.c_str());
1060 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +02001061 if (serving_operator_.GetName().empty()) {
1062 const char *provider_name = mobile_provider_get_name(provider);
1063 if (provider_name && *provider_name) {
1064 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001065 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001066 }
Darin Petkova4ca3c32012-08-17 16:05:24 +02001067 if (provider->country && *provider->country) {
1068 serving_operator_.SetCountry(provider->country);
1069 }
1070 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
1071 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001072 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001073 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001074 }
1075 }
1076 UpdateServingOperator();
1077}
1078
1079void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001080 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001081 if (cellular()->service().get()) {
1082 cellular()->service()->SetServingOperator(serving_operator_);
1083 }
1084}
1085
Arman Uguray6e5639f2012-11-15 20:30:19 -08001086void CellularCapabilityUniversal::UpdateBearerPath() {
1087 SLOG(Cellular, 2) << __func__;
1088 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1089 weak_ptr_factory_.GetWeakPtr());
1090 Error error;
mukesh agrawal510cc802013-08-15 18:31:42 -07001091 if (!modem_proxy_) {
1092 // This can be a perfectly legitimate state to be in, as this
1093 // function can be called before StartModem. In particular, this
1094 // happens when a Cellular object is contructed in
1095 // Modem::CreateDeviceFromModemProperties.
1096 LOG(INFO) << "Skipping ListBearers due to uninitialized modem_proxy_.";
1097 return;
1098 }
Arman Uguray6e5639f2012-11-15 20:30:19 -08001099 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1100}
1101
1102void CellularCapabilityUniversal::OnListBearersReply(
1103 const std::vector<DBus::Path> &paths,
1104 const Error &error) {
1105 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1106 if (error.IsFailure()) {
1107 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1108 return;
1109 }
1110 // Look for the first active bearer and use its path as the connected
1111 // one. Right now, we don't allow more than one active bearer.
mukesh agrawal9da07772013-05-15 14:15:17 -07001112 DBus::Path new_bearer_path;
1113 uint32 ipconfig_method(MM_BEARER_IP_METHOD_UNKNOWN);
1114 string network_device;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001115 for (size_t i = 0; i < paths.size(); ++i) {
1116 const DBus::Path &path = paths[i];
Ben Chan5db19692013-07-09 23:07:03 -07001117
1118 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1119 proxy_factory()->CreateDBusPropertiesProxy(path,
1120 cellular()->dbus_owner()));
1121 DBusPropertiesMap properties(
1122 properties_proxy->GetAll(MM_DBUS_INTERFACE_BEARER));
1123 if (properties.empty()) {
1124 LOG(WARNING) << "Could not get properties of bearer \"" << path
1125 << "\". Bearer is likely gone and thus ignored.";
mukesh agrawal9da07772013-05-15 14:15:17 -07001126 continue;
1127 }
Ben Chan5db19692013-07-09 23:07:03 -07001128
1129 bool connected = false;
1130 if (!DBusProperties::GetBool(
1131 properties, MM_BEARER_PROPERTY_CONNECTED, &connected)) {
1132 SLOG(Cellular, 2) << "Bearer does not indicate whether it is connected "
1133 "or not. Assume it is not connected.";
1134 continue;
1135 }
1136
1137 if (!connected) {
1138 continue;
1139 }
1140
mukesh agrawal9da07772013-05-15 14:15:17 -07001141 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan5db19692013-07-09 23:07:03 -07001142 CHECK(new_bearer_path.empty()) << "Found more than one active bearer.";
1143
1144 if (DBusProperties::GetString(
1145 properties, MM_BEARER_PROPERTY_INTERFACE, &network_device)) {
1146 SLOG(Cellular, 2) << "Bearer uses network interface \"" << network_device
1147 << "\".";
1148 } else {
1149 SLOG(Cellular, 2) << "Bearer does not specify network interface.";
1150 }
1151
mukesh agrawal9da07772013-05-15 14:15:17 -07001152 // TODO(quiche): Add support for scenarios where the bearer is
1153 // IPv6 only, or where there are conflicting configuration methods
1154 // for IPv4 and IPv6. crbug.com/248360.
Ben Chan5db19692013-07-09 23:07:03 -07001155 DBusPropertiesMap bearer_ip4config;
1156 DBusProperties::GetDBusPropertiesMap(
1157 properties, MM_BEARER_PROPERTY_IP4CONFIG, &bearer_ip4config);
1158
1159 if (DBusProperties::GetUint32(
1160 bearer_ip4config, kIpConfigPropertyMethod, &ipconfig_method)) {
mukesh agrawal9da07772013-05-15 14:15:17 -07001161 SLOG(Cellular, 2) << "Bearer has IPv4 config method " << ipconfig_method;
1162 } else {
1163 SLOG(Cellular, 2) << "Bearer does not specify IPv4 config method.";
1164 for (const auto &i : bearer_ip4config) {
1165 SLOG(Cellular, 5) << "Bearer IPv4 config has key \""
1166 << i.first
1167 << "\".";
Arman Uguray6e5639f2012-11-15 20:30:19 -08001168 }
1169 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001170 new_bearer_path = path;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001171 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001172 bearer_path_ = new_bearer_path;
1173 if (new_bearer_path.empty()) {
1174 SLOG(Cellular, 2) << "No active bearer found.";
1175 return;
1176 }
1177 if (ipconfig_method == MM_BEARER_IP_METHOD_PPP) {
1178 cellular()->StartPPP(network_device);
Arman Uguray6e5639f2012-11-15 20:30:19 -08001179 }
1180}
1181
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001182void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001183 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001184 if (!home_provider_) {
1185 return;
1186 }
1187 apn_list_.clear();
1188 for (int i = 0; i < home_provider_->num_apns; ++i) {
1189 Stringmap props;
1190 mobile_apn *apn = home_provider_->apns[i];
1191 if (apn->value) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001192 props[kApnProperty] = apn->value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001193 }
1194 if (apn->username) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001195 props[kApnUsernameProperty] = apn->username;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001196 }
1197 if (apn->password) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001198 props[kApnPasswordProperty] = apn->password;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001199 }
1200 // Find the first localized and non-localized name, if any.
1201 const localized_name *lname = NULL;
1202 const localized_name *name = NULL;
1203 for (int j = 0; j < apn->num_names; ++j) {
1204 if (apn->names[j]->lang) {
1205 if (!lname) {
1206 lname = apn->names[j];
1207 }
1208 } else if (!name) {
1209 name = apn->names[j];
1210 }
1211 }
1212 if (name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001213 props[kApnNameProperty] = name->name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001214 }
1215 if (lname) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001216 props[kApnLocalizedNameProperty] = lname->name;
1217 props[kApnLanguageProperty] = lname->lang;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001218 }
1219 apn_list_.push_back(props);
1220 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001221 if (cellular()->adaptor()) {
1222 cellular()->adaptor()->EmitStringmapsChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001223 kCellularApnListProperty, apn_list_);
Darin Petkovdb6083f2012-08-16 12:50:23 +02001224 } else {
1225 LOG(ERROR) << "Null RPC service adaptor.";
1226 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001227}
1228
Ben Chan15786032012-11-04 21:28:02 -08001229bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001230 // subscription_state_ is the definitive answer. If that does not work,
1231 // fallback on MDN based logic.
1232 if (subscription_state_ == kSubscriptionStateProvisioned ||
1233 subscription_state_ == kSubscriptionStateOutOfData)
1234 return false;
1235
1236 // We are in the process of activating, ignore all other clues from the
1237 // network and use our own knowledge about the activation state.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001238 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001239 modem_info()->pending_activation_store()->GetActivationState(
1240 PendingActivationStore::kIdentifierICCID,
1241 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001242 return false;
1243
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001244 // Network notification that the service needs to be activated.
1245 if (subscription_state_ == kSubscriptionStateUnprovisioned)
1246 return true;
1247
Ben Chan15786032012-11-04 21:28:02 -08001248 // If there is no online payment portal information, it's safer to assume
1249 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001250 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001251 return false;
1252
Arman Ugurayf4c61812013-01-10 18:58:39 -08001253 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001254 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001255 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001256 return false;
1257
Ben Chan200591a2013-08-07 14:39:04 -07001258 // If the MDN is invalid (i.e. empty or contains only zeros), the service
1259 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001260 return !IsMdnValid();
1261}
1262
1263bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001264 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001265 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001266 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001267 return true;
Ben Chan15786032012-11-04 21:28:02 -08001268 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001269 return false;
Ben Chan15786032012-11-04 21:28:02 -08001270}
1271
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001272// always called from an async context
1273void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001274 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001275 CHECK(!callback.is_null());
1276 Error error;
1277 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1278 weak_ptr_factory_.GetWeakPtr(), callback);
1279 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1280 if (error.IsFailure())
1281 callback.Run(error);
1282}
1283
1284void CellularCapabilityUniversal::RegisterOnNetwork(
1285 const string &network_id,
1286 Error *error,
1287 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001288 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001289 CHECK(error);
1290 desired_network_ = network_id;
1291 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1292 weak_ptr_factory_.GetWeakPtr(), callback);
1293 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1294}
1295
1296void CellularCapabilityUniversal::OnRegisterReply(
1297 const ResultCallback &callback,
1298 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001299 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001300
1301 if (error.IsSuccess()) {
1302 selected_network_ = desired_network_;
1303 desired_network_.clear();
1304 callback.Run(error);
1305 return;
1306 }
1307 // If registration on the desired network failed,
1308 // try to register on the home network.
1309 if (!desired_network_.empty()) {
1310 desired_network_.clear();
1311 selected_network_.clear();
1312 LOG(INFO) << "Couldn't register on selected network, trying home network";
1313 Register(callback);
1314 return;
1315 }
1316 callback.Run(error);
1317}
1318
1319bool CellularCapabilityUniversal::IsRegistered() {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001320 return IsRegisteredState(registration_state_);
1321}
1322
1323bool CellularCapabilityUniversal::IsRegisteredState(
1324 MMModem3gppRegistrationState state) {
1325 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1326 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001327}
1328
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001329void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1330 // If we're already in some non-registered state, don't override that
1331 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1332 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1333 registration_state_ =
1334 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1335 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1336 }
1337}
1338
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001339void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001340 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001341 Error *error, const ResultCallback &callback) {
1342 CHECK(error);
1343 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1344}
1345
1346void CellularCapabilityUniversal::EnterPIN(const string &pin,
1347 Error *error,
1348 const ResultCallback &callback) {
1349 CHECK(error);
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001350 SLOG(Cellular, 2) << __func__;
1351 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001352}
1353
1354void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1355 const string &pin,
1356 Error *error,
1357 const ResultCallback &callback) {
1358 CHECK(error);
1359 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1360}
1361
1362void CellularCapabilityUniversal::ChangePIN(
1363 const string &old_pin, const string &new_pin,
1364 Error *error, const ResultCallback &callback) {
1365 CHECK(error);
1366 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1367}
1368
Ben Chan5d0d32c2013-01-08 02:05:29 -08001369void CellularCapabilityUniversal::Reset(Error *error,
1370 const ResultCallback &callback) {
1371 SLOG(Cellular, 2) << __func__;
1372 CHECK(error);
1373 if (resetting_) {
1374 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1375 return;
1376 }
1377 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1378 weak_ptr_factory_.GetWeakPtr(), callback);
1379 modem_proxy_->Reset(error, cb, kTimeoutReset);
1380 if (!error->IsFailure()) {
1381 resetting_ = true;
1382 }
1383}
1384
1385void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1386 const Error &error) {
1387 SLOG(Cellular, 2) << __func__;
1388 resetting_ = false;
1389 if (!callback.is_null())
1390 callback.Run(error);
1391}
1392
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001393void CellularCapabilityUniversal::Scan(Error *error,
1394 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001395 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001396 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001397 if (scanning_) {
1398 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1399 return;
1400 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001401 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1402 weak_ptr_factory_.GetWeakPtr(), callback);
1403 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001404 if (!error->IsFailure()) {
1405 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001406 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001407 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001408}
1409
1410void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1411 const ScanResults &results,
1412 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001413 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001414
1415 // Error handling is weak. The current expectation is that on any
1416 // error, found_networks_ should be cleared and a property change
1417 // notification sent out.
1418 //
1419 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001420 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001421 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001422 found_networks_.clear();
1423 if (!error.IsFailure()) {
1424 for (ScanResults::const_iterator it = results.begin();
1425 it != results.end(); ++it) {
1426 found_networks_.push_back(ParseScanResult(*it));
1427 }
1428 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001429 cellular()->adaptor()->EmitStringmapsChanged(kFoundNetworksProperty,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001430 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001431
1432 // TODO(gmorain): This check for is_null() is a work-around because
1433 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1434 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1435 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1436 // Universal.
1437 if (!callback.is_null())
1438 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001439}
1440
1441Stringmap CellularCapabilityUniversal::ParseScanResult(
1442 const ScanResult &result) {
1443
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001444 /* ScanResults contain the following keys:
1445
1446 "status"
1447 A MMModem3gppNetworkAvailability value representing network
1448 availability status, given as an unsigned integer (signature "u").
1449 This key will always be present.
1450
1451 "operator-long"
1452 Long-format name of operator, given as a string value (signature
1453 "s"). If the name is unknown, this field should not be present.
1454
1455 "operator-short"
1456 Short-format name of operator, given as a string value
1457 (signature "s"). If the name is unknown, this field should not
1458 be present.
1459
1460 "operator-code"
1461 Mobile code of the operator, given as a string value (signature
1462 "s"). Returned in the format "MCCMNC", where MCC is the
1463 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1464 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1465
1466 "access-technology"
1467 A MMModemAccessTechnology value representing the generic access
1468 technology used by this mobile network, given as an unsigned
1469 integer (signature "u").
1470 */
1471 Stringmap parsed;
1472
1473 uint32 status;
1474 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1475 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1476 static const char * const kStatusString[] = {
1477 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1478 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1479 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1480 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1481 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001482 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001483 }
1484
1485 uint32 tech; // MMModemAccessTechnology
1486 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1487 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001488 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001489 }
1490
1491 string operator_long, operator_short, operator_code;
1492 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001493 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001494 if (DBusProperties::GetString(result, kOperatorShortProperty,
1495 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001496 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001497 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001498 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001499
1500 // If the long name is not available but the network ID is, look up the long
1501 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001502 if ((!ContainsKey(parsed, kLongNameProperty) ||
1503 parsed[kLongNameProperty].empty()) &&
1504 ContainsKey(parsed, kNetworkIdProperty)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001505 mobile_provider *provider =
1506 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001507 modem_info()->provider_db(),
Ben Chan7ea768e2013-09-20 15:08:40 -07001508 parsed[kNetworkIdProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001509 if (provider) {
1510 const char *long_name = mobile_provider_get_name(provider);
1511 if (long_name && *long_name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001512 parsed[kLongNameProperty] = long_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001513 }
1514 }
1515 }
1516 return parsed;
1517}
1518
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001519string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001520 // If we know that the modem is an E362, return LTE here to make sure that
1521 // Chrome sees LTE as the network technology even if the actual technology is
1522 // unknown.
1523 // TODO(armansito): This hack will cause the UI to display LTE even if the
1524 // modem doesn't support it at a given time. This might be problematic if we
1525 // ever want to support switching between access technologies (e.g. falling
1526 // back to 3G when LTE is not available).
1527 if (model_id_ == kE362ModelId)
Ben Chan7ea768e2013-09-20 15:08:40 -07001528 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001529
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001530 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001531 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001532 return AccessTechnologyToString(access_technologies_);
1533}
1534
1535string CellularCapabilityUniversal::GetRoamingStateString() const {
1536 switch (registration_state_) {
1537 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001538 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001539 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001540 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001541 default:
1542 break;
1543 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001544 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001545}
1546
Arman Uguray5d9a8522013-09-10 17:43:13 -07001547// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001548void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001549 // ModemManager always returns the cached value, so there is no need to
1550 // trigger an update here. The true value is updated through a property
1551 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001552}
1553
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001554string CellularCapabilityUniversal::GetTypeString() const {
1555 return AccessTechnologyToTechnologyFamily(access_technologies_);
1556}
1557
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001558void CellularCapabilityUniversal::OnModemPropertiesChanged(
1559 const DBusPropertiesMap &properties,
1560 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001561 // This solves a bootstrapping problem: If the modem is not yet
1562 // enabled, there are no proxy objects associated with the capability
1563 // object, so modem signals like StateChanged aren't seen. By monitoring
1564 // changes to the State property via the ModemManager, we're able to
1565 // get the initialization process started, which will result in the
1566 // creation of the proxy objects.
1567 //
1568 // The first time we see the change to State (when the modem state
1569 // is Unknown), we simply update the state, and rely on the Manager to
1570 // enable the device when it is registered with the Manager. On subsequent
1571 // changes to State, we need to explicitly enable the device ourselves.
1572 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001573 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001574 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001575 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001576 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001577 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001578 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001579 MM_MODEM_PROPERTY_SIM, &object_path_value))
1580 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001581
1582 DBusPropertiesMap::const_iterator it =
1583 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1584 if (it != properties.end()) {
1585 const vector<uint32> &supported_capabilities = it->second;
1586 OnSupportedCapabilitesChanged(supported_capabilities);
1587 }
1588
Jason Glasgowaf583282012-04-18 15:18:22 -04001589 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001590 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001591 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1592 &uint_value))
1593 OnModemCurrentCapabilitiesChanged(uint_value);
1594 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1595 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001596 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001597 if (DBusProperties::GetString(properties,
1598 MM_MODEM_PROPERTY_MANUFACTURER,
1599 &string_value))
1600 OnModemManufacturerChanged(string_value);
1601 if (DBusProperties::GetString(properties,
1602 MM_MODEM_PROPERTY_MODEL,
1603 &string_value))
1604 OnModemModelChanged(string_value);
1605 if (DBusProperties::GetString(properties,
1606 MM_MODEM_PROPERTY_REVISION,
1607 &string_value))
1608 OnModemRevisionChanged(string_value);
1609 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1610 // not needed: MM_MODEM_PROPERTY_DEVICE
1611 // not needed: MM_MODEM_PROPERTY_DRIVER
1612 // not needed: MM_MODEM_PROPERTY_PLUGIN
1613 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001614
Jason Glasgowaf583282012-04-18 15:18:22 -04001615 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001616 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001617 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001618 if (DBusProperties::GetUint32(properties,
1619 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001620 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001621 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001622 lock_status_changed = true;
1623 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001624
1625 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001626 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001627 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001628 LockRetryData lock_retries = it->second.operator LockRetryData();
1629 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001630 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001631 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001632
Arman Ugurayea5ff272013-06-25 10:28:02 -07001633 if (lock_status_changed)
1634 OnSimLockStatusChanged();
1635
Jason Glasgowaf583282012-04-18 15:18:22 -04001636 if (DBusProperties::GetUint32(properties,
1637 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1638 &uint_value))
1639 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001640
Jason Glasgowaf583282012-04-18 15:18:22 -04001641 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1642 if (it != properties.end()) {
1643 DBus::Struct<unsigned int, bool> quality = it->second;
1644 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001645 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001646 vector<string> numbers;
1647 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1648 &numbers)) {
1649 string mdn;
1650 if (numbers.size() > 0)
1651 mdn = numbers[0];
1652 OnMdnChanged(mdn);
1653 }
Ben Chan74924d82013-06-15 17:52:55 -07001654
1655 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1656 if (it != properties.end()) {
1657 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1658 vector<ModemModes> supported_modes;
1659 for (const auto &modes : mm_supported_modes) {
1660 supported_modes.push_back(
1661 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1662 }
1663 OnSupportedModesChanged(supported_modes);
1664 }
1665
1666 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1667 if (it != properties.end()) {
1668 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1669 OnCurrentModesChanged(ModemModes(
1670 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1671 }
1672
Jason Glasgowaf583282012-04-18 15:18:22 -04001673 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1674 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001675}
1676
1677void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1678 const string &interface,
1679 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001680 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001681 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001682 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001683 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001684 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001685 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1686 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001687 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001688 if (interface == MM_DBUS_INTERFACE_SIM) {
1689 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001690 }
1691}
1692
Jason Glasgow14521872012-05-07 19:12:15 -04001693bool CellularCapabilityUniversal::RetriableConnectError(
1694 const Error &error) const {
1695 if (error.type() == Error::kInvalidApn)
1696 return true;
1697
1698 // modemmanager does not ever return kInvalidApn for E362 modems
1699 // with 1.41 firmware. It remains to be seem if this will change
1700 // with 3.x firmware.
1701 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1702 return true;
1703
1704 return false;
1705}
1706
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001707void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1708 // TODO(petkov): Implement this.
1709 NOTIMPLEMENTED();
1710}
1711
Arman Uguray6552f8c2013-02-12 15:33:18 -08001712bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1713 return !sim_path.empty() && sim_path != kRootPath;
1714}
1715
Ben Chand7592522013-02-13 16:02:01 -08001716string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1717 string normalized_mdn;
1718 for (size_t i = 0; i < mdn.size(); ++i) {
1719 if (IsAsciiDigit(mdn[i]))
1720 normalized_mdn += mdn[i];
1721 }
1722 return normalized_mdn;
1723}
1724
Jason Glasgowaf583282012-04-18 15:18:22 -04001725void CellularCapabilityUniversal::OnSimPathChanged(
1726 const string &sim_path) {
1727 if (sim_path == sim_path_)
1728 return;
1729
1730 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001731 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001732 proxy = proxy_factory()->CreateSimProxy(sim_path,
1733 cellular()->dbus_owner());
1734 sim_path_ = sim_path;
1735 sim_proxy_.reset(proxy);
1736
Arman Uguray6552f8c2013-02-12 15:33:18 -08001737 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001738 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001739 imsi_ = "";
1740 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001741 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001742 OnSimIdentifierChanged("");
1743 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001744 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001745 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001746 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1747 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1748 cellular()->dbus_owner()));
1749 // TODO(jglasgow): convert to async interface
1750 DBusPropertiesMap properties(
1751 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1752 OnSimPropertiesChanged(properties, vector<string>());
1753 }
1754}
1755
Ben Chan74924d82013-06-15 17:52:55 -07001756void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1757 const vector<uint32> &supported_capabilities) {
1758 supported_capabilities_ = supported_capabilities;
1759}
1760
Jason Glasgowaf583282012-04-18 15:18:22 -04001761void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1762 uint32 current_capabilities) {
1763 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001764
1765 // Only allow network scan when the modem's current capabilities support
1766 // GSM/UMTS.
1767 //
1768 // TODO(benchan): We should consider having the modem plugins in ModemManager
1769 // reporting whether network scan is supported.
1770 scanning_supported_ =
1771 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1772 if (cellular()->adaptor()) {
1773 cellular()->adaptor()->EmitBoolChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001774 kSupportNetworkScanProperty, scanning_supported_);
Ben Chanfcca27b2013-01-22 15:03:44 -08001775 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001776}
1777
1778void CellularCapabilityUniversal::OnMdnChanged(
1779 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001780 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001781 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001782}
1783
1784void CellularCapabilityUniversal::OnModemManufacturerChanged(
1785 const string &manufacturer) {
1786 manufacturer_ = manufacturer;
1787}
1788
1789void CellularCapabilityUniversal::OnModemModelChanged(
1790 const string &model) {
1791 model_id_ = model;
1792}
1793
1794void CellularCapabilityUniversal::OnModemRevisionChanged(
1795 const string &revision) {
1796 firmware_revision_ = revision;
1797}
1798
1799void CellularCapabilityUniversal::OnModemStateChanged(
1800 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001801 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001802
1803 cellular()->OnModemStateChanged(state);
1804 UpdateScanningProperty();
1805 // TODO(armansito): Move the deferred enable logic to Cellular
1806 // (See crbug.com/279499).
1807 if (!deferred_enable_modem_callback_.is_null() &&
1808 state == Cellular::kModemStateDisabled) {
1809 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1810 deferred_enable_modem_callback_.Run();
1811 deferred_enable_modem_callback_.Reset();
1812 } else if (state == Cellular::kModemStateConnected) {
mukesh agrawal510cc802013-08-15 18:31:42 -07001813 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1814 UpdateBearerPath();
1815 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001816}
1817
1818void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1819 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001820 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001821 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001822 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001823 const string new_type_string(GetTypeString());
1824 if (new_type_string != old_type_string) {
1825 // TODO(jglasgow): address layering violation of emitting change
1826 // signal here for a property owned by Cellular.
1827 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001828 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001829 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001830 if (cellular()->service().get()) {
1831 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1832 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001833 }
1834}
1835
Ben Chan74924d82013-06-15 17:52:55 -07001836void CellularCapabilityUniversal::OnSupportedModesChanged(
1837 const vector<ModemModes> &supported_modes) {
1838 supported_modes_ = supported_modes;
1839}
1840
1841void CellularCapabilityUniversal::OnCurrentModesChanged(
1842 const ModemModes &current_modes) {
1843 current_modes_ = current_modes;
1844}
1845
Jason Glasgowaf583282012-04-18 15:18:22 -04001846void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001847 const LockRetryData &lock_retries) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001848 SLOG(Cellular, 2) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001849
Arman Ugurayea5ff272013-06-25 10:28:02 -07001850 // Look for the retries left for the current lock. Try the obtain the count
1851 // that matches the current count. If no count for the current lock is
1852 // available, report the first one in the dictionary.
1853 LockRetryData::const_iterator it =
1854 lock_retries.find(sim_lock_status_.lock_type);
1855 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001856 it = lock_retries.begin();
1857 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001858 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001859 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001860 // Unknown, use 999
1861 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001862}
1863
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001864void CellularCapabilityUniversal::OnLockTypeChanged(
1865 MMModemLock lock_type) {
1866 SLOG(Cellular, 2) << __func__ << ": " << lock_type;
1867 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001868
1869 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1870 // This is because the corresponding property 'EnabledFacilityLocks' is on
1871 // the 3GPP interface and the 3GPP interface is not available while the Modem
1872 // is in the 'LOCKED' state.
1873 if (lock_type != MM_MODEM_LOCK_NONE &&
1874 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1875 !sim_lock_status_.enabled)
1876 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001877}
1878
Jason Glasgowaf583282012-04-18 15:18:22 -04001879void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001880 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001881 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001882 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001883
1884 // If the SIM is currently unlocked, assume that we need to refresh
1885 // carrier information, since a locked SIM prevents shill from obtaining
1886 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001887 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001888 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1889 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001890 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1891 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1892 cellular()->dbus_owner()));
1893 DBusPropertiesMap properties(
1894 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1895 OnSimPropertiesChanged(properties, vector<string>());
1896 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001897}
1898
1899void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1900 const DBusPropertiesMap &properties,
1901 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001902 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001903 uint32 uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001904 string imei;
1905 if (DBusProperties::GetString(properties,
1906 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1907 &imei))
1908 OnImeiChanged(imei);
1909
1910 // Handle registration state changes as a single change
1911 string operator_code = serving_operator_.GetCode();
1912 string operator_name = serving_operator_.GetName();
1913 MMModem3gppRegistrationState state = registration_state_;
1914 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001915 if (DBusProperties::GetUint32(properties,
1916 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1917 &uint_value)) {
1918 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1919 registration_changed = true;
1920 }
1921 if (DBusProperties::GetString(properties,
1922 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1923 &operator_code))
1924 registration_changed = true;
1925 if (DBusProperties::GetString(properties,
1926 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1927 &operator_name))
1928 registration_changed = true;
1929 if (registration_changed)
1930 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001931 if (DBusProperties::GetUint32(properties,
1932 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1933 &uint_value))
1934 On3GPPSubscriptionStateChanged(
1935 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001936
1937 uint32 locks = 0;
1938 if (DBusProperties::GetUint32(
1939 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1940 &locks))
1941 OnFacilityLocksChanged(locks);
1942}
1943
1944void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1945 imei_ = imei;
1946}
1947
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001948void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1949 MMModem3gppRegistrationState state,
1950 const string &operator_code,
1951 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001952 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1953 << ", opercode=" << operator_code
1954 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001955
1956 // While the modem is connected, if the state changed from a registered state
1957 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001958 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1959 IsRegistered() && !IsRegisteredState(state)) {
1960 if (!registration_dropped_update_callback_.IsCancelled()) {
1961 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1962 << "Ignoring earlier notifications.";
1963 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001964 } else {
1965 // This is not a repeated post. So, count this instance of delayed drop
1966 // posted.
1967 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001968 }
1969 SLOG(Cellular, 2) << "Posted deferred registration state update";
1970 registration_dropped_update_callback_.Reset(
1971 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1972 weak_ptr_factory_.GetWeakPtr(),
1973 state,
1974 operator_code,
1975 operator_name));
1976 cellular()->dispatcher()->PostDelayedTask(
1977 registration_dropped_update_callback_.callback(),
1978 registration_dropped_update_timeout_milliseconds_);
1979 } else {
1980 if (!registration_dropped_update_callback_.IsCancelled()) {
1981 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1982 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001983 // If we cancelled the callback here, it means we had flaky network for a
1984 // small duration.
1985 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001986 }
1987 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1988 }
1989}
1990
1991void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1992 MMModem3gppRegistrationState updated_state,
1993 string updated_operator_code,
1994 string updated_operator_name) {
1995 // A finished callback does not qualify as a canceled callback.
1996 // We test for a canceled callback to check for outstanding callbacks.
1997 // So, explicitly cancel the callback here.
1998 registration_dropped_update_callback_.Cancel();
1999
2000 SLOG(Cellular, 2) << __func__ << ": regstate=" << updated_state
2001 << ", opercode=" << updated_operator_code
2002 << ", opername=" << updated_operator_name;
2003
2004 registration_state_ = updated_state;
2005 serving_operator_.SetCode(updated_operator_code);
2006 serving_operator_.SetName(updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08002007
2008 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002009 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08002010
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002011 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08002012
2013 // Update the user facing name of the cellular service.
2014 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08002015
2016 // If the modem registered with the network and the current ICCID is pending
2017 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08002018 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002019}
2020
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07002021void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
2022 MMModem3gppSubscriptionState updated_state) {
2023 SLOG(Cellular, 2) << __func__ << ": Updated subscription state = "
2024 << updated_state;
2025
2026 // A one-to-one enum mapping.
2027 switch (updated_state) {
2028 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
2029 subscription_state_ = kSubscriptionStateUnknown;
2030 break;
2031 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
2032 subscription_state_ = kSubscriptionStateProvisioned;
2033 break;
2034 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
2035 subscription_state_ = kSubscriptionStateUnprovisioned;
2036 break;
2037 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
2038 subscription_state_ = kSubscriptionStateOutOfData;
2039 break;
2040 default:
2041 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
2042 << updated_state;
2043 subscription_state_ = kSubscriptionStateUnknown;
2044 return;
2045 }
2046
2047 UpdateServiceActivationState();
2048 UpdatePendingActivationState();
2049}
2050
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04002051void CellularCapabilityUniversal::OnModemStateChangedSignal(
2052 int32 old_state, int32 new_state, uint32 reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07002053 Cellular::ModemState old_modem_state =
2054 static_cast<Cellular::ModemState>(old_state);
2055 Cellular::ModemState new_modem_state =
2056 static_cast<Cellular::ModemState>(new_state);
2057 SLOG(Cellular, 2) << __func__ << "("
2058 << Cellular::GetModemStateString(old_modem_state) << ", "
2059 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04002060 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04002061}
2062
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002063void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
2064 cellular()->HandleNewSignalQuality(quality);
2065}
2066
Jason Glasgowaf583282012-04-18 15:18:22 -04002067void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07002068 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
2069 if (sim_lock_status_.enabled != sim_enabled) {
2070 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04002071 OnSimLockStatusChanged();
2072 }
2073}
Jason Glasgowef965562012-04-10 16:12:35 -04002074
Jason Glasgowaf583282012-04-18 15:18:22 -04002075void CellularCapabilityUniversal::OnSimPropertiesChanged(
2076 const DBusPropertiesMap &props,
2077 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002078 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04002079 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04002080 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
2081 OnSimIdentifierChanged(value);
2082 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
2083 &value))
2084 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08002085 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
2086 OnSpnChanged(value);
2087 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
2088 OnImsiChanged(value);
2089 SetHomeProvider();
2090}
Jason Glasgowaf583282012-04-18 15:18:22 -04002091
Arman Ugurayd73783f2013-01-31 16:11:21 -08002092// TODO(armansito): The following methods should probably log their argument
2093// values. Need to learn if any of them need to be scrubbed.
2094void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
2095 imsi_ = imsi;
2096}
2097
2098void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
2099 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04002100}
2101
2102void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
2103 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08002104 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04002105}
2106
2107void CellularCapabilityUniversal::OnOperatorIdChanged(
2108 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002109 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04002110 operator_id_ = operator_id;
2111}
2112
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002113} // namespace shill