blob: 74be529c1b4e5c37aaab0cf53af6b7fed8acd3e2 [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"
15#include "shill/proxy_factory.h"
16
Darin Petkovb05315f2011-11-07 10:14:25 +010017using std::string;
18
Darin Petkovdaf43862011-10-27 11:37:28 +020019namespace shill {
20
Darin Petkov1272a432011-11-10 15:53:37 +010021const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
22 "access-tech";
23const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
24const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
25const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
26 "operator-short";
27const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
28
Darin Petkovdaf43862011-10-27 11:37:28 +020029CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
Darin Petkovb05315f2011-11-07 10:14:25 +010030 : CellularCapability(cellular),
Darin Petkov1272a432011-11-10 15:53:37 +010031 task_factory_(this),
32 scanning_(false),
33 scan_interval_(0) {
34 PropertyStore *store = cellular->mutable_store();
35 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
36 &found_networks_);
37 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
38 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
39}
Darin Petkovdaf43862011-10-27 11:37:28 +020040
41void CellularCapabilityGSM::InitProxies() {
42 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010043 card_proxy_.reset(
44 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020045 cellular()->dbus_path(),
46 cellular()->dbus_owner()));
Darin Petkovcb547732011-11-09 13:55:26 +010047 // TODO(petkov): Move GSM-specific proxy ownership from Cellular to this.
Darin Petkovdaf43862011-10-27 11:37:28 +020048 cellular()->set_modem_gsm_network_proxy(
49 proxy_factory()->CreateModemGSMNetworkProxy(cellular(),
50 cellular()->dbus_path(),
51 cellular()->dbus_owner()));
52}
53
Darin Petkovcb547732011-11-09 13:55:26 +010054void CellularCapabilityGSM::GetIdentifiers() {
55 VLOG(2) << __func__;
56 if (cellular()->imei().empty()) {
57 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
58 cellular()->set_imei(card_proxy_->GetIMEI());
59 VLOG(2) << "IMEI: " << cellular()->imei();
60 }
61 if (cellular()->imsi().empty()) {
62 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
63 cellular()->set_imsi(card_proxy_->GetIMSI());
64 VLOG(2) << "IMSI: " << cellular()->imsi();
65 }
66 if (cellular()->spn().empty()) {
67 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
68 try {
69 cellular()->set_spn(card_proxy_->GetSPN());
70 VLOG(2) << "SPN: " << cellular()->spn();
71 } catch (const DBus::Error e) {
72 // Some modems don't support this call so catch the exception explicitly.
73 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
74 }
75 }
76 if (cellular()->mdn().empty()) {
77 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
78 cellular()->set_mdn(card_proxy_->GetMSISDN());
79 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
80 }
81}
82
Darin Petkov3e509242011-11-10 14:46:44 +010083void CellularCapabilityGSM::GetSignalQuality() {
84 VLOG(2) << __func__;
85 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
86 uint32 strength = cellular()->modem_gsm_network_proxy()->GetSignalQuality();
87 cellular()->HandleNewSignalQuality(strength);
88}
89
Darin Petkovb05315f2011-11-07 10:14:25 +010090void CellularCapabilityGSM::RequirePIN(
91 const string &pin, bool require, Error */*error*/) {
92 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
93 // Defer because we may be in a dbus-c++ callback.
94 dispatcher()->PostTask(
95 task_factory_.NewRunnableMethod(
96 &CellularCapabilityGSM::RequirePINTask, pin, require));
97}
98
99void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
100 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
101 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100102 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100103}
104
105void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
106 VLOG(2) << __func__ << "(" << pin << ")";
107 // Defer because we may be in a dbus-c++ callback.
108 dispatcher()->PostTask(
109 task_factory_.NewRunnableMethod(
110 &CellularCapabilityGSM::EnterPINTask, pin));
111}
112
113void CellularCapabilityGSM::EnterPINTask(const string &pin) {
114 VLOG(2) << __func__ << "(" << pin << ")";
115 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100116 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100117}
118
119void CellularCapabilityGSM::UnblockPIN(
120 const string &unblock_code, const string &pin, Error */*error*/) {
121 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
122 // Defer because we may be in a dbus-c++ callback.
123 dispatcher()->PostTask(
124 task_factory_.NewRunnableMethod(
125 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
126}
127
128void CellularCapabilityGSM::UnblockPINTask(
129 const string &unblock_code, const string &pin) {
130 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
131 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100132 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100133}
134
135void CellularCapabilityGSM::ChangePIN(
136 const string &old_pin, const string &new_pin, Error */*error*/) {
137 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
138 // Defer because we may be in a dbus-c++ callback.
139 dispatcher()->PostTask(
140 task_factory_.NewRunnableMethod(
141 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
142}
143
144void CellularCapabilityGSM::ChangePINTask(
145 const string &old_pin, const string &new_pin) {
146 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
147 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100148 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100149}
150
Darin Petkov1272a432011-11-10 15:53:37 +0100151void CellularCapabilityGSM::Scan(Error */*error*/) {
152 VLOG(2) << __func__;
153 // Defer because we may be in a dbus-c++ callback.
154 dispatcher()->PostTask(
155 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
156}
157
158void CellularCapabilityGSM::ScanTask() {
159 VLOG(2) << __func__;
160 // TODO(petkov): Defer scan requests if a scan is in progress already.
161 //
162 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
163 // must for this call which is basically a stub at this point.
164 ModemGSMNetworkProxyInterface::ScanResults results =
165 cellular()->modem_gsm_network_proxy()->Scan();
166 found_networks_.clear();
167 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
168 results.begin(); it != results.end(); ++it) {
169 found_networks_.push_back(ParseScanResult(*it));
170 }
171}
172
173Stringmap CellularCapabilityGSM::ParseScanResult(
174 const ModemGSMNetworkProxyInterface::ScanResult &result) {
175 Stringmap parsed;
176 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
177 result.begin(); it != result.end(); ++it) {
178 // TODO(petkov): Define these in system_api/service_constants.h. The
179 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
180 static const char * const kStatusString[] = {
181 "unknown",
182 "available",
183 "current",
184 "forbidden",
185 };
186 static const char * const kTechnologyString[] = {
187 flimflam::kNetworkTechnologyGsm,
188 "GSM Compact",
189 flimflam::kNetworkTechnologyUmts,
190 flimflam::kNetworkTechnologyEdge,
191 "HSDPA",
192 "HSUPA",
193 flimflam::kNetworkTechnologyHspa,
194 };
195 VLOG(2) << "Network property: " << it->first << " = " << it->second;
196 if (it->first == kNetworkPropertyStatus) {
197 int status = 0;
198 if (base::StringToInt(it->second, &status) &&
199 status >= 0 &&
200 status < static_cast<int>(arraysize(kStatusString))) {
201 parsed[flimflam::kStatusProperty] = kStatusString[status];
202 } else {
203 LOG(ERROR) << "Unexpected status value: " << it->second;
204 }
205 } else if (it->first == kNetworkPropertyID) {
206 parsed[flimflam::kNetworkIdProperty] = it->second;
207 } else if (it->first == kNetworkPropertyLongName) {
208 parsed[flimflam::kLongNameProperty] = it->second;
209 } else if (it->first == kNetworkPropertyShortName) {
210 parsed[flimflam::kShortNameProperty] = it->second;
211 } else if (it->first == kNetworkPropertyAccessTechnology) {
212 int tech = 0;
213 if (base::StringToInt(it->second, &tech) &&
214 tech >= 0 &&
215 tech < static_cast<int>(arraysize(kTechnologyString))) {
216 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
217 } else {
218 LOG(ERROR) << "Unexpected technology value: " << it->second;
219 }
220 } else {
221 LOG(WARNING) << "Unknown network property ignored: " << it->first;
222 }
223 }
224 // If the long name is not available but the network ID is, look up the long
225 // name in the mobile provider database.
226 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
227 parsed[flimflam::kLongNameProperty].empty()) &&
228 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
229 mobile_provider *provider =
230 mobile_provider_lookup_by_network(
231 cellular()->provider_db(),
232 parsed[flimflam::kNetworkIdProperty].c_str());
233 if (provider) {
234 const char *long_name = mobile_provider_get_name(provider);
235 if (long_name && *long_name) {
236 parsed[flimflam::kLongNameProperty] = long_name;
237 }
238 }
239 }
240 return parsed;
241}
242
Darin Petkov20c13ec2011-11-09 15:07:15 +0100243string CellularCapabilityGSM::GetNetworkTechnologyString() const {
244 if (cellular()->gsm_registration_state() ==
245 MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
246 cellular()->gsm_registration_state() ==
247 MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
248 switch (cellular()->gsm_access_technology()) {
249 case MM_MODEM_GSM_ACCESS_TECH_GSM:
250 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
251 return flimflam::kNetworkTechnologyGsm;
252 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
253 return flimflam::kNetworkTechnologyGprs;
254 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
255 return flimflam::kNetworkTechnologyEdge;
256 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
257 return flimflam::kNetworkTechnologyUmts;
258 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
259 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
260 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
261 return flimflam::kNetworkTechnologyHspa;
262 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
263 return flimflam::kNetworkTechnologyHspaPlus;
264 default:
265 NOTREACHED();
266 }
267 }
268 return "";
269}
270
271string CellularCapabilityGSM::GetRoamingStateString() const {
272 switch (cellular()->gsm_registration_state()) {
273 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
274 return flimflam::kRoamingStateHome;
275 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
276 return flimflam::kRoamingStateRoaming;
277 default:
278 break;
279 }
280 return flimflam::kRoamingStateUnknown;
281}
282
Darin Petkovdaf43862011-10-27 11:37:28 +0200283} // namespace shill