blob: 34c5877ee7381f952bc91050b135a57259718904 [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 Petkov1272a432011-11-10 15:53:37 +010064}
Darin Petkovdaf43862011-10-27 11:37:28 +020065
Darin Petkov721ac932011-11-16 15:43:09 +010066StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
67 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
68 sim_lock_status_.lock_type),
69 make_pair(flimflam::kSIMLockRetriesLeftProperty,
70 sim_lock_status_.retries_left));
71}
72
73void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
74 const string &name,
75 StrIntPair(CellularCapabilityGSM::*get)(Error *),
76 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
77 cellular()->mutable_store()->RegisterDerivedStrIntPair(
78 name,
79 StrIntPairAccessor(
80 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
81 this, get, set)));
82}
83
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050084void CellularCapabilityGSM::StartModem()
85{
86 CellularCapability::StartModem();
Darin Petkovcb547732011-11-09 13:55:26 +010087 card_proxy_.reset(
88 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020089 cellular()->dbus_path(),
90 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010091 network_proxy_.reset(
92 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020093 cellular()->dbus_path(),
94 cellular()->dbus_owner()));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050095 MultiStepAsyncCallHandler *call_handler =
96 new MultiStepAsyncCallHandler(cellular()->dispatcher());
97 call_handler->AddTask(task_factory_.NewRunnableMethod(
98 &CellularCapabilityGSM::EnableModem, call_handler));
99
100 call_handler->AddTask(task_factory_.NewRunnableMethod(
101 &CellularCapabilityGSM::Register, call_handler));
102
103 call_handler->AddTask(task_factory_.NewRunnableMethod(
104 &CellularCapabilityGSM::GetModemStatus, call_handler));
105
106 call_handler->AddTask(task_factory_.NewRunnableMethod(
107 &CellularCapabilityGSM::GetIMEI, call_handler));
108
109 call_handler->AddTask(task_factory_.NewRunnableMethod(
110 &CellularCapabilityGSM::GetIMSI, call_handler));
111
112 call_handler->AddTask(task_factory_.NewRunnableMethod(
113 &CellularCapabilityGSM::GetSPN, call_handler));
114
115 call_handler->AddTask(task_factory_.NewRunnableMethod(
116 &CellularCapabilityGSM::GetMSISDN, call_handler));
117
118 call_handler->AddTask(task_factory_.NewRunnableMethod(
119 &CellularCapabilityGSM::GetProperties, call_handler));
120
121 call_handler->AddTask(task_factory_.NewRunnableMethod(
122 &CellularCapabilityGSM::GetModemInfo, call_handler));
123
124 call_handler->AddTask(task_factory_.NewRunnableMethod(
125 &CellularCapabilityGSM::GetRegistrationState,
126 call_handler));
127 call_handler->PostNextTask();
Darin Petkovdaf43862011-10-27 11:37:28 +0200128}
129
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500130void CellularCapabilityGSM::StopModem() {
Darin Petkov721ac932011-11-16 15:43:09 +0100131 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500132 CellularCapability::StopModem();
Darin Petkov721ac932011-11-16 15:43:09 +0100133 card_proxy_.reset();
134 network_proxy_.reset();
135}
136
Darin Petkov5f316f62011-11-18 12:10:26 +0100137void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100138 // If IMSI is available, base the service's storage identifier on it.
139 if (!imsi_.empty()) {
140 cellular()->service()->SetStorageIdentifier(
141 "cellular_" + cellular()->address() + "_" + imsi_);
142 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100143 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100144 flimflam::kActivationStateActivated);
145 UpdateServingOperator();
146}
147
Darin Petkovae0c64e2011-11-15 15:50:27 +0100148void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500149 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100150 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100151 }
152}
153
154void CellularCapabilityGSM::SetupConnectProperties(
155 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500156 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100157 kPhoneNumber);
158 // TODO(petkov): Setup apn and "home_only".
159}
160
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500161void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100162 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500163 if (imei_.empty()) {
164 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
165 } else {
166 VLOG(2) << "Already have IMEI " << imei_;
167 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100168 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500169}
170
171void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
172 VLOG(2) << __func__;
173 if (imsi_.empty()) {
174 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
175 } else {
176 VLOG(2) << "Already have IMSI " << imsi_;
177 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100178 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500179}
180
181void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
182 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100183 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500184 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
185 } else {
186 VLOG(2) << "Already have SPN " << spn_;
187 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100188 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500189}
190
191void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
192 VLOG(2) << __func__;
193 if (mdn_.empty()) {
194 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
195 } else {
196 VLOG(2) << "Already have MSISDN " << mdn_;
197 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100198 }
199}
200
Darin Petkov3e509242011-11-10 14:46:44 +0100201void CellularCapabilityGSM::GetSignalQuality() {
202 VLOG(2) << __func__;
203 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100204 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100205 cellular()->HandleNewSignalQuality(strength);
206}
207
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500208void CellularCapabilityGSM::GetRegistrationState(
209 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100210 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500211 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100212}
213
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500214void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100215 VLOG(2) << __func__;
216 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
217 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100218 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100219 VLOG(2) << "GSM AccessTechnology: " << tech;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500220 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100221}
222
Darin Petkovac635a82012-01-10 16:51:58 +0100223string CellularCapabilityGSM::CreateFriendlyServiceName() {
224 VLOG(2) << __func__;
225 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
226 !cellular()->home_provider().GetName().empty()) {
227 return cellular()->home_provider().GetName();
228 }
229 if (!serving_operator_.GetName().empty()) {
230 return serving_operator_.GetName();
231 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500232 if (!carrier_.empty()) {
233 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100234 }
235 if (!serving_operator_.GetCode().empty()) {
236 return "cellular_" + serving_operator_.GetCode();
237 }
238 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
239}
240
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100241void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500242 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100243 << " SPN: " << spn_ << ")";
244 // TODO(petkov): The test for NULL provider_db should be done by
245 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500246 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100247 return;
248 }
249 mobile_provider *provider =
250 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500251 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100252 if (!provider) {
253 VLOG(2) << "GSM provider not found.";
254 return;
255 }
256 home_provider_ = provider;
257 Cellular::Operator oper;
258 if (provider->networks) {
259 oper.SetCode(provider->networks[0]);
260 }
261 if (provider->country) {
262 oper.SetCountry(provider->country);
263 }
264 if (spn_.empty()) {
265 const char *name = mobile_provider_get_name(provider);
266 if (name) {
267 oper.SetName(name);
268 }
269 } else {
270 oper.SetName(spn_);
271 }
272 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100273 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100274}
275
Darin Petkovae0c64e2011-11-15 15:50:27 +0100276void CellularCapabilityGSM::UpdateOperatorInfo() {
277 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100278 const string &network_id = serving_operator_.GetCode();
279 if (!network_id.empty()) {
280 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100281 mobile_provider *provider =
282 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100283 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100284 if (provider) {
285 const char *provider_name = mobile_provider_get_name(provider);
286 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100287 serving_operator_.SetName(provider_name);
288 if (provider->country) {
289 serving_operator_.SetCountry(provider->country);
290 }
291 VLOG(2) << "Operator name: " << serving_operator_.GetName()
292 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100293 }
294 } else {
295 VLOG(2) << "GSM provider not found.";
296 }
297 }
298 UpdateServingOperator();
299}
300
301void CellularCapabilityGSM::UpdateServingOperator() {
302 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100303 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100304 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100305 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100306}
307
Darin Petkov3cfbf212011-11-21 16:02:09 +0100308void CellularCapabilityGSM::InitAPNList() {
309 VLOG(2) << __func__;
310 if (!home_provider_) {
311 return;
312 }
313 apn_list_.clear();
314 for (int i = 0; i < home_provider_->num_apns; ++i) {
315 Stringmap props;
316 mobile_apn *apn = home_provider_->apns[i];
317 if (apn->value) {
318 props[flimflam::kApnProperty] = apn->value;
319 }
320 if (apn->username) {
321 props[flimflam::kApnUsernameProperty] = apn->username;
322 }
323 if (apn->password) {
324 props[flimflam::kApnPasswordProperty] = apn->password;
325 }
326 // Find the first localized and non-localized name, if any.
327 const localized_name *lname = NULL;
328 const localized_name *name = NULL;
329 for (int j = 0; j < apn->num_names; ++j) {
330 if (apn->names[j]->lang) {
331 if (!lname) {
332 lname = apn->names[j];
333 }
334 } else if (!name) {
335 name = apn->names[j];
336 }
337 }
338 if (name) {
339 props[flimflam::kApnNameProperty] = name->name;
340 }
341 if (lname) {
342 props[flimflam::kApnLocalizedNameProperty] = lname->name;
343 props[flimflam::kApnLanguageProperty] = lname->lang;
344 }
345 apn_list_.push_back(props);
346 }
347 cellular()->adaptor()->EmitStringmapsChanged(
348 flimflam::kCellularApnListProperty, apn_list_);
349}
350
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500351void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
352 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
353 network_proxy_->Register(selected_network_, call_handler,
354 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100355}
356
357void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500358 const string &network_id, AsyncCallHandler *call_handler) {
359 VLOG(2) << __func__ << "(" << network_id << ")";
360 desired_network_ = network_id;
361 network_proxy_->Register(network_id, call_handler,
362 kTimeoutRegister);
363}
364
365void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
366 AsyncCallHandler *call_handler) {
367 VLOG(2) << __func__ << "(" << error << ")";
368
369 if (error.IsSuccess()) {
370 selected_network_ = desired_network_;
371 desired_network_.clear();
372 CompleteOperation(call_handler);
373 return;
374 }
375 // If registration on the desired network failed,
376 // try to register on the home network.
377 if (!desired_network_.empty()) {
378 desired_network_.clear();
379 selected_network_.clear();
380 Register(call_handler);
381 return;
382 }
383 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100384}
385
Darin Petkovb72cf402011-11-22 14:51:39 +0100386bool CellularCapabilityGSM::IsRegistered() {
387 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
388 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
389}
390
Darin Petkovb05315f2011-11-07 10:14:25 +0100391void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500392 const string &pin, bool require, AsyncCallHandler *call_handler) {
393 VLOG(2) << __func__ << "(" << call_handler << ")";
394 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100395}
396
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100397void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500398 AsyncCallHandler *call_handler) {
399 VLOG(2) << __func__ << "(" << call_handler << ")";
400 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100401}
402
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100403void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
404 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500405 AsyncCallHandler *call_handler) {
406 VLOG(2) << __func__ << "(" << call_handler << ")";
407 card_proxy_->SendPUK(unblock_code, pin, call_handler,
408 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100409}
410
411void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500412 const string &old_pin, const string &new_pin,
413 AsyncCallHandler *call_handler) {
414 VLOG(2) << __func__ << "(" << call_handler << ")";
415 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
416 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100417}
418
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500419void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100420 VLOG(2) << __func__;
421 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500422 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100423}
424
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500425void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
426 const Error &error,
427 AsyncCallHandler *call_handler) {
428 VLOG(2) << __func__;
429 if (error.IsFailure()) {
430 CompleteOperation(call_handler, error);
431 return;
432 }
433 found_networks_.clear();
434 for (GSMScanResults::const_iterator it = results.begin();
435 it != results.end(); ++it) {
436 found_networks_.push_back(ParseScanResult(*it));
437 }
438 CompleteOperation(call_handler);
439}
440
441Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100442 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500443 for (GSMScanResult::const_iterator it = result.begin();
444 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100445 // TODO(petkov): Define these in system_api/service_constants.h. The
446 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
447 static const char * const kStatusString[] = {
448 "unknown",
449 "available",
450 "current",
451 "forbidden",
452 };
453 static const char * const kTechnologyString[] = {
454 flimflam::kNetworkTechnologyGsm,
455 "GSM Compact",
456 flimflam::kNetworkTechnologyUmts,
457 flimflam::kNetworkTechnologyEdge,
458 "HSDPA",
459 "HSUPA",
460 flimflam::kNetworkTechnologyHspa,
461 };
462 VLOG(2) << "Network property: " << it->first << " = " << it->second;
463 if (it->first == kNetworkPropertyStatus) {
464 int status = 0;
465 if (base::StringToInt(it->second, &status) &&
466 status >= 0 &&
467 status < static_cast<int>(arraysize(kStatusString))) {
468 parsed[flimflam::kStatusProperty] = kStatusString[status];
469 } else {
470 LOG(ERROR) << "Unexpected status value: " << it->second;
471 }
472 } else if (it->first == kNetworkPropertyID) {
473 parsed[flimflam::kNetworkIdProperty] = it->second;
474 } else if (it->first == kNetworkPropertyLongName) {
475 parsed[flimflam::kLongNameProperty] = it->second;
476 } else if (it->first == kNetworkPropertyShortName) {
477 parsed[flimflam::kShortNameProperty] = it->second;
478 } else if (it->first == kNetworkPropertyAccessTechnology) {
479 int tech = 0;
480 if (base::StringToInt(it->second, &tech) &&
481 tech >= 0 &&
482 tech < static_cast<int>(arraysize(kTechnologyString))) {
483 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
484 } else {
485 LOG(ERROR) << "Unexpected technology value: " << it->second;
486 }
487 } else {
488 LOG(WARNING) << "Unknown network property ignored: " << it->first;
489 }
490 }
491 // If the long name is not available but the network ID is, look up the long
492 // name in the mobile provider database.
493 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
494 parsed[flimflam::kLongNameProperty].empty()) &&
495 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
496 mobile_provider *provider =
497 mobile_provider_lookup_by_network(
498 cellular()->provider_db(),
499 parsed[flimflam::kNetworkIdProperty].c_str());
500 if (provider) {
501 const char *long_name = mobile_provider_get_name(provider);
502 if (long_name && *long_name) {
503 parsed[flimflam::kLongNameProperty] = long_name;
504 }
505 }
506 }
507 return parsed;
508}
509
Darin Petkovae0c64e2011-11-15 15:50:27 +0100510void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
511 access_technology_ = access_technology;
512 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100513 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100514 }
515}
516
Darin Petkov20c13ec2011-11-09 15:07:15 +0100517string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100518 switch (access_technology_) {
519 case MM_MODEM_GSM_ACCESS_TECH_GSM:
520 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
521 return flimflam::kNetworkTechnologyGsm;
522 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
523 return flimflam::kNetworkTechnologyGprs;
524 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
525 return flimflam::kNetworkTechnologyEdge;
526 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
527 return flimflam::kNetworkTechnologyUmts;
528 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
529 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
530 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
531 return flimflam::kNetworkTechnologyHspa;
532 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
533 return flimflam::kNetworkTechnologyHspaPlus;
534 default:
535 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100536 }
537 return "";
538}
539
540string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100541 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100542 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
543 return flimflam::kRoamingStateHome;
544 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
545 return flimflam::kRoamingStateRoaming;
546 default:
547 break;
548 }
549 return flimflam::kRoamingStateUnknown;
550}
551
Darin Petkovae0c64e2011-11-15 15:50:27 +0100552void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
553 const DBusPropertiesMap &properties) {
554 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
555 if (DBusProperties::GetUint32(properties,
556 kPropertyAccessTechnology,
557 &access_technology)) {
558 SetAccessTechnology(access_technology);
559 }
Darin Petkov721ac932011-11-16 15:43:09 +0100560 DBusProperties::GetString(
561 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
562 DBusProperties::GetUint32(
563 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100564}
565
Darin Petkov184c54e2011-11-15 12:44:39 +0100566void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
567 // TODO(petkov): Implement this.
568 NOTIMPLEMENTED();
569}
570
571void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500572 uint32 status, const string &operator_code, const string &operator_name,
573 const Error &error, AsyncCallHandler *call_handler) {
574 if (error.IsSuccess()) {
575 VLOG(2) << __func__ << ": regstate=" << status
576 << ", opercode=" << operator_code
577 << ", opername=" << operator_name;
578 registration_state_ = status;
579 serving_operator_.SetCode(operator_code);
580 serving_operator_.SetName(operator_name);
581 UpdateOperatorInfo();
582 cellular()->HandleNewRegistrationState();
583 }
584 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100585}
586
587void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
588 cellular()->HandleNewSignalQuality(quality);
589}
590
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500591void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
592 const Error &error,
593 AsyncCallHandler *call_handler) {
594 if (error.IsSuccess()) {
595 VLOG(2) << "IMEI: " << imei;
596 imei_ = imei;
597 } else {
598 VLOG(2) << "GetIMEI failed - " << error;
599 }
600 CompleteOperation(call_handler, error);
601}
602
603void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
604 const Error &error,
605 AsyncCallHandler *call_handler) {
606 if (error.IsSuccess()) {
607 VLOG(2) << "IMSI: " << imsi;
608 imsi_ = imsi;
609 SetHomeProvider();
610 } else {
611 VLOG(2) << "GetIMSI failed - " << error;
612 }
613 CompleteOperation(call_handler, error);
614}
615
616void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
617 const Error &error,
618 AsyncCallHandler *call_handler) {
619 if (error.IsSuccess()) {
620 VLOG(2) << "SPN: " << spn;
621 spn_ = spn;
622 SetHomeProvider();
623 } else {
624 VLOG(2) << "GetSPN failed - " << error;
625 }
626 // Ignore the error - it's not fatal.
627 CompleteOperation(call_handler);
628}
629
630void CellularCapabilityGSM::OnGetMSISDNCallback(
631 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
632 if (error.IsSuccess()) {
633 VLOG(2) << "MSISDN: " << msisdn;
634 mdn_ = msisdn;
635 } else {
636 VLOG(2) << "GetMSISDN failed - " << error;
637 }
638 // Ignore the error - it's not fatal.
639 CompleteOperation(call_handler);
640}
641
642void CellularCapabilityGSM::OnPINOperationCallback(
643 const Error &error, AsyncCallHandler *call_handler) {
644 if (error.IsFailure())
645 VLOG(2) << "PIN operation failed - " << error;
646 else
647 VLOG(2) << "PIN operation complete";
648 CompleteOperation(call_handler, error);
649}
650
Darin Petkovdaf43862011-10-27 11:37:28 +0200651} // namespace shill