blob: 6a7e88e7cf7393b0a60ec6f896eb906b95cecfd4 [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
Eric Shienbrood3e20a232012-02-16 11:35:56 -05007#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +02008#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010010#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010011#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010012#include <chromeos/dbus/service_constants.h>
13#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010014#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020015
Darin Petkov3cfbf212011-11-21 16:02:09 +010016#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010017#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050018#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010019#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/proxy_factory.h"
21
Eric Shienbrood3e20a232012-02-16 11:35:56 -050022using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010023using std::string;
24
Darin Petkovdaf43862011-10-27 11:37:28 +020025namespace shill {
26
Darin Petkovac635a82012-01-10 16:51:58 +010027// static
28unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
29
Darin Petkov1272a432011-11-10 15:53:37 +010030const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
31 "access-tech";
32const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
33const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
34const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
35 "operator-short";
36const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010037const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
38const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
39 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010040const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
41 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010042const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
43const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010044
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050045CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
46 ProxyFactory *proxy_factory)
47 : CellularCapability(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010049 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010050 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010051 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010052 scanning_(false),
53 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010054 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010055 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010056 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
57 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010058 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
59 &found_networks_);
60 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
61 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010062 HelpRegisterDerivedKeyValueStore(
63 flimflam::kSIMLockStatusProperty,
64 &CellularCapabilityGSM::SimLockStatusToProperty,
65 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010066 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
67 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010068 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010069}
Darin Petkovdaf43862011-10-27 11:37:28 +020070
Darin Petkov63138a92012-02-06 14:09:15 +010071KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
72 KeyValueStore status;
73 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
74 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
75 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
76 sim_lock_status_.retries_left);
77 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010078}
79
Darin Petkov63138a92012-02-06 14:09:15 +010080void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010081 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010082 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
83 void(CellularCapabilityGSM::*set)(
84 const KeyValueStore &value, Error *error)) {
85 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010086 name,
Darin Petkov63138a92012-02-06 14:09:15 +010087 KeyValueStoreAccessor(
88 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +010089 this, get, set)));
90}
91
Eric Shienbrood9a245532012-03-07 14:20:39 -050092void CellularCapabilityGSM::InitProxies() {
93 CellularCapability::InitProxies();
Darin Petkovcb547732011-11-09 13:55:26 +010094 card_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050095 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020096 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010097 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050098 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020099 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500100 network_proxy_->set_signal_quality_callback(
101 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
102 weak_ptr_factory_.GetWeakPtr()));
103 network_proxy_->set_network_mode_callback(
104 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
105 weak_ptr_factory_.GetWeakPtr()));
106 network_proxy_->set_registration_info_callback(
107 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
108 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200109}
110
Eric Shienbrood9a245532012-03-07 14:20:39 -0500111void CellularCapabilityGSM::StartModem(Error *error,
112 const ResultCallback &callback) {
113 InitProxies();
114
115 CellularTaskList *tasks = new CellularTaskList();
116 ResultCallback cb =
117 Bind(&CellularCapabilityGSM::StepCompletedCallback,
118 weak_ptr_factory_.GetWeakPtr(), callback, tasks);
119 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
120 weak_ptr_factory_.GetWeakPtr(), cb));
121 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
122 weak_ptr_factory_.GetWeakPtr(), cb));
123 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemStatus,
124 weak_ptr_factory_.GetWeakPtr(), cb));
125 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
126 weak_ptr_factory_.GetWeakPtr(), cb));
127 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
128 weak_ptr_factory_.GetWeakPtr(), cb));
129 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
130 weak_ptr_factory_.GetWeakPtr(), cb));
131 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
132 weak_ptr_factory_.GetWeakPtr(), cb));
133 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
134 weak_ptr_factory_.GetWeakPtr(), cb));
135 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
136 weak_ptr_factory_.GetWeakPtr(), cb));
137 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
138 weak_ptr_factory_.GetWeakPtr(), cb));
139
140 RunNextStep(tasks);
141}
142
143void CellularCapabilityGSM::StopModem(Error *error,
144 const ResultCallback &callback) {
Darin Petkov721ac932011-11-16 15:43:09 +0100145 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500146
147 CellularTaskList *tasks = new CellularTaskList();
148 ResultCallback cb =
149 Bind(&CellularCapabilityGSM::StepCompletedCallback,
150 weak_ptr_factory_.GetWeakPtr(), callback, tasks);
151 tasks->push_back(Bind(&CellularCapabilityGSM::Disconnect,
152 weak_ptr_factory_.GetWeakPtr(),
153 static_cast<Error *>(NULL), cb));
154 tasks->push_back(Bind(&CellularCapabilityGSM::DisableModem,
155 weak_ptr_factory_.GetWeakPtr(), cb));
156 tasks->push_back(Bind(&CellularCapabilityGSM::FinishDisable,
157 weak_ptr_factory_.GetWeakPtr(), cb));
158
159 RunNextStep(tasks);
160}
161
162void CellularCapabilityGSM::ReleaseProxies() {
163 VLOG(2) << __func__;
164 CellularCapability::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100165 card_proxy_.reset();
166 network_proxy_.reset();
167}
168
Darin Petkov5f316f62011-11-18 12:10:26 +0100169void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100170 // If IMSI is available, base the service's storage identifier on it.
171 if (!imsi_.empty()) {
172 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100173 string(flimflam::kTypeCellular) + "_" +
174 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100175 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100176 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100177 flimflam::kActivationStateActivated);
178 UpdateServingOperator();
179}
180
Darin Petkovae0c64e2011-11-15 15:50:27 +0100181void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500182 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100183 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100184 }
185}
186
187void CellularCapabilityGSM::SetupConnectProperties(
188 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500189 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100190 kPhoneNumber);
191 // TODO(petkov): Setup apn and "home_only".
192}
193
Eric Shienbrood9a245532012-03-07 14:20:39 -0500194// always called from an async context
195void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Darin Petkovcb547732011-11-09 13:55:26 +0100196 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500197 CHECK(!callback.is_null());
198 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500199 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500200 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
201 weak_ptr_factory_.GetWeakPtr(), callback);
202 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
203 if (error.IsFailure())
204 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500205 } else {
206 VLOG(2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500207 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100208 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500209}
210
Eric Shienbrood9a245532012-03-07 14:20:39 -0500211// always called from an async context
212void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500213 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500214 CHECK(!callback.is_null());
215 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500216 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500217 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
218 weak_ptr_factory_.GetWeakPtr(),
219 callback);
220 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
221 if (error.IsFailure())
222 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500223 } else {
224 VLOG(2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500225 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100226 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500227}
228
Eric Shienbrood9a245532012-03-07 14:20:39 -0500229// always called from an async context
230void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500231 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500232 CHECK(!callback.is_null());
233 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100234 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500235 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
236 weak_ptr_factory_.GetWeakPtr(),
237 callback);
238 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
239 if (error.IsFailure())
240 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500241 } else {
242 VLOG(2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500243 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100244 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500245}
246
Eric Shienbrood9a245532012-03-07 14:20:39 -0500247// always called from an async context
248void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500249 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500250 CHECK(!callback.is_null());
251 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500252 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500253 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
254 weak_ptr_factory_.GetWeakPtr(),
255 callback);
256 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
257 if (error.IsFailure())
258 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500259 } else {
260 VLOG(2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500261 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100262 }
263}
264
Darin Petkov3e509242011-11-10 14:46:44 +0100265void CellularCapabilityGSM::GetSignalQuality() {
266 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500267 SignalQualityCallback callback =
268 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
269 weak_ptr_factory_.GetWeakPtr());
270 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100271}
272
Eric Shienbrood9a245532012-03-07 14:20:39 -0500273void CellularCapabilityGSM::GetRegistrationState() {
Darin Petkov184c54e2011-11-15 12:44:39 +0100274 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500275 RegistrationInfoCallback callback =
276 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
277 weak_ptr_factory_.GetWeakPtr());
278 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100279}
280
Eric Shienbrood9a245532012-03-07 14:20:39 -0500281void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100282 VLOG(2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100283
Darin Petkov184c54e2011-11-15 12:44:39 +0100284 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
285 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100286 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100287 VLOG(2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100288
289 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
290 uint32 locks = card_proxy_->EnabledFacilityLocks();
291 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
292 VLOG(2) << "GSM EnabledFacilityLocks: " << locks;
293
Eric Shienbrood9a245532012-03-07 14:20:39 -0500294 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100295}
296
Darin Petkovac635a82012-01-10 16:51:58 +0100297string CellularCapabilityGSM::CreateFriendlyServiceName() {
298 VLOG(2) << __func__;
299 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
300 !cellular()->home_provider().GetName().empty()) {
301 return cellular()->home_provider().GetName();
302 }
303 if (!serving_operator_.GetName().empty()) {
304 return serving_operator_.GetName();
305 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500306 if (!carrier_.empty()) {
307 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100308 }
309 if (!serving_operator_.GetCode().empty()) {
310 return "cellular_" + serving_operator_.GetCode();
311 }
312 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
313}
314
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100315void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500316 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100317 << " SPN: " << spn_ << ")";
318 // TODO(petkov): The test for NULL provider_db should be done by
319 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500320 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100321 return;
322 }
323 mobile_provider *provider =
324 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500325 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100326 if (!provider) {
327 VLOG(2) << "GSM provider not found.";
328 return;
329 }
330 home_provider_ = provider;
331 Cellular::Operator oper;
332 if (provider->networks) {
333 oper.SetCode(provider->networks[0]);
334 }
335 if (provider->country) {
336 oper.SetCountry(provider->country);
337 }
338 if (spn_.empty()) {
339 const char *name = mobile_provider_get_name(provider);
340 if (name) {
341 oper.SetName(name);
342 }
343 } else {
344 oper.SetName(spn_);
345 }
346 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100347 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100348}
349
Darin Petkovae0c64e2011-11-15 15:50:27 +0100350void CellularCapabilityGSM::UpdateOperatorInfo() {
351 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100352 const string &network_id = serving_operator_.GetCode();
353 if (!network_id.empty()) {
354 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100355 mobile_provider *provider =
356 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100357 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100358 if (provider) {
359 const char *provider_name = mobile_provider_get_name(provider);
360 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100361 serving_operator_.SetName(provider_name);
362 if (provider->country) {
363 serving_operator_.SetCountry(provider->country);
364 }
365 VLOG(2) << "Operator name: " << serving_operator_.GetName()
366 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100367 }
368 } else {
369 VLOG(2) << "GSM provider not found.";
370 }
371 }
372 UpdateServingOperator();
373}
374
375void CellularCapabilityGSM::UpdateServingOperator() {
376 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100377 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100378 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100379 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100380}
381
Darin Petkov3cfbf212011-11-21 16:02:09 +0100382void CellularCapabilityGSM::InitAPNList() {
383 VLOG(2) << __func__;
384 if (!home_provider_) {
385 return;
386 }
387 apn_list_.clear();
388 for (int i = 0; i < home_provider_->num_apns; ++i) {
389 Stringmap props;
390 mobile_apn *apn = home_provider_->apns[i];
391 if (apn->value) {
392 props[flimflam::kApnProperty] = apn->value;
393 }
394 if (apn->username) {
395 props[flimflam::kApnUsernameProperty] = apn->username;
396 }
397 if (apn->password) {
398 props[flimflam::kApnPasswordProperty] = apn->password;
399 }
400 // Find the first localized and non-localized name, if any.
401 const localized_name *lname = NULL;
402 const localized_name *name = NULL;
403 for (int j = 0; j < apn->num_names; ++j) {
404 if (apn->names[j]->lang) {
405 if (!lname) {
406 lname = apn->names[j];
407 }
408 } else if (!name) {
409 name = apn->names[j];
410 }
411 }
412 if (name) {
413 props[flimflam::kApnNameProperty] = name->name;
414 }
415 if (lname) {
416 props[flimflam::kApnLocalizedNameProperty] = lname->name;
417 props[flimflam::kApnLanguageProperty] = lname->lang;
418 }
419 apn_list_.push_back(props);
420 }
421 cellular()->adaptor()->EmitStringmapsChanged(
422 flimflam::kCellularApnListProperty, apn_list_);
423}
424
Eric Shienbrood9a245532012-03-07 14:20:39 -0500425// always called from an async context
426void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500427 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500428 CHECK(!callback.is_null());
429 Error error;
430 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
431 weak_ptr_factory_.GetWeakPtr(), callback);
432 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
433 if (error.IsFailure())
434 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100435}
436
437void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500438 const string &network_id,
439 Error *error,
440 const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500441 VLOG(2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500442 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500443 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500444 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
445 weak_ptr_factory_.GetWeakPtr(), callback);
446 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500447}
448
Eric Shienbrood9a245532012-03-07 14:20:39 -0500449void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
450 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500451 VLOG(2) << __func__ << "(" << error << ")";
452
453 if (error.IsSuccess()) {
454 selected_network_ = desired_network_;
455 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500456 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500457 return;
458 }
459 // If registration on the desired network failed,
460 // try to register on the home network.
461 if (!desired_network_.empty()) {
462 desired_network_.clear();
463 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500464 LOG(INFO) << "Couldn't register on selected network, trying home network";
465 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500466 return;
467 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500468 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100469}
470
Darin Petkovb72cf402011-11-22 14:51:39 +0100471bool CellularCapabilityGSM::IsRegistered() {
472 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
473 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
474}
475
Darin Petkovb05315f2011-11-07 10:14:25 +0100476void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500477 const std::string &pin, bool require,
478 Error *error, const ResultCallback &callback) {
479 CHECK(error);
480 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100481}
482
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100483void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500484 Error *error,
485 const ResultCallback &callback) {
486 CHECK(error);
487 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100488}
489
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100490void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
491 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500492 Error *error,
493 const ResultCallback &callback) {
494 CHECK(error);
495 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100496}
497
498void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500499 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500500 Error *error, const ResultCallback &callback) {
501 CHECK(error);
502 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100503}
504
Eric Shienbrood9a245532012-03-07 14:20:39 -0500505void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Darin Petkov1272a432011-11-10 15:53:37 +0100506 VLOG(2) << __func__;
507 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500508 CHECK(error);
509 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
510 weak_ptr_factory_.GetWeakPtr(), callback);
511 network_proxy_->Scan(error, cb, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100512}
513
Eric Shienbrood9a245532012-03-07 14:20:39 -0500514void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
515 const GSMScanResults &results,
516 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500517 VLOG(2) << __func__;
518 if (error.IsFailure()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500519 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500520 return;
521 }
522 found_networks_.clear();
523 for (GSMScanResults::const_iterator it = results.begin();
524 it != results.end(); ++it) {
525 found_networks_.push_back(ParseScanResult(*it));
526 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100527 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
528 found_networks_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500529 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500530}
531
532Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100533 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500534 for (GSMScanResult::const_iterator it = result.begin();
535 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100536 // TODO(petkov): Define these in system_api/service_constants.h. The
537 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
538 static const char * const kStatusString[] = {
539 "unknown",
540 "available",
541 "current",
542 "forbidden",
543 };
544 static const char * const kTechnologyString[] = {
545 flimflam::kNetworkTechnologyGsm,
546 "GSM Compact",
547 flimflam::kNetworkTechnologyUmts,
548 flimflam::kNetworkTechnologyEdge,
549 "HSDPA",
550 "HSUPA",
551 flimflam::kNetworkTechnologyHspa,
552 };
553 VLOG(2) << "Network property: " << it->first << " = " << it->second;
554 if (it->first == kNetworkPropertyStatus) {
555 int status = 0;
556 if (base::StringToInt(it->second, &status) &&
557 status >= 0 &&
558 status < static_cast<int>(arraysize(kStatusString))) {
559 parsed[flimflam::kStatusProperty] = kStatusString[status];
560 } else {
561 LOG(ERROR) << "Unexpected status value: " << it->second;
562 }
563 } else if (it->first == kNetworkPropertyID) {
564 parsed[flimflam::kNetworkIdProperty] = it->second;
565 } else if (it->first == kNetworkPropertyLongName) {
566 parsed[flimflam::kLongNameProperty] = it->second;
567 } else if (it->first == kNetworkPropertyShortName) {
568 parsed[flimflam::kShortNameProperty] = it->second;
569 } else if (it->first == kNetworkPropertyAccessTechnology) {
570 int tech = 0;
571 if (base::StringToInt(it->second, &tech) &&
572 tech >= 0 &&
573 tech < static_cast<int>(arraysize(kTechnologyString))) {
574 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
575 } else {
576 LOG(ERROR) << "Unexpected technology value: " << it->second;
577 }
578 } else {
579 LOG(WARNING) << "Unknown network property ignored: " << it->first;
580 }
581 }
582 // If the long name is not available but the network ID is, look up the long
583 // name in the mobile provider database.
584 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
585 parsed[flimflam::kLongNameProperty].empty()) &&
586 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
587 mobile_provider *provider =
588 mobile_provider_lookup_by_network(
589 cellular()->provider_db(),
590 parsed[flimflam::kNetworkIdProperty].c_str());
591 if (provider) {
592 const char *long_name = mobile_provider_get_name(provider);
593 if (long_name && *long_name) {
594 parsed[flimflam::kLongNameProperty] = long_name;
595 }
596 }
597 }
598 return parsed;
599}
600
Darin Petkovae0c64e2011-11-15 15:50:27 +0100601void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
602 access_technology_ = access_technology;
603 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100604 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100605 }
606}
607
Darin Petkov20c13ec2011-11-09 15:07:15 +0100608string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100609 switch (access_technology_) {
610 case MM_MODEM_GSM_ACCESS_TECH_GSM:
611 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
612 return flimflam::kNetworkTechnologyGsm;
613 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
614 return flimflam::kNetworkTechnologyGprs;
615 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
616 return flimflam::kNetworkTechnologyEdge;
617 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
618 return flimflam::kNetworkTechnologyUmts;
619 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
620 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
621 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
622 return flimflam::kNetworkTechnologyHspa;
623 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
624 return flimflam::kNetworkTechnologyHspaPlus;
625 default:
626 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100627 }
628 return "";
629}
630
631string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100632 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100633 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
634 return flimflam::kRoamingStateHome;
635 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
636 return flimflam::kRoamingStateRoaming;
637 default:
638 break;
639 }
640 return flimflam::kRoamingStateUnknown;
641}
642
Darin Petkovae0c64e2011-11-15 15:50:27 +0100643void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
644 const DBusPropertiesMap &properties) {
645 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
646 if (DBusProperties::GetUint32(properties,
647 kPropertyAccessTechnology,
648 &access_technology)) {
649 SetAccessTechnology(access_technology);
650 }
Darin Petkov63138a92012-02-06 14:09:15 +0100651 bool emit = false;
652 uint32 locks = 0;
653 if (DBusProperties::GetUint32(
654 properties, kPropertyEnabledFacilityLocks, &locks)) {
655 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
656 emit = true;
657 }
658 if (DBusProperties::GetString(
659 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type)) {
660 emit = true;
661 }
662 if (DBusProperties::GetUint32(
663 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left)) {
664 emit = true;
665 }
666 if (emit) {
667 cellular()->adaptor()->EmitKeyValueStoreChanged(
668 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
669 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100670}
671
Eric Shienbrood9a245532012-03-07 14:20:39 -0500672void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100673 // TODO(petkov): Implement this.
674 NOTIMPLEMENTED();
675}
676
Eric Shienbrood9a245532012-03-07 14:20:39 -0500677void CellularCapabilityGSM::OnRegistrationInfoSignal(
678 uint32 status, const string &operator_code, const string &operator_name) {
679 VLOG(2) << __func__ << ": regstate=" << status
680 << ", opercode=" << operator_code
681 << ", opername=" << operator_name;
682 registration_state_ = status;
683 serving_operator_.SetCode(operator_code);
684 serving_operator_.SetName(operator_name);
685 UpdateOperatorInfo();
686 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100687}
688
Eric Shienbrood9a245532012-03-07 14:20:39 -0500689void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100690 cellular()->HandleNewSignalQuality(quality);
691}
692
Eric Shienbrood9a245532012-03-07 14:20:39 -0500693void CellularCapabilityGSM::OnGetRegistrationInfoReply(
694 uint32 status, const string &operator_code, const string &operator_name,
695 const Error &error) {
696 if (error.IsSuccess())
697 OnRegistrationInfoSignal(status, operator_code, operator_name);
698}
699
700void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
701 const Error &error) {
702 if (error.IsSuccess())
703 OnSignalQualitySignal(quality);
704}
705
706void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
707 const string &imei,
708 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500709 if (error.IsSuccess()) {
710 VLOG(2) << "IMEI: " << imei;
711 imei_ = imei;
712 } else {
713 VLOG(2) << "GetIMEI failed - " << error;
714 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500715 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500716}
717
Eric Shienbrood9a245532012-03-07 14:20:39 -0500718void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
719 const string &imsi,
720 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500721 if (error.IsSuccess()) {
722 VLOG(2) << "IMSI: " << imsi;
723 imsi_ = imsi;
724 SetHomeProvider();
725 } else {
726 VLOG(2) << "GetIMSI failed - " << error;
727 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500728 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500729}
730
Eric Shienbrood9a245532012-03-07 14:20:39 -0500731void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
732 const string &spn,
733 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500734 if (error.IsSuccess()) {
735 VLOG(2) << "SPN: " << spn;
736 spn_ = spn;
737 SetHomeProvider();
738 } else {
739 VLOG(2) << "GetSPN failed - " << error;
740 }
741 // Ignore the error - it's not fatal.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500742 callback.Run(Error());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500743}
744
Eric Shienbrood9a245532012-03-07 14:20:39 -0500745void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
746 const string &msisdn,
747 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500748 if (error.IsSuccess()) {
749 VLOG(2) << "MSISDN: " << msisdn;
750 mdn_ = msisdn;
751 } else {
752 VLOG(2) << "GetMSISDN failed - " << error;
753 }
754 // Ignore the error - it's not fatal.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500755 callback.Run(Error());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500756}
757
Darin Petkovdaf43862011-10-27 11:37:28 +0200758} // namespace shill