blob: 0625195a843bb1b2f8f9311d09d709cc70c3ab0a [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
Arman Uguray1361c032013-02-11 17:53:39 -080056CellularCapabilityUniversal::kDefaultScanningOrSearchingTimeoutMilliseconds =
57 60000;
Arman Uguraya14941d2013-04-12 16:58:26 -070058const int64
59CellularCapabilityUniversal::kActivationRegistrationTimeoutMilliseconds =
60 20000;
Arman Uguray2717a102013-01-29 23:36:06 -080061const char CellularCapabilityUniversal::kGenericServiceNamePrefix[] =
62 "Mobile Network";
Arman Uguray6552f8c2013-02-12 15:33:18 -080063const char CellularCapabilityUniversal::kRootPath[] = "/";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040064const char CellularCapabilityUniversal::kStatusProperty[] = "status";
65const char CellularCapabilityUniversal::kOperatorLongProperty[] =
66 "operator-long";
67const char CellularCapabilityUniversal::kOperatorShortProperty[] =
68 "operator-short";
69const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
70 "operator-code";
71const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
72 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040073const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
Thieu Le2cac2942013-03-05 18:41:08 -080074const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
75 20000;
Jason Glasgow14521872012-05-07 19:12:15 -040076unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
77
Jason Glasgow82f9ab32012-04-04 14:27:19 -040078
79static const char kPhoneNumber[] = "*99#";
80
81static string AccessTechnologyToString(uint32 access_technologies) {
82 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
83 return flimflam::kNetworkTechnologyLte;
84 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
85 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
86 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
87 return flimflam::kNetworkTechnologyEvdo;
88 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
89 return flimflam::kNetworkTechnology1Xrtt;
90 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
91 return flimflam::kNetworkTechnologyHspaPlus;
92 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
93 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
94 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
95 return flimflam::kNetworkTechnologyHspa;
96 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
97 return flimflam::kNetworkTechnologyUmts;
98 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
99 return flimflam::kNetworkTechnologyEdge;
100 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
101 return flimflam::kNetworkTechnologyGprs;
102 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
103 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
104 return flimflam::kNetworkTechnologyGsm;
105 return "";
106}
107
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400108static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
109 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
110 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
111 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
112 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
113 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
114 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
115 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
116 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
117 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
118 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
119 return flimflam::kTechnologyFamilyGsm;
120 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800121 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
122 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400123 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
124 return flimflam::kTechnologyFamilyCdma;
125 return "";
126}
127
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400128CellularCapabilityUniversal::CellularCapabilityUniversal(
129 Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -0800130 ProxyFactory *proxy_factory,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700131 ModemInfo *modem_info)
132 : CellularCapability(cellular, proxy_factory, modem_info),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400133 weak_ptr_factory_(this),
134 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200135 capabilities_(MM_MODEM_CAPABILITY_NONE),
136 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400137 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400138 supported_modes_(MM_MODEM_MODE_NONE),
139 allowed_modes_(MM_MODEM_MODE_NONE),
140 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400141 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200142 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800143 resetting_(false),
Ben Chanfcca27b2013-01-22 15:03:44 -0800144 scanning_supported_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400145 scanning_(false),
Ben Chan8a2c01e2013-01-23 10:09:14 -0800146 scanning_or_searching_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700147 scan_interval_(0),
Arman Uguray1361c032013-02-11 17:53:39 -0800148 sim_present_(false),
Arman Ugurayc7b15602013-02-16 00:56:18 -0800149 reset_done_(false),
Arman Uguray1361c032013-02-11 17:53:39 -0800150 scanning_or_searching_timeout_milliseconds_(
Arman Uguraya14941d2013-04-12 16:58:26 -0700151 kDefaultScanningOrSearchingTimeoutMilliseconds),
152 activation_registration_timeout_milliseconds_(
153 kActivationRegistrationTimeoutMilliseconds) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700154 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400155 PropertyStore *store = cellular->mutable_store();
156
157 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
158 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
159 &scanning_supported_);
160 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
161 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
162 &firmware_revision_);
163 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
164 &hardware_revision_);
165 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
166 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700167 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400168 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
169 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
170 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
171 store->RegisterConstString(flimflam::kMinProperty, &min_);
172 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
173 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
174 &selected_network_);
175 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
176 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +0200177 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
178 &provider_requires_roaming_);
Ben Chan8a2c01e2013-01-23 10:09:14 -0800179 store->RegisterConstBool(flimflam::kScanningProperty,
180 &scanning_or_searching_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400181 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700182 HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400183 flimflam::kSIMLockStatusProperty,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700184 &CellularCapabilityUniversal::SimLockStatusToProperty);
Thieu Le550247c2013-04-30 17:16:43 -0700185 store->RegisterConstString(shill::kSIMOperatorIdProperty, &operator_id_);
Ben Chanbd3aee82012-10-16 23:52:04 -0700186 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400187 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
188 &apn_list_);
189}
190
191KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
192 Error */*error*/) {
193 KeyValueStore status;
194 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
195 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
196 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
197 sim_lock_status_.retries_left);
198 return status;
199}
200
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700201void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400202 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700203 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error)) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400204 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
205 name,
206 KeyValueStoreAccessor(
207 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700208 this, get, NULL)));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400209}
210
211void CellularCapabilityUniversal::InitProxies() {
212 modem_3gpp_proxy_.reset(
213 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
214 cellular()->dbus_owner()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400215 modem_proxy_.reset(
216 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
217 cellular()->dbus_owner()));
218 modem_simple_proxy_.reset(
219 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
220 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800221
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400222 modem_proxy_->set_state_changed_callback(
223 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
224 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400225 // Do not create a SIM proxy until the device is enabled because we
226 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400227 // TODO(jglasgow): register callbacks
228}
229
230void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400231 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700232 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400233 InitProxies();
234
Gary Moraine285a842012-08-15 08:23:57 -0700235 // ModemManager must be in the disabled state to accept the Enable command.
236 Cellular::ModemState state =
237 static_cast<Cellular::ModemState>(modem_proxy_->State());
238 if (state == Cellular::kModemStateDisabled) {
239 EnableModem(error, callback);
240 } else if (!cellular()->IsUnderlyingDeviceEnabled()) {
241 SLOG(Cellular, 2) << "Enabling of modem deferred because state is "
242 << state;
243 deferred_enable_modem_callback_ =
244 Bind(&CellularCapabilityUniversal::EnableModem,
245 weak_ptr_factory_.GetWeakPtr(), static_cast<Error *>(NULL),
246 callback);
247 } else {
Thieu Leb9c05e02013-03-04 14:09:32 -0800248 // This request cannot be completed synchronously here because a method
249 // reply requires a continuation tag that is not created until the message
250 // handler returns, see DBus-C++ ObjectAdapter::handle_message().
251 cellular()->dispatcher()->PostTask(
252 Bind(&CellularCapabilityUniversal::Start_ModemAlreadyEnabled,
253 weak_ptr_factory_.GetWeakPtr(), callback));
Gary Moraine285a842012-08-15 08:23:57 -0700254 }
255}
256
257void CellularCapabilityUniversal::EnableModem(Error *error,
258 const ResultCallback &callback) {
259 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400260 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700261 Error local_error(Error::kOperationInitiated);
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700262 modem_info()->metrics()->NotifyDeviceEnableStarted(
263 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400264 modem_proxy_->Enable(
265 true,
Gary Moraine285a842012-08-15 08:23:57 -0700266 &local_error,
Jason Glasgowef965562012-04-10 16:12:35 -0400267 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
268 weak_ptr_factory_.GetWeakPtr(), callback),
269 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700270 if (local_error.IsFailure()) {
271 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
Gary Moraine285a842012-08-15 08:23:57 -0700272 }
273 if (error) {
274 error->CopyFrom(local_error);
275 }
Jason Glasgowef965562012-04-10 16:12:35 -0400276}
277
Thieu Leb9c05e02013-03-04 14:09:32 -0800278void CellularCapabilityUniversal::Start_ModemAlreadyEnabled(
279 const ResultCallback &callback) {
280 // Call GetProperties() here to sync up with the modem state
281 GetProperties();
282 callback.Run(Error());
283}
284
Jason Glasgowef965562012-04-10 16:12:35 -0400285void CellularCapabilityUniversal::Start_EnableModemCompleted(
286 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400287 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400288 if (error.IsFailure()) {
289 callback.Run(error);
290 return;
291 }
292
293 // After modem is enabled, it should be possible to get properties
294 // TODO(jglasgow): handle errors from GetProperties
295 GetProperties();
Thieu Le18c11072013-01-28 17:21:37 -0800296 // We expect the modem to start scanning after it has been enabled.
297 // Change this if this behavior is no longer the case in the future.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700298 modem_info()->metrics()->NotifyDeviceEnableFinished(
299 cellular()->interface_index());
300 modem_info()->metrics()->NotifyDeviceScanStarted(
301 cellular()->interface_index());
Thieu Le18c11072013-01-28 17:21:37 -0800302 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400303}
304
305void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400306 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400307 CHECK(!callback.is_null());
308 CHECK(error);
Thieu Led0012052012-07-25 16:09:09 -0700309 Cellular::ModemState state = cellular()->modem_state();
310 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400311
Thieu Led0012052012-07-25 16:09:09 -0700312 if (cellular()->IsModemRegistered()) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400313 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400314 modem_simple_proxy_->Disconnect(
315 all_bearers,
316 error,
317 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
318 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le049adb52012-11-12 17:14:51 -0800319 kTimeoutDisconnect);
Jason Glasgowef965562012-04-10 16:12:35 -0400320 if (error->IsFailure())
321 callback.Run(*error);
322 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400323 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
324 weak_ptr_factory_.GetWeakPtr(),
325 callback);
326 cellular()->dispatcher()->PostTask(task);
327 }
Gary Moraine285a842012-08-15 08:23:57 -0700328 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400329}
330
331void CellularCapabilityUniversal::Stop_DisconnectCompleted(
332 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700333 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400334
335 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
336 Stop_Disable(callback);
337}
338
339void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
340 Error error;
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700341 modem_info()->metrics()->NotifyDeviceDisableStarted(
342 cellular()->interface_index());
Jason Glasgowef965562012-04-10 16:12:35 -0400343 modem_proxy_->Enable(
344 false, &error,
345 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
346 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400347 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400348 if (error.IsFailure())
349 callback.Run(error);
350}
351
352void CellularCapabilityUniversal::Stop_DisableCompleted(
353 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700354 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400355
Thieu Lea2519bf2013-01-23 16:51:54 -0800356 if (error.IsSuccess()) {
Arman Ugurayee464d32013-02-13 17:14:36 -0800357 // The modem has been successfully disabled, but we still need to power it
358 // down.
359 Stop_PowerDown(callback);
360 } else {
361 // An error occurred; terminate the disable sequence.
362 callback.Run(error);
Thieu Lea2519bf2013-01-23 16:51:54 -0800363 }
Arman Ugurayee464d32013-02-13 17:14:36 -0800364}
365
366void CellularCapabilityUniversal::Stop_PowerDown(
367 const ResultCallback &callback) {
368 SLOG(Cellular, 2) << __func__;
369 Error error;
370 modem_proxy_->SetPowerState(
371 MM_MODEM_POWER_STATE_LOW,
372 &error,
373 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
374 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le2cac2942013-03-05 18:41:08 -0800375 kSetPowerStateTimeoutMilliseconds);
Arman Ugurayee464d32013-02-13 17:14:36 -0800376
377 if (error.IsFailure())
378 // This really shouldn't happen, but if it does, report success,
379 // because a stop initiated power down is only called if the
380 // modem was successfully disabled, but the failure of this
381 // operation should still be propagated up as a successful disable.
382 Stop_PowerDownCompleted(callback, error);
383}
384
385void CellularCapabilityUniversal::Stop_PowerDownCompleted(
386 const ResultCallback &callback,
387 const Error &error) {
388 SLOG(Cellular, 2) << __func__;
389
390 if (error.IsFailure())
391 SLOG(Cellular, 2) << "Ignoring error returned by SetPowerState: " << error;
392
393 // Since the disable succeeded, if power down fails, we currently fail
394 // silently, i.e. we need to report the disable operation as having
395 // succeeded.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700396 modem_info()->metrics()->NotifyDeviceDisableFinished(
397 cellular()->interface_index());
Arman Ugurayee464d32013-02-13 17:14:36 -0800398 ReleaseProxies();
399 callback.Run(Error());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400400}
401
402void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
403 Error *error,
404 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700405 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400406 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
407 weak_ptr_factory_.GetWeakPtr(),
408 callback);
409 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400410}
411
412void CellularCapabilityUniversal::Disconnect(Error *error,
413 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700414 SLOG(Cellular, 2) << __func__;
Thieu Le5d6864a2012-07-20 11:43:51 -0700415 if (bearer_path_.empty()) {
416 LOG(WARNING) << "In " << __func__ << "(): "
417 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700418 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700419 modem_simple_proxy_->Disconnect(bearer_path_,
420 error,
421 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800422 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700423 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400424}
425
Christopher Wiley8a468902012-11-30 11:52:38 -0800426void CellularCapabilityUniversal::DisconnectCleanup() {
427 SLOG(Cellular, 2) << __func__;
428}
429
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400430void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400431 Error *error,
432 const ResultCallback &callback) {
433 OnUnsupportedOperation(__func__, error);
434}
435
Arman Uguraya14941d2013-04-12 16:58:26 -0700436void CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout() {
437 SLOG(Cellular, 2) << __func__;
438 if (sim_identifier_.empty() ||
Arman Uguray41cc6342013-03-29 16:34:39 -0700439 modem_info()->pending_activation_store()->GetActivationState(
440 PendingActivationStore::kIdentifierICCID,
441 sim_identifier_) == PendingActivationStore::kStateActivated) {
Arman Uguraya14941d2013-04-12 16:58:26 -0700442 SLOG(Cellular, 2) << "Modem is already scheduled to be reset.";
443 return;
444 }
445 if (IsMdnValid()) {
446 SLOG(Cellular, 2) << "MDN is valid. Already activated.";
447 return;
448 }
449 if (reset_done_) {
450 SLOG(Cellular, 2) << "Already done with reset.";
451 return;
452 }
453
454 // Still not activated after timeout. Reset the modem.
455 SLOG(Cellular, 2) << "Still not registered after timeout. Reset directly "
456 << "to update MDN.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700457 modem_info()->pending_activation_store()->SetActivationState(
458 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700459 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700460 PendingActivationStore::kStatePendingTimeout);
Arman Uguraya14941d2013-04-12 16:58:26 -0700461 ResetAfterActivation();
462}
463
Arman Ugurayc7b15602013-02-16 00:56:18 -0800464void CellularCapabilityUniversal::CompleteActivation(Error *error) {
465 SLOG(Cellular, 2) << __func__;
466
467 // Persist the ICCID as "Pending Activation".
468 // We're assuming that when this function gets called, |sim_identifier_| will
469 // be non-empty. We still check here that is non-empty, though something is
470 // wrong if it is empty.
471 if (IsMdnValid()) {
472 SLOG(Cellular, 2) << "Already acquired a valid MDN. Already activated.";
473 return;
474 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800475
Arman Ugurayc7b15602013-02-16 00:56:18 -0800476 if (sim_identifier_.empty()) {
477 SLOG(Cellular, 2) << "SIM identifier not available. Nothing to do.";
478 return;
479 }
Arman Ugurayefea6e02013-02-21 13:28:04 -0800480
481 // There should be a cellular service at this point.
482 if (cellular()->service().get())
483 cellular()->service()->SetActivationState(
484 flimflam::kActivationStateActivating);
Arman Uguray41cc6342013-03-29 16:34:39 -0700485 modem_info()->pending_activation_store()->SetActivationState(
486 PendingActivationStore::kIdentifierICCID,
Arman Ugurayc7b15602013-02-16 00:56:18 -0800487 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700488 PendingActivationStore::kStatePending);
Arman Uguraya14941d2013-04-12 16:58:26 -0700489
490 activation_wait_for_registration_callback_.Reset(
491 Bind(&CellularCapabilityUniversal::OnActivationWaitForRegisterTimeout,
492 weak_ptr_factory_.GetWeakPtr()));
493 cellular()->dispatcher()->PostDelayedTask(
494 activation_wait_for_registration_callback_.callback(),
495 activation_registration_timeout_milliseconds_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800496}
497
498void CellularCapabilityUniversal::ResetAfterActivation() {
499 SLOG(Cellular, 2) << __func__;
500
501 // Here the initial call to Reset might fail in rare cases. Simply ignore.
502 Error error;
503 ResultCallback callback = Bind(
504 &CellularCapabilityUniversal::OnResetAfterActivationReply,
505 weak_ptr_factory_.GetWeakPtr());
506 Reset(&error, callback);
507 if (error.IsFailure())
508 SLOG(Cellular, 2) << "Failed to reset after activation.";
509}
510
511void CellularCapabilityUniversal::OnResetAfterActivationReply(
512 const Error &error) {
513 SLOG(Cellular, 2) << __func__;
514 if (error.IsFailure()) {
515 SLOG(Cellular, 2) << "Failed to reset after activation. Try again later.";
516 // TODO(armansito): Maybe post a delayed reset task?
517 return;
518 }
519 reset_done_ = true;
Arman Uguraya14941d2013-04-12 16:58:26 -0700520 activation_wait_for_registration_callback_.Cancel();
Arman Uguray0a3e2792013-01-17 16:31:50 -0800521 UpdatePendingActivationState();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800522}
523
Arman Uguray0a3e2792013-01-17 16:31:50 -0800524void CellularCapabilityUniversal::UpdatePendingActivationState() {
Arman Ugurayc7b15602013-02-16 00:56:18 -0800525 SLOG(Cellular, 2) << __func__;
526
527 bool registered =
528 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
529
530 // If we have a valid MDN, the service is activated. Always try to remove
531 // the ICCID from persistence.
532 bool got_mdn = IsMdnValid();
533 if (got_mdn && !sim_identifier_.empty())
Arman Uguray41cc6342013-03-29 16:34:39 -0700534 modem_info()->pending_activation_store()->RemoveEntry(
535 PendingActivationStore::kIdentifierICCID,
536 sim_identifier_);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800537
Arman Ugurayefea6e02013-02-21 13:28:04 -0800538 CellularServiceRefPtr service = cellular()->service();
539
540 if (!service.get())
541 return;
542
543 if (service->activation_state() == flimflam::kActivationStateActivated)
Arman Ugurayc7b15602013-02-16 00:56:18 -0800544 // Either no service or already activated. Nothing to do.
545 return;
546
547 // If we have a valid MDN or we can connect to the network, then the service
548 // is activated.
549 if (got_mdn || cellular()->state() == Cellular::kStateConnected ||
550 cellular()->state() == Cellular::kStateLinked) {
551 SLOG(Cellular, 2) << "Marking service as activated.";
Arman Ugurayefea6e02013-02-21 13:28:04 -0800552 service->SetActivationState(flimflam::kActivationStateActivated);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800553 return;
554 }
555
556 // If the ICCID is not available, the following logic can be delayed until it
557 // becomes available.
Arman Ugurayefea6e02013-02-21 13:28:04 -0800558 if (sim_identifier_.empty())
559 return;
560
Arman Uguray41cc6342013-03-29 16:34:39 -0700561 PendingActivationStore::State state =
562 modem_info()->pending_activation_store()->GetActivationState(
563 PendingActivationStore::kIdentifierICCID,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700564 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800565 switch (state) {
Arman Uguray41cc6342013-03-29 16:34:39 -0700566 case PendingActivationStore::kStatePending:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800567 // Always mark the service as activating here, as the ICCID could have
568 // been unavailable earlier.
569 service->SetActivationState(flimflam::kActivationStateActivating);
570 if (reset_done_) {
571 SLOG(Cellular, 2) << "Post-payment activation reset complete.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700572 modem_info()->pending_activation_store()->SetActivationState(
573 PendingActivationStore::kIdentifierICCID,
Arman Ugurayefea6e02013-02-21 13:28:04 -0800574 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700575 PendingActivationStore::kStateActivated);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800576 } else if (registered) {
577 SLOG(Cellular, 2) << "Resetting modem for activation.";
Arman Uguraya14941d2013-04-12 16:58:26 -0700578 activation_wait_for_registration_callback_.Cancel();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800579 ResetAfterActivation();
580 }
581 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700582 case PendingActivationStore::kStateActivated:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800583 if (registered) {
584 // Trigger auto connect here.
585 SLOG(Cellular, 2) << "Modem has been reset at least once, try to "
586 << "autoconnect to force MDN to update.";
587 service->AutoConnect();
588 }
589 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700590 case PendingActivationStore::kStatePendingTimeout:
Arman Uguraya14941d2013-04-12 16:58:26 -0700591 SLOG(Cellular, 2) << "Modem failed to register within timeout, but has "
592 << "been reset at least once.";
593 if (registered) {
594 SLOG(Cellular, 2) << "Registered to network, marking as activated.";
Arman Uguray41cc6342013-03-29 16:34:39 -0700595 modem_info()->pending_activation_store()->SetActivationState(
596 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700597 sim_identifier_,
Arman Uguray41cc6342013-03-29 16:34:39 -0700598 PendingActivationStore::kStateActivated);
Arman Uguraya14941d2013-04-12 16:58:26 -0700599 service->SetActivationState(flimflam::kActivationStateActivated);
600 }
601 break;
Arman Uguray41cc6342013-03-29 16:34:39 -0700602 case PendingActivationStore::kStateUnknown:
Arman Ugurayefea6e02013-02-21 13:28:04 -0800603 // No entry exists for this ICCID. Nothing to do.
604 break;
605 default:
606 NOTREACHED();
Arman Ugurayc7b15602013-02-16 00:56:18 -0800607 }
608}
609
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400610void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700611 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400612 modem_3gpp_proxy_.reset();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400613 modem_proxy_.reset();
614 modem_simple_proxy_.reset();
615 sim_proxy_.reset();
616}
617
Arman Ugurayc9533572013-01-22 17:34:20 -0800618void CellularCapabilityUniversal::UpdateStorageIdentifier() {
619 if (!cellular()->service().get())
620 return;
621
622 // Lookup the unique identifier assigned to the current network and base the
623 // service's storage identifier on it.
624 const string prefix = "cellular_" + cellular()->address() + "_";
625 string storage_id;
626 if (!operator_id_.empty()) {
627 const CellularOperatorInfo::CellularOperator *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700628 modem_info()->cellular_operator_info()->GetCellularOperatorByMCCMNC(
629 operator_id_);
Arman Ugurayc9533572013-01-22 17:34:20 -0800630 if (provider && !provider->identifier().empty()) {
631 storage_id = prefix + provider->identifier();
632 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400633 }
Arman Ugurayc9533572013-01-22 17:34:20 -0800634 // If the above didn't work, append IMSI, if available.
635 if (storage_id.empty() && !imsi_.empty()) {
636 storage_id = prefix + imsi_;
637 }
638 if (!storage_id.empty()) {
639 cellular()->service()->SetStorageIdentifier(storage_id);
640 }
641}
642
Arman Ugurayefea6e02013-02-21 13:28:04 -0800643void CellularCapabilityUniversal::UpdateServiceActivationState() {
644 if (!cellular()->service().get())
645 return;
Ben Chan3d6de0e2012-12-10 12:01:34 -0800646 bool activation_required = IsServiceActivationRequired();
Arman Ugurayefea6e02013-02-21 13:28:04 -0800647 string activation_state = flimflam::kActivationStateActivated;
Arman Uguray41cc6342013-03-29 16:34:39 -0700648 PendingActivationStore::State state =
649 modem_info()->pending_activation_store()->GetActivationState(
650 PendingActivationStore::kIdentifierICCID,
Arman Uguraya14941d2013-04-12 16:58:26 -0700651 sim_identifier_);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800652 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -0700653 (state == PendingActivationStore::kStatePending ||
654 state == PendingActivationStore::kStatePendingTimeout))
Arman Ugurayefea6e02013-02-21 13:28:04 -0800655 activation_state = flimflam::kActivationStateActivating;
656 else if (activation_required)
657 activation_state = flimflam::kActivationStateNotActivated;
658 cellular()->service()->SetActivationState(activation_state);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800659 // TODO(benchan): For now, assume the cellular service is activated over
660 // a non-cellular network if service activation is required (i.e. a
661 // corresponding entry is found in the cellular operator info file).
662 // We will need to generalize this logic when migrating CDMA support from
663 // cromo to ModemManager.
664 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Arman Ugurayefea6e02013-02-21 13:28:04 -0800665}
666
667void CellularCapabilityUniversal::OnServiceCreated() {
668 UpdateStorageIdentifier();
669 UpdateServiceActivationState();
Ben Chane1e1e562013-01-26 00:39:01 -0800670 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400671 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800672 UpdateOLP();
Thieu Le398b1da2013-03-11 17:31:10 -0700673
674 // WORKAROUND:
675 // E362 modems on Verizon network does not properly redirect when a SIM
676 // runs out of credits, we need to enforce out-of-credits detection.
677 // TODO(thieule): Remove this workaround (crosbug.com/p/18619).
678 if (model_id_ == kE362ModelId)
679 cellular()->service()->set_enforce_out_of_credits_detection(true);
Arman Uguray7af0fac2013-03-18 17:35:35 -0700680
681 // Make sure that the network technology is set when the service gets
682 // created, just in case.
683 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400684}
685
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400686// Create the list of APNs to try, in the following order:
687// - last APN that resulted in a successful connection attempt on the
688// current network (if any)
689// - the APN, if any, that was set by the user
690// - the list of APNs found in the mobile broadband provider DB for the
691// home provider associated with the current SIM
692// - as a last resort, attempt to connect with no APN
693void CellularCapabilityUniversal::SetupApnTryList() {
694 apn_try_list_.clear();
695
696 DCHECK(cellular()->service().get());
697 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
698 if (apn_info)
699 apn_try_list_.push_back(*apn_info);
700
701 apn_info = cellular()->service()->GetUserSpecifiedApn();
702 if (apn_info)
703 apn_try_list_.push_back(*apn_info);
704
705 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
706}
707
708void CellularCapabilityUniversal::SetupConnectProperties(
709 DBusPropertiesMap *properties) {
710 SetupApnTryList();
711 FillConnectPropertyMap(properties);
712}
713
714void CellularCapabilityUniversal::FillConnectPropertyMap(
715 DBusPropertiesMap *properties) {
716
717 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400718 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400719 kPhoneNumber);
720
Jason Glasgow14521872012-05-07 19:12:15 -0400721 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400722 AllowRoaming());
723
724 if (!apn_try_list_.empty()) {
725 // Leave the APN at the front of the list, so that it can be recorded
726 // if the connect attempt succeeds.
727 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700728 SLOG(Cellular, 2) << __func__ << ": Using APN "
729 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400730 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400731 apn_info[flimflam::kApnProperty].c_str());
732 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400733 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400734 apn_info[flimflam::kApnUsernameProperty].c_str());
735 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400736 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400737 apn_info[flimflam::kApnPasswordProperty].c_str());
738 }
739}
740
741void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400742 const DBus::Path &path,
743 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700744 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400745
Jason Glasgow7234ec32012-05-23 16:01:21 -0400746 CellularServiceRefPtr service = cellular()->service();
747 if (!service) {
748 // The service could have been deleted before our Connect() request
749 // completes if the modem was enabled and then quickly disabled.
750 apn_try_list_.clear();
751 } else if (error.IsFailure()) {
752 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400753 // The APN that was just tried (and failed) is still at the
754 // front of the list, about to be removed. If the list is empty
755 // after that, try one last time without an APN. This may succeed
756 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400757 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400758 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700759 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
760 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400761 DBusPropertiesMap props;
762 FillConnectPropertyMap(&props);
763 Error error;
764 Connect(props, &error, callback);
765 return;
766 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400767 } else {
768 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400769 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400770 apn_try_list_.clear();
771 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400772 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400773 }
774
775 if (!callback.is_null())
776 callback.Run(error);
Arman Ugurayc7b15602013-02-16 00:56:18 -0800777
Arman Uguray0a3e2792013-01-17 16:31:50 -0800778 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400779}
780
781bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200782 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400783}
784
Arman Ugurayf84a4242013-04-09 20:01:07 -0700785bool CellularCapabilityUniversal::ShouldDetectOutOfCredit() const {
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700786 return model_id_ == kE362ModelId;
787}
788
Jason Glasgowef965562012-04-10 16:12:35 -0400789void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700790 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400791
Jason Glasgowaf583282012-04-18 15:18:22 -0400792 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
793 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
794 cellular()->dbus_owner()));
795 DBusPropertiesMap properties(
796 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
797 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400798
Jason Glasgowaf583282012-04-18 15:18:22 -0400799 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
800 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400801}
802
Arman Uguray2717a102013-01-29 23:36:06 -0800803// static
804string CellularCapabilityUniversal::GenerateNewGenericServiceName() {
805 return base::StringPrintf("%s %u",
806 kGenericServiceNamePrefix,
807 friendly_service_name_id_++);
808}
809
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400810string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200811 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800812
813 // If |serving_operator_| does not have an operator ID, call
814 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
815 if (serving_operator_.GetCode().empty()) {
816 UpdateOperatorInfo();
817 }
818
Darin Petkova4ca3c32012-08-17 16:05:24 +0200819 string name = serving_operator_.GetName();
820 string home_provider_name = cellular()->home_provider().GetName();
821 if (!name.empty()) {
822 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
823 // rules (TS 31.102 and annex A of 122.101).
824 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
825 !home_provider_name.empty()) {
826 return home_provider_name + " | " + name;
827 }
828 return name;
829 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400830 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200831 !home_provider_name.empty()) {
832 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400833 }
Arman Uguray2717a102013-01-29 23:36:06 -0800834 if (!serving_operator_.GetCode().empty()) {
835 return "cellular_" + serving_operator_.GetCode();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400836 }
Arman Uguray2717a102013-01-29 23:36:06 -0800837 return GenerateNewGenericServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400838}
839
840void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700841 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400842 << " SPN: " << spn_ << ")";
Arman Ugurayd73783f2013-01-31 16:11:21 -0800843
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700844 if (!modem_info()->provider_db())
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400845 return;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800846
847 // MCCMNC can be determined either from IMSI or Operator Code. Use whichever
848 // one is available. If both were reported by the SIM, use IMSI.
849 const string &network_id = imsi_.empty() ? operator_id_ : imsi_;
850 mobile_provider *provider = mobile_provider_lookup_best_match(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700851 modem_info()->provider_db(),
Arman Ugurayd73783f2013-01-31 16:11:21 -0800852 spn_.c_str(),
853 network_id.c_str());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400854 if (!provider) {
Arman Ugurayd73783f2013-01-31 16:11:21 -0800855 SLOG(Cellular, 2) << "3GPP provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400856 return;
857 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400858
859 // Even if provider is the same as home_provider_, it is possible
860 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400861 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200862 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400863 Cellular::Operator oper;
Arman Ugurayd73783f2013-01-31 16:11:21 -0800864 // If Operator ID is available, use that as network code, otherwise
865 // use what was returned from the database.
866 if (!operator_id_.empty()) {
867 oper.SetCode(operator_id_);
868 } else if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400869 oper.SetCode(provider->networks[0]);
870 }
871 if (provider->country) {
872 oper.SetCountry(provider->country);
873 }
874 if (spn_.empty()) {
875 const char *name = mobile_provider_get_name(provider);
876 if (name) {
877 oper.SetName(name);
878 }
879 } else {
880 oper.SetName(spn_);
881 }
882 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200883 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200884 << oper.GetName() << ", " << oper.GetCountry()
885 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400886 InitAPNList();
Arman Uguray2717a102013-01-29 23:36:06 -0800887 UpdateServiceName();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888}
889
Ben Chan8a2c01e2013-01-23 10:09:14 -0800890void CellularCapabilityUniversal::UpdateScanningProperty() {
891 // Set the Scanning property to true if there is a ongoing network scan
892 // (i.e. |scanning_| is true) or the modem is enabled but not yet registered
893 // to a network.
894 //
895 // TODO(benchan): As the Device DBus interface currently does not have a
896 // State property to indicate whether the device is being enabled, set the
897 // Scanning property to true when the modem is being enabled such that
898 // the network UI can start showing the initializing/scanning animation as
899 // soon as the modem is being enabled.
900 Cellular::ModemState modem_state = cellular()->modem_state();
Ben Chan40a2f862013-02-13 17:44:38 -0800901 bool is_activated_service_waiting_for_registration =
902 ((modem_state == Cellular::kModemStateEnabled ||
903 modem_state == Cellular::kModemStateSearching) &&
Ben Chane1e1e562013-01-26 00:39:01 -0800904 !IsServiceActivationRequired());
Ben Chan8a2c01e2013-01-23 10:09:14 -0800905 bool new_scanning_or_searching =
Ben Chan40a2f862013-02-13 17:44:38 -0800906 modem_state == Cellular::kModemStateEnabling ||
907 is_activated_service_waiting_for_registration ||
Ben Chan8a2c01e2013-01-23 10:09:14 -0800908 scanning_;
909 if (new_scanning_or_searching != scanning_or_searching_) {
910 scanning_or_searching_ = new_scanning_or_searching;
911 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
912 new_scanning_or_searching);
Arman Uguray1361c032013-02-11 17:53:39 -0800913
914 if (!scanning_or_searching_) {
915 SLOG(Cellular, 2) << "Initial network scan ended. Canceling timeout.";
916 scanning_or_searching_timeout_callback_.Cancel();
917 } else if (scanning_or_searching_timeout_callback_.IsCancelled()) {
918 SLOG(Cellular, 2) << "Initial network scan started. Starting timeout.";
919 scanning_or_searching_timeout_callback_.Reset(
920 Bind(&CellularCapabilityUniversal::OnScanningOrSearchingTimeout,
921 weak_ptr_factory_.GetWeakPtr()));
922 cellular()->dispatcher()->PostDelayedTask(
923 scanning_or_searching_timeout_callback_.callback(),
924 scanning_or_searching_timeout_milliseconds_);
925 }
Ben Chan8a2c01e2013-01-23 10:09:14 -0800926 }
927}
928
Arman Uguray1361c032013-02-11 17:53:39 -0800929void CellularCapabilityUniversal::OnScanningOrSearchingTimeout() {
930 SLOG(Cellular, 2) << "Initial network scan timed out. Changing "
931 << "flimflam::kScanningProperty to |false|.";
932 scanning_or_searching_ = false;
933 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty, false);
934}
935
Ben Chan6d0d1e72012-11-06 21:19:28 -0800936void CellularCapabilityUniversal::UpdateOLP() {
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700937 if (!modem_info()->cellular_operator_info())
Ben Chan6d0d1e72012-11-06 21:19:28 -0800938 return;
939
Arman Ugurayf4c61812013-01-10 18:58:39 -0800940 const CellularService::OLP *result =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700941 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -0800942 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800943 return;
944
Arman Ugurayf4c61812013-01-10 18:58:39 -0800945 CellularService::OLP olp;
946 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800947 string post_data = olp.GetPostData();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800948 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
949 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
950 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
951 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}", mdn_);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800952 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
953 olp.SetPostData(post_data);
954 cellular()->service()->SetOLP(olp);
955}
956
Arman Uguray2717a102013-01-29 23:36:06 -0800957void CellularCapabilityUniversal::UpdateServiceName() {
958 if (cellular()->service()) {
959 cellular()->service()->SetFriendlyName(CreateFriendlyServiceName());
960 }
961}
962
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400963void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700964 SLOG(Cellular, 2) << __func__;
Arman Uguray2717a102013-01-29 23:36:06 -0800965 // TODO(armansito): Use CellularOperatorInfo here instead of
966 // mobile_provider_db.
Ben Chan092b12b2012-11-07 22:04:05 -0800967
Arman Uguray3645c432013-01-31 15:57:26 -0800968 // Sometimes the modem fails to acquire the operator code OTA, in which case
969 // |serving_operator_| may not have an operator ID (sometimes due to service
970 // activation being required or broken modem firmware). Use |operator_id_| as
971 // a fallback when available. |operator_id_| is retrieved from the SIM card.
972 if (serving_operator_.GetCode().empty() && !operator_id_.empty()) {
Ben Chan092b12b2012-11-07 22:04:05 -0800973 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
974 << "' as serving operator.";
975 serving_operator_.SetCode(operator_id_);
976 }
977
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400978 const string &network_id = serving_operator_.GetCode();
979 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700980 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400981 mobile_provider *provider =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700982 mobile_provider_lookup_by_network(modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400983 network_id.c_str());
984 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200985 if (serving_operator_.GetName().empty()) {
986 const char *provider_name = mobile_provider_get_name(provider);
987 if (provider_name && *provider_name) {
988 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400989 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400990 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200991 if (provider->country && *provider->country) {
992 serving_operator_.SetCountry(provider->country);
993 }
994 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
995 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400996 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700997 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400998 }
999 }
1000 UpdateServingOperator();
1001}
1002
1003void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001004 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001005 if (cellular()->service().get()) {
1006 cellular()->service()->SetServingOperator(serving_operator_);
1007 }
1008}
1009
Arman Uguray6e5639f2012-11-15 20:30:19 -08001010void CellularCapabilityUniversal::UpdateBearerPath() {
1011 SLOG(Cellular, 2) << __func__;
1012 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
1013 weak_ptr_factory_.GetWeakPtr());
1014 Error error;
1015 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
1016}
1017
1018void CellularCapabilityUniversal::OnListBearersReply(
1019 const std::vector<DBus::Path> &paths,
1020 const Error &error) {
1021 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
1022 if (error.IsFailure()) {
1023 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
1024 return;
1025 }
1026 // Look for the first active bearer and use its path as the connected
1027 // one. Right now, we don't allow more than one active bearer.
1028 bool found_active = false;
1029 for (size_t i = 0; i < paths.size(); ++i) {
1030 const DBus::Path &path = paths[i];
1031 scoped_ptr<mm1::BearerProxyInterface> bearer_proxy(
1032 proxy_factory()->CreateBearerProxy(path, cellular()->dbus_owner()));
1033 bool is_active = bearer_proxy->Connected();
1034 if (is_active) {
1035 if (!found_active) {
1036 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
1037 bearer_path_ = path;
1038 found_active = true;
1039 } else {
1040 LOG(FATAL) << "Found more than one active bearer.";
1041 }
1042 }
1043 }
1044 if (!found_active) {
1045 SLOG(Cellular, 2) << "No active bearer found, clearing bearer_path_.";
1046 bearer_path_.clear();
1047 }
1048}
1049
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001050void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001051 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001052 if (!home_provider_) {
1053 return;
1054 }
1055 apn_list_.clear();
1056 for (int i = 0; i < home_provider_->num_apns; ++i) {
1057 Stringmap props;
1058 mobile_apn *apn = home_provider_->apns[i];
1059 if (apn->value) {
1060 props[flimflam::kApnProperty] = apn->value;
1061 }
1062 if (apn->username) {
1063 props[flimflam::kApnUsernameProperty] = apn->username;
1064 }
1065 if (apn->password) {
1066 props[flimflam::kApnPasswordProperty] = apn->password;
1067 }
1068 // Find the first localized and non-localized name, if any.
1069 const localized_name *lname = NULL;
1070 const localized_name *name = NULL;
1071 for (int j = 0; j < apn->num_names; ++j) {
1072 if (apn->names[j]->lang) {
1073 if (!lname) {
1074 lname = apn->names[j];
1075 }
1076 } else if (!name) {
1077 name = apn->names[j];
1078 }
1079 }
1080 if (name) {
1081 props[flimflam::kApnNameProperty] = name->name;
1082 }
1083 if (lname) {
1084 props[flimflam::kApnLocalizedNameProperty] = lname->name;
1085 props[flimflam::kApnLanguageProperty] = lname->lang;
1086 }
1087 apn_list_.push_back(props);
1088 }
Darin Petkovdb6083f2012-08-16 12:50:23 +02001089 if (cellular()->adaptor()) {
1090 cellular()->adaptor()->EmitStringmapsChanged(
1091 flimflam::kCellularApnListProperty, apn_list_);
1092 } else {
1093 LOG(ERROR) << "Null RPC service adaptor.";
1094 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001095}
1096
Ben Chan15786032012-11-04 21:28:02 -08001097bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
Arman Ugurayc7b15602013-02-16 00:56:18 -08001098 if (!sim_identifier_.empty() &&
Arman Uguray41cc6342013-03-29 16:34:39 -07001099 modem_info()->pending_activation_store()->GetActivationState(
1100 PendingActivationStore::kIdentifierICCID,
1101 sim_identifier_) != PendingActivationStore::kStateUnknown)
Arman Ugurayc7b15602013-02-16 00:56:18 -08001102 return false;
1103
Ben Chan15786032012-11-04 21:28:02 -08001104 // If there is no online payment portal information, it's safer to assume
1105 // the service does not require activation.
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001106 if (!modem_info()->cellular_operator_info())
Ben Chan15786032012-11-04 21:28:02 -08001107 return false;
1108
Arman Ugurayf4c61812013-01-10 18:58:39 -08001109 const CellularService::OLP *olp =
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001110 modem_info()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
Arman Ugurayf4c61812013-01-10 18:58:39 -08001111 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -08001112 return false;
1113
1114 // To avoid false positives, it's safer to assume the service does not
1115 // require activation if MDN is not set.
1116 if (mdn_.empty())
1117 return false;
1118
Ben Chand7592522013-02-13 16:02:01 -08001119 // If MDN contains only zeros, the service requires activation.
Arman Ugurayc7b15602013-02-16 00:56:18 -08001120 return !IsMdnValid();
1121}
1122
1123bool CellularCapabilityUniversal::IsMdnValid() const {
Arman Ugurayefea6e02013-02-21 13:28:04 -08001124 // Note that |mdn_| is normalized to contain only digits in OnMdnChanged().
Ben Chan15786032012-11-04 21:28:02 -08001125 for (size_t i = 0; i < mdn_.size(); ++i) {
Ben Chand7592522013-02-13 16:02:01 -08001126 if (mdn_[i] != '0')
Arman Ugurayc7b15602013-02-16 00:56:18 -08001127 return true;
Ben Chan15786032012-11-04 21:28:02 -08001128 }
Arman Ugurayc7b15602013-02-16 00:56:18 -08001129 return false;
Ben Chan15786032012-11-04 21:28:02 -08001130}
1131
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001132// always called from an async context
1133void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001134 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001135 CHECK(!callback.is_null());
1136 Error error;
1137 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1138 weak_ptr_factory_.GetWeakPtr(), callback);
1139 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
1140 if (error.IsFailure())
1141 callback.Run(error);
1142}
1143
1144void CellularCapabilityUniversal::RegisterOnNetwork(
1145 const string &network_id,
1146 Error *error,
1147 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001148 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001149 CHECK(error);
1150 desired_network_ = network_id;
1151 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
1152 weak_ptr_factory_.GetWeakPtr(), callback);
1153 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
1154}
1155
1156void CellularCapabilityUniversal::OnRegisterReply(
1157 const ResultCallback &callback,
1158 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001159 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160
1161 if (error.IsSuccess()) {
1162 selected_network_ = desired_network_;
1163 desired_network_.clear();
1164 callback.Run(error);
1165 return;
1166 }
1167 // If registration on the desired network failed,
1168 // try to register on the home network.
1169 if (!desired_network_.empty()) {
1170 desired_network_.clear();
1171 selected_network_.clear();
1172 LOG(INFO) << "Couldn't register on selected network, trying home network";
1173 Register(callback);
1174 return;
1175 }
1176 callback.Run(error);
1177}
1178
1179bool CellularCapabilityUniversal::IsRegistered() {
1180 return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1181 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
1182}
1183
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001184void CellularCapabilityUniversal::SetUnregistered(bool searching) {
1185 // If we're already in some non-registered state, don't override that
1186 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
1187 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1188 registration_state_ =
1189 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
1190 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
1191 }
1192}
1193
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001194void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001195 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001196 Error *error, const ResultCallback &callback) {
1197 CHECK(error);
1198 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
1199}
1200
1201void CellularCapabilityUniversal::EnterPIN(const string &pin,
1202 Error *error,
1203 const ResultCallback &callback) {
1204 CHECK(error);
1205 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
1206}
1207
1208void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
1209 const string &pin,
1210 Error *error,
1211 const ResultCallback &callback) {
1212 CHECK(error);
1213 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
1214}
1215
1216void CellularCapabilityUniversal::ChangePIN(
1217 const string &old_pin, const string &new_pin,
1218 Error *error, const ResultCallback &callback) {
1219 CHECK(error);
1220 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
1221}
1222
Ben Chan5d0d32c2013-01-08 02:05:29 -08001223void CellularCapabilityUniversal::Reset(Error *error,
1224 const ResultCallback &callback) {
1225 SLOG(Cellular, 2) << __func__;
1226 CHECK(error);
1227 if (resetting_) {
1228 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
1229 return;
1230 }
1231 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
1232 weak_ptr_factory_.GetWeakPtr(), callback);
1233 modem_proxy_->Reset(error, cb, kTimeoutReset);
1234 if (!error->IsFailure()) {
1235 resetting_ = true;
1236 }
1237}
1238
1239void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
1240 const Error &error) {
1241 SLOG(Cellular, 2) << __func__;
1242 resetting_ = false;
1243 if (!callback.is_null())
1244 callback.Run(error);
1245}
1246
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001247void CellularCapabilityUniversal::Scan(Error *error,
1248 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001249 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001250 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001251 if (scanning_) {
1252 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
1253 return;
1254 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001255 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
1256 weak_ptr_factory_.GetWeakPtr(), callback);
1257 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001258 if (!error->IsFailure()) {
1259 scanning_ = true;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001260 UpdateScanningProperty();
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001261 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001262}
1263
1264void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
1265 const ScanResults &results,
1266 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001267 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001268
1269 // Error handling is weak. The current expectation is that on any
1270 // error, found_networks_ should be cleared and a property change
1271 // notification sent out.
1272 //
1273 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -04001274 scanning_ = false;
Ben Chan8a2c01e2013-01-23 10:09:14 -08001275 UpdateScanningProperty();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001276 found_networks_.clear();
1277 if (!error.IsFailure()) {
1278 for (ScanResults::const_iterator it = results.begin();
1279 it != results.end(); ++it) {
1280 found_networks_.push_back(ParseScanResult(*it));
1281 }
1282 }
1283 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
1284 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -07001285
1286 // TODO(gmorain): This check for is_null() is a work-around because
1287 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
1288 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
1289 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
1290 // Universal.
1291 if (!callback.is_null())
1292 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001293}
1294
1295Stringmap CellularCapabilityUniversal::ParseScanResult(
1296 const ScanResult &result) {
1297
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001298 /* ScanResults contain the following keys:
1299
1300 "status"
1301 A MMModem3gppNetworkAvailability value representing network
1302 availability status, given as an unsigned integer (signature "u").
1303 This key will always be present.
1304
1305 "operator-long"
1306 Long-format name of operator, given as a string value (signature
1307 "s"). If the name is unknown, this field should not be present.
1308
1309 "operator-short"
1310 Short-format name of operator, given as a string value
1311 (signature "s"). If the name is unknown, this field should not
1312 be present.
1313
1314 "operator-code"
1315 Mobile code of the operator, given as a string value (signature
1316 "s"). Returned in the format "MCCMNC", where MCC is the
1317 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1318 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1319
1320 "access-technology"
1321 A MMModemAccessTechnology value representing the generic access
1322 technology used by this mobile network, given as an unsigned
1323 integer (signature "u").
1324 */
1325 Stringmap parsed;
1326
1327 uint32 status;
1328 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1329 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1330 static const char * const kStatusString[] = {
1331 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1332 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1333 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1334 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1335 };
1336 parsed[flimflam::kStatusProperty] = kStatusString[status];
1337 }
1338
1339 uint32 tech; // MMModemAccessTechnology
1340 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1341 &tech)) {
1342 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
1343 }
1344
1345 string operator_long, operator_short, operator_code;
1346 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
1347 parsed[flimflam::kLongNameProperty] = operator_long;
1348 if (DBusProperties::GetString(result, kOperatorShortProperty,
1349 &operator_short))
1350 parsed[flimflam::kShortNameProperty] = operator_short;
1351 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
1352 parsed[flimflam::kNetworkIdProperty] = operator_code;
1353
1354 // If the long name is not available but the network ID is, look up the long
1355 // name in the mobile provider database.
1356 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
1357 parsed[flimflam::kLongNameProperty].empty()) &&
1358 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
1359 mobile_provider *provider =
1360 mobile_provider_lookup_by_network(
Prathmesh Prabhu27526f12013-03-25 19:42:18 -07001361 modem_info()->provider_db(),
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001362 parsed[flimflam::kNetworkIdProperty].c_str());
1363 if (provider) {
1364 const char *long_name = mobile_provider_get_name(provider);
1365 if (long_name && *long_name) {
1366 parsed[flimflam::kLongNameProperty] = long_name;
1367 }
1368 }
1369 }
1370 return parsed;
1371}
1372
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001373string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Arman Uguray7af0fac2013-03-18 17:35:35 -07001374 // If we know that the modem is an E362, return LTE here to make sure that
1375 // Chrome sees LTE as the network technology even if the actual technology is
1376 // unknown.
1377 // TODO(armansito): This hack will cause the UI to display LTE even if the
1378 // modem doesn't support it at a given time. This might be problematic if we
1379 // ever want to support switching between access technologies (e.g. falling
1380 // back to 3G when LTE is not available).
1381 if (model_id_ == kE362ModelId)
1382 return flimflam::kNetworkTechnologyLte;
1383
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001384 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001385 // TODO(jglasgow): change shill interfaces to a capability model
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001386 return AccessTechnologyToString(access_technologies_);
1387}
1388
1389string CellularCapabilityUniversal::GetRoamingStateString() const {
1390 switch (registration_state_) {
1391 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1392 return flimflam::kRoamingStateHome;
1393 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1394 return flimflam::kRoamingStateRoaming;
1395 default:
1396 break;
1397 }
1398 return flimflam::kRoamingStateUnknown;
1399}
1400
1401void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -04001402 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
1403 const DBus::Struct<unsigned int, bool> quality =
1404 modem_proxy_->SignalQuality();
1405 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001406}
1407
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001408string CellularCapabilityUniversal::GetTypeString() const {
1409 return AccessTechnologyToTechnologyFamily(access_technologies_);
1410}
1411
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001412void CellularCapabilityUniversal::OnModemPropertiesChanged(
1413 const DBusPropertiesMap &properties,
1414 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001415 // This solves a bootstrapping problem: If the modem is not yet
1416 // enabled, there are no proxy objects associated with the capability
1417 // object, so modem signals like StateChanged aren't seen. By monitoring
1418 // changes to the State property via the ModemManager, we're able to
1419 // get the initialization process started, which will result in the
1420 // creation of the proxy objects.
1421 //
1422 // The first time we see the change to State (when the modem state
1423 // is Unknown), we simply update the state, and rely on the Manager to
1424 // enable the device when it is registered with the Manager. On subsequent
1425 // changes to State, we need to explicitly enable the device ourselves.
1426 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001427 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001428 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001429 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001430 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001431 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001432 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001433 MM_MODEM_PROPERTY_SIM, &string_value))
1434 OnSimPathChanged(string_value);
1435 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001436 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001437 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
1438 &uint_value))
1439 OnModemCapabilitesChanged(uint_value);
1440 if (DBusProperties::GetUint32(properties,
1441 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1442 &uint_value))
1443 OnModemCurrentCapabilitiesChanged(uint_value);
1444 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1445 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
1446 if (DBusProperties::GetString(properties,
1447 MM_MODEM_PROPERTY_MANUFACTURER,
1448 &string_value))
1449 OnModemManufacturerChanged(string_value);
1450 if (DBusProperties::GetString(properties,
1451 MM_MODEM_PROPERTY_MODEL,
1452 &string_value))
1453 OnModemModelChanged(string_value);
1454 if (DBusProperties::GetString(properties,
1455 MM_MODEM_PROPERTY_REVISION,
1456 &string_value))
1457 OnModemRevisionChanged(string_value);
1458 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1459 // not needed: MM_MODEM_PROPERTY_DEVICE
1460 // not needed: MM_MODEM_PROPERTY_DRIVER
1461 // not needed: MM_MODEM_PROPERTY_PLUGIN
1462 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001463
Jason Glasgowaf583282012-04-18 15:18:22 -04001464 // Unlock required and SimLock
1465 bool locks_changed = false;
1466 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001467 if (DBusProperties::GetUint32(properties,
1468 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -04001469 &unlock_required)) {
1470 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001471 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001472 LockRetryData lock_retries;
1473 DBusPropertiesMap::const_iterator it =
1474 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
1475 if (it != properties.end()) {
mukesh agrawal42457712013-04-05 16:05:39 -07001476 lock_retries = it->second.operator LockRetryData();
Jason Glasgowaf583282012-04-18 15:18:22 -04001477 locks_changed = true;
1478 }
1479 if (locks_changed)
1480 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
1481 lock_retries);
1482 if (DBusProperties::GetUint32(properties,
1483 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1484 &uint_value))
1485 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001486
Jason Glasgowaf583282012-04-18 15:18:22 -04001487 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1488 if (it != properties.end()) {
1489 DBus::Struct<unsigned int, bool> quality = it->second;
1490 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001491 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001492 vector<string> numbers;
1493 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1494 &numbers)) {
1495 string mdn;
1496 if (numbers.size() > 0)
1497 mdn = numbers[0];
1498 OnMdnChanged(mdn);
1499 }
1500 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
1501 &uint_value))
1502 OnSupportedModesChanged(uint_value);
1503 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
1504 &uint_value))
1505 OnAllowedModesChanged(uint_value);
1506 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
1507 &uint_value))
1508 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
1509 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1510 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001511}
1512
1513void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1514 const string &interface,
1515 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001516 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001517 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001518 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001519 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001520 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001521 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1522 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001523 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001524 if (interface == MM_DBUS_INTERFACE_SIM) {
1525 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001526 }
1527}
1528
Jason Glasgow14521872012-05-07 19:12:15 -04001529bool CellularCapabilityUniversal::RetriableConnectError(
1530 const Error &error) const {
1531 if (error.type() == Error::kInvalidApn)
1532 return true;
1533
1534 // modemmanager does not ever return kInvalidApn for E362 modems
1535 // with 1.41 firmware. It remains to be seem if this will change
1536 // with 3.x firmware.
1537 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1538 return true;
1539
1540 return false;
1541}
1542
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001543void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1544 // TODO(petkov): Implement this.
1545 NOTIMPLEMENTED();
1546}
1547
Arman Uguray6552f8c2013-02-12 15:33:18 -08001548bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1549 return !sim_path.empty() && sim_path != kRootPath;
1550}
1551
Ben Chand7592522013-02-13 16:02:01 -08001552string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1553 string normalized_mdn;
1554 for (size_t i = 0; i < mdn.size(); ++i) {
1555 if (IsAsciiDigit(mdn[i]))
1556 normalized_mdn += mdn[i];
1557 }
1558 return normalized_mdn;
1559}
1560
Jason Glasgowaf583282012-04-18 15:18:22 -04001561void CellularCapabilityUniversal::OnSimPathChanged(
1562 const string &sim_path) {
1563 if (sim_path == sim_path_)
1564 return;
1565
1566 mm1::SimProxyInterface *proxy = NULL;
Arman Uguray6552f8c2013-02-12 15:33:18 -08001567 if (IsValidSimPath(sim_path))
Jason Glasgowaf583282012-04-18 15:18:22 -04001568 proxy = proxy_factory()->CreateSimProxy(sim_path,
1569 cellular()->dbus_owner());
1570 sim_path_ = sim_path;
1571 sim_proxy_.reset(proxy);
1572
Arman Uguray6552f8c2013-02-12 15:33:18 -08001573 if (!IsValidSimPath(sim_path)) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001574 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001575 imsi_ = "";
1576 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001577 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001578 OnSimIdentifierChanged("");
1579 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001580 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001581 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001582 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1583 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1584 cellular()->dbus_owner()));
1585 // TODO(jglasgow): convert to async interface
1586 DBusPropertiesMap properties(
1587 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1588 OnSimPropertiesChanged(properties, vector<string>());
1589 }
1590}
1591
1592void CellularCapabilityUniversal::OnModemCapabilitesChanged(
1593 uint32 capabilities) {
1594 capabilities_ = capabilities;
1595}
1596
1597void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1598 uint32 current_capabilities) {
1599 current_capabilities_ = current_capabilities;
Ben Chanfcca27b2013-01-22 15:03:44 -08001600
1601 // Only allow network scan when the modem's current capabilities support
1602 // GSM/UMTS.
1603 //
1604 // TODO(benchan): We should consider having the modem plugins in ModemManager
1605 // reporting whether network scan is supported.
1606 scanning_supported_ =
1607 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0;
1608 if (cellular()->adaptor()) {
1609 cellular()->adaptor()->EmitBoolChanged(
1610 flimflam::kSupportNetworkScanProperty, scanning_supported_);
1611 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001612}
1613
1614void CellularCapabilityUniversal::OnMdnChanged(
1615 const string &mdn) {
Ben Chand7592522013-02-13 16:02:01 -08001616 mdn_ = NormalizeMdn(mdn);
Arman Uguray0a3e2792013-01-17 16:31:50 -08001617 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001618}
1619
1620void CellularCapabilityUniversal::OnModemManufacturerChanged(
1621 const string &manufacturer) {
1622 manufacturer_ = manufacturer;
1623}
1624
1625void CellularCapabilityUniversal::OnModemModelChanged(
1626 const string &model) {
1627 model_id_ = model;
1628}
1629
1630void CellularCapabilityUniversal::OnModemRevisionChanged(
1631 const string &revision) {
1632 firmware_revision_ = revision;
1633}
1634
1635void CellularCapabilityUniversal::OnModemStateChanged(
1636 Cellular::ModemState state) {
1637 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1638 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1639 if (Cellular::IsEnabledModemState(state))
1640 cellular()->set_modem_state(state);
Gary Moraine285a842012-08-15 08:23:57 -07001641 SLOG(Cellular, 2) << __func__ << ": prev_modem_state: " << prev_modem_state
1642 << " was_enabled: " << was_enabled
1643 << " cellular state: "
1644 << cellular()->GetStateString(cellular()->state());
Jason Glasgowaf583282012-04-18 15:18:22 -04001645 if (prev_modem_state != Cellular::kModemStateUnknown &&
1646 prev_modem_state != Cellular::kModemStateEnabling &&
1647 !was_enabled &&
1648 cellular()->state() == Cellular::kStateDisabled &&
1649 cellular()->IsUnderlyingDeviceEnabled()) {
1650 cellular()->SetEnabled(true);
1651 }
Ben Chan8a2c01e2013-01-23 10:09:14 -08001652 UpdateScanningProperty();
Jason Glasgowaf583282012-04-18 15:18:22 -04001653}
1654
1655void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1656 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001657 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001658 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001659 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001660 const string new_type_string(GetTypeString());
1661 if (new_type_string != old_type_string) {
1662 // TODO(jglasgow): address layering violation of emitting change
1663 // signal here for a property owned by Cellular.
1664 cellular()->adaptor()->EmitStringChanged(
1665 flimflam::kTechnologyFamilyProperty, new_type_string);
1666 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001667 if (cellular()->service().get()) {
1668 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1669 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001670 }
1671}
1672
1673void CellularCapabilityUniversal::OnSupportedModesChanged(
1674 uint32 supported_modes) {
1675 supported_modes_ = supported_modes;
1676}
1677
1678void CellularCapabilityUniversal::OnAllowedModesChanged(
1679 uint32 allowed_modes) {
1680 allowed_modes_ = allowed_modes;
1681}
1682
1683void CellularCapabilityUniversal::OnPreferredModeChanged(
1684 MMModemMode preferred_mode) {
1685 preferred_mode_ = preferred_mode;
1686}
1687
1688void CellularCapabilityUniversal::OnLockRetriesChanged(
1689 MMModemLock unlock_required,
1690 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001691 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001692 case MM_MODEM_LOCK_SIM_PIN:
1693 sim_lock_status_.lock_type = "sim-pin";
1694 break;
1695 case MM_MODEM_LOCK_SIM_PUK:
1696 sim_lock_status_.lock_type = "sim-puk";
1697 break;
1698 default:
1699 sim_lock_status_.lock_type = "";
1700 break;
1701 }
1702 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1703 if (it != lock_retries.end()) {
1704 sim_lock_status_.retries_left = it->second;
1705 } else {
1706 // Unknown, use 999
1707 sim_lock_status_.retries_left = 999;
1708 }
1709 OnSimLockStatusChanged();
1710}
1711
1712void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1713 cellular()->adaptor()->EmitKeyValueStoreChanged(
1714 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001715
1716 // If the SIM is currently unlocked, assume that we need to refresh
1717 // carrier information, since a locked SIM prevents shill from obtaining
1718 // the necessary data to establish a connection later (e.g. IMSI).
1719 if (!sim_path_.empty() && sim_lock_status_.lock_type.empty()) {
1720 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1721 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1722 cellular()->dbus_owner()));
1723 DBusPropertiesMap properties(
1724 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1725 OnSimPropertiesChanged(properties, vector<string>());
1726 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001727}
1728
1729void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1730 const DBusPropertiesMap &properties,
1731 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001732 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001733 string imei;
1734 if (DBusProperties::GetString(properties,
1735 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1736 &imei))
1737 OnImeiChanged(imei);
1738
1739 // Handle registration state changes as a single change
1740 string operator_code = serving_operator_.GetCode();
1741 string operator_name = serving_operator_.GetName();
1742 MMModem3gppRegistrationState state = registration_state_;
1743 bool registration_changed = false;
1744 uint32 uint_value;
1745 if (DBusProperties::GetUint32(properties,
1746 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1747 &uint_value)) {
1748 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1749 registration_changed = true;
1750 }
1751 if (DBusProperties::GetString(properties,
1752 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1753 &operator_code))
1754 registration_changed = true;
1755 if (DBusProperties::GetString(properties,
1756 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1757 &operator_name))
1758 registration_changed = true;
1759 if (registration_changed)
1760 On3GPPRegistrationChanged(state, operator_code, operator_name);
1761
1762 uint32 locks = 0;
1763 if (DBusProperties::GetUint32(
1764 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1765 &locks))
1766 OnFacilityLocksChanged(locks);
1767}
1768
1769void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1770 imei_ = imei;
1771}
1772
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001773void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1774 MMModem3gppRegistrationState state,
1775 const string &operator_code,
1776 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001777 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1778 << ", opercode=" << operator_code
1779 << ", opername=" << operator_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001780 registration_state_ = state;
1781 serving_operator_.SetCode(operator_code);
1782 serving_operator_.SetName(operator_name);
Arman Uguray2717a102013-01-29 23:36:06 -08001783
1784 // Update the carrier name for |serving_operator_|.
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001785 UpdateOperatorInfo();
Arman Uguray2717a102013-01-29 23:36:06 -08001786
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001787 cellular()->HandleNewRegistrationState();
Arman Uguray2717a102013-01-29 23:36:06 -08001788
1789 // Update the user facing name of the cellular service.
1790 UpdateServiceName();
Arman Ugurayc7b15602013-02-16 00:56:18 -08001791
1792 // If the modem registered with the network and the current ICCID is pending
1793 // activation, then reset the modem.
Arman Uguray0a3e2792013-01-17 16:31:50 -08001794 UpdatePendingActivationState();
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001795}
1796
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001797void CellularCapabilityUniversal::OnModemStateChangedSignal(
1798 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001799 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1800 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001801 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1802 static_cast<Cellular::ModemState>(new_state),
1803 reason);
Ben Chan2e12ccd2013-01-24 15:24:27 -08001804 UpdateScanningProperty();
Gary Moraine285a842012-08-15 08:23:57 -07001805 if (!deferred_enable_modem_callback_.is_null() &&
1806 (new_state == Cellular::kModemStateDisabled)) {
1807 SLOG(Cellular, 2) << "Enabling modem after deferring";
1808 deferred_enable_modem_callback_.Run();
1809 deferred_enable_modem_callback_.Reset();
Arman Uguray6e5639f2012-11-15 20:30:19 -08001810 } else if (new_state == Cellular::kModemStateConnected) {
1811 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1812 UpdateBearerPath();
Gary Moraine285a842012-08-15 08:23:57 -07001813 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001814}
1815
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001816void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1817 cellular()->HandleNewSignalQuality(quality);
1818}
1819
Jason Glasgowaf583282012-04-18 15:18:22 -04001820void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1821 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1822 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1823 OnSimLockStatusChanged();
1824 }
1825}
Jason Glasgowef965562012-04-10 16:12:35 -04001826
Jason Glasgowaf583282012-04-18 15:18:22 -04001827void CellularCapabilityUniversal::OnSimPropertiesChanged(
1828 const DBusPropertiesMap &props,
1829 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001830 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001831 string value;
Jason Glasgowaf583282012-04-18 15:18:22 -04001832 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1833 OnSimIdentifierChanged(value);
1834 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1835 &value))
1836 OnOperatorIdChanged(value);
Arman Ugurayd73783f2013-01-31 16:11:21 -08001837 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1838 OnSpnChanged(value);
1839 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value))
1840 OnImsiChanged(value);
1841 SetHomeProvider();
1842}
Jason Glasgowaf583282012-04-18 15:18:22 -04001843
Arman Ugurayd73783f2013-01-31 16:11:21 -08001844// TODO(armansito): The following methods should probably log their argument
1845// values. Need to learn if any of them need to be scrubbed.
1846void CellularCapabilityUniversal::OnImsiChanged(const std::string &imsi) {
1847 imsi_ = imsi;
1848}
1849
1850void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1851 spn_ = spn;
Jason Glasgowaf583282012-04-18 15:18:22 -04001852}
1853
1854void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1855 sim_identifier_ = id;
Arman Uguray0a3e2792013-01-17 16:31:50 -08001856 UpdatePendingActivationState();
Jason Glasgowaf583282012-04-18 15:18:22 -04001857}
1858
1859void CellularCapabilityUniversal::OnOperatorIdChanged(
1860 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001861 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04001862 operator_id_ = operator_id;
1863}
1864
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001865} // namespace shill