blob: d0452697dba5934ada2b0cc6b11143a38d73105d [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>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010012#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010013#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010014#include <chromeos/dbus/service_constants.h>
15#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010016#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020017
Darin Petkov3cfbf212011-11-21 16:02:09 +010018#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010019#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050020#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070021#include "shill/logging.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"
24
Eric Shienbrood3e20a232012-02-16 11:35:56 -050025using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010026using std::string;
Jason Glasgow4c0724a2012-04-17 15:47:40 -040027using std::vector;
Darin Petkovb05315f2011-11-07 10:14:25 +010028
Darin Petkovdaf43862011-10-27 11:37:28 +020029namespace shill {
30
Darin Petkovac635a82012-01-10 16:51:58 +010031// static
32unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
33
Darin Petkov1272a432011-11-10 15:53:37 +010034const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
35 "access-tech";
36const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
37const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
38const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
39 "operator-short";
40const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010041const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
42const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
43 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010044const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
45 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010046const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
47const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010048
Gary Morain82a31a02012-08-02 18:03:32 -070049const int CellularCapabilityGSM::kGetIMSIRetryLimit = 10;
50const int64 CellularCapabilityGSM::kGetIMSIRetryDelayMilliseconds = 200;
51
52
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050053CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
54 ProxyFactory *proxy_factory)
Jason Glasgow82f9ab32012-04-04 14:27:19 -040055 : CellularCapabilityClassic(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050056 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010057 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010058 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010059 home_provider_(NULL),
Gary Morain82a31a02012-08-02 18:03:32 -070060 get_imsi_retries_(0),
61 get_imsi_retry_delay_milliseconds_(kGetIMSIRetryDelayMilliseconds),
Darin Petkov1272a432011-11-10 15:53:37 +010062 scanning_(false),
63 scan_interval_(0) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070064 SLOG(Cellular, 2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010065 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010066 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
67 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010068 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
69 &found_networks_);
70 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
71 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010072 HelpRegisterDerivedKeyValueStore(
73 flimflam::kSIMLockStatusProperty,
74 &CellularCapabilityGSM::SimLockStatusToProperty,
75 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010076 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
77 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010078 scanning_supported_ = true;
Ben Chan3ecdf822012-08-06 12:29:23 -070079
80 // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI
81 // before InitProxies is called. There are side-effects of calling InitProxies
82 // before the device is enabled. It's better to refactor InitProxies such that
83 // proxies can be created when the cellular device/capability is constructed,
84 // but callbacks for DBus signal updates are not set up until the device is
85 // enabled.
86 card_proxy_.reset(
87 proxy_factory->CreateModemGSMCardProxy(cellular->dbus_path(),
88 cellular->dbus_owner()));
89 // TODO(benchan): To allow unit testing using a mock proxy without further
90 // complicating the code, the test proxy factory is set up to return a NULL
91 // pointer when CellularCapabilityGSM is constructed. Refactor the code to
92 // avoid this hack.
93 if (card_proxy_.get())
94 InitProperties();
Darin Petkov1272a432011-11-10 15:53:37 +010095}
Darin Petkovdaf43862011-10-27 11:37:28 +020096
Darin Petkov63138a92012-02-06 14:09:15 +010097KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
98 KeyValueStore status;
99 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
100 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
101 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
102 sim_lock_status_.retries_left);
103 return status;
Darin Petkov721ac932011-11-16 15:43:09 +0100104}
105
Darin Petkov63138a92012-02-06 14:09:15 +0100106void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100107 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +0100108 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
109 void(CellularCapabilityGSM::*set)(
110 const KeyValueStore &value, Error *error)) {
111 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100112 name,
Darin Petkov63138a92012-02-06 14:09:15 +0100113 KeyValueStoreAccessor(
114 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +0100115 this, get, set)));
116}
117
Eric Shienbrood9a245532012-03-07 14:20:39 -0500118void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400119 CellularCapabilityClassic::InitProxies();
Ben Chan3ecdf822012-08-06 12:29:23 -0700120 // TODO(benchan): Remove this check after refactoring the proxy
121 // initialization.
122 if (!card_proxy_.get()) {
123 card_proxy_.reset(
124 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
125 cellular()->dbus_owner()));
126 }
Darin Petkov184c54e2011-11-15 12:44:39 +0100127 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500128 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200129 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500130 network_proxy_->set_signal_quality_callback(
131 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
132 weak_ptr_factory_.GetWeakPtr()));
133 network_proxy_->set_network_mode_callback(
134 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
135 weak_ptr_factory_.GetWeakPtr()));
136 network_proxy_->set_registration_info_callback(
137 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
138 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200139}
140
Ben Chan3ecdf822012-08-06 12:29:23 -0700141void CellularCapabilityGSM::InitProperties() {
142 CellularTaskList *tasks = new CellularTaskList();
143 ResultCallback cb_ignore_error =
144 Bind(&CellularCapabilityGSM::StepCompletedCallback,
145 weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks);
146 // Chrome uses IMSI to determine if a SIM is present before allowing the
147 // modem to be enabled, so shill needs to obtain IMSI even before the device
148 // is enabled.
149 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
150 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
151 RunNextStep(tasks);
152}
153
Eric Shienbrood9a245532012-03-07 14:20:39 -0500154void CellularCapabilityGSM::StartModem(Error *error,
155 const ResultCallback &callback) {
156 InitProxies();
157
158 CellularTaskList *tasks = new CellularTaskList();
159 ResultCallback cb =
160 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700161 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
162 ResultCallback cb_ignore_error =
163 Bind(&CellularCapabilityGSM::StepCompletedCallback,
164 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400165 if (!cellular()->IsUnderlyingDeviceEnabled())
166 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
167 weak_ptr_factory_.GetWeakPtr(), cb));
168 // If we're within range of the home network, the modem will try to
169 // register once it's enabled, or may be already registered if we
170 // started out enabled.
171 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
172 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
173 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500174 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
175 weak_ptr_factory_.GetWeakPtr(), cb));
Gary Morain82a31a02012-08-02 18:03:32 -0700176 get_imsi_retries_ = 0;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500177 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
178 weak_ptr_factory_.GetWeakPtr(), cb));
179 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700180 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500181 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700182 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500183 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
184 weak_ptr_factory_.GetWeakPtr(), cb));
185 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400186 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500187 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
188 weak_ptr_factory_.GetWeakPtr(), cb));
189
190 RunNextStep(tasks);
191}
192
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400193bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
194 switch (cellular()->modem_state()) {
195 case Cellular::kModemStateUnknown:
196 case Cellular::kModemStateDisabled:
197 case Cellular::kModemStateInitializing:
198 case Cellular::kModemStateLocked:
199 case Cellular::kModemStateDisabling:
200 case Cellular::kModemStateEnabling:
201 case Cellular::kModemStateEnabled:
202 return false;
203 case Cellular::kModemStateSearching:
204 case Cellular::kModemStateRegistered:
205 case Cellular::kModemStateDisconnecting:
206 case Cellular::kModemStateConnecting:
207 case Cellular::kModemStateConnected:
208 return true;
209 }
210 return false;
211}
212
Eric Shienbrood9a245532012-03-07 14:20:39 -0500213void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700214 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400215 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100216 card_proxy_.reset();
217 network_proxy_.reset();
218}
219
Darin Petkov5f316f62011-11-18 12:10:26 +0100220void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100221 // If IMSI is available, base the service's storage identifier on it.
222 if (!imsi_.empty()) {
223 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100224 string(flimflam::kTypeCellular) + "_" +
225 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100226 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100227 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100228 flimflam::kActivationStateActivated);
229 UpdateServingOperator();
230}
231
Darin Petkovae0c64e2011-11-15 15:50:27 +0100232void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400233 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100234 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100235 }
236}
237
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400238// Create the list of APNs to try, in the following order:
239// - last APN that resulted in a successful connection attempt on the
240// current network (if any)
241// - the APN, if any, that was set by the user
242// - the list of APNs found in the mobile broadband provider DB for the
243// home provider associated with the current SIM
244// - as a last resort, attempt to connect with no APN
245void CellularCapabilityGSM::SetupApnTryList() {
246 apn_try_list_.clear();
247
248 DCHECK(cellular()->service().get());
249 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
250 if (apn_info)
251 apn_try_list_.push_back(*apn_info);
252
253 apn_info = cellular()->service()->GetUserSpecifiedApn();
254 if (apn_info)
255 apn_try_list_.push_back(*apn_info);
256
257 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
258}
259
Darin Petkovae0c64e2011-11-15 15:50:27 +0100260void CellularCapabilityGSM::SetupConnectProperties(
261 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400262 SetupApnTryList();
263 FillConnectPropertyMap(properties);
264}
265
266void CellularCapabilityGSM::FillConnectPropertyMap(
267 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500268 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100269 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400270
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400271 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400272 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
273
274 if (!apn_try_list_.empty()) {
275 // Leave the APN at the front of the list, so that it can be recorded
276 // if the connect attempt succeeds.
277 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700278 SLOG(Cellular, 2) << __func__ << ": Using APN "
279 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400280 (*properties)[kConnectPropertyApn].writer().append_string(
281 apn_info[flimflam::kApnProperty].c_str());
282 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
283 (*properties)[kConnectPropertyApnUsername].writer().append_string(
284 apn_info[flimflam::kApnUsernameProperty].c_str());
285 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
286 (*properties)[kConnectPropertyApnPassword].writer().append_string(
287 apn_info[flimflam::kApnPasswordProperty].c_str());
288 }
289}
290
Nathan Williamsb54974f2012-04-19 11:16:30 -0400291void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
292 Error *error,
293 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700294 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400295 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
296 weak_ptr_factory_.GetWeakPtr(),
297 callback);
298 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
299}
300
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400301void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
302 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700303 CellularServiceRefPtr service = cellular()->service();
304 if (!service) {
305 // The service could have been deleted before our Connect() request
306 // completes if the modem was enabled and then quickly disabled.
307 apn_try_list_.clear();
308 } else if (error.IsFailure()) {
309 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400310 // The APN that was just tried (and failed) is still at the
311 // front of the list, about to be removed. If the list is empty
312 // after that, try one last time without an APN. This may succeed
313 // with some modems in some cases.
314 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
315 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700316 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
317 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400318 DBusPropertiesMap props;
319 FillConnectPropertyMap(&props);
320 Error error;
321 Connect(props, &error, callback);
322 return;
323 }
324 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700325 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400326 apn_try_list_.clear();
327 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400328 if (!callback.is_null())
329 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400330}
331
332bool CellularCapabilityGSM::AllowRoaming() {
333 bool requires_roaming =
334 home_provider_ ? home_provider_->requires_roaming : false;
335 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100336}
337
Eric Shienbrood9a245532012-03-07 14:20:39 -0500338// always called from an async context
339void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700340 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500341 CHECK(!callback.is_null());
342 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500343 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500344 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
345 weak_ptr_factory_.GetWeakPtr(), callback);
346 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
347 if (error.IsFailure())
348 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500349 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700350 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500351 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100352 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500353}
354
Eric Shienbrood9a245532012-03-07 14:20:39 -0500355// always called from an async context
356void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700357 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500358 CHECK(!callback.is_null());
359 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500360 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500361 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
362 weak_ptr_factory_.GetWeakPtr(),
363 callback);
364 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
365 if (error.IsFailure())
366 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500367 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700368 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500369 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100370 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500371}
372
Eric Shienbrood9a245532012-03-07 14:20:39 -0500373// always called from an async context
374void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700375 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500376 CHECK(!callback.is_null());
377 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100378 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500379 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
380 weak_ptr_factory_.GetWeakPtr(),
381 callback);
382 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
383 if (error.IsFailure())
384 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500385 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700386 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500387 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100388 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500389}
390
Eric Shienbrood9a245532012-03-07 14:20:39 -0500391// always called from an async context
392void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700393 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500394 CHECK(!callback.is_null());
395 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500396 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500397 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
398 weak_ptr_factory_.GetWeakPtr(),
399 callback);
400 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
401 if (error.IsFailure())
402 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500403 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700404 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500405 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100406 }
407}
408
Darin Petkov3e509242011-11-10 14:46:44 +0100409void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700410 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500411 SignalQualityCallback callback =
412 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
413 weak_ptr_factory_.GetWeakPtr());
414 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100415}
416
Eric Shienbrood9a245532012-03-07 14:20:39 -0500417void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700418 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500419 RegistrationInfoCallback callback =
420 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
421 weak_ptr_factory_.GetWeakPtr());
422 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100423}
424
Eric Shienbrood9a245532012-03-07 14:20:39 -0500425void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700426 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100427
Darin Petkov184c54e2011-11-15 12:44:39 +0100428 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
429 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100430 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700431 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100432
433 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
434 uint32 locks = card_proxy_->EnabledFacilityLocks();
435 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700436 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100437
Eric Shienbrood9a245532012-03-07 14:20:39 -0500438 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100439}
440
Darin Petkovac635a82012-01-10 16:51:58 +0100441string CellularCapabilityGSM::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200442 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
443 string name = serving_operator_.GetName();
444 string home_provider_name = cellular()->home_provider().GetName();
445 if (!name.empty()) {
446 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
447 // rules (TS 31.102 and annex A of 122.101).
448 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING &&
449 !home_provider_name.empty()) {
450 return home_provider_name + " | " + name;
451 }
452 return name;
Darin Petkovac635a82012-01-10 16:51:58 +0100453 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200454 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
455 !home_provider_name.empty()) {
456 return home_provider_name;
Darin Petkovac635a82012-01-10 16:51:58 +0100457 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500458 if (!carrier_.empty()) {
459 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100460 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200461 string serving_operator_code = serving_operator_.GetCode();
462 if (!serving_operator_code.empty()) {
463 return "cellular_" + serving_operator_code;
Darin Petkovac635a82012-01-10 16:51:58 +0100464 }
465 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
466}
467
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100468void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700469 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
470 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100471 // TODO(petkov): The test for NULL provider_db should be done by
472 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500473 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100474 return;
475 }
476 mobile_provider *provider =
477 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500478 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100479 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700480 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100481 return;
482 }
483 home_provider_ = provider;
484 Cellular::Operator oper;
Darin Petkovb4fccd22012-08-10 11:59:26 +0200485 if (provider->networks && provider->networks[0]) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100486 oper.SetCode(provider->networks[0]);
487 }
488 if (provider->country) {
489 oper.SetCountry(provider->country);
490 }
491 if (spn_.empty()) {
492 const char *name = mobile_provider_get_name(provider);
493 if (name) {
494 oper.SetName(name);
495 }
496 } else {
497 oper.SetName(spn_);
498 }
499 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200500 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
501 << oper.GetName() << ", " << oper.GetCountry();
Darin Petkov3cfbf212011-11-21 16:02:09 +0100502 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100503}
504
Darin Petkovae0c64e2011-11-15 15:50:27 +0100505void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700506 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100507 const string &network_id = serving_operator_.GetCode();
508 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700509 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100510 mobile_provider *provider =
511 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100512 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100513 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200514 if (serving_operator_.GetName().empty()) {
515 const char *provider_name = mobile_provider_get_name(provider);
516 if (provider_name && *provider_name) {
517 serving_operator_.SetName(provider_name);
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100518 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100519 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200520 if (provider->country && *provider->country) {
521 serving_operator_.SetCountry(provider->country);
522 }
523 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
524 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100525 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700526 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100527 }
528 }
529 UpdateServingOperator();
530}
531
532void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700533 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100534 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100535 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100536 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100537}
538
Darin Petkov3cfbf212011-11-21 16:02:09 +0100539void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700540 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100541 if (!home_provider_) {
542 return;
543 }
544 apn_list_.clear();
545 for (int i = 0; i < home_provider_->num_apns; ++i) {
546 Stringmap props;
547 mobile_apn *apn = home_provider_->apns[i];
548 if (apn->value) {
549 props[flimflam::kApnProperty] = apn->value;
550 }
551 if (apn->username) {
552 props[flimflam::kApnUsernameProperty] = apn->username;
553 }
554 if (apn->password) {
555 props[flimflam::kApnPasswordProperty] = apn->password;
556 }
557 // Find the first localized and non-localized name, if any.
558 const localized_name *lname = NULL;
559 const localized_name *name = NULL;
560 for (int j = 0; j < apn->num_names; ++j) {
561 if (apn->names[j]->lang) {
562 if (!lname) {
563 lname = apn->names[j];
564 }
565 } else if (!name) {
566 name = apn->names[j];
567 }
568 }
569 if (name) {
570 props[flimflam::kApnNameProperty] = name->name;
571 }
572 if (lname) {
573 props[flimflam::kApnLocalizedNameProperty] = lname->name;
574 props[flimflam::kApnLanguageProperty] = lname->lang;
575 }
576 apn_list_.push_back(props);
577 }
Darin Petkovdb6083f2012-08-16 12:50:23 +0200578 if (cellular()->adaptor()) {
579 cellular()->adaptor()->EmitStringmapsChanged(
580 flimflam::kCellularApnListProperty, apn_list_);
581 } else {
582 LOG(ERROR) << "Null RPC service adaptor.";
583 }
Darin Petkov3cfbf212011-11-21 16:02:09 +0100584}
585
Eric Shienbrood9a245532012-03-07 14:20:39 -0500586// always called from an async context
587void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700588 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500589 CHECK(!callback.is_null());
590 Error error;
591 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
592 weak_ptr_factory_.GetWeakPtr(), callback);
593 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
594 if (error.IsFailure())
595 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100596}
597
598void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500599 const string &network_id,
600 Error *error,
601 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700602 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500603 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500604 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500605 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
606 weak_ptr_factory_.GetWeakPtr(), callback);
607 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500608}
609
Eric Shienbrood9a245532012-03-07 14:20:39 -0500610void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
611 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700612 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500613
614 if (error.IsSuccess()) {
615 selected_network_ = desired_network_;
616 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500617 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500618 return;
619 }
620 // If registration on the desired network failed,
621 // try to register on the home network.
622 if (!desired_network_.empty()) {
623 desired_network_.clear();
624 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500625 LOG(INFO) << "Couldn't register on selected network, trying home network";
626 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500627 return;
628 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500629 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100630}
631
Darin Petkovb72cf402011-11-22 14:51:39 +0100632bool CellularCapabilityGSM::IsRegistered() {
633 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
634 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
635}
636
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400637void CellularCapabilityGSM::SetUnregistered(bool searching) {
638 // If we're already in some non-registered state, don't override that
639 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
640 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
641 registration_state_ =
642 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
643 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
644 }
645}
646
Darin Petkovb05315f2011-11-07 10:14:25 +0100647void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500648 const std::string &pin, bool require,
649 Error *error, const ResultCallback &callback) {
650 CHECK(error);
651 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100652}
653
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100654void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500655 Error *error,
656 const ResultCallback &callback) {
657 CHECK(error);
658 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100659}
660
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100661void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
662 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500663 Error *error,
664 const ResultCallback &callback) {
665 CHECK(error);
666 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100667}
668
669void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500670 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500671 Error *error, const ResultCallback &callback) {
672 CHECK(error);
673 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100674}
675
Eric Shienbrood9a245532012-03-07 14:20:39 -0500676void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700677 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500678 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400679 if (scanning_) {
680 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
681 return;
682 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500683 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
684 weak_ptr_factory_.GetWeakPtr(), callback);
685 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400686 if (!error->IsFailure()) {
687 scanning_ = true;
688 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
689 scanning_);
690 }
Darin Petkov1272a432011-11-10 15:53:37 +0100691}
692
Eric Shienbrood9a245532012-03-07 14:20:39 -0500693void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
694 const GSMScanResults &results,
695 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700696 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400697
698 // Error handling is weak. The current expectation is that on any
699 // error, found_networks_ should be cleared and a property change
700 // notification sent out.
701 //
702 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400703 scanning_ = false;
704 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
705 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500706 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400707 if (!error.IsFailure()) {
708 for (GSMScanResults::const_iterator it = results.begin();
709 it != results.end(); ++it) {
710 found_networks_.push_back(ParseScanResult(*it));
711 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500712 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100713 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
714 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700715 if (!callback.is_null())
716 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500717}
718
719Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100720 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500721 for (GSMScanResult::const_iterator it = result.begin();
722 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100723 // TODO(petkov): Define these in system_api/service_constants.h. The
724 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
725 static const char * const kStatusString[] = {
726 "unknown",
727 "available",
728 "current",
729 "forbidden",
730 };
731 static const char * const kTechnologyString[] = {
732 flimflam::kNetworkTechnologyGsm,
733 "GSM Compact",
734 flimflam::kNetworkTechnologyUmts,
735 flimflam::kNetworkTechnologyEdge,
736 "HSDPA",
737 "HSUPA",
738 flimflam::kNetworkTechnologyHspa,
739 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700740 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
741 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100742 if (it->first == kNetworkPropertyStatus) {
743 int status = 0;
744 if (base::StringToInt(it->second, &status) &&
745 status >= 0 &&
746 status < static_cast<int>(arraysize(kStatusString))) {
747 parsed[flimflam::kStatusProperty] = kStatusString[status];
748 } else {
749 LOG(ERROR) << "Unexpected status value: " << it->second;
750 }
751 } else if (it->first == kNetworkPropertyID) {
752 parsed[flimflam::kNetworkIdProperty] = it->second;
753 } else if (it->first == kNetworkPropertyLongName) {
754 parsed[flimflam::kLongNameProperty] = it->second;
755 } else if (it->first == kNetworkPropertyShortName) {
756 parsed[flimflam::kShortNameProperty] = it->second;
757 } else if (it->first == kNetworkPropertyAccessTechnology) {
758 int tech = 0;
759 if (base::StringToInt(it->second, &tech) &&
760 tech >= 0 &&
761 tech < static_cast<int>(arraysize(kTechnologyString))) {
762 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
763 } else {
764 LOG(ERROR) << "Unexpected technology value: " << it->second;
765 }
766 } else {
767 LOG(WARNING) << "Unknown network property ignored: " << it->first;
768 }
769 }
770 // If the long name is not available but the network ID is, look up the long
771 // name in the mobile provider database.
772 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
773 parsed[flimflam::kLongNameProperty].empty()) &&
774 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
775 mobile_provider *provider =
776 mobile_provider_lookup_by_network(
777 cellular()->provider_db(),
778 parsed[flimflam::kNetworkIdProperty].c_str());
779 if (provider) {
780 const char *long_name = mobile_provider_get_name(provider);
781 if (long_name && *long_name) {
782 parsed[flimflam::kLongNameProperty] = long_name;
783 }
784 }
785 }
786 return parsed;
787}
788
Darin Petkovae0c64e2011-11-15 15:50:27 +0100789void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
790 access_technology_ = access_technology;
791 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100792 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100793 }
794}
795
Darin Petkov20c13ec2011-11-09 15:07:15 +0100796string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100797 switch (access_technology_) {
798 case MM_MODEM_GSM_ACCESS_TECH_GSM:
799 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
800 return flimflam::kNetworkTechnologyGsm;
801 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
802 return flimflam::kNetworkTechnologyGprs;
803 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
804 return flimflam::kNetworkTechnologyEdge;
805 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
806 return flimflam::kNetworkTechnologyUmts;
807 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
808 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
809 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
810 return flimflam::kNetworkTechnologyHspa;
811 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
812 return flimflam::kNetworkTechnologyHspaPlus;
813 default:
814 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100815 }
816 return "";
817}
818
819string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100820 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100821 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
822 return flimflam::kRoamingStateHome;
823 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
824 return flimflam::kRoamingStateRoaming;
825 default:
826 break;
827 }
828 return flimflam::kRoamingStateUnknown;
829}
830
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400831void CellularCapabilityGSM::OnDBusPropertiesChanged(
832 const string &interface,
833 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400834 const vector<string> &invalidated_properties) {
835 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
836 properties,
837 invalidated_properties);
838 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
839 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
840 if (DBusProperties::GetUint32(properties,
841 kPropertyAccessTechnology,
842 &access_technology)) {
843 SetAccessTechnology(access_technology);
844 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700845 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400846 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700847 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
848 uint32 locks = 0;
849 if (DBusProperties::GetUint32(
850 properties, kPropertyEnabledFacilityLocks, &locks)) {
851 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
852 emit = true;
853 }
854 } else if (interface == MM_MODEM_INTERFACE) {
855 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
856 &sim_lock_status_.lock_type)) {
857 emit = true;
858 }
859 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
860 &sim_lock_status_.retries_left)) {
861 emit = true;
862 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400863 }
864 if (emit) {
865 cellular()->adaptor()->EmitKeyValueStoreChanged(
866 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
867 }
Darin Petkov63138a92012-02-06 14:09:15 +0100868 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100869}
870
Eric Shienbrood9a245532012-03-07 14:20:39 -0500871void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100872 // TODO(petkov): Implement this.
873 NOTIMPLEMENTED();
874}
875
Eric Shienbrood9a245532012-03-07 14:20:39 -0500876void CellularCapabilityGSM::OnRegistrationInfoSignal(
877 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700878 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
879 << ", opercode=" << operator_code
880 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500881 registration_state_ = status;
882 serving_operator_.SetCode(operator_code);
883 serving_operator_.SetName(operator_name);
884 UpdateOperatorInfo();
885 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100886}
887
Eric Shienbrood9a245532012-03-07 14:20:39 -0500888void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100889 cellular()->HandleNewSignalQuality(quality);
890}
891
Eric Shienbrood9a245532012-03-07 14:20:39 -0500892void CellularCapabilityGSM::OnGetRegistrationInfoReply(
893 uint32 status, const string &operator_code, const string &operator_name,
894 const Error &error) {
895 if (error.IsSuccess())
896 OnRegistrationInfoSignal(status, operator_code, operator_name);
897}
898
899void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
900 const Error &error) {
901 if (error.IsSuccess())
902 OnSignalQualitySignal(quality);
903}
904
905void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
906 const string &imei,
907 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500908 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700909 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500910 imei_ = imei;
911 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700912 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500913 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500914 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500915}
916
Eric Shienbrood9a245532012-03-07 14:20:39 -0500917void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
918 const string &imsi,
919 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500920 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700921 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500922 imsi_ = imsi;
923 SetHomeProvider();
Gary Morain82a31a02012-08-02 18:03:32 -0700924 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500925 } else {
Gary Morain82a31a02012-08-02 18:03:32 -0700926 if (get_imsi_retries_++ < kGetIMSIRetryLimit) {
927 SLOG(Cellular, 2) << "GetIMSI failed - " << error << ". Retrying";
928 base::Callback<void(void)> retry_get_imsi_cb =
929 Bind(&CellularCapabilityGSM::GetIMSI,
930 weak_ptr_factory_.GetWeakPtr(), callback);
931 cellular()->dispatcher()->PostDelayedTask(
932 retry_get_imsi_cb,
933 get_imsi_retry_delay_milliseconds_);
934 } else {
935 LOG(INFO) << "GetIMSI failed - " << error;
936 callback.Run(error);
937 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500938 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500939}
940
Eric Shienbrood9a245532012-03-07 14:20:39 -0500941void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
942 const string &spn,
943 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500944 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700945 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500946 spn_ = spn;
947 SetHomeProvider();
948 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700949 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500950 }
Thieu Le923006b2012-04-05 16:32:58 -0700951 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500952}
953
Eric Shienbrood9a245532012-03-07 14:20:39 -0500954void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
955 const string &msisdn,
956 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500957 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700958 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500959 mdn_ = msisdn;
960 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700961 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500962 }
Thieu Le923006b2012-04-05 16:32:58 -0700963 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500964}
965
Darin Petkovdaf43862011-10-27 11:37:28 +0200966} // namespace shill