blob: 48d4c8fea52ab6519001a28f5e0e81f06a07fead [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),
Darin Petkov184c54e2011-11-15 12:44:39 +010032 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkov1272a432011-11-10 15:53:37 +010033 scanning_(false),
34 scan_interval_(0) {
35 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010036 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
37 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010038 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
39 &found_networks_);
40 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
41 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
42}
Darin Petkovdaf43862011-10-27 11:37:28 +020043
44void CellularCapabilityGSM::InitProxies() {
45 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010046 card_proxy_.reset(
47 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020048 cellular()->dbus_path(),
49 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010050 network_proxy_.reset(
51 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020052 cellular()->dbus_path(),
53 cellular()->dbus_owner()));
54}
55
Darin Petkovcb547732011-11-09 13:55:26 +010056void CellularCapabilityGSM::GetIdentifiers() {
57 VLOG(2) << __func__;
58 if (cellular()->imei().empty()) {
59 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
60 cellular()->set_imei(card_proxy_->GetIMEI());
61 VLOG(2) << "IMEI: " << cellular()->imei();
62 }
63 if (cellular()->imsi().empty()) {
64 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
65 cellular()->set_imsi(card_proxy_->GetIMSI());
66 VLOG(2) << "IMSI: " << cellular()->imsi();
67 }
68 if (cellular()->spn().empty()) {
69 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
70 try {
71 cellular()->set_spn(card_proxy_->GetSPN());
72 VLOG(2) << "SPN: " << cellular()->spn();
73 } catch (const DBus::Error e) {
74 // Some modems don't support this call so catch the exception explicitly.
75 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
76 }
77 }
78 if (cellular()->mdn().empty()) {
79 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
80 cellular()->set_mdn(card_proxy_->GetMSISDN());
81 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
82 }
83}
84
Darin Petkov3e509242011-11-10 14:46:44 +010085void CellularCapabilityGSM::GetSignalQuality() {
86 VLOG(2) << __func__;
87 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +010088 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +010089 cellular()->HandleNewSignalQuality(strength);
90}
91
Darin Petkov184c54e2011-11-15 12:44:39 +010092void CellularCapabilityGSM::GetRegistrationState() {
93 VLOG(2) << __func__;
94 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
95 ModemGSMNetworkProxyInterface::RegistrationInfo info =
96 network_proxy_->GetRegistrationInfo();
97 registration_state_ = info._1;
98 cellular()->set_gsm_network_id(info._2);
99 cellular()->set_gsm_operator_name(info._3);
100 VLOG(2) << "GSM Registration: " << info._1 << ", "
101 << info._2 << ", " << info._3;
102 cellular()->UpdateGSMOperatorInfo();
103 cellular()->HandleNewRegistrationState();
104}
105
106void CellularCapabilityGSM::GetProperties() {
107 VLOG(2) << __func__;
108 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
109 uint32 tech = network_proxy_->AccessTechnology();
110 cellular()->SetGSMAccessTechnology(tech);
111 VLOG(2) << "GSM AccessTechnology: " << tech;
112}
113
114void CellularCapabilityGSM::Register() {
115 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
116 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
117 network_proxy_->Register(selected_network_);
118 // TODO(petkov): Handle registration failure including trying the home network
119 // when selected_network_ is not empty.
120}
121
122void CellularCapabilityGSM::RegisterOnNetwork(
123 const string &network_id, Error */*error*/) {
124 LOG(INFO) << __func__ << "(" << network_id << ")";
125 // Defer because we may be in a dbus-c++ callback.
126 dispatcher()->PostTask(
127 task_factory_.NewRunnableMethod(
128 &CellularCapabilityGSM::RegisterOnNetworkTask,
129 network_id));
130}
131
132void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
133 LOG(INFO) << __func__ << "(" << network_id << ")";
134 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
135 network_proxy_->Register(network_id);
136 // TODO(petkov): Handle registration failure.
137 selected_network_ = network_id;
138}
139
Darin Petkovb05315f2011-11-07 10:14:25 +0100140void CellularCapabilityGSM::RequirePIN(
141 const string &pin, bool require, Error */*error*/) {
142 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
143 // Defer because we may be in a dbus-c++ callback.
144 dispatcher()->PostTask(
145 task_factory_.NewRunnableMethod(
146 &CellularCapabilityGSM::RequirePINTask, pin, require));
147}
148
149void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
150 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
151 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100152 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100153}
154
155void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
156 VLOG(2) << __func__ << "(" << pin << ")";
157 // Defer because we may be in a dbus-c++ callback.
158 dispatcher()->PostTask(
159 task_factory_.NewRunnableMethod(
160 &CellularCapabilityGSM::EnterPINTask, pin));
161}
162
163void CellularCapabilityGSM::EnterPINTask(const string &pin) {
164 VLOG(2) << __func__ << "(" << pin << ")";
165 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100166 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100167}
168
169void CellularCapabilityGSM::UnblockPIN(
170 const string &unblock_code, const string &pin, Error */*error*/) {
171 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
172 // Defer because we may be in a dbus-c++ callback.
173 dispatcher()->PostTask(
174 task_factory_.NewRunnableMethod(
175 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
176}
177
178void CellularCapabilityGSM::UnblockPINTask(
179 const string &unblock_code, const string &pin) {
180 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
181 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100182 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100183}
184
185void CellularCapabilityGSM::ChangePIN(
186 const string &old_pin, const string &new_pin, Error */*error*/) {
187 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
188 // Defer because we may be in a dbus-c++ callback.
189 dispatcher()->PostTask(
190 task_factory_.NewRunnableMethod(
191 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
192}
193
194void CellularCapabilityGSM::ChangePINTask(
195 const string &old_pin, const string &new_pin) {
196 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
197 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100198 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100199}
200
Darin Petkov1272a432011-11-10 15:53:37 +0100201void CellularCapabilityGSM::Scan(Error */*error*/) {
202 VLOG(2) << __func__;
203 // Defer because we may be in a dbus-c++ callback.
204 dispatcher()->PostTask(
205 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
206}
207
208void CellularCapabilityGSM::ScanTask() {
209 VLOG(2) << __func__;
210 // TODO(petkov): Defer scan requests if a scan is in progress already.
211 //
212 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
213 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100214 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100215 found_networks_.clear();
216 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
217 results.begin(); it != results.end(); ++it) {
218 found_networks_.push_back(ParseScanResult(*it));
219 }
220}
221
222Stringmap CellularCapabilityGSM::ParseScanResult(
223 const ModemGSMNetworkProxyInterface::ScanResult &result) {
224 Stringmap parsed;
225 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
226 result.begin(); it != result.end(); ++it) {
227 // TODO(petkov): Define these in system_api/service_constants.h. The
228 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
229 static const char * const kStatusString[] = {
230 "unknown",
231 "available",
232 "current",
233 "forbidden",
234 };
235 static const char * const kTechnologyString[] = {
236 flimflam::kNetworkTechnologyGsm,
237 "GSM Compact",
238 flimflam::kNetworkTechnologyUmts,
239 flimflam::kNetworkTechnologyEdge,
240 "HSDPA",
241 "HSUPA",
242 flimflam::kNetworkTechnologyHspa,
243 };
244 VLOG(2) << "Network property: " << it->first << " = " << it->second;
245 if (it->first == kNetworkPropertyStatus) {
246 int status = 0;
247 if (base::StringToInt(it->second, &status) &&
248 status >= 0 &&
249 status < static_cast<int>(arraysize(kStatusString))) {
250 parsed[flimflam::kStatusProperty] = kStatusString[status];
251 } else {
252 LOG(ERROR) << "Unexpected status value: " << it->second;
253 }
254 } else if (it->first == kNetworkPropertyID) {
255 parsed[flimflam::kNetworkIdProperty] = it->second;
256 } else if (it->first == kNetworkPropertyLongName) {
257 parsed[flimflam::kLongNameProperty] = it->second;
258 } else if (it->first == kNetworkPropertyShortName) {
259 parsed[flimflam::kShortNameProperty] = it->second;
260 } else if (it->first == kNetworkPropertyAccessTechnology) {
261 int tech = 0;
262 if (base::StringToInt(it->second, &tech) &&
263 tech >= 0 &&
264 tech < static_cast<int>(arraysize(kTechnologyString))) {
265 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
266 } else {
267 LOG(ERROR) << "Unexpected technology value: " << it->second;
268 }
269 } else {
270 LOG(WARNING) << "Unknown network property ignored: " << it->first;
271 }
272 }
273 // If the long name is not available but the network ID is, look up the long
274 // name in the mobile provider database.
275 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
276 parsed[flimflam::kLongNameProperty].empty()) &&
277 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
278 mobile_provider *provider =
279 mobile_provider_lookup_by_network(
280 cellular()->provider_db(),
281 parsed[flimflam::kNetworkIdProperty].c_str());
282 if (provider) {
283 const char *long_name = mobile_provider_get_name(provider);
284 if (long_name && *long_name) {
285 parsed[flimflam::kLongNameProperty] = long_name;
286 }
287 }
288 }
289 return parsed;
290}
291
Darin Petkov20c13ec2011-11-09 15:07:15 +0100292string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100293 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
294 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100295 switch (cellular()->gsm_access_technology()) {
296 case MM_MODEM_GSM_ACCESS_TECH_GSM:
297 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
298 return flimflam::kNetworkTechnologyGsm;
299 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
300 return flimflam::kNetworkTechnologyGprs;
301 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
302 return flimflam::kNetworkTechnologyEdge;
303 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
304 return flimflam::kNetworkTechnologyUmts;
305 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
306 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
307 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
308 return flimflam::kNetworkTechnologyHspa;
309 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
310 return flimflam::kNetworkTechnologyHspaPlus;
311 default:
312 NOTREACHED();
313 }
314 }
315 return "";
316}
317
318string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100319 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100320 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
321 return flimflam::kRoamingStateHome;
322 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
323 return flimflam::kRoamingStateRoaming;
324 default:
325 break;
326 }
327 return flimflam::kRoamingStateUnknown;
328}
329
Darin Petkov184c54e2011-11-15 12:44:39 +0100330void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
331 // TODO(petkov): Implement this.
332 NOTIMPLEMENTED();
333}
334
335void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
336 uint32 status, const string &operator_code, const string &operator_name) {
337 registration_state_ = status;
338 cellular()->set_gsm_network_id(operator_code);
339 cellular()->set_gsm_operator_name(operator_name);
340 cellular()->UpdateGSMOperatorInfo();
341 cellular()->HandleNewRegistrationState();
342}
343
344void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
345 cellular()->HandleNewSignalQuality(quality);
346}
347
Darin Petkovdaf43862011-10-27 11:37:28 +0200348} // namespace shill