blob: 1cac8f79b486e7d8f769b9f8bb2f4c59e0529c6d [file] [log] [blame]
Darin Petkovc64fe5e2012-01-11 12:46:13 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Masone3bd3c8c2011-06-13 08:20:26 -07002// 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
Eric Shienbrood3e20a232012-02-16 11:35:56 -050014#include <base/bind.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070015#include <base/logging.h>
Darin Petkove9d12e02011-07-27 15:09:37 -070016#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070017#include <chromeos/dbus/service_constants.h>
Darin Petkov137884a2011-10-26 18:52:47 +020018#include <mobile_provider.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070019
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050020#include "shill/adaptor_interfaces.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020021#include "shill/cellular_capability_cdma.h"
22#include "shill/cellular_capability_gsm.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040023#include "shill/cellular_capability_universal.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070024#include "shill/cellular_service.h"
25#include "shill/control_interface.h"
26#include "shill/device.h"
27#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070028#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070029#include "shill/event_dispatcher.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070030#include "shill/manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070031#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070032#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070033#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070034#include "shill/rtnl_handler.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070035#include "shill/scope_logger.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080036#include "shill/technology.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070037
Eric Shienbrood3e20a232012-02-16 11:35:56 -050038using base::Bind;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070039using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070040using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070041
42namespace shill {
43
Darin Petkov3335b372011-08-22 11:05:32 -070044Cellular::Operator::Operator() {
45 SetName("");
46 SetCode("");
47 SetCountry("");
48}
49
50Cellular::Operator::~Operator() {}
51
52void Cellular::Operator::CopyFrom(const Operator &oper) {
53 dict_ = oper.dict_;
54}
55
56const string &Cellular::Operator::GetName() const {
57 return dict_.find(flimflam::kOperatorNameKey)->second;
58}
59
60void Cellular::Operator::SetName(const string &name) {
61 dict_[flimflam::kOperatorNameKey] = name;
62}
63
64const string &Cellular::Operator::GetCode() const {
65 return dict_.find(flimflam::kOperatorCodeKey)->second;
66}
67
68void Cellular::Operator::SetCode(const string &code) {
69 dict_[flimflam::kOperatorCodeKey] = code;
70}
71
72const string &Cellular::Operator::GetCountry() const {
73 return dict_.find(flimflam::kOperatorCountryKey)->second;
74}
75
76void Cellular::Operator::SetCountry(const string &country) {
77 dict_[flimflam::kOperatorCountryKey] = country;
78}
79
80const Stringmap &Cellular::Operator::ToDict() const {
81 return dict_;
82}
83
Chris Masone3bd3c8c2011-06-13 08:20:26 -070084Cellular::Cellular(ControlInterface *control_interface,
85 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080086 Metrics *metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070087 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070088 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070089 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070090 int interface_index,
91 Type type,
92 const string &owner,
Darin Petkov137884a2011-10-26 18:52:47 +020093 const string &path,
94 mobile_provider_db *provider_db)
Chris Masone3bd3c8c2011-06-13 08:20:26 -070095 : Device(control_interface,
96 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080097 metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070098 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070099 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700100 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800101 interface_index,
102 Technology::kCellular),
Darin Petkove9d12e02011-07-27 15:09:37 -0700103 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700104 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700105 dbus_owner_(owner),
106 dbus_path_(path),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500107 provider_db_(provider_db) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700108 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700109 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
110 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400111 HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
112 &Cellular::GetTechnologyFamily,
113 NULL);
Paul Stewartac4ac002011-08-26 12:04:26 -0700114 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700115 &home_provider_.ToDict());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500116 // For now, only a single capability is supported.
117 InitCapability(type, ProxyFactory::GetInstance());
Chris Masoneb925cc82011-06-22 15:39:57 -0700118
Ben Chanfad4a0b2012-04-18 15:49:59 -0700119 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
120 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700121}
122
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500123Cellular::~Cellular() {
124}
Darin Petkove9d12e02011-07-27 15:09:37 -0700125
Darin Petkovcc044422011-08-17 13:30:06 -0700126// static
127string Cellular::GetStateString(State state) {
128 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700129 case kStateDisabled: return "CellularStateDisabled";
130 case kStateEnabled: return "CellularStateEnabled";
131 case kStateRegistered: return "CellularStateRegistered";
132 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700133 case kStateLinked: return "CellularStateLinked";
134 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700135 }
Darin Petkovcc044422011-08-17 13:30:06 -0700136 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700137}
138
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400139string Cellular::GetTechnologyFamily(Error *error) {
140 return capability_->GetTypeString();
141}
142
Darin Petkov0828f5f2011-08-11 10:18:52 -0700143void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700144 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
145 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700146 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700147}
148
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400149void Cellular::HelpRegisterDerivedString(
150 const string &name,
151 string(Cellular::*get)(Error *),
152 void(Cellular::*set)(const string&, Error *)) {
153 mutable_store()->RegisterDerivedString(
154 name,
155 StringAccessor(new CustomAccessor<Cellular, string>(this, get, set)));
156}
157
Eric Shienbrood9a245532012-03-07 14:20:39 -0500158void Cellular::Start(Error *error,
159 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400160 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700161 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500162 if (state_ != kStateDisabled) {
163 return;
164 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500165 capability_->StartModem(error,
166 Bind(&Cellular::OnModemStarted, this, callback));
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700167}
168
Eric Shienbrood9a245532012-03-07 14:20:39 -0500169void Cellular::Stop(Error *error,
170 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700171 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500172 if (service_) {
173 // TODO(ers): See whether we can/should do DestroyService() here.
174 manager()->DeregisterService(service_);
175 service_ = NULL;
176 }
177 capability_->StopModem(error,
178 Bind(&Cellular::OnModemStopped, this, callback));
179}
180
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400181bool Cellular::IsUnderlyingDeviceEnabled() const {
182 return IsEnabledModemState(modem_state_);
183}
184
185// static
186bool Cellular::IsEnabledModemState(ModemState state) {
187 switch (state) {
188 case kModemStateUnknown:
189 case kModemStateDisabled:
190 case kModemStateInitializing:
191 case kModemStateLocked:
192 case kModemStateDisabling:
193 case kModemStateEnabling:
194 return false;
195 case kModemStateEnabled:
196 case kModemStateSearching:
197 case kModemStateRegistered:
198 case kModemStateDisconnecting:
199 case kModemStateConnecting:
200 case kModemStateConnected:
201 return true;
202 }
203 return false;
204}
205
Eric Shienbrood9a245532012-03-07 14:20:39 -0500206void Cellular::OnModemStarted(const EnabledStateChangedCallback &callback,
207 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700208 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500209 if (state_ == kStateDisabled)
210 SetState(kStateEnabled);
211 callback.Run(error);
212}
213
214void Cellular::OnModemStopped(const EnabledStateChangedCallback &callback,
215 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700216 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500217 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500218 SetState(kStateDisabled);
219 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700220}
221
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500222void Cellular::InitCapability(Type type, ProxyFactory *proxy_factory) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100223 // TODO(petkov): Consider moving capability construction into a factory that's
224 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700225 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100226 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200227 case kTypeGSM:
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500228 capability_.reset(new CellularCapabilityGSM(this, proxy_factory));
Darin Petkovdaf43862011-10-27 11:37:28 +0200229 break;
230 case kTypeCDMA:
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500231 capability_.reset(new CellularCapabilityCDMA(this, proxy_factory));
Darin Petkovdaf43862011-10-27 11:37:28 +0200232 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400233 case kTypeUniversal:
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400234 capability_.reset(new CellularCapabilityUniversal(this, proxy_factory));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400235 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200236 default: NOTREACHED();
237 }
238}
239
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400240void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500241 Error *error, const ResultCallback &callback) {
242 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700243}
244
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500245void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500246 Error *error,
247 const ResultCallback &callback) {
248 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100249}
250
Eric Shienbrood9a245532012-03-07 14:20:39 -0500251void Cellular::RequirePIN(const string &pin, bool require,
252 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700253 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500254 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700255}
256
Eric Shienbrood9a245532012-03-07 14:20:39 -0500257void Cellular::EnterPIN(const string &pin,
258 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700259 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500260 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700261}
262
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100263void Cellular::UnblockPIN(const string &unblock_code,
264 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500265 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700266 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500267 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700268}
269
Eric Shienbrood9a245532012-03-07 14:20:39 -0500270void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
271 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700272 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500273 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700274}
275
Eric Shienbrood9a245532012-03-07 14:20:39 -0500276void Cellular::Scan(Error *error) {
277 // TODO(ers): for now report immediate success or failure.
278 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700279}
280
Darin Petkovd9661952011-08-03 16:25:42 -0700281void Cellular::HandleNewRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700282 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Darin Petkovb72cf402011-11-22 14:51:39 +0100283 if (!capability_->IsRegistered()) {
Darin Petkov2c377382012-01-11 11:40:43 +0100284 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700285 if (state_ == kStateLinked ||
286 state_ == kStateConnected ||
287 state_ == kStateRegistered) {
288 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700289 }
290 return;
291 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500292 // In Disabled state, defer creating a service until fully
293 // enabled. UI will ignore the appearance of a new service
294 // on a disabled device.
295 if (state_ == kStateDisabled) {
296 return;
297 }
Darin Petkovd9661952011-08-03 16:25:42 -0700298 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700299 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700300 }
301 if (!service_.get()) {
Darin Petkovd9661952011-08-03 16:25:42 -0700302 CreateService();
303 }
Darin Petkov3e509242011-11-10 14:46:44 +0100304 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500305 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
306 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100307 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
308 service_->SetRoamingState(capability_->GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700309}
310
Darin Petkovd9661952011-08-03 16:25:42 -0700311void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700312 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100313 if (service_) {
314 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700315 }
316}
317
318void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700319 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700320 CHECK(!service_.get());
321 service_ =
Thieu Le3426c8f2012-01-11 17:35:11 -0800322 new CellularService(control_interface(), dispatcher(), metrics(),
323 manager(), this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100324 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100325 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700326}
327
Darin Petkov2c377382012-01-11 11:40:43 +0100328void Cellular::DestroyService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700329 SLOG(Cellular, 2) << __func__;
Darin Petkov2c377382012-01-11 11:40:43 +0100330 DestroyIPConfig();
331 if (service_) {
332 manager()->DeregisterService(service_);
333 service_ = NULL;
334 }
335 SelectService(NULL);
336}
337
Paul Stewartfdd16072011-09-16 12:41:35 -0700338bool Cellular::TechnologyIs(const Technology::Identifier type) const {
339 return type == Technology::kCellular;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700340}
341
Darin Petkov4d6d9412011-08-24 13:19:54 -0700342void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700343 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400344 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700345 Error::PopulateAndLog(error, Error::kAlreadyConnected,
346 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700347 return;
348 }
349 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700350
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400351 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700352 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700353 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
354 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700355 return;
356 }
357
Darin Petkovc5f56562011-08-06 16:40:05 -0700358 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100359 capability_->SetupConnectProperties(&properties);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400360 // TODO(njw): Should a weak pointer be used here instead?
Nathan Williams3022be52012-04-19 17:40:49 -0400361 // Would require something like a WeakPtrFactory on the class.
Nathan Williamsb54974f2012-04-19 11:16:30 -0400362 ResultCallback cb = Bind(&Cellular::OnConnectReply, this);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400363 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400364 capability_->Connect(properties, error, cb);
365}
366
367// Note that there's no ResultCallback argument to this,
368// since Connect() isn't yet passed one.
369void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700370 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400371 if (error.IsSuccess())
372 OnConnected();
373 else
374 OnConnectFailed(error);
Darin Petkovc5f56562011-08-06 16:40:05 -0700375}
376
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400377void Cellular::OnConnecting() {
378 if (service_)
379 service_->SetState(Service::kStateAssociating);
380}
381
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500382void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700383 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400384 if (state_ == kStateConnected || state_ == kStateLinked) {
385 VLOG(2) << "Already connected";
386 return;
387 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700388 SetState(kStateConnected);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400389 if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100390 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
391 Disconnect(NULL);
392 } else {
393 EstablishLink();
394 }
Darin Petkovbac96002011-08-09 13:22:00 -0700395}
396
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400397void Cellular::OnConnectFailed(const Error &error) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400398 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500399}
400
Darin Petkovfb0625e2012-01-16 13:05:56 +0100401void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700402 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500403 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100404 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500405 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100406 return;
407 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400408 // TODO(njw): See Connect() about possible weak ptr for 'this'.
409 ResultCallback cb = Bind(&Cellular::OnDisconnectReply, this);
410 capability_->Disconnect(error, cb);
411}
412
413// Note that there's no ResultCallback argument to this,
414// since Disconnect() isn't yet passed one.
415void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700416 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400417 if (error.IsSuccess())
418 OnDisconnected();
419 else
420 OnDisconnectFailed();
Darin Petkovfb0625e2012-01-16 13:05:56 +0100421}
422
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500423void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700424 SLOG(Cellular, 2) << __func__;
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400425 if (state_ == kStateConnected || state_ == kStateLinked) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500426 SetState(kStateRegistered);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400427 SetServiceFailureSilent(Service::kFailureUnknown);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400428 DestroyIPConfig();
429 rtnl_handler()->SetInterfaceFlags(interface_index(), 0, IFF_UP);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400430 } else {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500431 LOG(WARNING) << "Disconnect occurred while in state "
432 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400433 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500434}
435
436void Cellular::OnDisconnectFailed() {
437 // TODO(ers): Signal failure.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100438}
439
Darin Petkovbac96002011-08-09 13:22:00 -0700440void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700441 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700442 CHECK_EQ(kStateConnected, state_);
443 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700444 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700445 (flags & IFF_UP) != 0) {
446 LinkEvent(flags, IFF_UP);
447 return;
448 }
449 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700450 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700451}
452
453void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
454 Device::LinkEvent(flags, change);
455 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700456 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700457 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800458 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700459 SelectService(service_);
460 SetServiceState(Service::kStateConfiguring);
461 } else {
462 LOG(ERROR) << "Unable to acquire DHCP config.";
463 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700464 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
465 SetState(kStateConnected);
Darin Petkov2c377382012-01-11 11:40:43 +0100466 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700467 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700468}
469
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400470void Cellular::OnDBusPropertiesChanged(
471 const string &interface,
472 const DBusPropertiesMap &changed_properties,
473 const vector<string> &invalidated_properties) {
474 capability_->OnDBusPropertiesChanged(interface,
475 changed_properties,
476 invalidated_properties);
477}
478
Darin Petkovae0c64e2011-11-15 15:50:27 +0100479void Cellular::set_home_provider(const Operator &oper) {
480 home_provider_.CopyFrom(oper);
481}
482
Darin Petkovac635a82012-01-10 16:51:58 +0100483string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700484 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100485 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
486}
487
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400488void Cellular::OnModemStateChanged(ModemState old_state,
489 ModemState new_state,
490 uint32 /*reason*/) {
491 if (old_state == new_state) {
492 return;
493 }
494 set_modem_state(new_state);
495 switch (new_state) {
496 case kModemStateDisabled:
497 SetEnabled(false);
498 break;
499 case kModemStateEnabled:
500 case kModemStateSearching:
501 // Note: we only handle changes to Enabled from the Registered
502 // state here. Changes from Disabled to Enabled are handled in
503 // the DBusPropertiesChanged handler.
504 if (old_state == kModemStateRegistered) {
505 capability_->SetUnregistered(new_state == kModemStateSearching);
506 HandleNewRegistrationState();
507 }
508 case kModemStateRegistered:
509 if (old_state == kModemStateConnected ||
510 old_state == kModemStateConnecting ||
511 old_state == kModemStateDisconnecting)
512 OnDisconnected();
513 break;
514 case kModemStateConnecting:
515 OnConnecting();
516 break;
517 case kModemStateConnected:
518 OnConnected();
519 break;
520 default:
521 break;
522 }
523}
524
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700525} // namespace shill