blob: 016e28858a8f17e33c1325e721172b34ac36531a [file] [log] [blame]
Darin Petkovc64fe5e2012-01-11 12:46:13 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkovdaf43862011-10-27 11:37:28 +02002// 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_gsm.h"
6
Jason Glasgow4c0724a2012-04-17 15:47:40 -04007#include <string>
8#include <vector>
9
Eric Shienbrood3e20a232012-02-16 11:35:56 -050010#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020011#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010013#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010014#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010015#include <chromeos/dbus/service_constants.h>
16#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010017#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020018
Darin Petkov3cfbf212011-11-21 16:02:09 +010019#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010020#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050021#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010022#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020023#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070024#include "shill/scope_logger.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020025
Eric Shienbrood3e20a232012-02-16 11:35:56 -050026using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010027using std::string;
Jason Glasgow4c0724a2012-04-17 15:47:40 -040028using std::vector;
Darin Petkovb05315f2011-11-07 10:14:25 +010029
Darin Petkovdaf43862011-10-27 11:37:28 +020030namespace shill {
31
Darin Petkovac635a82012-01-10 16:51:58 +010032// static
33unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
34
Darin Petkov1272a432011-11-10 15:53:37 +010035const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
36 "access-tech";
37const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
38const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
39const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
40 "operator-short";
41const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010042const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
43const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
44 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010045const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
46 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010047const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
48const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010049
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050050CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
51 ProxyFactory *proxy_factory)
Jason Glasgow82f9ab32012-04-04 14:27:19 -040052 : CellularCapabilityClassic(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050053 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010054 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010055 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010056 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010057 scanning_(false),
58 scan_interval_(0) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070059 SLOG(Cellular, 2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010060 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010061 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
62 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010063 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
64 &found_networks_);
65 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
66 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010067 HelpRegisterDerivedKeyValueStore(
68 flimflam::kSIMLockStatusProperty,
69 &CellularCapabilityGSM::SimLockStatusToProperty,
70 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010071 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
72 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010073 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010074}
Darin Petkovdaf43862011-10-27 11:37:28 +020075
Darin Petkov63138a92012-02-06 14:09:15 +010076KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
77 KeyValueStore status;
78 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
79 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
80 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
81 sim_lock_status_.retries_left);
82 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010083}
84
Darin Petkov63138a92012-02-06 14:09:15 +010085void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010086 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010087 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
88 void(CellularCapabilityGSM::*set)(
89 const KeyValueStore &value, Error *error)) {
90 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010091 name,
Darin Petkov63138a92012-02-06 14:09:15 +010092 KeyValueStoreAccessor(
93 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +010094 this, get, set)));
95}
96
Eric Shienbrood9a245532012-03-07 14:20:39 -050097void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040098 CellularCapabilityClassic::InitProxies();
Darin Petkovcb547732011-11-09 13:55:26 +010099 card_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500100 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200101 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +0100102 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500103 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200104 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500105 network_proxy_->set_signal_quality_callback(
106 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
107 weak_ptr_factory_.GetWeakPtr()));
108 network_proxy_->set_network_mode_callback(
109 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
110 weak_ptr_factory_.GetWeakPtr()));
111 network_proxy_->set_registration_info_callback(
112 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
113 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200114}
115
Eric Shienbrood9a245532012-03-07 14:20:39 -0500116void CellularCapabilityGSM::StartModem(Error *error,
117 const ResultCallback &callback) {
118 InitProxies();
119
120 CellularTaskList *tasks = new CellularTaskList();
121 ResultCallback cb =
122 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700123 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
124 ResultCallback cb_ignore_error =
125 Bind(&CellularCapabilityGSM::StepCompletedCallback,
126 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400127 if (!cellular()->IsUnderlyingDeviceEnabled())
128 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
129 weak_ptr_factory_.GetWeakPtr(), cb));
130 // If we're within range of the home network, the modem will try to
131 // register once it's enabled, or may be already registered if we
132 // started out enabled.
133 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
134 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
135 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500136 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
137 weak_ptr_factory_.GetWeakPtr(), cb));
138 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
139 weak_ptr_factory_.GetWeakPtr(), cb));
140 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700141 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500142 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700143 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500144 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
145 weak_ptr_factory_.GetWeakPtr(), cb));
146 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400147 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500148 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
149 weak_ptr_factory_.GetWeakPtr(), cb));
150
151 RunNextStep(tasks);
152}
153
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400154bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
155 switch (cellular()->modem_state()) {
156 case Cellular::kModemStateUnknown:
157 case Cellular::kModemStateDisabled:
158 case Cellular::kModemStateInitializing:
159 case Cellular::kModemStateLocked:
160 case Cellular::kModemStateDisabling:
161 case Cellular::kModemStateEnabling:
162 case Cellular::kModemStateEnabled:
163 return false;
164 case Cellular::kModemStateSearching:
165 case Cellular::kModemStateRegistered:
166 case Cellular::kModemStateDisconnecting:
167 case Cellular::kModemStateConnecting:
168 case Cellular::kModemStateConnected:
169 return true;
170 }
171 return false;
172}
173
Eric Shienbrood9a245532012-03-07 14:20:39 -0500174void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700175 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400176 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100177 card_proxy_.reset();
178 network_proxy_.reset();
179}
180
Darin Petkov5f316f62011-11-18 12:10:26 +0100181void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100182 // If IMSI is available, base the service's storage identifier on it.
183 if (!imsi_.empty()) {
184 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100185 string(flimflam::kTypeCellular) + "_" +
186 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100187 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100188 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100189 flimflam::kActivationStateActivated);
190 UpdateServingOperator();
191}
192
Darin Petkovae0c64e2011-11-15 15:50:27 +0100193void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400194 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100195 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100196 }
197}
198
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400199// Create the list of APNs to try, in the following order:
200// - last APN that resulted in a successful connection attempt on the
201// current network (if any)
202// - the APN, if any, that was set by the user
203// - the list of APNs found in the mobile broadband provider DB for the
204// home provider associated with the current SIM
205// - as a last resort, attempt to connect with no APN
206void CellularCapabilityGSM::SetupApnTryList() {
207 apn_try_list_.clear();
208
209 DCHECK(cellular()->service().get());
210 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
211 if (apn_info)
212 apn_try_list_.push_back(*apn_info);
213
214 apn_info = cellular()->service()->GetUserSpecifiedApn();
215 if (apn_info)
216 apn_try_list_.push_back(*apn_info);
217
218 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
219}
220
Darin Petkovae0c64e2011-11-15 15:50:27 +0100221void CellularCapabilityGSM::SetupConnectProperties(
222 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400223 SetupApnTryList();
224 FillConnectPropertyMap(properties);
225}
226
227void CellularCapabilityGSM::FillConnectPropertyMap(
228 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500229 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100230 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400231
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400232 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400233 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
234
235 if (!apn_try_list_.empty()) {
236 // Leave the APN at the front of the list, so that it can be recorded
237 // if the connect attempt succeeds.
238 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700239 SLOG(Cellular, 2) << __func__ << ": Using APN "
240 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400241 (*properties)[kConnectPropertyApn].writer().append_string(
242 apn_info[flimflam::kApnProperty].c_str());
243 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
244 (*properties)[kConnectPropertyApnUsername].writer().append_string(
245 apn_info[flimflam::kApnUsernameProperty].c_str());
246 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
247 (*properties)[kConnectPropertyApnPassword].writer().append_string(
248 apn_info[flimflam::kApnPasswordProperty].c_str());
249 }
250}
251
Nathan Williamsb54974f2012-04-19 11:16:30 -0400252void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
253 Error *error,
254 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700255 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400256 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
257 weak_ptr_factory_.GetWeakPtr(),
258 callback);
259 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
260}
261
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400262void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
263 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700264 CellularServiceRefPtr service = cellular()->service();
265 if (!service) {
266 // The service could have been deleted before our Connect() request
267 // completes if the modem was enabled and then quickly disabled.
268 apn_try_list_.clear();
269 } else if (error.IsFailure()) {
270 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400271 // The APN that was just tried (and failed) is still at the
272 // front of the list, about to be removed. If the list is empty
273 // after that, try one last time without an APN. This may succeed
274 // with some modems in some cases.
275 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
276 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700277 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
278 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400279 DBusPropertiesMap props;
280 FillConnectPropertyMap(&props);
281 Error error;
282 Connect(props, &error, callback);
283 return;
284 }
285 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700286 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400287 apn_try_list_.clear();
288 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400289 if (!callback.is_null())
290 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400291}
292
293bool CellularCapabilityGSM::AllowRoaming() {
294 bool requires_roaming =
295 home_provider_ ? home_provider_->requires_roaming : false;
296 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100297}
298
Eric Shienbrood9a245532012-03-07 14:20:39 -0500299// always called from an async context
300void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700301 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500302 CHECK(!callback.is_null());
303 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500304 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500305 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
306 weak_ptr_factory_.GetWeakPtr(), callback);
307 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
308 if (error.IsFailure())
309 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500310 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700311 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500312 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100313 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500314}
315
Eric Shienbrood9a245532012-03-07 14:20:39 -0500316// always called from an async context
317void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700318 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500319 CHECK(!callback.is_null());
320 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500321 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500322 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
323 weak_ptr_factory_.GetWeakPtr(),
324 callback);
325 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
326 if (error.IsFailure())
327 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500328 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700329 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500330 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100331 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500332}
333
Eric Shienbrood9a245532012-03-07 14:20:39 -0500334// always called from an async context
335void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700336 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500337 CHECK(!callback.is_null());
338 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100339 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500340 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
341 weak_ptr_factory_.GetWeakPtr(),
342 callback);
343 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
344 if (error.IsFailure())
345 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500346 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700347 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500348 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100349 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500350}
351
Eric Shienbrood9a245532012-03-07 14:20:39 -0500352// always called from an async context
353void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700354 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500355 CHECK(!callback.is_null());
356 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500357 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500358 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
359 weak_ptr_factory_.GetWeakPtr(),
360 callback);
361 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
362 if (error.IsFailure())
363 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500364 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700365 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500366 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100367 }
368}
369
Darin Petkov3e509242011-11-10 14:46:44 +0100370void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700371 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500372 SignalQualityCallback callback =
373 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
374 weak_ptr_factory_.GetWeakPtr());
375 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100376}
377
Eric Shienbrood9a245532012-03-07 14:20:39 -0500378void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700379 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500380 RegistrationInfoCallback callback =
381 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
382 weak_ptr_factory_.GetWeakPtr());
383 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100384}
385
Eric Shienbrood9a245532012-03-07 14:20:39 -0500386void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700387 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100388
Darin Petkov184c54e2011-11-15 12:44:39 +0100389 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
390 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100391 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700392 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100393
394 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
395 uint32 locks = card_proxy_->EnabledFacilityLocks();
396 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700397 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100398
Eric Shienbrood9a245532012-03-07 14:20:39 -0500399 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100400}
401
Darin Petkovac635a82012-01-10 16:51:58 +0100402string CellularCapabilityGSM::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700403 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100404 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
405 !cellular()->home_provider().GetName().empty()) {
406 return cellular()->home_provider().GetName();
407 }
408 if (!serving_operator_.GetName().empty()) {
409 return serving_operator_.GetName();
410 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500411 if (!carrier_.empty()) {
412 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100413 }
414 if (!serving_operator_.GetCode().empty()) {
415 return "cellular_" + serving_operator_.GetCode();
416 }
417 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
418}
419
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100420void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700421 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
422 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100423 // TODO(petkov): The test for NULL provider_db should be done by
424 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500425 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100426 return;
427 }
428 mobile_provider *provider =
429 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500430 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100431 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700432 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100433 return;
434 }
435 home_provider_ = provider;
436 Cellular::Operator oper;
437 if (provider->networks) {
438 oper.SetCode(provider->networks[0]);
439 }
440 if (provider->country) {
441 oper.SetCountry(provider->country);
442 }
443 if (spn_.empty()) {
444 const char *name = mobile_provider_get_name(provider);
445 if (name) {
446 oper.SetName(name);
447 }
448 } else {
449 oper.SetName(spn_);
450 }
451 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100452 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100453}
454
Darin Petkovae0c64e2011-11-15 15:50:27 +0100455void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700456 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100457 const string &network_id = serving_operator_.GetCode();
458 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700459 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100460 mobile_provider *provider =
461 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100462 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100463 if (provider) {
464 const char *provider_name = mobile_provider_get_name(provider);
465 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100466 serving_operator_.SetName(provider_name);
467 if (provider->country) {
468 serving_operator_.SetCountry(provider->country);
469 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700470 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
471 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100472 }
473 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700474 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100475 }
476 }
477 UpdateServingOperator();
478}
479
480void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700481 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100482 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100483 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100484 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100485}
486
Darin Petkov3cfbf212011-11-21 16:02:09 +0100487void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700488 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100489 if (!home_provider_) {
490 return;
491 }
492 apn_list_.clear();
493 for (int i = 0; i < home_provider_->num_apns; ++i) {
494 Stringmap props;
495 mobile_apn *apn = home_provider_->apns[i];
496 if (apn->value) {
497 props[flimflam::kApnProperty] = apn->value;
498 }
499 if (apn->username) {
500 props[flimflam::kApnUsernameProperty] = apn->username;
501 }
502 if (apn->password) {
503 props[flimflam::kApnPasswordProperty] = apn->password;
504 }
505 // Find the first localized and non-localized name, if any.
506 const localized_name *lname = NULL;
507 const localized_name *name = NULL;
508 for (int j = 0; j < apn->num_names; ++j) {
509 if (apn->names[j]->lang) {
510 if (!lname) {
511 lname = apn->names[j];
512 }
513 } else if (!name) {
514 name = apn->names[j];
515 }
516 }
517 if (name) {
518 props[flimflam::kApnNameProperty] = name->name;
519 }
520 if (lname) {
521 props[flimflam::kApnLocalizedNameProperty] = lname->name;
522 props[flimflam::kApnLanguageProperty] = lname->lang;
523 }
524 apn_list_.push_back(props);
525 }
526 cellular()->adaptor()->EmitStringmapsChanged(
527 flimflam::kCellularApnListProperty, apn_list_);
528}
529
Eric Shienbrood9a245532012-03-07 14:20:39 -0500530// always called from an async context
531void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700532 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500533 CHECK(!callback.is_null());
534 Error error;
535 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
536 weak_ptr_factory_.GetWeakPtr(), callback);
537 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
538 if (error.IsFailure())
539 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100540}
541
542void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500543 const string &network_id,
544 Error *error,
545 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700546 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500547 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500548 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500549 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
550 weak_ptr_factory_.GetWeakPtr(), callback);
551 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500552}
553
Eric Shienbrood9a245532012-03-07 14:20:39 -0500554void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
555 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700556 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500557
558 if (error.IsSuccess()) {
559 selected_network_ = desired_network_;
560 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500561 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500562 return;
563 }
564 // If registration on the desired network failed,
565 // try to register on the home network.
566 if (!desired_network_.empty()) {
567 desired_network_.clear();
568 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500569 LOG(INFO) << "Couldn't register on selected network, trying home network";
570 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500571 return;
572 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500573 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100574}
575
Darin Petkovb72cf402011-11-22 14:51:39 +0100576bool CellularCapabilityGSM::IsRegistered() {
577 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
578 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
579}
580
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400581void CellularCapabilityGSM::SetUnregistered(bool searching) {
582 // If we're already in some non-registered state, don't override that
583 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
584 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
585 registration_state_ =
586 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
587 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
588 }
589}
590
Darin Petkovb05315f2011-11-07 10:14:25 +0100591void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500592 const std::string &pin, bool require,
593 Error *error, const ResultCallback &callback) {
594 CHECK(error);
595 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100596}
597
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100598void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500599 Error *error,
600 const ResultCallback &callback) {
601 CHECK(error);
602 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100603}
604
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100605void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
606 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500607 Error *error,
608 const ResultCallback &callback) {
609 CHECK(error);
610 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100611}
612
613void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500614 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500615 Error *error, const ResultCallback &callback) {
616 CHECK(error);
617 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100618}
619
Eric Shienbrood9a245532012-03-07 14:20:39 -0500620void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700621 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500622 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400623 if (scanning_) {
624 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
625 return;
626 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500627 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
628 weak_ptr_factory_.GetWeakPtr(), callback);
629 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400630 if (!error->IsFailure()) {
631 scanning_ = true;
632 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
633 scanning_);
634 }
Darin Petkov1272a432011-11-10 15:53:37 +0100635}
636
Eric Shienbrood9a245532012-03-07 14:20:39 -0500637void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
638 const GSMScanResults &results,
639 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700640 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400641
642 // Error handling is weak. The current expectation is that on any
643 // error, found_networks_ should be cleared and a property change
644 // notification sent out.
645 //
646 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400647 scanning_ = false;
648 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
649 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500650 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400651 if (!error.IsFailure()) {
652 for (GSMScanResults::const_iterator it = results.begin();
653 it != results.end(); ++it) {
654 found_networks_.push_back(ParseScanResult(*it));
655 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500656 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100657 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
658 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700659 if (!callback.is_null())
660 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500661}
662
663Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100664 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500665 for (GSMScanResult::const_iterator it = result.begin();
666 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100667 // TODO(petkov): Define these in system_api/service_constants.h. The
668 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
669 static const char * const kStatusString[] = {
670 "unknown",
671 "available",
672 "current",
673 "forbidden",
674 };
675 static const char * const kTechnologyString[] = {
676 flimflam::kNetworkTechnologyGsm,
677 "GSM Compact",
678 flimflam::kNetworkTechnologyUmts,
679 flimflam::kNetworkTechnologyEdge,
680 "HSDPA",
681 "HSUPA",
682 flimflam::kNetworkTechnologyHspa,
683 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700684 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
685 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100686 if (it->first == kNetworkPropertyStatus) {
687 int status = 0;
688 if (base::StringToInt(it->second, &status) &&
689 status >= 0 &&
690 status < static_cast<int>(arraysize(kStatusString))) {
691 parsed[flimflam::kStatusProperty] = kStatusString[status];
692 } else {
693 LOG(ERROR) << "Unexpected status value: " << it->second;
694 }
695 } else if (it->first == kNetworkPropertyID) {
696 parsed[flimflam::kNetworkIdProperty] = it->second;
697 } else if (it->first == kNetworkPropertyLongName) {
698 parsed[flimflam::kLongNameProperty] = it->second;
699 } else if (it->first == kNetworkPropertyShortName) {
700 parsed[flimflam::kShortNameProperty] = it->second;
701 } else if (it->first == kNetworkPropertyAccessTechnology) {
702 int tech = 0;
703 if (base::StringToInt(it->second, &tech) &&
704 tech >= 0 &&
705 tech < static_cast<int>(arraysize(kTechnologyString))) {
706 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
707 } else {
708 LOG(ERROR) << "Unexpected technology value: " << it->second;
709 }
710 } else {
711 LOG(WARNING) << "Unknown network property ignored: " << it->first;
712 }
713 }
714 // If the long name is not available but the network ID is, look up the long
715 // name in the mobile provider database.
716 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
717 parsed[flimflam::kLongNameProperty].empty()) &&
718 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
719 mobile_provider *provider =
720 mobile_provider_lookup_by_network(
721 cellular()->provider_db(),
722 parsed[flimflam::kNetworkIdProperty].c_str());
723 if (provider) {
724 const char *long_name = mobile_provider_get_name(provider);
725 if (long_name && *long_name) {
726 parsed[flimflam::kLongNameProperty] = long_name;
727 }
728 }
729 }
730 return parsed;
731}
732
Darin Petkovae0c64e2011-11-15 15:50:27 +0100733void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
734 access_technology_ = access_technology;
735 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100736 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100737 }
738}
739
Darin Petkov20c13ec2011-11-09 15:07:15 +0100740string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100741 switch (access_technology_) {
742 case MM_MODEM_GSM_ACCESS_TECH_GSM:
743 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
744 return flimflam::kNetworkTechnologyGsm;
745 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
746 return flimflam::kNetworkTechnologyGprs;
747 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
748 return flimflam::kNetworkTechnologyEdge;
749 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
750 return flimflam::kNetworkTechnologyUmts;
751 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
752 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
753 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
754 return flimflam::kNetworkTechnologyHspa;
755 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
756 return flimflam::kNetworkTechnologyHspaPlus;
757 default:
758 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100759 }
760 return "";
761}
762
763string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100764 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100765 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
766 return flimflam::kRoamingStateHome;
767 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
768 return flimflam::kRoamingStateRoaming;
769 default:
770 break;
771 }
772 return flimflam::kRoamingStateUnknown;
773}
774
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400775void CellularCapabilityGSM::OnDBusPropertiesChanged(
776 const string &interface,
777 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400778 const vector<string> &invalidated_properties) {
779 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
780 properties,
781 invalidated_properties);
782 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
783 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
784 if (DBusProperties::GetUint32(properties,
785 kPropertyAccessTechnology,
786 &access_technology)) {
787 SetAccessTechnology(access_technology);
788 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700789 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400790 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700791 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
792 uint32 locks = 0;
793 if (DBusProperties::GetUint32(
794 properties, kPropertyEnabledFacilityLocks, &locks)) {
795 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
796 emit = true;
797 }
798 } else if (interface == MM_MODEM_INTERFACE) {
799 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
800 &sim_lock_status_.lock_type)) {
801 emit = true;
802 }
803 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
804 &sim_lock_status_.retries_left)) {
805 emit = true;
806 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400807 }
808 if (emit) {
809 cellular()->adaptor()->EmitKeyValueStoreChanged(
810 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
811 }
Darin Petkov63138a92012-02-06 14:09:15 +0100812 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100813}
814
Eric Shienbrood9a245532012-03-07 14:20:39 -0500815void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100816 // TODO(petkov): Implement this.
817 NOTIMPLEMENTED();
818}
819
Eric Shienbrood9a245532012-03-07 14:20:39 -0500820void CellularCapabilityGSM::OnRegistrationInfoSignal(
821 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700822 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
823 << ", opercode=" << operator_code
824 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500825 registration_state_ = status;
826 serving_operator_.SetCode(operator_code);
827 serving_operator_.SetName(operator_name);
828 UpdateOperatorInfo();
829 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100830}
831
Eric Shienbrood9a245532012-03-07 14:20:39 -0500832void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100833 cellular()->HandleNewSignalQuality(quality);
834}
835
Eric Shienbrood9a245532012-03-07 14:20:39 -0500836void CellularCapabilityGSM::OnGetRegistrationInfoReply(
837 uint32 status, const string &operator_code, const string &operator_name,
838 const Error &error) {
839 if (error.IsSuccess())
840 OnRegistrationInfoSignal(status, operator_code, operator_name);
841}
842
843void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
844 const Error &error) {
845 if (error.IsSuccess())
846 OnSignalQualitySignal(quality);
847}
848
849void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
850 const string &imei,
851 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500852 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700853 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500854 imei_ = imei;
855 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700856 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500857 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500858 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500859}
860
Eric Shienbrood9a245532012-03-07 14:20:39 -0500861void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
862 const string &imsi,
863 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500864 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700865 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500866 imsi_ = imsi;
867 SetHomeProvider();
868 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700869 SLOG(Cellular, 2) << "GetIMSI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500870 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500871 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500872}
873
Eric Shienbrood9a245532012-03-07 14:20:39 -0500874void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
875 const string &spn,
876 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500877 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700878 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500879 spn_ = spn;
880 SetHomeProvider();
881 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700882 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500883 }
Thieu Le923006b2012-04-05 16:32:58 -0700884 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500885}
886
Eric Shienbrood9a245532012-03-07 14:20:39 -0500887void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
888 const string &msisdn,
889 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500890 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700891 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500892 mdn_ = msisdn;
893 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700894 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500895 }
Thieu Le923006b2012-04-05 16:32:58 -0700896 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500897}
898
Darin Petkovdaf43862011-10-27 11:37:28 +0200899} // namespace shill