blob: 6fb10aac81705a131b263d6d17f07928cc1b70c7 [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 Petkov20c13ec2011-11-09 15:07:15 +010010#include <chromeos/dbus/service_constants.h>
11#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010012#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020013
Darin Petkov3cfbf212011-11-21 16:02:09 +010014#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010015#include "shill/cellular_service.h"
Darin Petkov721ac932011-11-16 15:43:09 +010016#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020017#include "shill/proxy_factory.h"
18
Darin Petkov721ac932011-11-16 15:43:09 +010019using std::make_pair;
Darin Petkovb05315f2011-11-07 10:14:25 +010020using std::string;
21
Darin Petkovdaf43862011-10-27 11:37:28 +020022namespace shill {
23
Darin Petkov1272a432011-11-10 15:53:37 +010024const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
25 "access-tech";
26const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
27const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
28const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
29 "operator-short";
30const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010031const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
32const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
33 "AccessTechnology";
Darin Petkov721ac932011-11-16 15:43:09 +010034const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
35const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010036
Darin Petkovdaf43862011-10-27 11:37:28 +020037CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
Darin Petkovb05315f2011-11-07 10:14:25 +010038 : CellularCapability(cellular),
Darin Petkov1272a432011-11-10 15:53:37 +010039 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010040 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010041 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010042 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010043 scanning_(false),
44 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010045 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010046 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010047 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
48 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010049 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
50 &found_networks_);
51 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
52 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010053 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
54 &CellularCapabilityGSM::SimLockStatusToProperty,
55 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010056 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
57 &apn_list_);
Darin Petkov1272a432011-11-10 15:53:37 +010058}
Darin Petkovdaf43862011-10-27 11:37:28 +020059
Darin Petkov721ac932011-11-16 15:43:09 +010060StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
61 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
62 sim_lock_status_.lock_type),
63 make_pair(flimflam::kSIMLockRetriesLeftProperty,
64 sim_lock_status_.retries_left));
65}
66
67void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
68 const string &name,
69 StrIntPair(CellularCapabilityGSM::*get)(Error *),
70 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
71 cellular()->mutable_store()->RegisterDerivedStrIntPair(
72 name,
73 StrIntPairAccessor(
74 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
75 this, get, set)));
76}
77
Darin Petkov5f316f62011-11-18 12:10:26 +010078void CellularCapabilityGSM::OnDeviceStarted() {
Darin Petkovdaf43862011-10-27 11:37:28 +020079 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010080 card_proxy_.reset(
81 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020082 cellular()->dbus_path(),
83 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010084 network_proxy_.reset(
85 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020086 cellular()->dbus_path(),
87 cellular()->dbus_owner()));
88}
89
Darin Petkov5f316f62011-11-18 12:10:26 +010090void CellularCapabilityGSM::OnDeviceStopped() {
Darin Petkov721ac932011-11-16 15:43:09 +010091 VLOG(2) << __func__;
92 card_proxy_.reset();
93 network_proxy_.reset();
94}
95
Darin Petkov5f316f62011-11-18 12:10:26 +010096void CellularCapabilityGSM::OnServiceCreated() {
97 cellular()->service()->set_activation_state(
98 flimflam::kActivationStateActivated);
99 UpdateServingOperator();
100}
101
Darin Petkovae0c64e2011-11-15 15:50:27 +0100102void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100103 if (ContainsKey(properties, Cellular::kPropertyIMSI)) {
104 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100105 }
106}
107
108void CellularCapabilityGSM::SetupConnectProperties(
109 DBusPropertiesMap *properties) {
110 (*properties)[Cellular::kConnectPropertyPhoneNumber].writer().append_string(
111 kPhoneNumber);
112 // TODO(petkov): Setup apn and "home_only".
113}
114
Darin Petkovcb547732011-11-09 13:55:26 +0100115void CellularCapabilityGSM::GetIdentifiers() {
116 VLOG(2) << __func__;
117 if (cellular()->imei().empty()) {
118 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
119 cellular()->set_imei(card_proxy_->GetIMEI());
Darin Petkovcb547732011-11-09 13:55:26 +0100120 }
121 if (cellular()->imsi().empty()) {
122 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100123 try {
124 cellular()->set_imsi(card_proxy_->GetIMSI());
125 VLOG(2) << "IMSI: " << cellular()->imsi();
126 } catch (const DBus::Error e) {
127 LOG(WARNING) << "Unable to obtain IMSI: " << e.what();
128 }
Darin Petkovcb547732011-11-09 13:55:26 +0100129 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100130 if (spn_.empty()) {
Darin Petkovcb547732011-11-09 13:55:26 +0100131 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
132 try {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100133 spn_ = card_proxy_->GetSPN();
134 VLOG(2) << "SPN: " << spn_;
Darin Petkovcb547732011-11-09 13:55:26 +0100135 } catch (const DBus::Error e) {
136 // Some modems don't support this call so catch the exception explicitly.
137 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
138 }
139 }
140 if (cellular()->mdn().empty()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100141 try {
142 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
143 cellular()->set_mdn(card_proxy_->GetMSISDN());
144 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
145 } catch (const DBus::Error e) {
146 LOG(WARNING) << "Unable to obtain MSISDN/MDN: " << e.what();
147 }
Darin Petkovcb547732011-11-09 13:55:26 +0100148 }
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100149 SetHomeProvider();
Darin Petkovcb547732011-11-09 13:55:26 +0100150}
151
Darin Petkov3e509242011-11-10 14:46:44 +0100152void CellularCapabilityGSM::GetSignalQuality() {
153 VLOG(2) << __func__;
154 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100155 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100156 cellular()->HandleNewSignalQuality(strength);
157}
158
Darin Petkov184c54e2011-11-15 12:44:39 +0100159void CellularCapabilityGSM::GetRegistrationState() {
160 VLOG(2) << __func__;
161 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
162 ModemGSMNetworkProxyInterface::RegistrationInfo info =
163 network_proxy_->GetRegistrationInfo();
164 registration_state_ = info._1;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100165 serving_operator_.SetCode(info._2);
166 serving_operator_.SetName(info._3);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100167 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100168 << serving_operator_.GetCode() << ", "
169 << serving_operator_.GetName();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100170 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100171 cellular()->HandleNewRegistrationState();
172}
173
174void CellularCapabilityGSM::GetProperties() {
175 VLOG(2) << __func__;
176 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
177 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100178 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100179 VLOG(2) << "GSM AccessTechnology: " << tech;
180}
181
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100182void CellularCapabilityGSM::SetHomeProvider() {
183 VLOG(2) << __func__ << "(IMSI: " << cellular()->imsi()
184 << " SPN: " << spn_ << ")";
185 // TODO(petkov): The test for NULL provider_db should be done by
186 // mobile_provider_lookup_best_match.
187 if (cellular()->imsi().empty() || !cellular()->provider_db()) {
188 return;
189 }
190 mobile_provider *provider =
191 mobile_provider_lookup_best_match(
192 cellular()->provider_db(), spn_.c_str(), cellular()->imsi().c_str());
193 if (!provider) {
194 VLOG(2) << "GSM provider not found.";
195 return;
196 }
197 home_provider_ = provider;
198 Cellular::Operator oper;
199 if (provider->networks) {
200 oper.SetCode(provider->networks[0]);
201 }
202 if (provider->country) {
203 oper.SetCountry(provider->country);
204 }
205 if (spn_.empty()) {
206 const char *name = mobile_provider_get_name(provider);
207 if (name) {
208 oper.SetName(name);
209 }
210 } else {
211 oper.SetName(spn_);
212 }
213 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100214 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100215}
216
Darin Petkovae0c64e2011-11-15 15:50:27 +0100217void CellularCapabilityGSM::UpdateOperatorInfo() {
218 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100219 const string &network_id = serving_operator_.GetCode();
220 if (!network_id.empty()) {
221 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100222 mobile_provider *provider =
223 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100224 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100225 if (provider) {
226 const char *provider_name = mobile_provider_get_name(provider);
227 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100228 serving_operator_.SetName(provider_name);
229 if (provider->country) {
230 serving_operator_.SetCountry(provider->country);
231 }
232 VLOG(2) << "Operator name: " << serving_operator_.GetName()
233 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100234 }
235 } else {
236 VLOG(2) << "GSM provider not found.";
237 }
238 }
239 UpdateServingOperator();
240}
241
242void CellularCapabilityGSM::UpdateServingOperator() {
243 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100244 if (cellular()->service().get()) {
245 cellular()->service()->set_serving_operator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100246 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100247}
248
Darin Petkov3cfbf212011-11-21 16:02:09 +0100249void CellularCapabilityGSM::InitAPNList() {
250 VLOG(2) << __func__;
251 if (!home_provider_) {
252 return;
253 }
254 apn_list_.clear();
255 for (int i = 0; i < home_provider_->num_apns; ++i) {
256 Stringmap props;
257 mobile_apn *apn = home_provider_->apns[i];
258 if (apn->value) {
259 props[flimflam::kApnProperty] = apn->value;
260 }
261 if (apn->username) {
262 props[flimflam::kApnUsernameProperty] = apn->username;
263 }
264 if (apn->password) {
265 props[flimflam::kApnPasswordProperty] = apn->password;
266 }
267 // Find the first localized and non-localized name, if any.
268 const localized_name *lname = NULL;
269 const localized_name *name = NULL;
270 for (int j = 0; j < apn->num_names; ++j) {
271 if (apn->names[j]->lang) {
272 if (!lname) {
273 lname = apn->names[j];
274 }
275 } else if (!name) {
276 name = apn->names[j];
277 }
278 }
279 if (name) {
280 props[flimflam::kApnNameProperty] = name->name;
281 }
282 if (lname) {
283 props[flimflam::kApnLocalizedNameProperty] = lname->name;
284 props[flimflam::kApnLanguageProperty] = lname->lang;
285 }
286 apn_list_.push_back(props);
287 }
288 cellular()->adaptor()->EmitStringmapsChanged(
289 flimflam::kCellularApnListProperty, apn_list_);
290}
291
Darin Petkov184c54e2011-11-15 12:44:39 +0100292void CellularCapabilityGSM::Register() {
293 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
294 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
295 network_proxy_->Register(selected_network_);
296 // TODO(petkov): Handle registration failure including trying the home network
297 // when selected_network_ is not empty.
298}
299
300void CellularCapabilityGSM::RegisterOnNetwork(
301 const string &network_id, Error */*error*/) {
302 LOG(INFO) << __func__ << "(" << network_id << ")";
303 // Defer because we may be in a dbus-c++ callback.
304 dispatcher()->PostTask(
305 task_factory_.NewRunnableMethod(
306 &CellularCapabilityGSM::RegisterOnNetworkTask,
307 network_id));
308}
309
Darin Petkovb72cf402011-11-22 14:51:39 +0100310bool CellularCapabilityGSM::IsRegistered() {
311 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
312 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
313}
314
Darin Petkov184c54e2011-11-15 12:44:39 +0100315void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
316 LOG(INFO) << __func__ << "(" << network_id << ")";
317 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
318 network_proxy_->Register(network_id);
319 // TODO(petkov): Handle registration failure.
320 selected_network_ = network_id;
321}
322
Darin Petkovb05315f2011-11-07 10:14:25 +0100323void CellularCapabilityGSM::RequirePIN(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100324 const string &pin, bool require, ReturnerInterface *returner) {
325 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100326 // Defer because we may be in a dbus-c++ callback.
327 dispatcher()->PostTask(
328 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100329 &CellularCapabilityGSM::RequirePINTask, pin, require, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100330}
331
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100332void CellularCapabilityGSM::RequirePINTask(
333 const string &pin, bool require, ReturnerInterface *returner) {
334 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100335 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100336 try {
337 card_proxy_->EnablePIN(pin, require);
338 } catch (DBus::Error e) {
339 LOG(ERROR) << "EnablePIN failed: " << e.name() << "/" << e.message();
340 returner->ReturnError(Error(Error::kInternalError));
341 return;
342 }
343 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100344}
345
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100346void CellularCapabilityGSM::EnterPIN(const string &pin,
347 ReturnerInterface *returner) {
348 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100349 // Defer because we may be in a dbus-c++ callback.
350 dispatcher()->PostTask(
351 task_factory_.NewRunnableMethod(
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100352 &CellularCapabilityGSM::EnterPINTask, pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100353}
354
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100355void CellularCapabilityGSM::EnterPINTask(const string &pin,
356 ReturnerInterface *returner) {
357 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100358 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100359 try {
360 card_proxy_->SendPIN(pin);
361 } catch (DBus::Error e) {
362 LOG(ERROR) << "EnterPIN failed: " << e.name() << "/" << e.message();
363 returner->ReturnError(Error(Error::kInternalError));
364 return;
365 }
366 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100367}
368
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100369void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
370 const string &pin,
371 ReturnerInterface *returner) {
372 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100373 // Defer because we may be in a dbus-c++ callback.
374 dispatcher()->PostTask(
375 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100376 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100377}
378
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100379void CellularCapabilityGSM::UnblockPINTask(const string &unblock_code,
380 const string &pin,
381 ReturnerInterface *returner) {
382 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100383 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100384 try {
385 card_proxy_->SendPUK(unblock_code, pin);
386 } catch (DBus::Error e) {
387 LOG(ERROR) << "SendPUK failed: " << e.name() << "/" << e.message();
388 returner->ReturnError(Error(Error::kInternalError));
389 return;
390 }
391 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100392}
393
394void CellularCapabilityGSM::ChangePIN(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100395 const string &old_pin, const string &new_pin, ReturnerInterface *returner) {
396 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100397 // Defer because we may be in a dbus-c++ callback.
398 dispatcher()->PostTask(
399 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100400 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100401}
402
403void CellularCapabilityGSM::ChangePINTask(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100404 const string &old_pin, const string &new_pin, ReturnerInterface *returner) {
405 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100406 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100407 try {
408 card_proxy_->ChangePIN(old_pin, new_pin);
409 } catch (DBus::Error e) {
410 LOG(ERROR) << "ChangePIN failed: " << e.name() << "/" << e.message();
411 returner->ReturnError(Error(Error::kInternalError));
412 return;
413 }
414 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100415}
416
Darin Petkov1272a432011-11-10 15:53:37 +0100417void CellularCapabilityGSM::Scan(Error */*error*/) {
418 VLOG(2) << __func__;
419 // Defer because we may be in a dbus-c++ callback.
420 dispatcher()->PostTask(
421 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
422}
423
424void CellularCapabilityGSM::ScanTask() {
425 VLOG(2) << __func__;
426 // TODO(petkov): Defer scan requests if a scan is in progress already.
427 //
428 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
429 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100430 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100431 found_networks_.clear();
432 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
433 results.begin(); it != results.end(); ++it) {
434 found_networks_.push_back(ParseScanResult(*it));
435 }
436}
437
438Stringmap CellularCapabilityGSM::ParseScanResult(
439 const ModemGSMNetworkProxyInterface::ScanResult &result) {
440 Stringmap parsed;
441 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
442 result.begin(); it != result.end(); ++it) {
443 // TODO(petkov): Define these in system_api/service_constants.h. The
444 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
445 static const char * const kStatusString[] = {
446 "unknown",
447 "available",
448 "current",
449 "forbidden",
450 };
451 static const char * const kTechnologyString[] = {
452 flimflam::kNetworkTechnologyGsm,
453 "GSM Compact",
454 flimflam::kNetworkTechnologyUmts,
455 flimflam::kNetworkTechnologyEdge,
456 "HSDPA",
457 "HSUPA",
458 flimflam::kNetworkTechnologyHspa,
459 };
460 VLOG(2) << "Network property: " << it->first << " = " << it->second;
461 if (it->first == kNetworkPropertyStatus) {
462 int status = 0;
463 if (base::StringToInt(it->second, &status) &&
464 status >= 0 &&
465 status < static_cast<int>(arraysize(kStatusString))) {
466 parsed[flimflam::kStatusProperty] = kStatusString[status];
467 } else {
468 LOG(ERROR) << "Unexpected status value: " << it->second;
469 }
470 } else if (it->first == kNetworkPropertyID) {
471 parsed[flimflam::kNetworkIdProperty] = it->second;
472 } else if (it->first == kNetworkPropertyLongName) {
473 parsed[flimflam::kLongNameProperty] = it->second;
474 } else if (it->first == kNetworkPropertyShortName) {
475 parsed[flimflam::kShortNameProperty] = it->second;
476 } else if (it->first == kNetworkPropertyAccessTechnology) {
477 int tech = 0;
478 if (base::StringToInt(it->second, &tech) &&
479 tech >= 0 &&
480 tech < static_cast<int>(arraysize(kTechnologyString))) {
481 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
482 } else {
483 LOG(ERROR) << "Unexpected technology value: " << it->second;
484 }
485 } else {
486 LOG(WARNING) << "Unknown network property ignored: " << it->first;
487 }
488 }
489 // If the long name is not available but the network ID is, look up the long
490 // name in the mobile provider database.
491 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
492 parsed[flimflam::kLongNameProperty].empty()) &&
493 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
494 mobile_provider *provider =
495 mobile_provider_lookup_by_network(
496 cellular()->provider_db(),
497 parsed[flimflam::kNetworkIdProperty].c_str());
498 if (provider) {
499 const char *long_name = mobile_provider_get_name(provider);
500 if (long_name && *long_name) {
501 parsed[flimflam::kLongNameProperty] = long_name;
502 }
503 }
504 }
505 return parsed;
506}
507
Darin Petkovae0c64e2011-11-15 15:50:27 +0100508void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
509 access_technology_ = access_technology;
510 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100511 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100512 }
513}
514
Darin Petkov20c13ec2011-11-09 15:07:15 +0100515string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100516 switch (access_technology_) {
517 case MM_MODEM_GSM_ACCESS_TECH_GSM:
518 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
519 return flimflam::kNetworkTechnologyGsm;
520 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
521 return flimflam::kNetworkTechnologyGprs;
522 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
523 return flimflam::kNetworkTechnologyEdge;
524 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
525 return flimflam::kNetworkTechnologyUmts;
526 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
527 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
528 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
529 return flimflam::kNetworkTechnologyHspa;
530 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
531 return flimflam::kNetworkTechnologyHspaPlus;
532 default:
533 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100534 }
535 return "";
536}
537
538string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100539 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100540 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
541 return flimflam::kRoamingStateHome;
542 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
543 return flimflam::kRoamingStateRoaming;
544 default:
545 break;
546 }
547 return flimflam::kRoamingStateUnknown;
548}
549
Darin Petkovae0c64e2011-11-15 15:50:27 +0100550void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
551 const DBusPropertiesMap &properties) {
552 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
553 if (DBusProperties::GetUint32(properties,
554 kPropertyAccessTechnology,
555 &access_technology)) {
556 SetAccessTechnology(access_technology);
557 }
Darin Petkov721ac932011-11-16 15:43:09 +0100558 DBusProperties::GetString(
559 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
560 DBusProperties::GetUint32(
561 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100562}
563
Darin Petkov184c54e2011-11-15 12:44:39 +0100564void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
565 // TODO(petkov): Implement this.
566 NOTIMPLEMENTED();
567}
568
569void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
570 uint32 status, const string &operator_code, const string &operator_name) {
571 registration_state_ = status;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100572 serving_operator_.SetCode(operator_code);
573 serving_operator_.SetName(operator_name);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100574 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100575 cellular()->HandleNewRegistrationState();
576}
577
578void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
579 cellular()->HandleNewSignalQuality(quality);
580}
581
Darin Petkovdaf43862011-10-27 11:37:28 +0200582} // namespace shill