blob: 9bbbef23f36750fc459a3d34ecd868e63917a8ea [file] [log] [blame]
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// 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"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040024#include "shill/property_accessor.h"
25#include "shill/proxy_factory.h"
26
27#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
28#error "Do not include mm-modem.h"
29#endif
30
Jason Glasgow82f9ab32012-04-04 14:27:19 -040031using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040032using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040033using std::string;
34using std::vector;
35
36namespace shill {
37
38// static
Jason Glasgow14521872012-05-07 19:12:15 -040039const char CellularCapabilityUniversal::kConnectPin[] = "pin";
40const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
41const char CellularCapabilityUniversal::kConnectBands[] = "bands";
42const char CellularCapabilityUniversal::kConnectAllowedModes[] =
43 "allowed-modes";
44const char CellularCapabilityUniversal::kConnectPreferredMode[] =
45 "preferred-mode";
46const char CellularCapabilityUniversal::kConnectApn[] = "apn";
47const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
48const char CellularCapabilityUniversal::kConnectUser[] = "user";
49const char CellularCapabilityUniversal::kConnectPassword[] = "password";
50const char CellularCapabilityUniversal::kConnectNumber[] = "number";
51const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
52 "allow-roaming";
53const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040054const char CellularCapabilityUniversal::kStatusProperty[] = "status";
55const char CellularCapabilityUniversal::kOperatorLongProperty[] =
56 "operator-long";
57const char CellularCapabilityUniversal::kOperatorShortProperty[] =
58 "operator-short";
59const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
60 "operator-code";
61const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
62 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040063const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
64unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
65
Jason Glasgow82f9ab32012-04-04 14:27:19 -040066
67static const char kPhoneNumber[] = "*99#";
68
69static string AccessTechnologyToString(uint32 access_technologies) {
70 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
71 return flimflam::kNetworkTechnologyLte;
72 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
73 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
74 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
75 return flimflam::kNetworkTechnologyEvdo;
76 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
77 return flimflam::kNetworkTechnology1Xrtt;
78 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
79 return flimflam::kNetworkTechnologyHspaPlus;
80 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
81 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
82 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
83 return flimflam::kNetworkTechnologyHspa;
84 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
85 return flimflam::kNetworkTechnologyUmts;
86 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
87 return flimflam::kNetworkTechnologyEdge;
88 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
89 return flimflam::kNetworkTechnologyGprs;
90 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
91 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
92 return flimflam::kNetworkTechnologyGsm;
93 return "";
94}
95
Jason Glasgow9f09aef2012-05-08 16:26:55 -040096static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
97 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
100 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
101 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
102 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
103 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
104 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
105 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
106 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
107 return flimflam::kTechnologyFamilyGsm;
108 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800109 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
110 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400111 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
112 return flimflam::kTechnologyFamilyCdma;
113 return "";
114}
115
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400116CellularCapabilityUniversal::CellularCapabilityUniversal(
117 Cellular *cellular,
118 ProxyFactory *proxy_factory)
119 : CellularCapability(cellular, proxy_factory),
120 weak_ptr_factory_(this),
121 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
122 cdma_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200123 capabilities_(MM_MODEM_CAPABILITY_NONE),
124 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400125 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400126 supported_modes_(MM_MODEM_MODE_NONE),
127 allowed_modes_(MM_MODEM_MODE_NONE),
128 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400129 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200130 provider_requires_roaming_(false),
Ben Chan5d0d32c2013-01-08 02:05:29 -0800131 resetting_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400132 scanning_supported_(true),
133 scanning_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700134 scan_interval_(0),
135 sim_present_(false) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700136 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400137 PropertyStore *store = cellular->mutable_store();
138
139 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
140 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
141 &scanning_supported_);
142 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
143 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
144 &firmware_revision_);
145 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
146 &hardware_revision_);
147 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
148 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700149 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400150 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
151 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
152 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
153 store->RegisterConstString(flimflam::kMinProperty, &min_);
154 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
155 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
156 &selected_network_);
157 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
158 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +0200159 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
160 &provider_requires_roaming_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400161 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
162 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
163 HelpRegisterDerivedKeyValueStore(
164 flimflam::kSIMLockStatusProperty,
165 &CellularCapabilityUniversal::SimLockStatusToProperty,
166 NULL);
Ben Chanbd3aee82012-10-16 23:52:04 -0700167 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400168 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
169 &apn_list_);
170}
171
172KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
173 Error */*error*/) {
174 KeyValueStore status;
175 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
176 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
177 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
178 sim_lock_status_.retries_left);
179 return status;
180}
181
182void CellularCapabilityUniversal::HelpRegisterDerivedKeyValueStore(
183 const string &name,
184 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
185 void(CellularCapabilityUniversal::*set)(
186 const KeyValueStore &value, Error *error)) {
187 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
188 name,
189 KeyValueStoreAccessor(
190 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
191 this, get, set)));
192}
193
194void CellularCapabilityUniversal::InitProxies() {
195 modem_3gpp_proxy_.reset(
196 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
197 cellular()->dbus_owner()));
198 modem_cdma_proxy_.reset(
199 proxy_factory()->CreateMM1ModemModemCdmaProxy(cellular()->dbus_path(),
200 cellular()->dbus_owner()));
201 modem_proxy_.reset(
202 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
203 cellular()->dbus_owner()));
204 modem_simple_proxy_.reset(
205 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
206 cellular()->dbus_owner()));
Arman Uguray6e5639f2012-11-15 20:30:19 -0800207
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400208 modem_proxy_->set_state_changed_callback(
209 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
210 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400211 // Do not create a SIM proxy until the device is enabled because we
212 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400213 // TODO(jglasgow): register callbacks
214}
215
216void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400217 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700218 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400219 InitProxies();
220
Gary Moraine285a842012-08-15 08:23:57 -0700221 // ModemManager must be in the disabled state to accept the Enable command.
222 Cellular::ModemState state =
223 static_cast<Cellular::ModemState>(modem_proxy_->State());
224 if (state == Cellular::kModemStateDisabled) {
225 EnableModem(error, callback);
226 } else if (!cellular()->IsUnderlyingDeviceEnabled()) {
227 SLOG(Cellular, 2) << "Enabling of modem deferred because state is "
228 << state;
229 deferred_enable_modem_callback_ =
230 Bind(&CellularCapabilityUniversal::EnableModem,
231 weak_ptr_factory_.GetWeakPtr(), static_cast<Error *>(NULL),
232 callback);
233 } else {
Arman Uguray403fad42012-09-25 17:08:39 -0700234 // Call GetProperties() here to sync up with the modem state
235 GetProperties();
Gary Moraine285a842012-08-15 08:23:57 -0700236 callback.Run(*error);
237 }
238}
239
240void CellularCapabilityUniversal::EnableModem(Error *error,
241 const ResultCallback &callback) {
242 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400243 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700244 Error local_error(Error::kOperationInitiated);
Jason Glasgowef965562012-04-10 16:12:35 -0400245 modem_proxy_->Enable(
246 true,
Gary Moraine285a842012-08-15 08:23:57 -0700247 &local_error,
Jason Glasgowef965562012-04-10 16:12:35 -0400248 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
249 weak_ptr_factory_.GetWeakPtr(), callback),
250 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700251 if (local_error.IsFailure()) {
252 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
253 callback.Run(local_error);
254 }
255 if (error) {
256 error->CopyFrom(local_error);
257 }
Jason Glasgowef965562012-04-10 16:12:35 -0400258}
259
260void CellularCapabilityUniversal::Start_EnableModemCompleted(
261 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400262 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400263 if (error.IsFailure()) {
264 callback.Run(error);
265 return;
266 }
267
268 // After modem is enabled, it should be possible to get properties
269 // TODO(jglasgow): handle errors from GetProperties
270 GetProperties();
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400271 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400272}
273
274void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400275 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400276 CHECK(!callback.is_null());
277 CHECK(error);
Thieu Led0012052012-07-25 16:09:09 -0700278 Cellular::ModemState state = cellular()->modem_state();
279 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400280
Thieu Led0012052012-07-25 16:09:09 -0700281 if (cellular()->IsModemRegistered()) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400282 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400283 modem_simple_proxy_->Disconnect(
284 all_bearers,
285 error,
286 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
287 weak_ptr_factory_.GetWeakPtr(), callback),
Thieu Le049adb52012-11-12 17:14:51 -0800288 kTimeoutDisconnect);
Jason Glasgowef965562012-04-10 16:12:35 -0400289 if (error->IsFailure())
290 callback.Run(*error);
291 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400292 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
293 weak_ptr_factory_.GetWeakPtr(),
294 callback);
295 cellular()->dispatcher()->PostTask(task);
296 }
Gary Moraine285a842012-08-15 08:23:57 -0700297 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400298}
299
300void CellularCapabilityUniversal::Stop_DisconnectCompleted(
301 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700302 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400303
304 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
305 Stop_Disable(callback);
306}
307
308void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
309 Error error;
310 modem_proxy_->Enable(
311 false, &error,
312 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
313 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400314 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400315 if (error.IsFailure())
316 callback.Run(error);
317}
318
319void CellularCapabilityUniversal::Stop_DisableCompleted(
320 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700321 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400322
323 if (error.IsSuccess())
324 ReleaseProxies();
325 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400326}
327
328void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
329 Error *error,
330 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700331 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400332 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
333 weak_ptr_factory_.GetWeakPtr(),
334 callback);
335 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400336}
337
338void CellularCapabilityUniversal::Disconnect(Error *error,
339 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700340 SLOG(Cellular, 2) << __func__;
Thieu Le5d6864a2012-07-20 11:43:51 -0700341 if (bearer_path_.empty()) {
342 LOG(WARNING) << "In " << __func__ << "(): "
343 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700344 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700345 modem_simple_proxy_->Disconnect(bearer_path_,
346 error,
347 callback,
Thieu Le049adb52012-11-12 17:14:51 -0800348 kTimeoutDisconnect);
Thieu Le5d6864a2012-07-20 11:43:51 -0700349 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400350}
351
Christopher Wiley8a468902012-11-30 11:52:38 -0800352void CellularCapabilityUniversal::DisconnectCleanup() {
353 SLOG(Cellular, 2) << __func__;
354}
355
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400356void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400357 Error *error,
358 const ResultCallback &callback) {
359 OnUnsupportedOperation(__func__, error);
360}
361
362void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700363 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400364 modem_3gpp_proxy_.reset();
365 modem_cdma_proxy_.reset();
366 modem_proxy_.reset();
367 modem_simple_proxy_.reset();
368 sim_proxy_.reset();
369}
370
371void CellularCapabilityUniversal::OnServiceCreated() {
372 // If IMSI is available, base the service's storage identifier on it.
373 if (!imsi_.empty()) {
374 cellular()->service()->SetStorageIdentifier(
375 string(flimflam::kTypeCellular) + "_" +
376 cellular()->address() + "_" + imsi_);
377 }
Ben Chan3d6de0e2012-12-10 12:01:34 -0800378 bool activation_required = IsServiceActivationRequired();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400379 cellular()->service()->SetActivationState(
Ben Chan3d6de0e2012-12-10 12:01:34 -0800380 activation_required ?
Ben Chan15786032012-11-04 21:28:02 -0800381 flimflam::kActivationStateNotActivated :
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400382 flimflam::kActivationStateActivated);
Ben Chan3d6de0e2012-12-10 12:01:34 -0800383 // TODO(benchan): For now, assume the cellular service is activated over
384 // a non-cellular network if service activation is required (i.e. a
385 // corresponding entry is found in the cellular operator info file).
386 // We will need to generalize this logic when migrating CDMA support from
387 // cromo to ModemManager.
388 cellular()->service()->SetActivateOverNonCellularNetwork(activation_required);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400389 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800390 UpdateOLP();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400391}
392
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400393// Create the list of APNs to try, in the following order:
394// - last APN that resulted in a successful connection attempt on the
395// current network (if any)
396// - the APN, if any, that was set by the user
397// - the list of APNs found in the mobile broadband provider DB for the
398// home provider associated with the current SIM
399// - as a last resort, attempt to connect with no APN
400void CellularCapabilityUniversal::SetupApnTryList() {
401 apn_try_list_.clear();
402
403 DCHECK(cellular()->service().get());
404 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
405 if (apn_info)
406 apn_try_list_.push_back(*apn_info);
407
408 apn_info = cellular()->service()->GetUserSpecifiedApn();
409 if (apn_info)
410 apn_try_list_.push_back(*apn_info);
411
412 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
413}
414
415void CellularCapabilityUniversal::SetupConnectProperties(
416 DBusPropertiesMap *properties) {
417 SetupApnTryList();
418 FillConnectPropertyMap(properties);
419}
420
421void CellularCapabilityUniversal::FillConnectPropertyMap(
422 DBusPropertiesMap *properties) {
423
424 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400425 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400426 kPhoneNumber);
427
Jason Glasgow14521872012-05-07 19:12:15 -0400428 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400429 AllowRoaming());
430
431 if (!apn_try_list_.empty()) {
432 // Leave the APN at the front of the list, so that it can be recorded
433 // if the connect attempt succeeds.
434 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700435 SLOG(Cellular, 2) << __func__ << ": Using APN "
436 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400437 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400438 apn_info[flimflam::kApnProperty].c_str());
439 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400440 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400441 apn_info[flimflam::kApnUsernameProperty].c_str());
442 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400443 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400444 apn_info[flimflam::kApnPasswordProperty].c_str());
445 }
446}
447
448void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400449 const DBus::Path &path,
450 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700451 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400452
Jason Glasgow7234ec32012-05-23 16:01:21 -0400453 CellularServiceRefPtr service = cellular()->service();
454 if (!service) {
455 // The service could have been deleted before our Connect() request
456 // completes if the modem was enabled and then quickly disabled.
457 apn_try_list_.clear();
458 } else if (error.IsFailure()) {
459 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400460 // The APN that was just tried (and failed) is still at the
461 // front of the list, about to be removed. If the list is empty
462 // after that, try one last time without an APN. This may succeed
463 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400464 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400465 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700466 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
467 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400468 DBusPropertiesMap props;
469 FillConnectPropertyMap(&props);
470 Error error;
471 Connect(props, &error, callback);
472 return;
473 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400474 } else {
475 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400476 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400477 apn_try_list_.clear();
478 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400479 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400480 }
481
482 if (!callback.is_null())
483 callback.Run(error);
484}
485
486bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200487 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400488}
489
Jason Glasgowef965562012-04-10 16:12:35 -0400490void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700491 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400492
Jason Glasgowaf583282012-04-18 15:18:22 -0400493 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
494 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
495 cellular()->dbus_owner()));
496 DBusPropertiesMap properties(
497 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
498 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400499
Jason Glasgowaf583282012-04-18 15:18:22 -0400500 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
501 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400502}
503
504string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200505 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
Ben Chan092b12b2012-11-07 22:04:05 -0800506
507 // If |serving_operator_| does not have an operator ID, call
508 // UpdateOperatorInfo() to use |operator_id_| as a fallback when appropriate.
509 if (serving_operator_.GetCode().empty()) {
510 UpdateOperatorInfo();
511 }
512
Darin Petkova4ca3c32012-08-17 16:05:24 +0200513 string name = serving_operator_.GetName();
514 string home_provider_name = cellular()->home_provider().GetName();
515 if (!name.empty()) {
516 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
517 // rules (TS 31.102 and annex A of 122.101).
518 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
519 !home_provider_name.empty()) {
520 return home_provider_name + " | " + name;
521 }
522 return name;
523 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400524 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200525 !home_provider_name.empty()) {
526 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400527 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200528 string serving_operator_code = serving_operator_.GetCode();
529 if (!serving_operator_code.empty()) {
530 return "cellular_" + serving_operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400531 }
532 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
533}
534
535void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700536 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400537 << " SPN: " << spn_ << ")";
538 // TODO(petkov): The test for NULL provider_db should be done by
539 // mobile_provider_lookup_best_match.
540 if (imsi_.empty() || !cellular()->provider_db()) {
541 return;
542 }
543 mobile_provider *provider =
544 mobile_provider_lookup_best_match(
545 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
546 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700547 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400548 return;
549 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400550
551 // Even if provider is the same as home_provider_, it is possible
552 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400553 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200554 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400555 Cellular::Operator oper;
Darin Petkovb4fccd22012-08-10 11:59:26 +0200556 if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400557 oper.SetCode(provider->networks[0]);
558 }
559 if (provider->country) {
560 oper.SetCountry(provider->country);
561 }
562 if (spn_.empty()) {
563 const char *name = mobile_provider_get_name(provider);
564 if (name) {
565 oper.SetName(name);
566 }
567 } else {
568 oper.SetName(spn_);
569 }
570 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200571 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200572 << oper.GetName() << ", " << oper.GetCountry()
573 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400574 InitAPNList();
575}
576
Ben Chan6d0d1e72012-11-06 21:19:28 -0800577void CellularCapabilityUniversal::UpdateOLP() {
578 if (!cellular()->cellular_operator_info())
579 return;
580
Arman Ugurayf4c61812013-01-10 18:58:39 -0800581 const CellularService::OLP *result =
582 cellular()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
583 if (!result)
Ben Chan6d0d1e72012-11-06 21:19:28 -0800584 return;
585
Arman Ugurayf4c61812013-01-10 18:58:39 -0800586 CellularService::OLP olp;
587 olp.CopyFrom(*result);
Ben Chan6d0d1e72012-11-06 21:19:28 -0800588 string post_data = olp.GetPostData();
589 ReplaceSubstringsAfterOffset(&post_data, 0, "${esn}", esn_);
590 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
591 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
592 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
593 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}", mdn_);
594 ReplaceSubstringsAfterOffset(&post_data, 0, "${meid}", meid_);
595 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
596 olp.SetPostData(post_data);
597 cellular()->service()->SetOLP(olp);
598}
599
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400600void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700601 SLOG(Cellular, 2) << __func__;
Ben Chan092b12b2012-11-07 22:04:05 -0800602
603 // If service activation is required, |serving_operator_| may not have an
604 // operator ID. Use |operator_id_| as a fallback when available.
605 // |operator_id_| is retrieved from the SIM card.
606 if (IsServiceActivationRequired() && serving_operator_.GetCode().empty() &&
607 !operator_id_.empty()) {
608 SLOG(Cellular, 2) << "Assuming operator '" << operator_id_
609 << "' as serving operator.";
610 serving_operator_.SetCode(operator_id_);
611 }
612
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400613 const string &network_id = serving_operator_.GetCode();
614 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700615 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400616 mobile_provider *provider =
617 mobile_provider_lookup_by_network(cellular()->provider_db(),
618 network_id.c_str());
619 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200620 if (serving_operator_.GetName().empty()) {
621 const char *provider_name = mobile_provider_get_name(provider);
622 if (provider_name && *provider_name) {
623 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400624 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400625 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200626 if (provider->country && *provider->country) {
627 serving_operator_.SetCountry(provider->country);
628 }
629 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
630 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400631 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700632 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400633 }
634 }
635 UpdateServingOperator();
636}
637
638void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700639 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400640 if (cellular()->service().get()) {
641 cellular()->service()->SetServingOperator(serving_operator_);
642 }
643}
644
Arman Uguray6e5639f2012-11-15 20:30:19 -0800645void CellularCapabilityUniversal::UpdateBearerPath() {
646 SLOG(Cellular, 2) << __func__;
647 DBusPathsCallback cb = Bind(&CellularCapabilityUniversal::OnListBearersReply,
648 weak_ptr_factory_.GetWeakPtr());
649 Error error;
650 modem_proxy_->ListBearers(&error, cb, kTimeoutDefault);
651}
652
653void CellularCapabilityUniversal::OnListBearersReply(
654 const std::vector<DBus::Path> &paths,
655 const Error &error) {
656 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
657 if (error.IsFailure()) {
658 SLOG(Cellular, 2) << "ListBearers failed with error: " << error;
659 return;
660 }
661 // Look for the first active bearer and use its path as the connected
662 // one. Right now, we don't allow more than one active bearer.
663 bool found_active = false;
664 for (size_t i = 0; i < paths.size(); ++i) {
665 const DBus::Path &path = paths[i];
666 scoped_ptr<mm1::BearerProxyInterface> bearer_proxy(
667 proxy_factory()->CreateBearerProxy(path, cellular()->dbus_owner()));
668 bool is_active = bearer_proxy->Connected();
669 if (is_active) {
670 if (!found_active) {
671 SLOG(Cellular, 2) << "Found active bearer \"" << path << "\".";
672 bearer_path_ = path;
673 found_active = true;
674 } else {
675 LOG(FATAL) << "Found more than one active bearer.";
676 }
677 }
678 }
679 if (!found_active) {
680 SLOG(Cellular, 2) << "No active bearer found, clearing bearer_path_.";
681 bearer_path_.clear();
682 }
683}
684
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400685void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700686 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400687 if (!home_provider_) {
688 return;
689 }
690 apn_list_.clear();
691 for (int i = 0; i < home_provider_->num_apns; ++i) {
692 Stringmap props;
693 mobile_apn *apn = home_provider_->apns[i];
694 if (apn->value) {
695 props[flimflam::kApnProperty] = apn->value;
696 }
697 if (apn->username) {
698 props[flimflam::kApnUsernameProperty] = apn->username;
699 }
700 if (apn->password) {
701 props[flimflam::kApnPasswordProperty] = apn->password;
702 }
703 // Find the first localized and non-localized name, if any.
704 const localized_name *lname = NULL;
705 const localized_name *name = NULL;
706 for (int j = 0; j < apn->num_names; ++j) {
707 if (apn->names[j]->lang) {
708 if (!lname) {
709 lname = apn->names[j];
710 }
711 } else if (!name) {
712 name = apn->names[j];
713 }
714 }
715 if (name) {
716 props[flimflam::kApnNameProperty] = name->name;
717 }
718 if (lname) {
719 props[flimflam::kApnLocalizedNameProperty] = lname->name;
720 props[flimflam::kApnLanguageProperty] = lname->lang;
721 }
722 apn_list_.push_back(props);
723 }
Darin Petkovdb6083f2012-08-16 12:50:23 +0200724 if (cellular()->adaptor()) {
725 cellular()->adaptor()->EmitStringmapsChanged(
726 flimflam::kCellularApnListProperty, apn_list_);
727 } else {
728 LOG(ERROR) << "Null RPC service adaptor.";
729 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400730}
731
Ben Chan15786032012-11-04 21:28:02 -0800732bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
733 // If there is no online payment portal information, it's safer to assume
734 // the service does not require activation.
735 if (!cellular()->cellular_operator_info())
736 return false;
737
Arman Ugurayf4c61812013-01-10 18:58:39 -0800738 const CellularService::OLP *olp =
739 cellular()->cellular_operator_info()->GetOLPByMCCMNC(operator_id_);
740 if (!olp)
Ben Chan15786032012-11-04 21:28:02 -0800741 return false;
742
743 // To avoid false positives, it's safer to assume the service does not
744 // require activation if MDN is not set.
745 if (mdn_.empty())
746 return false;
747
748 // If MDN contains only zeros ('+' and '-' characters are ignored),
749 // the service requires activation.
750 for (size_t i = 0; i < mdn_.size(); ++i) {
751 if (mdn_[i] != '0' && mdn_[i] != '-' && mdn_[i] != '+')
752 return false;
753 }
754 return true;
755}
756
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400757// always called from an async context
758void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700759 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400760 CHECK(!callback.is_null());
761 Error error;
762 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
763 weak_ptr_factory_.GetWeakPtr(), callback);
764 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
765 if (error.IsFailure())
766 callback.Run(error);
767}
768
769void CellularCapabilityUniversal::RegisterOnNetwork(
770 const string &network_id,
771 Error *error,
772 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700773 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400774 CHECK(error);
775 desired_network_ = network_id;
776 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
777 weak_ptr_factory_.GetWeakPtr(), callback);
778 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
779}
780
781void CellularCapabilityUniversal::OnRegisterReply(
782 const ResultCallback &callback,
783 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700784 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400785
786 if (error.IsSuccess()) {
787 selected_network_ = desired_network_;
788 desired_network_.clear();
789 callback.Run(error);
790 return;
791 }
792 // If registration on the desired network failed,
793 // try to register on the home network.
794 if (!desired_network_.empty()) {
795 desired_network_.clear();
796 selected_network_.clear();
797 LOG(INFO) << "Couldn't register on selected network, trying home network";
798 Register(callback);
799 return;
800 }
801 callback.Run(error);
802}
803
804bool CellularCapabilityUniversal::IsRegistered() {
805 return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
806 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
807}
808
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400809void CellularCapabilityUniversal::SetUnregistered(bool searching) {
810 // If we're already in some non-registered state, don't override that
811 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
812 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
813 registration_state_ =
814 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
815 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
816 }
817}
818
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400819void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400820 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400821 Error *error, const ResultCallback &callback) {
822 CHECK(error);
823 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
824}
825
826void CellularCapabilityUniversal::EnterPIN(const string &pin,
827 Error *error,
828 const ResultCallback &callback) {
829 CHECK(error);
830 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
831}
832
833void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
834 const string &pin,
835 Error *error,
836 const ResultCallback &callback) {
837 CHECK(error);
838 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
839}
840
841void CellularCapabilityUniversal::ChangePIN(
842 const string &old_pin, const string &new_pin,
843 Error *error, const ResultCallback &callback) {
844 CHECK(error);
845 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
846}
847
Ben Chan5d0d32c2013-01-08 02:05:29 -0800848void CellularCapabilityUniversal::Reset(Error *error,
849 const ResultCallback &callback) {
850 SLOG(Cellular, 2) << __func__;
851 CHECK(error);
852 if (resetting_) {
853 Error::PopulateAndLog(error, Error::kInProgress, "Already resetting");
854 return;
855 }
856 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
857 weak_ptr_factory_.GetWeakPtr(), callback);
858 modem_proxy_->Reset(error, cb, kTimeoutReset);
859 if (!error->IsFailure()) {
860 resetting_ = true;
861 }
862}
863
864void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
865 const Error &error) {
866 SLOG(Cellular, 2) << __func__;
867 resetting_ = false;
868 if (!callback.is_null())
869 callback.Run(error);
870}
871
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400872void CellularCapabilityUniversal::Scan(Error *error,
873 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700874 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400875 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400876 if (scanning_) {
877 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
878 return;
879 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400880 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
881 weak_ptr_factory_.GetWeakPtr(), callback);
882 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400883 if (!error->IsFailure()) {
884 scanning_ = true;
885 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
886 scanning_);
887 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400888}
889
890void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
891 const ScanResults &results,
892 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700893 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400894
895 // Error handling is weak. The current expectation is that on any
896 // error, found_networks_ should be cleared and a property change
897 // notification sent out.
898 //
899 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400900 scanning_ = false;
901 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
902 scanning_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400903 found_networks_.clear();
904 if (!error.IsFailure()) {
905 for (ScanResults::const_iterator it = results.begin();
906 it != results.end(); ++it) {
907 found_networks_.push_back(ParseScanResult(*it));
908 }
909 }
910 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
911 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -0700912
913 // TODO(gmorain): This check for is_null() is a work-around because
914 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
915 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
916 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
917 // Universal.
918 if (!callback.is_null())
919 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400920}
921
922Stringmap CellularCapabilityUniversal::ParseScanResult(
923 const ScanResult &result) {
924
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400925 /* ScanResults contain the following keys:
926
927 "status"
928 A MMModem3gppNetworkAvailability value representing network
929 availability status, given as an unsigned integer (signature "u").
930 This key will always be present.
931
932 "operator-long"
933 Long-format name of operator, given as a string value (signature
934 "s"). If the name is unknown, this field should not be present.
935
936 "operator-short"
937 Short-format name of operator, given as a string value
938 (signature "s"). If the name is unknown, this field should not
939 be present.
940
941 "operator-code"
942 Mobile code of the operator, given as a string value (signature
943 "s"). Returned in the format "MCCMNC", where MCC is the
944 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
945 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
946
947 "access-technology"
948 A MMModemAccessTechnology value representing the generic access
949 technology used by this mobile network, given as an unsigned
950 integer (signature "u").
951 */
952 Stringmap parsed;
953
954 uint32 status;
955 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
956 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
957 static const char * const kStatusString[] = {
958 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
959 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
960 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
961 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
962 };
963 parsed[flimflam::kStatusProperty] = kStatusString[status];
964 }
965
966 uint32 tech; // MMModemAccessTechnology
967 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
968 &tech)) {
969 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
970 }
971
972 string operator_long, operator_short, operator_code;
973 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
974 parsed[flimflam::kLongNameProperty] = operator_long;
975 if (DBusProperties::GetString(result, kOperatorShortProperty,
976 &operator_short))
977 parsed[flimflam::kShortNameProperty] = operator_short;
978 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
979 parsed[flimflam::kNetworkIdProperty] = operator_code;
980
981 // If the long name is not available but the network ID is, look up the long
982 // name in the mobile provider database.
983 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
984 parsed[flimflam::kLongNameProperty].empty()) &&
985 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
986 mobile_provider *provider =
987 mobile_provider_lookup_by_network(
988 cellular()->provider_db(),
989 parsed[flimflam::kNetworkIdProperty].c_str());
990 if (provider) {
991 const char *long_name = mobile_provider_get_name(provider);
992 if (long_name && *long_name) {
993 parsed[flimflam::kLongNameProperty] = long_name;
994 }
995 }
996 }
997 return parsed;
998}
999
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001000string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001001 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001002 // TODO(jglasgow): change shill interfaces to a capability model
1003
1004 return AccessTechnologyToString(access_technologies_);
1005}
1006
1007string CellularCapabilityUniversal::GetRoamingStateString() const {
1008 switch (registration_state_) {
1009 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1010 return flimflam::kRoamingStateHome;
1011 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1012 return flimflam::kRoamingStateRoaming;
1013 default:
1014 break;
1015 }
1016 return flimflam::kRoamingStateUnknown;
1017}
1018
1019void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -04001020 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
1021 const DBus::Struct<unsigned int, bool> quality =
1022 modem_proxy_->SignalQuality();
1023 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001024}
1025
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001026string CellularCapabilityUniversal::GetTypeString() const {
1027 return AccessTechnologyToTechnologyFamily(access_technologies_);
1028}
1029
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001030void CellularCapabilityUniversal::OnModemPropertiesChanged(
1031 const DBusPropertiesMap &properties,
1032 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001033 // This solves a bootstrapping problem: If the modem is not yet
1034 // enabled, there are no proxy objects associated with the capability
1035 // object, so modem signals like StateChanged aren't seen. By monitoring
1036 // changes to the State property via the ModemManager, we're able to
1037 // get the initialization process started, which will result in the
1038 // creation of the proxy objects.
1039 //
1040 // The first time we see the change to State (when the modem state
1041 // is Unknown), we simply update the state, and rely on the Manager to
1042 // enable the device when it is registered with the Manager. On subsequent
1043 // changes to State, we need to explicitly enable the device ourselves.
1044 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -04001045 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001046 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -04001047 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001048 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001049 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -04001050 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001051 MM_MODEM_PROPERTY_SIM, &string_value))
1052 OnSimPathChanged(string_value);
1053 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001054 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -04001055 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
1056 &uint_value))
1057 OnModemCapabilitesChanged(uint_value);
1058 if (DBusProperties::GetUint32(properties,
1059 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1060 &uint_value))
1061 OnModemCurrentCapabilitiesChanged(uint_value);
1062 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1063 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
1064 if (DBusProperties::GetString(properties,
1065 MM_MODEM_PROPERTY_MANUFACTURER,
1066 &string_value))
1067 OnModemManufacturerChanged(string_value);
1068 if (DBusProperties::GetString(properties,
1069 MM_MODEM_PROPERTY_MODEL,
1070 &string_value))
1071 OnModemModelChanged(string_value);
1072 if (DBusProperties::GetString(properties,
1073 MM_MODEM_PROPERTY_REVISION,
1074 &string_value))
1075 OnModemRevisionChanged(string_value);
1076 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1077 // not needed: MM_MODEM_PROPERTY_DEVICE
1078 // not needed: MM_MODEM_PROPERTY_DRIVER
1079 // not needed: MM_MODEM_PROPERTY_PLUGIN
1080 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -04001081
Jason Glasgowaf583282012-04-18 15:18:22 -04001082 // Unlock required and SimLock
1083 bool locks_changed = false;
1084 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001085 if (DBusProperties::GetUint32(properties,
1086 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -04001087 &unlock_required)) {
1088 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001089 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001090 LockRetryData lock_retries;
1091 DBusPropertiesMap::const_iterator it =
1092 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
1093 if (it != properties.end()) {
1094 lock_retries = it->second;
1095 locks_changed = true;
1096 }
1097 if (locks_changed)
1098 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
1099 lock_retries);
1100 if (DBusProperties::GetUint32(properties,
1101 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1102 &uint_value))
1103 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001104
Jason Glasgowaf583282012-04-18 15:18:22 -04001105 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1106 if (it != properties.end()) {
1107 DBus::Struct<unsigned int, bool> quality = it->second;
1108 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001109 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001110 vector<string> numbers;
1111 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1112 &numbers)) {
1113 string mdn;
1114 if (numbers.size() > 0)
1115 mdn = numbers[0];
1116 OnMdnChanged(mdn);
1117 }
1118 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
1119 &uint_value))
1120 OnSupportedModesChanged(uint_value);
1121 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
1122 &uint_value))
1123 OnAllowedModesChanged(uint_value);
1124 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
1125 &uint_value))
1126 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
1127 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1128 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001129}
1130
1131void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1132 const string &interface,
1133 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001134 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001135 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001136 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001137 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001138 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001139 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1140 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001141 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001142 if (interface == MM_DBUS_INTERFACE_SIM) {
1143 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001144 }
1145}
1146
Jason Glasgow14521872012-05-07 19:12:15 -04001147bool CellularCapabilityUniversal::RetriableConnectError(
1148 const Error &error) const {
1149 if (error.type() == Error::kInvalidApn)
1150 return true;
1151
1152 // modemmanager does not ever return kInvalidApn for E362 modems
1153 // with 1.41 firmware. It remains to be seem if this will change
1154 // with 3.x firmware.
1155 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1156 return true;
1157
1158 return false;
1159}
1160
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001161void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1162 // TODO(petkov): Implement this.
1163 NOTIMPLEMENTED();
1164}
1165
Jason Glasgowaf583282012-04-18 15:18:22 -04001166void CellularCapabilityUniversal::OnSimPathChanged(
1167 const string &sim_path) {
1168 if (sim_path == sim_path_)
1169 return;
1170
1171 mm1::SimProxyInterface *proxy = NULL;
1172 if (!sim_path.empty())
1173 proxy = proxy_factory()->CreateSimProxy(sim_path,
1174 cellular()->dbus_owner());
1175 sim_path_ = sim_path;
1176 sim_proxy_.reset(proxy);
1177
1178 if (sim_path.empty()) {
1179 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001180 imsi_ = "";
1181 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001182 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001183 OnSimIdentifierChanged("");
1184 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001185 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001186 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001187 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1188 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1189 cellular()->dbus_owner()));
1190 // TODO(jglasgow): convert to async interface
1191 DBusPropertiesMap properties(
1192 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1193 OnSimPropertiesChanged(properties, vector<string>());
1194 }
1195}
1196
1197void CellularCapabilityUniversal::OnModemCapabilitesChanged(
1198 uint32 capabilities) {
1199 capabilities_ = capabilities;
1200}
1201
1202void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1203 uint32 current_capabilities) {
1204 current_capabilities_ = current_capabilities;
1205}
1206
1207void CellularCapabilityUniversal::OnMdnChanged(
1208 const string &mdn) {
1209 mdn_ = mdn;
1210}
1211
1212void CellularCapabilityUniversal::OnModemManufacturerChanged(
1213 const string &manufacturer) {
1214 manufacturer_ = manufacturer;
1215}
1216
1217void CellularCapabilityUniversal::OnModemModelChanged(
1218 const string &model) {
1219 model_id_ = model;
1220}
1221
1222void CellularCapabilityUniversal::OnModemRevisionChanged(
1223 const string &revision) {
1224 firmware_revision_ = revision;
1225}
1226
1227void CellularCapabilityUniversal::OnModemStateChanged(
1228 Cellular::ModemState state) {
1229 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1230 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1231 if (Cellular::IsEnabledModemState(state))
1232 cellular()->set_modem_state(state);
Gary Moraine285a842012-08-15 08:23:57 -07001233 SLOG(Cellular, 2) << __func__ << ": prev_modem_state: " << prev_modem_state
1234 << " was_enabled: " << was_enabled
1235 << " cellular state: "
1236 << cellular()->GetStateString(cellular()->state());
Jason Glasgowaf583282012-04-18 15:18:22 -04001237 if (prev_modem_state != Cellular::kModemStateUnknown &&
1238 prev_modem_state != Cellular::kModemStateEnabling &&
1239 !was_enabled &&
1240 cellular()->state() == Cellular::kStateDisabled &&
1241 cellular()->IsUnderlyingDeviceEnabled()) {
1242 cellular()->SetEnabled(true);
1243 }
1244}
1245
1246void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1247 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001248 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001249 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001250 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001251 const string new_type_string(GetTypeString());
1252 if (new_type_string != old_type_string) {
1253 // TODO(jglasgow): address layering violation of emitting change
1254 // signal here for a property owned by Cellular.
1255 cellular()->adaptor()->EmitStringChanged(
1256 flimflam::kTechnologyFamilyProperty, new_type_string);
1257 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001258 if (cellular()->service().get()) {
1259 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1260 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001261 }
1262}
1263
1264void CellularCapabilityUniversal::OnSupportedModesChanged(
1265 uint32 supported_modes) {
1266 supported_modes_ = supported_modes;
1267}
1268
1269void CellularCapabilityUniversal::OnAllowedModesChanged(
1270 uint32 allowed_modes) {
1271 allowed_modes_ = allowed_modes;
1272}
1273
1274void CellularCapabilityUniversal::OnPreferredModeChanged(
1275 MMModemMode preferred_mode) {
1276 preferred_mode_ = preferred_mode;
1277}
1278
1279void CellularCapabilityUniversal::OnLockRetriesChanged(
1280 MMModemLock unlock_required,
1281 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001282 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001283 case MM_MODEM_LOCK_SIM_PIN:
1284 sim_lock_status_.lock_type = "sim-pin";
1285 break;
1286 case MM_MODEM_LOCK_SIM_PUK:
1287 sim_lock_status_.lock_type = "sim-puk";
1288 break;
1289 default:
1290 sim_lock_status_.lock_type = "";
1291 break;
1292 }
1293 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1294 if (it != lock_retries.end()) {
1295 sim_lock_status_.retries_left = it->second;
1296 } else {
1297 // Unknown, use 999
1298 sim_lock_status_.retries_left = 999;
1299 }
1300 OnSimLockStatusChanged();
1301}
1302
1303void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1304 cellular()->adaptor()->EmitKeyValueStoreChanged(
1305 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
Arman Ugurayab9364e2012-12-19 20:45:25 -08001306
1307 // If the SIM is currently unlocked, assume that we need to refresh
1308 // carrier information, since a locked SIM prevents shill from obtaining
1309 // the necessary data to establish a connection later (e.g. IMSI).
1310 if (!sim_path_.empty() && sim_lock_status_.lock_type.empty()) {
1311 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1312 proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1313 cellular()->dbus_owner()));
1314 DBusPropertiesMap properties(
1315 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1316 OnSimPropertiesChanged(properties, vector<string>());
1317 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001318}
1319
1320void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1321 const DBusPropertiesMap &properties,
1322 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001323 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001324 string imei;
1325 if (DBusProperties::GetString(properties,
1326 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1327 &imei))
1328 OnImeiChanged(imei);
1329
1330 // Handle registration state changes as a single change
1331 string operator_code = serving_operator_.GetCode();
1332 string operator_name = serving_operator_.GetName();
1333 MMModem3gppRegistrationState state = registration_state_;
1334 bool registration_changed = false;
1335 uint32 uint_value;
1336 if (DBusProperties::GetUint32(properties,
1337 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1338 &uint_value)) {
1339 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1340 registration_changed = true;
1341 }
1342 if (DBusProperties::GetString(properties,
1343 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1344 &operator_code))
1345 registration_changed = true;
1346 if (DBusProperties::GetString(properties,
1347 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1348 &operator_name))
1349 registration_changed = true;
1350 if (registration_changed)
1351 On3GPPRegistrationChanged(state, operator_code, operator_name);
1352
1353 uint32 locks = 0;
1354 if (DBusProperties::GetUint32(
1355 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1356 &locks))
1357 OnFacilityLocksChanged(locks);
1358}
1359
1360void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1361 imei_ = imei;
1362}
1363
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001364void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1365 MMModem3gppRegistrationState state,
1366 const string &operator_code,
1367 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001368 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1369 << ", opercode=" << operator_code
1370 << ", opername=" << operator_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001371 registration_state_ = state;
1372 serving_operator_.SetCode(operator_code);
1373 serving_operator_.SetName(operator_name);
1374 UpdateOperatorInfo();
1375 cellular()->HandleNewRegistrationState();
1376}
1377
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001378void CellularCapabilityUniversal::OnModemStateChangedSignal(
1379 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001380 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1381 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001382 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1383 static_cast<Cellular::ModemState>(new_state),
1384 reason);
Gary Moraine285a842012-08-15 08:23:57 -07001385 if (!deferred_enable_modem_callback_.is_null() &&
1386 (new_state == Cellular::kModemStateDisabled)) {
1387 SLOG(Cellular, 2) << "Enabling modem after deferring";
1388 deferred_enable_modem_callback_.Run();
1389 deferred_enable_modem_callback_.Reset();
Arman Uguray6e5639f2012-11-15 20:30:19 -08001390 } else if (new_state == Cellular::kModemStateConnected) {
1391 SLOG(Cellular, 2) << "Updating bearer path to reflect the active bearer.";
1392 UpdateBearerPath();
Gary Moraine285a842012-08-15 08:23:57 -07001393 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001394}
1395
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001396void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1397 cellular()->HandleNewSignalQuality(quality);
1398}
1399
Jason Glasgowaf583282012-04-18 15:18:22 -04001400void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1401 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1402 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1403 OnSimLockStatusChanged();
1404 }
1405}
Jason Glasgowef965562012-04-10 16:12:35 -04001406
Jason Glasgowaf583282012-04-18 15:18:22 -04001407void CellularCapabilityUniversal::OnSimPropertiesChanged(
1408 const DBusPropertiesMap &props,
1409 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001410 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001411 string value;
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001412 bool must_update_home_provider = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001413 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1414 OnSimIdentifierChanged(value);
1415 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1416 &value))
1417 OnOperatorIdChanged(value);
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001418 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value)) {
1419 spn_ = value;
1420 must_update_home_provider = true;
1421 }
1422 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
1423 imsi_ = value;
1424 must_update_home_provider = true;
1425 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001426 // TODO(jglasgow): May eventually want to get SPDI, etc
Jason Glasgowaf583282012-04-18 15:18:22 -04001427
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001428 if (must_update_home_provider)
1429 SetHomeProvider();
Jason Glasgowaf583282012-04-18 15:18:22 -04001430}
1431
1432void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1433 sim_identifier_ = id;
1434}
1435
1436void CellularCapabilityUniversal::OnOperatorIdChanged(
1437 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001438 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04001439 operator_id_ = operator_id;
1440}
1441
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001442} // namespace shill