blob: 4618c06df3237bf7af9d310b27966202c0bea986 [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
Darin Petkov0828f5f2011-08-11 10:18:52 -07007#include <netinet/in.h>
8#include <linux/if.h>
9
Chris Masone3bd3c8c2011-06-13 08:20:26 -070010#include <string>
Chris Masone889666b2011-07-03 12:58:50 -070011#include <utility>
12#include <vector>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070013
14#include <base/logging.h>
Darin Petkove9d12e02011-07-27 15:09:37 -070015#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070016#include <chromeos/dbus/service_constants.h>
Darin Petkovbec79a22011-08-01 14:47:17 -070017#include <mm/mm-modem.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070018
19#include "shill/cellular_service.h"
20#include "shill/control_interface.h"
21#include "shill/device.h"
22#include "shill/device_info.h"
23#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070024#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070025#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070026#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070027#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070028#include "shill/rtnl_handler.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070029#include "shill/shill_event.h"
30
Chris Masone889666b2011-07-03 12:58:50 -070031using std::make_pair;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070032using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070033using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070034
35namespace shill {
36
Darin Petkovc5f56562011-08-06 16:40:05 -070037const char Cellular::kConnectPropertyPhoneNumber[] = "number";
38const char Cellular::kPhoneNumberCDMA[] = "#777";
39const char Cellular::kPhoneNumberGSM[] = "*99#";
40
Chris Masone889666b2011-07-03 12:58:50 -070041Cellular::Network::Network() {
42 dict_[flimflam::kStatusProperty] = "";
43 dict_[flimflam::kNetworkIdProperty] = "";
44 dict_[flimflam::kShortNameProperty] = "";
45 dict_[flimflam::kLongNameProperty] = "";
46 dict_[flimflam::kTechnologyProperty] = "";
47}
48
49Cellular::Network::~Network() {}
50
51const std::string &Cellular::Network::GetStatus() const {
52 return dict_.find(flimflam::kStatusProperty)->second;
53}
54
55void Cellular::Network::SetStatus(const std::string &status) {
56 dict_[flimflam::kStatusProperty] = status;
57}
58
59const std::string &Cellular::Network::GetId() const {
60 return dict_.find(flimflam::kNetworkIdProperty)->second;
61}
62
63void Cellular::Network::SetId(const std::string &id) {
64 dict_[flimflam::kNetworkIdProperty] = id;
65}
66
67const std::string &Cellular::Network::GetShortName() const {
68 return dict_.find(flimflam::kShortNameProperty)->second;
69}
70
71void Cellular::Network::SetShortName(const std::string &name) {
72 dict_[flimflam::kShortNameProperty] = name;
73}
74
75const std::string &Cellular::Network::GetLongName() const {
76 return dict_.find(flimflam::kLongNameProperty)->second;
77}
78
79void Cellular::Network::SetLongName(const std::string &name) {
80 dict_[flimflam::kLongNameProperty] = name;
81}
82
83const std::string &Cellular::Network::GetTechnology() const {
84 return dict_.find(flimflam::kTechnologyProperty)->second;
85}
86
87void Cellular::Network::SetTechnology(const std::string &technology) {
88 dict_[flimflam::kTechnologyProperty] = technology;
89}
90
91const Stringmap &Cellular::Network::ToDict() const {
92 return dict_;
93}
94
Darin Petkovbec79a22011-08-01 14:47:17 -070095Cellular::CDMA::CDMA()
96 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
97 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkovcc044422011-08-17 13:30:06 -070098 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
99 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -0700100
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700101Cellular::Cellular(ControlInterface *control_interface,
102 EventDispatcher *dispatcher,
103 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700104 const string &link_name,
105 int interface_index,
106 Type type,
107 const string &owner,
108 const string &path)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700109 : Device(control_interface,
110 dispatcher,
111 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700112 link_name,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700113 interface_index),
Darin Petkove9d12e02011-07-27 15:09:37 -0700114 type_(type),
115 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700116 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700117 dbus_owner_(owner),
118 dbus_path_(path),
Darin Petkovc5f56562011-08-06 16:40:05 -0700119 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700120 allow_roaming_(false),
Darin Petkove9d12e02011-07-27 15:09:37 -0700121 scanning_(false),
122 scan_interval_(0) {
123 store_.RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
124 store_.RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700125 store_.RegisterConstString(flimflam::kCarrierProperty, &carrier_);
Chris Masone4d42df82011-07-02 17:09:39 -0700126 store_.RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700127 store_.RegisterConstString(flimflam::kEsnProperty, &esn_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700128 store_.RegisterConstString(flimflam::kFirmwareRevisionProperty,
129 &firmware_revision_);
130 store_.RegisterConstString(flimflam::kHardwareRevisionProperty,
131 &hardware_revision_);
Chris Masone4d42df82011-07-02 17:09:39 -0700132 store_.RegisterConstString(flimflam::kImeiProperty, &imei_);
133 store_.RegisterConstString(flimflam::kImsiProperty, &imsi_);
134 store_.RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
135 store_.RegisterConstString(flimflam::kMdnProperty, &mdn_);
136 store_.RegisterConstString(flimflam::kMeidProperty, &meid_);
137 store_.RegisterConstString(flimflam::kMinProperty, &min_);
138 store_.RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkovcc044422011-08-17 13:30:06 -0700139 store_.RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
Chris Masoneb925cc82011-06-22 15:39:57 -0700140
Chris Masone889666b2011-07-03 12:58:50 -0700141 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
142 &Cellular::SimLockStatusToProperty,
143 NULL);
144 HelpRegisterDerivedStringmaps(flimflam::kFoundNetworksProperty,
145 &Cellular::EnumerateNetworks,
146 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700147
Chris Masone4d42df82011-07-02 17:09:39 -0700148 store_.RegisterConstBool(flimflam::kScanningProperty, &scanning_);
149 store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
150
Darin Petkove9d12e02011-07-27 15:09:37 -0700151 VLOG(2) << "Cellular device " << link_name_ << " initialized: "
152 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700153}
154
Darin Petkove9d12e02011-07-27 15:09:37 -0700155Cellular::~Cellular() {}
156
Darin Petkovcc044422011-08-17 13:30:06 -0700157string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700158 switch (type_) {
159 case kTypeGSM: return "CellularTypeGSM";
160 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700161 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700162 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700163 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700164}
165
Darin Petkovcc044422011-08-17 13:30:06 -0700166// static
167string Cellular::GetStateString(State state) {
168 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700169 case kStateDisabled: return "CellularStateDisabled";
170 case kStateEnabled: return "CellularStateEnabled";
171 case kStateRegistered: return "CellularStateRegistered";
172 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700173 case kStateLinked: return "CellularStateLinked";
174 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700175 }
Darin Petkovcc044422011-08-17 13:30:06 -0700176 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700177}
178
Darin Petkovc408e692011-08-17 13:47:15 -0700179// static
180string Cellular::GetCDMAActivationStateString(uint32 state) {
181 switch (state) {
182 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700183 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700184 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700185 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700186 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700187 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700188 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700189 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700190 default:
Darin Petkov51489002011-08-18 13:13:20 -0700191 return flimflam::kActivationStateUnknown;
192 }
193}
194
195// static
196string Cellular::GetCDMAActivationErrorString(uint32 error) {
197 switch (error) {
198 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
199 return flimflam::kErrorNeedEvdo;
200 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
201 return flimflam::kErrorNeedHomeNetwork;
202 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
203 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
204 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
205 return flimflam::kErrorOtaspFailed;
206 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
207 return "";
208 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
209 default:
210 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700211 }
212}
213
Darin Petkov0828f5f2011-08-11 10:18:52 -0700214void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700215 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700216 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700217}
218
219void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700220 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkovbec79a22011-08-01 14:47:17 -0700221 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700222 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700223 if (type_ == kTypeGSM) {
224 RegisterGSMModem();
225 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700226 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700227 GetModemIdentifiers();
228 if (type_ == kTypeGSM) {
229 GetGSMProperties();
230 }
231 GetModemInfo();
232 GetModemRegistrationState();
Darin Petkove9d12e02011-07-27 15:09:37 -0700233 // TODO(petkov): Device::Start();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700234}
235
236void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700237 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700238 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700239 cdma_proxy_.reset();
Chris Masone2b105542011-06-22 10:58:09 -0700240 manager_->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700241 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700242 SetState(kStateDisabled);
243 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index_, 0, IFF_UP);
Darin Petkove9d12e02011-07-27 15:09:37 -0700244 // TODO(petkov): Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700245}
246
Darin Petkovbec79a22011-08-01 14:47:17 -0700247void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700248 VLOG(2) << __func__;
Darin Petkovbec79a22011-08-01 14:47:17 -0700249 proxy_.reset(
Darin Petkovc5f56562011-08-06 16:40:05 -0700250 ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700251 simple_proxy_.reset(
252 ProxyFactory::factory()->CreateModemSimpleProxy(
253 dbus_path_, dbus_owner_));
254 switch (type_) {
255 case kTypeGSM:
256 NOTIMPLEMENTED();
257 break;
258 case kTypeCDMA:
259 cdma_proxy_.reset(
260 ProxyFactory::factory()->CreateModemCDMAProxy(
Darin Petkovd9661952011-08-03 16:25:42 -0700261 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700262 break;
263 default: NOTREACHED();
264 }
265}
266
Darin Petkovf5f61e02011-07-29 11:35:40 -0700267void Cellular::EnableModem() {
268 CHECK_EQ(kStateDisabled, state_);
269 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
270 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700271 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700272}
273
274void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700275 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700276 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
277 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700278 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
279 type_ == kTypeCDMA) {
280 // TODO(petkov): Set Cellular.FirmwareImageName and home_provider based on
281 // the carrier.
Darin Petkovf5f61e02011-07-29 11:35:40 -0700282 }
Darin Petkovceb68172011-07-29 14:47:48 -0700283 DBusProperties::GetString(properties, "meid", &meid_);
284 DBusProperties::GetString(properties, "imei", &imei_);
285 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
286 type_ == kTypeGSM) {
287 // TODO(petkov): Set GSM provider.
288 }
289 DBusProperties::GetString(properties, "esn", &esn_);
290 DBusProperties::GetString(properties, "mdn", &mdn_);
291 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700292 DBusProperties::GetString(
293 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700294
Darin Petkovc408e692011-08-17 13:47:15 -0700295 // TODO(petkov): Handle "state".
Darin Petkovb27e5442011-08-16 14:36:45 -0700296
Darin Petkovceb68172011-07-29 14:47:48 -0700297 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700298 DBusProperties::GetUint32(
299 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700300 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700301 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
302 // to match flimflam. In the future, provide a plugin API to get these
303 // directly from the modem driver.
304 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
305 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700306 }
307}
308
309void Cellular::GetModemIdentifiers() {
310 // TODO(petkov): Implement this.
311 NOTIMPLEMENTED();
312}
313
314void Cellular::GetGSMProperties() {
315 // TODO(petkov): Implement this.
316 NOTIMPLEMENTED();
317}
318
319void Cellular::RegisterGSMModem() {
320 // TODO(petkov): Invoke ModemManager.Modem.Gsm.Network.Register.
321 NOTIMPLEMENTED();
322}
323
324void Cellular::GetModemInfo() {
325 ModemProxyInterface::Info info = proxy_->GetInfo();
326 manufacturer_ = info._1;
327 model_id_ = info._2;
328 hardware_revision_ = info._3;
329 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
330 << hardware_revision_;
331}
332
333void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700334 switch (type_) {
335 case kTypeGSM:
336 GetGSMRegistrationState();
337 break;
338 case kTypeCDMA:
339 GetCDMARegistrationState();
340 break;
341 default: NOTREACHED();
342 }
Darin Petkovd9661952011-08-03 16:25:42 -0700343 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700344}
345
346void Cellular::GetCDMARegistrationState() {
347 CHECK_EQ(kTypeCDMA, type_);
348 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
349 &cdma_.registration_state_evdo);
350 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
351 << ") EVDO(" << cdma_.registration_state_evdo << ")";
352 // TODO(petkov): handle_reported_connect?
353}
354
355void Cellular::GetGSMRegistrationState() {
Darin Petkovceb68172011-07-29 14:47:48 -0700356 // TODO(petkov): Implement this.
357 NOTIMPLEMENTED();
358}
359
Darin Petkovd9661952011-08-03 16:25:42 -0700360bool Cellular::IsModemRegistered() {
361 return cdma_.registration_state_1x !=
362 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN ||
363 cdma_.registration_state_evdo !=
364 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
365 // TODO(petkov): Handle GSM states.
366}
367
368void Cellular::HandleNewRegistrationState() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700369 dispatcher_->PostTask(
370 task_factory_.NewRunnableMethod(
371 &Cellular::HandleNewRegistrationStateTask));
372}
373
374void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700375 VLOG(2) << __func__;
376 if (!IsModemRegistered()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700377 if (state_ == kStateLinked) {
378 manager_->DeregisterService(service_);
379 }
Darin Petkovd9661952011-08-03 16:25:42 -0700380 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700381 if (state_ == kStateLinked ||
382 state_ == kStateConnected ||
383 state_ == kStateRegistered) {
384 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700385 }
386 return;
387 }
Darin Petkovd9661952011-08-03 16:25:42 -0700388 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700389 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700390 }
391 if (!service_.get()) {
392 // For now, no endpoint is created. Revisit if necessary.
393 CreateService();
394 }
395 GetModemSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700396 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
397 SetState(kStateConnected);
398 EstablishLink();
399 }
Darin Petkovd9661952011-08-03 16:25:42 -0700400 // TODO(petkov): Update the service.
401}
402
403void Cellular::GetModemSignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700404 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700405 uint32 strength = 0;
406 switch (type_) {
407 case kTypeGSM:
408 strength = GetGSMSignalQuality();
409 break;
410 case kTypeCDMA:
411 strength = GetCDMASignalQuality();
412 break;
413 default: NOTREACHED();
414 }
415 HandleNewSignalQuality(strength);
416}
417
418uint32 Cellular::GetCDMASignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700419 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700420 CHECK_EQ(kTypeCDMA, type_);
421 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
422 return cdma_proxy_->GetSignalQuality();
423}
424
425uint32 Cellular::GetGSMSignalQuality() {
Darin Petkovceb68172011-07-29 14:47:48 -0700426 // TODO(petkov): Implement this.
427 NOTIMPLEMENTED();
Darin Petkovd9661952011-08-03 16:25:42 -0700428 return 0;
429}
430
431void Cellular::HandleNewSignalQuality(uint32 strength) {
432 VLOG(2) << "Signal strength: " << strength;
433 if (service_.get()) {
434 service_->set_strength(strength);
435 }
436}
437
438void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700439 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700440 CHECK(!service_.get());
441 service_ =
442 new CellularService(control_interface_, dispatcher_, manager_, this);
Darin Petkovc408e692011-08-17 13:47:15 -0700443 switch (type_) {
444 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700445 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkovc408e692011-08-17 13:47:15 -0700446 break;
447 case kTypeCDMA:
448 service_->set_payment_url(cdma_.payment_url);
449 service_->set_usage_url(cdma_.usage_url);
450 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
451 break;
452 default:
453 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700454 }
Darin Petkovd9661952011-08-03 16:25:42 -0700455 // TODO(petkov): Set operator.
Darin Petkovf5f61e02011-07-29 11:35:40 -0700456}
457
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700458bool Cellular::TechnologyIs(const Device::Technology type) const {
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700459 return type == Device::kCellular;
460}
461
Darin Petkovc5f56562011-08-06 16:40:05 -0700462void Cellular::Connect() {
463 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700464 if (state_ == kStateConnected ||
465 state_ == kStateLinked) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700466 return;
467 }
468 CHECK_EQ(kStateRegistered, state_);
469 DBusPropertiesMap properties;
470 const char *phone_number = NULL;
471 switch (type_) {
472 case kTypeGSM:
473 phone_number = kPhoneNumberGSM;
474 break;
475 case kTypeCDMA:
476 phone_number = kPhoneNumberCDMA;
477 break;
478 default: NOTREACHED();
479 }
480 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
481 // TODO(petkov): Setup apn and "home_only".
482
483 // Defer connect because we may be in a dbus-c++ callback.
484 dispatcher_->PostTask(
485 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
486}
487
488void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
489 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700490 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700491 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700492 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700493 EstablishLink();
494}
495
496void Cellular::EstablishLink() {
497 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700498 CHECK_EQ(kStateConnected, state_);
499 unsigned int flags = 0;
500 if (manager_->device_info()->GetFlags(interface_index_, &flags) &&
501 (flags & IFF_UP) != 0) {
502 LinkEvent(flags, IFF_UP);
503 return;
504 }
505 // TODO(petkov): Provide a timeout for a failed link-up request.
506 RTNLHandler::GetInstance()->SetInterfaceFlags(
507 interface_index_, IFF_UP, IFF_UP);
508}
509
510void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
511 Device::LinkEvent(flags, change);
512 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
513 LOG(INFO) << link_name_ << " is up.";
514 SetState(kStateLinked);
515 manager_->RegisterService(service_);
516 // TODO(petkov): For GSM, remember the APN.
Darin Petkov77cb6812011-08-15 16:19:41 -0700517 LOG_IF(ERROR, !AcquireDHCPConfig()) << "Unable to acquire DHCP config.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700518 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
519 SetState(kStateConnected);
520 manager_->DeregisterService(service_);
Darin Petkov77cb6812011-08-15 16:19:41 -0700521 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700522 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700523}
524
Darin Petkovc408e692011-08-17 13:47:15 -0700525void Cellular::Activate(const string &carrier) {
526 CHECK_EQ(kTypeCDMA, type_);
527 // Defer connect because we may be in a dbus-c++ callback.
528 dispatcher_->PostTask(
529 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
530}
531
532void Cellular::ActivateTask(const string &carrier) {
533 VLOG(2) << __func__ << "(" << carrier << ")";
534 if (state_ != kStateEnabled && state_ != kStateRegistered) {
535 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
536 return;
537 }
538 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
539 uint32 status = cdma_proxy_->Activate(carrier);
540 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
541 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
542 }
543 HandleNewCDMAActivationState(status);
544}
545
546void Cellular::HandleNewCDMAActivationState(uint32 error) {
547 if (!service_.get()) {
548 return;
549 }
550 service_->set_activation_state(
551 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700552 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700553}
554
Darin Petkovb27e5442011-08-16 14:36:45 -0700555void Cellular::OnCDMAActivationStateChanged(
556 uint32 activation_state,
557 uint32 activation_error,
558 const DBusPropertiesMap &status_changes) {
559 CHECK_EQ(kTypeCDMA, type_);
560 DBusProperties::GetString(status_changes, "mdn", &mdn_);
561 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700562 if (DBusProperties::GetString(
563 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700564 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700565 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700566 }
Darin Petkovc408e692011-08-17 13:47:15 -0700567 cdma_.activation_state = activation_state;
568 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700569}
570
Darin Petkovd9661952011-08-03 16:25:42 -0700571void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
572 uint32 state_evdo) {
573 CHECK_EQ(kTypeCDMA, type_);
574 cdma_.registration_state_1x = state_1x;
575 cdma_.registration_state_evdo = state_evdo;
576 HandleNewRegistrationState();
577}
578
579void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
580 CHECK_EQ(kTypeCDMA, type_);
581 HandleNewSignalQuality(strength);
582}
583
Darin Petkovc5f56562011-08-06 16:40:05 -0700584void Cellular::OnModemStateChanged(uint32 old_state,
585 uint32 new_state,
586 uint32 reason) {
587 // TODO(petkov): Implement this.
588 NOTIMPLEMENTED();
589}
590
Chris Masone889666b2011-07-03 12:58:50 -0700591Stringmaps Cellular::EnumerateNetworks() {
592 Stringmaps to_return;
593 for (vector<Network>::const_iterator it = found_networks_.begin();
594 it != found_networks_.end();
595 ++it) {
596 to_return.push_back(it->ToDict());
597 }
598 return to_return;
599}
600
601StrIntPair Cellular::SimLockStatusToProperty() {
602 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
603 sim_lock_status_.lock_type),
604 make_pair(flimflam::kSIMLockRetriesLeftProperty,
605 sim_lock_status_.retries_left));
606}
607
608void Cellular::HelpRegisterDerivedStringmaps(
609 const string &name,
610 Stringmaps(Cellular::*get)(void),
611 bool(Cellular::*set)(const Stringmaps&)) {
612 store_.RegisterDerivedStringmaps(
613 name,
614 StringmapsAccessor(
615 new CustomAccessor<Cellular, Stringmaps>(this, get, set)));
616}
617
618void Cellular::HelpRegisterDerivedStrIntPair(
619 const string &name,
620 StrIntPair(Cellular::*get)(void),
621 bool(Cellular::*set)(const StrIntPair&)) {
622 store_.RegisterDerivedStrIntPair(
623 name,
624 StrIntPairAccessor(
625 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
626}
627
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700628} // namespace shill