blob: f1d7a45381448c759f34c0ea8814dc0e3f4d17de [file] [log] [blame]
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001// 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.h"
6
7#include <string>
Chris Masone889666b2011-07-03 12:58:50 -07008#include <utility>
9#include <vector>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070010
11#include <base/logging.h>
Darin Petkove9d12e02011-07-27 15:09:37 -070012#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070013#include <chromeos/dbus/service_constants.h>
Darin Petkovbec79a22011-08-01 14:47:17 -070014#include <mm/mm-modem.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070015
16#include "shill/cellular_service.h"
17#include "shill/control_interface.h"
18#include "shill/device.h"
19#include "shill/device_info.h"
20#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070021#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070022#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070023#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070024#include "shill/proxy_factory.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070025#include "shill/shill_event.h"
26
Chris Masone889666b2011-07-03 12:58:50 -070027using std::make_pair;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070028using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070029using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070030
31namespace shill {
32
Darin Petkovc5f56562011-08-06 16:40:05 -070033const char Cellular::kConnectPropertyPhoneNumber[] = "number";
34const char Cellular::kPhoneNumberCDMA[] = "#777";
35const char Cellular::kPhoneNumberGSM[] = "*99#";
36
Chris Masone889666b2011-07-03 12:58:50 -070037Cellular::Network::Network() {
38 dict_[flimflam::kStatusProperty] = "";
39 dict_[flimflam::kNetworkIdProperty] = "";
40 dict_[flimflam::kShortNameProperty] = "";
41 dict_[flimflam::kLongNameProperty] = "";
42 dict_[flimflam::kTechnologyProperty] = "";
43}
44
45Cellular::Network::~Network() {}
46
47const std::string &Cellular::Network::GetStatus() const {
48 return dict_.find(flimflam::kStatusProperty)->second;
49}
50
51void Cellular::Network::SetStatus(const std::string &status) {
52 dict_[flimflam::kStatusProperty] = status;
53}
54
55const std::string &Cellular::Network::GetId() const {
56 return dict_.find(flimflam::kNetworkIdProperty)->second;
57}
58
59void Cellular::Network::SetId(const std::string &id) {
60 dict_[flimflam::kNetworkIdProperty] = id;
61}
62
63const std::string &Cellular::Network::GetShortName() const {
64 return dict_.find(flimflam::kShortNameProperty)->second;
65}
66
67void Cellular::Network::SetShortName(const std::string &name) {
68 dict_[flimflam::kShortNameProperty] = name;
69}
70
71const std::string &Cellular::Network::GetLongName() const {
72 return dict_.find(flimflam::kLongNameProperty)->second;
73}
74
75void Cellular::Network::SetLongName(const std::string &name) {
76 dict_[flimflam::kLongNameProperty] = name;
77}
78
79const std::string &Cellular::Network::GetTechnology() const {
80 return dict_.find(flimflam::kTechnologyProperty)->second;
81}
82
83void Cellular::Network::SetTechnology(const std::string &technology) {
84 dict_[flimflam::kTechnologyProperty] = technology;
85}
86
87const Stringmap &Cellular::Network::ToDict() const {
88 return dict_;
89}
90
Darin Petkovbec79a22011-08-01 14:47:17 -070091Cellular::CDMA::CDMA()
92 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
93 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
94 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED) {}
95
Chris Masone3bd3c8c2011-06-13 08:20:26 -070096Cellular::Cellular(ControlInterface *control_interface,
97 EventDispatcher *dispatcher,
98 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070099 const string &link_name,
100 int interface_index,
101 Type type,
102 const string &owner,
103 const string &path)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700104 : Device(control_interface,
105 dispatcher,
106 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700107 link_name,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700108 interface_index),
Darin Petkove9d12e02011-07-27 15:09:37 -0700109 type_(type),
110 state_(kStateDisabled),
111 dbus_owner_(owner),
112 dbus_path_(path),
Darin Petkove9d12e02011-07-27 15:09:37 -0700113 service_registered_(false),
Darin Petkovc5f56562011-08-06 16:40:05 -0700114 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700115 allow_roaming_(false),
116 prl_version_(0),
117 scanning_(false),
118 scan_interval_(0) {
119 store_.RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
120 store_.RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700121 store_.RegisterConstString(flimflam::kCarrierProperty, &carrier_);
Chris Masone4d42df82011-07-02 17:09:39 -0700122 store_.RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700123 store_.RegisterConstString(flimflam::kEsnProperty, &esn_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700124 store_.RegisterConstString(flimflam::kFirmwareRevisionProperty,
125 &firmware_revision_);
126 store_.RegisterConstString(flimflam::kHardwareRevisionProperty,
127 &hardware_revision_);
Chris Masone4d42df82011-07-02 17:09:39 -0700128 store_.RegisterConstString(flimflam::kImeiProperty, &imei_);
129 store_.RegisterConstString(flimflam::kImsiProperty, &imsi_);
130 store_.RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
131 store_.RegisterConstString(flimflam::kMdnProperty, &mdn_);
132 store_.RegisterConstString(flimflam::kMeidProperty, &meid_);
133 store_.RegisterConstString(flimflam::kMinProperty, &min_);
134 store_.RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkovceb68172011-07-29 14:47:48 -0700135 store_.RegisterConstUint16(flimflam::kPRLVersionProperty, &prl_version_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700136
Chris Masone889666b2011-07-03 12:58:50 -0700137 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
138 &Cellular::SimLockStatusToProperty,
139 NULL);
140 HelpRegisterDerivedStringmaps(flimflam::kFoundNetworksProperty,
141 &Cellular::EnumerateNetworks,
142 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700143
Chris Masone4d42df82011-07-02 17:09:39 -0700144 store_.RegisterConstBool(flimflam::kScanningProperty, &scanning_);
145 store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
146
Darin Petkove9d12e02011-07-27 15:09:37 -0700147 VLOG(2) << "Cellular device " << link_name_ << " initialized: "
148 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700149}
150
Darin Petkove9d12e02011-07-27 15:09:37 -0700151Cellular::~Cellular() {}
152
153std::string Cellular::GetTypeString() {
154 switch (type_) {
155 case kTypeGSM: return "CellularTypeGSM";
156 case kTypeCDMA: return "CellularTypeCDMA";
157 default: return StringPrintf("CellularTypeUnknown-%d", type_);
158 }
159}
160
161std::string Cellular::GetStateString() {
162 switch (state_) {
163 case kStateDisabled: return "CellularStateDisabled";
164 case kStateEnabled: return "CellularStateEnabled";
165 case kStateRegistered: return "CellularStateRegistered";
166 case kStateConnected: return "CellularStateConnected";
167 default: return StringPrintf("CellularStateUnknown-%d", state_);
168 }
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700169}
170
171void Cellular::Start() {
Darin Petkovf5f61e02011-07-29 11:35:40 -0700172 VLOG(2) << __func__ << ": " << GetStateString();
Darin Petkovbec79a22011-08-01 14:47:17 -0700173 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700174 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700175 if (type_ == kTypeGSM) {
176 RegisterGSMModem();
177 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700178 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700179 GetModemIdentifiers();
180 if (type_ == kTypeGSM) {
181 GetGSMProperties();
182 }
183 GetModemInfo();
184 GetModemRegistrationState();
Darin Petkove9d12e02011-07-27 15:09:37 -0700185 // TODO(petkov): Device::Start();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700186}
187
188void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700189 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700190 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700191 cdma_proxy_.reset();
Chris Masone2b105542011-06-22 10:58:09 -0700192 manager_->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700193 service_ = NULL; // Breaks a reference cycle.
Darin Petkovd9661952011-08-03 16:25:42 -0700194 state_ = kStateDisabled;
Darin Petkove9d12e02011-07-27 15:09:37 -0700195 // TODO(petkov): Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700196}
197
Darin Petkovbec79a22011-08-01 14:47:17 -0700198void Cellular::InitProxies() {
199 proxy_.reset(
Darin Petkovc5f56562011-08-06 16:40:05 -0700200 ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700201 simple_proxy_.reset(
202 ProxyFactory::factory()->CreateModemSimpleProxy(
203 dbus_path_, dbus_owner_));
204 switch (type_) {
205 case kTypeGSM:
206 NOTIMPLEMENTED();
207 break;
208 case kTypeCDMA:
209 cdma_proxy_.reset(
210 ProxyFactory::factory()->CreateModemCDMAProxy(
Darin Petkovd9661952011-08-03 16:25:42 -0700211 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700212 break;
213 default: NOTREACHED();
214 }
215}
216
Darin Petkovf5f61e02011-07-29 11:35:40 -0700217void Cellular::EnableModem() {
218 CHECK_EQ(kStateDisabled, state_);
219 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
220 proxy_->Enable(true);
221 state_ = kStateEnabled;
222}
223
224void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700225 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700226 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
227 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700228 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
229 type_ == kTypeCDMA) {
230 // TODO(petkov): Set Cellular.FirmwareImageName and home_provider based on
231 // the carrier.
Darin Petkovf5f61e02011-07-29 11:35:40 -0700232 }
Darin Petkovceb68172011-07-29 14:47:48 -0700233 DBusProperties::GetString(properties, "meid", &meid_);
234 DBusProperties::GetString(properties, "imei", &imei_);
235 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
236 type_ == kTypeGSM) {
237 // TODO(petkov): Set GSM provider.
238 }
239 DBusProperties::GetString(properties, "esn", &esn_);
240 DBusProperties::GetString(properties, "mdn", &mdn_);
241 DBusProperties::GetString(properties, "min", &min_);
242 DBusProperties::GetUint16(properties, "prl_version", &prl_version_);
243 DBusProperties::GetString(
244 properties, "firmware_revision", &firmware_revision_);
245 // TODO(petkov): Get payment_url/olp_url/usage_url. For now, get these from
246 // ModemManager to match flimflam. In the future, provide a plugin API to get
247 // these directly from the modem driver.
248 if (type_ == kTypeCDMA) {
249 // TODO(petkov): Get activation_state.
250 }
251}
252
253void Cellular::GetModemIdentifiers() {
254 // TODO(petkov): Implement this.
255 NOTIMPLEMENTED();
256}
257
258void Cellular::GetGSMProperties() {
259 // TODO(petkov): Implement this.
260 NOTIMPLEMENTED();
261}
262
263void Cellular::RegisterGSMModem() {
264 // TODO(petkov): Invoke ModemManager.Modem.Gsm.Network.Register.
265 NOTIMPLEMENTED();
266}
267
268void Cellular::GetModemInfo() {
269 ModemProxyInterface::Info info = proxy_->GetInfo();
270 manufacturer_ = info._1;
271 model_id_ = info._2;
272 hardware_revision_ = info._3;
273 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
274 << hardware_revision_;
275}
276
277void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700278 switch (type_) {
279 case kTypeGSM:
280 GetGSMRegistrationState();
281 break;
282 case kTypeCDMA:
283 GetCDMARegistrationState();
284 break;
285 default: NOTREACHED();
286 }
Darin Petkovd9661952011-08-03 16:25:42 -0700287 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700288}
289
290void Cellular::GetCDMARegistrationState() {
291 CHECK_EQ(kTypeCDMA, type_);
292 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
293 &cdma_.registration_state_evdo);
294 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
295 << ") EVDO(" << cdma_.registration_state_evdo << ")";
296 // TODO(petkov): handle_reported_connect?
297}
298
299void Cellular::GetGSMRegistrationState() {
Darin Petkovceb68172011-07-29 14:47:48 -0700300 // TODO(petkov): Implement this.
301 NOTIMPLEMENTED();
302}
303
Darin Petkovd9661952011-08-03 16:25:42 -0700304bool Cellular::IsModemRegistered() {
305 return cdma_.registration_state_1x !=
306 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN ||
307 cdma_.registration_state_evdo !=
308 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
309 // TODO(petkov): Handle GSM states.
310}
311
312void Cellular::HandleNewRegistrationState() {
313 VLOG(2) << __func__;
314 if (!IsModemRegistered()) {
315 service_ = NULL;
316 if (state_ == kStateConnected || state_ == kStateRegistered) {
317 state_ = kStateEnabled;
318 }
319 return;
320 }
321
322 if (state_ == kStateEnabled) {
323 state_ = kStateRegistered;
324 }
325 if (!service_.get()) {
326 // For now, no endpoint is created. Revisit if necessary.
327 CreateService();
328 }
329 GetModemSignalQuality();
330 // TODO(petkov): Update the service.
331}
332
333void Cellular::GetModemSignalQuality() {
334 uint32 strength = 0;
335 switch (type_) {
336 case kTypeGSM:
337 strength = GetGSMSignalQuality();
338 break;
339 case kTypeCDMA:
340 strength = GetCDMASignalQuality();
341 break;
342 default: NOTREACHED();
343 }
344 HandleNewSignalQuality(strength);
345}
346
347uint32 Cellular::GetCDMASignalQuality() {
348 CHECK_EQ(kTypeCDMA, type_);
349 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
350 return cdma_proxy_->GetSignalQuality();
351}
352
353uint32 Cellular::GetGSMSignalQuality() {
Darin Petkovceb68172011-07-29 14:47:48 -0700354 // TODO(petkov): Implement this.
355 NOTIMPLEMENTED();
Darin Petkovd9661952011-08-03 16:25:42 -0700356 return 0;
357}
358
359void Cellular::HandleNewSignalQuality(uint32 strength) {
360 VLOG(2) << "Signal strength: " << strength;
361 if (service_.get()) {
362 service_->set_strength(strength);
363 }
364}
365
366void Cellular::CreateService() {
367 CHECK(!service_.get());
368 service_ =
369 new CellularService(control_interface_, dispatcher_, manager_, this);
370 // TODO(petkov): Set activation_state.
371 // TODO(petkov): Set operator.
372 // TODO(petkov): Set old_url/usage_url.
Darin Petkovf5f61e02011-07-29 11:35:40 -0700373}
374
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700375bool Cellular::TechnologyIs(const Device::Technology type) const {
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700376 return type == Device::kCellular;
377}
378
Darin Petkovc5f56562011-08-06 16:40:05 -0700379void Cellular::Connect() {
380 VLOG(2) << __func__;
381 if (state_ == kStateConnected) {
382 return;
383 }
384 CHECK_EQ(kStateRegistered, state_);
385 DBusPropertiesMap properties;
386 const char *phone_number = NULL;
387 switch (type_) {
388 case kTypeGSM:
389 phone_number = kPhoneNumberGSM;
390 break;
391 case kTypeCDMA:
392 phone_number = kPhoneNumberCDMA;
393 break;
394 default: NOTREACHED();
395 }
396 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
397 // TODO(petkov): Setup apn and "home_only".
398
399 // Defer connect because we may be in a dbus-c++ callback.
400 dispatcher_->PostTask(
401 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
402}
403
404void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
405 VLOG(2) << __func__;
406 simple_proxy_->Connect(properties);
407}
408
Darin Petkovd9661952011-08-03 16:25:42 -0700409void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
410 uint32 state_evdo) {
411 CHECK_EQ(kTypeCDMA, type_);
412 cdma_.registration_state_1x = state_1x;
413 cdma_.registration_state_evdo = state_evdo;
414 HandleNewRegistrationState();
415}
416
417void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
418 CHECK_EQ(kTypeCDMA, type_);
419 HandleNewSignalQuality(strength);
420}
421
Darin Petkovc5f56562011-08-06 16:40:05 -0700422void Cellular::OnModemStateChanged(uint32 old_state,
423 uint32 new_state,
424 uint32 reason) {
425 // TODO(petkov): Implement this.
426 NOTIMPLEMENTED();
427}
428
Chris Masone889666b2011-07-03 12:58:50 -0700429Stringmaps Cellular::EnumerateNetworks() {
430 Stringmaps to_return;
431 for (vector<Network>::const_iterator it = found_networks_.begin();
432 it != found_networks_.end();
433 ++it) {
434 to_return.push_back(it->ToDict());
435 }
436 return to_return;
437}
438
439StrIntPair Cellular::SimLockStatusToProperty() {
440 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
441 sim_lock_status_.lock_type),
442 make_pair(flimflam::kSIMLockRetriesLeftProperty,
443 sim_lock_status_.retries_left));
444}
445
446void Cellular::HelpRegisterDerivedStringmaps(
447 const string &name,
448 Stringmaps(Cellular::*get)(void),
449 bool(Cellular::*set)(const Stringmaps&)) {
450 store_.RegisterDerivedStringmaps(
451 name,
452 StringmapsAccessor(
453 new CustomAccessor<Cellular, Stringmaps>(this, get, set)));
454}
455
456void Cellular::HelpRegisterDerivedStrIntPair(
457 const string &name,
458 StrIntPair(Cellular::*get)(void),
459 bool(Cellular::*set)(const StrIntPair&)) {
460 store_.RegisterDerivedStrIntPair(
461 name,
462 StrIntPairAccessor(
463 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
464}
465
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700466} // namespace shill