blob: 3b0291e1acf5ae6fe69ea0880017683c07a4d0e2 [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
Darin Petkov3335b372011-08-22 11:05:32 -070041Cellular::Operator::Operator() {
42 SetName("");
43 SetCode("");
44 SetCountry("");
45}
46
47Cellular::Operator::~Operator() {}
48
49void Cellular::Operator::CopyFrom(const Operator &oper) {
50 dict_ = oper.dict_;
51}
52
53const string &Cellular::Operator::GetName() const {
54 return dict_.find(flimflam::kOperatorNameKey)->second;
55}
56
57void Cellular::Operator::SetName(const string &name) {
58 dict_[flimflam::kOperatorNameKey] = name;
59}
60
61const string &Cellular::Operator::GetCode() const {
62 return dict_.find(flimflam::kOperatorCodeKey)->second;
63}
64
65void Cellular::Operator::SetCode(const string &code) {
66 dict_[flimflam::kOperatorCodeKey] = code;
67}
68
69const string &Cellular::Operator::GetCountry() const {
70 return dict_.find(flimflam::kOperatorCountryKey)->second;
71}
72
73void Cellular::Operator::SetCountry(const string &country) {
74 dict_[flimflam::kOperatorCountryKey] = country;
75}
76
77const Stringmap &Cellular::Operator::ToDict() const {
78 return dict_;
79}
80
Chris Masone889666b2011-07-03 12:58:50 -070081Cellular::Network::Network() {
82 dict_[flimflam::kStatusProperty] = "";
83 dict_[flimflam::kNetworkIdProperty] = "";
84 dict_[flimflam::kShortNameProperty] = "";
85 dict_[flimflam::kLongNameProperty] = "";
86 dict_[flimflam::kTechnologyProperty] = "";
87}
88
89Cellular::Network::~Network() {}
90
Darin Petkov3335b372011-08-22 11:05:32 -070091const string &Cellular::Network::GetStatus() const {
Chris Masone889666b2011-07-03 12:58:50 -070092 return dict_.find(flimflam::kStatusProperty)->second;
93}
94
Darin Petkov3335b372011-08-22 11:05:32 -070095void Cellular::Network::SetStatus(const string &status) {
Chris Masone889666b2011-07-03 12:58:50 -070096 dict_[flimflam::kStatusProperty] = status;
97}
98
Darin Petkov3335b372011-08-22 11:05:32 -070099const string &Cellular::Network::GetId() const {
Chris Masone889666b2011-07-03 12:58:50 -0700100 return dict_.find(flimflam::kNetworkIdProperty)->second;
101}
102
Darin Petkov3335b372011-08-22 11:05:32 -0700103void Cellular::Network::SetId(const string &id) {
Chris Masone889666b2011-07-03 12:58:50 -0700104 dict_[flimflam::kNetworkIdProperty] = id;
105}
106
Darin Petkov3335b372011-08-22 11:05:32 -0700107const string &Cellular::Network::GetShortName() const {
Chris Masone889666b2011-07-03 12:58:50 -0700108 return dict_.find(flimflam::kShortNameProperty)->second;
109}
110
Darin Petkov3335b372011-08-22 11:05:32 -0700111void Cellular::Network::SetShortName(const string &name) {
Chris Masone889666b2011-07-03 12:58:50 -0700112 dict_[flimflam::kShortNameProperty] = name;
113}
114
Darin Petkov3335b372011-08-22 11:05:32 -0700115const string &Cellular::Network::GetLongName() const {
Chris Masone889666b2011-07-03 12:58:50 -0700116 return dict_.find(flimflam::kLongNameProperty)->second;
117}
118
Darin Petkov3335b372011-08-22 11:05:32 -0700119void Cellular::Network::SetLongName(const string &name) {
Chris Masone889666b2011-07-03 12:58:50 -0700120 dict_[flimflam::kLongNameProperty] = name;
121}
122
Darin Petkov3335b372011-08-22 11:05:32 -0700123const string &Cellular::Network::GetTechnology() const {
Chris Masone889666b2011-07-03 12:58:50 -0700124 return dict_.find(flimflam::kTechnologyProperty)->second;
125}
126
Darin Petkov3335b372011-08-22 11:05:32 -0700127void Cellular::Network::SetTechnology(const string &technology) {
Chris Masone889666b2011-07-03 12:58:50 -0700128 dict_[flimflam::kTechnologyProperty] = technology;
129}
130
131const Stringmap &Cellular::Network::ToDict() const {
132 return dict_;
133}
134
Darin Petkovbec79a22011-08-01 14:47:17 -0700135Cellular::CDMA::CDMA()
136 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
137 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkovcc044422011-08-17 13:30:06 -0700138 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
139 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -0700140
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700141Cellular::Cellular(ControlInterface *control_interface,
142 EventDispatcher *dispatcher,
143 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700144 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -0700145 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -0700146 int interface_index,
147 Type type,
148 const string &owner,
149 const string &path)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700150 : Device(control_interface,
151 dispatcher,
152 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700153 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700154 address,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700155 interface_index),
Darin Petkove9d12e02011-07-27 15:09:37 -0700156 type_(type),
157 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700158 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700159 dbus_owner_(owner),
160 dbus_path_(path),
Darin Petkovc5f56562011-08-06 16:40:05 -0700161 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700162 allow_roaming_(false),
Darin Petkove9d12e02011-07-27 15:09:37 -0700163 scanning_(false),
164 scan_interval_(0) {
165 store_.RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
166 store_.RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700167 store_.RegisterConstString(flimflam::kCarrierProperty, &carrier_);
Chris Masone4d42df82011-07-02 17:09:39 -0700168 store_.RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700169 store_.RegisterConstString(flimflam::kEsnProperty, &esn_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700170 store_.RegisterConstString(flimflam::kFirmwareRevisionProperty,
171 &firmware_revision_);
172 store_.RegisterConstString(flimflam::kHardwareRevisionProperty,
173 &hardware_revision_);
Darin Petkov3335b372011-08-22 11:05:32 -0700174 store_.RegisterConstStringmap(flimflam::kHomeProviderProperty,
175 &home_provider_.ToDict());
Chris Masone4d42df82011-07-02 17:09:39 -0700176 store_.RegisterConstString(flimflam::kImeiProperty, &imei_);
177 store_.RegisterConstString(flimflam::kImsiProperty, &imsi_);
178 store_.RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
179 store_.RegisterConstString(flimflam::kMdnProperty, &mdn_);
180 store_.RegisterConstString(flimflam::kMeidProperty, &meid_);
181 store_.RegisterConstString(flimflam::kMinProperty, &min_);
182 store_.RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkovcc044422011-08-17 13:30:06 -0700183 store_.RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
Chris Masoneb925cc82011-06-22 15:39:57 -0700184
Chris Masone889666b2011-07-03 12:58:50 -0700185 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
186 &Cellular::SimLockStatusToProperty,
187 NULL);
188 HelpRegisterDerivedStringmaps(flimflam::kFoundNetworksProperty,
189 &Cellular::EnumerateNetworks,
190 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700191
Chris Masone4d42df82011-07-02 17:09:39 -0700192 store_.RegisterConstBool(flimflam::kScanningProperty, &scanning_);
193 store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
194
Darin Petkove9d12e02011-07-27 15:09:37 -0700195 VLOG(2) << "Cellular device " << link_name_ << " initialized: "
196 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700197}
198
Darin Petkove9d12e02011-07-27 15:09:37 -0700199Cellular::~Cellular() {}
200
Darin Petkovcc044422011-08-17 13:30:06 -0700201string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700202 switch (type_) {
203 case kTypeGSM: return "CellularTypeGSM";
204 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700205 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700206 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700207 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700208}
209
Darin Petkovcc044422011-08-17 13:30:06 -0700210// static
211string Cellular::GetStateString(State state) {
212 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700213 case kStateDisabled: return "CellularStateDisabled";
214 case kStateEnabled: return "CellularStateEnabled";
215 case kStateRegistered: return "CellularStateRegistered";
216 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700217 case kStateLinked: return "CellularStateLinked";
218 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700219 }
Darin Petkovcc044422011-08-17 13:30:06 -0700220 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700221}
222
Darin Petkovc408e692011-08-17 13:47:15 -0700223// static
224string Cellular::GetCDMAActivationStateString(uint32 state) {
225 switch (state) {
226 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700227 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700228 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700229 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700230 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700231 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700232 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700233 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700234 default:
Darin Petkov51489002011-08-18 13:13:20 -0700235 return flimflam::kActivationStateUnknown;
236 }
237}
238
239// static
240string Cellular::GetCDMAActivationErrorString(uint32 error) {
241 switch (error) {
242 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
243 return flimflam::kErrorNeedEvdo;
244 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
245 return flimflam::kErrorNeedHomeNetwork;
246 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
247 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
248 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
249 return flimflam::kErrorOtaspFailed;
250 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
251 return "";
252 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
253 default:
254 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700255 }
256}
257
Darin Petkov0828f5f2011-08-11 10:18:52 -0700258void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700259 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700260 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700261}
262
263void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700264 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700265 Device::Start();
Darin Petkovbec79a22011-08-01 14:47:17 -0700266 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700267 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700268 if (type_ == kTypeGSM) {
269 RegisterGSMModem();
270 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700271 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700272 GetModemIdentifiers();
273 if (type_ == kTypeGSM) {
274 GetGSMProperties();
275 }
276 GetModemInfo();
277 GetModemRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700278}
279
280void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700281 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700282 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700283 cdma_proxy_.reset();
Chris Masone2b105542011-06-22 10:58:09 -0700284 manager_->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700285 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700286 SetState(kStateDisabled);
287 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index_, 0, IFF_UP);
Darin Petkov3335b372011-08-22 11:05:32 -0700288 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700289}
290
Darin Petkovbec79a22011-08-01 14:47:17 -0700291void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700292 VLOG(2) << __func__;
Darin Petkovbec79a22011-08-01 14:47:17 -0700293 proxy_.reset(
Darin Petkovc5f56562011-08-06 16:40:05 -0700294 ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700295 simple_proxy_.reset(
296 ProxyFactory::factory()->CreateModemSimpleProxy(
297 dbus_path_, dbus_owner_));
298 switch (type_) {
299 case kTypeGSM:
300 NOTIMPLEMENTED();
301 break;
302 case kTypeCDMA:
303 cdma_proxy_.reset(
304 ProxyFactory::factory()->CreateModemCDMAProxy(
Darin Petkovd9661952011-08-03 16:25:42 -0700305 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700306 break;
307 default: NOTREACHED();
308 }
309}
310
Darin Petkovf5f61e02011-07-29 11:35:40 -0700311void Cellular::EnableModem() {
312 CHECK_EQ(kStateDisabled, state_);
313 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
314 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700315 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700316}
317
318void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700319 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700320 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
321 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700322 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
323 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700324 home_provider_.SetName(carrier_);
325 home_provider_.SetCode("");
326 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700327 }
Darin Petkovceb68172011-07-29 14:47:48 -0700328 DBusProperties::GetString(properties, "meid", &meid_);
329 DBusProperties::GetString(properties, "imei", &imei_);
330 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
331 type_ == kTypeGSM) {
332 // TODO(petkov): Set GSM provider.
333 }
334 DBusProperties::GetString(properties, "esn", &esn_);
335 DBusProperties::GetString(properties, "mdn", &mdn_);
336 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700337 DBusProperties::GetString(
338 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700339
Darin Petkovc408e692011-08-17 13:47:15 -0700340 // TODO(petkov): Handle "state".
Darin Petkovb27e5442011-08-16 14:36:45 -0700341
Darin Petkovceb68172011-07-29 14:47:48 -0700342 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700343 DBusProperties::GetUint32(
344 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700345 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700346 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
347 // to match flimflam. In the future, provide a plugin API to get these
348 // directly from the modem driver.
349 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
350 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700351 }
352}
353
354void Cellular::GetModemIdentifiers() {
355 // TODO(petkov): Implement this.
356 NOTIMPLEMENTED();
357}
358
359void Cellular::GetGSMProperties() {
360 // TODO(petkov): Implement this.
361 NOTIMPLEMENTED();
362}
363
364void Cellular::RegisterGSMModem() {
365 // TODO(petkov): Invoke ModemManager.Modem.Gsm.Network.Register.
366 NOTIMPLEMENTED();
367}
368
369void Cellular::GetModemInfo() {
370 ModemProxyInterface::Info info = proxy_->GetInfo();
371 manufacturer_ = info._1;
372 model_id_ = info._2;
373 hardware_revision_ = info._3;
374 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
375 << hardware_revision_;
376}
377
378void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700379 switch (type_) {
380 case kTypeGSM:
381 GetGSMRegistrationState();
382 break;
383 case kTypeCDMA:
384 GetCDMARegistrationState();
385 break;
386 default: NOTREACHED();
387 }
Darin Petkovd9661952011-08-03 16:25:42 -0700388 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700389}
390
391void Cellular::GetCDMARegistrationState() {
392 CHECK_EQ(kTypeCDMA, type_);
393 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
394 &cdma_.registration_state_evdo);
395 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
396 << ") EVDO(" << cdma_.registration_state_evdo << ")";
397 // TODO(petkov): handle_reported_connect?
398}
399
400void Cellular::GetGSMRegistrationState() {
Darin Petkovceb68172011-07-29 14:47:48 -0700401 // TODO(petkov): Implement this.
402 NOTIMPLEMENTED();
403}
404
Darin Petkovd9661952011-08-03 16:25:42 -0700405bool Cellular::IsModemRegistered() {
406 return cdma_.registration_state_1x !=
407 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN ||
408 cdma_.registration_state_evdo !=
409 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN;
410 // TODO(petkov): Handle GSM states.
411}
412
413void Cellular::HandleNewRegistrationState() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700414 dispatcher_->PostTask(
415 task_factory_.NewRunnableMethod(
416 &Cellular::HandleNewRegistrationStateTask));
417}
418
419void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700420 VLOG(2) << __func__;
421 if (!IsModemRegistered()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700422 if (state_ == kStateLinked) {
423 manager_->DeregisterService(service_);
424 }
Darin Petkovd9661952011-08-03 16:25:42 -0700425 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700426 if (state_ == kStateLinked ||
427 state_ == kStateConnected ||
428 state_ == kStateRegistered) {
429 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700430 }
431 return;
432 }
Darin Petkovd9661952011-08-03 16:25:42 -0700433 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700434 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700435 }
436 if (!service_.get()) {
437 // For now, no endpoint is created. Revisit if necessary.
438 CreateService();
439 }
440 GetModemSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700441 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
442 SetState(kStateConnected);
443 EstablishLink();
444 }
Darin Petkovd9661952011-08-03 16:25:42 -0700445 // TODO(petkov): Update the service.
446}
447
448void Cellular::GetModemSignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700449 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700450 uint32 strength = 0;
451 switch (type_) {
452 case kTypeGSM:
453 strength = GetGSMSignalQuality();
454 break;
455 case kTypeCDMA:
456 strength = GetCDMASignalQuality();
457 break;
458 default: NOTREACHED();
459 }
460 HandleNewSignalQuality(strength);
461}
462
463uint32 Cellular::GetCDMASignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700464 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700465 CHECK_EQ(kTypeCDMA, type_);
466 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
467 return cdma_proxy_->GetSignalQuality();
468}
469
470uint32 Cellular::GetGSMSignalQuality() {
Darin Petkovceb68172011-07-29 14:47:48 -0700471 // TODO(petkov): Implement this.
472 NOTIMPLEMENTED();
Darin Petkovd9661952011-08-03 16:25:42 -0700473 return 0;
474}
475
476void Cellular::HandleNewSignalQuality(uint32 strength) {
477 VLOG(2) << "Signal strength: " << strength;
478 if (service_.get()) {
479 service_->set_strength(strength);
480 }
481}
482
483void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700484 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700485 CHECK(!service_.get());
486 service_ =
487 new CellularService(control_interface_, dispatcher_, manager_, this);
Darin Petkovc408e692011-08-17 13:47:15 -0700488 switch (type_) {
489 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700490 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov3335b372011-08-22 11:05:32 -0700491 // TODO(petkov): Set serving operator.
Darin Petkovc408e692011-08-17 13:47:15 -0700492 break;
493 case kTypeCDMA:
494 service_->set_payment_url(cdma_.payment_url);
495 service_->set_usage_url(cdma_.usage_url);
Darin Petkov3335b372011-08-22 11:05:32 -0700496 service_->set_serving_operator(home_provider_);
Darin Petkovc408e692011-08-17 13:47:15 -0700497 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
498 break;
499 default:
500 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700501 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700502}
503
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700504bool Cellular::TechnologyIs(const Device::Technology type) const {
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700505 return type == Device::kCellular;
506}
507
Darin Petkovc5f56562011-08-06 16:40:05 -0700508void Cellular::Connect() {
509 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700510 if (state_ == kStateConnected ||
511 state_ == kStateLinked) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700512 return;
513 }
514 CHECK_EQ(kStateRegistered, state_);
515 DBusPropertiesMap properties;
516 const char *phone_number = NULL;
517 switch (type_) {
518 case kTypeGSM:
519 phone_number = kPhoneNumberGSM;
520 break;
521 case kTypeCDMA:
522 phone_number = kPhoneNumberCDMA;
523 break;
524 default: NOTREACHED();
525 }
526 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
527 // TODO(petkov): Setup apn and "home_only".
528
529 // Defer connect because we may be in a dbus-c++ callback.
530 dispatcher_->PostTask(
531 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
532}
533
534void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
535 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700536 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700537 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700538 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700539 EstablishLink();
540}
541
542void Cellular::EstablishLink() {
543 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700544 CHECK_EQ(kStateConnected, state_);
545 unsigned int flags = 0;
546 if (manager_->device_info()->GetFlags(interface_index_, &flags) &&
547 (flags & IFF_UP) != 0) {
548 LinkEvent(flags, IFF_UP);
549 return;
550 }
551 // TODO(petkov): Provide a timeout for a failed link-up request.
552 RTNLHandler::GetInstance()->SetInterfaceFlags(
553 interface_index_, IFF_UP, IFF_UP);
554}
555
556void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
557 Device::LinkEvent(flags, change);
558 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
559 LOG(INFO) << link_name_ << " is up.";
560 SetState(kStateLinked);
561 manager_->RegisterService(service_);
562 // TODO(petkov): For GSM, remember the APN.
Darin Petkov77cb6812011-08-15 16:19:41 -0700563 LOG_IF(ERROR, !AcquireDHCPConfig()) << "Unable to acquire DHCP config.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700564 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
565 SetState(kStateConnected);
566 manager_->DeregisterService(service_);
Darin Petkov77cb6812011-08-15 16:19:41 -0700567 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700568 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700569}
570
Darin Petkovc408e692011-08-17 13:47:15 -0700571void Cellular::Activate(const string &carrier) {
572 CHECK_EQ(kTypeCDMA, type_);
573 // Defer connect because we may be in a dbus-c++ callback.
574 dispatcher_->PostTask(
575 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
576}
577
578void Cellular::ActivateTask(const string &carrier) {
579 VLOG(2) << __func__ << "(" << carrier << ")";
580 if (state_ != kStateEnabled && state_ != kStateRegistered) {
581 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
582 return;
583 }
584 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
585 uint32 status = cdma_proxy_->Activate(carrier);
586 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
587 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
588 }
589 HandleNewCDMAActivationState(status);
590}
591
592void Cellular::HandleNewCDMAActivationState(uint32 error) {
593 if (!service_.get()) {
594 return;
595 }
596 service_->set_activation_state(
597 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700598 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700599}
600
Darin Petkovb27e5442011-08-16 14:36:45 -0700601void Cellular::OnCDMAActivationStateChanged(
602 uint32 activation_state,
603 uint32 activation_error,
604 const DBusPropertiesMap &status_changes) {
605 CHECK_EQ(kTypeCDMA, type_);
606 DBusProperties::GetString(status_changes, "mdn", &mdn_);
607 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700608 if (DBusProperties::GetString(
609 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700610 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700611 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700612 }
Darin Petkovc408e692011-08-17 13:47:15 -0700613 cdma_.activation_state = activation_state;
614 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700615}
616
Darin Petkovd9661952011-08-03 16:25:42 -0700617void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
618 uint32 state_evdo) {
619 CHECK_EQ(kTypeCDMA, type_);
620 cdma_.registration_state_1x = state_1x;
621 cdma_.registration_state_evdo = state_evdo;
622 HandleNewRegistrationState();
623}
624
625void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
626 CHECK_EQ(kTypeCDMA, type_);
627 HandleNewSignalQuality(strength);
628}
629
Darin Petkovc5f56562011-08-06 16:40:05 -0700630void Cellular::OnModemStateChanged(uint32 old_state,
631 uint32 new_state,
632 uint32 reason) {
633 // TODO(petkov): Implement this.
634 NOTIMPLEMENTED();
635}
636
Chris Masone889666b2011-07-03 12:58:50 -0700637Stringmaps Cellular::EnumerateNetworks() {
638 Stringmaps to_return;
639 for (vector<Network>::const_iterator it = found_networks_.begin();
640 it != found_networks_.end();
641 ++it) {
642 to_return.push_back(it->ToDict());
643 }
644 return to_return;
645}
646
647StrIntPair Cellular::SimLockStatusToProperty() {
648 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
649 sim_lock_status_.lock_type),
650 make_pair(flimflam::kSIMLockRetriesLeftProperty,
651 sim_lock_status_.retries_left));
652}
653
654void Cellular::HelpRegisterDerivedStringmaps(
655 const string &name,
656 Stringmaps(Cellular::*get)(void),
657 bool(Cellular::*set)(const Stringmaps&)) {
658 store_.RegisterDerivedStringmaps(
659 name,
660 StringmapsAccessor(
661 new CustomAccessor<Cellular, Stringmaps>(this, get, set)));
662}
663
664void Cellular::HelpRegisterDerivedStrIntPair(
665 const string &name,
666 StrIntPair(Cellular::*get)(void),
667 bool(Cellular::*set)(const StrIntPair&)) {
668 store_.RegisterDerivedStrIntPair(
669 name,
670 StrIntPairAccessor(
671 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
672}
673
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700674} // namespace shill