blob: 55dd803dd85ee2f94379b7de0bc49bba1ec28d1e [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>
Gary Moraina9fb3252012-05-31 12:05:31 -070015#include <base/callback.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"
Christopher Wileyb691efd2012-08-09 13:51:51 -070030#include "shill/logging.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070031#include "shill/manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070032#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070033#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070034#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070035#include "shill/rtnl_handler.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;
Gary Moraina9fb3252012-05-31 12:05:31 -070040using base::Closure;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070041using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070042using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070043
44namespace shill {
45
Jason Glasgow7b461df2012-05-01 16:38:45 -040046// static
47const char Cellular::kAllowRoaming[] = "AllowRoaming";
48
Darin Petkov3335b372011-08-22 11:05:32 -070049Cellular::Operator::Operator() {
50 SetName("");
51 SetCode("");
52 SetCountry("");
53}
54
55Cellular::Operator::~Operator() {}
56
57void Cellular::Operator::CopyFrom(const Operator &oper) {
58 dict_ = oper.dict_;
59}
60
61const string &Cellular::Operator::GetName() const {
62 return dict_.find(flimflam::kOperatorNameKey)->second;
63}
64
65void Cellular::Operator::SetName(const string &name) {
66 dict_[flimflam::kOperatorNameKey] = name;
67}
68
69const string &Cellular::Operator::GetCode() const {
70 return dict_.find(flimflam::kOperatorCodeKey)->second;
71}
72
73void Cellular::Operator::SetCode(const string &code) {
74 dict_[flimflam::kOperatorCodeKey] = code;
75}
76
77const string &Cellular::Operator::GetCountry() const {
78 return dict_.find(flimflam::kOperatorCountryKey)->second;
79}
80
81void Cellular::Operator::SetCountry(const string &country) {
82 dict_[flimflam::kOperatorCountryKey] = country;
83}
84
85const Stringmap &Cellular::Operator::ToDict() const {
86 return dict_;
87}
88
Chris Masone3bd3c8c2011-06-13 08:20:26 -070089Cellular::Cellular(ControlInterface *control_interface,
90 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080091 Metrics *metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070092 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070093 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070094 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070095 int interface_index,
96 Type type,
97 const string &owner,
Jason Glasgowa585fc32012-06-06 11:04:09 -040098 const string &service,
Darin Petkov137884a2011-10-26 18:52:47 +020099 const string &path,
Ben Chan62028b22012-11-05 11:20:02 -0800100 CellularOperatorInfo *cellular_operator_info,
Ben Chan3ecdf822012-08-06 12:29:23 -0700101 mobile_provider_db *provider_db,
102 ProxyFactory *proxy_factory)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700103 : Device(control_interface,
104 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -0800105 metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700106 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700107 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700108 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800109 interface_index,
110 Technology::kCellular),
Thieu Le64b0fe52012-08-08 14:57:36 -0700111 weak_ptr_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700112 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700113 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700114 dbus_owner_(owner),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400115 dbus_service_(service),
Darin Petkove9d12e02011-07-27 15:09:37 -0700116 dbus_path_(path),
Ben Chan62028b22012-11-05 11:20:02 -0800117 cellular_operator_info_(cellular_operator_info),
Jason Glasgow7b461df2012-05-01 16:38:45 -0400118 provider_db_(provider_db),
Ben Chan3ecdf822012-08-06 12:29:23 -0700119 proxy_factory_(proxy_factory),
Jason Glasgow7b461df2012-05-01 16:38:45 -0400120 allow_roaming_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700121 PropertyStore *store = this->mutable_store();
Jason Glasgowa585fc32012-06-06 11:04:09 -0400122 // TODO(jglasgow): kDBusConnectionProperty is deprecated.
Paul Stewartac4ac002011-08-26 12:04:26 -0700123 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
Jason Glasgowa585fc32012-06-06 11:04:09 -0400124 store->RegisterConstString(flimflam::kDBusServiceProperty, &dbus_service_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700125 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400126 HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
127 &Cellular::GetTechnologyFamily,
128 NULL);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400129 HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
130 &Cellular::GetAllowRoaming,
131 &Cellular::SetAllowRoaming);
Paul Stewartac4ac002011-08-26 12:04:26 -0700132 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700133 &home_provider_.ToDict());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500134 // For now, only a single capability is supported.
Ben Chan3ecdf822012-08-06 12:29:23 -0700135 InitCapability(type);
Chris Masoneb925cc82011-06-22 15:39:57 -0700136
Ben Chanfad4a0b2012-04-18 15:49:59 -0700137 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
138 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700139}
140
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500141Cellular::~Cellular() {
142}
Darin Petkove9d12e02011-07-27 15:09:37 -0700143
Jason Glasgow7b461df2012-05-01 16:38:45 -0400144bool Cellular::Load(StoreInterface *storage) {
145 const string id = GetStorageIdentifier();
146 if (!storage->ContainsGroup(id)) {
147 LOG(WARNING) << "Device is not available in the persistent store: " << id;
148 return false;
149 }
150 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
151 return Device::Load(storage);
152}
153
154bool Cellular::Save(StoreInterface *storage) {
155 const string id = GetStorageIdentifier();
156 storage->SetBool(id, kAllowRoaming, allow_roaming_);
157 return Device::Save(storage);
158}
159
Darin Petkovcc044422011-08-17 13:30:06 -0700160// static
161string Cellular::GetStateString(State state) {
162 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700163 case kStateDisabled: return "CellularStateDisabled";
164 case kStateEnabled: return "CellularStateEnabled";
165 case kStateRegistered: return "CellularStateRegistered";
166 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700167 case kStateLinked: return "CellularStateLinked";
168 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700169 }
Darin Petkovcc044422011-08-17 13:30:06 -0700170 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700171}
172
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400173string Cellular::GetTechnologyFamily(Error *error) {
174 return capability_->GetTypeString();
175}
176
Darin Petkov0828f5f2011-08-11 10:18:52 -0700177void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700178 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
179 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700180 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700181}
182
Jason Glasgow7b461df2012-05-01 16:38:45 -0400183void Cellular::HelpRegisterDerivedBool(
184 const string &name,
185 bool(Cellular::*get)(Error *error),
186 void(Cellular::*set)(const bool &value, Error *error)) {
187 mutable_store()->RegisterDerivedBool(
188 name,
189 BoolAccessor(
190 new CustomAccessor<Cellular, bool>(this, get, set)));
191}
192
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400193void Cellular::HelpRegisterDerivedString(
194 const string &name,
195 string(Cellular::*get)(Error *),
196 void(Cellular::*set)(const string&, Error *)) {
197 mutable_store()->RegisterDerivedString(
198 name,
199 StringAccessor(new CustomAccessor<Cellular, string>(this, get, set)));
200}
201
Eric Shienbrood9a245532012-03-07 14:20:39 -0500202void Cellular::Start(Error *error,
203 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400204 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700205 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500206 if (state_ != kStateDisabled) {
207 return;
208 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700209 ResultCallback cb = Bind(&Cellular::StartModemCallback,
210 weak_ptr_factory_.GetWeakPtr(),
211 callback);
212 capability_->StartModem(error, cb);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700213}
214
Eric Shienbrood9a245532012-03-07 14:20:39 -0500215void Cellular::Stop(Error *error,
216 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700217 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le64b0fe52012-08-08 14:57:36 -0700218 ResultCallback cb = Bind(&Cellular::StopModemCallback,
219 weak_ptr_factory_.GetWeakPtr(),
220 callback);
221 capability_->StopModem(error, cb);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500222}
223
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400224bool Cellular::IsUnderlyingDeviceEnabled() const {
225 return IsEnabledModemState(modem_state_);
226}
227
Thieu Led0012052012-07-25 16:09:09 -0700228bool Cellular::IsModemRegistered() const {
229 return (modem_state_ == Cellular::kModemStateRegistered ||
230 modem_state_ == Cellular::kModemStateConnecting ||
231 modem_state_ == Cellular::kModemStateConnected);
232}
233
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400234// static
235bool Cellular::IsEnabledModemState(ModemState state) {
236 switch (state) {
237 case kModemStateUnknown:
238 case kModemStateDisabled:
239 case kModemStateInitializing:
240 case kModemStateLocked:
241 case kModemStateDisabling:
242 case kModemStateEnabling:
243 return false;
244 case kModemStateEnabled:
245 case kModemStateSearching:
246 case kModemStateRegistered:
247 case kModemStateDisconnecting:
248 case kModemStateConnecting:
249 case kModemStateConnected:
250 return true;
251 }
252 return false;
253}
254
Thieu Le37b90032012-05-15 15:18:41 -0700255void Cellular::StartModemCallback(const EnabledStateChangedCallback &callback,
256 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700257 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700258 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500259 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400260 // Registration state updates may have been ignored while the
261 // modem was not yet marked enabled.
262 HandleNewRegistrationState();
263 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500264 callback.Run(error);
265}
266
Thieu Le37b90032012-05-15 15:18:41 -0700267void Cellular::StopModemCallback(const EnabledStateChangedCallback &callback,
268 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700269 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le37b90032012-05-15 15:18:41 -0700270 // Destroy the cellular service regardless of any errors that occur during
271 // the stop process since we do not know the state of the modem at this
272 // point.
273 DestroyService();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500274 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500275 SetState(kStateDisabled);
276 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700277}
278
Ben Chan3ecdf822012-08-06 12:29:23 -0700279void Cellular::InitCapability(Type type) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100280 // TODO(petkov): Consider moving capability construction into a factory that's
281 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700282 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100283 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200284 case kTypeGSM:
Ben Chan3ecdf822012-08-06 12:29:23 -0700285 capability_.reset(new CellularCapabilityGSM(this, proxy_factory_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200286 break;
287 case kTypeCDMA:
Ben Chan3ecdf822012-08-06 12:29:23 -0700288 capability_.reset(new CellularCapabilityCDMA(this, proxy_factory_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200289 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400290 case kTypeUniversal:
Ben Chan3ecdf822012-08-06 12:29:23 -0700291 capability_.reset(new CellularCapabilityUniversal(this, proxy_factory_));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400292 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200293 default: NOTREACHED();
294 }
295}
296
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400297void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500298 Error *error, const ResultCallback &callback) {
299 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700300}
301
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500302void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500303 Error *error,
304 const ResultCallback &callback) {
305 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100306}
307
Eric Shienbrood9a245532012-03-07 14:20:39 -0500308void Cellular::RequirePIN(const string &pin, bool require,
309 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700310 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500311 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700312}
313
Eric Shienbrood9a245532012-03-07 14:20:39 -0500314void Cellular::EnterPIN(const string &pin,
315 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700316 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500317 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700318}
319
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100320void Cellular::UnblockPIN(const string &unblock_code,
321 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500322 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700323 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500324 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700325}
326
Eric Shienbrood9a245532012-03-07 14:20:39 -0500327void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
328 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700329 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500330 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700331}
332
Darin Petkovc37a9c42012-09-06 15:28:22 +0200333void Cellular::SetCarrier(const string &carrier,
334 Error *error, const ResultCallback &callback) {
335 SLOG(Cellular, 2) << __func__ << "(" << carrier << ")";
336 capability_->SetCarrier(carrier, error, callback);
337}
338
Eric Shienbrood9a245532012-03-07 14:20:39 -0500339void Cellular::Scan(Error *error) {
340 // TODO(ers): for now report immediate success or failure.
341 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700342}
343
Darin Petkovd9661952011-08-03 16:25:42 -0700344void Cellular::HandleNewRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700345 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Ben Chan09fa2a02012-11-07 22:09:09 -0800346 if (capability_->IsServiceActivationRequired()) {
347 if (state_ == kStateEnabled && !service_.get()) {
348 CreateService();
349 }
350 return;
351 }
Darin Petkovb72cf402011-11-22 14:51:39 +0100352 if (!capability_->IsRegistered()) {
Darin Petkov2c377382012-01-11 11:40:43 +0100353 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700354 if (state_ == kStateLinked ||
355 state_ == kStateConnected ||
356 state_ == kStateRegistered) {
357 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700358 }
359 return;
360 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500361 // In Disabled state, defer creating a service until fully
362 // enabled. UI will ignore the appearance of a new service
363 // on a disabled device.
364 if (state_ == kStateDisabled) {
365 return;
366 }
Darin Petkovd9661952011-08-03 16:25:42 -0700367 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700368 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700369 }
370 if (!service_.get()) {
Darin Petkovd9661952011-08-03 16:25:42 -0700371 CreateService();
372 }
Darin Petkov3e509242011-11-10 14:46:44 +0100373 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500374 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
375 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100376 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
377 service_->SetRoamingState(capability_->GetRoamingStateString());
Christopher Wiley9169d252012-11-30 15:13:39 -0800378 manager()->UpdateService(service_);
Darin Petkovd9661952011-08-03 16:25:42 -0700379}
380
Darin Petkovd9661952011-08-03 16:25:42 -0700381void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700382 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100383 if (service_) {
384 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700385 }
386}
387
388void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700389 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700390 CHECK(!service_.get());
391 service_ =
Thieu Le3426c8f2012-01-11 17:35:11 -0800392 new CellularService(control_interface(), dispatcher(), metrics(),
393 manager(), this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100394 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100395 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700396}
397
Darin Petkov2c377382012-01-11 11:40:43 +0100398void Cellular::DestroyService() {
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100399 DropConnection();
Darin Petkov2c377382012-01-11 11:40:43 +0100400 if (service_) {
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100401 LOG(INFO) << "Deregistering cellular service " << service_->friendly_name()
402 << " for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100403 manager()->DeregisterService(service_);
404 service_ = NULL;
405 }
Darin Petkov2c377382012-01-11 11:40:43 +0100406}
407
Darin Petkov4d6d9412011-08-24 13:19:54 -0700408void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700409 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400410 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700411 Error::PopulateAndLog(error, Error::kAlreadyConnected,
412 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700413 return;
414 }
415 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700416
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400417 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700418 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700419 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
420 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700421 return;
422 }
423
Darin Petkovc5f56562011-08-06 16:40:05 -0700424 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100425 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700426 ResultCallback cb = Bind(&Cellular::OnConnectReply,
427 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400428 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400429 capability_->Connect(properties, error, cb);
430}
431
432// Note that there's no ResultCallback argument to this,
433// since Connect() isn't yet passed one.
434void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700435 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400436 if (error.IsSuccess())
437 OnConnected();
438 else
439 OnConnectFailed(error);
Darin Petkovc5f56562011-08-06 16:40:05 -0700440}
441
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400442void Cellular::OnConnecting() {
443 if (service_)
444 service_->SetState(Service::kStateAssociating);
445}
446
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500447void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700448 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400449 if (state_ == kStateConnected || state_ == kStateLinked) {
Ben Chan09fa2a02012-11-07 22:09:09 -0800450 SLOG(Cellular, 2) << "Already connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400451 return;
452 }
Darin Petkov1c01bef2012-09-13 15:27:17 +0200453 Closure start_cb = Bind(&Cellular::StartTermination,
454 weak_ptr_factory_.GetWeakPtr());
Gary Moraina9fb3252012-05-31 12:05:31 -0700455 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700456 SetState(kStateConnected);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400457 if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100458 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Arman Uguray539c4232012-09-11 10:00:22 -0700459 LOG(INFO) << "Disconnecting due to roaming.";
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100460 Disconnect(NULL);
461 } else {
462 EstablishLink();
463 }
Darin Petkovbac96002011-08-09 13:22:00 -0700464}
465
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400466void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700467 if (service_)
468 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500469}
470
Christopher Wiley8a468902012-11-30 11:52:38 -0800471void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700472 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500473 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100474 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500475 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100476 return;
477 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700478 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
Christopher Wiley8a468902012-11-30 11:52:38 -0800479 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400480 capability_->Disconnect(error, cb);
481}
482
Christopher Wiley8a468902012-11-30 11:52:38 -0800483void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700484 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400485 if (error.IsSuccess())
486 OnDisconnected();
487 else
488 OnDisconnectFailed();
Gary Moraina9fb3252012-05-31 12:05:31 -0700489 manager()->TerminationActionComplete(FriendlyName());
490 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100491}
492
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500493void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700494 SLOG(Cellular, 2) << __func__;
Arman Uguray539c4232012-09-11 10:00:22 -0700495 if (!DisconnectCleanup()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500496 LOG(WARNING) << "Disconnect occurred while in state "
497 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400498 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500499}
500
501void Cellular::OnDisconnectFailed() {
Arman Uguray539c4232012-09-11 10:00:22 -0700502 SLOG(Cellular, 2) << __func__;
503 // If the modem is in the disconnecting state, then
504 // the disconnect should eventually succeed, so do
505 // nothing.
506 if (modem_state_ == kModemStateDisconnecting) {
507 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
508 return;
509 }
510
511 // OnDisconnectFailed got called because no bearers
512 // to disconnect were found. Which means that we shouldn't
513 // really remain in the connected/linked state if we
514 // are in one of those.
515 if (!DisconnectCleanup()) {
516 // otherwise, no-op
517 LOG(WARNING) << "Ignoring failed disconnect while in state "
518 << GetStateString(state_);
519 }
520
521 // TODO(armansito): In either case, shill ends up thinking
522 // that it's disconnected, while for some reason the underlying
523 // modem might still actually be connected. In that case the UI
524 // would be reflecting an incorrect state and a further connection
525 // request would fail. We should perhaps tear down the modem and
526 // restart it here.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100527}
528
Darin Petkovbac96002011-08-09 13:22:00 -0700529void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700530 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700531 CHECK_EQ(kStateConnected, state_);
532 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700533 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700534 (flags & IFF_UP) != 0) {
535 LinkEvent(flags, IFF_UP);
536 return;
537 }
538 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700539 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Arman Uguray32c76402012-11-27 14:01:13 -0800540
541 // Set state to associating.
542 OnConnecting();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700543}
544
545void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
546 Device::LinkEvent(flags, change);
547 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700548 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700549 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800550 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700551 SelectService(service_);
552 SetServiceState(Service::kStateConfiguring);
553 } else {
554 LOG(ERROR) << "Unable to acquire DHCP config.";
555 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700556 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
Arman Uguray32c76402012-11-27 14:01:13 -0800557 LOG(INFO) << link_name() << " is down.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700558 SetState(kStateConnected);
Arman Uguray32c76402012-11-27 14:01:13 -0800559 DropConnection();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700560 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700561}
562
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400563void Cellular::OnDBusPropertiesChanged(
564 const string &interface,
565 const DBusPropertiesMap &changed_properties,
566 const vector<string> &invalidated_properties) {
567 capability_->OnDBusPropertiesChanged(interface,
568 changed_properties,
569 invalidated_properties);
570}
571
Darin Petkovae0c64e2011-11-15 15:50:27 +0100572void Cellular::set_home_provider(const Operator &oper) {
573 home_provider_.CopyFrom(oper);
574}
575
Darin Petkovac635a82012-01-10 16:51:58 +0100576string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700577 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100578 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
579}
580
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400581void Cellular::OnModemStateChanged(ModemState old_state,
582 ModemState new_state,
583 uint32 /*reason*/) {
584 if (old_state == new_state) {
585 return;
586 }
587 set_modem_state(new_state);
Thieu Le5218cf22012-11-26 11:52:57 -0800588 if (old_state >= kModemStateRegistered &&
589 new_state < kModemStateRegistered) {
590 capability_->SetUnregistered(new_state == kModemStateSearching);
591 HandleNewRegistrationState();
592 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400593 switch (new_state) {
594 case kModemStateDisabled:
595 SetEnabled(false);
596 break;
597 case kModemStateEnabled:
Thieu Le5218cf22012-11-26 11:52:57 -0800598 // Transition from Disabled to Enabled is handled in the
599 // DBusPropertiesChanged handler.
600 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Thieu Led0012052012-07-25 16:09:09 -0700601 // Intentionally falls through.
Thieu Le5218cf22012-11-26 11:52:57 -0800602 case kModemStateSearching:
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400603 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700604 // If the modem state changes from Connecting/Connected/Disconnecting
605 // to Registered/Enabled/Searching, then it's an indication that the
606 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400607 if (old_state == kModemStateConnected ||
608 old_state == kModemStateConnecting ||
609 old_state == kModemStateDisconnecting)
610 OnDisconnected();
611 break;
612 case kModemStateConnecting:
613 OnConnecting();
614 break;
615 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700616 if (old_state == kModemStateConnecting)
617 OnConnected();
618 else
619 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400620 break;
621 default:
622 break;
623 }
624}
625
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800626bool Cellular::IsActivating() const {
627 return capability_->IsActivating();
628}
629
Jason Glasgow7b461df2012-05-01 16:38:45 -0400630void Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
631 SLOG(Cellular, 2) << __func__
632 << "(" << allow_roaming_ << "->" << value << ")";
633 if (allow_roaming_ == value) {
634 return;
635 }
636 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200637 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400638
639 // Use AllowRoaming() instead of allow_roaming_ in order to
640 // incorporate provider preferences when evaluating if a disconnect
641 // is required.
642 if (!capability_->AllowRoaming() &&
643 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
644 Error error;
645 Disconnect(&error);
646 }
647 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
648}
649
Gary Moraina9fb3252012-05-31 12:05:31 -0700650void Cellular::StartTermination() {
Darin Petkov3ec55342012-09-28 14:04:44 +0200651 LOG(INFO) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -0700652 Error error;
653 Disconnect(&error);
654}
655
Arman Uguray539c4232012-09-11 10:00:22 -0700656bool Cellular::DisconnectCleanup() {
Christopher Wiley8a468902012-11-30 11:52:38 -0800657 bool succeeded = false;
Arman Uguray539c4232012-09-11 10:00:22 -0700658 if (state_ == kStateConnected || state_ == kStateLinked) {
659 SetState(kStateRegistered);
660 SetServiceFailureSilent(Service::kFailureUnknown);
661 DestroyIPConfig();
Christopher Wiley8a468902012-11-30 11:52:38 -0800662 succeeded = true;
Arman Uguray539c4232012-09-11 10:00:22 -0700663 }
Christopher Wiley8a468902012-11-30 11:52:38 -0800664 capability_->DisconnectCleanup();
665 return succeeded;
Arman Uguray539c4232012-09-11 10:00:22 -0700666}
Gary Moraina9fb3252012-05-31 12:05:31 -0700667
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700668} // namespace shill