blob: fbc1884865bc0192ed8cd5b258e0362f5d87c015 [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) {
264 if (error.IsFailure()) {
265 cellular()->service()->ClearLastGoodApn();
266 // The APN that was just tried (and failed) is still at the
267 // front of the list, about to be removed. If the list is empty
268 // after that, try one last time without an APN. This may succeed
269 // with some modems in some cases.
270 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
271 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700272 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
273 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400274 DBusPropertiesMap props;
275 FillConnectPropertyMap(&props);
276 Error error;
277 Connect(props, &error, callback);
278 return;
279 }
280 } else if (!apn_try_list_.empty()) {
281 cellular()->service()->SetLastGoodApn(apn_try_list_.front());
282 apn_try_list_.clear();
283 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400284 if (!callback.is_null())
285 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400286}
287
288bool CellularCapabilityGSM::AllowRoaming() {
289 bool requires_roaming =
290 home_provider_ ? home_provider_->requires_roaming : false;
291 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100292}
293
Eric Shienbrood9a245532012-03-07 14:20:39 -0500294// always called from an async context
295void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700296 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500297 CHECK(!callback.is_null());
298 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500299 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500300 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
301 weak_ptr_factory_.GetWeakPtr(), callback);
302 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
303 if (error.IsFailure())
304 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500305 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700306 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500307 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100308 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500309}
310
Eric Shienbrood9a245532012-03-07 14:20:39 -0500311// always called from an async context
312void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700313 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500314 CHECK(!callback.is_null());
315 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500316 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500317 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
318 weak_ptr_factory_.GetWeakPtr(),
319 callback);
320 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
321 if (error.IsFailure())
322 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500323 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700324 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500325 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100326 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500327}
328
Eric Shienbrood9a245532012-03-07 14:20:39 -0500329// always called from an async context
330void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700331 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500332 CHECK(!callback.is_null());
333 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100334 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500335 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
336 weak_ptr_factory_.GetWeakPtr(),
337 callback);
338 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
339 if (error.IsFailure())
340 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500341 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700342 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500343 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100344 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500345}
346
Eric Shienbrood9a245532012-03-07 14:20:39 -0500347// always called from an async context
348void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700349 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500350 CHECK(!callback.is_null());
351 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500352 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500353 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
354 weak_ptr_factory_.GetWeakPtr(),
355 callback);
356 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
357 if (error.IsFailure())
358 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500359 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700360 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500361 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100362 }
363}
364
Darin Petkov3e509242011-11-10 14:46:44 +0100365void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700366 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500367 SignalQualityCallback callback =
368 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
369 weak_ptr_factory_.GetWeakPtr());
370 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100371}
372
Eric Shienbrood9a245532012-03-07 14:20:39 -0500373void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700374 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500375 RegistrationInfoCallback callback =
376 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
377 weak_ptr_factory_.GetWeakPtr());
378 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100379}
380
Eric Shienbrood9a245532012-03-07 14:20:39 -0500381void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700382 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100383
Darin Petkov184c54e2011-11-15 12:44:39 +0100384 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
385 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100386 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700387 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100388
389 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
390 uint32 locks = card_proxy_->EnabledFacilityLocks();
391 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700392 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100393
Eric Shienbrood9a245532012-03-07 14:20:39 -0500394 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100395}
396
Darin Petkovac635a82012-01-10 16:51:58 +0100397string CellularCapabilityGSM::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700398 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100399 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
400 !cellular()->home_provider().GetName().empty()) {
401 return cellular()->home_provider().GetName();
402 }
403 if (!serving_operator_.GetName().empty()) {
404 return serving_operator_.GetName();
405 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500406 if (!carrier_.empty()) {
407 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100408 }
409 if (!serving_operator_.GetCode().empty()) {
410 return "cellular_" + serving_operator_.GetCode();
411 }
412 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
413}
414
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100415void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700416 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
417 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100418 // TODO(petkov): The test for NULL provider_db should be done by
419 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500420 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100421 return;
422 }
423 mobile_provider *provider =
424 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500425 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100426 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700427 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100428 return;
429 }
430 home_provider_ = provider;
431 Cellular::Operator oper;
432 if (provider->networks) {
433 oper.SetCode(provider->networks[0]);
434 }
435 if (provider->country) {
436 oper.SetCountry(provider->country);
437 }
438 if (spn_.empty()) {
439 const char *name = mobile_provider_get_name(provider);
440 if (name) {
441 oper.SetName(name);
442 }
443 } else {
444 oper.SetName(spn_);
445 }
446 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100447 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100448}
449
Darin Petkovae0c64e2011-11-15 15:50:27 +0100450void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700451 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100452 const string &network_id = serving_operator_.GetCode();
453 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700454 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100455 mobile_provider *provider =
456 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100457 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100458 if (provider) {
459 const char *provider_name = mobile_provider_get_name(provider);
460 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100461 serving_operator_.SetName(provider_name);
462 if (provider->country) {
463 serving_operator_.SetCountry(provider->country);
464 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700465 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
466 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100467 }
468 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700469 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100470 }
471 }
472 UpdateServingOperator();
473}
474
475void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700476 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100477 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100478 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100479 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100480}
481
Darin Petkov3cfbf212011-11-21 16:02:09 +0100482void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700483 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100484 if (!home_provider_) {
485 return;
486 }
487 apn_list_.clear();
488 for (int i = 0; i < home_provider_->num_apns; ++i) {
489 Stringmap props;
490 mobile_apn *apn = home_provider_->apns[i];
491 if (apn->value) {
492 props[flimflam::kApnProperty] = apn->value;
493 }
494 if (apn->username) {
495 props[flimflam::kApnUsernameProperty] = apn->username;
496 }
497 if (apn->password) {
498 props[flimflam::kApnPasswordProperty] = apn->password;
499 }
500 // Find the first localized and non-localized name, if any.
501 const localized_name *lname = NULL;
502 const localized_name *name = NULL;
503 for (int j = 0; j < apn->num_names; ++j) {
504 if (apn->names[j]->lang) {
505 if (!lname) {
506 lname = apn->names[j];
507 }
508 } else if (!name) {
509 name = apn->names[j];
510 }
511 }
512 if (name) {
513 props[flimflam::kApnNameProperty] = name->name;
514 }
515 if (lname) {
516 props[flimflam::kApnLocalizedNameProperty] = lname->name;
517 props[flimflam::kApnLanguageProperty] = lname->lang;
518 }
519 apn_list_.push_back(props);
520 }
521 cellular()->adaptor()->EmitStringmapsChanged(
522 flimflam::kCellularApnListProperty, apn_list_);
523}
524
Eric Shienbrood9a245532012-03-07 14:20:39 -0500525// always called from an async context
526void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700527 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500528 CHECK(!callback.is_null());
529 Error error;
530 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
531 weak_ptr_factory_.GetWeakPtr(), callback);
532 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
533 if (error.IsFailure())
534 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100535}
536
537void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500538 const string &network_id,
539 Error *error,
540 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700541 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500542 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500543 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500544 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
545 weak_ptr_factory_.GetWeakPtr(), callback);
546 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500547}
548
Eric Shienbrood9a245532012-03-07 14:20:39 -0500549void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
550 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700551 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500552
553 if (error.IsSuccess()) {
554 selected_network_ = desired_network_;
555 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500556 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500557 return;
558 }
559 // If registration on the desired network failed,
560 // try to register on the home network.
561 if (!desired_network_.empty()) {
562 desired_network_.clear();
563 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500564 LOG(INFO) << "Couldn't register on selected network, trying home network";
565 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500566 return;
567 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500568 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100569}
570
Darin Petkovb72cf402011-11-22 14:51:39 +0100571bool CellularCapabilityGSM::IsRegistered() {
572 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
573 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
574}
575
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400576void CellularCapabilityGSM::SetUnregistered(bool searching) {
577 // If we're already in some non-registered state, don't override that
578 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
579 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
580 registration_state_ =
581 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
582 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
583 }
584}
585
Darin Petkovb05315f2011-11-07 10:14:25 +0100586void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500587 const std::string &pin, bool require,
588 Error *error, const ResultCallback &callback) {
589 CHECK(error);
590 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100591}
592
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100593void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500594 Error *error,
595 const ResultCallback &callback) {
596 CHECK(error);
597 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100598}
599
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100600void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
601 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500602 Error *error,
603 const ResultCallback &callback) {
604 CHECK(error);
605 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100606}
607
608void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500609 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500610 Error *error, const ResultCallback &callback) {
611 CHECK(error);
612 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100613}
614
Eric Shienbrood9a245532012-03-07 14:20:39 -0500615void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700616 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500617 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400618 if (scanning_) {
619 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
620 return;
621 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500622 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
623 weak_ptr_factory_.GetWeakPtr(), callback);
624 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400625 if (!error->IsFailure()) {
626 scanning_ = true;
627 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
628 scanning_);
629 }
Darin Petkov1272a432011-11-10 15:53:37 +0100630}
631
Eric Shienbrood9a245532012-03-07 14:20:39 -0500632void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
633 const GSMScanResults &results,
634 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700635 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400636
637 // Error handling is weak. The current expectation is that on any
638 // error, found_networks_ should be cleared and a property change
639 // notification sent out.
640 //
641 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400642 scanning_ = false;
643 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
644 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500645 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400646 if (!error.IsFailure()) {
647 for (GSMScanResults::const_iterator it = results.begin();
648 it != results.end(); ++it) {
649 found_networks_.push_back(ParseScanResult(*it));
650 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500651 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100652 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
653 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700654 if (!callback.is_null())
655 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500656}
657
658Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100659 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500660 for (GSMScanResult::const_iterator it = result.begin();
661 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100662 // TODO(petkov): Define these in system_api/service_constants.h. The
663 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
664 static const char * const kStatusString[] = {
665 "unknown",
666 "available",
667 "current",
668 "forbidden",
669 };
670 static const char * const kTechnologyString[] = {
671 flimflam::kNetworkTechnologyGsm,
672 "GSM Compact",
673 flimflam::kNetworkTechnologyUmts,
674 flimflam::kNetworkTechnologyEdge,
675 "HSDPA",
676 "HSUPA",
677 flimflam::kNetworkTechnologyHspa,
678 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700679 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
680 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100681 if (it->first == kNetworkPropertyStatus) {
682 int status = 0;
683 if (base::StringToInt(it->second, &status) &&
684 status >= 0 &&
685 status < static_cast<int>(arraysize(kStatusString))) {
686 parsed[flimflam::kStatusProperty] = kStatusString[status];
687 } else {
688 LOG(ERROR) << "Unexpected status value: " << it->second;
689 }
690 } else if (it->first == kNetworkPropertyID) {
691 parsed[flimflam::kNetworkIdProperty] = it->second;
692 } else if (it->first == kNetworkPropertyLongName) {
693 parsed[flimflam::kLongNameProperty] = it->second;
694 } else if (it->first == kNetworkPropertyShortName) {
695 parsed[flimflam::kShortNameProperty] = it->second;
696 } else if (it->first == kNetworkPropertyAccessTechnology) {
697 int tech = 0;
698 if (base::StringToInt(it->second, &tech) &&
699 tech >= 0 &&
700 tech < static_cast<int>(arraysize(kTechnologyString))) {
701 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
702 } else {
703 LOG(ERROR) << "Unexpected technology value: " << it->second;
704 }
705 } else {
706 LOG(WARNING) << "Unknown network property ignored: " << it->first;
707 }
708 }
709 // If the long name is not available but the network ID is, look up the long
710 // name in the mobile provider database.
711 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
712 parsed[flimflam::kLongNameProperty].empty()) &&
713 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
714 mobile_provider *provider =
715 mobile_provider_lookup_by_network(
716 cellular()->provider_db(),
717 parsed[flimflam::kNetworkIdProperty].c_str());
718 if (provider) {
719 const char *long_name = mobile_provider_get_name(provider);
720 if (long_name && *long_name) {
721 parsed[flimflam::kLongNameProperty] = long_name;
722 }
723 }
724 }
725 return parsed;
726}
727
Darin Petkovae0c64e2011-11-15 15:50:27 +0100728void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
729 access_technology_ = access_technology;
730 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100731 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100732 }
733}
734
Darin Petkov20c13ec2011-11-09 15:07:15 +0100735string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100736 switch (access_technology_) {
737 case MM_MODEM_GSM_ACCESS_TECH_GSM:
738 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
739 return flimflam::kNetworkTechnologyGsm;
740 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
741 return flimflam::kNetworkTechnologyGprs;
742 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
743 return flimflam::kNetworkTechnologyEdge;
744 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
745 return flimflam::kNetworkTechnologyUmts;
746 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
747 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
748 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
749 return flimflam::kNetworkTechnologyHspa;
750 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
751 return flimflam::kNetworkTechnologyHspaPlus;
752 default:
753 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100754 }
755 return "";
756}
757
758string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100759 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100760 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
761 return flimflam::kRoamingStateHome;
762 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
763 return flimflam::kRoamingStateRoaming;
764 default:
765 break;
766 }
767 return flimflam::kRoamingStateUnknown;
768}
769
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400770void CellularCapabilityGSM::OnDBusPropertiesChanged(
771 const string &interface,
772 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400773 const vector<string> &invalidated_properties) {
774 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
775 properties,
776 invalidated_properties);
777 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
778 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
779 if (DBusProperties::GetUint32(properties,
780 kPropertyAccessTechnology,
781 &access_technology)) {
782 SetAccessTechnology(access_technology);
783 }
784 } else if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
785 bool emit = false;
786 uint32 locks = 0;
787 if (DBusProperties::GetUint32(
788 properties, kPropertyEnabledFacilityLocks, &locks)) {
789 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
790 emit = true;
791 }
792 if (DBusProperties::GetString(
793 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type)) {
794 emit = true;
795 }
796 if (DBusProperties::GetUint32(
797 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left)) {
798 emit = true;
799 }
800 if (emit) {
801 cellular()->adaptor()->EmitKeyValueStoreChanged(
802 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
803 }
Darin Petkov63138a92012-02-06 14:09:15 +0100804 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100805}
806
Eric Shienbrood9a245532012-03-07 14:20:39 -0500807void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100808 // TODO(petkov): Implement this.
809 NOTIMPLEMENTED();
810}
811
Eric Shienbrood9a245532012-03-07 14:20:39 -0500812void CellularCapabilityGSM::OnRegistrationInfoSignal(
813 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700814 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
815 << ", opercode=" << operator_code
816 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500817 registration_state_ = status;
818 serving_operator_.SetCode(operator_code);
819 serving_operator_.SetName(operator_name);
820 UpdateOperatorInfo();
821 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100822}
823
Eric Shienbrood9a245532012-03-07 14:20:39 -0500824void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100825 cellular()->HandleNewSignalQuality(quality);
826}
827
Eric Shienbrood9a245532012-03-07 14:20:39 -0500828void CellularCapabilityGSM::OnGetRegistrationInfoReply(
829 uint32 status, const string &operator_code, const string &operator_name,
830 const Error &error) {
831 if (error.IsSuccess())
832 OnRegistrationInfoSignal(status, operator_code, operator_name);
833}
834
835void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
836 const Error &error) {
837 if (error.IsSuccess())
838 OnSignalQualitySignal(quality);
839}
840
841void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
842 const string &imei,
843 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500844 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700845 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500846 imei_ = imei;
847 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700848 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500849 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500850 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500851}
852
Eric Shienbrood9a245532012-03-07 14:20:39 -0500853void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
854 const string &imsi,
855 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500856 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700857 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500858 imsi_ = imsi;
859 SetHomeProvider();
860 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700861 SLOG(Cellular, 2) << "GetIMSI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500862 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500863 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500864}
865
Eric Shienbrood9a245532012-03-07 14:20:39 -0500866void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
867 const string &spn,
868 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500869 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700870 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500871 spn_ = spn;
872 SetHomeProvider();
873 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700874 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500875 }
Thieu Le923006b2012-04-05 16:32:58 -0700876 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500877}
878
Eric Shienbrood9a245532012-03-07 14:20:39 -0500879void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
880 const string &msisdn,
881 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500882 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700883 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500884 mdn_ = msisdn;
885 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700886 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500887 }
Thieu Le923006b2012-04-05 16:32:58 -0700888 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500889}
890
Darin Petkovdaf43862011-10-27 11:37:28 +0200891} // namespace shill