blob: 3d658764a8d5b1a5e552434decf83c554a40bf59 [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>
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -07008#include <linux/if.h> // Needs definitions from netinet/in.h
Darin Petkov0828f5f2011-08-11 10:18:52 -07009
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>
Darin Petkov137884a2011-10-26 18:52:47 +020018#include <mobile_provider.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070019
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/cellular_capability_cdma.h"
21#include "shill/cellular_capability_gsm.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070022#include "shill/cellular_service.h"
23#include "shill/control_interface.h"
24#include "shill/device.h"
25#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070026#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070027#include "shill/event_dispatcher.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070028#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070029#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070030#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070031#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070032#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070033#include "shill/rtnl_handler.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070034
Chris Masone889666b2011-07-03 12:58:50 -070035using std::make_pair;
Darin Petkovc0865312011-09-16 15:31:20 -070036using std::map;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070037using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070038using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070039
40namespace shill {
41
Darin Petkovc5f56562011-08-06 16:40:05 -070042const char Cellular::kConnectPropertyPhoneNumber[] = "number";
43const char Cellular::kPhoneNumberCDMA[] = "#777";
44const char Cellular::kPhoneNumberGSM[] = "*99#";
45
Darin Petkov3335b372011-08-22 11:05:32 -070046Cellular::Operator::Operator() {
47 SetName("");
48 SetCode("");
49 SetCountry("");
50}
51
52Cellular::Operator::~Operator() {}
53
54void Cellular::Operator::CopyFrom(const Operator &oper) {
55 dict_ = oper.dict_;
56}
57
58const string &Cellular::Operator::GetName() const {
59 return dict_.find(flimflam::kOperatorNameKey)->second;
60}
61
62void Cellular::Operator::SetName(const string &name) {
63 dict_[flimflam::kOperatorNameKey] = name;
64}
65
66const string &Cellular::Operator::GetCode() const {
67 return dict_.find(flimflam::kOperatorCodeKey)->second;
68}
69
70void Cellular::Operator::SetCode(const string &code) {
71 dict_[flimflam::kOperatorCodeKey] = code;
72}
73
74const string &Cellular::Operator::GetCountry() const {
75 return dict_.find(flimflam::kOperatorCountryKey)->second;
76}
77
78void Cellular::Operator::SetCountry(const string &country) {
79 dict_[flimflam::kOperatorCountryKey] = country;
80}
81
82const Stringmap &Cellular::Operator::ToDict() const {
83 return dict_;
84}
85
Darin Petkovbec79a22011-08-01 14:47:17 -070086Cellular::CDMA::CDMA()
Darin Petkov184c54e2011-11-15 12:44:39 +010087 : activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
Darin Petkovcc044422011-08-17 13:30:06 -070088 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -070089
Darin Petkov9bac6fe2011-08-26 12:49:05 -070090Cellular::GSM::GSM()
Darin Petkov184c54e2011-11-15 12:44:39 +010091 : access_technology(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN) {}
Darin Petkov9bac6fe2011-08-26 12:49:05 -070092
Chris Masone3bd3c8c2011-06-13 08:20:26 -070093Cellular::Cellular(ControlInterface *control_interface,
94 EventDispatcher *dispatcher,
95 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070096 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070097 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070098 int interface_index,
99 Type type,
100 const string &owner,
Darin Petkov137884a2011-10-26 18:52:47 +0200101 const string &path,
102 mobile_provider_db *provider_db)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700103 : Device(control_interface,
104 dispatcher,
105 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700106 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700107 address,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700108 interface_index),
Darin Petkovab565bb2011-10-06 02:55:51 -0700109 proxy_factory_(ProxyFactory::GetInstance()),
Darin Petkove9d12e02011-07-27 15:09:37 -0700110 type_(type),
111 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700112 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700113 dbus_owner_(owner),
114 dbus_path_(path),
Darin Petkov137884a2011-10-26 18:52:47 +0200115 provider_db_(provider_db),
Darin Petkovc5f56562011-08-06 16:40:05 -0700116 task_factory_(this),
Darin Petkov1272a432011-11-10 15:53:37 +0100117 allow_roaming_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700118 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700119 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
120 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
121 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
122 store->RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
123 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
124 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700125 &firmware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700126 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700127 &hardware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700128 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700129 &home_provider_.ToDict());
Paul Stewartac4ac002011-08-26 12:04:26 -0700130 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
131 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
132 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
133 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
134 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
135 store->RegisterConstString(flimflam::kMinProperty, &min_);
136 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
137 store->RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
Chris Masoneb925cc82011-06-22 15:39:57 -0700138
Chris Masone889666b2011-07-03 12:58:50 -0700139 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
140 &Cellular::SimLockStatusToProperty,
141 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700142
Paul Stewartac4ac002011-08-26 12:04:26 -0700143 VLOG(2) << "Cellular device " << this->link_name() << " initialized: "
Darin Petkove9d12e02011-07-27 15:09:37 -0700144 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700145}
146
Darin Petkove9d12e02011-07-27 15:09:37 -0700147Cellular::~Cellular() {}
148
Darin Petkovcc044422011-08-17 13:30:06 -0700149string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700150 switch (type_) {
151 case kTypeGSM: return "CellularTypeGSM";
152 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700153 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700154 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700155 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700156}
157
Darin Petkovcc044422011-08-17 13:30:06 -0700158// static
159string Cellular::GetStateString(State state) {
160 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700161 case kStateDisabled: return "CellularStateDisabled";
162 case kStateEnabled: return "CellularStateEnabled";
163 case kStateRegistered: return "CellularStateRegistered";
164 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700165 case kStateLinked: return "CellularStateLinked";
166 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700167 }
Darin Petkovcc044422011-08-17 13:30:06 -0700168 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700169}
170
Darin Petkovc408e692011-08-17 13:47:15 -0700171// static
172string Cellular::GetCDMAActivationStateString(uint32 state) {
173 switch (state) {
174 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700175 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700176 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700177 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700178 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700179 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700180 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700181 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700182 default:
Darin Petkov51489002011-08-18 13:13:20 -0700183 return flimflam::kActivationStateUnknown;
184 }
185}
186
187// static
188string Cellular::GetCDMAActivationErrorString(uint32 error) {
189 switch (error) {
190 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
191 return flimflam::kErrorNeedEvdo;
192 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
193 return flimflam::kErrorNeedHomeNetwork;
194 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
195 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
196 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
197 return flimflam::kErrorOtaspFailed;
198 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
199 return "";
200 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
201 default:
202 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700203 }
204}
205
Darin Petkov0828f5f2011-08-11 10:18:52 -0700206void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700207 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700208 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700209}
210
211void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700212 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700213 Device::Start();
Darin Petkovdaf43862011-10-27 11:37:28 +0200214 InitCapability(); // For now, only a single capability is supported.
Darin Petkovbec79a22011-08-01 14:47:17 -0700215 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700216 EnableModem();
Darin Petkov184c54e2011-11-15 12:44:39 +0100217 capability_->Register();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700218 GetModemStatus();
Darin Petkovcb547732011-11-09 13:55:26 +0100219 capability_->GetIdentifiers();
Darin Petkov184c54e2011-11-15 12:44:39 +0100220 capability_->GetProperties();
Darin Petkovceb68172011-07-29 14:47:48 -0700221 GetModemInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100222 capability_->GetRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700223}
224
225void Cellular::Stop() {
Darin Petkovdaf43862011-10-27 11:37:28 +0200226 capability_.reset();
Darin Petkove9d12e02011-07-27 15:09:37 -0700227 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700228 simple_proxy_.reset();
Paul Stewartac4ac002011-08-26 12:04:26 -0700229 manager()->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700230 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700231 SetState(kStateDisabled);
Darin Petkov3335b372011-08-22 11:05:32 -0700232 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700233}
234
Darin Petkovdaf43862011-10-27 11:37:28 +0200235void Cellular::InitCapability() {
236 VLOG(2) << __func__;
237 switch (type_) {
238 case kTypeGSM:
239 capability_.reset(new CellularCapabilityGSM(this));
240 break;
241 case kTypeCDMA:
242 capability_.reset(new CellularCapabilityCDMA(this));
243 break;
244 default: NOTREACHED();
245 }
246}
247
Darin Petkovbec79a22011-08-01 14:47:17 -0700248void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700249 VLOG(2) << __func__;
Darin Petkovab565bb2011-10-06 02:55:51 -0700250 proxy_.reset(proxy_factory_->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700251 simple_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700252 proxy_factory_->CreateModemSimpleProxy(dbus_path_, dbus_owner_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200253 capability_->InitProxies();
Darin Petkovbec79a22011-08-01 14:47:17 -0700254}
255
Darin Petkovf5f61e02011-07-29 11:35:40 -0700256void Cellular::EnableModem() {
257 CHECK_EQ(kStateDisabled, state_);
258 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
259 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700260 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700261}
262
263void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700264 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700265 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
266 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700267 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
268 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700269 home_provider_.SetName(carrier_);
270 home_provider_.SetCode("");
271 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700272 }
Darin Petkovceb68172011-07-29 14:47:48 -0700273 DBusProperties::GetString(properties, "meid", &meid_);
274 DBusProperties::GetString(properties, "imei", &imei_);
275 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
276 type_ == kTypeGSM) {
Darin Petkov137884a2011-10-26 18:52:47 +0200277 // TODO(petkov): Set GSM provider based on IMSI and SPN.
Darin Petkovceb68172011-07-29 14:47:48 -0700278 }
279 DBusProperties::GetString(properties, "esn", &esn_);
280 DBusProperties::GetString(properties, "mdn", &mdn_);
281 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700282 DBusProperties::GetString(
283 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700284
Darin Petkovd2045802011-08-23 11:09:25 -0700285 uint32 state = 0;
286 if (DBusProperties::GetUint32(properties, "state", &state)) {
287 modem_state_ = static_cast<ModemState>(state);
288 }
Darin Petkovb27e5442011-08-16 14:36:45 -0700289
Darin Petkovceb68172011-07-29 14:47:48 -0700290 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700291 DBusProperties::GetUint32(
292 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700293 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700294 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
295 // to match flimflam. In the future, provide a plugin API to get these
296 // directly from the modem driver.
297 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
298 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700299 }
300}
301
Darin Petkov184c54e2011-11-15 12:44:39 +0100302void Cellular::Activate(const std::string &carrier, Error *error) {
303 capability_->Activate(carrier, error);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700304}
305
306void Cellular::RegisterOnNetwork(const string &network_id, Error *error) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100307 capability_->RegisterOnNetwork(network_id, error);
Darin Petkova3d3be52011-11-14 21:34:16 +0100308}
309
Darin Petkove42e1012011-08-31 12:35:04 -0700310void Cellular::RequirePIN(const string &pin, bool require, Error *error) {
Darin Petkovb05315f2011-11-07 10:14:25 +0100311 capability_->RequirePIN(pin, require, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700312}
313
314void Cellular::EnterPIN(const string &pin, Error *error) {
Darin Petkovb05315f2011-11-07 10:14:25 +0100315 capability_->EnterPIN(pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700316}
317
Darin Petkovb05315f2011-11-07 10:14:25 +0100318void Cellular::UnblockPIN(
319 const string &unblock_code, const string &pin, Error *error) {
320 capability_->UnblockPIN(unblock_code, pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700321}
322
Darin Petkovb05315f2011-11-07 10:14:25 +0100323void Cellular::ChangePIN(
324 const string &old_pin, const string &new_pin, Error *error) {
325 capability_->ChangePIN(old_pin, new_pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700326}
327
Darin Petkov1272a432011-11-10 15:53:37 +0100328void Cellular::Scan(Error *error) {
329 capability_->Scan(error);
330}
331
Darin Petkovceb68172011-07-29 14:47:48 -0700332void Cellular::GetModemInfo() {
Darin Petkovd2045802011-08-23 11:09:25 -0700333 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovceb68172011-07-29 14:47:48 -0700334 ModemProxyInterface::Info info = proxy_->GetInfo();
335 manufacturer_ = info._1;
336 model_id_ = info._2;
337 hardware_revision_ = info._3;
338 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
339 << hardware_revision_;
340}
341
Darin Petkovd9661952011-08-03 16:25:42 -0700342void Cellular::HandleNewRegistrationState() {
Paul Stewartac4ac002011-08-26 12:04:26 -0700343 dispatcher()->PostTask(
Darin Petkov0828f5f2011-08-11 10:18:52 -0700344 task_factory_.NewRunnableMethod(
345 &Cellular::HandleNewRegistrationStateTask));
346}
347
348void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700349 VLOG(2) << __func__;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100350 const string network_tech = capability_->GetNetworkTechnologyString();
Darin Petkovd2045802011-08-23 11:09:25 -0700351 if (network_tech.empty()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700352 if (state_ == kStateLinked) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700353 manager()->DeregisterService(service_);
Darin Petkovc408e692011-08-17 13:47:15 -0700354 }
Darin Petkovd9661952011-08-03 16:25:42 -0700355 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700356 if (state_ == kStateLinked ||
357 state_ == kStateConnected ||
358 state_ == kStateRegistered) {
359 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700360 }
361 return;
362 }
Darin Petkovd9661952011-08-03 16:25:42 -0700363 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700364 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700365 }
366 if (!service_.get()) {
367 // For now, no endpoint is created. Revisit if necessary.
368 CreateService();
369 }
Darin Petkov3e509242011-11-10 14:46:44 +0100370 capability_->GetSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700371 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
372 SetState(kStateConnected);
373 EstablishLink();
374 }
Darin Petkovd2045802011-08-23 11:09:25 -0700375 service_->set_network_tech(network_tech);
Darin Petkov20c13ec2011-11-09 15:07:15 +0100376 service_->set_roaming_state(capability_->GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700377}
378
Darin Petkovd9661952011-08-03 16:25:42 -0700379void Cellular::HandleNewSignalQuality(uint32 strength) {
380 VLOG(2) << "Signal strength: " << strength;
381 if (service_.get()) {
382 service_->set_strength(strength);
383 }
384}
385
386void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700387 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700388 CHECK(!service_.get());
389 service_ =
Paul Stewartac4ac002011-08-26 12:04:26 -0700390 new CellularService(control_interface(), dispatcher(), manager(), this);
Darin Petkovc408e692011-08-17 13:47:15 -0700391 switch (type_) {
392 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700393 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov137884a2011-10-26 18:52:47 +0200394 UpdateServingOperator();
Darin Petkovc408e692011-08-17 13:47:15 -0700395 break;
396 case kTypeCDMA:
397 service_->set_payment_url(cdma_.payment_url);
398 service_->set_usage_url(cdma_.usage_url);
Darin Petkov137884a2011-10-26 18:52:47 +0200399 UpdateServingOperator();
Darin Petkovc408e692011-08-17 13:47:15 -0700400 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
401 break;
402 default:
403 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700404 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700405}
406
Paul Stewartfdd16072011-09-16 12:41:35 -0700407bool Cellular::TechnologyIs(const Technology::Identifier type) const {
408 return type == Technology::kCellular;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700409}
410
Darin Petkov4d6d9412011-08-24 13:19:54 -0700411void Cellular::Connect(Error *error) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700412 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700413 if (state_ == kStateConnected ||
414 state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700415 Error::PopulateAndLog(error, Error::kAlreadyConnected,
416 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700417 return;
418 }
419 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700420
421 if (!allow_roaming_ &&
422 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700423 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
424 "Roaming disallowed; connection request ignored.");
Darin Petkov4d6d9412011-08-24 13:19:54 -0700425 CHECK(error);
Darin Petkovd2045802011-08-23 11:09:25 -0700426 return;
427 }
428
Darin Petkovc5f56562011-08-06 16:40:05 -0700429 DBusPropertiesMap properties;
430 const char *phone_number = NULL;
431 switch (type_) {
432 case kTypeGSM:
433 phone_number = kPhoneNumberGSM;
434 break;
435 case kTypeCDMA:
436 phone_number = kPhoneNumberCDMA;
437 break;
438 default: NOTREACHED();
439 }
440 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
441 // TODO(petkov): Setup apn and "home_only".
442
443 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700444 dispatcher()->PostTask(
Darin Petkovc5f56562011-08-06 16:40:05 -0700445 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
446}
447
448void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
449 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700450 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700451 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700452 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700453 EstablishLink();
454}
455
456void Cellular::EstablishLink() {
457 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700458 CHECK_EQ(kStateConnected, state_);
459 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700460 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700461 (flags & IFF_UP) != 0) {
462 LinkEvent(flags, IFF_UP);
463 return;
464 }
465 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700466 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700467}
468
469void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
470 Device::LinkEvent(flags, change);
471 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700472 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700473 SetState(kStateLinked);
Paul Stewartac4ac002011-08-26 12:04:26 -0700474 manager()->RegisterService(service_);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700475 // TODO(petkov): For GSM, remember the APN.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700476 if (AcquireDHCPConfig()) {
477 SelectService(service_);
478 SetServiceState(Service::kStateConfiguring);
479 } else {
480 LOG(ERROR) << "Unable to acquire DHCP config.";
481 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700482 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
483 SetState(kStateConnected);
Paul Stewartac4ac002011-08-26 12:04:26 -0700484 manager()->DeregisterService(service_);
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700485 SelectService(NULL);
Darin Petkov77cb6812011-08-15 16:19:41 -0700486 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700487 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700488}
489
Darin Petkovc408e692011-08-17 13:47:15 -0700490void Cellular::HandleNewCDMAActivationState(uint32 error) {
491 if (!service_.get()) {
492 return;
493 }
494 service_->set_activation_state(
495 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700496 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700497}
498
mukesh agrawal1830fa12011-09-26 14:31:40 -0700499void Cellular::OnModemStateChanged(uint32 /*old_state*/,
500 uint32 /*new_state*/,
501 uint32 /*reason*/) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700502 // TODO(petkov): Implement this.
503 NOTIMPLEMENTED();
504}
505
Darin Petkov48a511a2011-09-15 10:33:37 -0700506void Cellular::SetGSMAccessTechnology(uint32 access_technology) {
507 CHECK_EQ(kTypeGSM, type_);
508 gsm_.access_technology = access_technology;
509 if (service_.get()) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100510 service_->set_network_tech(capability_->GetNetworkTechnologyString());
Darin Petkov48a511a2011-09-15 10:33:37 -0700511 }
512}
513
Darin Petkov137884a2011-10-26 18:52:47 +0200514void Cellular::UpdateGSMOperatorInfo() {
515 if (!gsm_.network_id.empty()) {
516 VLOG(2) << "Looking up network id: " << gsm_.network_id;
517 mobile_provider *provider =
518 mobile_provider_lookup_by_network(provider_db_,
519 gsm_.network_id.c_str());
520 if (provider) {
521 const char *provider_name = mobile_provider_get_name(provider);
522 if (provider_name && *provider_name) {
523 gsm_.operator_name = provider_name;
524 gsm_.operator_country = provider->country;
525 VLOG(2) << "Operator name: " << gsm_.operator_name
526 << ", country: " << gsm_.operator_country;
527 }
528 } else {
529 VLOG(2) << "GSM provider not found.";
530 }
531 }
532 UpdateServingOperator();
533}
534
535void Cellular::UpdateServingOperator() {
536 if (!service_.get()) {
537 return;
538 }
539 switch (type_) {
540 case kTypeGSM: {
541 Operator oper;
542 oper.SetName(gsm_.operator_name);
543 oper.SetCode(gsm_.network_id);
544 oper.SetCountry(gsm_.operator_country);
545 service_->set_serving_operator(oper);
546 break;
547 }
548 case kTypeCDMA:
549 service_->set_serving_operator(home_provider_);
550 break;
551 default: NOTREACHED();
552 }
553}
554
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800555StrIntPair Cellular::SimLockStatusToProperty(Error */*error*/) {
Chris Masone889666b2011-07-03 12:58:50 -0700556 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
557 sim_lock_status_.lock_type),
558 make_pair(flimflam::kSIMLockRetriesLeftProperty,
559 sim_lock_status_.retries_left));
560}
561
Chris Masone889666b2011-07-03 12:58:50 -0700562void Cellular::HelpRegisterDerivedStrIntPair(
563 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800564 StrIntPair(Cellular::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700565 void(Cellular::*set)(const StrIntPair&, Error *)) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700566 mutable_store()->RegisterDerivedStrIntPair(
Chris Masone889666b2011-07-03 12:58:50 -0700567 name,
568 StrIntPairAccessor(
569 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
570}
571
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700572} // namespace shill