blob: a9ca732f9d3d582600732f750600abb96a1093bd [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
Ben Chanc89b9282012-12-12 14:00:29 -080049const int CellularCapabilityGSM::kGetIMSIRetryLimit = 40;
50const int64 CellularCapabilityGSM::kGetIMSIRetryDelayMilliseconds = 500;
Gary Morain82a31a02012-08-02 18:03:32 -070051
52
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050053CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
Thieu Lece4483e2013-01-23 15:12:03 -080054 ProxyFactory *proxy_factory,
55 Metrics *metrics)
56 : CellularCapabilityClassic(cellular, proxy_factory, metrics),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050057 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010058 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010059 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010060 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +020061 provider_requires_roaming_(false),
Gary Morain82a31a02012-08-02 18:03:32 -070062 get_imsi_retries_(0),
63 get_imsi_retry_delay_milliseconds_(kGetIMSIRetryDelayMilliseconds),
Darin Petkov1272a432011-11-10 15:53:37 +010064 scanning_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -070065 scan_interval_(0),
66 sim_present_(false) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070067 SLOG(Cellular, 2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010068 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010069 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
70 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010071 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
72 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +020073 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
74 &provider_requires_roaming_);
Darin Petkov1272a432011-11-10 15:53:37 +010075 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
76 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Ben Chanbd3aee82012-10-16 23:52:04 -070077 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Darin Petkov63138a92012-02-06 14:09:15 +010078 HelpRegisterDerivedKeyValueStore(
79 flimflam::kSIMLockStatusProperty,
80 &CellularCapabilityGSM::SimLockStatusToProperty,
81 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010082 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
83 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010084 scanning_supported_ = true;
Ben Chan3ecdf822012-08-06 12:29:23 -070085
86 // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI
87 // before InitProxies is called. There are side-effects of calling InitProxies
88 // before the device is enabled. It's better to refactor InitProxies such that
89 // proxies can be created when the cellular device/capability is constructed,
90 // but callbacks for DBus signal updates are not set up until the device is
91 // enabled.
92 card_proxy_.reset(
93 proxy_factory->CreateModemGSMCardProxy(cellular->dbus_path(),
94 cellular->dbus_owner()));
95 // TODO(benchan): To allow unit testing using a mock proxy without further
96 // complicating the code, the test proxy factory is set up to return a NULL
97 // pointer when CellularCapabilityGSM is constructed. Refactor the code to
98 // avoid this hack.
99 if (card_proxy_.get())
100 InitProperties();
Darin Petkov1272a432011-11-10 15:53:37 +0100101}
Darin Petkovdaf43862011-10-27 11:37:28 +0200102
Darin Petkov63138a92012-02-06 14:09:15 +0100103KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
104 KeyValueStore status;
105 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
106 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
107 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
108 sim_lock_status_.retries_left);
109 return status;
Darin Petkov721ac932011-11-16 15:43:09 +0100110}
111
Darin Petkov63138a92012-02-06 14:09:15 +0100112void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100113 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +0100114 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
115 void(CellularCapabilityGSM::*set)(
116 const KeyValueStore &value, Error *error)) {
117 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100118 name,
Darin Petkov63138a92012-02-06 14:09:15 +0100119 KeyValueStoreAccessor(
120 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +0100121 this, get, set)));
122}
123
Eric Shienbrood9a245532012-03-07 14:20:39 -0500124void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400125 CellularCapabilityClassic::InitProxies();
Ben Chan3ecdf822012-08-06 12:29:23 -0700126 // TODO(benchan): Remove this check after refactoring the proxy
127 // initialization.
128 if (!card_proxy_.get()) {
129 card_proxy_.reset(
130 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
131 cellular()->dbus_owner()));
132 }
Darin Petkov184c54e2011-11-15 12:44:39 +0100133 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500134 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200135 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500136 network_proxy_->set_signal_quality_callback(
137 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
138 weak_ptr_factory_.GetWeakPtr()));
139 network_proxy_->set_network_mode_callback(
140 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
141 weak_ptr_factory_.GetWeakPtr()));
142 network_proxy_->set_registration_info_callback(
143 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
144 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200145}
146
Ben Chan3ecdf822012-08-06 12:29:23 -0700147void CellularCapabilityGSM::InitProperties() {
148 CellularTaskList *tasks = new CellularTaskList();
149 ResultCallback cb_ignore_error =
150 Bind(&CellularCapabilityGSM::StepCompletedCallback,
151 weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks);
Ben Chanbd3aee82012-10-16 23:52:04 -0700152 // Chrome checks if a SIM is present before allowing the modem to be enabled,
153 // so shill needs to obtain IMSI, as an indicator of SIM presence, even
154 // before the device is enabled.
Ben Chan3ecdf822012-08-06 12:29:23 -0700155 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
156 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
157 RunNextStep(tasks);
158}
159
Eric Shienbrood9a245532012-03-07 14:20:39 -0500160void CellularCapabilityGSM::StartModem(Error *error,
161 const ResultCallback &callback) {
162 InitProxies();
163
164 CellularTaskList *tasks = new CellularTaskList();
165 ResultCallback cb =
166 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700167 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
168 ResultCallback cb_ignore_error =
169 Bind(&CellularCapabilityGSM::StepCompletedCallback,
170 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400171 if (!cellular()->IsUnderlyingDeviceEnabled())
172 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
173 weak_ptr_factory_.GetWeakPtr(), cb));
174 // If we're within range of the home network, the modem will try to
175 // register once it's enabled, or may be already registered if we
176 // started out enabled.
177 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
178 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
179 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500180 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
181 weak_ptr_factory_.GetWeakPtr(), cb));
Gary Morain82a31a02012-08-02 18:03:32 -0700182 get_imsi_retries_ = 0;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500183 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
184 weak_ptr_factory_.GetWeakPtr(), cb));
185 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700186 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500187 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700188 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500189 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
190 weak_ptr_factory_.GetWeakPtr(), cb));
191 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400192 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500193 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
194 weak_ptr_factory_.GetWeakPtr(), cb));
195
196 RunNextStep(tasks);
197}
198
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400199bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
200 switch (cellular()->modem_state()) {
201 case Cellular::kModemStateUnknown:
202 case Cellular::kModemStateDisabled:
203 case Cellular::kModemStateInitializing:
204 case Cellular::kModemStateLocked:
205 case Cellular::kModemStateDisabling:
206 case Cellular::kModemStateEnabling:
207 case Cellular::kModemStateEnabled:
208 return false;
209 case Cellular::kModemStateSearching:
210 case Cellular::kModemStateRegistered:
211 case Cellular::kModemStateDisconnecting:
212 case Cellular::kModemStateConnecting:
213 case Cellular::kModemStateConnected:
214 return true;
215 }
216 return false;
217}
218
Eric Shienbrood9a245532012-03-07 14:20:39 -0500219void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700220 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400221 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100222 card_proxy_.reset();
223 network_proxy_.reset();
224}
225
Darin Petkov5f316f62011-11-18 12:10:26 +0100226void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100227 // If IMSI is available, base the service's storage identifier on it.
228 if (!imsi_.empty()) {
229 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100230 string(flimflam::kTypeCellular) + "_" +
231 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100232 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100233 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100234 flimflam::kActivationStateActivated);
235 UpdateServingOperator();
236}
237
Darin Petkovae0c64e2011-11-15 15:50:27 +0100238void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400239 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100240 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100241 }
242}
243
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400244// Create the list of APNs to try, in the following order:
245// - last APN that resulted in a successful connection attempt on the
246// current network (if any)
247// - the APN, if any, that was set by the user
248// - the list of APNs found in the mobile broadband provider DB for the
249// home provider associated with the current SIM
250// - as a last resort, attempt to connect with no APN
251void CellularCapabilityGSM::SetupApnTryList() {
252 apn_try_list_.clear();
253
254 DCHECK(cellular()->service().get());
255 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
256 if (apn_info)
257 apn_try_list_.push_back(*apn_info);
258
259 apn_info = cellular()->service()->GetUserSpecifiedApn();
260 if (apn_info)
261 apn_try_list_.push_back(*apn_info);
262
263 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
264}
265
Darin Petkovae0c64e2011-11-15 15:50:27 +0100266void CellularCapabilityGSM::SetupConnectProperties(
267 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400268 SetupApnTryList();
269 FillConnectPropertyMap(properties);
270}
271
272void CellularCapabilityGSM::FillConnectPropertyMap(
273 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500274 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100275 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400276
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400277 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400278 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
279
280 if (!apn_try_list_.empty()) {
281 // Leave the APN at the front of the list, so that it can be recorded
282 // if the connect attempt succeeds.
283 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700284 SLOG(Cellular, 2) << __func__ << ": Using APN "
285 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400286 (*properties)[kConnectPropertyApn].writer().append_string(
287 apn_info[flimflam::kApnProperty].c_str());
288 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
289 (*properties)[kConnectPropertyApnUsername].writer().append_string(
290 apn_info[flimflam::kApnUsernameProperty].c_str());
291 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
292 (*properties)[kConnectPropertyApnPassword].writer().append_string(
293 apn_info[flimflam::kApnPasswordProperty].c_str());
294 }
295}
296
Nathan Williamsb54974f2012-04-19 11:16:30 -0400297void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
298 Error *error,
299 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700300 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400301 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
302 weak_ptr_factory_.GetWeakPtr(),
303 callback);
304 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
305}
306
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400307void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
308 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700309 CellularServiceRefPtr service = cellular()->service();
310 if (!service) {
311 // The service could have been deleted before our Connect() request
312 // completes if the modem was enabled and then quickly disabled.
313 apn_try_list_.clear();
314 } else if (error.IsFailure()) {
315 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400316 // The APN that was just tried (and failed) is still at the
317 // front of the list, about to be removed. If the list is empty
318 // after that, try one last time without an APN. This may succeed
319 // with some modems in some cases.
320 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
321 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700322 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
323 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400324 DBusPropertiesMap props;
325 FillConnectPropertyMap(&props);
326 Error error;
327 Connect(props, &error, callback);
328 return;
329 }
330 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700331 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400332 apn_try_list_.clear();
333 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400334 if (!callback.is_null())
335 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400336}
337
338bool CellularCapabilityGSM::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200339 return provider_requires_roaming_ || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100340}
341
Eric Shienbrood9a245532012-03-07 14:20:39 -0500342// always called from an async context
343void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700344 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500345 CHECK(!callback.is_null());
346 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500347 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500348 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
349 weak_ptr_factory_.GetWeakPtr(), callback);
350 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
351 if (error.IsFailure())
352 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500353 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700354 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500355 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100356 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500357}
358
Eric Shienbrood9a245532012-03-07 14:20:39 -0500359// always called from an async context
360void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700361 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500362 CHECK(!callback.is_null());
363 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500364 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500365 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
366 weak_ptr_factory_.GetWeakPtr(),
367 callback);
368 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
369 if (error.IsFailure())
370 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500371 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700372 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500373 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100374 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500375}
376
Eric Shienbrood9a245532012-03-07 14:20:39 -0500377// always called from an async context
378void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700379 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500380 CHECK(!callback.is_null());
381 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100382 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500383 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
384 weak_ptr_factory_.GetWeakPtr(),
385 callback);
386 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
387 if (error.IsFailure())
388 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500389 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700390 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500391 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100392 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500393}
394
Eric Shienbrood9a245532012-03-07 14:20:39 -0500395// always called from an async context
396void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700397 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500398 CHECK(!callback.is_null());
399 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500400 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500401 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
402 weak_ptr_factory_.GetWeakPtr(),
403 callback);
404 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
405 if (error.IsFailure())
406 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500407 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700408 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500409 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100410 }
411}
412
Darin Petkov3e509242011-11-10 14:46:44 +0100413void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700414 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500415 SignalQualityCallback callback =
416 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
417 weak_ptr_factory_.GetWeakPtr());
418 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100419}
420
Eric Shienbrood9a245532012-03-07 14:20:39 -0500421void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700422 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500423 RegistrationInfoCallback callback =
424 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
425 weak_ptr_factory_.GetWeakPtr());
426 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100427}
428
Eric Shienbrood9a245532012-03-07 14:20:39 -0500429void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700430 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100431
Darin Petkov184c54e2011-11-15 12:44:39 +0100432 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
433 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100434 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700435 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100436
437 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
438 uint32 locks = card_proxy_->EnabledFacilityLocks();
439 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700440 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100441
Eric Shienbrood9a245532012-03-07 14:20:39 -0500442 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100443}
444
Darin Petkovac635a82012-01-10 16:51:58 +0100445string CellularCapabilityGSM::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200446 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
447 string name = serving_operator_.GetName();
448 string home_provider_name = cellular()->home_provider().GetName();
449 if (!name.empty()) {
450 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
451 // rules (TS 31.102 and annex A of 122.101).
452 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING &&
453 !home_provider_name.empty()) {
454 return home_provider_name + " | " + name;
455 }
456 return name;
Darin Petkovac635a82012-01-10 16:51:58 +0100457 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200458 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
459 !home_provider_name.empty()) {
460 return home_provider_name;
Darin Petkovac635a82012-01-10 16:51:58 +0100461 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500462 if (!carrier_.empty()) {
463 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100464 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200465 string serving_operator_code = serving_operator_.GetCode();
466 if (!serving_operator_code.empty()) {
467 return "cellular_" + serving_operator_code;
Darin Petkovac635a82012-01-10 16:51:58 +0100468 }
469 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
470}
471
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100472void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700473 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
474 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100475 // TODO(petkov): The test for NULL provider_db should be done by
476 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500477 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100478 return;
479 }
480 mobile_provider *provider =
481 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500482 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100483 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700484 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100485 return;
486 }
487 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200488 provider_requires_roaming_ = home_provider_->requires_roaming;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100489 Cellular::Operator oper;
Darin Petkovb4fccd22012-08-10 11:59:26 +0200490 if (provider->networks && provider->networks[0]) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100491 oper.SetCode(provider->networks[0]);
492 }
493 if (provider->country) {
494 oper.SetCountry(provider->country);
495 }
496 if (spn_.empty()) {
497 const char *name = mobile_provider_get_name(provider);
498 if (name) {
499 oper.SetName(name);
500 }
501 } else {
502 oper.SetName(spn_);
503 }
504 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200505 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200506 << oper.GetName() << ", " << oper.GetCountry()
507 << (provider_requires_roaming_ ? ", roaming required" : "");
Darin Petkov3cfbf212011-11-21 16:02:09 +0100508 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100509}
510
Darin Petkovae0c64e2011-11-15 15:50:27 +0100511void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700512 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100513 const string &network_id = serving_operator_.GetCode();
514 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700515 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100516 mobile_provider *provider =
517 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100518 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100519 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200520 if (serving_operator_.GetName().empty()) {
521 const char *provider_name = mobile_provider_get_name(provider);
522 if (provider_name && *provider_name) {
523 serving_operator_.SetName(provider_name);
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100524 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100525 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200526 if (provider->country && *provider->country) {
527 serving_operator_.SetCountry(provider->country);
528 }
529 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
530 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100531 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700532 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100533 }
534 }
535 UpdateServingOperator();
536}
537
538void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700539 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100540 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100541 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100542 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100543}
544
Darin Petkov3cfbf212011-11-21 16:02:09 +0100545void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700546 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100547 if (!home_provider_) {
548 return;
549 }
550 apn_list_.clear();
551 for (int i = 0; i < home_provider_->num_apns; ++i) {
552 Stringmap props;
553 mobile_apn *apn = home_provider_->apns[i];
554 if (apn->value) {
555 props[flimflam::kApnProperty] = apn->value;
556 }
557 if (apn->username) {
558 props[flimflam::kApnUsernameProperty] = apn->username;
559 }
560 if (apn->password) {
561 props[flimflam::kApnPasswordProperty] = apn->password;
562 }
563 // Find the first localized and non-localized name, if any.
564 const localized_name *lname = NULL;
565 const localized_name *name = NULL;
566 for (int j = 0; j < apn->num_names; ++j) {
567 if (apn->names[j]->lang) {
568 if (!lname) {
569 lname = apn->names[j];
570 }
571 } else if (!name) {
572 name = apn->names[j];
573 }
574 }
575 if (name) {
576 props[flimflam::kApnNameProperty] = name->name;
577 }
578 if (lname) {
579 props[flimflam::kApnLocalizedNameProperty] = lname->name;
580 props[flimflam::kApnLanguageProperty] = lname->lang;
581 }
582 apn_list_.push_back(props);
583 }
Darin Petkovdb6083f2012-08-16 12:50:23 +0200584 if (cellular()->adaptor()) {
585 cellular()->adaptor()->EmitStringmapsChanged(
586 flimflam::kCellularApnListProperty, apn_list_);
587 } else {
588 LOG(ERROR) << "Null RPC service adaptor.";
589 }
Darin Petkov3cfbf212011-11-21 16:02:09 +0100590}
591
Eric Shienbrood9a245532012-03-07 14:20:39 -0500592// always called from an async context
593void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700594 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500595 CHECK(!callback.is_null());
596 Error error;
597 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
598 weak_ptr_factory_.GetWeakPtr(), callback);
599 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
600 if (error.IsFailure())
601 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100602}
603
604void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500605 const string &network_id,
606 Error *error,
607 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700608 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500609 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500610 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500611 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
612 weak_ptr_factory_.GetWeakPtr(), callback);
613 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500614}
615
Eric Shienbrood9a245532012-03-07 14:20:39 -0500616void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
617 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700618 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500619
620 if (error.IsSuccess()) {
621 selected_network_ = desired_network_;
622 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500623 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500624 return;
625 }
626 // If registration on the desired network failed,
627 // try to register on the home network.
628 if (!desired_network_.empty()) {
629 desired_network_.clear();
630 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500631 LOG(INFO) << "Couldn't register on selected network, trying home network";
632 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500633 return;
634 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500635 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100636}
637
Darin Petkovb72cf402011-11-22 14:51:39 +0100638bool CellularCapabilityGSM::IsRegistered() {
639 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
640 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
641}
642
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400643void CellularCapabilityGSM::SetUnregistered(bool searching) {
644 // If we're already in some non-registered state, don't override that
645 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
646 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
647 registration_state_ =
648 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
649 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
650 }
651}
652
Darin Petkovb05315f2011-11-07 10:14:25 +0100653void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500654 const std::string &pin, bool require,
655 Error *error, const ResultCallback &callback) {
656 CHECK(error);
657 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100658}
659
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100660void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500661 Error *error,
662 const ResultCallback &callback) {
663 CHECK(error);
664 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100665}
666
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100667void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
668 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500669 Error *error,
670 const ResultCallback &callback) {
671 CHECK(error);
672 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100673}
674
675void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500676 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500677 Error *error, const ResultCallback &callback) {
678 CHECK(error);
679 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100680}
681
Eric Shienbrood9a245532012-03-07 14:20:39 -0500682void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700683 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500684 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400685 if (scanning_) {
686 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
687 return;
688 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500689 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
690 weak_ptr_factory_.GetWeakPtr(), callback);
691 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400692 if (!error->IsFailure()) {
693 scanning_ = true;
694 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
695 scanning_);
696 }
Darin Petkov1272a432011-11-10 15:53:37 +0100697}
698
Eric Shienbrood9a245532012-03-07 14:20:39 -0500699void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
700 const GSMScanResults &results,
701 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700702 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400703
704 // Error handling is weak. The current expectation is that on any
705 // error, found_networks_ should be cleared and a property change
706 // notification sent out.
707 //
708 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400709 scanning_ = false;
710 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
711 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500712 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400713 if (!error.IsFailure()) {
714 for (GSMScanResults::const_iterator it = results.begin();
715 it != results.end(); ++it) {
716 found_networks_.push_back(ParseScanResult(*it));
717 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500718 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100719 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
720 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700721 if (!callback.is_null())
722 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500723}
724
725Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100726 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500727 for (GSMScanResult::const_iterator it = result.begin();
728 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100729 // TODO(petkov): Define these in system_api/service_constants.h. The
730 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
731 static const char * const kStatusString[] = {
732 "unknown",
733 "available",
734 "current",
735 "forbidden",
736 };
737 static const char * const kTechnologyString[] = {
738 flimflam::kNetworkTechnologyGsm,
739 "GSM Compact",
740 flimflam::kNetworkTechnologyUmts,
741 flimflam::kNetworkTechnologyEdge,
742 "HSDPA",
743 "HSUPA",
744 flimflam::kNetworkTechnologyHspa,
745 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700746 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
747 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100748 if (it->first == kNetworkPropertyStatus) {
749 int status = 0;
750 if (base::StringToInt(it->second, &status) &&
751 status >= 0 &&
752 status < static_cast<int>(arraysize(kStatusString))) {
753 parsed[flimflam::kStatusProperty] = kStatusString[status];
754 } else {
755 LOG(ERROR) << "Unexpected status value: " << it->second;
756 }
757 } else if (it->first == kNetworkPropertyID) {
758 parsed[flimflam::kNetworkIdProperty] = it->second;
759 } else if (it->first == kNetworkPropertyLongName) {
760 parsed[flimflam::kLongNameProperty] = it->second;
761 } else if (it->first == kNetworkPropertyShortName) {
762 parsed[flimflam::kShortNameProperty] = it->second;
763 } else if (it->first == kNetworkPropertyAccessTechnology) {
764 int tech = 0;
765 if (base::StringToInt(it->second, &tech) &&
766 tech >= 0 &&
767 tech < static_cast<int>(arraysize(kTechnologyString))) {
768 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
769 } else {
770 LOG(ERROR) << "Unexpected technology value: " << it->second;
771 }
772 } else {
773 LOG(WARNING) << "Unknown network property ignored: " << it->first;
774 }
775 }
776 // If the long name is not available but the network ID is, look up the long
777 // name in the mobile provider database.
778 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
779 parsed[flimflam::kLongNameProperty].empty()) &&
780 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
781 mobile_provider *provider =
782 mobile_provider_lookup_by_network(
783 cellular()->provider_db(),
784 parsed[flimflam::kNetworkIdProperty].c_str());
785 if (provider) {
786 const char *long_name = mobile_provider_get_name(provider);
787 if (long_name && *long_name) {
788 parsed[flimflam::kLongNameProperty] = long_name;
789 }
790 }
791 }
792 return parsed;
793}
794
Darin Petkovae0c64e2011-11-15 15:50:27 +0100795void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
796 access_technology_ = access_technology;
797 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100798 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100799 }
800}
801
Darin Petkov20c13ec2011-11-09 15:07:15 +0100802string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100803 switch (access_technology_) {
804 case MM_MODEM_GSM_ACCESS_TECH_GSM:
805 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
806 return flimflam::kNetworkTechnologyGsm;
807 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
808 return flimflam::kNetworkTechnologyGprs;
809 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
810 return flimflam::kNetworkTechnologyEdge;
811 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
812 return flimflam::kNetworkTechnologyUmts;
813 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
814 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
815 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
816 return flimflam::kNetworkTechnologyHspa;
817 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
818 return flimflam::kNetworkTechnologyHspaPlus;
819 default:
820 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100821 }
822 return "";
823}
824
825string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100826 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100827 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
828 return flimflam::kRoamingStateHome;
829 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
830 return flimflam::kRoamingStateRoaming;
831 default:
832 break;
833 }
834 return flimflam::kRoamingStateUnknown;
835}
836
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400837void CellularCapabilityGSM::OnDBusPropertiesChanged(
838 const string &interface,
839 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400840 const vector<string> &invalidated_properties) {
841 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
842 properties,
843 invalidated_properties);
844 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
845 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
846 if (DBusProperties::GetUint32(properties,
847 kPropertyAccessTechnology,
848 &access_technology)) {
849 SetAccessTechnology(access_technology);
850 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700851 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400852 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700853 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
854 uint32 locks = 0;
855 if (DBusProperties::GetUint32(
856 properties, kPropertyEnabledFacilityLocks, &locks)) {
857 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
858 emit = true;
859 }
860 } else if (interface == MM_MODEM_INTERFACE) {
861 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
862 &sim_lock_status_.lock_type)) {
863 emit = true;
864 }
865 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
866 &sim_lock_status_.retries_left)) {
867 emit = true;
868 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400869 }
870 if (emit) {
871 cellular()->adaptor()->EmitKeyValueStoreChanged(
872 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
873 }
Darin Petkov63138a92012-02-06 14:09:15 +0100874 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100875}
876
Eric Shienbrood9a245532012-03-07 14:20:39 -0500877void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100878 // TODO(petkov): Implement this.
879 NOTIMPLEMENTED();
880}
881
Eric Shienbrood9a245532012-03-07 14:20:39 -0500882void CellularCapabilityGSM::OnRegistrationInfoSignal(
883 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700884 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
885 << ", opercode=" << operator_code
886 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500887 registration_state_ = status;
888 serving_operator_.SetCode(operator_code);
889 serving_operator_.SetName(operator_name);
890 UpdateOperatorInfo();
891 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100892}
893
Eric Shienbrood9a245532012-03-07 14:20:39 -0500894void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100895 cellular()->HandleNewSignalQuality(quality);
896}
897
Eric Shienbrood9a245532012-03-07 14:20:39 -0500898void CellularCapabilityGSM::OnGetRegistrationInfoReply(
899 uint32 status, const string &operator_code, const string &operator_name,
900 const Error &error) {
901 if (error.IsSuccess())
902 OnRegistrationInfoSignal(status, operator_code, operator_name);
903}
904
905void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
906 const Error &error) {
907 if (error.IsSuccess())
908 OnSignalQualitySignal(quality);
909}
910
911void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
912 const string &imei,
913 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500914 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700915 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500916 imei_ = imei;
917 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700918 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500919 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500920 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500921}
922
Eric Shienbrood9a245532012-03-07 14:20:39 -0500923void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
924 const string &imsi,
925 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500926 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700927 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500928 imsi_ = imsi;
Ben Chanbd3aee82012-10-16 23:52:04 -0700929 sim_present_ = true;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500930 SetHomeProvider();
Gary Morain82a31a02012-08-02 18:03:32 -0700931 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500932 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -0700933 sim_present_ = false;
Gary Morain82a31a02012-08-02 18:03:32 -0700934 if (get_imsi_retries_++ < kGetIMSIRetryLimit) {
935 SLOG(Cellular, 2) << "GetIMSI failed - " << error << ". Retrying";
936 base::Callback<void(void)> retry_get_imsi_cb =
937 Bind(&CellularCapabilityGSM::GetIMSI,
938 weak_ptr_factory_.GetWeakPtr(), callback);
939 cellular()->dispatcher()->PostDelayedTask(
940 retry_get_imsi_cb,
941 get_imsi_retry_delay_milliseconds_);
942 } else {
943 LOG(INFO) << "GetIMSI failed - " << error;
944 callback.Run(error);
945 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500946 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500947}
948
Eric Shienbrood9a245532012-03-07 14:20:39 -0500949void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
950 const string &spn,
951 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500952 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700953 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500954 spn_ = spn;
955 SetHomeProvider();
956 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700957 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500958 }
Thieu Le923006b2012-04-05 16:32:58 -0700959 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500960}
961
Eric Shienbrood9a245532012-03-07 14:20:39 -0500962void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
963 const string &msisdn,
964 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500965 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700966 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500967 mdn_ = msisdn;
968 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700969 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500970 }
Thieu Le923006b2012-04-05 16:32:58 -0700971 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500972}
973
Darin Petkovdaf43862011-10-27 11:37:28 +0200974} // namespace shill