blob: b7969d33c2e6c3ce5d3e7d986b577bc3d8b250c2 [file] [log] [blame]
Darin Petkovdaf43862011-10-27 11:37:28 +02001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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
14#include "shill/cellular.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010015#include "shill/cellular_service.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020016#include "shill/proxy_factory.h"
17
Darin Petkovb05315f2011-11-07 10:14:25 +010018using std::string;
19
Darin Petkovdaf43862011-10-27 11:37:28 +020020namespace shill {
21
Darin Petkov1272a432011-11-10 15:53:37 +010022const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
23 "access-tech";
24const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
25const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
26const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
27 "operator-short";
28const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010029const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
30const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
31 "AccessTechnology";
Darin Petkov1272a432011-11-10 15:53:37 +010032
Darin Petkovdaf43862011-10-27 11:37:28 +020033CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
Darin Petkovb05315f2011-11-07 10:14:25 +010034 : CellularCapability(cellular),
Darin Petkov1272a432011-11-10 15:53:37 +010035 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010036 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010037 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov1272a432011-11-10 15:53:37 +010038 scanning_(false),
39 scan_interval_(0) {
40 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010041 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
42 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010043 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
44 &found_networks_);
45 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
46 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
47}
Darin Petkovdaf43862011-10-27 11:37:28 +020048
49void CellularCapabilityGSM::InitProxies() {
50 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010051 card_proxy_.reset(
52 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020053 cellular()->dbus_path(),
54 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010055 network_proxy_.reset(
56 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020057 cellular()->dbus_path(),
58 cellular()->dbus_owner()));
59}
60
Darin Petkovae0c64e2011-11-15 15:50:27 +010061void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
62 string imsi;
63 if (DBusProperties::GetString(properties, "imsi", &imsi)) {
64 // TODO(petkov): Set GSM provider based on IMSI and SPN.
65 }
66}
67
68void CellularCapabilityGSM::SetupConnectProperties(
69 DBusPropertiesMap *properties) {
70 (*properties)[Cellular::kConnectPropertyPhoneNumber].writer().append_string(
71 kPhoneNumber);
72 // TODO(petkov): Setup apn and "home_only".
73}
74
Darin Petkovcb547732011-11-09 13:55:26 +010075void CellularCapabilityGSM::GetIdentifiers() {
76 VLOG(2) << __func__;
77 if (cellular()->imei().empty()) {
78 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
79 cellular()->set_imei(card_proxy_->GetIMEI());
80 VLOG(2) << "IMEI: " << cellular()->imei();
81 }
82 if (cellular()->imsi().empty()) {
83 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
84 cellular()->set_imsi(card_proxy_->GetIMSI());
85 VLOG(2) << "IMSI: " << cellular()->imsi();
86 }
Darin Petkovae0c64e2011-11-15 15:50:27 +010087 if (spn_.empty()) {
Darin Petkovcb547732011-11-09 13:55:26 +010088 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
89 try {
Darin Petkovae0c64e2011-11-15 15:50:27 +010090 spn_ = card_proxy_->GetSPN();
91 VLOG(2) << "SPN: " << spn_;
Darin Petkovcb547732011-11-09 13:55:26 +010092 } catch (const DBus::Error e) {
93 // Some modems don't support this call so catch the exception explicitly.
94 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
95 }
96 }
97 if (cellular()->mdn().empty()) {
98 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
99 cellular()->set_mdn(card_proxy_->GetMSISDN());
100 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
101 }
102}
103
Darin Petkov3e509242011-11-10 14:46:44 +0100104void CellularCapabilityGSM::GetSignalQuality() {
105 VLOG(2) << __func__;
106 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100107 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100108 cellular()->HandleNewSignalQuality(strength);
109}
110
Darin Petkov184c54e2011-11-15 12:44:39 +0100111void CellularCapabilityGSM::GetRegistrationState() {
112 VLOG(2) << __func__;
113 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
114 ModemGSMNetworkProxyInterface::RegistrationInfo info =
115 network_proxy_->GetRegistrationInfo();
116 registration_state_ = info._1;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100117 network_id_ = info._2;
118 operator_name_ = info._3;
119 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
120 << network_id_ << ", " << operator_name_;
121 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100122 cellular()->HandleNewRegistrationState();
123}
124
125void CellularCapabilityGSM::GetProperties() {
126 VLOG(2) << __func__;
127 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
128 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100129 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100130 VLOG(2) << "GSM AccessTechnology: " << tech;
131}
132
Darin Petkovae0c64e2011-11-15 15:50:27 +0100133void CellularCapabilityGSM::UpdateOperatorInfo() {
134 VLOG(2) << __func__;
135 if (!network_id_.empty()) {
136 VLOG(2) << "Looking up network id: " << network_id_;
137 mobile_provider *provider =
138 mobile_provider_lookup_by_network(cellular()->provider_db(),
139 network_id_.c_str());
140 if (provider) {
141 const char *provider_name = mobile_provider_get_name(provider);
142 if (provider_name && *provider_name) {
143 operator_name_ = provider_name;
144 operator_country_ = provider->country;
145 VLOG(2) << "Operator name: " << operator_name_
146 << ", country: " << operator_country_;
147 }
148 } else {
149 VLOG(2) << "GSM provider not found.";
150 }
151 }
152 UpdateServingOperator();
153}
154
155void CellularCapabilityGSM::UpdateServingOperator() {
156 VLOG(2) << __func__;
157 if (!cellular()->service().get()) {
158 return;
159 }
160 Cellular::Operator oper;
161 oper.SetName(operator_name_);
162 oper.SetCode(network_id_);
163 oper.SetCountry(operator_country_);
164 cellular()->service()->set_serving_operator(oper);
165}
166
Darin Petkov184c54e2011-11-15 12:44:39 +0100167void CellularCapabilityGSM::Register() {
168 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
169 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
170 network_proxy_->Register(selected_network_);
171 // TODO(petkov): Handle registration failure including trying the home network
172 // when selected_network_ is not empty.
173}
174
175void CellularCapabilityGSM::RegisterOnNetwork(
176 const string &network_id, Error */*error*/) {
177 LOG(INFO) << __func__ << "(" << network_id << ")";
178 // Defer because we may be in a dbus-c++ callback.
179 dispatcher()->PostTask(
180 task_factory_.NewRunnableMethod(
181 &CellularCapabilityGSM::RegisterOnNetworkTask,
182 network_id));
183}
184
185void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
186 LOG(INFO) << __func__ << "(" << network_id << ")";
187 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
188 network_proxy_->Register(network_id);
189 // TODO(petkov): Handle registration failure.
190 selected_network_ = network_id;
191}
192
Darin Petkovb05315f2011-11-07 10:14:25 +0100193void CellularCapabilityGSM::RequirePIN(
194 const string &pin, bool require, Error */*error*/) {
195 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
196 // Defer because we may be in a dbus-c++ callback.
197 dispatcher()->PostTask(
198 task_factory_.NewRunnableMethod(
199 &CellularCapabilityGSM::RequirePINTask, pin, require));
200}
201
202void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
203 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
204 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100205 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100206}
207
208void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
209 VLOG(2) << __func__ << "(" << pin << ")";
210 // Defer because we may be in a dbus-c++ callback.
211 dispatcher()->PostTask(
212 task_factory_.NewRunnableMethod(
213 &CellularCapabilityGSM::EnterPINTask, pin));
214}
215
216void CellularCapabilityGSM::EnterPINTask(const string &pin) {
217 VLOG(2) << __func__ << "(" << pin << ")";
218 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100219 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100220}
221
222void CellularCapabilityGSM::UnblockPIN(
223 const string &unblock_code, const string &pin, Error */*error*/) {
224 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
225 // Defer because we may be in a dbus-c++ callback.
226 dispatcher()->PostTask(
227 task_factory_.NewRunnableMethod(
228 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
229}
230
231void CellularCapabilityGSM::UnblockPINTask(
232 const string &unblock_code, const string &pin) {
233 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
234 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100235 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100236}
237
238void CellularCapabilityGSM::ChangePIN(
239 const string &old_pin, const string &new_pin, Error */*error*/) {
240 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
241 // Defer because we may be in a dbus-c++ callback.
242 dispatcher()->PostTask(
243 task_factory_.NewRunnableMethod(
244 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
245}
246
247void CellularCapabilityGSM::ChangePINTask(
248 const string &old_pin, const string &new_pin) {
249 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
250 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100251 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100252}
253
Darin Petkov1272a432011-11-10 15:53:37 +0100254void CellularCapabilityGSM::Scan(Error */*error*/) {
255 VLOG(2) << __func__;
256 // Defer because we may be in a dbus-c++ callback.
257 dispatcher()->PostTask(
258 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
259}
260
261void CellularCapabilityGSM::ScanTask() {
262 VLOG(2) << __func__;
263 // TODO(petkov): Defer scan requests if a scan is in progress already.
264 //
265 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
266 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100267 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100268 found_networks_.clear();
269 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
270 results.begin(); it != results.end(); ++it) {
271 found_networks_.push_back(ParseScanResult(*it));
272 }
273}
274
275Stringmap CellularCapabilityGSM::ParseScanResult(
276 const ModemGSMNetworkProxyInterface::ScanResult &result) {
277 Stringmap parsed;
278 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
279 result.begin(); it != result.end(); ++it) {
280 // TODO(petkov): Define these in system_api/service_constants.h. The
281 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
282 static const char * const kStatusString[] = {
283 "unknown",
284 "available",
285 "current",
286 "forbidden",
287 };
288 static const char * const kTechnologyString[] = {
289 flimflam::kNetworkTechnologyGsm,
290 "GSM Compact",
291 flimflam::kNetworkTechnologyUmts,
292 flimflam::kNetworkTechnologyEdge,
293 "HSDPA",
294 "HSUPA",
295 flimflam::kNetworkTechnologyHspa,
296 };
297 VLOG(2) << "Network property: " << it->first << " = " << it->second;
298 if (it->first == kNetworkPropertyStatus) {
299 int status = 0;
300 if (base::StringToInt(it->second, &status) &&
301 status >= 0 &&
302 status < static_cast<int>(arraysize(kStatusString))) {
303 parsed[flimflam::kStatusProperty] = kStatusString[status];
304 } else {
305 LOG(ERROR) << "Unexpected status value: " << it->second;
306 }
307 } else if (it->first == kNetworkPropertyID) {
308 parsed[flimflam::kNetworkIdProperty] = it->second;
309 } else if (it->first == kNetworkPropertyLongName) {
310 parsed[flimflam::kLongNameProperty] = it->second;
311 } else if (it->first == kNetworkPropertyShortName) {
312 parsed[flimflam::kShortNameProperty] = it->second;
313 } else if (it->first == kNetworkPropertyAccessTechnology) {
314 int tech = 0;
315 if (base::StringToInt(it->second, &tech) &&
316 tech >= 0 &&
317 tech < static_cast<int>(arraysize(kTechnologyString))) {
318 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
319 } else {
320 LOG(ERROR) << "Unexpected technology value: " << it->second;
321 }
322 } else {
323 LOG(WARNING) << "Unknown network property ignored: " << it->first;
324 }
325 }
326 // If the long name is not available but the network ID is, look up the long
327 // name in the mobile provider database.
328 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
329 parsed[flimflam::kLongNameProperty].empty()) &&
330 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
331 mobile_provider *provider =
332 mobile_provider_lookup_by_network(
333 cellular()->provider_db(),
334 parsed[flimflam::kNetworkIdProperty].c_str());
335 if (provider) {
336 const char *long_name = mobile_provider_get_name(provider);
337 if (long_name && *long_name) {
338 parsed[flimflam::kLongNameProperty] = long_name;
339 }
340 }
341 }
342 return parsed;
343}
344
Darin Petkovae0c64e2011-11-15 15:50:27 +0100345void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
346 access_technology_ = access_technology;
347 if (cellular()->service().get()) {
348 cellular()->service()->set_network_tech(GetNetworkTechnologyString());
349 }
350}
351
Darin Petkov20c13ec2011-11-09 15:07:15 +0100352string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100353 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
354 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100355 switch (access_technology_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100356 case MM_MODEM_GSM_ACCESS_TECH_GSM:
357 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
358 return flimflam::kNetworkTechnologyGsm;
359 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
360 return flimflam::kNetworkTechnologyGprs;
361 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
362 return flimflam::kNetworkTechnologyEdge;
363 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
364 return flimflam::kNetworkTechnologyUmts;
365 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
366 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
367 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
368 return flimflam::kNetworkTechnologyHspa;
369 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
370 return flimflam::kNetworkTechnologyHspaPlus;
371 default:
372 NOTREACHED();
373 }
374 }
375 return "";
376}
377
378string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100379 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100380 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
381 return flimflam::kRoamingStateHome;
382 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
383 return flimflam::kRoamingStateRoaming;
384 default:
385 break;
386 }
387 return flimflam::kRoamingStateUnknown;
388}
389
Darin Petkovae0c64e2011-11-15 15:50:27 +0100390void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
391 const DBusPropertiesMap &properties) {
392 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
393 if (DBusProperties::GetUint32(properties,
394 kPropertyAccessTechnology,
395 &access_technology)) {
396 SetAccessTechnology(access_technology);
397 }
398}
399
400void CellularCapabilityGSM::OnServiceCreated() {
401 cellular()->service()->set_activation_state(
402 flimflam::kActivationStateActivated);
403 UpdateServingOperator();
404}
405
Darin Petkov184c54e2011-11-15 12:44:39 +0100406void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
407 // TODO(petkov): Implement this.
408 NOTIMPLEMENTED();
409}
410
411void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
412 uint32 status, const string &operator_code, const string &operator_name) {
413 registration_state_ = status;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100414 network_id_ = operator_code;
415 operator_name_ = operator_name;
416 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100417 cellular()->HandleNewRegistrationState();
418}
419
420void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
421 cellular()->HandleNewSignalQuality(quality);
422}
423
Darin Petkovdaf43862011-10-27 11:37:28 +0200424} // namespace shill