blob: 4bbbfcc2eb640112c2a3738f227605c617fe9a92 [file] [log] [blame]
Arman Uguray72fab6a2013-01-10 19:32:42 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/cellular_capability_universal.h"
6
7#include <base/bind.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04008#include <base/stl_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04009#include <base/stringprintf.h>
Ben Chan6d0d1e72012-11-06 21:19:28 -080010#include <base/string_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040011#include <chromeos/dbus/service_constants.h>
12#include <mobile_provider.h>
Ben Chan5c853ef2012-10-05 00:05:37 -070013#include <ModemManager/ModemManager.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040014
15#include <string>
16#include <vector>
17
18#include "shill/adaptor_interfaces.h"
19#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040020#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040021#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070022#include "shill/logging.h"
Arman Uguray41cc6342013-03-29 16:34:39 -070023#include "shill/pending_activation_store.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040024#include "shill/property_accessor.h"
25#include "shill/proxy_factory.h"
26
27#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
28#error "Do not include mm-modem.h"
29#endif
30
Jason Glasgow82f9ab32012-04-04 14:27:19 -040031using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040032using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040033using std::string;
34using std::vector;
35
36namespace shill {
37
38// static
Jason Glasgow14521872012-05-07 19:12:15 -040039const char CellularCapabilityUniversal::kConnectPin[] = "pin";
40const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
Jason Glasgow14521872012-05-07 19:12:15 -040041const char CellularCapabilityUniversal::kConnectApn[] = "apn";
42const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
43const char CellularCapabilityUniversal::kConnectUser[] = "user";
44const char CellularCapabilityUniversal::kConnectPassword[] = "password";
45const char CellularCapabilityUniversal::kConnectNumber[] = "number";
46const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
47 "allow-roaming";
48const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Arman Uguraya14941d2013-04-12 16:58:26 -070049const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070050CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
51 20000;
52const int64
Arman Uguray1361c032013-02-11 17:53:39 -080053CellularCapabilityUniversal::kDefaultScanningOrSearchingTimeoutMilliseconds =
54 60000;
Arman Ugurayf6366ac2013-06-12 16:02:28 -070055const int64 CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
Arman Uguraya14941d2013-04-12 16:58:26 -070056const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070057CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
58 15000;
Arman Uguray2717a102013-01-29 23:36:06 -080059const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
60 "Mobile Network";
Arman Uguray6552f8c2013-02-12 15:33:18 -080061const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040062const char CellularCapabilityUniversal::kStatusProperty[] = "status";
63const char CellularCapabilityUniversal::kOperatorLongProperty[] =
64 "operator-long";
65const char CellularCapabilityUniversal::kOperatorShortProperty[] =
66 "operator-short";
67const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
68 "operator-code";
69const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
70 "access-technology";
mukesh agrawal9da07772013-05-15 14:15:17 -070071const char CellularCapabilityUniversal::kIpConfigPropertyMethod[] = "method";
Jason Glasgow14521872012-05-07 19:12:15 -040072const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080073const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
74 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040075unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
76
Ben Chan07193fd2013-07-12 22:10:55 -070077namespace {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040078
Ben Chan07193fd2013-07-12 22:10:55 -070079const char kPhoneNumber[] = "*99#";
Jason Glasgow82f9ab32012-04-04 14:27:19 -040080
Ben Chan07193fd2013-07-12 22:10:55 -070081// This identifier is specified in the cellular_operator_info file.
82const char kVzwIdentifier[] = "vzw";
83const size_t kVzwMdnLength = 10;
84
85string AccessTechnologyToString(uint32 access_technologies) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040086 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
87 return flimflam::kNetworkTechnologyLte;
88 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
89 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
90 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
91 return flimflam::kNetworkTechnologyEvdo;
92 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
93 return flimflam::kNetworkTechnology1Xrtt;
94 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
95 return flimflam::kNetworkTechnologyHspaPlus;
96 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
99 return flimflam::kNetworkTechnologyHspa;
100 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
101 return flimflam::kNetworkTechnologyUmts;
102 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
103 return flimflam::kNetworkTechnologyEdge;
104 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
105 return flimflam::kNetworkTechnologyGprs;
106 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
107 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
108 return flimflam::kNetworkTechnologyGsm;
109 return "";
110}
111
Ben Chan07193fd2013-07-12 22:10:55 -0700112string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400113 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
114 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
118 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
119 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
120 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
121 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
122 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
123 return flimflam::kTechnologyFamilyGsm;
124 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800125 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
126 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400127 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
128 return flimflam::kTechnologyFamilyCdma;
129 return "";
130}
131
Ben Chan07193fd2013-07-12 22:10:55 -0700132} // namespace
133
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400134CellularCapabilityUniversal::CellularCapabilityUniversal(
135 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800136 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700137 ModemInfo *modem_info)
138 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400139 weak_ptr_factory_(this),
140 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200141 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400142 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
143 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200144 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800145 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800146 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400147 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800148 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700149 scan_interval_(0),
Arman Uguray1361c032013-02-11 17:53:39 -0800150 sim_present_(false),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800151 reset_done_(false),
Arman Uguray1361c032013-02-11 17:53:39 -0800152 scanning_or_searching_timeout_milliseconds_(
Arman Uguraya14941d2013-04-12 16:58:26 -0700153 kDefaultScanningOrSearchingTimeoutMilliseconds),
154 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700155 kActivationRegistrationTimeoutMilliseconds),
156 registration_dropped_update_timeout_milliseconds_(
157 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700158 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400159 PropertyStore *store = cellular->mutable_store();
160
161 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
162 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
163 &scanning_supported_);
164 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
165 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
166 &firmware_revision_);
167 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
168 &hardware_revision_);
169 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
170 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700171 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400172 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
173 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
174 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
175 store->RegisterConstString(flimflam::kMinProperty, &min_);
176 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
177 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
178 &selected_network_);
179 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
180 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +0200181 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
182 &provider_requires_roaming_);
Ben Chan8a2c01e2013-01-23 10:09:14 -0800183 store->RegisterConstBool(flimflam::kScanningProperty,
184 &scanning_or_searching_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400185 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700186 HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400187 flimflam::kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700188 &CellularCapabilityUniversal::SimLockStatusToProperty);
Thieu Le550247c2013-04-30 17:16:43 -0700189 store->RegisterConstString(shill::kSIMOperatorIdProperty, &operator_id_);
Ben Chanbd3aee82012-10-16 23:52:04 -0700190 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400191 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
192 &apn_list_);
193}
194
195KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
196 Error */*error*/) {
197 KeyValueStore status;
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700198 string lock_type;
199 switch (sim_lock_status_.lock_type) {
200 case MM_MODEM_LOCK_SIM_PIN:
201 lock_type = "sim-pin";
202 break;
203 case MM_MODEM_LOCK_SIM_PUK:
204 lock_type = "sim-puk";
205 break;
206 default:
207 lock_type = "";
208 break;
209 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400210 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
Arman Ugurayc7e63af2013-06-13 17:07:32 -0700211 status.SetString(flimflam::kSIMLockTypeProperty, lock_type);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400212 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
213 sim_lock_status_.retries_left);
214 return status;
215}
216
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700217void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400218 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700219 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400220 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
221 name,
222 KeyValueStoreAccessor(
223 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700224 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400225}
226
227void CellularCapabilityUniversal::InitProxies() {
228 modem_3gpp_proxy_.reset(
229 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
230 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400231 modem_proxy_.reset(
232 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
233 cellular()->dbus_owner()));
234 modem_simple_proxy_.reset(
235 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
236 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800237
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400238 modem_proxy_->set_state_changed_callback(
239 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
240 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400241 // Do not create a SIM proxy until the device is enabled because we
242 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400243 // TODO(jglasgow): register callbacks
244}
245
246void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400247 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700248 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400249 InitProxies();
250
Gary Moraine285a842012-08-15 08:23:57 -0700251 // ModemManager must be in the disabled state to accept the Enable command.
252 Cellular::ModemState state =
253 static_cast<Cellular::ModemState>(modem_proxy_->State());
254 if (state == Cellular::kModemStateDisabled) {
255 EnableModem(error, callback);
256 } else if (!cellular()->IsUnderlyingDeviceEnabled()) {
257 SLOG(Cellular, 2) << "Enabling of modem deferred because state is "
258 << state;
259 deferred_enable_modem_callback_ =
260 Bind(&CellularCapabilityUniversal::EnableModem,
261 weak_ptr_factory_.GetWeakPtr(), static_cast<Error *>(NULL),
262 callback);
263 } else {
Thieu Leb9c05e02013-03-04 14:09:32 -0800264 // This request cannot be completed synchronously here because a method
265 // reply requires a continuation tag that is not created until the message
266 // handler returns, see DBus-C++ ObjectAdapter::handle_message().
267 cellular()->dispatcher()->PostTask(
268 Bind(&CellularCapabilityUniversal::Start_ModemAlreadyEnabled,
269 weak_ptr_factory_.GetWeakPtr(), callback));
Gary Moraine285a842012-08-15 08:23:57 -0700270 }
271}
272
273void CellularCapabilityUniversal::EnableModem(Error *error,
274 const ResultCallback &callback) {
275 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400276 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700277 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700278 modem_info()->metrics()->NotifyDeviceEnableStarted(
279 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400280 modem_proxy_->Enable(
281 true,
Gary Moraine285a842012-08-15 08:23:57 -0700282 &local_error,
Jason Glasgowef965562012-04-10 16:12:35 -0400283 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
284 weak_ptr_factory_.GetWeakPtr(), callback),
285 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700286 if (local_error.IsFailure()) {
287 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700288 }
289 if (error) {
290 error->CopyFrom(local_error);
291 }
Jason Glasgowef965562012-04-10 16:12:35 -0400292}
293
Thieu Leb9c05e02013-03-04 14:09:32 -0800294void CellularCapabilityUniversal::Start_ModemAlreadyEnabled(
295 const ResultCallback &callback) {
296 // Call GetProperties() here to sync up with the modem state
297 GetProperties();
298 callback.Run(Error());
299}
300
Jason Glasgowef965562012-04-10 16:12:35 -0400301void CellularCapabilityUniversal::Start_EnableModemCompleted(
302 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400303 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400304 if (error.IsFailure()) {
305 callback.Run(error);
306 return;
307 }
308
309 // After modem is enabled, it should be possible to get properties
310 // TODO(jglasgow): handle errors from GetProperties
311 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800312 // We expect the modem to start scanning after it has been enabled.
313 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700314 modem_info()->metrics()->NotifyDeviceEnableFinished(
315 cellular()->interface_index());
316 modem_info()->metrics()->NotifyDeviceScanStarted(
317 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800318 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400319}
320
321void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400322 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400323 CHECK(!callback.is_null());
324 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700325 // If there is an outstanding registration change, simply ignore it since
326 // the service will be destroyed anyway.
327 if (!registration_dropped_update_callback_.IsCancelled()) {
328 registration_dropped_update_callback_.Cancel();
329 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
330 }
331
Thieu Led0012052012-07-25 16:09:09 -0700332 Cellular::ModemState state = cellular()->modem_state();
333 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400334
Thieu Led0012052012-07-25 16:09:09 -0700335 if (cellular()->IsModemRegistered()) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400336 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400337 modem_simple_proxy_->Disconnect(
338 all_bearers,
339 error,
340 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
341 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le049adb52012-11-12 17:14:51 -0800342 kTimeoutDisconnect);
Jason Glasgowef965562012-04-10 16:12:35 -0400343 if (error->IsFailure())
344 callback.Run(*error);
345 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400346 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
347 weak_ptr_factory_.GetWeakPtr(),
348 callback);
349 cellular()->dispatcher()->PostTask(task);
350 }
Gary Moraine285a842012-08-15 08:23:57 -0700351 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400352}
353
354void CellularCapabilityUniversal::Stop_DisconnectCompleted(
355 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700356 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400357
358 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
359 Stop_Disable(callback);
360}
361
362void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
363 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700364 modem_info()->metrics()->NotifyDeviceDisableStarted(
365 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400366 modem_proxy_->Enable(
367 false, &error,
368 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
369 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400370 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400371 if (error.IsFailure())
372 callback.Run(error);
373}
374
375void CellularCapabilityUniversal::Stop_DisableCompleted(
376 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700377 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400378
Thieu Lea2519bf2013-01-23 16:51:54 -0800379 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800380 // The modem has been successfully disabled, but we still need to power it
381 // down.
382 Stop_PowerDown(callback);
383 } else {
384 // An error occurred; terminate the disable sequence.
385 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800386 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800387}
388
389void CellularCapabilityUniversal::Stop_PowerDown(
390 const ResultCallback &callback) {
391 SLOG(Cellular, 2) << __func__;
392 Error error;
393 modem_proxy_->SetPowerState(
394 MM_MODEM_POWER_STATE_LOW,
395 &error,
396 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
397 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800398 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800399
400 if (error.IsFailure())
401 // This really shouldn't happen, but if it does, report success,
402 // because a stop initiated power down is only called if the
403 // modem was successfully disabled, but the failure of this
404 // operation should still be propagated up as a successful disable.
405 Stop_PowerDownCompleted(callback, error);
406}
407
408void CellularCapabilityUniversal::Stop_PowerDownCompleted(
409 const ResultCallback &callback,
410 const Error &error) {
411 SLOG(Cellular, 2) << __func__;
412
413 if (error.IsFailure())
414 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
415
416 // Since the disable succeeded, if power down fails, we currently fail
417 // silently, i.e. we need to report the disable operation as having
418 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700419 modem_info()->metrics()->NotifyDeviceDisableFinished(
420 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800421 ReleaseProxies();
422 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400423}
424
425void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
426 Error *error,
427 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700428 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400429 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
430 weak_ptr_factory_.GetWeakPtr(),
431 callback);
432 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400433}
434
435void CellularCapabilityUniversal::Disconnect(Error *error,
436 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700437 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700438 // If a deferred registration loss request exists, process it.
439 if (!registration_dropped_update_callback_.IsCancelled()) {
440 registration_dropped_update_callback_.callback().Run();
441 DCHECK(cellular()->state() != Cellular::kStateConnected &&
442 cellular()->state() != Cellular::kStateLinked);
443 SLOG(Cellular, 1) << "Processed deferred registration loss before "
444 << "disconnect request.";
445 }
Thieu Le5d6864a2012-07-20 11:43:51 -0700446 if (bearer_path_.empty()) {
447 LOG(WARNING) << "In " << __func__ << "(): "
448 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700449 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700450 modem_simple_proxy_->Disconnect(bearer_path_,
451 error,
452 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800453 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700454 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400455}
456
Christopher Wiley8a468902012-11-30 11:52:38 -0800457void CellularCapabilityUniversal::DisconnectCleanup() {
458 SLOG(Cellular, 2) << __func__;
459}
460
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400461void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400462 Error *error,
463 const ResultCallback &callback) {
464 OnUnsupportedOperation(__func__, error);
465}
466
Arman Uguraya14941d2013-04-12 16:58:26 -0700467void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
468 SLOG(Cellular, 2) << __func__;
469 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700470 modem_info()->pending_activation_store()->GetActivationState(
471 PendingActivationStore::kIdentifierICCID,
472 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700473 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
474 return;
475 }
476 if (IsMdnValid()) {
477 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
478 return;
479 }
480 if (reset_done_) {
481 SLOG(Cellular, 2) << "Already done with reset.";
482 return;
483 }
484
485 // Still not activated after timeout. Reset the modem.
486 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
487 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700488 modem_info()->pending_activation_store()->SetActivationState(
489 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700490 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700491 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700492 ResetAfterActivation();
493}
494
Arman Ugurayc7b15602013-02-16 00:56:18 -0800495void CellularCapabilityUniversal::CompleteActivation(Error *error) {
496 SLOG(Cellular, 2) << __func__;
497
498 // Persist the ICCID as "Pending Activation".
499 // We're assuming that when this function gets called, |sim_identifier_| will
500 // be non-empty. We still check here that is non-empty, though something is
501 // wrong if it is empty.
502 if (IsMdnValid()) {
503 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
504 return;
505 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800506
Arman Ugurayc7b15602013-02-16 00:56:18 -0800507 if (sim_identifier_.empty()) {
508 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
509 return;
510 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800511
512 // There should be a cellular service at this point.
513 if (cellular()->service().get())
514 cellular()->service()->SetActivationState(
515 flimflam::kActivationStateActivating);
Arman Uguray41cc6342013-03-29 16:34:39 -0700516 modem_info()->pending_activation_store()->SetActivationState(
517 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800518 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700519 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700520
521 activation_wait_for_registration_callback_.Reset(
522 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
523 weak_ptr_factory_.GetWeakPtr()));
524 cellular()->dispatcher()->PostDelayedTask(
525 activation_wait_for_registration_callback_.callback(),
526 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800527}
528
529void CellularCapabilityUniversal::ResetAfterActivation() {
530 SLOG(Cellular, 2) << __func__;
531
532 // Here the initial call to Reset might fail in rare cases. Simply ignore.
533 Error error;
534 ResultCallback callback = Bind(
535 &CellularCapabilityUniversal::OnResetAfterActivationReply,
536 weak_ptr_factory_.GetWeakPtr());
537 Reset(&error, callback);
538 if (error.IsFailure())
539 SLOG(Cellular, 2) << "Failed to reset after activation.";
540}
541
542void CellularCapabilityUniversal::OnResetAfterActivationReply(
543 const Error &error) {
544 SLOG(Cellular, 2) << __func__;
545 if (error.IsFailure()) {
546 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
547 // TODO(armansito): Maybe post a delayed reset task?
548 return;
549 }
550 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700551 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800552 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800553}
554
Arman Uguray0a3e2792013-01-17 16:31:50 -0800555void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800556 SLOG(Cellular, 2) << __func__;
557
558 bool registered =
559 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
560
561 // If we have a valid MDN, the service is activated. Always try to remove
562 // the ICCID from persistence.
563 bool got_mdn = IsMdnValid();
564 if (got_mdn && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700565 modem_info()->pending_activation_store()->RemoveEntry(
566 PendingActivationStore::kIdentifierICCID,
567 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800568
Arman Ugurayefea6e02013-02-21 13:28:04 -0800569 CellularServiceRefPtr service = cellular()->service();
570
571 if (!service.get())
572 return;
573
574 if (service->activation_state() == flimflam::kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800575 // Either no service or already activated. Nothing to do.
576 return;
577
578 // If we have a valid MDN or we can connect to the network, then the service
579 // is activated.
580 if (got_mdn || cellular()->state() == Cellular::kStateConnected ||
581 cellular()->state() == Cellular::kStateLinked) {
582 SLOG(Cellular, 2) << "Marking service as activated.";
Arman Ugurayefea6e02013-02-21 13:28:04 -0800583 service->SetActivationState(flimflam::kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800584 return;
585 }
586
587 // If the ICCID is not available, the following logic can be delayed until it
588 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800589 if (sim_identifier_.empty())
590 return;
591
Arman Uguray41cc6342013-03-29 16:34:39 -0700592 PendingActivationStore::State state =
593 modem_info()->pending_activation_store()->GetActivationState(
594 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700595 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800596 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700597 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800598 // Always mark the service as activating here, as the ICCID could have
599 // been unavailable earlier.
600 service->SetActivationState(flimflam::kActivationStateActivating);
601 if (reset_done_) {
602 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700603 modem_info()->pending_activation_store()->SetActivationState(
604 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800605 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700606 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800607 } else if (registered) {
608 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700609 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800610 ResetAfterActivation();
611 }
612 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700613 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800614 if (registered) {
615 // Trigger auto connect here.
616 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
617 << "autoconnect to force MDN to update.";
618 service->AutoConnect();
619 }
620 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700621 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700622 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
623 << "been reset at least once.";
624 if (registered) {
625 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700626 modem_info()->pending_activation_store()->SetActivationState(
627 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700628 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700629 PendingActivationStore::kStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700630 service->SetActivationState(flimflam::kActivationStateActivated);
631 }
632 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700633 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800634 // No entry exists for this ICCID. Nothing to do.
635 break;
636 default:
637 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800638 }
639}
640
Ben Chan07193fd2013-07-12 22:10:55 -0700641string CellularCapabilityUniversal::GetMdnForOLP(
642 const CellularOperatorInfo::CellularOperator &cellular_operator) const {
643 // TODO(benchan): This is ugly. Remove carrier specific code once we move
644 // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
645 if (cellular_operator.identifier() == kVzwIdentifier &&
646 mdn_.length() > kVzwMdnLength) {
647 return mdn_.substr(mdn_.length() - kVzwMdnLength);
648 }
649 return mdn_;
650}
651
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400652void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700653 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400654 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400655 modem_proxy_.reset();
656 modem_simple_proxy_.reset();
657 sim_proxy_.reset();
658}
659
Arman Ugurayc9533572013-01-22 17:34:20 -0800660void CellularCapabilityUniversal::UpdateStorageIdentifier() {
661 if (!cellular()->service().get())
662 return;
663
664 // Lookup the unique identifier assigned to the current network and base the
665 // service's storage identifier on it.
666 const string prefix = "cellular_" + cellular()->address() + "_";
667 string storage_id;
668 if (!operator_id_.empty()) {
669 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700670 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
671 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800672 if (provider && !provider->identifier().empty()) {
673 storage_id = prefix + provider->identifier();
674 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400675 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800676 // If the above didn't work, append IMSI, if available.
677 if (storage_id.empty() && !imsi_.empty()) {
678 storage_id = prefix + imsi_;
679 }
680 if (!storage_id.empty()) {
681 cellular()->service()->SetStorageIdentifier(storage_id);
682 }
683}
684
Arman Ugurayefea6e02013-02-21 13:28:04 -0800685void CellularCapabilityUniversal::UpdateServiceActivationState() {
686 if (!cellular()->service().get())
687 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800688 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700689 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700690 PendingActivationStore::State state =
691 modem_info()->pending_activation_store()->GetActivationState(
692 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700693 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800694 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700695 (state == PendingActivationStore::kStatePending ||
696 state == PendingActivationStore::kStatePendingTimeout))
Arman Ugurayefea6e02013-02-21 13:28:04 -0800697 activation_state = flimflam::kActivationStateActivating;
698 else if (activation_required)
699 activation_state = flimflam::kActivationStateNotActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700700 else {
701 activation_state = flimflam::kActivationStateActivated;
702
703 // Mark an activated service for auto-connect by default. Since data from
704 // the user profile will be loaded after the call to OnServiceCreated, this
705 // property will be corrected based on the user data at that time.
706 cellular()->service()->SetAutoConnect(true);
707 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800708 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800709 // TODO(benchan): For now, assume the cellular service is activated over
710 // a non-cellular network if service activation is required (i.e. a
711 // corresponding entry is found in the cellular operator info file).
712 // We will need to generalize this logic when migrating CDMA support from
713 // cromo to ModemManager.
714 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800715}
716
717void CellularCapabilityUniversal::OnServiceCreated() {
718 UpdateStorageIdentifier();
719 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800720 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400721 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800722 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700723
724 // WORKAROUND:
725 // E362 modems on Verizon network does not properly redirect when a SIM
726 // runs out of credits, we need to enforce out-of-credits detection.
727 // TODO(thieule): Remove this workaround (crosbug.com/p/18619).
728 if (model_id_ == kE362ModelId)
729 cellular()->service()->set_enforce_out_of_credits_detection(true);
Arman Uguray7af0fac2013-03-18 17:35:35 -0700730
731 // Make sure that the network technology is set when the service gets
732 // created, just in case.
733 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400734}
735
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400736// Create the list of APNs to try, in the following order:
737// - last APN that resulted in a successful connection attempt on the
738// current network (if any)
739// - the APN, if any, that was set by the user
740// - the list of APNs found in the mobile broadband provider DB for the
741// home provider associated with the current SIM
742// - as a last resort, attempt to connect with no APN
743void CellularCapabilityUniversal::SetupApnTryList() {
744 apn_try_list_.clear();
745
746 DCHECK(cellular()->service().get());
747 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
748 if (apn_info)
749 apn_try_list_.push_back(*apn_info);
750
751 apn_info = cellular()->service()->GetUserSpecifiedApn();
752 if (apn_info)
753 apn_try_list_.push_back(*apn_info);
754
755 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
756}
757
758void CellularCapabilityUniversal::SetupConnectProperties(
759 DBusPropertiesMap *properties) {
760 SetupApnTryList();
761 FillConnectPropertyMap(properties);
762}
763
764void CellularCapabilityUniversal::FillConnectPropertyMap(
765 DBusPropertiesMap *properties) {
766
767 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400768 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400769 kPhoneNumber);
770
Jason Glasgow14521872012-05-07 19:12:15 -0400771 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400772 AllowRoaming());
773
774 if (!apn_try_list_.empty()) {
775 // Leave the APN at the front of the list, so that it can be recorded
776 // if the connect attempt succeeds.
777 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700778 SLOG(Cellular, 2) << __func__ << ": Using APN "
779 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400780 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400781 apn_info[flimflam::kApnProperty].c_str());
782 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400783 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400784 apn_info[flimflam::kApnUsernameProperty].c_str());
785 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400786 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400787 apn_info[flimflam::kApnPasswordProperty].c_str());
788 }
789}
790
791void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400792 const DBus::Path &path,
793 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700794 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400795
Jason Glasgow7234ec32012-05-23 16:01:21 -0400796 CellularServiceRefPtr service = cellular()->service();
797 if (!service) {
798 // The service could have been deleted before our Connect() request
799 // completes if the modem was enabled and then quickly disabled.
800 apn_try_list_.clear();
801 } else if (error.IsFailure()) {
802 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400803 // The APN that was just tried (and failed) is still at the
804 // front of the list, about to be removed. If the list is empty
805 // after that, try one last time without an APN. This may succeed
806 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400807 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400808 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700809 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
810 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400811 DBusPropertiesMap props;
812 FillConnectPropertyMap(&props);
813 Error error;
814 Connect(props, &error, callback);
815 return;
816 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400817 } else {
818 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400819 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400820 apn_try_list_.clear();
821 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400822 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400823 }
824
825 if (!callback.is_null())
826 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800827
Arman Uguray0a3e2792013-01-17 16:31:50 -0800828 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400829}
830
831bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200832 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400833}
834
Arman Ugurayf84a4242013-04-09 20:01:07 -0700835bool CellularCapabilityUniversal::ShouldDetectOutOfCredit() const {
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700836 return model_id_ == kE362ModelId;
837}
838
Jason Glasgowef965562012-04-10 16:12:35 -0400839void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700840 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400841
Jason Glasgowaf583282012-04-18 15:18:22 -0400842 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
843 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
844 cellular()->dbus_owner()));
845 DBusPropertiesMap properties(
846 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
847 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400848
Jason Glasgowaf583282012-04-18 15:18:22 -0400849 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
850 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400851}
852
Arman Uguray2717a102013-01-29 23:36:06 -0800853// static
854string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
855 return base::StringPrintf("%s %u",
856 kGenericServiceNamePrefix,
857 friendly_service_name_id_++);
858}
859
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400860string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200861 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800862
863 // If |serving_operator_| does not have an operator ID, call
864 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
865 if (serving_operator_.GetCode().empty()) {
866 UpdateOperatorInfo();
867 }
868
Darin Petkova4ca3c32012-08-17 16:05:24 +0200869 string name = serving_operator_.GetName();
870 string home_provider_name = cellular()->home_provider().GetName();
871 if (!name.empty()) {
872 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
873 // rules (TS 31.102 and annex A of 122.101).
874 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
875 !home_provider_name.empty()) {
876 return home_provider_name + " | " + name;
877 }
878 return name;
879 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400880 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200881 !home_provider_name.empty()) {
882 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400883 }
Arman Uguray2717a102013-01-29 23:36:06 -0800884 if (!serving_operator_.GetCode().empty()) {
885 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400886 }
Arman Uguray2717a102013-01-29 23:36:06 -0800887 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888}
889
890void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700891 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400892 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800893
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700894 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400895 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800896
897 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
898 // one is available. If both were reported by the SIM, use IMSI.
899 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
900 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700901 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800902 spn_.c_str(),
903 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400904 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800905 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400906 return;
907 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400908
909 // Even if provider is the same as home_provider_, it is possible
910 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400911 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200912 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400913 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800914 // If Operator ID is available, use that as network code, otherwise
915 // use what was returned from the database.
916 if (!operator_id_.empty()) {
917 oper.SetCode(operator_id_);
918 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400919 oper.SetCode(provider->networks[0]);
920 }
921 if (provider->country) {
922 oper.SetCountry(provider->country);
923 }
924 if (spn_.empty()) {
925 const char *name = mobile_provider_get_name(provider);
926 if (name) {
927 oper.SetName(name);
928 }
929 } else {
930 oper.SetName(spn_);
931 }
932 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200933 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200934 << oper.GetName() << ", " << oper.GetCountry()
935 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400936 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800937 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400938}
939
Ben Chan8a2c01e2013-01-23 10:09:14 -0800940void CellularCapabilityUniversal::UpdateScanningProperty() {
941 // Set the Scanning property to true if there is a ongoing network scan
942 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
943 // to a network.
944 //
945 // TODO(benchan): As the Device DBus interface currently does not have a
946 // State property to indicate whether the device is being enabled, set the
947 // Scanning property to true when the modem is being enabled such that
948 // the network UI can start showing the initializing/scanning animation as
949 // soon as the modem is being enabled.
950 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800951 bool is_activated_service_waiting_for_registration =
952 ((modem_state == Cellular::kModemStateEnabled ||
953 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800954 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800955 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800956 modem_state == Cellular::kModemStateEnabling ||
957 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800958 scanning_;
959 if (new_scanning_or_searching != scanning_or_searching_) {
960 scanning_or_searching_ = new_scanning_or_searching;
961 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
962 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800963
964 if (!scanning_or_searching_) {
965 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
966 scanning_or_searching_timeout_callback_.Cancel();
967 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
968 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
969 scanning_or_searching_timeout_callback_.Reset(
970 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
971 weak_ptr_factory_.GetWeakPtr()));
972 cellular()->dispatcher()->PostDelayedTask(
973 scanning_or_searching_timeout_callback_.callback(),
974 scanning_or_searching_timeout_milliseconds_);
975 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800976 }
977}
978
Arman Uguray1361c032013-02-11 17:53:39 -0800979void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
980 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
981 << "flimflam::kScanningProperty to |false|.";
982 scanning_or_searching_ = false;
983 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty, false);
984}
985
Ben Chan6d0d1e72012-11-06 21:19:28 -0800986void CellularCapabilityUniversal::UpdateOLP() {
Ben Chan07193fd2013-07-12 22:10:55 -0700987 SLOG(Cellular, 2) << __func__;
988
989 const CellularOperatorInfo *cellular_operator_info =
990 modem_info()->cellular_operator_info();
991 if (!cellular_operator_info)
992 return;
993
994 const CellularOperatorInfo::CellularOperator *cellular_operator =
995 cellular_operator_info->GetCellularOperatorByMCCMNC(operator_id_);
996 if (!cellular_operator)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800997 return;
998
Arman Ugurayf4c61812013-01-10 18:58:39 -0800999 const CellularService::OLP *result =
Ben Chan07193fd2013-07-12 22:10:55 -07001000 cellular_operator_info->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001001 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -08001002 return;
1003
Arman Ugurayf4c61812013-01-10 18:58:39 -08001004 CellularService::OLP olp;
1005 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -08001006 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -08001007 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
1008 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
1009 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
Ben Chan07193fd2013-07-12 22:10:55 -07001010 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
1011 GetMdnForOLP(*cellular_operator));
Ben Chan6d0d1e72012-11-06 21:19:28 -08001012 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
1013 olp.SetPostData(post_data);
1014 cellular()->service()->SetOLP(olp);
1015}
1016
Arman Uguray2717a102013-01-29 23:36:06 -08001017void CellularCapabilityUniversal::UpdateServiceName() {
1018 if (cellular()->service()) {
1019 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
1020 }
1021}
1022
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001023void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001024 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -08001025 // TODO(armansito): Use CellularOperatorInfo here instead of
1026 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -08001027
Arman Uguray3645c432013-01-31 15:57:26 -08001028 // Sometimes the modem fails to acquire the operator code OTA, in which case
1029 // |serving_operator_| may not have an operator ID (sometimes due to service
1030 // activation being required or broken modem firmware). Use |operator_id_| as
1031 // a fallback when available. |operator_id_| is retrieved from the SIM card.
1032 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -08001033 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
1034 << "' as serving operator.";
1035 serving_operator_.SetCode(operator_id_);
1036 }
1037
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001038 const string &network_id = serving_operator_.GetCode();
1039 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001040 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001041 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001042 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001043 network_id.c_str());
1044 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +02001045 if (serving_operator_.GetName().empty()) {
1046 const char *provider_name = mobile_provider_get_name(provider);
1047 if (provider_name && *provider_name) {
1048 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001049 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001050 }
Darin Petkova4ca3c32012-08-17 16:05:24 +02001051 if (provider->country && *provider->country) {
1052 serving_operator_.SetCountry(provider->country);
1053 }
1054 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
1055 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001056 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001057 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001058 }
1059 }
1060 UpdateServingOperator();
1061}
1062
1063void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001064 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001065 if (cellular()->service().get()) {
1066 cellular()->service()->SetServingOperator(serving_operator_);
1067 }
1068}
1069
Arman Uguray6e5639f2012-11-15 20:30:19 -08001070void CellularCapabilityUniversal::UpdateBearerPath() {
1071 SLOG(Cellular, 2) << __func__;
1072 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1073 weak_ptr_factory_.GetWeakPtr());
1074 Error error;
1075 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1076}
1077
1078void CellularCapabilityUniversal::OnListBearersReply(
1079 const std::vector<DBus::Path> &paths,
1080 const Error &error) {
1081 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1082 if (error.IsFailure()) {
1083 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1084 return;
1085 }
1086 // Look for the first active bearer and use its path as the connected
1087 // one. Right now, we don't allow more than one active bearer.
mukesh agrawal9da07772013-05-15 14:15:17 -07001088 DBus::Path new_bearer_path;
1089 uint32 ipconfig_method(MM_BEARER_IP_METHOD_UNKNOWN);
1090 string network_device;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001091 for (size_t i = 0; i < paths.size(); ++i) {
1092 const DBus::Path &path = paths[i];
Ben Chan5db19692013-07-09 23:07:03 -07001093
1094 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1095 proxy_factory()->CreateDBusPropertiesProxy(path,
1096 cellular()->dbus_owner()));
1097 DBusPropertiesMap properties(
1098 properties_proxy->GetAll(MM_DBUS_INTERFACE_BEARER));
1099 if (properties.empty()) {
1100 LOG(WARNING) << "Could not get properties of bearer \"" << path
1101 << "\". Bearer is likely gone and thus ignored.";
mukesh agrawal9da07772013-05-15 14:15:17 -07001102 continue;
1103 }
Ben Chan5db19692013-07-09 23:07:03 -07001104
1105 bool connected = false;
1106 if (!DBusProperties::GetBool(
1107 properties, MM_BEARER_PROPERTY_CONNECTED, &connected)) {
1108 SLOG(Cellular, 2) << "Bearer does not indicate whether it is connected "
1109 "or not. Assume it is not connected.";
1110 continue;
1111 }
1112
1113 if (!connected) {
1114 continue;
1115 }
1116
mukesh agrawal9da07772013-05-15 14:15:17 -07001117 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
Ben Chan5db19692013-07-09 23:07:03 -07001118 CHECK(new_bearer_path.empty()) << "Found more than one active bearer.";
1119
1120 if (DBusProperties::GetString(
1121 properties, MM_BEARER_PROPERTY_INTERFACE, &network_device)) {
1122 SLOG(Cellular, 2) << "Bearer uses network interface \"" << network_device
1123 << "\".";
1124 } else {
1125 SLOG(Cellular, 2) << "Bearer does not specify network interface.";
1126 }
1127
mukesh agrawal9da07772013-05-15 14:15:17 -07001128 // TODO(quiche): Add support for scenarios where the bearer is
1129 // IPv6 only, or where there are conflicting configuration methods
1130 // for IPv4 and IPv6. crbug.com/248360.
Ben Chan5db19692013-07-09 23:07:03 -07001131 DBusPropertiesMap bearer_ip4config;
1132 DBusProperties::GetDBusPropertiesMap(
1133 properties, MM_BEARER_PROPERTY_IP4CONFIG, &bearer_ip4config);
1134
1135 if (DBusProperties::GetUint32(
1136 bearer_ip4config, kIpConfigPropertyMethod, &ipconfig_method)) {
mukesh agrawal9da07772013-05-15 14:15:17 -07001137 SLOG(Cellular, 2) << "Bearer has IPv4 config method " << ipconfig_method;
1138 } else {
1139 SLOG(Cellular, 2) << "Bearer does not specify IPv4 config method.";
1140 for (const auto &i : bearer_ip4config) {
1141 SLOG(Cellular, 5) << "Bearer IPv4 config has key \""
1142 << i.first
1143 << "\".";
Arman Uguray6e5639f2012-11-15 20:30:19 -08001144 }
1145 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001146 new_bearer_path = path;
Arman Uguray6e5639f2012-11-15 20:30:19 -08001147 }
mukesh agrawal9da07772013-05-15 14:15:17 -07001148 bearer_path_ = new_bearer_path;
1149 if (new_bearer_path.empty()) {
1150 SLOG(Cellular, 2) << "No active bearer found.";
1151 return;
1152 }
1153 if (ipconfig_method == MM_BEARER_IP_METHOD_PPP) {
1154 cellular()->StartPPP(network_device);
Arman Uguray6e5639f2012-11-15 20:30:19 -08001155 }
1156}
1157
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001158void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001159 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160 if (!home_provider_) {
1161 return;
1162 }
1163 apn_list_.clear();
1164 for (int i = 0; i < home_provider_->num_apns; ++i) {
1165 Stringmap props;
1166 mobile_apn *apn = home_provider_->apns[i];
1167 if (apn->value) {
1168 props[flimflam::kApnProperty] = apn->value;
1169 }
1170 if (apn->username) {
1171 props[flimflam::kApnUsernameProperty] = apn->username;
1172 }
1173 if (apn->password) {
1174 props[flimflam::kApnPasswordProperty] = apn->password;
1175 }
1176 // Find the first localized and non-localized name, if any.
1177 const localized_name *lname = NULL;
1178 const localized_name *name = NULL;
1179 for (int j = 0; j < apn->num_names; ++j) {
1180 if (apn->names[j]->lang) {
1181 if (!lname) {
1182 lname = apn->names[j];
1183 }
1184 } else if (!name) {
1185 name = apn->names[j];
1186 }
1187 }
1188 if (name) {
1189 props[flimflam::kApnNameProperty] = name->name;
1190 }
1191 if (lname) {
1192 props[flimflam::kApnLocalizedNameProperty] = lname->name;
1193 props[flimflam::kApnLanguageProperty] = lname->lang;
1194 }
1195 apn_list_.push_back(props);
1196 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001197 if (cellular()->adaptor()) {
1198 cellular()->adaptor()->EmitStringmapsChanged(
1199 flimflam::kCellularApnListProperty, apn_list_);
1200 } else {
1201 LOG(ERROR) << "Null RPC service adaptor.";
1202 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001203}
1204
Ben Chan15786032012-11-04 21:28:02 -08001205bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Arman Ugurayc7b15602013-02-16 00:56:18 -08001206 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001207 modem_info()->pending_activation_store()->GetActivationState(
1208 PendingActivationStore::kIdentifierICCID,
1209 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001210 return false;
1211
Ben Chan15786032012-11-04 21:28:02 -08001212 // If there is no online payment portal information, it's safer to assume
1213 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001214 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001215 return false;
1216
Arman Ugurayf4c61812013-01-10 18:58:39 -08001217 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001218 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001219 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001220 return false;
1221
1222 // To avoid false positives, it's safer to assume the service does not
1223 // require activation if MDN is not set.
1224 if (mdn_.empty())
1225 return false;
1226
Ben Chand7592522013-02-13 16:02:01 -08001227 // If MDN contains only zeros, the service requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001228 return !IsMdnValid();
1229}
1230
1231bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001232 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001233 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001234 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001235 return true;
Ben Chan15786032012-11-04 21:28:02 -08001236 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001237 return false;
Ben Chan15786032012-11-04 21:28:02 -08001238}
1239
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001240// always called from an async context
1241void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001242 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001243 CHECK(!callback.is_null());
1244 Error error;
1245 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1246 weak_ptr_factory_.GetWeakPtr(), callback);
1247 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1248 if (error.IsFailure())
1249 callback.Run(error);
1250}
1251
1252void CellularCapabilityUniversal::RegisterOnNetwork(
1253 const string &network_id,
1254 Error *error,
1255 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001256 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001257 CHECK(error);
1258 desired_network_ = network_id;
1259 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1260 weak_ptr_factory_.GetWeakPtr(), callback);
1261 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1262}
1263
1264void CellularCapabilityUniversal::OnRegisterReply(
1265 const ResultCallback &callback,
1266 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001267 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001268
1269 if (error.IsSuccess()) {
1270 selected_network_ = desired_network_;
1271 desired_network_.clear();
1272 callback.Run(error);
1273 return;
1274 }
1275 // If registration on the desired network failed,
1276 // try to register on the home network.
1277 if (!desired_network_.empty()) {
1278 desired_network_.clear();
1279 selected_network_.clear();
1280 LOG(INFO) << "Couldn't register on selected network, trying home network";
1281 Register(callback);
1282 return;
1283 }
1284 callback.Run(error);
1285}
1286
1287bool CellularCapabilityUniversal::IsRegistered() {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001288 return IsRegisteredState(registration_state_);
1289}
1290
1291bool CellularCapabilityUniversal::IsRegisteredState(
1292 MMModem3gppRegistrationState state) {
1293 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1294 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001295}
1296
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001297void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1298 // If we're already in some non-registered state, don't override that
1299 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1300 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1301 registration_state_ =
1302 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1303 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1304 }
1305}
1306
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001307void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001308 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001309 Error *error, const ResultCallback &callback) {
1310 CHECK(error);
1311 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1312}
1313
1314void CellularCapabilityUniversal::EnterPIN(const string &pin,
1315 Error *error,
1316 const ResultCallback &callback) {
1317 CHECK(error);
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001318 SLOG(Cellular, 2) << __func__;
1319 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001320}
1321
1322void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1323 const string &pin,
1324 Error *error,
1325 const ResultCallback &callback) {
1326 CHECK(error);
1327 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1328}
1329
1330void CellularCapabilityUniversal::ChangePIN(
1331 const string &old_pin, const string &new_pin,
1332 Error *error, const ResultCallback &callback) {
1333 CHECK(error);
1334 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1335}
1336
Ben Chan5d0d32c2013-01-08 02:05:29 -08001337void CellularCapabilityUniversal::Reset(Error *error,
1338 const ResultCallback &callback) {
1339 SLOG(Cellular, 2) << __func__;
1340 CHECK(error);
1341 if (resetting_) {
1342 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1343 return;
1344 }
1345 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1346 weak_ptr_factory_.GetWeakPtr(), callback);
1347 modem_proxy_->Reset(error, cb, kTimeoutReset);
1348 if (!error->IsFailure()) {
1349 resetting_ = true;
1350 }
1351}
1352
1353void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1354 const Error &error) {
1355 SLOG(Cellular, 2) << __func__;
1356 resetting_ = false;
1357 if (!callback.is_null())
1358 callback.Run(error);
1359}
1360
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001361void CellularCapabilityUniversal::Scan(Error *error,
1362 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001363 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001364 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001365 if (scanning_) {
1366 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1367 return;
1368 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001369 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1370 weak_ptr_factory_.GetWeakPtr(), callback);
1371 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001372 if (!error->IsFailure()) {
1373 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001374 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001375 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001376}
1377
1378void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1379 const ScanResults &results,
1380 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001381 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001382
1383 // Error handling is weak. The current expectation is that on any
1384 // error, found_networks_ should be cleared and a property change
1385 // notification sent out.
1386 //
1387 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001388 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001389 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001390 found_networks_.clear();
1391 if (!error.IsFailure()) {
1392 for (ScanResults::const_iterator it = results.begin();
1393 it != results.end(); ++it) {
1394 found_networks_.push_back(ParseScanResult(*it));
1395 }
1396 }
1397 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
1398 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001399
1400 // TODO(gmorain): This check for is_null() is a work-around because
1401 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1402 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1403 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1404 // Universal.
1405 if (!callback.is_null())
1406 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001407}
1408
1409Stringmap CellularCapabilityUniversal::ParseScanResult(
1410 const ScanResult &result) {
1411
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001412 /* ScanResults contain the following keys:
1413
1414 "status"
1415 A MMModem3gppNetworkAvailability value representing network
1416 availability status, given as an unsigned integer (signature "u").
1417 This key will always be present.
1418
1419 "operator-long"
1420 Long-format name of operator, given as a string value (signature
1421 "s"). If the name is unknown, this field should not be present.
1422
1423 "operator-short"
1424 Short-format name of operator, given as a string value
1425 (signature "s"). If the name is unknown, this field should not
1426 be present.
1427
1428 "operator-code"
1429 Mobile code of the operator, given as a string value (signature
1430 "s"). Returned in the format "MCCMNC", where MCC is the
1431 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1432 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1433
1434 "access-technology"
1435 A MMModemAccessTechnology value representing the generic access
1436 technology used by this mobile network, given as an unsigned
1437 integer (signature "u").
1438 */
1439 Stringmap parsed;
1440
1441 uint32 status;
1442 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1443 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1444 static const char * const kStatusString[] = {
1445 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1446 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1447 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1448 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1449 };
1450 parsed[flimflam::kStatusProperty] = kStatusString[status];
1451 }
1452
1453 uint32 tech; // MMModemAccessTechnology
1454 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1455 &tech)) {
1456 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
1457 }
1458
1459 string operator_long, operator_short, operator_code;
1460 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
1461 parsed[flimflam::kLongNameProperty] = operator_long;
1462 if (DBusProperties::GetString(result, kOperatorShortProperty,
1463 &operator_short))
1464 parsed[flimflam::kShortNameProperty] = operator_short;
1465 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
1466 parsed[flimflam::kNetworkIdProperty] = operator_code;
1467
1468 // If the long name is not available but the network ID is, look up the long
1469 // name in the mobile provider database.
1470 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
1471 parsed[flimflam::kLongNameProperty].empty()) &&
1472 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
1473 mobile_provider *provider =
1474 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001475 modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001476 parsed[flimflam::kNetworkIdProperty].c_str());
1477 if (provider) {
1478 const char *long_name = mobile_provider_get_name(provider);
1479 if (long_name && *long_name) {
1480 parsed[flimflam::kLongNameProperty] = long_name;
1481 }
1482 }
1483 }
1484 return parsed;
1485}
1486
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001487string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001488 // If we know that the modem is an E362, return LTE here to make sure that
1489 // Chrome sees LTE as the network technology even if the actual technology is
1490 // unknown.
1491 // TODO(armansito): This hack will cause the UI to display LTE even if the
1492 // modem doesn't support it at a given time. This might be problematic if we
1493 // ever want to support switching between access technologies (e.g. falling
1494 // back to 3G when LTE is not available).
1495 if (model_id_ == kE362ModelId)
1496 return flimflam::kNetworkTechnologyLte;
1497
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001498 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001499 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001500 return AccessTechnologyToString(access_technologies_);
1501}
1502
1503string CellularCapabilityUniversal::GetRoamingStateString() const {
1504 switch (registration_state_) {
1505 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1506 return flimflam::kRoamingStateHome;
1507 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1508 return flimflam::kRoamingStateRoaming;
1509 default:
1510 break;
1511 }
1512 return flimflam::kRoamingStateUnknown;
1513}
1514
1515void CellularCapabilityUniversal::GetSignalQuality() {
Paul Stewartee6b3d72013-07-12 16:07:51 -07001516 // TODO(njw): Switch to asynchronous calls (crbug.com/200687).
Nathan Williams218cbcd2012-04-17 16:48:44 -04001517 const DBus::Struct<unsigned int, bool> quality =
1518 modem_proxy_->SignalQuality();
1519 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001520}
1521
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001522string CellularCapabilityUniversal::GetTypeString() const {
1523 return AccessTechnologyToTechnologyFamily(access_technologies_);
1524}
1525
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001526void CellularCapabilityUniversal::OnModemPropertiesChanged(
1527 const DBusPropertiesMap &properties,
1528 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001529 // This solves a bootstrapping problem: If the modem is not yet
1530 // enabled, there are no proxy objects associated with the capability
1531 // object, so modem signals like StateChanged aren't seen. By monitoring
1532 // changes to the State property via the ModemManager, we're able to
1533 // get the initialization process started, which will result in the
1534 // creation of the proxy objects.
1535 //
1536 // The first time we see the change to State (when the modem state
1537 // is Unknown), we simply update the state, and rely on the Manager to
1538 // enable the device when it is registered with the Manager. On subsequent
1539 // changes to State, we need to explicitly enable the device ourselves.
1540 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001541 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001542 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001543 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001544 }
Ben Chan0a3a3a52013-07-10 11:34:07 -07001545 DBus::Path object_path_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001546 if (DBusProperties::GetObjectPath(properties,
Ben Chan0a3a3a52013-07-10 11:34:07 -07001547 MM_MODEM_PROPERTY_SIM, &object_path_value))
1548 OnSimPathChanged(object_path_value);
Ben Chan74924d82013-06-15 17:52:55 -07001549
1550 DBusPropertiesMap::const_iterator it =
1551 properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1552 if (it != properties.end()) {
1553 const vector<uint32> &supported_capabilities = it->second;
1554 OnSupportedCapabilitesChanged(supported_capabilities);
1555 }
1556
Jason Glasgowaf583282012-04-18 15:18:22 -04001557 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001558 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001559 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1560 &uint_value))
1561 OnModemCurrentCapabilitiesChanged(uint_value);
1562 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1563 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
Ben Chan0a3a3a52013-07-10 11:34:07 -07001564 string string_value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001565 if (DBusProperties::GetString(properties,
1566 MM_MODEM_PROPERTY_MANUFACTURER,
1567 &string_value))
1568 OnModemManufacturerChanged(string_value);
1569 if (DBusProperties::GetString(properties,
1570 MM_MODEM_PROPERTY_MODEL,
1571 &string_value))
1572 OnModemModelChanged(string_value);
1573 if (DBusProperties::GetString(properties,
1574 MM_MODEM_PROPERTY_REVISION,
1575 &string_value))
1576 OnModemRevisionChanged(string_value);
1577 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1578 // not needed: MM_MODEM_PROPERTY_DEVICE
1579 // not needed: MM_MODEM_PROPERTY_DRIVER
1580 // not needed: MM_MODEM_PROPERTY_PLUGIN
1581 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001582
Jason Glasgowaf583282012-04-18 15:18:22 -04001583 // Unlock required and SimLock
Ben Chan74924d82013-06-15 17:52:55 -07001584 uint32 unlock_required; // This is really of type MMModemLock
Arman Ugurayea5ff272013-06-25 10:28:02 -07001585 bool lock_status_changed = false;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001586 if (DBusProperties::GetUint32(properties,
1587 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Arman Ugurayea5ff272013-06-25 10:28:02 -07001588 &unlock_required)) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001589 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
Arman Ugurayea5ff272013-06-25 10:28:02 -07001590 lock_status_changed = true;
1591 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001592
1593 // Unlock retries
Ben Chan74924d82013-06-15 17:52:55 -07001594 it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
Jason Glasgowaf583282012-04-18 15:18:22 -04001595 if (it != properties.end()) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001596 LockRetryData lock_retries = it->second.operator LockRetryData();
1597 OnLockRetriesChanged(lock_retries);
Arman Ugurayea5ff272013-06-25 10:28:02 -07001598 lock_status_changed = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001599 }
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001600
Arman Ugurayea5ff272013-06-25 10:28:02 -07001601 if (lock_status_changed)
1602 OnSimLockStatusChanged();
1603
Jason Glasgowaf583282012-04-18 15:18:22 -04001604 if (DBusProperties::GetUint32(properties,
1605 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1606 &uint_value))
1607 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001608
Jason Glasgowaf583282012-04-18 15:18:22 -04001609 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1610 if (it != properties.end()) {
1611 DBus::Struct<unsigned int, bool> quality = it->second;
1612 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001613 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001614 vector<string> numbers;
1615 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1616 &numbers)) {
1617 string mdn;
1618 if (numbers.size() > 0)
1619 mdn = numbers[0];
1620 OnMdnChanged(mdn);
1621 }
Ben Chan74924d82013-06-15 17:52:55 -07001622
1623 it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1624 if (it != properties.end()) {
1625 const vector<DBus::Struct<uint32, uint32>> &mm_supported_modes = it->second;
1626 vector<ModemModes> supported_modes;
1627 for (const auto &modes : mm_supported_modes) {
1628 supported_modes.push_back(
1629 ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1630 }
1631 OnSupportedModesChanged(supported_modes);
1632 }
1633
1634 it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1635 if (it != properties.end()) {
1636 const DBus::Struct<uint32, uint32> &current_modes = it->second;
1637 OnCurrentModesChanged(ModemModes(
1638 current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1639 }
1640
Jason Glasgowaf583282012-04-18 15:18:22 -04001641 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1642 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001643}
1644
1645void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1646 const string &interface,
1647 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001648 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001649 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001650 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001651 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001652 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001653 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1654 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001655 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001656 if (interface == MM_DBUS_INTERFACE_SIM) {
1657 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001658 }
1659}
1660
Jason Glasgow14521872012-05-07 19:12:15 -04001661bool CellularCapabilityUniversal::RetriableConnectError(
1662 const Error &error) const {
1663 if (error.type() == Error::kInvalidApn)
1664 return true;
1665
1666 // modemmanager does not ever return kInvalidApn for E362 modems
1667 // with 1.41 firmware. It remains to be seem if this will change
1668 // with 3.x firmware.
1669 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1670 return true;
1671
1672 return false;
1673}
1674
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001675void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1676 // TODO(petkov): Implement this.
1677 NOTIMPLEMENTED();
1678}
1679
Arman Uguray6552f8c2013-02-12 15:33:18 -08001680bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1681 return !sim_path.empty() && sim_path != kRootPath;
1682}
1683
Ben Chand7592522013-02-13 16:02:01 -08001684string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1685 string normalized_mdn;
1686 for (size_t i = 0; i < mdn.size(); ++i) {
1687 if (IsAsciiDigit(mdn[i]))
1688 normalized_mdn += mdn[i];
1689 }
1690 return normalized_mdn;
1691}
1692
Jason Glasgowaf583282012-04-18 15:18:22 -04001693void CellularCapabilityUniversal::OnSimPathChanged(
1694 const string &sim_path) {
1695 if (sim_path == sim_path_)
1696 return;
1697
1698 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001699 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001700 proxy = proxy_factory()->CreateSimProxy(sim_path,
1701 cellular()->dbus_owner());
1702 sim_path_ = sim_path;
1703 sim_proxy_.reset(proxy);
1704
Arman Uguray6552f8c2013-02-12 15:33:18 -08001705 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001706 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001707 imsi_ = "";
1708 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001709 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001710 OnSimIdentifierChanged("");
1711 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001712 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001713 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001714 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1715 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1716 cellular()->dbus_owner()));
1717 // TODO(jglasgow): convert to async interface
1718 DBusPropertiesMap properties(
1719 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1720 OnSimPropertiesChanged(properties, vector<string>());
1721 }
1722}
1723
Ben Chan74924d82013-06-15 17:52:55 -07001724void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1725 const vector<uint32> &supported_capabilities) {
1726 supported_capabilities_ = supported_capabilities;
1727}
1728
Jason Glasgowaf583282012-04-18 15:18:22 -04001729void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1730 uint32 current_capabilities) {
1731 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001732
1733 // Only allow network scan when the modem's current capabilities support
1734 // GSM/UMTS.
1735 //
1736 // TODO(benchan): We should consider having the modem plugins in ModemManager
1737 // reporting whether network scan is supported.
1738 scanning_supported_ =
1739 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1740 if (cellular()->adaptor()) {
1741 cellular()->adaptor()->EmitBoolChanged(
1742 flimflam::kSupportNetworkScanProperty, scanning_supported_);
1743 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001744}
1745
1746void CellularCapabilityUniversal::OnMdnChanged(
1747 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001748 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001749 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001750}
1751
1752void CellularCapabilityUniversal::OnModemManufacturerChanged(
1753 const string &manufacturer) {
1754 manufacturer_ = manufacturer;
1755}
1756
1757void CellularCapabilityUniversal::OnModemModelChanged(
1758 const string &model) {
1759 model_id_ = model;
1760}
1761
1762void CellularCapabilityUniversal::OnModemRevisionChanged(
1763 const string &revision) {
1764 firmware_revision_ = revision;
1765}
1766
1767void CellularCapabilityUniversal::OnModemStateChanged(
1768 Cellular::ModemState state) {
1769 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1770 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1771 if (Cellular::IsEnabledModemState(state))
1772 cellular()->set_modem_state(state);
Gary Moraine285a842012-08-15 08:23:57 -07001773 SLOG(Cellular, 2) << __func__ << ": prev_modem_state: " << prev_modem_state
1774 << " was_enabled: " << was_enabled
1775 << " cellular state: "
1776 << cellular()->GetStateString(cellular()->state());
Jason Glasgowaf583282012-04-18 15:18:22 -04001777 if (prev_modem_state != Cellular::kModemStateUnknown &&
1778 prev_modem_state != Cellular::kModemStateEnabling &&
1779 !was_enabled &&
1780 cellular()->state() == Cellular::kStateDisabled &&
1781 cellular()->IsUnderlyingDeviceEnabled()) {
1782 cellular()->SetEnabled(true);
1783 }
Ben Chan8a2c01e2013-01-23 10:09:14 -08001784 UpdateScanningProperty();
Jason Glasgowaf583282012-04-18 15:18:22 -04001785}
1786
1787void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1788 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001789 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001790 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001791 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001792 const string new_type_string(GetTypeString());
1793 if (new_type_string != old_type_string) {
1794 // TODO(jglasgow): address layering violation of emitting change
1795 // signal here for a property owned by Cellular.
1796 cellular()->adaptor()->EmitStringChanged(
1797 flimflam::kTechnologyFamilyProperty, new_type_string);
1798 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001799 if (cellular()->service().get()) {
1800 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1801 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001802 }
1803}
1804
Ben Chan74924d82013-06-15 17:52:55 -07001805void CellularCapabilityUniversal::OnSupportedModesChanged(
1806 const vector<ModemModes> &supported_modes) {
1807 supported_modes_ = supported_modes;
1808}
1809
1810void CellularCapabilityUniversal::OnCurrentModesChanged(
1811 const ModemModes &current_modes) {
1812 current_modes_ = current_modes;
1813}
1814
Jason Glasgowaf583282012-04-18 15:18:22 -04001815void CellularCapabilityUniversal::OnLockRetriesChanged(
Jason Glasgowaf583282012-04-18 15:18:22 -04001816 const LockRetryData &lock_retries) {
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001817 SLOG(Cellular, 2) << __func__;
Arman Uguray192ad822013-06-13 19:49:16 -07001818
Arman Ugurayea5ff272013-06-25 10:28:02 -07001819 // Look for the retries left for the current lock. Try the obtain the count
1820 // that matches the current count. If no count for the current lock is
1821 // available, report the first one in the dictionary.
1822 LockRetryData::const_iterator it =
1823 lock_retries.find(sim_lock_status_.lock_type);
1824 if (it == lock_retries.end())
Arman Uguray192ad822013-06-13 19:49:16 -07001825 it = lock_retries.begin();
1826 if (it != lock_retries.end())
Jason Glasgowaf583282012-04-18 15:18:22 -04001827 sim_lock_status_.retries_left = it->second;
Arman Uguray192ad822013-06-13 19:49:16 -07001828 else
Jason Glasgowaf583282012-04-18 15:18:22 -04001829 // Unknown, use 999
1830 sim_lock_status_.retries_left = 999;
Jason Glasgowaf583282012-04-18 15:18:22 -04001831}
1832
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001833void CellularCapabilityUniversal::OnLockTypeChanged(
1834 MMModemLock lock_type) {
1835 SLOG(Cellular, 2) << __func__ << ": " << lock_type;
1836 sim_lock_status_.lock_type = lock_type;
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001837
1838 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1839 // This is because the corresponding property 'EnabledFacilityLocks' is on
1840 // the 3GPP interface and the 3GPP interface is not available while the Modem
1841 // is in the 'LOCKED' state.
1842 if (lock_type != MM_MODEM_LOCK_NONE &&
1843 lock_type != MM_MODEM_LOCK_UNKNOWN &&
1844 !sim_lock_status_.enabled)
1845 sim_lock_status_.enabled = true;
Arman Ugurayc7e63af2013-06-13 17:07:32 -07001846}
1847
Jason Glasgowaf583282012-04-18 15:18:22 -04001848void CellularCapabilityUniversal::OnSimLockStatusChanged() {
Arman Ugurayf6366ac2013-06-12 16:02:28 -07001849 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001850 cellular()->adaptor()->EmitKeyValueStoreChanged(
1851 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001852
1853 // If the SIM is currently unlocked, assume that we need to refresh
1854 // carrier information, since a locked SIM prevents shill from obtaining
1855 // the necessary data to establish a connection later (e.g. IMSI).
Ben Chand3b18742013-07-12 00:30:25 -07001856 if (IsValidSimPath(sim_path_) &&
Arman Uguray4ef02fd2013-06-13 20:14:20 -07001857 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1858 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
Arman Ugurayab9364e2012-12-19 20:45:25 -08001859 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1860 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1861 cellular()->dbus_owner()));
1862 DBusPropertiesMap properties(
1863 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1864 OnSimPropertiesChanged(properties, vector<string>());
1865 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001866}
1867
1868void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1869 const DBusPropertiesMap &properties,
1870 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001871 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001872 string imei;
1873 if (DBusProperties::GetString(properties,
1874 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1875 &imei))
1876 OnImeiChanged(imei);
1877
1878 // Handle registration state changes as a single change
1879 string operator_code = serving_operator_.GetCode();
1880 string operator_name = serving_operator_.GetName();
1881 MMModem3gppRegistrationState state = registration_state_;
1882 bool registration_changed = false;
1883 uint32 uint_value;
1884 if (DBusProperties::GetUint32(properties,
1885 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1886 &uint_value)) {
1887 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1888 registration_changed = true;
1889 }
1890 if (DBusProperties::GetString(properties,
1891 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1892 &operator_code))
1893 registration_changed = true;
1894 if (DBusProperties::GetString(properties,
1895 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1896 &operator_name))
1897 registration_changed = true;
1898 if (registration_changed)
1899 On3GPPRegistrationChanged(state, operator_code, operator_name);
1900
1901 uint32 locks = 0;
1902 if (DBusProperties::GetUint32(
1903 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1904 &locks))
1905 OnFacilityLocksChanged(locks);
1906}
1907
1908void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1909 imei_ = imei;
1910}
1911
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001912void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1913 MMModem3gppRegistrationState state,
1914 const string &operator_code,
1915 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001916 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1917 << ", opercode=" << operator_code
1918 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001919
1920 // While the modem is connected, if the state changed from a registered state
1921 // to a non registered state, defer the state change by 15 seconds.
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001922 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1923 IsRegistered() && !IsRegisteredState(state)) {
1924 if (!registration_dropped_update_callback_.IsCancelled()) {
1925 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1926 << "Ignoring earlier notifications.";
1927 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001928 } else {
1929 // This is not a repeated post. So, count this instance of delayed drop
1930 // posted.
1931 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001932 }
1933 SLOG(Cellular, 2) << "Posted deferred registration state update";
1934 registration_dropped_update_callback_.Reset(
1935 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1936 weak_ptr_factory_.GetWeakPtr(),
1937 state,
1938 operator_code,
1939 operator_name));
1940 cellular()->dispatcher()->PostDelayedTask(
1941 registration_dropped_update_callback_.callback(),
1942 registration_dropped_update_timeout_milliseconds_);
1943 } else {
1944 if (!registration_dropped_update_callback_.IsCancelled()) {
1945 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1946 registration_dropped_update_callback_.Cancel();
Prathmesh Prabhu08757aa2013-05-15 17:17:33 -07001947 // If we cancelled the callback here, it means we had flaky network for a
1948 // small duration.
1949 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001950 }
1951 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1952 }
1953}
1954
1955void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1956 MMModem3gppRegistrationState updated_state,
1957 string updated_operator_code,
1958 string updated_operator_name) {
1959 // A finished callback does not qualify as a canceled callback.
1960 // We test for a canceled callback to check for outstanding callbacks.
1961 // So, explicitly cancel the callback here.
1962 registration_dropped_update_callback_.Cancel();
1963
1964 SLOG(Cellular, 2) << __func__ << ": regstate=" << updated_state
1965 << ", opercode=" << updated_operator_code
1966 << ", opername=" << updated_operator_name;
1967
1968 registration_state_ = updated_state;
1969 serving_operator_.SetCode(updated_operator_code);
1970 serving_operator_.SetName(updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001971
1972 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001973 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08001974
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001975 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001976
1977 // Update the user facing name of the cellular service.
1978 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08001979
1980 // If the modem registered with the network and the current ICCID is pending
1981 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001982 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001983}
1984
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001985void CellularCapabilityUniversal::OnModemStateChangedSignal(
1986 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001987 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1988 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001989 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1990 static_cast<Cellular::ModemState>(new_state),
1991 reason);
Ben Chan2e12ccd2013-01-24 15:24:27 -08001992 UpdateScanningProperty();
Gary Moraine285a842012-08-15 08:23:57 -07001993 if (!deferred_enable_modem_callback_.is_null() &&
1994 (new_state == Cellular::kModemStateDisabled)) {
1995 SLOG(Cellular, 2) << "Enabling modem after deferring";
1996 deferred_enable_modem_callback_.Run();
1997 deferred_enable_modem_callback_.Reset();
Arman Uguray6e5639f2012-11-15 20:30:19 -08001998 } else if (new_state == Cellular::kModemStateConnected) {
1999 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
2000 UpdateBearerPath();
Gary Moraine285a842012-08-15 08:23:57 -07002001 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04002002}
2003
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002004void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
2005 cellular()->HandleNewSignalQuality(quality);
2006}
2007
Jason Glasgowaf583282012-04-18 15:18:22 -04002008void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
Arman Uguray4ef02fd2013-06-13 20:14:20 -07002009 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
2010 if (sim_lock_status_.enabled != sim_enabled) {
2011 sim_lock_status_.enabled = sim_enabled;
Jason Glasgowaf583282012-04-18 15:18:22 -04002012 OnSimLockStatusChanged();
2013 }
2014}
Jason Glasgowef965562012-04-10 16:12:35 -04002015
Jason Glasgowaf583282012-04-18 15:18:22 -04002016void CellularCapabilityUniversal::OnSimPropertiesChanged(
2017 const DBusPropertiesMap &props,
2018 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002019 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04002020 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04002021 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
2022 OnSimIdentifierChanged(value);
2023 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
2024 &value))
2025 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08002026 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
2027 OnSpnChanged(value);
2028 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
2029 OnImsiChanged(value);
2030 SetHomeProvider();
2031}
Jason Glasgowaf583282012-04-18 15:18:22 -04002032
Arman Ugurayd73783f2013-01-31 16:11:21 -08002033// TODO(armansito): The following methods should probably log their argument
2034// values. Need to learn if any of them need to be scrubbed.
2035void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
2036 imsi_ = imsi;
2037}
2038
2039void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
2040 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04002041}
2042
2043void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
2044 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08002045 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04002046}
2047
2048void CellularCapabilityUniversal::OnOperatorIdChanged(
2049 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08002050 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04002051 operator_id_ = operator_id;
2052}
2053
Jason Glasgow82f9ab32012-04-04 14:27:19 -04002054} // namespace shill