blob: 55675dc8c49d931cb792a4dbab6610c5945e9d16 [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"
Jason Glasgow7b461df2012-05-01 16:38:45 -040036#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080037#include "shill/technology.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070038
Eric Shienbrood3e20a232012-02-16 11:35:56 -050039using base::Bind;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070040using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070041using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070042
43namespace shill {
44
Jason Glasgow7b461df2012-05-01 16:38:45 -040045// static
46const char Cellular::kAllowRoaming[] = "AllowRoaming";
47
Darin Petkov3335b372011-08-22 11:05:32 -070048Cellular::Operator::Operator() {
49 SetName("");
50 SetCode("");
51 SetCountry("");
52}
53
54Cellular::Operator::~Operator() {}
55
56void Cellular::Operator::CopyFrom(const Operator &oper) {
57 dict_ = oper.dict_;
58}
59
60const string &Cellular::Operator::GetName() const {
61 return dict_.find(flimflam::kOperatorNameKey)->second;
62}
63
64void Cellular::Operator::SetName(const string &name) {
65 dict_[flimflam::kOperatorNameKey] = name;
66}
67
68const string &Cellular::Operator::GetCode() const {
69 return dict_.find(flimflam::kOperatorCodeKey)->second;
70}
71
72void Cellular::Operator::SetCode(const string &code) {
73 dict_[flimflam::kOperatorCodeKey] = code;
74}
75
76const string &Cellular::Operator::GetCountry() const {
77 return dict_.find(flimflam::kOperatorCountryKey)->second;
78}
79
80void Cellular::Operator::SetCountry(const string &country) {
81 dict_[flimflam::kOperatorCountryKey] = country;
82}
83
84const Stringmap &Cellular::Operator::ToDict() const {
85 return dict_;
86}
87
Chris Masone3bd3c8c2011-06-13 08:20:26 -070088Cellular::Cellular(ControlInterface *control_interface,
89 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080090 Metrics *metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070091 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070092 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070093 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070094 int interface_index,
95 Type type,
96 const string &owner,
Darin Petkov137884a2011-10-26 18:52:47 +020097 const string &path,
98 mobile_provider_db *provider_db)
Chris Masone3bd3c8c2011-06-13 08:20:26 -070099 : Device(control_interface,
100 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -0800101 metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700102 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700103 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700104 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800105 interface_index,
106 Technology::kCellular),
Darin Petkove9d12e02011-07-27 15:09:37 -0700107 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700108 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700109 dbus_owner_(owner),
110 dbus_path_(path),
Jason Glasgow7b461df2012-05-01 16:38:45 -0400111 provider_db_(provider_db),
112 allow_roaming_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700113 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700114 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
115 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400116 HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
117 &Cellular::GetTechnologyFamily,
118 NULL);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400119 HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
120 &Cellular::GetAllowRoaming,
121 &Cellular::SetAllowRoaming);
Paul Stewartac4ac002011-08-26 12:04:26 -0700122 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700123 &home_provider_.ToDict());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500124 // For now, only a single capability is supported.
125 InitCapability(type, ProxyFactory::GetInstance());
Chris Masoneb925cc82011-06-22 15:39:57 -0700126
Ben Chanfad4a0b2012-04-18 15:49:59 -0700127 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
128 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700129}
130
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500131Cellular::~Cellular() {
132}
Darin Petkove9d12e02011-07-27 15:09:37 -0700133
Jason Glasgow7b461df2012-05-01 16:38:45 -0400134bool Cellular::Load(StoreInterface *storage) {
135 const string id = GetStorageIdentifier();
136 if (!storage->ContainsGroup(id)) {
137 LOG(WARNING) << "Device is not available in the persistent store: " << id;
138 return false;
139 }
140 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
141 return Device::Load(storage);
142}
143
144bool Cellular::Save(StoreInterface *storage) {
145 const string id = GetStorageIdentifier();
146 storage->SetBool(id, kAllowRoaming, allow_roaming_);
147 return Device::Save(storage);
148}
149
Darin Petkovcc044422011-08-17 13:30:06 -0700150// static
151string Cellular::GetStateString(State state) {
152 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700153 case kStateDisabled: return "CellularStateDisabled";
154 case kStateEnabled: return "CellularStateEnabled";
155 case kStateRegistered: return "CellularStateRegistered";
156 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700157 case kStateLinked: return "CellularStateLinked";
158 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700159 }
Darin Petkovcc044422011-08-17 13:30:06 -0700160 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700161}
162
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400163string Cellular::GetTechnologyFamily(Error *error) {
164 return capability_->GetTypeString();
165}
166
Darin Petkov0828f5f2011-08-11 10:18:52 -0700167void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700168 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
169 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700170 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700171}
172
Jason Glasgow7b461df2012-05-01 16:38:45 -0400173void Cellular::HelpRegisterDerivedBool(
174 const string &name,
175 bool(Cellular::*get)(Error *error),
176 void(Cellular::*set)(const bool &value, Error *error)) {
177 mutable_store()->RegisterDerivedBool(
178 name,
179 BoolAccessor(
180 new CustomAccessor<Cellular, bool>(this, get, set)));
181}
182
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400183void Cellular::HelpRegisterDerivedString(
184 const string &name,
185 string(Cellular::*get)(Error *),
186 void(Cellular::*set)(const string&, Error *)) {
187 mutable_store()->RegisterDerivedString(
188 name,
189 StringAccessor(new CustomAccessor<Cellular, string>(this, get, set)));
190}
191
Eric Shienbrood9a245532012-03-07 14:20:39 -0500192void Cellular::Start(Error *error,
193 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400194 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700195 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500196 if (state_ != kStateDisabled) {
197 return;
198 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500199 capability_->StartModem(error,
200 Bind(&Cellular::OnModemStarted, this, callback));
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700201}
202
Eric Shienbrood9a245532012-03-07 14:20:39 -0500203void Cellular::Stop(Error *error,
204 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700205 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500206 if (service_) {
207 // TODO(ers): See whether we can/should do DestroyService() here.
208 manager()->DeregisterService(service_);
209 service_ = NULL;
210 }
211 capability_->StopModem(error,
212 Bind(&Cellular::OnModemStopped, this, callback));
213}
214
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400215bool Cellular::IsUnderlyingDeviceEnabled() const {
216 return IsEnabledModemState(modem_state_);
217}
218
219// static
220bool Cellular::IsEnabledModemState(ModemState state) {
221 switch (state) {
222 case kModemStateUnknown:
223 case kModemStateDisabled:
224 case kModemStateInitializing:
225 case kModemStateLocked:
226 case kModemStateDisabling:
227 case kModemStateEnabling:
228 return false;
229 case kModemStateEnabled:
230 case kModemStateSearching:
231 case kModemStateRegistered:
232 case kModemStateDisconnecting:
233 case kModemStateConnecting:
234 case kModemStateConnected:
235 return true;
236 }
237 return false;
238}
239
Eric Shienbrood9a245532012-03-07 14:20:39 -0500240void Cellular::OnModemStarted(const EnabledStateChangedCallback &callback,
241 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700242 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700243 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500244 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400245 // Registration state updates may have been ignored while the
246 // modem was not yet marked enabled.
247 HandleNewRegistrationState();
248 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500249 callback.Run(error);
250}
251
252void Cellular::OnModemStopped(const EnabledStateChangedCallback &callback,
253 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700254 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500255 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500256 SetState(kStateDisabled);
257 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700258}
259
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500260void Cellular::InitCapability(Type type, ProxyFactory *proxy_factory) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100261 // TODO(petkov): Consider moving capability construction into a factory that's
262 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700263 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100264 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200265 case kTypeGSM:
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500266 capability_.reset(new CellularCapabilityGSM(this, proxy_factory));
Darin Petkovdaf43862011-10-27 11:37:28 +0200267 break;
268 case kTypeCDMA:
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500269 capability_.reset(new CellularCapabilityCDMA(this, proxy_factory));
Darin Petkovdaf43862011-10-27 11:37:28 +0200270 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400271 case kTypeUniversal:
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400272 capability_.reset(new CellularCapabilityUniversal(this, proxy_factory));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400273 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200274 default: NOTREACHED();
275 }
276}
277
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400278void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500279 Error *error, const ResultCallback &callback) {
280 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700281}
282
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500283void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500284 Error *error,
285 const ResultCallback &callback) {
286 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100287}
288
Eric Shienbrood9a245532012-03-07 14:20:39 -0500289void Cellular::RequirePIN(const string &pin, bool require,
290 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700291 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500292 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700293}
294
Eric Shienbrood9a245532012-03-07 14:20:39 -0500295void Cellular::EnterPIN(const string &pin,
296 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700297 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500298 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700299}
300
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100301void Cellular::UnblockPIN(const string &unblock_code,
302 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500303 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700304 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500305 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700306}
307
Eric Shienbrood9a245532012-03-07 14:20:39 -0500308void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
309 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700310 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500311 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700312}
313
Eric Shienbrood9a245532012-03-07 14:20:39 -0500314void Cellular::Scan(Error *error) {
315 // TODO(ers): for now report immediate success or failure.
316 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700317}
318
Darin Petkovd9661952011-08-03 16:25:42 -0700319void Cellular::HandleNewRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700320 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Darin Petkovb72cf402011-11-22 14:51:39 +0100321 if (!capability_->IsRegistered()) {
Darin Petkov2c377382012-01-11 11:40:43 +0100322 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700323 if (state_ == kStateLinked ||
324 state_ == kStateConnected ||
325 state_ == kStateRegistered) {
326 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700327 }
328 return;
329 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500330 // In Disabled state, defer creating a service until fully
331 // enabled. UI will ignore the appearance of a new service
332 // on a disabled device.
333 if (state_ == kStateDisabled) {
334 return;
335 }
Darin Petkovd9661952011-08-03 16:25:42 -0700336 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700337 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700338 }
339 if (!service_.get()) {
Darin Petkovd9661952011-08-03 16:25:42 -0700340 CreateService();
341 }
Darin Petkov3e509242011-11-10 14:46:44 +0100342 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500343 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
344 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100345 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
346 service_->SetRoamingState(capability_->GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700347}
348
Darin Petkovd9661952011-08-03 16:25:42 -0700349void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700350 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100351 if (service_) {
352 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700353 }
354}
355
356void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700357 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700358 CHECK(!service_.get());
359 service_ =
Thieu Le3426c8f2012-01-11 17:35:11 -0800360 new CellularService(control_interface(), dispatcher(), metrics(),
361 manager(), this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100362 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100363 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700364}
365
Darin Petkov2c377382012-01-11 11:40:43 +0100366void Cellular::DestroyService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700367 SLOG(Cellular, 2) << __func__;
Darin Petkov2c377382012-01-11 11:40:43 +0100368 DestroyIPConfig();
369 if (service_) {
370 manager()->DeregisterService(service_);
371 service_ = NULL;
372 }
373 SelectService(NULL);
374}
375
Paul Stewartfdd16072011-09-16 12:41:35 -0700376bool Cellular::TechnologyIs(const Technology::Identifier type) const {
377 return type == Technology::kCellular;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700378}
379
Darin Petkov4d6d9412011-08-24 13:19:54 -0700380void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700381 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400382 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700383 Error::PopulateAndLog(error, Error::kAlreadyConnected,
384 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700385 return;
386 }
387 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700388
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400389 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700390 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700391 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
392 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700393 return;
394 }
395
Darin Petkovc5f56562011-08-06 16:40:05 -0700396 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100397 capability_->SetupConnectProperties(&properties);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400398 // TODO(njw): Should a weak pointer be used here instead?
Nathan Williams3022be52012-04-19 17:40:49 -0400399 // Would require something like a WeakPtrFactory on the class.
Nathan Williamsb54974f2012-04-19 11:16:30 -0400400 ResultCallback cb = Bind(&Cellular::OnConnectReply, this);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400401 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400402 capability_->Connect(properties, error, cb);
403}
404
405// Note that there's no ResultCallback argument to this,
406// since Connect() isn't yet passed one.
407void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700408 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400409 if (error.IsSuccess())
410 OnConnected();
411 else
412 OnConnectFailed(error);
Darin Petkovc5f56562011-08-06 16:40:05 -0700413}
414
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400415void Cellular::OnConnecting() {
416 if (service_)
417 service_->SetState(Service::kStateAssociating);
418}
419
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500420void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700421 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400422 if (state_ == kStateConnected || state_ == kStateLinked) {
423 VLOG(2) << "Already connected";
424 return;
425 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700426 SetState(kStateConnected);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400427 if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100428 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
429 Disconnect(NULL);
430 } else {
431 EstablishLink();
432 }
Darin Petkovbac96002011-08-09 13:22:00 -0700433}
434
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400435void Cellular::OnConnectFailed(const Error &error) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400436 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500437}
438
Darin Petkovfb0625e2012-01-16 13:05:56 +0100439void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700440 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500441 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100442 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500443 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100444 return;
445 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400446 // TODO(njw): See Connect() about possible weak ptr for 'this'.
447 ResultCallback cb = Bind(&Cellular::OnDisconnectReply, this);
448 capability_->Disconnect(error, cb);
449}
450
451// Note that there's no ResultCallback argument to this,
452// since Disconnect() isn't yet passed one.
453void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700454 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400455 if (error.IsSuccess())
456 OnDisconnected();
457 else
458 OnDisconnectFailed();
Darin Petkovfb0625e2012-01-16 13:05:56 +0100459}
460
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500461void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700462 SLOG(Cellular, 2) << __func__;
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400463 if (state_ == kStateConnected || state_ == kStateLinked) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500464 SetState(kStateRegistered);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400465 SetServiceFailureSilent(Service::kFailureUnknown);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400466 DestroyIPConfig();
467 rtnl_handler()->SetInterfaceFlags(interface_index(), 0, IFF_UP);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400468 } else {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500469 LOG(WARNING) << "Disconnect occurred while in state "
470 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400471 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500472}
473
474void Cellular::OnDisconnectFailed() {
475 // TODO(ers): Signal failure.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100476}
477
Darin Petkovbac96002011-08-09 13:22:00 -0700478void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700479 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700480 CHECK_EQ(kStateConnected, state_);
481 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700482 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700483 (flags & IFF_UP) != 0) {
484 LinkEvent(flags, IFF_UP);
485 return;
486 }
487 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700488 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700489}
490
491void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
492 Device::LinkEvent(flags, change);
493 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700494 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700495 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800496 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700497 SelectService(service_);
498 SetServiceState(Service::kStateConfiguring);
499 } else {
500 LOG(ERROR) << "Unable to acquire DHCP config.";
501 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700502 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
503 SetState(kStateConnected);
Darin Petkov2c377382012-01-11 11:40:43 +0100504 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700505 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700506}
507
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400508void Cellular::OnDBusPropertiesChanged(
509 const string &interface,
510 const DBusPropertiesMap &changed_properties,
511 const vector<string> &invalidated_properties) {
512 capability_->OnDBusPropertiesChanged(interface,
513 changed_properties,
514 invalidated_properties);
515}
516
Darin Petkovae0c64e2011-11-15 15:50:27 +0100517void Cellular::set_home_provider(const Operator &oper) {
518 home_provider_.CopyFrom(oper);
519}
520
Darin Petkovac635a82012-01-10 16:51:58 +0100521string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700522 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100523 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
524}
525
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400526void Cellular::OnModemStateChanged(ModemState old_state,
527 ModemState new_state,
528 uint32 /*reason*/) {
529 if (old_state == new_state) {
530 return;
531 }
532 set_modem_state(new_state);
533 switch (new_state) {
534 case kModemStateDisabled:
535 SetEnabled(false);
536 break;
537 case kModemStateEnabled:
538 case kModemStateSearching:
539 // Note: we only handle changes to Enabled from the Registered
540 // state here. Changes from Disabled to Enabled are handled in
541 // the DBusPropertiesChanged handler.
542 if (old_state == kModemStateRegistered) {
543 capability_->SetUnregistered(new_state == kModemStateSearching);
544 HandleNewRegistrationState();
545 }
546 case kModemStateRegistered:
547 if (old_state == kModemStateConnected ||
548 old_state == kModemStateConnecting ||
549 old_state == kModemStateDisconnecting)
550 OnDisconnected();
551 break;
552 case kModemStateConnecting:
553 OnConnecting();
554 break;
555 case kModemStateConnected:
556 OnConnected();
557 break;
558 default:
559 break;
560 }
561}
562
Jason Glasgow7b461df2012-05-01 16:38:45 -0400563void Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
564 SLOG(Cellular, 2) << __func__
565 << "(" << allow_roaming_ << "->" << value << ")";
566 if (allow_roaming_ == value) {
567 return;
568 }
569 allow_roaming_ = value;
570 manager()->SaveActiveProfile();
571
572 // Use AllowRoaming() instead of allow_roaming_ in order to
573 // incorporate provider preferences when evaluating if a disconnect
574 // is required.
575 if (!capability_->AllowRoaming() &&
576 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
577 Error error;
578 Disconnect(&error);
579 }
580 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
581}
582
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700583} // namespace shill