blob: decded18d84b135f41b4ce5e935c78f3db19aa60 [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";
Thieu Le43ce4d42013-10-04 16:08:55 -070072const char CellularCapabilityUniversal::kALT3100ModelId[] = "ALT3100";
Jason Glasgow14521872012-05-07 19:12:15 -040073const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080074const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
75 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040076unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
77
Ben Chan07193fd2013-07-12 22:10:55 -070078namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040079
Ben Chan07193fd2013-07-12 22:10:55 -070080const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040081
Ben Chan07193fd2013-07-12 22:10:55 -070082// This identifier is specified in the cellular_operator_info file.
83const char kVzwIdentifier[] = "vzw";
84const size_t kVzwMdnLength = 10;
85
86string AccessTechnologyToString(uint32 access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040087 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
Ben Chan7ea768e2013-09-20 15:08:40 -070088 return kNetworkTechnologyLte;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040089 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
90 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
91 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
Ben Chan7ea768e2013-09-20 15:08:40 -070092 return kNetworkTechnologyEvdo;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
Ben Chan7ea768e2013-09-20 15:08:40 -070094 return kNetworkTechnology1Xrtt;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040095 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
Ben Chan7ea768e2013-09-20 15:08:40 -070096 return kNetworkTechnologyHspaPlus;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040097 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
Ben Chan7ea768e2013-09-20 15:08:40 -0700100 return kNetworkTechnologyHspa;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400101 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700102 return kNetworkTechnologyUmts;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400103 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
Ben Chan7ea768e2013-09-20 15:08:40 -0700104 return kNetworkTechnologyEdge;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400105 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
Ben Chan7ea768e2013-09-20 15:08:40 -0700106 return kNetworkTechnologyGprs;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400107 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
108 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700109 return kNetworkTechnologyGsm;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400110 return "";
111}
112
Ben Chan07193fd2013-07-12 22:10:55 -0700113string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400114 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
118 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
119 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
120 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
121 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
122 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
123 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
Ben Chan7ea768e2013-09-20 15:08:40 -0700124 return kTechnologyFamilyGsm;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400125 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800126 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
127 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400128 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
Ben Chan7ea768e2013-09-20 15:08:40 -0700129 return kTechnologyFamilyCdma;
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400130 return "";
131}
132
Ben Chan07193fd2013-07-12 22:10:55 -0700133} // namespace
134
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400135CellularCapabilityUniversal::CellularCapabilityUniversal(
136 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800137 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700138 ModemInfo *modem_info)
139 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400140 weak_ptr_factory_(this),
141 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200142 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400143 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
144 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200145 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800146 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800147 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400148 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800149 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700150 scan_interval_(0),
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700151 subscription_state_(kSubscriptionStateUnknown),
Arman Uguray1361c032013-02-11 17:53:39 -0800152 sim_present_(false),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800153 reset_done_(false),
Arman Uguray1361c032013-02-11 17:53:39 -0800154 scanning_or_searching_timeout_milliseconds_(
Arman Uguraya14941d2013-04-12 16:58:26 -0700155 kDefaultScanningOrSearchingTimeoutMilliseconds),
156 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700157 kActivationRegistrationTimeoutMilliseconds),
158 registration_dropped_update_timeout_milliseconds_(
159 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700160 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400161 PropertyStore *store = cellular->mutable_store();
162
Ben Chan7ea768e2013-09-20 15:08:40 -0700163 store->RegisterConstString(kCarrierProperty, &carrier_);
164 store->RegisterConstBool(kSupportNetworkScanProperty, &scanning_supported_);
165 store->RegisterConstString(kEsnProperty, &esn_);
166 store->RegisterConstString(kFirmwareRevisionProperty, &firmware_revision_);
167 store->RegisterConstString(kHardwareRevisionProperty, &hardware_revision_);
168 store->RegisterConstString(kImeiProperty, &imei_);
169 store->RegisterConstString(kImsiProperty, &imsi_);
170 store->RegisterConstString(kIccidProperty, &sim_identifier_);
171 store->RegisterConstString(kManufacturerProperty, &manufacturer_);
172 store->RegisterConstString(kMdnProperty, &mdn_);
173 store->RegisterConstString(kMeidProperty, &meid_);
174 store->RegisterConstString(kMinProperty, &min_);
175 store->RegisterConstString(kModelIDProperty, &model_id_);
176 store->RegisterConstString(kSelectedNetworkProperty, &selected_network_);
177 store->RegisterConstStringmaps(kFoundNetworksProperty, &found_networks_);
Ben Chan39a7beb2013-09-21 11:28:00 -0700178 store->RegisterConstBool(kProviderRequiresRoamingProperty,
Darin Petkovf508c822012-09-21 13:43:17 +0200179 &provider_requires_roaming_);
Ben Chan7ea768e2013-09-20 15:08:40 -0700180 store->RegisterConstBool(kScanningProperty, &scanning_or_searching_);
181 store->RegisterUint16(kScanIntervalProperty, &scan_interval_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700182 HelpRegisterConstDerivedKeyValueStore(
Ben Chan7ea768e2013-09-20 15:08:40 -0700183 kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700184 &CellularCapabilityUniversal::SimLockStatusToProperty);
Ben Chan39a7beb2013-09-21 11:28:00 -0700185 store->RegisterConstString(kSIMOperatorIdProperty, &operator_id_);
186 store->RegisterConstBool(kSIMPresentProperty, &sim_present_);
Ben Chan7ea768e2013-09-20 15:08:40 -0700187 store->RegisterConstStringmaps(kCellularApnListProperty, &apn_list_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400188}
189
190KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
191 Error */*error*/) {
192 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700193 string lock_type;
194 switch (sim_lock_status_.lock_type) {
195 case MM_MODEM_LOCK_SIM_PIN:
196 lock_type = "sim-pin";
197 break;
198 case MM_MODEM_LOCK_SIM_PUK:
199 lock_type = "sim-puk";
200 break;
201 default:
202 lock_type = "";
203 break;
204 }
Ben Chan7ea768e2013-09-20 15:08:40 -0700205 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
206 status.SetString(kSIMLockTypeProperty, lock_type);
207 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400208 return status;
209}
210
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700211void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400212 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700213 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400214 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
215 name,
216 KeyValueStoreAccessor(
217 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700218 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400219}
220
221void CellularCapabilityUniversal::InitProxies() {
222 modem_3gpp_proxy_.reset(
223 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
224 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400225 modem_proxy_.reset(
226 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
227 cellular()->dbus_owner()));
228 modem_simple_proxy_.reset(
229 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
230 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800231
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400232 modem_proxy_->set_state_changed_callback(
233 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
234 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400235 // Do not create a SIM proxy until the device is enabled because we
236 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400237 // TODO(jglasgow): register callbacks
238}
239
240void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400241 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700242 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400243 InitProxies();
Ben Chan151d4472013-09-06 13:29:46 -0700244 deferred_enable_modem_callback_.Reset();
245 EnableModem(true, error, callback);
Gary Moraine285a842012-08-15 08:23:57 -0700246}
247
Ben Chan151d4472013-09-06 13:29:46 -0700248void CellularCapabilityUniversal::EnableModem(bool deferrable,
249 Error *error,
Gary Moraine285a842012-08-15 08:23:57 -0700250 const ResultCallback &callback) {
Ben Chan151d4472013-09-06 13:29:46 -0700251 SLOG(Cellular, 2) << __func__ << "(deferrable=" << deferrable << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400252 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700253 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700254 modem_info()->metrics()->NotifyDeviceEnableStarted(
255 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400256 modem_proxy_->Enable(
257 true,
Gary Moraine285a842012-08-15 08:23:57 -0700258 &local_error,
Ben Chan151d4472013-09-06 13:29:46 -0700259 Bind(&CellularCapabilityUniversal::EnableModemCompleted,
260 weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
Jason Glasgowef965562012-04-10 16:12:35 -0400261 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700262 if (local_error.IsFailure()) {
263 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700264 }
265 if (error) {
266 error->CopyFrom(local_error);
267 }
Jason Glasgowef965562012-04-10 16:12:35 -0400268}
269
Ben Chan151d4472013-09-06 13:29:46 -0700270void CellularCapabilityUniversal::EnableModemCompleted(
271 bool deferrable, const ResultCallback &callback, const Error &error) {
272 SLOG(Cellular, 2) << __func__ << "(deferrable=" << deferrable
273 << ", error=" << error << ")";
Thieu Leb9c05e02013-03-04 14:09:32 -0800274
Ben Chan151d4472013-09-06 13:29:46 -0700275 // If the enable operation failed with Error::kWrongState, the modem is not
276 // in the expected state (i.e. disabled). If |deferrable| indicates that the
277 // enable operation can be deferred, we defer the operation until the modem
278 // goes into the expected state (see OnModemStateChangedSignal).
279 //
280 // Note that when the SIM is locked, the enable operation also fails with
281 // Error::kWrongState. The enable operation is deferred until the modem goes
282 // into the disabled state after the SIM is unlocked. We may choose not to
283 // defer the enable operation when the SIM is locked, but the UI needs to
284 // trigger the enable operation after the SIM is unlocked, which is currently
285 // not the case.
Jason Glasgowef965562012-04-10 16:12:35 -0400286 if (error.IsFailure()) {
Ben Chan151d4472013-09-06 13:29:46 -0700287 if (!deferrable || error.type() != Error::kWrongState) {
288 callback.Run(error);
289 return;
290 }
291
292 if (deferred_enable_modem_callback_.is_null()) {
293 SLOG(Cellular, 2) << "Defer enable operation.";
294 // The Enable operation to be deferred should not be further deferrable.
295 deferred_enable_modem_callback_ =
296 Bind(&CellularCapabilityUniversal::EnableModem,
297 weak_ptr_factory_.GetWeakPtr(),
298 false, // non-deferrable
299 static_cast<Error*>(NULL),
300 callback);
301 }
Jason Glasgowef965562012-04-10 16:12:35 -0400302 return;
303 }
304
305 // After modem is enabled, it should be possible to get properties
306 // TODO(jglasgow): handle errors from GetProperties
307 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800308 // We expect the modem to start scanning after it has been enabled.
309 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700310 modem_info()->metrics()->NotifyDeviceEnableFinished(
311 cellular()->interface_index());
312 modem_info()->metrics()->NotifyDeviceScanStarted(
313 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800314 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400315}
316
317void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400318 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400319 CHECK(!callback.is_null());
320 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700321 // If there is an outstanding registration change, simply ignore it since
322 // the service will be destroyed anyway.
323 if (!registration_dropped_update_callback_.IsCancelled()) {
324 registration_dropped_update_callback_.Cancel();
325 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
326 }
327
Ben Chan9de146f2013-09-11 13:11:31 -0700328 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
329 weak_ptr_factory_.GetWeakPtr(),
330 callback);
331 cellular()->dispatcher()->PostTask(task);
Gary Moraine285a842012-08-15 08:23:57 -0700332 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400333}
334
Jason Glasgowef965562012-04-10 16:12:35 -0400335void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
336 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700337 modem_info()->metrics()->NotifyDeviceDisableStarted(
338 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400339 modem_proxy_->Enable(
340 false, &error,
341 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
342 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400343 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400344 if (error.IsFailure())
345 callback.Run(error);
346}
347
348void CellularCapabilityUniversal::Stop_DisableCompleted(
349 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700350 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400351
Thieu Lea2519bf2013-01-23 16:51:54 -0800352 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800353 // The modem has been successfully disabled, but we still need to power it
354 // down.
355 Stop_PowerDown(callback);
356 } else {
357 // An error occurred; terminate the disable sequence.
358 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800359 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800360}
361
362void CellularCapabilityUniversal::Stop_PowerDown(
363 const ResultCallback &callback) {
364 SLOG(Cellular, 2) << __func__;
365 Error error;
366 modem_proxy_->SetPowerState(
367 MM_MODEM_POWER_STATE_LOW,
368 &error,
369 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
370 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800371 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800372
373 if (error.IsFailure())
374 // This really shouldn't happen, but if it does, report success,
375 // because a stop initiated power down is only called if the
376 // modem was successfully disabled, but the failure of this
377 // operation should still be propagated up as a successful disable.
378 Stop_PowerDownCompleted(callback, error);
379}
380
mukesh agrawal28185512013-10-18 16:57:09 -0700381// Note: if we were in the middle of powering down the modem when the
382// system suspended, we might not get this event from
383// ModemManager. And we might not even get a timeout from dbus-c++,
384// because StartModem re-initializes proxies.
Arman Ugurayee464d32013-02-13 17:14:36 -0800385void CellularCapabilityUniversal::Stop_PowerDownCompleted(
386 const ResultCallback &callback,
387 const Error &error) {
388 SLOG(Cellular, 2) << __func__;
389
390 if (error.IsFailure())
391 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
392
393 // Since the disable succeeded, if power down fails, we currently fail
394 // silently, i.e. we need to report the disable operation as having
395 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700396 modem_info()->metrics()->NotifyDeviceDisableFinished(
397 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800398 ReleaseProxies();
399 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400400}
401
402void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
403 Error *error,
404 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700405 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400406 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
407 weak_ptr_factory_.GetWeakPtr(),
408 callback);
409 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400410}
411
412void CellularCapabilityUniversal::Disconnect(Error *error,
413 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700414 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700415 // If a deferred registration loss request exists, process it.
416 if (!registration_dropped_update_callback_.IsCancelled()) {
417 registration_dropped_update_callback_.callback().Run();
418 DCHECK(cellular()->state() != Cellular::kStateConnected &&
419 cellular()->state() != Cellular::kStateLinked);
420 SLOG(Cellular, 1) << "Processed deferred registration loss before "
421 << "disconnect request.";
422 }
Thieu Le5d6864a2012-07-20 11:43:51 -0700423 if (bearer_path_.empty()) {
424 LOG(WARNING) << "In " << __func__ << "(): "
425 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700426 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700427 modem_simple_proxy_->Disconnect(bearer_path_,
428 error,
429 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800430 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700431 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400432}
433
Christopher Wiley8a468902012-11-30 11:52:38 -0800434void CellularCapabilityUniversal::DisconnectCleanup() {
435 SLOG(Cellular, 2) << __func__;
436}
437
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400438void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400439 Error *error,
440 const ResultCallback &callback) {
441 OnUnsupportedOperation(__func__, error);
442}
443
Arman Uguraya14941d2013-04-12 16:58:26 -0700444void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
445 SLOG(Cellular, 2) << __func__;
446 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700447 modem_info()->pending_activation_store()->GetActivationState(
448 PendingActivationStore::kIdentifierICCID,
449 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700450 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
451 return;
452 }
453 if (IsMdnValid()) {
454 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
455 return;
456 }
457 if (reset_done_) {
458 SLOG(Cellular, 2) << "Already done with reset.";
459 return;
460 }
461
462 // Still not activated after timeout. Reset the modem.
463 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
464 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700465 modem_info()->pending_activation_store()->SetActivationState(
466 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700467 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700468 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700469 ResetAfterActivation();
470}
471
Arman Ugurayc7b15602013-02-16 00:56:18 -0800472void CellularCapabilityUniversal::CompleteActivation(Error *error) {
473 SLOG(Cellular, 2) << __func__;
474
475 // Persist the ICCID as "Pending Activation".
476 // We're assuming that when this function gets called, |sim_identifier_| will
477 // be non-empty. We still check here that is non-empty, though something is
478 // wrong if it is empty.
Arman Ugurayc7b15602013-02-16 00:56:18 -0800479 if (sim_identifier_.empty()) {
480 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
481 return;
482 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800483
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700484 if (IsMdnValid()) {
485 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
486 return;
487 }
488
Arman Ugurayefea6e02013-02-21 13:28:04 -0800489 // There should be a cellular service at this point.
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700490 if (cellular()->service().get()) {
491 if (cellular()->service()->activation_state() == kActivationStateActivated)
492 return;
493
Ben Chan7ea768e2013-09-20 15:08:40 -0700494 cellular()->service()->SetActivationState(kActivationStateActivating);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700495 }
Arman Uguray41cc6342013-03-29 16:34:39 -0700496 modem_info()->pending_activation_store()->SetActivationState(
497 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800498 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700499 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700500
501 activation_wait_for_registration_callback_.Reset(
502 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
503 weak_ptr_factory_.GetWeakPtr()));
504 cellular()->dispatcher()->PostDelayedTask(
505 activation_wait_for_registration_callback_.callback(),
506 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800507}
508
509void CellularCapabilityUniversal::ResetAfterActivation() {
510 SLOG(Cellular, 2) << __func__;
511
512 // Here the initial call to Reset might fail in rare cases. Simply ignore.
513 Error error;
514 ResultCallback callback = Bind(
515 &CellularCapabilityUniversal::OnResetAfterActivationReply,
516 weak_ptr_factory_.GetWeakPtr());
517 Reset(&error, callback);
518 if (error.IsFailure())
519 SLOG(Cellular, 2) << "Failed to reset after activation.";
520}
521
522void CellularCapabilityUniversal::OnResetAfterActivationReply(
523 const Error &error) {
524 SLOG(Cellular, 2) << __func__;
525 if (error.IsFailure()) {
526 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
527 // TODO(armansito): Maybe post a delayed reset task?
528 return;
529 }
530 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700531 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800532 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800533}
534
Arman Uguray0a3e2792013-01-17 16:31:50 -0800535void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800536 SLOG(Cellular, 2) << __func__;
537
538 bool registered =
539 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
540
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700541 // We know a service is activated if |subscription_state_| is
542 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
543 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
544 // fallback on checking for a valid MDN.
545 bool activated =
546 ((subscription_state_ == kSubscriptionStateProvisioned) ||
547 (subscription_state_ == kSubscriptionStateOutOfData)) ||
548 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
549
550 if (activated && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700551 modem_info()->pending_activation_store()->RemoveEntry(
552 PendingActivationStore::kIdentifierICCID,
553 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800554
Arman Ugurayefea6e02013-02-21 13:28:04 -0800555 CellularServiceRefPtr service = cellular()->service();
556
557 if (!service.get())
558 return;
559
Ben Chan7ea768e2013-09-20 15:08:40 -0700560 if (service->activation_state() == kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800561 // Either no service or already activated. Nothing to do.
562 return;
563
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700564 // Besides the indicators above, a connected service also indicates an
565 // activated SIM.
566 if (activated || cellular()->state() == Cellular::kStateConnected ||
Arman Ugurayc7b15602013-02-16 00:56:18 -0800567 cellular()->state() == Cellular::kStateLinked) {
568 SLOG(Cellular, 2) << "Marking service as activated.";
Ben Chan7ea768e2013-09-20 15:08:40 -0700569 service->SetActivationState(kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800570 return;
571 }
572
573 // If the ICCID is not available, the following logic can be delayed until it
574 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800575 if (sim_identifier_.empty())
576 return;
577
Arman Uguray41cc6342013-03-29 16:34:39 -0700578 PendingActivationStore::State state =
579 modem_info()->pending_activation_store()->GetActivationState(
580 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700581 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800582 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700583 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800584 // Always mark the service as activating here, as the ICCID could have
585 // been unavailable earlier.
Ben Chan7ea768e2013-09-20 15:08:40 -0700586 service->SetActivationState(kActivationStateActivating);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800587 if (reset_done_) {
588 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700589 modem_info()->pending_activation_store()->SetActivationState(
590 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800591 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700592 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800593 } else if (registered) {
594 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700595 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800596 ResetAfterActivation();
597 }
598 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700599 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800600 if (registered) {
601 // Trigger auto connect here.
602 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
603 << "autoconnect to force MDN to update.";
604 service->AutoConnect();
605 }
606 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700607 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700608 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
609 << "been reset at least once.";
610 if (registered) {
611 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700612 modem_info()->pending_activation_store()->SetActivationState(
613 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700614 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700615 PendingActivationStore::kStateActivated);
Ben Chan7ea768e2013-09-20 15:08:40 -0700616 service->SetActivationState(kActivationStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700617 }
618 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700619 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800620 // No entry exists for this ICCID. Nothing to do.
621 break;
622 default:
623 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800624 }
625}
626
Ben Chan07193fd2013-07-12 22:10:55 -0700627string CellularCapabilityUniversal::GetMdnForOLP(
628 const CellularOperatorInfo::CellularOperator &cellular_operator) const {
629 // TODO(benchan): This is ugly. Remove carrier specific code once we move
630 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
Ben Chan200591a2013-08-07 14:39:04 -0700631 if (cellular_operator.identifier() == kVzwIdentifier) {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700632 // subscription_state_ is the definitive indicator of whether we need
633 // activation. The OLP expects an all zero MDN in that case.
634 if (subscription_state_ == kSubscriptionStateUnprovisioned ||
635 mdn_.empty()) {
Ben Chan200591a2013-08-07 14:39:04 -0700636 return string(kVzwMdnLength, '0');
637 }
638 if (mdn_.length() > kVzwMdnLength) {
639 return mdn_.substr(mdn_.length() - kVzwMdnLength);
640 }
Ben Chan07193fd2013-07-12 22:10:55 -0700641 }
642 return mdn_;
643}
644
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400645void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700646 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400647 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400648 modem_proxy_.reset();
649 modem_simple_proxy_.reset();
650 sim_proxy_.reset();
651}
652
Arman Ugurayc9533572013-01-22 17:34:20 -0800653void CellularCapabilityUniversal::UpdateStorageIdentifier() {
654 if (!cellular()->service().get())
655 return;
656
657 // Lookup the unique identifier assigned to the current network and base the
658 // service's storage identifier on it.
Arman Ugurayc5391232013-09-23 21:30:46 -0700659 const string kPrefix =
660 string(shill::kTypeCellular) + "_" + cellular()->address() + "_";
Arman Ugurayc9533572013-01-22 17:34:20 -0800661 string storage_id;
662 if (!operator_id_.empty()) {
663 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700664 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
665 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800666 if (provider && !provider->identifier().empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700667 storage_id = kPrefix + provider->identifier();
Arman Ugurayc9533572013-01-22 17:34:20 -0800668 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400669 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800670 // If the above didn't work, append IMSI, if available.
671 if (storage_id.empty() && !imsi_.empty()) {
Arman Ugurayc5391232013-09-23 21:30:46 -0700672 storage_id = kPrefix + imsi_;
Arman Ugurayc9533572013-01-22 17:34:20 -0800673 }
674 if (!storage_id.empty()) {
675 cellular()->service()->SetStorageIdentifier(storage_id);
676 }
677}
678
Arman Ugurayefea6e02013-02-21 13:28:04 -0800679void CellularCapabilityUniversal::UpdateServiceActivationState() {
680 if (!cellular()->service().get())
681 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800682 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700683 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700684 PendingActivationStore::State state =
685 modem_info()->pending_activation_store()->GetActivationState(
686 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700687 sim_identifier_);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -0700688 if ((subscription_state_ == kSubscriptionStateUnknown ||
689 subscription_state_ == kSubscriptionStateUnprovisioned) &&
690 !sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700691 (state == PendingActivationStore::kStatePending ||
692 state == PendingActivationStore::kStatePendingTimeout))
Ben Chan7ea768e2013-09-20 15:08:40 -0700693 activation_state = kActivationStateActivating;
Arman Ugurayefea6e02013-02-21 13:28:04 -0800694 else if (activation_required)
Ben Chan7ea768e2013-09-20 15:08:40 -0700695 activation_state = kActivationStateNotActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700696 else {
Ben Chan7ea768e2013-09-20 15:08:40 -0700697 activation_state = kActivationStateActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700698
699 // Mark an activated service for auto-connect by default. Since data from
700 // the user profile will be loaded after the call to OnServiceCreated, this
701 // property will be corrected based on the user data at that time.
702 cellular()->service()->SetAutoConnect(true);
703 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800704 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800705 // TODO(benchan): For now, assume the cellular service is activated over
706 // a non-cellular network if service activation is required (i.e. a
707 // corresponding entry is found in the cellular operator info file).
708 // We will need to generalize this logic when migrating CDMA support from
709 // cromo to ModemManager.
710 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800711}
712
713void CellularCapabilityUniversal::OnServiceCreated() {
714 UpdateStorageIdentifier();
715 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800716 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400717 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800718 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700719
720 // WORKAROUND:
721 // E362 modems on Verizon network does not properly redirect when a SIM
722 // runs out of credits, we need to enforce out-of-credits detection.
Ben Chan4ffc03b2013-08-07 17:44:53 -0700723 //
724 // The out-of-credits detection is also needed on ALT3100 modems until the PCO
725 // support is ready (crosbug.com/p/20461).
Thieu Le43ce4d42013-10-04 16:08:55 -0700726 cellular()->service()->InitOutOfCreditsDetection(
727 GetOutOfCreditsDetectionType());
Arman Uguray7af0fac2013-03-18 17:35:35 -0700728
729 // Make sure that the network technology is set when the service gets
730 // created, just in case.
731 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400732}
733
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400734// Create the list of APNs to try, in the following order:
735// - last APN that resulted in a successful connection attempt on the
736// current network (if any)
737// - the APN, if any, that was set by the user
738// - the list of APNs found in the mobile broadband provider DB for the
739// home provider associated with the current SIM
740// - as a last resort, attempt to connect with no APN
741void CellularCapabilityUniversal::SetupApnTryList() {
742 apn_try_list_.clear();
743
744 DCHECK(cellular()->service().get());
745 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
746 if (apn_info)
747 apn_try_list_.push_back(*apn_info);
748
749 apn_info = cellular()->service()->GetUserSpecifiedApn();
750 if (apn_info)
751 apn_try_list_.push_back(*apn_info);
752
753 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
754}
755
756void CellularCapabilityUniversal::SetupConnectProperties(
757 DBusPropertiesMap *properties) {
758 SetupApnTryList();
759 FillConnectPropertyMap(properties);
760}
761
762void CellularCapabilityUniversal::FillConnectPropertyMap(
763 DBusPropertiesMap *properties) {
764
765 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400766 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400767 kPhoneNumber);
768
Jason Glasgow14521872012-05-07 19:12:15 -0400769 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400770 AllowRoaming());
771
772 if (!apn_try_list_.empty()) {
773 // Leave the APN at the front of the list, so that it can be recorded
774 // if the connect attempt succeeds.
775 Stringmap apn_info = apn_try_list_.front();
Ben Chan7ea768e2013-09-20 15:08:40 -0700776 SLOG(Cellular, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400777 (*properties)[kConnectApn].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700778 apn_info[kApnProperty].c_str());
779 if (ContainsKey(apn_info, kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400780 (*properties)[kConnectUser].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700781 apn_info[kApnUsernameProperty].c_str());
782 if (ContainsKey(apn_info, kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400783 (*properties)[kConnectPassword].writer().append_string(
Ben Chan7ea768e2013-09-20 15:08:40 -0700784 apn_info[kApnPasswordProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400785 }
786}
787
788void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400789 const DBus::Path &path,
790 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700791 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400792
Jason Glasgow7234ec32012-05-23 16:01:21 -0400793 CellularServiceRefPtr service = cellular()->service();
794 if (!service) {
795 // The service could have been deleted before our Connect() request
796 // completes if the modem was enabled and then quickly disabled.
797 apn_try_list_.clear();
798 } else if (error.IsFailure()) {
799 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400800 // The APN that was just tried (and failed) is still at the
801 // front of the list, about to be removed. If the list is empty
802 // after that, try one last time without an APN. This may succeed
803 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400804 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400805 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700806 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
807 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400808 DBusPropertiesMap props;
809 FillConnectPropertyMap(&props);
810 Error error;
811 Connect(props, &error, callback);
812 return;
813 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400814 } else {
815 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400816 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400817 apn_try_list_.clear();
818 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400819 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400820 }
821
822 if (!callback.is_null())
823 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800824
Arman Uguray0a3e2792013-01-17 16:31:50 -0800825 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400826}
827
828bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200829 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400830}
831
Jason Glasgowef965562012-04-10 16:12:35 -0400832void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700833 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400834
Jason Glasgowaf583282012-04-18 15:18:22 -0400835 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
836 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
837 cellular()->dbus_owner()));
838 DBusPropertiesMap properties(
839 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
840 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400841
Jason Glasgowaf583282012-04-18 15:18:22 -0400842 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
843 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400844}
845
Arman Uguray2717a102013-01-29 23:36:06 -0800846// static
847string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
848 return base::StringPrintf("%s %u",
849 kGenericServiceNamePrefix,
850 friendly_service_name_id_++);
851}
852
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400853string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200854 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800855
856 // If |serving_operator_| does not have an operator ID, call
857 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
858 if (serving_operator_.GetCode().empty()) {
859 UpdateOperatorInfo();
860 }
861
Darin Petkova4ca3c32012-08-17 16:05:24 +0200862 string name = serving_operator_.GetName();
863 string home_provider_name = cellular()->home_provider().GetName();
864 if (!name.empty()) {
865 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
866 // rules (TS 31.102 and annex A of 122.101).
867 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
868 !home_provider_name.empty()) {
869 return home_provider_name + " | " + name;
870 }
871 return name;
872 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400873 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200874 !home_provider_name.empty()) {
875 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400876 }
Arman Uguray2717a102013-01-29 23:36:06 -0800877 if (!serving_operator_.GetCode().empty()) {
878 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400879 }
Arman Uguray2717a102013-01-29 23:36:06 -0800880 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400881}
882
883void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700884 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400885 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800886
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700887 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800889
890 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
891 // one is available. If both were reported by the SIM, use IMSI.
892 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
893 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700894 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800895 spn_.c_str(),
896 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400897 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800898 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400899 return;
900 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400901
902 // Even if provider is the same as home_provider_, it is possible
903 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400904 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200905 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400906 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800907 // If Operator ID is available, use that as network code, otherwise
908 // use what was returned from the database.
909 if (!operator_id_.empty()) {
910 oper.SetCode(operator_id_);
911 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400912 oper.SetCode(provider->networks[0]);
913 }
914 if (provider->country) {
915 oper.SetCountry(provider->country);
916 }
917 if (spn_.empty()) {
918 const char *name = mobile_provider_get_name(provider);
919 if (name) {
920 oper.SetName(name);
921 }
922 } else {
923 oper.SetName(spn_);
924 }
925 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200926 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200927 << oper.GetName() << ", " << oper.GetCountry()
928 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400929 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800930 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400931}
932
Ben Chan8a2c01e2013-01-23 10:09:14 -0800933void CellularCapabilityUniversal::UpdateScanningProperty() {
934 // Set the Scanning property to true if there is a ongoing network scan
935 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
936 // to a network.
937 //
938 // TODO(benchan): As the Device DBus interface currently does not have a
939 // State property to indicate whether the device is being enabled, set the
940 // Scanning property to true when the modem is being enabled such that
941 // the network UI can start showing the initializing/scanning animation as
942 // soon as the modem is being enabled.
943 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800944 bool is_activated_service_waiting_for_registration =
945 ((modem_state == Cellular::kModemStateEnabled ||
946 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800947 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800948 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800949 modem_state == Cellular::kModemStateEnabling ||
950 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800951 scanning_;
952 if (new_scanning_or_searching != scanning_or_searching_) {
953 scanning_or_searching_ = new_scanning_or_searching;
Ben Chan7ea768e2013-09-20 15:08:40 -0700954 cellular()->adaptor()->EmitBoolChanged(kScanningProperty,
Ben Chan8a2c01e2013-01-23 10:09:14 -0800955 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800956
957 if (!scanning_or_searching_) {
958 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
959 scanning_or_searching_timeout_callback_.Cancel();
960 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
961 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
962 scanning_or_searching_timeout_callback_.Reset(
963 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
964 weak_ptr_factory_.GetWeakPtr()));
965 cellular()->dispatcher()->PostDelayedTask(
966 scanning_or_searching_timeout_callback_.callback(),
967 scanning_or_searching_timeout_milliseconds_);
968 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800969 }
970}
971
Arman Uguray1361c032013-02-11 17:53:39 -0800972void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
973 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
Ben Chan7ea768e2013-09-20 15:08:40 -0700974 << "kScanningProperty to |false|.";
Arman Uguray1361c032013-02-11 17:53:39 -0800975 scanning_or_searching_ = false;
Ben Chan7ea768e2013-09-20 15:08:40 -0700976 cellular()->adaptor()->EmitBoolChanged(kScanningProperty, false);
Arman Uguray1361c032013-02-11 17:53:39 -0800977}
978
Ben Chan6d0d1e72012-11-06 21:19:28 -0800979void CellularCapabilityUniversal::UpdateOLP() {
Ben Chan07193fd2013-07-12 22:10:55 -0700980 SLOG(Cellular, 2) << __func__;
981
Arman Ugurayf87fa2f2013-10-16 14:24:56 -0700982 // TODO(armansito): Do this mapping in MobileOperator (See crbug.com/298408).
Ben Chan07193fd2013-07-12 22:10:55 -0700983 const CellularOperatorInfo *cellular_operator_info =
984 modem_info()->cellular_operator_info();
985 if (!cellular_operator_info)
986 return;
987
988 const CellularOperatorInfo::CellularOperator *cellular_operator =
989 cellular_operator_info->GetCellularOperatorByMCCMNC(operator_id_);
990 if (!cellular_operator)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800991 return;
992
Arman Ugurayf4c61812013-01-10 18:58:39 -0800993 const CellularService::OLP *result =
Ben Chan07193fd2013-07-12 22:10:55 -0700994 cellular_operator_info->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -0800995 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800996 return;
997
Arman Ugurayf4c61812013-01-10 18:58:39 -0800998 CellularService::OLP olp;
999 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -08001000 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -08001001 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
1002 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
1003 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
Ben Chan07193fd2013-07-12 22:10:55 -07001004 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
1005 GetMdnForOLP(*cellular_operator));
Ben Chan6d0d1e72012-11-06 21:19:28 -08001006 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
Arman Ugurayf87fa2f2013-10-16 14:24:56 -07001007
1008 // TODO(armansito): Define constants for the OEM IDs in MobileOperator
1009 // (See crbug.com/298408).
1010 string oem_id = (model_id_ == kE362ModelId) ? "GOG3" : "QUA";
1011 ReplaceSubstringsAfterOffset(&post_data, 0, "${oem}", oem_id);
Ben Chan6d0d1e72012-11-06 21:19:28 -08001012 olp.SetPostData(post_data);
1013 cellular()->service()->SetOLP(olp);
1014}
1015
Arman Uguray2717a102013-01-29 23:36:06 -08001016void CellularCapabilityUniversal::UpdateServiceName() {
1017 if (cellular()->service()) {
1018 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
1019 }
1020}
1021
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001022void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001023 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -08001024 // TODO(armansito): Use CellularOperatorInfo here instead of
1025 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -08001026
Arman Uguray3645c432013-01-31 15:57:26 -08001027 // Sometimes the modem fails to acquire the operator code OTA, in which case
1028 // |serving_operator_| may not have an operator ID (sometimes due to service
1029 // activation being required or broken modem firmware). Use |operator_id_| as
1030 // a fallback when available. |operator_id_| is retrieved from the SIM card.
1031 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -08001032 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
1033 << "' as serving operator.";
1034 serving_operator_.SetCode(operator_id_);
Arman Uguray41c64712013-10-11 18:12:31 -07001035 } else if (!serving_operator_.GetCode().empty() && operator_id_.empty()) {
1036 // Sometimes the SIM may fail to report an operator code. Since we build
1037 // the APN list based on home provider, report that the serving operator
1038 // is the home provider.
1039 // TODO(armansito): This is clearly not the best behavior for the roaming
1040 // case: we are now reporting that the roaming carrier is the same as the
1041 // home carrier. While this is not preferable, we don't have any home
1042 // provider to report either way, so this won't hurt the user experience.
1043 // This is a quick fix needed for the M31 release (crbug.com/306310).
1044 // Remove it with a better approach for M32 (crbug.com/298408).
1045 SLOG(Cellular, 2) << "Home provider is unknown but serving operator is. "
1046 << "Reporting serving operator as home provider.";
1047 operator_id_ = serving_operator_.GetCode();
1048 SetHomeProvider();
Ben Chan092b12b2012-11-07 22:04:05 -08001049 }
1050
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001051 const string &network_id = serving_operator_.GetCode();
1052 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001053 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001054 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001055 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001056 network_id.c_str());
1057 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +02001058 if (serving_operator_.GetName().empty()) {
1059 const char *provider_name = mobile_provider_get_name(provider);
1060 if (provider_name && *provider_name) {
1061 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001062 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001063 }
Darin Petkova4ca3c32012-08-17 16:05:24 +02001064 if (provider->country && *provider->country) {
1065 serving_operator_.SetCountry(provider->country);
1066 }
1067 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
1068 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001069 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001070 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001071 }
1072 }
1073 UpdateServingOperator();
1074}
1075
1076void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001077 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001078 if (cellular()->service().get()) {
1079 cellular()->service()->SetServingOperator(serving_operator_);
1080 }
1081}
1082
Arman Uguray6e5639f2012-11-15 20:30:19 -08001083void CellularCapabilityUniversal::UpdateBearerPath() {
1084 SLOG(Cellular, 2) << __func__;
1085 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1086 weak_ptr_factory_.GetWeakPtr());
1087 Error error;
mukesh agrawal510cc802013-08-15 18:31:42 -07001088 if (!modem_proxy_) {
1089 // This can be a perfectly legitimate state to be in, as this
1090 // function can be called before StartModem. In particular, this
1091 // happens when a Cellular object is contructed in
1092 // Modem::CreateDeviceFromModemProperties.
1093 LOG(INFO) << "Skipping ListBearers due to uninitialized modem_proxy_.";
1094 return;
1095 }
Arman Uguray6e5639f2012-11-15 20:30:19 -08001096 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1097}
1098
1099void CellularCapabilityUniversal::OnListBearersReply(
1100 const std::vector<DBus::Path> &paths,
1101 const Error &error) {
1102 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1103 if (error.IsFailure()) {
1104 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1105 return;
1106 }
1107 // Look for the first active bearer and use its path as the connected
1108 // one. Right now, we don't allow more than one active bearer.
mukesh agrawal9da07772013-05-15 14:15:17 -07001109 DBus::Path new_bearer_path;
1110 uint32 ipconfig_method(MM_BEARER_IP_METHOD_UNKNOWN);
1111 string network_device;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001112 for (size_t i = 0; i < paths.size(); ++i) {
1113 const DBus::Path &path = paths[i];
Ben Chan5db19692013-07-09 23:07:03 -07001114
1115 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1116 proxy_factory()->CreateDBusPropertiesProxy(path,
1117 cellular()->dbus_owner()));
1118 DBusPropertiesMap properties(
1119 properties_proxy->GetAll(MM_DBUS_INTERFACE_BEARER));
1120 if (properties.empty()) {
1121 LOG(WARNING) << "Could not get properties of bearer \"" << path
1122 << "\". Bearer is likely gone and thus ignored.";
mukesh agrawal9da07772013-05-15 14:15:17 -07001123 continue;
1124 }
Ben Chan5db19692013-07-09 23:07:03 -07001125
1126 bool connected = false;
1127 if (!DBusProperties::GetBool(
1128 properties, MM_BEARER_PROPERTY_CONNECTED, &connected)) {
1129 SLOG(Cellular, 2) << "Bearer does not indicate whether it is connected "
1130 "or not. Assume it is not connected.";
1131 continue;
1132 }
1133
1134 if (!connected) {
1135 continue;
1136 }
1137
mukesh agrawal9da07772013-05-15 14:15:17 -07001138 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan5db19692013-07-09 23:07:03 -07001139 CHECK(new_bearer_path.empty()) << "Found more than one active bearer.";
1140
1141 if (DBusProperties::GetString(
1142 properties, MM_BEARER_PROPERTY_INTERFACE, &network_device)) {
1143 SLOG(Cellular, 2) << "Bearer uses network interface \"" << network_device
1144 << "\".";
1145 } else {
1146 SLOG(Cellular, 2) << "Bearer does not specify network interface.";
1147 }
1148
mukesh agrawal9da07772013-05-15 14:15:17 -07001149 // TODO(quiche): Add support for scenarios where the bearer is
1150 // IPv6 only, or where there are conflicting configuration methods
1151 // for IPv4 and IPv6. crbug.com/248360.
Ben Chan5db19692013-07-09 23:07:03 -07001152 DBusPropertiesMap bearer_ip4config;
1153 DBusProperties::GetDBusPropertiesMap(
1154 properties, MM_BEARER_PROPERTY_IP4CONFIG, &bearer_ip4config);
1155
1156 if (DBusProperties::GetUint32(
1157 bearer_ip4config, kIpConfigPropertyMethod, &ipconfig_method)) {
mukesh agrawal9da07772013-05-15 14:15:17 -07001158 SLOG(Cellular, 2) << "Bearer has IPv4 config method " << ipconfig_method;
1159 } else {
1160 SLOG(Cellular, 2) << "Bearer does not specify IPv4 config method.";
1161 for (const auto &i : bearer_ip4config) {
1162 SLOG(Cellular, 5) << "Bearer IPv4 config has key \""
1163 << i.first
1164 << "\".";
Arman Uguray6e5639f2012-11-15 20:30:19 -08001165 }
1166 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001167 new_bearer_path = path;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001168 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001169 bearer_path_ = new_bearer_path;
1170 if (new_bearer_path.empty()) {
1171 SLOG(Cellular, 2) << "No active bearer found.";
1172 return;
1173 }
1174 if (ipconfig_method == MM_BEARER_IP_METHOD_PPP) {
1175 cellular()->StartPPP(network_device);
Arman Uguray6e5639f2012-11-15 20:30:19 -08001176 }
1177}
1178
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001179void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001180 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001181 if (!home_provider_) {
1182 return;
1183 }
1184 apn_list_.clear();
1185 for (int i = 0; i < home_provider_->num_apns; ++i) {
1186 Stringmap props;
1187 mobile_apn *apn = home_provider_->apns[i];
1188 if (apn->value) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001189 props[kApnProperty] = apn->value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001190 }
1191 if (apn->username) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001192 props[kApnUsernameProperty] = apn->username;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001193 }
1194 if (apn->password) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001195 props[kApnPasswordProperty] = apn->password;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001196 }
1197 // Find the first localized and non-localized name, if any.
1198 const localized_name *lname = NULL;
1199 const localized_name *name = NULL;
1200 for (int j = 0; j < apn->num_names; ++j) {
1201 if (apn->names[j]->lang) {
1202 if (!lname) {
1203 lname = apn->names[j];
1204 }
1205 } else if (!name) {
1206 name = apn->names[j];
1207 }
1208 }
1209 if (name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001210 props[kApnNameProperty] = name->name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001211 }
1212 if (lname) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001213 props[kApnLocalizedNameProperty] = lname->name;
1214 props[kApnLanguageProperty] = lname->lang;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001215 }
1216 apn_list_.push_back(props);
1217 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001218 if (cellular()->adaptor()) {
1219 cellular()->adaptor()->EmitStringmapsChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001220 kCellularApnListProperty, apn_list_);
Darin Petkovdb6083f2012-08-16 12:50:23 +02001221 } else {
1222 LOG(ERROR) << "Null RPC service adaptor.";
1223 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001224}
1225
Ben Chan15786032012-11-04 21:28:02 -08001226bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001227 // subscription_state_ is the definitive answer. If that does not work,
1228 // fallback on MDN based logic.
1229 if (subscription_state_ == kSubscriptionStateProvisioned ||
1230 subscription_state_ == kSubscriptionStateOutOfData)
1231 return false;
1232
1233 // We are in the process of activating, ignore all other clues from the
1234 // network and use our own knowledge about the activation state.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001235 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001236 modem_info()->pending_activation_store()->GetActivationState(
1237 PendingActivationStore::kIdentifierICCID,
1238 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001239 return false;
1240
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001241 // Network notification that the service needs to be activated.
1242 if (subscription_state_ == kSubscriptionStateUnprovisioned)
1243 return true;
1244
Ben Chan15786032012-11-04 21:28:02 -08001245 // If there is no online payment portal information, it's safer to assume
1246 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001247 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001248 return false;
1249
Arman Ugurayf4c61812013-01-10 18:58:39 -08001250 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001251 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001252 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001253 return false;
1254
Ben Chan200591a2013-08-07 14:39:04 -07001255 // If the MDN is invalid (i.e. empty or contains only zeros), the service
1256 // requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001257 return !IsMdnValid();
1258}
1259
1260bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001261 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001262 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001263 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001264 return true;
Ben Chan15786032012-11-04 21:28:02 -08001265 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001266 return false;
Ben Chan15786032012-11-04 21:28:02 -08001267}
1268
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001269// always called from an async context
1270void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001271 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001272 CHECK(!callback.is_null());
1273 Error error;
1274 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1275 weak_ptr_factory_.GetWeakPtr(), callback);
1276 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1277 if (error.IsFailure())
1278 callback.Run(error);
1279}
1280
1281void CellularCapabilityUniversal::RegisterOnNetwork(
1282 const string &network_id,
1283 Error *error,
1284 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001285 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001286 CHECK(error);
1287 desired_network_ = network_id;
1288 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1289 weak_ptr_factory_.GetWeakPtr(), callback);
1290 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1291}
1292
1293void CellularCapabilityUniversal::OnRegisterReply(
1294 const ResultCallback &callback,
1295 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001296 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001297
1298 if (error.IsSuccess()) {
1299 selected_network_ = desired_network_;
1300 desired_network_.clear();
1301 callback.Run(error);
1302 return;
1303 }
1304 // If registration on the desired network failed,
1305 // try to register on the home network.
1306 if (!desired_network_.empty()) {
1307 desired_network_.clear();
1308 selected_network_.clear();
1309 LOG(INFO) << "Couldn't register on selected network, trying home network";
1310 Register(callback);
1311 return;
1312 }
1313 callback.Run(error);
1314}
1315
1316bool CellularCapabilityUniversal::IsRegistered() {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001317 return IsRegisteredState(registration_state_);
1318}
1319
1320bool CellularCapabilityUniversal::IsRegisteredState(
1321 MMModem3gppRegistrationState state) {
1322 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1323 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001324}
1325
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001326void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1327 // If we're already in some non-registered state, don't override that
1328 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1329 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1330 registration_state_ =
1331 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1332 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1333 }
1334}
1335
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001336void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001337 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001338 Error *error, const ResultCallback &callback) {
1339 CHECK(error);
1340 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1341}
1342
1343void CellularCapabilityUniversal::EnterPIN(const string &pin,
1344 Error *error,
1345 const ResultCallback &callback) {
1346 CHECK(error);
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001347 SLOG(Cellular, 2) << __func__;
1348 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001349}
1350
1351void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1352 const string &pin,
1353 Error *error,
1354 const ResultCallback &callback) {
1355 CHECK(error);
1356 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1357}
1358
1359void CellularCapabilityUniversal::ChangePIN(
1360 const string &old_pin, const string &new_pin,
1361 Error *error, const ResultCallback &callback) {
1362 CHECK(error);
1363 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1364}
1365
Ben Chan5d0d32c2013-01-08 02:05:29 -08001366void CellularCapabilityUniversal::Reset(Error *error,
1367 const ResultCallback &callback) {
1368 SLOG(Cellular, 2) << __func__;
1369 CHECK(error);
1370 if (resetting_) {
1371 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1372 return;
1373 }
1374 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1375 weak_ptr_factory_.GetWeakPtr(), callback);
1376 modem_proxy_->Reset(error, cb, kTimeoutReset);
1377 if (!error->IsFailure()) {
1378 resetting_ = true;
1379 }
1380}
1381
1382void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1383 const Error &error) {
1384 SLOG(Cellular, 2) << __func__;
1385 resetting_ = false;
1386 if (!callback.is_null())
1387 callback.Run(error);
1388}
1389
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001390void CellularCapabilityUniversal::Scan(Error *error,
1391 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001392 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001393 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001394 if (scanning_) {
1395 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1396 return;
1397 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001398 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1399 weak_ptr_factory_.GetWeakPtr(), callback);
1400 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001401 if (!error->IsFailure()) {
1402 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001403 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001404 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001405}
1406
1407void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1408 const ScanResults &results,
1409 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001410 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001411
1412 // Error handling is weak. The current expectation is that on any
1413 // error, found_networks_ should be cleared and a property change
1414 // notification sent out.
1415 //
1416 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001417 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001418 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001419 found_networks_.clear();
1420 if (!error.IsFailure()) {
1421 for (ScanResults::const_iterator it = results.begin();
1422 it != results.end(); ++it) {
1423 found_networks_.push_back(ParseScanResult(*it));
1424 }
1425 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001426 cellular()->adaptor()->EmitStringmapsChanged(kFoundNetworksProperty,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001427 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001428
1429 // TODO(gmorain): This check for is_null() is a work-around because
1430 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1431 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1432 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1433 // Universal.
1434 if (!callback.is_null())
1435 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001436}
1437
1438Stringmap CellularCapabilityUniversal::ParseScanResult(
1439 const ScanResult &result) {
1440
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001441 /* ScanResults contain the following keys:
1442
1443 "status"
1444 A MMModem3gppNetworkAvailability value representing network
1445 availability status, given as an unsigned integer (signature "u").
1446 This key will always be present.
1447
1448 "operator-long"
1449 Long-format name of operator, given as a string value (signature
1450 "s"). If the name is unknown, this field should not be present.
1451
1452 "operator-short"
1453 Short-format name of operator, given as a string value
1454 (signature "s"). If the name is unknown, this field should not
1455 be present.
1456
1457 "operator-code"
1458 Mobile code of the operator, given as a string value (signature
1459 "s"). Returned in the format "MCCMNC", where MCC is the
1460 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1461 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1462
1463 "access-technology"
1464 A MMModemAccessTechnology value representing the generic access
1465 technology used by this mobile network, given as an unsigned
1466 integer (signature "u").
1467 */
1468 Stringmap parsed;
1469
1470 uint32 status;
1471 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1472 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1473 static const char * const kStatusString[] = {
1474 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1475 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1476 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1477 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1478 };
Ben Chan7ea768e2013-09-20 15:08:40 -07001479 parsed[kStatusProperty] = kStatusString[status];
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001480 }
1481
1482 uint32 tech; // MMModemAccessTechnology
1483 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1484 &tech)) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001485 parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001486 }
1487
1488 string operator_long, operator_short, operator_code;
1489 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
Ben Chan7ea768e2013-09-20 15:08:40 -07001490 parsed[kLongNameProperty] = operator_long;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001491 if (DBusProperties::GetString(result, kOperatorShortProperty,
1492 &operator_short))
Ben Chan7ea768e2013-09-20 15:08:40 -07001493 parsed[kShortNameProperty] = operator_short;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001494 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
Ben Chan7ea768e2013-09-20 15:08:40 -07001495 parsed[kNetworkIdProperty] = operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001496
1497 // If the long name is not available but the network ID is, look up the long
1498 // name in the mobile provider database.
Ben Chan7ea768e2013-09-20 15:08:40 -07001499 if ((!ContainsKey(parsed, kLongNameProperty) ||
1500 parsed[kLongNameProperty].empty()) &&
1501 ContainsKey(parsed, kNetworkIdProperty)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001502 mobile_provider *provider =
1503 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001504 modem_info()->provider_db(),
Ben Chan7ea768e2013-09-20 15:08:40 -07001505 parsed[kNetworkIdProperty].c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001506 if (provider) {
1507 const char *long_name = mobile_provider_get_name(provider);
1508 if (long_name && *long_name) {
Ben Chan7ea768e2013-09-20 15:08:40 -07001509 parsed[kLongNameProperty] = long_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001510 }
1511 }
1512 }
1513 return parsed;
1514}
1515
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001516string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001517 // If we know that the modem is an E362, return LTE here to make sure that
1518 // Chrome sees LTE as the network technology even if the actual technology is
1519 // unknown.
1520 // TODO(armansito): This hack will cause the UI to display LTE even if the
1521 // modem doesn't support it at a given time. This might be problematic if we
1522 // ever want to support switching between access technologies (e.g. falling
1523 // back to 3G when LTE is not available).
1524 if (model_id_ == kE362ModelId)
Ben Chan7ea768e2013-09-20 15:08:40 -07001525 return kNetworkTechnologyLte;
Arman Uguray7af0fac2013-03-18 17:35:35 -07001526
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001527 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001528 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001529 return AccessTechnologyToString(access_technologies_);
1530}
1531
1532string CellularCapabilityUniversal::GetRoamingStateString() const {
1533 switch (registration_state_) {
1534 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
Ben Chan7ea768e2013-09-20 15:08:40 -07001535 return kRoamingStateHome;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001536 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
Ben Chan7ea768e2013-09-20 15:08:40 -07001537 return kRoamingStateRoaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001538 default:
1539 break;
1540 }
Ben Chan7ea768e2013-09-20 15:08:40 -07001541 return kRoamingStateUnknown;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001542}
1543
Arman Uguray5d9a8522013-09-10 17:43:13 -07001544// TODO(armansito): Remove this method once cromo is deprecated.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001545void CellularCapabilityUniversal::GetSignalQuality() {
Arman Uguray5d9a8522013-09-10 17:43:13 -07001546 // ModemManager always returns the cached value, so there is no need to
1547 // trigger an update here. The true value is updated through a property
1548 // change signal.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001549}
1550
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001551string CellularCapabilityUniversal::GetTypeString() const {
1552 return AccessTechnologyToTechnologyFamily(access_technologies_);
1553}
1554
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001555void CellularCapabilityUniversal::OnModemPropertiesChanged(
1556 const DBusPropertiesMap &properties,
1557 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001558 // This solves a bootstrapping problem: If the modem is not yet
1559 // enabled, there are no proxy objects associated with the capability
1560 // object, so modem signals like StateChanged aren't seen. By monitoring
1561 // changes to the State property via the ModemManager, we're able to
1562 // get the initialization process started, which will result in the
1563 // creation of the proxy objects.
1564 //
1565 // The first time we see the change to State (when the modem state
1566 // is Unknown), we simply update the state, and rely on the Manager to
1567 // enable the device when it is registered with the Manager. On subsequent
1568 // changes to State, we need to explicitly enable the device ourselves.
1569 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001570 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001571 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001572 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001573 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001574 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001575 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001576 MM_MODEM_PROPERTY_SIM, &object_path_value))
1577 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001578
1579 DBusPropertiesMap::const_iterator it =
1580 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1581 if (it != properties.end()) {
1582 const vector<uint32> &supported_capabilities = it->second;
1583 OnSupportedCapabilitesChanged(supported_capabilities);
1584 }
1585
Jason Glasgowaf583282012-04-18 15:18:22 -04001586 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001587 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001588 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1589 &uint_value))
1590 OnModemCurrentCapabilitiesChanged(uint_value);
1591 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1592 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001593 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001594 if (DBusProperties::GetString(properties,
1595 MM_MODEM_PROPERTY_MANUFACTURER,
1596 &string_value))
1597 OnModemManufacturerChanged(string_value);
1598 if (DBusProperties::GetString(properties,
1599 MM_MODEM_PROPERTY_MODEL,
1600 &string_value))
1601 OnModemModelChanged(string_value);
1602 if (DBusProperties::GetString(properties,
1603 MM_MODEM_PROPERTY_REVISION,
1604 &string_value))
1605 OnModemRevisionChanged(string_value);
1606 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1607 // not needed: MM_MODEM_PROPERTY_DEVICE
1608 // not needed: MM_MODEM_PROPERTY_DRIVER
1609 // not needed: MM_MODEM_PROPERTY_PLUGIN
1610 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001611
Jason Glasgowaf583282012-04-18 15:18:22 -04001612 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001613 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001614 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001615 if (DBusProperties::GetUint32(properties,
1616 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001617 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001618 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001619 lock_status_changed = true;
1620 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001621
1622 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001623 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001624 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001625 LockRetryData lock_retries = it->second.operator LockRetryData();
1626 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001627 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001628 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001629
Arman Ugurayea5ff272013-06-25 10:28:02 -07001630 if (lock_status_changed)
1631 OnSimLockStatusChanged();
1632
Jason Glasgowaf583282012-04-18 15:18:22 -04001633 if (DBusProperties::GetUint32(properties,
1634 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1635 &uint_value))
1636 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001637
Jason Glasgowaf583282012-04-18 15:18:22 -04001638 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1639 if (it != properties.end()) {
1640 DBus::Struct<unsigned int, bool> quality = it->second;
1641 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001642 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001643 vector<string> numbers;
1644 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1645 &numbers)) {
1646 string mdn;
1647 if (numbers.size() > 0)
1648 mdn = numbers[0];
1649 OnMdnChanged(mdn);
1650 }
Ben Chan74924d82013-06-15 17:52:55 -07001651
1652 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1653 if (it != properties.end()) {
1654 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1655 vector<ModemModes> supported_modes;
1656 for (const auto &modes : mm_supported_modes) {
1657 supported_modes.push_back(
1658 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1659 }
1660 OnSupportedModesChanged(supported_modes);
1661 }
1662
1663 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1664 if (it != properties.end()) {
1665 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1666 OnCurrentModesChanged(ModemModes(
1667 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1668 }
1669
Jason Glasgowaf583282012-04-18 15:18:22 -04001670 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1671 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001672}
1673
1674void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1675 const string &interface,
1676 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001677 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001678 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001679 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001680 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001681 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001682 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1683 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001684 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001685 if (interface == MM_DBUS_INTERFACE_SIM) {
1686 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001687 }
1688}
1689
Jason Glasgow14521872012-05-07 19:12:15 -04001690bool CellularCapabilityUniversal::RetriableConnectError(
1691 const Error &error) const {
1692 if (error.type() == Error::kInvalidApn)
1693 return true;
1694
1695 // modemmanager does not ever return kInvalidApn for E362 modems
1696 // with 1.41 firmware. It remains to be seem if this will change
1697 // with 3.x firmware.
1698 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1699 return true;
1700
1701 return false;
1702}
1703
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001704void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1705 // TODO(petkov): Implement this.
1706 NOTIMPLEMENTED();
1707}
1708
Arman Uguray6552f8c2013-02-12 15:33:18 -08001709bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1710 return !sim_path.empty() && sim_path != kRootPath;
1711}
1712
Ben Chand7592522013-02-13 16:02:01 -08001713string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1714 string normalized_mdn;
1715 for (size_t i = 0; i < mdn.size(); ++i) {
1716 if (IsAsciiDigit(mdn[i]))
1717 normalized_mdn += mdn[i];
1718 }
1719 return normalized_mdn;
1720}
1721
Jason Glasgowaf583282012-04-18 15:18:22 -04001722void CellularCapabilityUniversal::OnSimPathChanged(
1723 const string &sim_path) {
1724 if (sim_path == sim_path_)
1725 return;
1726
1727 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001728 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001729 proxy = proxy_factory()->CreateSimProxy(sim_path,
1730 cellular()->dbus_owner());
1731 sim_path_ = sim_path;
1732 sim_proxy_.reset(proxy);
1733
Arman Uguray6552f8c2013-02-12 15:33:18 -08001734 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001735 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001736 imsi_ = "";
1737 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001738 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001739 OnSimIdentifierChanged("");
1740 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001741 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001742 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001743 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1744 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1745 cellular()->dbus_owner()));
1746 // TODO(jglasgow): convert to async interface
1747 DBusPropertiesMap properties(
1748 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1749 OnSimPropertiesChanged(properties, vector<string>());
1750 }
1751}
1752
Ben Chan74924d82013-06-15 17:52:55 -07001753void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1754 const vector<uint32> &supported_capabilities) {
1755 supported_capabilities_ = supported_capabilities;
1756}
1757
Jason Glasgowaf583282012-04-18 15:18:22 -04001758void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1759 uint32 current_capabilities) {
1760 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001761
1762 // Only allow network scan when the modem's current capabilities support
1763 // GSM/UMTS.
1764 //
1765 // TODO(benchan): We should consider having the modem plugins in ModemManager
1766 // reporting whether network scan is supported.
1767 scanning_supported_ =
1768 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1769 if (cellular()->adaptor()) {
1770 cellular()->adaptor()->EmitBoolChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001771 kSupportNetworkScanProperty, scanning_supported_);
Ben Chanfcca27b2013-01-22 15:03:44 -08001772 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001773}
1774
1775void CellularCapabilityUniversal::OnMdnChanged(
1776 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001777 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001778 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001779}
1780
1781void CellularCapabilityUniversal::OnModemManufacturerChanged(
1782 const string &manufacturer) {
1783 manufacturer_ = manufacturer;
1784}
1785
1786void CellularCapabilityUniversal::OnModemModelChanged(
1787 const string &model) {
1788 model_id_ = model;
1789}
1790
1791void CellularCapabilityUniversal::OnModemRevisionChanged(
1792 const string &revision) {
1793 firmware_revision_ = revision;
1794}
1795
1796void CellularCapabilityUniversal::OnModemStateChanged(
1797 Cellular::ModemState state) {
Ben Chanf45b3232013-10-08 20:54:01 -07001798 SLOG(Cellular, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
Arman Uguray1ee93912013-09-24 21:24:10 -07001799
1800 cellular()->OnModemStateChanged(state);
1801 UpdateScanningProperty();
1802 // TODO(armansito): Move the deferred enable logic to Cellular
1803 // (See crbug.com/279499).
1804 if (!deferred_enable_modem_callback_.is_null() &&
1805 state == Cellular::kModemStateDisabled) {
1806 SLOG(Cellular, 2) << "Enabling modem after deferring.";
1807 deferred_enable_modem_callback_.Run();
1808 deferred_enable_modem_callback_.Reset();
1809 } else if (state == Cellular::kModemStateConnected) {
mukesh agrawal510cc802013-08-15 18:31:42 -07001810 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1811 UpdateBearerPath();
1812 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001813}
1814
1815void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1816 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001817 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001818 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001819 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001820 const string new_type_string(GetTypeString());
1821 if (new_type_string != old_type_string) {
1822 // TODO(jglasgow): address layering violation of emitting change
1823 // signal here for a property owned by Cellular.
1824 cellular()->adaptor()->EmitStringChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001825 kTechnologyFamilyProperty, new_type_string);
Jason Glasgowbad114b2012-05-21 15:24:16 -04001826 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001827 if (cellular()->service().get()) {
1828 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1829 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001830 }
1831}
1832
Ben Chan74924d82013-06-15 17:52:55 -07001833void CellularCapabilityUniversal::OnSupportedModesChanged(
1834 const vector<ModemModes> &supported_modes) {
1835 supported_modes_ = supported_modes;
1836}
1837
1838void CellularCapabilityUniversal::OnCurrentModesChanged(
1839 const ModemModes &current_modes) {
1840 current_modes_ = current_modes;
1841}
1842
Jason Glasgowaf583282012-04-18 15:18:22 -04001843void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001844 const LockRetryData &lock_retries) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001845 SLOG(Cellular, 2) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001846
Arman Ugurayea5ff272013-06-25 10:28:02 -07001847 // Look for the retries left for the current lock. Try the obtain the count
1848 // that matches the current count. If no count for the current lock is
1849 // available, report the first one in the dictionary.
1850 LockRetryData::const_iterator it =
1851 lock_retries.find(sim_lock_status_.lock_type);
1852 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001853 it = lock_retries.begin();
1854 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001855 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001856 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001857 // Unknown, use 999
1858 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001859}
1860
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001861void CellularCapabilityUniversal::OnLockTypeChanged(
1862 MMModemLock lock_type) {
1863 SLOG(Cellular, 2) << __func__ << ": " << lock_type;
1864 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001865
1866 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1867 // This is because the corresponding property 'EnabledFacilityLocks' is on
1868 // the 3GPP interface and the 3GPP interface is not available while the Modem
1869 // is in the 'LOCKED' state.
1870 if (lock_type != MM_MODEM_LOCK_NONE &&
1871 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1872 !sim_lock_status_.enabled)
1873 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001874}
1875
Jason Glasgowaf583282012-04-18 15:18:22 -04001876void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001877 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001878 cellular()->adaptor()->EmitKeyValueStoreChanged(
Ben Chan7ea768e2013-09-20 15:08:40 -07001879 kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001880
1881 // If the SIM is currently unlocked, assume that we need to refresh
1882 // carrier information, since a locked SIM prevents shill from obtaining
1883 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001884 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001885 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1886 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001887 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1888 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1889 cellular()->dbus_owner()));
1890 DBusPropertiesMap properties(
1891 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1892 OnSimPropertiesChanged(properties, vector<string>());
1893 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001894}
1895
1896void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1897 const DBusPropertiesMap &properties,
1898 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001899 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001900 uint32 uint_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001901 string imei;
1902 if (DBusProperties::GetString(properties,
1903 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1904 &imei))
1905 OnImeiChanged(imei);
1906
1907 // Handle registration state changes as a single change
1908 string operator_code = serving_operator_.GetCode();
1909 string operator_name = serving_operator_.GetName();
1910 MMModem3gppRegistrationState state = registration_state_;
1911 bool registration_changed = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001912 if (DBusProperties::GetUint32(properties,
1913 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1914 &uint_value)) {
1915 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1916 registration_changed = true;
1917 }
1918 if (DBusProperties::GetString(properties,
1919 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1920 &operator_code))
1921 registration_changed = true;
1922 if (DBusProperties::GetString(properties,
1923 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1924 &operator_name))
1925 registration_changed = true;
1926 if (registration_changed)
1927 On3GPPRegistrationChanged(state, operator_code, operator_name);
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07001928 if (DBusProperties::GetUint32(properties,
1929 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1930 &uint_value))
1931 On3GPPSubscriptionStateChanged(
1932 static_cast<MMModem3gppSubscriptionState>(uint_value));
Jason Glasgowaf583282012-04-18 15:18:22 -04001933
Thieu Le43ce4d42013-10-04 16:08:55 -07001934 uint32 subscription_state;
1935 CellularServiceRefPtr service = cellular()->service();
1936 if (service.get() &&
1937 DBusProperties::GetUint32(properties,
1938 MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1939 &subscription_state)) {
1940 SLOG(Cellular, 2) << __func__ << ": Subscription state = "
1941 << subscription_state;
1942 service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1943 subscription_state);
1944 }
1945
Jason Glasgowaf583282012-04-18 15:18:22 -04001946 uint32 locks = 0;
1947 if (DBusProperties::GetUint32(
1948 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1949 &locks))
1950 OnFacilityLocksChanged(locks);
1951}
1952
1953void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1954 imei_ = imei;
1955}
1956
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001957void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1958 MMModem3gppRegistrationState state,
1959 const string &operator_code,
1960 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001961 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1962 << ", opercode=" << operator_code
1963 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001964
1965 // While the modem is connected, if the state changed from a registered state
1966 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001967 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1968 IsRegistered() && !IsRegisteredState(state)) {
1969 if (!registration_dropped_update_callback_.IsCancelled()) {
1970 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1971 << "Ignoring earlier notifications.";
1972 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001973 } else {
1974 // This is not a repeated post. So, count this instance of delayed drop
1975 // posted.
1976 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001977 }
1978 SLOG(Cellular, 2) << "Posted deferred registration state update";
1979 registration_dropped_update_callback_.Reset(
1980 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1981 weak_ptr_factory_.GetWeakPtr(),
1982 state,
1983 operator_code,
1984 operator_name));
1985 cellular()->dispatcher()->PostDelayedTask(
1986 registration_dropped_update_callback_.callback(),
1987 registration_dropped_update_timeout_milliseconds_);
1988 } else {
1989 if (!registration_dropped_update_callback_.IsCancelled()) {
1990 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1991 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001992 // If we cancelled the callback here, it means we had flaky network for a
1993 // small duration.
1994 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001995 }
1996 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1997 }
1998}
1999
2000void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
2001 MMModem3gppRegistrationState updated_state,
2002 string updated_operator_code,
2003 string updated_operator_name) {
2004 // A finished callback does not qualify as a canceled callback.
2005 // We test for a canceled callback to check for outstanding callbacks.
2006 // So, explicitly cancel the callback here.
2007 registration_dropped_update_callback_.Cancel();
2008
2009 SLOG(Cellular, 2) << __func__ << ": regstate=" << updated_state
2010 << ", opercode=" << updated_operator_code
2011 << ", opername=" << updated_operator_name;
2012
2013 registration_state_ = updated_state;
2014 serving_operator_.SetCode(updated_operator_code);
2015 serving_operator_.SetName(updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08002016
2017 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002018 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08002019
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002020 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08002021
2022 // Update the user facing name of the cellular service.
2023 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08002024
2025 // If the modem registered with the network and the current ICCID is pending
2026 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08002027 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002028}
2029
Prathmesh Prabhu9a0534e2013-10-10 16:20:34 -07002030void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
2031 MMModem3gppSubscriptionState updated_state) {
2032 SLOG(Cellular, 2) << __func__ << ": Updated subscription state = "
2033 << updated_state;
2034
2035 // A one-to-one enum mapping.
2036 switch (updated_state) {
2037 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
2038 subscription_state_ = kSubscriptionStateUnknown;
2039 break;
2040 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
2041 subscription_state_ = kSubscriptionStateProvisioned;
2042 break;
2043 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
2044 subscription_state_ = kSubscriptionStateUnprovisioned;
2045 break;
2046 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
2047 subscription_state_ = kSubscriptionStateOutOfData;
2048 break;
2049 default:
2050 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
2051 << updated_state;
2052 subscription_state_ = kSubscriptionStateUnknown;
2053 return;
2054 }
2055
2056 UpdateServiceActivationState();
2057 UpdatePendingActivationState();
2058}
2059
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04002060void CellularCapabilityUniversal::OnModemStateChangedSignal(
2061 int32 old_state, int32 new_state, uint32 reason) {
Ben Chanf45b3232013-10-08 20:54:01 -07002062 Cellular::ModemState old_modem_state =
2063 static_cast<Cellular::ModemState>(old_state);
2064 Cellular::ModemState new_modem_state =
2065 static_cast<Cellular::ModemState>(new_state);
2066 SLOG(Cellular, 2) << __func__ << "("
2067 << Cellular::GetModemStateString(old_modem_state) << ", "
2068 << Cellular::GetModemStateString(new_modem_state) << ", "
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04002069 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04002070}
2071
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002072void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
2073 cellular()->HandleNewSignalQuality(quality);
2074}
2075
Jason Glasgowaf583282012-04-18 15:18:22 -04002076void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07002077 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
2078 if (sim_lock_status_.enabled != sim_enabled) {
2079 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04002080 OnSimLockStatusChanged();
2081 }
2082}
Jason Glasgowef965562012-04-10 16:12:35 -04002083
Jason Glasgowaf583282012-04-18 15:18:22 -04002084void CellularCapabilityUniversal::OnSimPropertiesChanged(
2085 const DBusPropertiesMap &props,
2086 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002087 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04002088 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04002089 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
2090 OnSimIdentifierChanged(value);
2091 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
2092 &value))
2093 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08002094 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
2095 OnSpnChanged(value);
2096 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
2097 OnImsiChanged(value);
2098 SetHomeProvider();
2099}
Jason Glasgowaf583282012-04-18 15:18:22 -04002100
Arman Ugurayd73783f2013-01-31 16:11:21 -08002101// TODO(armansito): The following methods should probably log their argument
2102// values. Need to learn if any of them need to be scrubbed.
2103void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
2104 imsi_ = imsi;
2105}
2106
2107void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
2108 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04002109}
2110
2111void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
2112 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08002113 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04002114}
2115
2116void CellularCapabilityUniversal::OnOperatorIdChanged(
2117 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002118 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04002119 operator_id_ = operator_id;
2120}
2121
Thieu Le43ce4d42013-10-04 16:08:55 -07002122OutOfCreditsDetector::OOCType
2123CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
2124 if (model_id_ == kALT3100ModelId) {
2125 return OutOfCreditsDetector::OOCTypeSubscriptionState;
2126 } else if (model_id_ == kE362ModelId) {
2127 return OutOfCreditsDetector::OOCTypeActivePassive;
2128 } else {
2129 return OutOfCreditsDetector::OOCTypeNone;
2130 }
2131}
2132
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002133} // namespace shill