blob: c79501b5f85d793c7fd5f40c3bd1839dc7ebeff5 [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 Petkovb9c99332012-01-12 13:13:00 +0100138 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100139 flimflam::kActivationStateActivated);
140 UpdateServingOperator();
141}
142
Darin Petkovae0c64e2011-11-15 15:50:27 +0100143void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500144 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100145 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100146 }
147}
148
149void CellularCapabilityGSM::SetupConnectProperties(
150 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500151 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100152 kPhoneNumber);
153 // TODO(petkov): Setup apn and "home_only".
154}
155
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500156void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100157 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500158 if (imei_.empty()) {
159 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
160 } else {
161 VLOG(2) << "Already have IMEI " << imei_;
162 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100163 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500164}
165
166void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
167 VLOG(2) << __func__;
168 if (imsi_.empty()) {
169 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
170 } else {
171 VLOG(2) << "Already have IMSI " << imsi_;
172 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100173 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500174}
175
176void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
177 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100178 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500179 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
180 } else {
181 VLOG(2) << "Already have SPN " << spn_;
182 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100183 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500184}
185
186void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
187 VLOG(2) << __func__;
188 if (mdn_.empty()) {
189 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
190 } else {
191 VLOG(2) << "Already have MSISDN " << mdn_;
192 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100193 }
194}
195
Darin Petkov3e509242011-11-10 14:46:44 +0100196void CellularCapabilityGSM::GetSignalQuality() {
197 VLOG(2) << __func__;
198 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100199 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100200 cellular()->HandleNewSignalQuality(strength);
201}
202
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500203void CellularCapabilityGSM::GetRegistrationState(
204 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100205 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500206 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100207}
208
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500209void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100210 VLOG(2) << __func__;
211 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
212 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100213 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100214 VLOG(2) << "GSM AccessTechnology: " << tech;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500215 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100216}
217
Darin Petkovac635a82012-01-10 16:51:58 +0100218string CellularCapabilityGSM::CreateFriendlyServiceName() {
219 VLOG(2) << __func__;
220 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
221 !cellular()->home_provider().GetName().empty()) {
222 return cellular()->home_provider().GetName();
223 }
224 if (!serving_operator_.GetName().empty()) {
225 return serving_operator_.GetName();
226 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500227 if (!carrier_.empty()) {
228 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100229 }
230 if (!serving_operator_.GetCode().empty()) {
231 return "cellular_" + serving_operator_.GetCode();
232 }
233 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
234}
235
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100236void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500237 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100238 << " SPN: " << spn_ << ")";
239 // TODO(petkov): The test for NULL provider_db should be done by
240 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500241 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100242 return;
243 }
244 mobile_provider *provider =
245 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500246 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100247 if (!provider) {
248 VLOG(2) << "GSM provider not found.";
249 return;
250 }
251 home_provider_ = provider;
252 Cellular::Operator oper;
253 if (provider->networks) {
254 oper.SetCode(provider->networks[0]);
255 }
256 if (provider->country) {
257 oper.SetCountry(provider->country);
258 }
259 if (spn_.empty()) {
260 const char *name = mobile_provider_get_name(provider);
261 if (name) {
262 oper.SetName(name);
263 }
264 } else {
265 oper.SetName(spn_);
266 }
267 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100268 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100269}
270
Darin Petkovae0c64e2011-11-15 15:50:27 +0100271void CellularCapabilityGSM::UpdateOperatorInfo() {
272 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100273 const string &network_id = serving_operator_.GetCode();
274 if (!network_id.empty()) {
275 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100276 mobile_provider *provider =
277 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100278 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100279 if (provider) {
280 const char *provider_name = mobile_provider_get_name(provider);
281 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100282 serving_operator_.SetName(provider_name);
283 if (provider->country) {
284 serving_operator_.SetCountry(provider->country);
285 }
286 VLOG(2) << "Operator name: " << serving_operator_.GetName()
287 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100288 }
289 } else {
290 VLOG(2) << "GSM provider not found.";
291 }
292 }
293 UpdateServingOperator();
294}
295
296void CellularCapabilityGSM::UpdateServingOperator() {
297 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100298 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100299 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100300 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100301}
302
Darin Petkov3cfbf212011-11-21 16:02:09 +0100303void CellularCapabilityGSM::InitAPNList() {
304 VLOG(2) << __func__;
305 if (!home_provider_) {
306 return;
307 }
308 apn_list_.clear();
309 for (int i = 0; i < home_provider_->num_apns; ++i) {
310 Stringmap props;
311 mobile_apn *apn = home_provider_->apns[i];
312 if (apn->value) {
313 props[flimflam::kApnProperty] = apn->value;
314 }
315 if (apn->username) {
316 props[flimflam::kApnUsernameProperty] = apn->username;
317 }
318 if (apn->password) {
319 props[flimflam::kApnPasswordProperty] = apn->password;
320 }
321 // Find the first localized and non-localized name, if any.
322 const localized_name *lname = NULL;
323 const localized_name *name = NULL;
324 for (int j = 0; j < apn->num_names; ++j) {
325 if (apn->names[j]->lang) {
326 if (!lname) {
327 lname = apn->names[j];
328 }
329 } else if (!name) {
330 name = apn->names[j];
331 }
332 }
333 if (name) {
334 props[flimflam::kApnNameProperty] = name->name;
335 }
336 if (lname) {
337 props[flimflam::kApnLocalizedNameProperty] = lname->name;
338 props[flimflam::kApnLanguageProperty] = lname->lang;
339 }
340 apn_list_.push_back(props);
341 }
342 cellular()->adaptor()->EmitStringmapsChanged(
343 flimflam::kCellularApnListProperty, apn_list_);
344}
345
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500346void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
347 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
348 network_proxy_->Register(selected_network_, call_handler,
349 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100350}
351
352void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500353 const string &network_id, AsyncCallHandler *call_handler) {
354 VLOG(2) << __func__ << "(" << network_id << ")";
355 desired_network_ = network_id;
356 network_proxy_->Register(network_id, call_handler,
357 kTimeoutRegister);
358}
359
360void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
361 AsyncCallHandler *call_handler) {
362 VLOG(2) << __func__ << "(" << error << ")";
363
364 if (error.IsSuccess()) {
365 selected_network_ = desired_network_;
366 desired_network_.clear();
367 CompleteOperation(call_handler);
368 return;
369 }
370 // If registration on the desired network failed,
371 // try to register on the home network.
372 if (!desired_network_.empty()) {
373 desired_network_.clear();
374 selected_network_.clear();
375 Register(call_handler);
376 return;
377 }
378 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100379}
380
Darin Petkovb72cf402011-11-22 14:51:39 +0100381bool CellularCapabilityGSM::IsRegistered() {
382 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
383 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
384}
385
Darin Petkovb05315f2011-11-07 10:14:25 +0100386void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500387 const string &pin, bool require, AsyncCallHandler *call_handler) {
388 VLOG(2) << __func__ << "(" << call_handler << ")";
389 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100390}
391
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100392void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500393 AsyncCallHandler *call_handler) {
394 VLOG(2) << __func__ << "(" << call_handler << ")";
395 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100396}
397
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100398void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
399 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500400 AsyncCallHandler *call_handler) {
401 VLOG(2) << __func__ << "(" << call_handler << ")";
402 card_proxy_->SendPUK(unblock_code, pin, call_handler,
403 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100404}
405
406void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500407 const string &old_pin, const string &new_pin,
408 AsyncCallHandler *call_handler) {
409 VLOG(2) << __func__ << "(" << call_handler << ")";
410 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
411 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100412}
413
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500414void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100415 VLOG(2) << __func__;
416 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500417 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100418}
419
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500420void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
421 const Error &error,
422 AsyncCallHandler *call_handler) {
423 VLOG(2) << __func__;
424 if (error.IsFailure()) {
425 CompleteOperation(call_handler, error);
426 return;
427 }
428 found_networks_.clear();
429 for (GSMScanResults::const_iterator it = results.begin();
430 it != results.end(); ++it) {
431 found_networks_.push_back(ParseScanResult(*it));
432 }
433 CompleteOperation(call_handler);
434}
435
436Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100437 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500438 for (GSMScanResult::const_iterator it = result.begin();
439 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100440 // TODO(petkov): Define these in system_api/service_constants.h. The
441 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
442 static const char * const kStatusString[] = {
443 "unknown",
444 "available",
445 "current",
446 "forbidden",
447 };
448 static const char * const kTechnologyString[] = {
449 flimflam::kNetworkTechnologyGsm,
450 "GSM Compact",
451 flimflam::kNetworkTechnologyUmts,
452 flimflam::kNetworkTechnologyEdge,
453 "HSDPA",
454 "HSUPA",
455 flimflam::kNetworkTechnologyHspa,
456 };
457 VLOG(2) << "Network property: " << it->first << " = " << it->second;
458 if (it->first == kNetworkPropertyStatus) {
459 int status = 0;
460 if (base::StringToInt(it->second, &status) &&
461 status >= 0 &&
462 status < static_cast<int>(arraysize(kStatusString))) {
463 parsed[flimflam::kStatusProperty] = kStatusString[status];
464 } else {
465 LOG(ERROR) << "Unexpected status value: " << it->second;
466 }
467 } else if (it->first == kNetworkPropertyID) {
468 parsed[flimflam::kNetworkIdProperty] = it->second;
469 } else if (it->first == kNetworkPropertyLongName) {
470 parsed[flimflam::kLongNameProperty] = it->second;
471 } else if (it->first == kNetworkPropertyShortName) {
472 parsed[flimflam::kShortNameProperty] = it->second;
473 } else if (it->first == kNetworkPropertyAccessTechnology) {
474 int tech = 0;
475 if (base::StringToInt(it->second, &tech) &&
476 tech >= 0 &&
477 tech < static_cast<int>(arraysize(kTechnologyString))) {
478 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
479 } else {
480 LOG(ERROR) << "Unexpected technology value: " << it->second;
481 }
482 } else {
483 LOG(WARNING) << "Unknown network property ignored: " << it->first;
484 }
485 }
486 // If the long name is not available but the network ID is, look up the long
487 // name in the mobile provider database.
488 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
489 parsed[flimflam::kLongNameProperty].empty()) &&
490 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
491 mobile_provider *provider =
492 mobile_provider_lookup_by_network(
493 cellular()->provider_db(),
494 parsed[flimflam::kNetworkIdProperty].c_str());
495 if (provider) {
496 const char *long_name = mobile_provider_get_name(provider);
497 if (long_name && *long_name) {
498 parsed[flimflam::kLongNameProperty] = long_name;
499 }
500 }
501 }
502 return parsed;
503}
504
Darin Petkovae0c64e2011-11-15 15:50:27 +0100505void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
506 access_technology_ = access_technology;
507 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100508 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100509 }
510}
511
Darin Petkov20c13ec2011-11-09 15:07:15 +0100512string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100513 switch (access_technology_) {
514 case MM_MODEM_GSM_ACCESS_TECH_GSM:
515 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
516 return flimflam::kNetworkTechnologyGsm;
517 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
518 return flimflam::kNetworkTechnologyGprs;
519 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
520 return flimflam::kNetworkTechnologyEdge;
521 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
522 return flimflam::kNetworkTechnologyUmts;
523 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
524 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
525 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
526 return flimflam::kNetworkTechnologyHspa;
527 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
528 return flimflam::kNetworkTechnologyHspaPlus;
529 default:
530 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100531 }
532 return "";
533}
534
535string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100536 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100537 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
538 return flimflam::kRoamingStateHome;
539 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
540 return flimflam::kRoamingStateRoaming;
541 default:
542 break;
543 }
544 return flimflam::kRoamingStateUnknown;
545}
546
Darin Petkovae0c64e2011-11-15 15:50:27 +0100547void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
548 const DBusPropertiesMap &properties) {
549 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
550 if (DBusProperties::GetUint32(properties,
551 kPropertyAccessTechnology,
552 &access_technology)) {
553 SetAccessTechnology(access_technology);
554 }
Darin Petkov721ac932011-11-16 15:43:09 +0100555 DBusProperties::GetString(
556 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
557 DBusProperties::GetUint32(
558 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100559}
560
Darin Petkov184c54e2011-11-15 12:44:39 +0100561void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
562 // TODO(petkov): Implement this.
563 NOTIMPLEMENTED();
564}
565
566void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500567 uint32 status, const string &operator_code, const string &operator_name,
568 const Error &error, AsyncCallHandler *call_handler) {
569 if (error.IsSuccess()) {
570 VLOG(2) << __func__ << ": regstate=" << status
571 << ", opercode=" << operator_code
572 << ", opername=" << operator_name;
573 registration_state_ = status;
574 serving_operator_.SetCode(operator_code);
575 serving_operator_.SetName(operator_name);
576 UpdateOperatorInfo();
577 cellular()->HandleNewRegistrationState();
578 }
579 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100580}
581
582void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
583 cellular()->HandleNewSignalQuality(quality);
584}
585
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500586void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
587 const Error &error,
588 AsyncCallHandler *call_handler) {
589 if (error.IsSuccess()) {
590 VLOG(2) << "IMEI: " << imei;
591 imei_ = imei;
592 } else {
593 VLOG(2) << "GetIMEI failed - " << error;
594 }
595 CompleteOperation(call_handler, error);
596}
597
598void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
599 const Error &error,
600 AsyncCallHandler *call_handler) {
601 if (error.IsSuccess()) {
602 VLOG(2) << "IMSI: " << imsi;
603 imsi_ = imsi;
604 SetHomeProvider();
605 } else {
606 VLOG(2) << "GetIMSI failed - " << error;
607 }
608 CompleteOperation(call_handler, error);
609}
610
611void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
612 const Error &error,
613 AsyncCallHandler *call_handler) {
614 if (error.IsSuccess()) {
615 VLOG(2) << "SPN: " << spn;
616 spn_ = spn;
617 SetHomeProvider();
618 } else {
619 VLOG(2) << "GetSPN failed - " << error;
620 }
621 // Ignore the error - it's not fatal.
622 CompleteOperation(call_handler);
623}
624
625void CellularCapabilityGSM::OnGetMSISDNCallback(
626 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
627 if (error.IsSuccess()) {
628 VLOG(2) << "MSISDN: " << msisdn;
629 mdn_ = msisdn;
630 } else {
631 VLOG(2) << "GetMSISDN failed - " << error;
632 }
633 // Ignore the error - it's not fatal.
634 CompleteOperation(call_handler);
635}
636
637void CellularCapabilityGSM::OnPINOperationCallback(
638 const Error &error, AsyncCallHandler *call_handler) {
639 if (error.IsFailure())
640 VLOG(2) << "PIN operation failed - " << error;
641 else
642 VLOG(2) << "PIN operation complete";
643 CompleteOperation(call_handler, error);
644}
645
Darin Petkovdaf43862011-10-27 11:37:28 +0200646} // namespace shill