blob: 7e61185450fe3b2e7381753e9053365250d40793 [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
7#include <base/logging.h>
Darin Petkov1272a432011-11-10 15:53:37 +01008#include <base/stl_util-inl.h>
9#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010010#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010011#include <chromeos/dbus/service_constants.h>
12#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010013#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020014
Darin Petkov3cfbf212011-11-21 16:02:09 +010015#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010016#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050017#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010018#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020019#include "shill/proxy_factory.h"
20
Darin Petkov721ac932011-11-16 15:43:09 +010021using std::make_pair;
Darin Petkovb05315f2011-11-07 10:14:25 +010022using std::string;
23
Darin Petkovdaf43862011-10-27 11:37:28 +020024namespace shill {
25
Darin Petkovac635a82012-01-10 16:51:58 +010026// static
27unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
28
Darin Petkov1272a432011-11-10 15:53:37 +010029const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
30 "access-tech";
31const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
32const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
33const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
34 "operator-short";
35const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010036const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
37const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
38 "AccessTechnology";
Darin Petkov721ac932011-11-16 15:43:09 +010039const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
40const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010041
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050042CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
43 ProxyFactory *proxy_factory)
44 : CellularCapability(cellular, proxy_factory),
Darin Petkov1272a432011-11-10 15:53:37 +010045 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010046 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010047 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010048 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010049 scanning_(false),
50 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010051 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010052 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010053 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
54 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010055 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
56 &found_networks_);
57 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
58 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010059 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
60 &CellularCapabilityGSM::SimLockStatusToProperty,
61 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010062 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
63 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010064 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010065}
Darin Petkovdaf43862011-10-27 11:37:28 +020066
Darin Petkov721ac932011-11-16 15:43:09 +010067StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
68 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
69 sim_lock_status_.lock_type),
70 make_pair(flimflam::kSIMLockRetriesLeftProperty,
71 sim_lock_status_.retries_left));
72}
73
74void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
75 const string &name,
76 StrIntPair(CellularCapabilityGSM::*get)(Error *),
77 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
78 cellular()->mutable_store()->RegisterDerivedStrIntPair(
79 name,
80 StrIntPairAccessor(
81 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
82 this, get, set)));
83}
84
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050085void CellularCapabilityGSM::StartModem()
86{
87 CellularCapability::StartModem();
Darin Petkovcb547732011-11-09 13:55:26 +010088 card_proxy_.reset(
89 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020090 cellular()->dbus_path(),
91 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010092 network_proxy_.reset(
93 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020094 cellular()->dbus_path(),
95 cellular()->dbus_owner()));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050096 MultiStepAsyncCallHandler *call_handler =
97 new MultiStepAsyncCallHandler(cellular()->dispatcher());
98 call_handler->AddTask(task_factory_.NewRunnableMethod(
99 &CellularCapabilityGSM::EnableModem, call_handler));
100
101 call_handler->AddTask(task_factory_.NewRunnableMethod(
102 &CellularCapabilityGSM::Register, call_handler));
103
104 call_handler->AddTask(task_factory_.NewRunnableMethod(
105 &CellularCapabilityGSM::GetModemStatus, call_handler));
106
107 call_handler->AddTask(task_factory_.NewRunnableMethod(
108 &CellularCapabilityGSM::GetIMEI, call_handler));
109
110 call_handler->AddTask(task_factory_.NewRunnableMethod(
111 &CellularCapabilityGSM::GetIMSI, call_handler));
112
113 call_handler->AddTask(task_factory_.NewRunnableMethod(
114 &CellularCapabilityGSM::GetSPN, call_handler));
115
116 call_handler->AddTask(task_factory_.NewRunnableMethod(
117 &CellularCapabilityGSM::GetMSISDN, call_handler));
118
119 call_handler->AddTask(task_factory_.NewRunnableMethod(
120 &CellularCapabilityGSM::GetProperties, call_handler));
121
122 call_handler->AddTask(task_factory_.NewRunnableMethod(
123 &CellularCapabilityGSM::GetModemInfo, call_handler));
124
125 call_handler->AddTask(task_factory_.NewRunnableMethod(
126 &CellularCapabilityGSM::GetRegistrationState,
127 call_handler));
128 call_handler->PostNextTask();
Darin Petkovdaf43862011-10-27 11:37:28 +0200129}
130
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500131void CellularCapabilityGSM::StopModem() {
Darin Petkov721ac932011-11-16 15:43:09 +0100132 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500133 CellularCapability::StopModem();
Darin Petkov721ac932011-11-16 15:43:09 +0100134 card_proxy_.reset();
135 network_proxy_.reset();
136}
137
Darin Petkov5f316f62011-11-18 12:10:26 +0100138void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100139 // If IMSI is available, base the service's storage identifier on it.
140 if (!imsi_.empty()) {
141 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100142 string(flimflam::kTypeCellular) + "_" +
143 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100144 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100145 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100146 flimflam::kActivationStateActivated);
147 UpdateServingOperator();
148}
149
Darin Petkovae0c64e2011-11-15 15:50:27 +0100150void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500151 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100152 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100153 }
154}
155
156void CellularCapabilityGSM::SetupConnectProperties(
157 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500158 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100159 kPhoneNumber);
160 // TODO(petkov): Setup apn and "home_only".
161}
162
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500163void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100164 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500165 if (imei_.empty()) {
166 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
167 } else {
168 VLOG(2) << "Already have IMEI " << imei_;
169 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100170 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500171}
172
173void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
174 VLOG(2) << __func__;
175 if (imsi_.empty()) {
176 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
177 } else {
178 VLOG(2) << "Already have IMSI " << imsi_;
179 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100180 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500181}
182
183void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
184 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100185 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500186 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
187 } else {
188 VLOG(2) << "Already have SPN " << spn_;
189 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100190 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500191}
192
193void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
194 VLOG(2) << __func__;
195 if (mdn_.empty()) {
196 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
197 } else {
198 VLOG(2) << "Already have MSISDN " << mdn_;
199 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100200 }
201}
202
Darin Petkov3e509242011-11-10 14:46:44 +0100203void CellularCapabilityGSM::GetSignalQuality() {
204 VLOG(2) << __func__;
205 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100206 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100207 cellular()->HandleNewSignalQuality(strength);
208}
209
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500210void CellularCapabilityGSM::GetRegistrationState(
211 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100212 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500213 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100214}
215
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500216void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100217 VLOG(2) << __func__;
218 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
219 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100220 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100221 VLOG(2) << "GSM AccessTechnology: " << tech;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500222 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100223}
224
Darin Petkovac635a82012-01-10 16:51:58 +0100225string CellularCapabilityGSM::CreateFriendlyServiceName() {
226 VLOG(2) << __func__;
227 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
228 !cellular()->home_provider().GetName().empty()) {
229 return cellular()->home_provider().GetName();
230 }
231 if (!serving_operator_.GetName().empty()) {
232 return serving_operator_.GetName();
233 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500234 if (!carrier_.empty()) {
235 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100236 }
237 if (!serving_operator_.GetCode().empty()) {
238 return "cellular_" + serving_operator_.GetCode();
239 }
240 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
241}
242
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100243void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500244 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100245 << " SPN: " << spn_ << ")";
246 // TODO(petkov): The test for NULL provider_db should be done by
247 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500248 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100249 return;
250 }
251 mobile_provider *provider =
252 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500253 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100254 if (!provider) {
255 VLOG(2) << "GSM provider not found.";
256 return;
257 }
258 home_provider_ = provider;
259 Cellular::Operator oper;
260 if (provider->networks) {
261 oper.SetCode(provider->networks[0]);
262 }
263 if (provider->country) {
264 oper.SetCountry(provider->country);
265 }
266 if (spn_.empty()) {
267 const char *name = mobile_provider_get_name(provider);
268 if (name) {
269 oper.SetName(name);
270 }
271 } else {
272 oper.SetName(spn_);
273 }
274 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100275 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100276}
277
Darin Petkovae0c64e2011-11-15 15:50:27 +0100278void CellularCapabilityGSM::UpdateOperatorInfo() {
279 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100280 const string &network_id = serving_operator_.GetCode();
281 if (!network_id.empty()) {
282 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100283 mobile_provider *provider =
284 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100285 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100286 if (provider) {
287 const char *provider_name = mobile_provider_get_name(provider);
288 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100289 serving_operator_.SetName(provider_name);
290 if (provider->country) {
291 serving_operator_.SetCountry(provider->country);
292 }
293 VLOG(2) << "Operator name: " << serving_operator_.GetName()
294 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100295 }
296 } else {
297 VLOG(2) << "GSM provider not found.";
298 }
299 }
300 UpdateServingOperator();
301}
302
303void CellularCapabilityGSM::UpdateServingOperator() {
304 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100305 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100306 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100307 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100308}
309
Darin Petkov3cfbf212011-11-21 16:02:09 +0100310void CellularCapabilityGSM::InitAPNList() {
311 VLOG(2) << __func__;
312 if (!home_provider_) {
313 return;
314 }
315 apn_list_.clear();
316 for (int i = 0; i < home_provider_->num_apns; ++i) {
317 Stringmap props;
318 mobile_apn *apn = home_provider_->apns[i];
319 if (apn->value) {
320 props[flimflam::kApnProperty] = apn->value;
321 }
322 if (apn->username) {
323 props[flimflam::kApnUsernameProperty] = apn->username;
324 }
325 if (apn->password) {
326 props[flimflam::kApnPasswordProperty] = apn->password;
327 }
328 // Find the first localized and non-localized name, if any.
329 const localized_name *lname = NULL;
330 const localized_name *name = NULL;
331 for (int j = 0; j < apn->num_names; ++j) {
332 if (apn->names[j]->lang) {
333 if (!lname) {
334 lname = apn->names[j];
335 }
336 } else if (!name) {
337 name = apn->names[j];
338 }
339 }
340 if (name) {
341 props[flimflam::kApnNameProperty] = name->name;
342 }
343 if (lname) {
344 props[flimflam::kApnLocalizedNameProperty] = lname->name;
345 props[flimflam::kApnLanguageProperty] = lname->lang;
346 }
347 apn_list_.push_back(props);
348 }
349 cellular()->adaptor()->EmitStringmapsChanged(
350 flimflam::kCellularApnListProperty, apn_list_);
351}
352
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500353void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
354 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
355 network_proxy_->Register(selected_network_, call_handler,
356 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100357}
358
359void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500360 const string &network_id, AsyncCallHandler *call_handler) {
361 VLOG(2) << __func__ << "(" << network_id << ")";
362 desired_network_ = network_id;
363 network_proxy_->Register(network_id, call_handler,
364 kTimeoutRegister);
365}
366
367void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
368 AsyncCallHandler *call_handler) {
369 VLOG(2) << __func__ << "(" << error << ")";
370
371 if (error.IsSuccess()) {
372 selected_network_ = desired_network_;
373 desired_network_.clear();
374 CompleteOperation(call_handler);
375 return;
376 }
377 // If registration on the desired network failed,
378 // try to register on the home network.
379 if (!desired_network_.empty()) {
380 desired_network_.clear();
381 selected_network_.clear();
382 Register(call_handler);
383 return;
384 }
385 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100386}
387
Darin Petkovb72cf402011-11-22 14:51:39 +0100388bool CellularCapabilityGSM::IsRegistered() {
389 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
390 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
391}
392
Darin Petkovb05315f2011-11-07 10:14:25 +0100393void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500394 const string &pin, bool require, AsyncCallHandler *call_handler) {
395 VLOG(2) << __func__ << "(" << call_handler << ")";
396 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100397}
398
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100399void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500400 AsyncCallHandler *call_handler) {
401 VLOG(2) << __func__ << "(" << call_handler << ")";
402 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100403}
404
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100405void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
406 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500407 AsyncCallHandler *call_handler) {
408 VLOG(2) << __func__ << "(" << call_handler << ")";
409 card_proxy_->SendPUK(unblock_code, pin, call_handler,
410 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100411}
412
413void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500414 const string &old_pin, const string &new_pin,
415 AsyncCallHandler *call_handler) {
416 VLOG(2) << __func__ << "(" << call_handler << ")";
417 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
418 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100419}
420
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500421void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100422 VLOG(2) << __func__;
423 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500424 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100425}
426
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500427void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
428 const Error &error,
429 AsyncCallHandler *call_handler) {
430 VLOG(2) << __func__;
431 if (error.IsFailure()) {
432 CompleteOperation(call_handler, error);
433 return;
434 }
435 found_networks_.clear();
436 for (GSMScanResults::const_iterator it = results.begin();
437 it != results.end(); ++it) {
438 found_networks_.push_back(ParseScanResult(*it));
439 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100440 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
441 found_networks_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500442 CompleteOperation(call_handler);
443}
444
445Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100446 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500447 for (GSMScanResult::const_iterator it = result.begin();
448 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100449 // TODO(petkov): Define these in system_api/service_constants.h. The
450 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
451 static const char * const kStatusString[] = {
452 "unknown",
453 "available",
454 "current",
455 "forbidden",
456 };
457 static const char * const kTechnologyString[] = {
458 flimflam::kNetworkTechnologyGsm,
459 "GSM Compact",
460 flimflam::kNetworkTechnologyUmts,
461 flimflam::kNetworkTechnologyEdge,
462 "HSDPA",
463 "HSUPA",
464 flimflam::kNetworkTechnologyHspa,
465 };
466 VLOG(2) << "Network property: " << it->first << " = " << it->second;
467 if (it->first == kNetworkPropertyStatus) {
468 int status = 0;
469 if (base::StringToInt(it->second, &status) &&
470 status >= 0 &&
471 status < static_cast<int>(arraysize(kStatusString))) {
472 parsed[flimflam::kStatusProperty] = kStatusString[status];
473 } else {
474 LOG(ERROR) << "Unexpected status value: " << it->second;
475 }
476 } else if (it->first == kNetworkPropertyID) {
477 parsed[flimflam::kNetworkIdProperty] = it->second;
478 } else if (it->first == kNetworkPropertyLongName) {
479 parsed[flimflam::kLongNameProperty] = it->second;
480 } else if (it->first == kNetworkPropertyShortName) {
481 parsed[flimflam::kShortNameProperty] = it->second;
482 } else if (it->first == kNetworkPropertyAccessTechnology) {
483 int tech = 0;
484 if (base::StringToInt(it->second, &tech) &&
485 tech >= 0 &&
486 tech < static_cast<int>(arraysize(kTechnologyString))) {
487 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
488 } else {
489 LOG(ERROR) << "Unexpected technology value: " << it->second;
490 }
491 } else {
492 LOG(WARNING) << "Unknown network property ignored: " << it->first;
493 }
494 }
495 // If the long name is not available but the network ID is, look up the long
496 // name in the mobile provider database.
497 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
498 parsed[flimflam::kLongNameProperty].empty()) &&
499 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
500 mobile_provider *provider =
501 mobile_provider_lookup_by_network(
502 cellular()->provider_db(),
503 parsed[flimflam::kNetworkIdProperty].c_str());
504 if (provider) {
505 const char *long_name = mobile_provider_get_name(provider);
506 if (long_name && *long_name) {
507 parsed[flimflam::kLongNameProperty] = long_name;
508 }
509 }
510 }
511 return parsed;
512}
513
Darin Petkovae0c64e2011-11-15 15:50:27 +0100514void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
515 access_technology_ = access_technology;
516 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100517 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100518 }
519}
520
Darin Petkov20c13ec2011-11-09 15:07:15 +0100521string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100522 switch (access_technology_) {
523 case MM_MODEM_GSM_ACCESS_TECH_GSM:
524 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
525 return flimflam::kNetworkTechnologyGsm;
526 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
527 return flimflam::kNetworkTechnologyGprs;
528 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
529 return flimflam::kNetworkTechnologyEdge;
530 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
531 return flimflam::kNetworkTechnologyUmts;
532 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
533 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
534 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
535 return flimflam::kNetworkTechnologyHspa;
536 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
537 return flimflam::kNetworkTechnologyHspaPlus;
538 default:
539 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100540 }
541 return "";
542}
543
544string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100545 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100546 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
547 return flimflam::kRoamingStateHome;
548 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
549 return flimflam::kRoamingStateRoaming;
550 default:
551 break;
552 }
553 return flimflam::kRoamingStateUnknown;
554}
555
Darin Petkovae0c64e2011-11-15 15:50:27 +0100556void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
557 const DBusPropertiesMap &properties) {
558 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
559 if (DBusProperties::GetUint32(properties,
560 kPropertyAccessTechnology,
561 &access_technology)) {
562 SetAccessTechnology(access_technology);
563 }
Darin Petkov721ac932011-11-16 15:43:09 +0100564 DBusProperties::GetString(
565 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
566 DBusProperties::GetUint32(
567 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100568}
569
Darin Petkov184c54e2011-11-15 12:44:39 +0100570void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
571 // TODO(petkov): Implement this.
572 NOTIMPLEMENTED();
573}
574
575void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500576 uint32 status, const string &operator_code, const string &operator_name,
577 const Error &error, AsyncCallHandler *call_handler) {
578 if (error.IsSuccess()) {
579 VLOG(2) << __func__ << ": regstate=" << status
580 << ", opercode=" << operator_code
581 << ", opername=" << operator_name;
582 registration_state_ = status;
583 serving_operator_.SetCode(operator_code);
584 serving_operator_.SetName(operator_name);
585 UpdateOperatorInfo();
586 cellular()->HandleNewRegistrationState();
587 }
588 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100589}
590
591void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
592 cellular()->HandleNewSignalQuality(quality);
593}
594
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500595void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
596 const Error &error,
597 AsyncCallHandler *call_handler) {
598 if (error.IsSuccess()) {
599 VLOG(2) << "IMEI: " << imei;
600 imei_ = imei;
601 } else {
602 VLOG(2) << "GetIMEI failed - " << error;
603 }
604 CompleteOperation(call_handler, error);
605}
606
607void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
608 const Error &error,
609 AsyncCallHandler *call_handler) {
610 if (error.IsSuccess()) {
611 VLOG(2) << "IMSI: " << imsi;
612 imsi_ = imsi;
613 SetHomeProvider();
614 } else {
615 VLOG(2) << "GetIMSI failed - " << error;
616 }
617 CompleteOperation(call_handler, error);
618}
619
620void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
621 const Error &error,
622 AsyncCallHandler *call_handler) {
623 if (error.IsSuccess()) {
624 VLOG(2) << "SPN: " << spn;
625 spn_ = spn;
626 SetHomeProvider();
627 } else {
628 VLOG(2) << "GetSPN failed - " << error;
629 }
630 // Ignore the error - it's not fatal.
631 CompleteOperation(call_handler);
632}
633
634void CellularCapabilityGSM::OnGetMSISDNCallback(
635 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
636 if (error.IsSuccess()) {
637 VLOG(2) << "MSISDN: " << msisdn;
638 mdn_ = msisdn;
639 } else {
640 VLOG(2) << "GetMSISDN failed - " << error;
641 }
642 // Ignore the error - it's not fatal.
643 CompleteOperation(call_handler);
644}
645
646void CellularCapabilityGSM::OnPINOperationCallback(
647 const Error &error, AsyncCallHandler *call_handler) {
648 if (error.IsFailure())
649 VLOG(2) << "PIN operation failed - " << error;
650 else
651 VLOG(2) << "PIN operation complete";
652 CompleteOperation(call_handler, error);
653}
654
Darin Petkovdaf43862011-10-27 11:37:28 +0200655} // namespace shill