blob: 7695d4319c13eb9c7cc0b5418e2f3c91a22b3c75 [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"
Ben Chan15786032012-11-04 21:28:02 -080019#include "shill/cellular_operator_info.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040020#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040021#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040022#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070023#include "shill/logging.h"
Arman Uguray41cc6342013-03-29 16:34:39 -070024#include "shill/pending_activation_store.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040025#include "shill/property_accessor.h"
26#include "shill/proxy_factory.h"
27
28#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
29#error "Do not include mm-modem.h"
30#endif
31
Jason Glasgow82f9ab32012-04-04 14:27:19 -040032using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040033using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040034using std::string;
35using std::vector;
36
37namespace shill {
38
39// static
Jason Glasgow14521872012-05-07 19:12:15 -040040const char CellularCapabilityUniversal::kConnectPin[] = "pin";
41const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
42const char CellularCapabilityUniversal::kConnectBands[] = "bands";
43const char CellularCapabilityUniversal::kConnectAllowedModes[] =
44 "allowed-modes";
45const char CellularCapabilityUniversal::kConnectPreferredMode[] =
46 "preferred-mode";
47const char CellularCapabilityUniversal::kConnectApn[] = "apn";
48const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
49const char CellularCapabilityUniversal::kConnectUser[] = "user";
50const char CellularCapabilityUniversal::kConnectPassword[] = "password";
51const char CellularCapabilityUniversal::kConnectNumber[] = "number";
52const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
53 "allow-roaming";
54const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Arman Uguraya14941d2013-04-12 16:58:26 -070055const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070056CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
57 20000;
58const int64
Arman Uguray1361c032013-02-11 17:53:39 -080059CellularCapabilityUniversal::kDefaultScanningOrSearchingTimeoutMilliseconds =
60 60000;
Arman Uguraya14941d2013-04-12 16:58:26 -070061const int64
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -070062CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
63 15000;
Arman Uguray2717a102013-01-29 23:36:06 -080064const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
65 "Mobile Network";
Arman Uguray6552f8c2013-02-12 15:33:18 -080066const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040067const char CellularCapabilityUniversal::kStatusProperty[] = "status";
68const char CellularCapabilityUniversal::kOperatorLongProperty[] =
69 "operator-long";
70const char CellularCapabilityUniversal::kOperatorShortProperty[] =
71 "operator-short";
72const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
73 "operator-code";
74const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
75 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040076const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080077const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
78 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040079unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
80
Jason Glasgow82f9ab32012-04-04 14:27:19 -040081
82static const char kPhoneNumber[] = "*99#";
83
84static string AccessTechnologyToString(uint32 access_technologies) {
85 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
86 return flimflam::kNetworkTechnologyLte;
87 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
88 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
89 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
90 return flimflam::kNetworkTechnologyEvdo;
91 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
92 return flimflam::kNetworkTechnology1Xrtt;
93 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
94 return flimflam::kNetworkTechnologyHspaPlus;
95 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
96 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
98 return flimflam::kNetworkTechnologyHspa;
99 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
100 return flimflam::kNetworkTechnologyUmts;
101 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
102 return flimflam::kNetworkTechnologyEdge;
103 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
104 return flimflam::kNetworkTechnologyGprs;
105 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
106 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
107 return flimflam::kNetworkTechnologyGsm;
108 return "";
109}
110
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400111static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
112 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
113 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
114 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
115 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
116 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
117 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
118 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
119 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
120 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
121 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
122 return flimflam::kTechnologyFamilyGsm;
123 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800124 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
125 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400126 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
127 return flimflam::kTechnologyFamilyCdma;
128 return "";
129}
130
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400131CellularCapabilityUniversal::CellularCapabilityUniversal(
132 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800133 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700134 ModemInfo *modem_info)
135 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400136 weak_ptr_factory_(this),
137 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200138 capabilities_(MM_MODEM_CAPABILITY_NONE),
139 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400140 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400141 supported_modes_(MM_MODEM_MODE_NONE),
142 allowed_modes_(MM_MODEM_MODE_NONE),
143 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400144 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200145 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800146 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800147 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400148 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800149 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700150 scan_interval_(0),
Arman Uguray1361c032013-02-11 17:53:39 -0800151 sim_present_(false),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800152 reset_done_(false),
Arman Uguray1361c032013-02-11 17:53:39 -0800153 scanning_or_searching_timeout_milliseconds_(
Arman Uguraya14941d2013-04-12 16:58:26 -0700154 kDefaultScanningOrSearchingTimeoutMilliseconds),
155 activation_registration_timeout_milliseconds_(
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700156 kActivationRegistrationTimeoutMilliseconds),
157 registration_dropped_update_timeout_milliseconds_(
158 kRegistrationDroppedUpdateTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700159 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160 PropertyStore *store = cellular->mutable_store();
161
162 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
163 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
164 &scanning_supported_);
165 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
166 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
167 &firmware_revision_);
168 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
169 &hardware_revision_);
170 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
171 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700172 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400173 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
174 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
175 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
176 store->RegisterConstString(flimflam::kMinProperty, &min_);
177 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
178 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
179 &selected_network_);
180 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
181 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +0200182 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
183 &provider_requires_roaming_);
Ben Chan8a2c01e2013-01-23 10:09:14 -0800184 store->RegisterConstBool(flimflam::kScanningProperty,
185 &scanning_or_searching_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400186 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700187 HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400188 flimflam::kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700189 &CellularCapabilityUniversal::SimLockStatusToProperty);
Thieu Le550247c2013-04-30 17:16:43 -0700190 store->RegisterConstString(shill::kSIMOperatorIdProperty, &operator_id_);
Ben Chanbd3aee82012-10-16 23:52:04 -0700191 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400192 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
193 &apn_list_);
194}
195
196KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
197 Error */*error*/) {
198 KeyValueStore status;
199 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
200 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
201 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
202 sim_lock_status_.retries_left);
203 return status;
204}
205
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700206void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400207 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700208 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400209 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
210 name,
211 KeyValueStoreAccessor(
212 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700213 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400214}
215
216void CellularCapabilityUniversal::InitProxies() {
217 modem_3gpp_proxy_.reset(
218 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
219 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400220 modem_proxy_.reset(
221 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
222 cellular()->dbus_owner()));
223 modem_simple_proxy_.reset(
224 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
225 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800226
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400227 modem_proxy_->set_state_changed_callback(
228 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
229 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400230 // Do not create a SIM proxy until the device is enabled because we
231 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400232 // TODO(jglasgow): register callbacks
233}
234
235void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400236 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700237 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400238 InitProxies();
239
Gary Moraine285a842012-08-15 08:23:57 -0700240 // ModemManager must be in the disabled state to accept the Enable command.
241 Cellular::ModemState state =
242 static_cast<Cellular::ModemState>(modem_proxy_->State());
243 if (state == Cellular::kModemStateDisabled) {
244 EnableModem(error, callback);
245 } else if (!cellular()->IsUnderlyingDeviceEnabled()) {
246 SLOG(Cellular, 2) << "Enabling of modem deferred because state is "
247 << state;
248 deferred_enable_modem_callback_ =
249 Bind(&CellularCapabilityUniversal::EnableModem,
250 weak_ptr_factory_.GetWeakPtr(), static_cast<Error *>(NULL),
251 callback);
252 } else {
Thieu Leb9c05e02013-03-04 14:09:32 -0800253 // This request cannot be completed synchronously here because a method
254 // reply requires a continuation tag that is not created until the message
255 // handler returns, see DBus-C++ ObjectAdapter::handle_message().
256 cellular()->dispatcher()->PostTask(
257 Bind(&CellularCapabilityUniversal::Start_ModemAlreadyEnabled,
258 weak_ptr_factory_.GetWeakPtr(), callback));
Gary Moraine285a842012-08-15 08:23:57 -0700259 }
260}
261
262void CellularCapabilityUniversal::EnableModem(Error *error,
263 const ResultCallback &callback) {
264 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400265 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700266 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700267 modem_info()->metrics()->NotifyDeviceEnableStarted(
268 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400269 modem_proxy_->Enable(
270 true,
Gary Moraine285a842012-08-15 08:23:57 -0700271 &local_error,
Jason Glasgowef965562012-04-10 16:12:35 -0400272 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
273 weak_ptr_factory_.GetWeakPtr(), callback),
274 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700275 if (local_error.IsFailure()) {
276 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700277 }
278 if (error) {
279 error->CopyFrom(local_error);
280 }
Jason Glasgowef965562012-04-10 16:12:35 -0400281}
282
Thieu Leb9c05e02013-03-04 14:09:32 -0800283void CellularCapabilityUniversal::Start_ModemAlreadyEnabled(
284 const ResultCallback &callback) {
285 // Call GetProperties() here to sync up with the modem state
286 GetProperties();
287 callback.Run(Error());
288}
289
Jason Glasgowef965562012-04-10 16:12:35 -0400290void CellularCapabilityUniversal::Start_EnableModemCompleted(
291 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400292 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400293 if (error.IsFailure()) {
294 callback.Run(error);
295 return;
296 }
297
298 // After modem is enabled, it should be possible to get properties
299 // TODO(jglasgow): handle errors from GetProperties
300 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800301 // We expect the modem to start scanning after it has been enabled.
302 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700303 modem_info()->metrics()->NotifyDeviceEnableFinished(
304 cellular()->interface_index());
305 modem_info()->metrics()->NotifyDeviceScanStarted(
306 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800307 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400308}
309
310void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400311 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400312 CHECK(!callback.is_null());
313 CHECK(error);
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700314 // If there is an outstanding registration change, simply ignore it since
315 // the service will be destroyed anyway.
316 if (!registration_dropped_update_callback_.IsCancelled()) {
317 registration_dropped_update_callback_.Cancel();
318 SLOG(Cellular, 2) << __func__ << " Cancelled delayed deregister.";
319 }
320
Thieu Led0012052012-07-25 16:09:09 -0700321 Cellular::ModemState state = cellular()->modem_state();
322 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400323
Thieu Led0012052012-07-25 16:09:09 -0700324 if (cellular()->IsModemRegistered()) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400325 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400326 modem_simple_proxy_->Disconnect(
327 all_bearers,
328 error,
329 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
330 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le049adb52012-11-12 17:14:51 -0800331 kTimeoutDisconnect);
Jason Glasgowef965562012-04-10 16:12:35 -0400332 if (error->IsFailure())
333 callback.Run(*error);
334 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400335 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
336 weak_ptr_factory_.GetWeakPtr(),
337 callback);
338 cellular()->dispatcher()->PostTask(task);
339 }
Gary Moraine285a842012-08-15 08:23:57 -0700340 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400341}
342
343void CellularCapabilityUniversal::Stop_DisconnectCompleted(
344 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700345 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400346
347 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
348 Stop_Disable(callback);
349}
350
351void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
352 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700353 modem_info()->metrics()->NotifyDeviceDisableStarted(
354 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400355 modem_proxy_->Enable(
356 false, &error,
357 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
358 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400359 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400360 if (error.IsFailure())
361 callback.Run(error);
362}
363
364void CellularCapabilityUniversal::Stop_DisableCompleted(
365 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700366 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400367
Thieu Lea2519bf2013-01-23 16:51:54 -0800368 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800369 // The modem has been successfully disabled, but we still need to power it
370 // down.
371 Stop_PowerDown(callback);
372 } else {
373 // An error occurred; terminate the disable sequence.
374 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800375 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800376}
377
378void CellularCapabilityUniversal::Stop_PowerDown(
379 const ResultCallback &callback) {
380 SLOG(Cellular, 2) << __func__;
381 Error error;
382 modem_proxy_->SetPowerState(
383 MM_MODEM_POWER_STATE_LOW,
384 &error,
385 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
386 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800387 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800388
389 if (error.IsFailure())
390 // This really shouldn't happen, but if it does, report success,
391 // because a stop initiated power down is only called if the
392 // modem was successfully disabled, but the failure of this
393 // operation should still be propagated up as a successful disable.
394 Stop_PowerDownCompleted(callback, error);
395}
396
397void CellularCapabilityUniversal::Stop_PowerDownCompleted(
398 const ResultCallback &callback,
399 const Error &error) {
400 SLOG(Cellular, 2) << __func__;
401
402 if (error.IsFailure())
403 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
404
405 // Since the disable succeeded, if power down fails, we currently fail
406 // silently, i.e. we need to report the disable operation as having
407 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700408 modem_info()->metrics()->NotifyDeviceDisableFinished(
409 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800410 ReleaseProxies();
411 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400412}
413
414void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
415 Error *error,
416 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700417 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400418 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
419 weak_ptr_factory_.GetWeakPtr(),
420 callback);
421 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400422}
423
424void CellularCapabilityUniversal::Disconnect(Error *error,
425 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700426 SLOG(Cellular, 2) << __func__;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -0700427 // If a deferred registration loss request exists, process it.
428 if (!registration_dropped_update_callback_.IsCancelled()) {
429 registration_dropped_update_callback_.callback().Run();
430 DCHECK(cellular()->state() != Cellular::kStateConnected &&
431 cellular()->state() != Cellular::kStateLinked);
432 SLOG(Cellular, 1) << "Processed deferred registration loss before "
433 << "disconnect request.";
434 }
Thieu Le5d6864a2012-07-20 11:43:51 -0700435 if (bearer_path_.empty()) {
436 LOG(WARNING) << "In " << __func__ << "(): "
437 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700438 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700439 modem_simple_proxy_->Disconnect(bearer_path_,
440 error,
441 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800442 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700443 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400444}
445
Christopher Wiley8a468902012-11-30 11:52:38 -0800446void CellularCapabilityUniversal::DisconnectCleanup() {
447 SLOG(Cellular, 2) << __func__;
448}
449
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400450void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400451 Error *error,
452 const ResultCallback &callback) {
453 OnUnsupportedOperation(__func__, error);
454}
455
Arman Uguraya14941d2013-04-12 16:58:26 -0700456void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
457 SLOG(Cellular, 2) << __func__;
458 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700459 modem_info()->pending_activation_store()->GetActivationState(
460 PendingActivationStore::kIdentifierICCID,
461 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700462 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
463 return;
464 }
465 if (IsMdnValid()) {
466 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
467 return;
468 }
469 if (reset_done_) {
470 SLOG(Cellular, 2) << "Already done with reset.";
471 return;
472 }
473
474 // Still not activated after timeout. Reset the modem.
475 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
476 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700477 modem_info()->pending_activation_store()->SetActivationState(
478 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700479 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700480 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700481 ResetAfterActivation();
482}
483
Arman Ugurayc7b15602013-02-16 00:56:18 -0800484void CellularCapabilityUniversal::CompleteActivation(Error *error) {
485 SLOG(Cellular, 2) << __func__;
486
487 // Persist the ICCID as "Pending Activation".
488 // We're assuming that when this function gets called, |sim_identifier_| will
489 // be non-empty. We still check here that is non-empty, though something is
490 // wrong if it is empty.
491 if (IsMdnValid()) {
492 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
493 return;
494 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800495
Arman Ugurayc7b15602013-02-16 00:56:18 -0800496 if (sim_identifier_.empty()) {
497 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
498 return;
499 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800500
501 // There should be a cellular service at this point.
502 if (cellular()->service().get())
503 cellular()->service()->SetActivationState(
504 flimflam::kActivationStateActivating);
Arman Uguray41cc6342013-03-29 16:34:39 -0700505 modem_info()->pending_activation_store()->SetActivationState(
506 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800507 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700508 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700509
510 activation_wait_for_registration_callback_.Reset(
511 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
512 weak_ptr_factory_.GetWeakPtr()));
513 cellular()->dispatcher()->PostDelayedTask(
514 activation_wait_for_registration_callback_.callback(),
515 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800516}
517
518void CellularCapabilityUniversal::ResetAfterActivation() {
519 SLOG(Cellular, 2) << __func__;
520
521 // Here the initial call to Reset might fail in rare cases. Simply ignore.
522 Error error;
523 ResultCallback callback = Bind(
524 &CellularCapabilityUniversal::OnResetAfterActivationReply,
525 weak_ptr_factory_.GetWeakPtr());
526 Reset(&error, callback);
527 if (error.IsFailure())
528 SLOG(Cellular, 2) << "Failed to reset after activation.";
529}
530
531void CellularCapabilityUniversal::OnResetAfterActivationReply(
532 const Error &error) {
533 SLOG(Cellular, 2) << __func__;
534 if (error.IsFailure()) {
535 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
536 // TODO(armansito): Maybe post a delayed reset task?
537 return;
538 }
539 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700540 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800541 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800542}
543
Arman Uguray0a3e2792013-01-17 16:31:50 -0800544void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800545 SLOG(Cellular, 2) << __func__;
546
547 bool registered =
548 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
549
550 // If we have a valid MDN, the service is activated. Always try to remove
551 // the ICCID from persistence.
552 bool got_mdn = IsMdnValid();
553 if (got_mdn && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700554 modem_info()->pending_activation_store()->RemoveEntry(
555 PendingActivationStore::kIdentifierICCID,
556 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800557
Arman Ugurayefea6e02013-02-21 13:28:04 -0800558 CellularServiceRefPtr service = cellular()->service();
559
560 if (!service.get())
561 return;
562
563 if (service->activation_state() == flimflam::kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800564 // Either no service or already activated. Nothing to do.
565 return;
566
567 // If we have a valid MDN or we can connect to the network, then the service
568 // is activated.
569 if (got_mdn || cellular()->state() == Cellular::kStateConnected ||
570 cellular()->state() == Cellular::kStateLinked) {
571 SLOG(Cellular, 2) << "Marking service as activated.";
Arman Ugurayefea6e02013-02-21 13:28:04 -0800572 service->SetActivationState(flimflam::kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800573 return;
574 }
575
576 // If the ICCID is not available, the following logic can be delayed until it
577 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800578 if (sim_identifier_.empty())
579 return;
580
Arman Uguray41cc6342013-03-29 16:34:39 -0700581 PendingActivationStore::State state =
582 modem_info()->pending_activation_store()->GetActivationState(
583 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700584 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800585 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700586 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800587 // Always mark the service as activating here, as the ICCID could have
588 // been unavailable earlier.
589 service->SetActivationState(flimflam::kActivationStateActivating);
590 if (reset_done_) {
591 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700592 modem_info()->pending_activation_store()->SetActivationState(
593 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800594 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700595 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800596 } else if (registered) {
597 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700598 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800599 ResetAfterActivation();
600 }
601 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700602 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800603 if (registered) {
604 // Trigger auto connect here.
605 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
606 << "autoconnect to force MDN to update.";
607 service->AutoConnect();
608 }
609 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700610 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700611 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
612 << "been reset at least once.";
613 if (registered) {
614 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700615 modem_info()->pending_activation_store()->SetActivationState(
616 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700617 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700618 PendingActivationStore::kStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700619 service->SetActivationState(flimflam::kActivationStateActivated);
620 }
621 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700622 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800623 // No entry exists for this ICCID. Nothing to do.
624 break;
625 default:
626 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800627 }
628}
629
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400630void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700631 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400632 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400633 modem_proxy_.reset();
634 modem_simple_proxy_.reset();
635 sim_proxy_.reset();
636}
637
Arman Ugurayc9533572013-01-22 17:34:20 -0800638void CellularCapabilityUniversal::UpdateStorageIdentifier() {
639 if (!cellular()->service().get())
640 return;
641
642 // Lookup the unique identifier assigned to the current network and base the
643 // service's storage identifier on it.
644 const string prefix = "cellular_" + cellular()->address() + "_";
645 string storage_id;
646 if (!operator_id_.empty()) {
647 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700648 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
649 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800650 if (provider && !provider->identifier().empty()) {
651 storage_id = prefix + provider->identifier();
652 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400653 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800654 // If the above didn't work, append IMSI, if available.
655 if (storage_id.empty() && !imsi_.empty()) {
656 storage_id = prefix + imsi_;
657 }
658 if (!storage_id.empty()) {
659 cellular()->service()->SetStorageIdentifier(storage_id);
660 }
661}
662
Arman Ugurayefea6e02013-02-21 13:28:04 -0800663void CellularCapabilityUniversal::UpdateServiceActivationState() {
664 if (!cellular()->service().get())
665 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800666 bool activation_required = IsServiceActivationRequired();
Arman Uguray6bb252d2013-05-15 14:29:53 -0700667 string activation_state;
Arman Uguray41cc6342013-03-29 16:34:39 -0700668 PendingActivationStore::State state =
669 modem_info()->pending_activation_store()->GetActivationState(
670 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700671 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800672 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700673 (state == PendingActivationStore::kStatePending ||
674 state == PendingActivationStore::kStatePendingTimeout))
Arman Ugurayefea6e02013-02-21 13:28:04 -0800675 activation_state = flimflam::kActivationStateActivating;
676 else if (activation_required)
677 activation_state = flimflam::kActivationStateNotActivated;
Arman Uguray6bb252d2013-05-15 14:29:53 -0700678 else {
679 activation_state = flimflam::kActivationStateActivated;
680
681 // Mark an activated service for auto-connect by default. Since data from
682 // the user profile will be loaded after the call to OnServiceCreated, this
683 // property will be corrected based on the user data at that time.
684 cellular()->service()->SetAutoConnect(true);
685 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800686 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800687 // TODO(benchan): For now, assume the cellular service is activated over
688 // a non-cellular network if service activation is required (i.e. a
689 // corresponding entry is found in the cellular operator info file).
690 // We will need to generalize this logic when migrating CDMA support from
691 // cromo to ModemManager.
692 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800693}
694
695void CellularCapabilityUniversal::OnServiceCreated() {
696 UpdateStorageIdentifier();
697 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800698 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400699 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800700 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700701
702 // WORKAROUND:
703 // E362 modems on Verizon network does not properly redirect when a SIM
704 // runs out of credits, we need to enforce out-of-credits detection.
705 // TODO(thieule): Remove this workaround (crosbug.com/p/18619).
706 if (model_id_ == kE362ModelId)
707 cellular()->service()->set_enforce_out_of_credits_detection(true);
Arman Uguray7af0fac2013-03-18 17:35:35 -0700708
709 // Make sure that the network technology is set when the service gets
710 // created, just in case.
711 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400712}
713
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400714// Create the list of APNs to try, in the following order:
715// - last APN that resulted in a successful connection attempt on the
716// current network (if any)
717// - the APN, if any, that was set by the user
718// - the list of APNs found in the mobile broadband provider DB for the
719// home provider associated with the current SIM
720// - as a last resort, attempt to connect with no APN
721void CellularCapabilityUniversal::SetupApnTryList() {
722 apn_try_list_.clear();
723
724 DCHECK(cellular()->service().get());
725 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
726 if (apn_info)
727 apn_try_list_.push_back(*apn_info);
728
729 apn_info = cellular()->service()->GetUserSpecifiedApn();
730 if (apn_info)
731 apn_try_list_.push_back(*apn_info);
732
733 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
734}
735
736void CellularCapabilityUniversal::SetupConnectProperties(
737 DBusPropertiesMap *properties) {
738 SetupApnTryList();
739 FillConnectPropertyMap(properties);
740}
741
742void CellularCapabilityUniversal::FillConnectPropertyMap(
743 DBusPropertiesMap *properties) {
744
745 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400746 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400747 kPhoneNumber);
748
Jason Glasgow14521872012-05-07 19:12:15 -0400749 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400750 AllowRoaming());
751
752 if (!apn_try_list_.empty()) {
753 // Leave the APN at the front of the list, so that it can be recorded
754 // if the connect attempt succeeds.
755 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700756 SLOG(Cellular, 2) << __func__ << ": Using APN "
757 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400758 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400759 apn_info[flimflam::kApnProperty].c_str());
760 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400761 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400762 apn_info[flimflam::kApnUsernameProperty].c_str());
763 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400764 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400765 apn_info[flimflam::kApnPasswordProperty].c_str());
766 }
767}
768
769void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400770 const DBus::Path &path,
771 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700772 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400773
Jason Glasgow7234ec32012-05-23 16:01:21 -0400774 CellularServiceRefPtr service = cellular()->service();
775 if (!service) {
776 // The service could have been deleted before our Connect() request
777 // completes if the modem was enabled and then quickly disabled.
778 apn_try_list_.clear();
779 } else if (error.IsFailure()) {
780 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400781 // The APN that was just tried (and failed) is still at the
782 // front of the list, about to be removed. If the list is empty
783 // after that, try one last time without an APN. This may succeed
784 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400785 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400786 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700787 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
788 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400789 DBusPropertiesMap props;
790 FillConnectPropertyMap(&props);
791 Error error;
792 Connect(props, &error, callback);
793 return;
794 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400795 } else {
796 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400797 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400798 apn_try_list_.clear();
799 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400800 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400801 }
802
803 if (!callback.is_null())
804 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800805
Arman Uguray0a3e2792013-01-17 16:31:50 -0800806 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400807}
808
809bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200810 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400811}
812
Arman Ugurayf84a4242013-04-09 20:01:07 -0700813bool CellularCapabilityUniversal::ShouldDetectOutOfCredit() const {
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700814 return model_id_ == kE362ModelId;
815}
816
Jason Glasgowef965562012-04-10 16:12:35 -0400817void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700818 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400819
Jason Glasgowaf583282012-04-18 15:18:22 -0400820 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
821 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
822 cellular()->dbus_owner()));
823 DBusPropertiesMap properties(
824 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
825 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400826
Jason Glasgowaf583282012-04-18 15:18:22 -0400827 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
828 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400829}
830
Arman Uguray2717a102013-01-29 23:36:06 -0800831// static
832string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
833 return base::StringPrintf("%s %u",
834 kGenericServiceNamePrefix,
835 friendly_service_name_id_++);
836}
837
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400838string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200839 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800840
841 // If |serving_operator_| does not have an operator ID, call
842 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
843 if (serving_operator_.GetCode().empty()) {
844 UpdateOperatorInfo();
845 }
846
Darin Petkova4ca3c32012-08-17 16:05:24 +0200847 string name = serving_operator_.GetName();
848 string home_provider_name = cellular()->home_provider().GetName();
849 if (!name.empty()) {
850 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
851 // rules (TS 31.102 and annex A of 122.101).
852 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
853 !home_provider_name.empty()) {
854 return home_provider_name + " | " + name;
855 }
856 return name;
857 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400858 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200859 !home_provider_name.empty()) {
860 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400861 }
Arman Uguray2717a102013-01-29 23:36:06 -0800862 if (!serving_operator_.GetCode().empty()) {
863 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400864 }
Arman Uguray2717a102013-01-29 23:36:06 -0800865 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400866}
867
868void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700869 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400870 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800871
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700872 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400873 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800874
875 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
876 // one is available. If both were reported by the SIM, use IMSI.
877 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
878 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700879 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800880 spn_.c_str(),
881 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400882 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800883 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400884 return;
885 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400886
887 // Even if provider is the same as home_provider_, it is possible
888 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400889 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200890 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400891 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800892 // If Operator ID is available, use that as network code, otherwise
893 // use what was returned from the database.
894 if (!operator_id_.empty()) {
895 oper.SetCode(operator_id_);
896 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400897 oper.SetCode(provider->networks[0]);
898 }
899 if (provider->country) {
900 oper.SetCountry(provider->country);
901 }
902 if (spn_.empty()) {
903 const char *name = mobile_provider_get_name(provider);
904 if (name) {
905 oper.SetName(name);
906 }
907 } else {
908 oper.SetName(spn_);
909 }
910 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200911 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200912 << oper.GetName() << ", " << oper.GetCountry()
913 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400914 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800915 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400916}
917
Ben Chan8a2c01e2013-01-23 10:09:14 -0800918void CellularCapabilityUniversal::UpdateScanningProperty() {
919 // Set the Scanning property to true if there is a ongoing network scan
920 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
921 // to a network.
922 //
923 // TODO(benchan): As the Device DBus interface currently does not have a
924 // State property to indicate whether the device is being enabled, set the
925 // Scanning property to true when the modem is being enabled such that
926 // the network UI can start showing the initializing/scanning animation as
927 // soon as the modem is being enabled.
928 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800929 bool is_activated_service_waiting_for_registration =
930 ((modem_state == Cellular::kModemStateEnabled ||
931 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800932 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800933 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800934 modem_state == Cellular::kModemStateEnabling ||
935 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800936 scanning_;
937 if (new_scanning_or_searching != scanning_or_searching_) {
938 scanning_or_searching_ = new_scanning_or_searching;
939 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
940 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800941
942 if (!scanning_or_searching_) {
943 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
944 scanning_or_searching_timeout_callback_.Cancel();
945 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
946 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
947 scanning_or_searching_timeout_callback_.Reset(
948 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
949 weak_ptr_factory_.GetWeakPtr()));
950 cellular()->dispatcher()->PostDelayedTask(
951 scanning_or_searching_timeout_callback_.callback(),
952 scanning_or_searching_timeout_milliseconds_);
953 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800954 }
955}
956
Arman Uguray1361c032013-02-11 17:53:39 -0800957void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
958 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
959 << "flimflam::kScanningProperty to |false|.";
960 scanning_or_searching_ = false;
961 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty, false);
962}
963
Ben Chan6d0d1e72012-11-06 21:19:28 -0800964void CellularCapabilityUniversal::UpdateOLP() {
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700965 if (!modem_info()->cellular_operator_info())
Ben Chan6d0d1e72012-11-06 21:19:28 -0800966 return;
967
Arman Ugurayf4c61812013-01-10 18:58:39 -0800968 const CellularService::OLP *result =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700969 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -0800970 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800971 return;
972
Arman Ugurayf4c61812013-01-10 18:58:39 -0800973 CellularService::OLP olp;
974 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800975 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800976 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
977 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
978 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
979 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}", mdn_);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800980 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
981 olp.SetPostData(post_data);
982 cellular()->service()->SetOLP(olp);
983}
984
Arman Uguray2717a102013-01-29 23:36:06 -0800985void CellularCapabilityUniversal::UpdateServiceName() {
986 if (cellular()->service()) {
987 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
988 }
989}
990
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400991void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700992 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -0800993 // TODO(armansito): Use CellularOperatorInfo here instead of
994 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -0800995
Arman Uguray3645c432013-01-31 15:57:26 -0800996 // Sometimes the modem fails to acquire the operator code OTA, in which case
997 // |serving_operator_| may not have an operator ID (sometimes due to service
998 // activation being required or broken modem firmware). Use |operator_id_| as
999 // a fallback when available. |operator_id_| is retrieved from the SIM card.
1000 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -08001001 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
1002 << "' as serving operator.";
1003 serving_operator_.SetCode(operator_id_);
1004 }
1005
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001006 const string &network_id = serving_operator_.GetCode();
1007 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001008 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001009 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001010 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001011 network_id.c_str());
1012 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +02001013 if (serving_operator_.GetName().empty()) {
1014 const char *provider_name = mobile_provider_get_name(provider);
1015 if (provider_name && *provider_name) {
1016 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001017 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001018 }
Darin Petkova4ca3c32012-08-17 16:05:24 +02001019 if (provider->country && *provider->country) {
1020 serving_operator_.SetCountry(provider->country);
1021 }
1022 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
1023 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001024 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001025 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001026 }
1027 }
1028 UpdateServingOperator();
1029}
1030
1031void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001032 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001033 if (cellular()->service().get()) {
1034 cellular()->service()->SetServingOperator(serving_operator_);
1035 }
1036}
1037
Arman Uguray6e5639f2012-11-15 20:30:19 -08001038void CellularCapabilityUniversal::UpdateBearerPath() {
1039 SLOG(Cellular, 2) << __func__;
1040 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1041 weak_ptr_factory_.GetWeakPtr());
1042 Error error;
1043 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1044}
1045
1046void CellularCapabilityUniversal::OnListBearersReply(
1047 const std::vector<DBus::Path> &paths,
1048 const Error &error) {
1049 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1050 if (error.IsFailure()) {
1051 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1052 return;
1053 }
1054 // Look for the first active bearer and use its path as the connected
1055 // one. Right now, we don't allow more than one active bearer.
1056 bool found_active = false;
1057 for (size_t i = 0; i < paths.size(); ++i) {
1058 const DBus::Path &path = paths[i];
1059 scoped_ptr<mm1::BearerProxyInterface> bearer_proxy(
1060 proxy_factory()->CreateBearerProxy(path, cellular()->dbus_owner()));
1061 bool is_active = bearer_proxy->Connected();
1062 if (is_active) {
1063 if (!found_active) {
1064 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
1065 bearer_path_ = path;
1066 found_active = true;
1067 } else {
1068 LOG(FATAL) << "Found more than one active bearer.";
1069 }
1070 }
1071 }
1072 if (!found_active) {
1073 SLOG(Cellular, 2) << "No active bearer found, clearing bearer_path_.";
1074 bearer_path_.clear();
1075 }
1076}
1077
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001078void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001079 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001080 if (!home_provider_) {
1081 return;
1082 }
1083 apn_list_.clear();
1084 for (int i = 0; i < home_provider_->num_apns; ++i) {
1085 Stringmap props;
1086 mobile_apn *apn = home_provider_->apns[i];
1087 if (apn->value) {
1088 props[flimflam::kApnProperty] = apn->value;
1089 }
1090 if (apn->username) {
1091 props[flimflam::kApnUsernameProperty] = apn->username;
1092 }
1093 if (apn->password) {
1094 props[flimflam::kApnPasswordProperty] = apn->password;
1095 }
1096 // Find the first localized and non-localized name, if any.
1097 const localized_name *lname = NULL;
1098 const localized_name *name = NULL;
1099 for (int j = 0; j < apn->num_names; ++j) {
1100 if (apn->names[j]->lang) {
1101 if (!lname) {
1102 lname = apn->names[j];
1103 }
1104 } else if (!name) {
1105 name = apn->names[j];
1106 }
1107 }
1108 if (name) {
1109 props[flimflam::kApnNameProperty] = name->name;
1110 }
1111 if (lname) {
1112 props[flimflam::kApnLocalizedNameProperty] = lname->name;
1113 props[flimflam::kApnLanguageProperty] = lname->lang;
1114 }
1115 apn_list_.push_back(props);
1116 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001117 if (cellular()->adaptor()) {
1118 cellular()->adaptor()->EmitStringmapsChanged(
1119 flimflam::kCellularApnListProperty, apn_list_);
1120 } else {
1121 LOG(ERROR) << "Null RPC service adaptor.";
1122 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001123}
1124
Ben Chan15786032012-11-04 21:28:02 -08001125bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Arman Ugurayc7b15602013-02-16 00:56:18 -08001126 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001127 modem_info()->pending_activation_store()->GetActivationState(
1128 PendingActivationStore::kIdentifierICCID,
1129 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001130 return false;
1131
Ben Chan15786032012-11-04 21:28:02 -08001132 // If there is no online payment portal information, it's safer to assume
1133 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001134 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001135 return false;
1136
Arman Ugurayf4c61812013-01-10 18:58:39 -08001137 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001138 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001139 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001140 return false;
1141
1142 // To avoid false positives, it's safer to assume the service does not
1143 // require activation if MDN is not set.
1144 if (mdn_.empty())
1145 return false;
1146
Ben Chand7592522013-02-13 16:02:01 -08001147 // If MDN contains only zeros, the service requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001148 return !IsMdnValid();
1149}
1150
1151bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001152 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001153 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001154 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001155 return true;
Ben Chan15786032012-11-04 21:28:02 -08001156 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001157 return false;
Ben Chan15786032012-11-04 21:28:02 -08001158}
1159
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160// always called from an async context
1161void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001162 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001163 CHECK(!callback.is_null());
1164 Error error;
1165 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1166 weak_ptr_factory_.GetWeakPtr(), callback);
1167 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1168 if (error.IsFailure())
1169 callback.Run(error);
1170}
1171
1172void CellularCapabilityUniversal::RegisterOnNetwork(
1173 const string &network_id,
1174 Error *error,
1175 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001176 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001177 CHECK(error);
1178 desired_network_ = network_id;
1179 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1180 weak_ptr_factory_.GetWeakPtr(), callback);
1181 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1182}
1183
1184void CellularCapabilityUniversal::OnRegisterReply(
1185 const ResultCallback &callback,
1186 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001187 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001188
1189 if (error.IsSuccess()) {
1190 selected_network_ = desired_network_;
1191 desired_network_.clear();
1192 callback.Run(error);
1193 return;
1194 }
1195 // If registration on the desired network failed,
1196 // try to register on the home network.
1197 if (!desired_network_.empty()) {
1198 desired_network_.clear();
1199 selected_network_.clear();
1200 LOG(INFO) << "Couldn't register on selected network, trying home network";
1201 Register(callback);
1202 return;
1203 }
1204 callback.Run(error);
1205}
1206
1207bool CellularCapabilityUniversal::IsRegistered() {
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001208 return IsRegisteredState(registration_state_);
1209}
1210
1211bool CellularCapabilityUniversal::IsRegisteredState(
1212 MMModem3gppRegistrationState state) {
1213 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1214 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001215}
1216
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001217void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1218 // If we're already in some non-registered state, don't override that
1219 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1220 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1221 registration_state_ =
1222 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1223 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1224 }
1225}
1226
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001227void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001228 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001229 Error *error, const ResultCallback &callback) {
1230 CHECK(error);
1231 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1232}
1233
1234void CellularCapabilityUniversal::EnterPIN(const string &pin,
1235 Error *error,
1236 const ResultCallback &callback) {
1237 CHECK(error);
1238 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
1239}
1240
1241void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1242 const string &pin,
1243 Error *error,
1244 const ResultCallback &callback) {
1245 CHECK(error);
1246 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1247}
1248
1249void CellularCapabilityUniversal::ChangePIN(
1250 const string &old_pin, const string &new_pin,
1251 Error *error, const ResultCallback &callback) {
1252 CHECK(error);
1253 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1254}
1255
Ben Chan5d0d32c2013-01-08 02:05:29 -08001256void CellularCapabilityUniversal::Reset(Error *error,
1257 const ResultCallback &callback) {
1258 SLOG(Cellular, 2) << __func__;
1259 CHECK(error);
1260 if (resetting_) {
1261 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1262 return;
1263 }
1264 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1265 weak_ptr_factory_.GetWeakPtr(), callback);
1266 modem_proxy_->Reset(error, cb, kTimeoutReset);
1267 if (!error->IsFailure()) {
1268 resetting_ = true;
1269 }
1270}
1271
1272void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1273 const Error &error) {
1274 SLOG(Cellular, 2) << __func__;
1275 resetting_ = false;
1276 if (!callback.is_null())
1277 callback.Run(error);
1278}
1279
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001280void CellularCapabilityUniversal::Scan(Error *error,
1281 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001282 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001283 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001284 if (scanning_) {
1285 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1286 return;
1287 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001288 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1289 weak_ptr_factory_.GetWeakPtr(), callback);
1290 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001291 if (!error->IsFailure()) {
1292 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001293 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001294 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001295}
1296
1297void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1298 const ScanResults &results,
1299 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001300 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001301
1302 // Error handling is weak. The current expectation is that on any
1303 // error, found_networks_ should be cleared and a property change
1304 // notification sent out.
1305 //
1306 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001307 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001308 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001309 found_networks_.clear();
1310 if (!error.IsFailure()) {
1311 for (ScanResults::const_iterator it = results.begin();
1312 it != results.end(); ++it) {
1313 found_networks_.push_back(ParseScanResult(*it));
1314 }
1315 }
1316 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
1317 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001318
1319 // TODO(gmorain): This check for is_null() is a work-around because
1320 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1321 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1322 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1323 // Universal.
1324 if (!callback.is_null())
1325 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001326}
1327
1328Stringmap CellularCapabilityUniversal::ParseScanResult(
1329 const ScanResult &result) {
1330
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001331 /* ScanResults contain the following keys:
1332
1333 "status"
1334 A MMModem3gppNetworkAvailability value representing network
1335 availability status, given as an unsigned integer (signature "u").
1336 This key will always be present.
1337
1338 "operator-long"
1339 Long-format name of operator, given as a string value (signature
1340 "s"). If the name is unknown, this field should not be present.
1341
1342 "operator-short"
1343 Short-format name of operator, given as a string value
1344 (signature "s"). If the name is unknown, this field should not
1345 be present.
1346
1347 "operator-code"
1348 Mobile code of the operator, given as a string value (signature
1349 "s"). Returned in the format "MCCMNC", where MCC is the
1350 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1351 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1352
1353 "access-technology"
1354 A MMModemAccessTechnology value representing the generic access
1355 technology used by this mobile network, given as an unsigned
1356 integer (signature "u").
1357 */
1358 Stringmap parsed;
1359
1360 uint32 status;
1361 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1362 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1363 static const char * const kStatusString[] = {
1364 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1365 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1366 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1367 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1368 };
1369 parsed[flimflam::kStatusProperty] = kStatusString[status];
1370 }
1371
1372 uint32 tech; // MMModemAccessTechnology
1373 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1374 &tech)) {
1375 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
1376 }
1377
1378 string operator_long, operator_short, operator_code;
1379 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
1380 parsed[flimflam::kLongNameProperty] = operator_long;
1381 if (DBusProperties::GetString(result, kOperatorShortProperty,
1382 &operator_short))
1383 parsed[flimflam::kShortNameProperty] = operator_short;
1384 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
1385 parsed[flimflam::kNetworkIdProperty] = operator_code;
1386
1387 // If the long name is not available but the network ID is, look up the long
1388 // name in the mobile provider database.
1389 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
1390 parsed[flimflam::kLongNameProperty].empty()) &&
1391 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
1392 mobile_provider *provider =
1393 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001394 modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001395 parsed[flimflam::kNetworkIdProperty].c_str());
1396 if (provider) {
1397 const char *long_name = mobile_provider_get_name(provider);
1398 if (long_name && *long_name) {
1399 parsed[flimflam::kLongNameProperty] = long_name;
1400 }
1401 }
1402 }
1403 return parsed;
1404}
1405
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001406string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001407 // If we know that the modem is an E362, return LTE here to make sure that
1408 // Chrome sees LTE as the network technology even if the actual technology is
1409 // unknown.
1410 // TODO(armansito): This hack will cause the UI to display LTE even if the
1411 // modem doesn't support it at a given time. This might be problematic if we
1412 // ever want to support switching between access technologies (e.g. falling
1413 // back to 3G when LTE is not available).
1414 if (model_id_ == kE362ModelId)
1415 return flimflam::kNetworkTechnologyLte;
1416
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001417 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001418 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001419 return AccessTechnologyToString(access_technologies_);
1420}
1421
1422string CellularCapabilityUniversal::GetRoamingStateString() const {
1423 switch (registration_state_) {
1424 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1425 return flimflam::kRoamingStateHome;
1426 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1427 return flimflam::kRoamingStateRoaming;
1428 default:
1429 break;
1430 }
1431 return flimflam::kRoamingStateUnknown;
1432}
1433
1434void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -04001435 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
1436 const DBus::Struct<unsigned int, bool> quality =
1437 modem_proxy_->SignalQuality();
1438 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001439}
1440
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001441string CellularCapabilityUniversal::GetTypeString() const {
1442 return AccessTechnologyToTechnologyFamily(access_technologies_);
1443}
1444
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001445void CellularCapabilityUniversal::OnModemPropertiesChanged(
1446 const DBusPropertiesMap &properties,
1447 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001448 // This solves a bootstrapping problem: If the modem is not yet
1449 // enabled, there are no proxy objects associated with the capability
1450 // object, so modem signals like StateChanged aren't seen. By monitoring
1451 // changes to the State property via the ModemManager, we're able to
1452 // get the initialization process started, which will result in the
1453 // creation of the proxy objects.
1454 //
1455 // The first time we see the change to State (when the modem state
1456 // is Unknown), we simply update the state, and rely on the Manager to
1457 // enable the device when it is registered with the Manager. On subsequent
1458 // changes to State, we need to explicitly enable the device ourselves.
1459 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001460 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001461 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001462 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001463 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001464 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001465 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001466 MM_MODEM_PROPERTY_SIM, &string_value))
1467 OnSimPathChanged(string_value);
1468 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001469 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001470 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
1471 &uint_value))
1472 OnModemCapabilitesChanged(uint_value);
1473 if (DBusProperties::GetUint32(properties,
1474 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1475 &uint_value))
1476 OnModemCurrentCapabilitiesChanged(uint_value);
1477 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1478 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
1479 if (DBusProperties::GetString(properties,
1480 MM_MODEM_PROPERTY_MANUFACTURER,
1481 &string_value))
1482 OnModemManufacturerChanged(string_value);
1483 if (DBusProperties::GetString(properties,
1484 MM_MODEM_PROPERTY_MODEL,
1485 &string_value))
1486 OnModemModelChanged(string_value);
1487 if (DBusProperties::GetString(properties,
1488 MM_MODEM_PROPERTY_REVISION,
1489 &string_value))
1490 OnModemRevisionChanged(string_value);
1491 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1492 // not needed: MM_MODEM_PROPERTY_DEVICE
1493 // not needed: MM_MODEM_PROPERTY_DRIVER
1494 // not needed: MM_MODEM_PROPERTY_PLUGIN
1495 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001496
Jason Glasgowaf583282012-04-18 15:18:22 -04001497 // Unlock required and SimLock
1498 bool locks_changed = false;
1499 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001500 if (DBusProperties::GetUint32(properties,
1501 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -04001502 &unlock_required)) {
1503 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001504 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001505 LockRetryData lock_retries;
1506 DBusPropertiesMap::const_iterator it =
1507 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
1508 if (it != properties.end()) {
mukesh agrawal42457712013-04-05 16:05:39 -07001509 lock_retries = it->second.operator LockRetryData();
Jason Glasgowaf583282012-04-18 15:18:22 -04001510 locks_changed = true;
1511 }
1512 if (locks_changed)
1513 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
1514 lock_retries);
1515 if (DBusProperties::GetUint32(properties,
1516 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1517 &uint_value))
1518 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001519
Jason Glasgowaf583282012-04-18 15:18:22 -04001520 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1521 if (it != properties.end()) {
1522 DBus::Struct<unsigned int, bool> quality = it->second;
1523 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001524 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001525 vector<string> numbers;
1526 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1527 &numbers)) {
1528 string mdn;
1529 if (numbers.size() > 0)
1530 mdn = numbers[0];
1531 OnMdnChanged(mdn);
1532 }
1533 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
1534 &uint_value))
1535 OnSupportedModesChanged(uint_value);
1536 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
1537 &uint_value))
1538 OnAllowedModesChanged(uint_value);
1539 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
1540 &uint_value))
1541 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
1542 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1543 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001544}
1545
1546void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1547 const string &interface,
1548 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001549 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001550 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001551 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001552 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001553 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001554 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1555 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001556 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001557 if (interface == MM_DBUS_INTERFACE_SIM) {
1558 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001559 }
1560}
1561
Jason Glasgow14521872012-05-07 19:12:15 -04001562bool CellularCapabilityUniversal::RetriableConnectError(
1563 const Error &error) const {
1564 if (error.type() == Error::kInvalidApn)
1565 return true;
1566
1567 // modemmanager does not ever return kInvalidApn for E362 modems
1568 // with 1.41 firmware. It remains to be seem if this will change
1569 // with 3.x firmware.
1570 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1571 return true;
1572
1573 return false;
1574}
1575
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001576void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1577 // TODO(petkov): Implement this.
1578 NOTIMPLEMENTED();
1579}
1580
Arman Uguray6552f8c2013-02-12 15:33:18 -08001581bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1582 return !sim_path.empty() && sim_path != kRootPath;
1583}
1584
Ben Chand7592522013-02-13 16:02:01 -08001585string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1586 string normalized_mdn;
1587 for (size_t i = 0; i < mdn.size(); ++i) {
1588 if (IsAsciiDigit(mdn[i]))
1589 normalized_mdn += mdn[i];
1590 }
1591 return normalized_mdn;
1592}
1593
Jason Glasgowaf583282012-04-18 15:18:22 -04001594void CellularCapabilityUniversal::OnSimPathChanged(
1595 const string &sim_path) {
1596 if (sim_path == sim_path_)
1597 return;
1598
1599 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001600 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001601 proxy = proxy_factory()->CreateSimProxy(sim_path,
1602 cellular()->dbus_owner());
1603 sim_path_ = sim_path;
1604 sim_proxy_.reset(proxy);
1605
Arman Uguray6552f8c2013-02-12 15:33:18 -08001606 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001607 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001608 imsi_ = "";
1609 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001610 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001611 OnSimIdentifierChanged("");
1612 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001613 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001614 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001615 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1616 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1617 cellular()->dbus_owner()));
1618 // TODO(jglasgow): convert to async interface
1619 DBusPropertiesMap properties(
1620 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1621 OnSimPropertiesChanged(properties, vector<string>());
1622 }
1623}
1624
1625void CellularCapabilityUniversal::OnModemCapabilitesChanged(
1626 uint32 capabilities) {
1627 capabilities_ = capabilities;
1628}
1629
1630void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1631 uint32 current_capabilities) {
1632 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001633
1634 // Only allow network scan when the modem's current capabilities support
1635 // GSM/UMTS.
1636 //
1637 // TODO(benchan): We should consider having the modem plugins in ModemManager
1638 // reporting whether network scan is supported.
1639 scanning_supported_ =
1640 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1641 if (cellular()->adaptor()) {
1642 cellular()->adaptor()->EmitBoolChanged(
1643 flimflam::kSupportNetworkScanProperty, scanning_supported_);
1644 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001645}
1646
1647void CellularCapabilityUniversal::OnMdnChanged(
1648 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001649 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001650 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001651}
1652
1653void CellularCapabilityUniversal::OnModemManufacturerChanged(
1654 const string &manufacturer) {
1655 manufacturer_ = manufacturer;
1656}
1657
1658void CellularCapabilityUniversal::OnModemModelChanged(
1659 const string &model) {
1660 model_id_ = model;
1661}
1662
1663void CellularCapabilityUniversal::OnModemRevisionChanged(
1664 const string &revision) {
1665 firmware_revision_ = revision;
1666}
1667
1668void CellularCapabilityUniversal::OnModemStateChanged(
1669 Cellular::ModemState state) {
1670 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1671 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1672 if (Cellular::IsEnabledModemState(state))
1673 cellular()->set_modem_state(state);
Gary Moraine285a842012-08-15 08:23:57 -07001674 SLOG(Cellular, 2) << __func__ << ": prev_modem_state: " << prev_modem_state
1675 << " was_enabled: " << was_enabled
1676 << " cellular state: "
1677 << cellular()->GetStateString(cellular()->state());
Jason Glasgowaf583282012-04-18 15:18:22 -04001678 if (prev_modem_state != Cellular::kModemStateUnknown &&
1679 prev_modem_state != Cellular::kModemStateEnabling &&
1680 !was_enabled &&
1681 cellular()->state() == Cellular::kStateDisabled &&
1682 cellular()->IsUnderlyingDeviceEnabled()) {
1683 cellular()->SetEnabled(true);
1684 }
Ben Chan8a2c01e2013-01-23 10:09:14 -08001685 UpdateScanningProperty();
Jason Glasgowaf583282012-04-18 15:18:22 -04001686}
1687
1688void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1689 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001690 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001691 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001692 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001693 const string new_type_string(GetTypeString());
1694 if (new_type_string != old_type_string) {
1695 // TODO(jglasgow): address layering violation of emitting change
1696 // signal here for a property owned by Cellular.
1697 cellular()->adaptor()->EmitStringChanged(
1698 flimflam::kTechnologyFamilyProperty, new_type_string);
1699 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001700 if (cellular()->service().get()) {
1701 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1702 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001703 }
1704}
1705
1706void CellularCapabilityUniversal::OnSupportedModesChanged(
1707 uint32 supported_modes) {
1708 supported_modes_ = supported_modes;
1709}
1710
1711void CellularCapabilityUniversal::OnAllowedModesChanged(
1712 uint32 allowed_modes) {
1713 allowed_modes_ = allowed_modes;
1714}
1715
1716void CellularCapabilityUniversal::OnPreferredModeChanged(
1717 MMModemMode preferred_mode) {
1718 preferred_mode_ = preferred_mode;
1719}
1720
1721void CellularCapabilityUniversal::OnLockRetriesChanged(
1722 MMModemLock unlock_required,
1723 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001724 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001725 case MM_MODEM_LOCK_SIM_PIN:
1726 sim_lock_status_.lock_type = "sim-pin";
1727 break;
1728 case MM_MODEM_LOCK_SIM_PUK:
1729 sim_lock_status_.lock_type = "sim-puk";
1730 break;
1731 default:
1732 sim_lock_status_.lock_type = "";
1733 break;
1734 }
1735 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1736 if (it != lock_retries.end()) {
1737 sim_lock_status_.retries_left = it->second;
1738 } else {
1739 // Unknown, use 999
1740 sim_lock_status_.retries_left = 999;
1741 }
1742 OnSimLockStatusChanged();
1743}
1744
1745void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1746 cellular()->adaptor()->EmitKeyValueStoreChanged(
1747 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001748
1749 // If the SIM is currently unlocked, assume that we need to refresh
1750 // carrier information, since a locked SIM prevents shill from obtaining
1751 // the necessary data to establish a connection later (e.g. IMSI).
1752 if (!sim_path_.empty() && sim_lock_status_.lock_type.empty()) {
1753 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1754 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1755 cellular()->dbus_owner()));
1756 DBusPropertiesMap properties(
1757 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1758 OnSimPropertiesChanged(properties, vector<string>());
1759 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001760}
1761
1762void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1763 const DBusPropertiesMap &properties,
1764 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001765 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001766 string imei;
1767 if (DBusProperties::GetString(properties,
1768 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1769 &imei))
1770 OnImeiChanged(imei);
1771
1772 // Handle registration state changes as a single change
1773 string operator_code = serving_operator_.GetCode();
1774 string operator_name = serving_operator_.GetName();
1775 MMModem3gppRegistrationState state = registration_state_;
1776 bool registration_changed = false;
1777 uint32 uint_value;
1778 if (DBusProperties::GetUint32(properties,
1779 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1780 &uint_value)) {
1781 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1782 registration_changed = true;
1783 }
1784 if (DBusProperties::GetString(properties,
1785 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1786 &operator_code))
1787 registration_changed = true;
1788 if (DBusProperties::GetString(properties,
1789 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1790 &operator_name))
1791 registration_changed = true;
1792 if (registration_changed)
1793 On3GPPRegistrationChanged(state, operator_code, operator_name);
1794
1795 uint32 locks = 0;
1796 if (DBusProperties::GetUint32(
1797 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1798 &locks))
1799 OnFacilityLocksChanged(locks);
1800}
1801
1802void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1803 imei_ = imei;
1804}
1805
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001806void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1807 MMModem3gppRegistrationState state,
1808 const string &operator_code,
1809 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001810 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1811 << ", opercode=" << operator_code
1812 << ", opername=" << operator_name;
Prathmesh Prabhu8f6479f2013-05-15 12:56:13 -07001813
1814 // While the modem is connected, if the state changed from a registered state
1815 // to a non registered state, defer the state change by 15 seconds.
1816 // TODO(pprabhu) [crbug.com/241231] Add UMA stat to determine whether this
1817 // condition is specific to E362. If it is, guard the delayed update by E362
1818 // specific flag.
1819 if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1820 IsRegistered() && !IsRegisteredState(state)) {
1821 if (!registration_dropped_update_callback_.IsCancelled()) {
1822 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1823 << "Ignoring earlier notifications.";
1824 registration_dropped_update_callback_.Cancel();
1825 }
1826 SLOG(Cellular, 2) << "Posted deferred registration state update";
1827 registration_dropped_update_callback_.Reset(
1828 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1829 weak_ptr_factory_.GetWeakPtr(),
1830 state,
1831 operator_code,
1832 operator_name));
1833 cellular()->dispatcher()->PostDelayedTask(
1834 registration_dropped_update_callback_.callback(),
1835 registration_dropped_update_timeout_milliseconds_);
1836 } else {
1837 if (!registration_dropped_update_callback_.IsCancelled()) {
1838 SLOG(Cellular, 2) << "Cancelled a deferred registration state update";
1839 registration_dropped_update_callback_.Cancel();
1840 }
1841 Handle3GPPRegistrationChange(state, operator_code, operator_name);
1842 }
1843}
1844
1845void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1846 MMModem3gppRegistrationState updated_state,
1847 string updated_operator_code,
1848 string updated_operator_name) {
1849 // A finished callback does not qualify as a canceled callback.
1850 // We test for a canceled callback to check for outstanding callbacks.
1851 // So, explicitly cancel the callback here.
1852 registration_dropped_update_callback_.Cancel();
1853
1854 SLOG(Cellular, 2) << __func__ << ": regstate=" << updated_state
1855 << ", opercode=" << updated_operator_code
1856 << ", opername=" << updated_operator_name;
1857
1858 registration_state_ = updated_state;
1859 serving_operator_.SetCode(updated_operator_code);
1860 serving_operator_.SetName(updated_operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001861
1862 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001863 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08001864
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001865 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001866
1867 // Update the user facing name of the cellular service.
1868 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08001869
1870 // If the modem registered with the network and the current ICCID is pending
1871 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001872 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001873}
1874
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001875void CellularCapabilityUniversal::OnModemStateChangedSignal(
1876 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001877 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1878 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001879 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1880 static_cast<Cellular::ModemState>(new_state),
1881 reason);
Ben Chan2e12ccd2013-01-24 15:24:27 -08001882 UpdateScanningProperty();
Gary Moraine285a842012-08-15 08:23:57 -07001883 if (!deferred_enable_modem_callback_.is_null() &&
1884 (new_state == Cellular::kModemStateDisabled)) {
1885 SLOG(Cellular, 2) << "Enabling modem after deferring";
1886 deferred_enable_modem_callback_.Run();
1887 deferred_enable_modem_callback_.Reset();
Arman Uguray6e5639f2012-11-15 20:30:19 -08001888 } else if (new_state == Cellular::kModemStateConnected) {
1889 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1890 UpdateBearerPath();
Gary Moraine285a842012-08-15 08:23:57 -07001891 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001892}
1893
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001894void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1895 cellular()->HandleNewSignalQuality(quality);
1896}
1897
Jason Glasgowaf583282012-04-18 15:18:22 -04001898void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1899 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1900 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1901 OnSimLockStatusChanged();
1902 }
1903}
Jason Glasgowef965562012-04-10 16:12:35 -04001904
Jason Glasgowaf583282012-04-18 15:18:22 -04001905void CellularCapabilityUniversal::OnSimPropertiesChanged(
1906 const DBusPropertiesMap &props,
1907 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001908 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001909 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001910 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1911 OnSimIdentifierChanged(value);
1912 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1913 &value))
1914 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001915 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1916 OnSpnChanged(value);
1917 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
1918 OnImsiChanged(value);
1919 SetHomeProvider();
1920}
Jason Glasgowaf583282012-04-18 15:18:22 -04001921
Arman Ugurayd73783f2013-01-31 16:11:21 -08001922// TODO(armansito): The following methods should probably log their argument
1923// values. Need to learn if any of them need to be scrubbed.
1924void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
1925 imsi_ = imsi;
1926}
1927
1928void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1929 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04001930}
1931
1932void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1933 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08001934 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001935}
1936
1937void CellularCapabilityUniversal::OnOperatorIdChanged(
1938 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001939 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04001940 operator_id_ = operator_id;
1941}
1942
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001943} // namespace shill