blob: ddb834bc1948216a0942b56b49fe2c064f44f282 [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
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070089Cellular::Cellular(ModemInfo *modem_info,
Darin Petkove9d12e02011-07-27 15:09:37 -070090 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070091 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070092 int interface_index,
93 Type type,
94 const string &owner,
Jason Glasgowa585fc32012-06-06 11:04:09 -040095 const string &service,
Darin Petkov137884a2011-10-26 18:52:47 +020096 const string &path,
Ben Chan3ecdf822012-08-06 12:29:23 -070097 ProxyFactory *proxy_factory)
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070098 : Device(modem_info->control_interface(),
99 modem_info->dispatcher(),
100 modem_info->metrics(),
101 modem_info->manager(),
Darin Petkove9d12e02011-07-27 15:09:37 -0700102 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700103 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800104 interface_index,
105 Technology::kCellular),
Thieu Le64b0fe52012-08-08 14:57:36 -0700106 weak_ptr_factory_(this),
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),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400110 dbus_service_(service),
Darin Petkove9d12e02011-07-27 15:09:37 -0700111 dbus_path_(path),
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700112 modem_info_(modem_info),
Ben Chan3ecdf822012-08-06 12:29:23 -0700113 proxy_factory_(proxy_factory),
Thieu Le26fc01b2013-01-28 12:08:48 -0800114 allow_roaming_(false),
115 explicit_disconnect_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700116 PropertyStore *store = this->mutable_store();
Jason Glasgowa585fc32012-06-06 11:04:09 -0400117 // TODO(jglasgow): kDBusConnectionProperty is deprecated.
Paul Stewartac4ac002011-08-26 12:04:26 -0700118 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
Jason Glasgowa585fc32012-06-06 11:04:09 -0400119 store->RegisterConstString(flimflam::kDBusServiceProperty, &dbus_service_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700120 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400121 HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
122 &Cellular::GetTechnologyFamily,
123 NULL);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400124 HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
125 &Cellular::GetAllowRoaming,
126 &Cellular::SetAllowRoaming);
Paul Stewartac4ac002011-08-26 12:04:26 -0700127 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700128 &home_provider_.ToDict());
Arman Ugurayc7b15602013-02-16 00:56:18 -0800129
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500130 // For now, only a single capability is supported.
Ben Chan3ecdf822012-08-06 12:29:23 -0700131 InitCapability(type);
Chris Masoneb925cc82011-06-22 15:39:57 -0700132
Ben Chanfad4a0b2012-04-18 15:49:59 -0700133 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
134 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700135}
136
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500137Cellular::~Cellular() {
138}
Darin Petkove9d12e02011-07-27 15:09:37 -0700139
Jason Glasgow7b461df2012-05-01 16:38:45 -0400140bool Cellular::Load(StoreInterface *storage) {
141 const string id = GetStorageIdentifier();
142 if (!storage->ContainsGroup(id)) {
143 LOG(WARNING) << "Device is not available in the persistent store: " << id;
144 return false;
145 }
146 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
147 return Device::Load(storage);
148}
149
150bool Cellular::Save(StoreInterface *storage) {
151 const string id = GetStorageIdentifier();
152 storage->SetBool(id, kAllowRoaming, allow_roaming_);
153 return Device::Save(storage);
154}
155
Darin Petkovcc044422011-08-17 13:30:06 -0700156// static
157string Cellular::GetStateString(State state) {
158 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700159 case kStateDisabled: return "CellularStateDisabled";
160 case kStateEnabled: return "CellularStateEnabled";
161 case kStateRegistered: return "CellularStateRegistered";
162 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700163 case kStateLinked: return "CellularStateLinked";
164 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700165 }
Darin Petkovcc044422011-08-17 13:30:06 -0700166 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700167}
168
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400169string Cellular::GetTechnologyFamily(Error *error) {
170 return capability_->GetTypeString();
171}
172
Darin Petkov0828f5f2011-08-11 10:18:52 -0700173void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700174 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
175 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700176 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700177}
178
Jason Glasgow7b461df2012-05-01 16:38:45 -0400179void Cellular::HelpRegisterDerivedBool(
180 const string &name,
181 bool(Cellular::*get)(Error *error),
182 void(Cellular::*set)(const bool &value, Error *error)) {
183 mutable_store()->RegisterDerivedBool(
184 name,
185 BoolAccessor(
186 new CustomAccessor<Cellular, bool>(this, get, set)));
187}
188
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400189void Cellular::HelpRegisterDerivedString(
190 const string &name,
191 string(Cellular::*get)(Error *),
192 void(Cellular::*set)(const string&, Error *)) {
193 mutable_store()->RegisterDerivedString(
194 name,
195 StringAccessor(new CustomAccessor<Cellular, string>(this, get, set)));
196}
197
Eric Shienbrood9a245532012-03-07 14:20:39 -0500198void Cellular::Start(Error *error,
199 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400200 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700201 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500202 if (state_ != kStateDisabled) {
203 return;
204 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700205 ResultCallback cb = Bind(&Cellular::StartModemCallback,
206 weak_ptr_factory_.GetWeakPtr(),
207 callback);
208 capability_->StartModem(error, cb);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700209}
210
Eric Shienbrood9a245532012-03-07 14:20:39 -0500211void Cellular::Stop(Error *error,
212 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700213 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le26fc01b2013-01-28 12:08:48 -0800214 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700215 ResultCallback cb = Bind(&Cellular::StopModemCallback,
216 weak_ptr_factory_.GetWeakPtr(),
217 callback);
218 capability_->StopModem(error, cb);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500219}
220
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400221bool Cellular::IsUnderlyingDeviceEnabled() const {
222 return IsEnabledModemState(modem_state_);
223}
224
Thieu Led0012052012-07-25 16:09:09 -0700225bool Cellular::IsModemRegistered() const {
226 return (modem_state_ == Cellular::kModemStateRegistered ||
227 modem_state_ == Cellular::kModemStateConnecting ||
228 modem_state_ == Cellular::kModemStateConnected);
229}
230
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400231// static
232bool Cellular::IsEnabledModemState(ModemState state) {
233 switch (state) {
234 case kModemStateUnknown:
235 case kModemStateDisabled:
236 case kModemStateInitializing:
237 case kModemStateLocked:
238 case kModemStateDisabling:
239 case kModemStateEnabling:
240 return false;
241 case kModemStateEnabled:
242 case kModemStateSearching:
243 case kModemStateRegistered:
244 case kModemStateDisconnecting:
245 case kModemStateConnecting:
246 case kModemStateConnected:
247 return true;
248 }
249 return false;
250}
251
Thieu Le37b90032012-05-15 15:18:41 -0700252void Cellular::StartModemCallback(const EnabledStateChangedCallback &callback,
253 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700254 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700255 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500256 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400257 // Registration state updates may have been ignored while the
258 // modem was not yet marked enabled.
259 HandleNewRegistrationState();
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700260 if (capability_->ShouldEnableTrafficMonitoring())
261 set_traffic_monitor_enabled(true);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400262 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500263 callback.Run(error);
264}
265
Thieu Le37b90032012-05-15 15:18:41 -0700266void Cellular::StopModemCallback(const EnabledStateChangedCallback &callback,
267 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700268 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le26fc01b2013-01-28 12:08:48 -0800269 explicit_disconnect_ = false;
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);
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700276 set_traffic_monitor_enabled(false);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500277 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700278}
279
Ben Chan3ecdf822012-08-06 12:29:23 -0700280void Cellular::InitCapability(Type type) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100281 // TODO(petkov): Consider moving capability construction into a factory that's
282 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700283 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100284 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200285 case kTypeGSM:
Thieu Lece4483e2013-01-23 15:12:03 -0800286 capability_.reset(new CellularCapabilityGSM(this,
287 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700288 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200289 break;
290 case kTypeCDMA:
Thieu Lece4483e2013-01-23 15:12:03 -0800291 capability_.reset(new CellularCapabilityCDMA(this,
292 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700293 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200294 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400295 case kTypeUniversal:
Arman Ugurayc7b15602013-02-16 00:56:18 -0800296 capability_.reset(new CellularCapabilityUniversal(
297 this,
298 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700299 modem_info_));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400300 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200301 default: NOTREACHED();
302 }
303}
304
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400305void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500306 Error *error, const ResultCallback &callback) {
307 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700308}
309
Arman Ugurayc7b15602013-02-16 00:56:18 -0800310void Cellular::CompleteActivation(Error *error) {
311 capability_->CompleteActivation(error);
312}
313
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500314void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500315 Error *error,
316 const ResultCallback &callback) {
317 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100318}
319
Eric Shienbrood9a245532012-03-07 14:20:39 -0500320void Cellular::RequirePIN(const string &pin, bool require,
321 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700322 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500323 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700324}
325
Eric Shienbrood9a245532012-03-07 14:20:39 -0500326void Cellular::EnterPIN(const string &pin,
327 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700328 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500329 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700330}
331
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100332void Cellular::UnblockPIN(const string &unblock_code,
333 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500334 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700335 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500336 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700337}
338
Eric Shienbrood9a245532012-03-07 14:20:39 -0500339void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
340 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700341 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500342 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700343}
344
Ben Chan5d0d32c2013-01-08 02:05:29 -0800345void Cellular::Reset(Error *error, const ResultCallback &callback) {
346 SLOG(Cellular, 2) << __func__;
347 capability_->Reset(error, callback);
348}
349
Darin Petkovc37a9c42012-09-06 15:28:22 +0200350void Cellular::SetCarrier(const string &carrier,
351 Error *error, const ResultCallback &callback) {
352 SLOG(Cellular, 2) << __func__ << "(" << carrier << ")";
353 capability_->SetCarrier(carrier, error, callback);
354}
355
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700356void Cellular::OnNoNetworkRouting() {
357 SLOG(Cellular, 2) << __func__;
358 Device::OnNoNetworkRouting();
359 // TODO(armansito): Initiate active probing.
360}
361
Wade Guthrie68d41092013-04-02 12:56:02 -0700362void Cellular::Scan(ScanType scan_type, Error *error) {
363 // |scan_type| is ignored because Cellular only does a full scan.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500364 // TODO(ers): for now report immediate success or failure.
365 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700366}
367
Darin Petkovd9661952011-08-03 16:25:42 -0700368void Cellular::HandleNewRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700369 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Ben Chan09fa2a02012-11-07 22:09:09 -0800370 if (capability_->IsServiceActivationRequired()) {
371 if (state_ == kStateEnabled && !service_.get()) {
372 CreateService();
373 }
374 return;
375 }
Darin Petkovb72cf402011-11-22 14:51:39 +0100376 if (!capability_->IsRegistered()) {
Thieu Le26fc01b2013-01-28 12:08:48 -0800377 if (!explicit_disconnect_ &&
378 (state_ == kStateLinked || state_ == kStateConnected) &&
379 service_.get())
380 metrics()->NotifyCellularDeviceDrop(
Thieu Le6c1e3bb2013-02-06 15:20:35 -0800381 interface_index(),
382 capability_->GetNetworkTechnologyString(),
383 service_->strength());
Darin Petkov2c377382012-01-11 11:40:43 +0100384 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700385 if (state_ == kStateLinked ||
386 state_ == kStateConnected ||
387 state_ == kStateRegistered) {
388 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700389 }
390 return;
391 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500392 // In Disabled state, defer creating a service until fully
393 // enabled. UI will ignore the appearance of a new service
394 // on a disabled device.
395 if (state_ == kStateDisabled) {
396 return;
397 }
Darin Petkovd9661952011-08-03 16:25:42 -0700398 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700399 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700400 }
401 if (!service_.get()) {
Thieu Le18c11072013-01-28 17:21:37 -0800402 metrics()->NotifyDeviceScanFinished(interface_index());
Darin Petkovd9661952011-08-03 16:25:42 -0700403 CreateService();
404 }
Darin Petkov3e509242011-11-10 14:46:44 +0100405 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500406 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
407 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100408 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
409 service_->SetRoamingState(capability_->GetRoamingStateString());
Christopher Wiley9169d252012-11-30 15:13:39 -0800410 manager()->UpdateService(service_);
Darin Petkovd9661952011-08-03 16:25:42 -0700411}
412
Darin Petkovd9661952011-08-03 16:25:42 -0700413void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700414 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100415 if (service_) {
416 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700417 }
418}
419
420void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700421 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700422 CHECK(!service_.get());
423 service_ =
Thieu Le3426c8f2012-01-11 17:35:11 -0800424 new CellularService(control_interface(), dispatcher(), metrics(),
425 manager(), this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100426 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100427 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700428}
429
Darin Petkov2c377382012-01-11 11:40:43 +0100430void Cellular::DestroyService() {
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100431 DropConnection();
Darin Petkov2c377382012-01-11 11:40:43 +0100432 if (service_) {
Darin Petkov457728b2013-01-09 09:49:08 +0100433 LOG(INFO) << "Deregistering cellular service " << service_->unique_name()
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100434 << " for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100435 manager()->DeregisterService(service_);
436 service_ = NULL;
437 }
Darin Petkov2c377382012-01-11 11:40:43 +0100438}
439
Darin Petkov4d6d9412011-08-24 13:19:54 -0700440void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700441 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400442 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700443 Error::PopulateAndLog(error, Error::kAlreadyConnected,
444 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700445 return;
Thieu Lec7d8cd12013-02-13 11:38:14 -0800446 } else if (state_ != kStateRegistered) {
447 Error::PopulateAndLog(error, Error::kNotRegistered,
448 "Modem not registered; connection request ignored.");
449 return;
Darin Petkovc5f56562011-08-06 16:40:05 -0700450 }
Darin Petkovd2045802011-08-23 11:09:25 -0700451
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400452 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700453 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700454 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
455 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700456 return;
457 }
458
Darin Petkovc5f56562011-08-06 16:40:05 -0700459 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100460 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700461 ResultCallback cb = Bind(&Cellular::OnConnectReply,
462 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400463 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400464 capability_->Connect(properties, error, cb);
Thieu Le7cf36b02013-01-30 17:15:56 -0800465 if (!error->IsSuccess())
466 return;
467
468 bool is_auto_connecting = service_.get() && service_->is_auto_connecting();
469 metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400470}
471
472// Note that there's no ResultCallback argument to this,
473// since Connect() isn't yet passed one.
474void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700475 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Lecdb5a212013-01-25 11:17:18 -0800476 if (error.IsSuccess()) {
477 metrics()->NotifyDeviceConnectFinished(interface_index());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400478 OnConnected();
Thieu Lecdb5a212013-01-25 11:17:18 -0800479 } else {
Thieu Leb7aa5f72013-01-31 15:57:48 -0800480 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400481 OnConnectFailed(error);
Thieu Lecdb5a212013-01-25 11:17:18 -0800482 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700483}
484
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400485void Cellular::OnConnecting() {
486 if (service_)
487 service_->SetState(Service::kStateAssociating);
488}
489
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500490void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700491 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400492 if (state_ == kStateConnected || state_ == kStateLinked) {
Ben Chan09fa2a02012-11-07 22:09:09 -0800493 SLOG(Cellular, 2) << "Already connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400494 return;
495 }
Darin Petkov1c01bef2012-09-13 15:27:17 +0200496 Closure start_cb = Bind(&Cellular::StartTermination,
497 weak_ptr_factory_.GetWeakPtr());
Gary Moraina9fb3252012-05-31 12:05:31 -0700498 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700499 SetState(kStateConnected);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400500 if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100501 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Arman Uguray539c4232012-09-11 10:00:22 -0700502 LOG(INFO) << "Disconnecting due to roaming.";
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100503 Disconnect(NULL);
504 } else {
505 EstablishLink();
506 }
Darin Petkovbac96002011-08-09 13:22:00 -0700507}
508
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400509void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700510 if (service_)
511 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500512}
513
Christopher Wiley8a468902012-11-30 11:52:38 -0800514void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700515 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500516 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100517 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500518 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100519 return;
520 }
Thieu Le26fc01b2013-01-28 12:08:48 -0800521 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700522 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
Christopher Wiley8a468902012-11-30 11:52:38 -0800523 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400524 capability_->Disconnect(error, cb);
525}
526
Christopher Wiley8a468902012-11-30 11:52:38 -0800527void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700528 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Le26fc01b2013-01-28 12:08:48 -0800529 explicit_disconnect_ = false;
Thieu Leb7aa5f72013-01-31 15:57:48 -0800530 if (error.IsSuccess()) {
Nathan Williamsb54974f2012-04-19 11:16:30 -0400531 OnDisconnected();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800532 } else {
533 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400534 OnDisconnectFailed();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800535 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700536 manager()->TerminationActionComplete(FriendlyName());
537 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100538}
539
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500540void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700541 SLOG(Cellular, 2) << __func__;
Arman Uguray539c4232012-09-11 10:00:22 -0700542 if (!DisconnectCleanup()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500543 LOG(WARNING) << "Disconnect occurred while in state "
544 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400545 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500546}
547
548void Cellular::OnDisconnectFailed() {
Arman Uguray539c4232012-09-11 10:00:22 -0700549 SLOG(Cellular, 2) << __func__;
550 // If the modem is in the disconnecting state, then
551 // the disconnect should eventually succeed, so do
552 // nothing.
553 if (modem_state_ == kModemStateDisconnecting) {
554 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
555 return;
556 }
557
558 // OnDisconnectFailed got called because no bearers
559 // to disconnect were found. Which means that we shouldn't
560 // really remain in the connected/linked state if we
561 // are in one of those.
562 if (!DisconnectCleanup()) {
563 // otherwise, no-op
564 LOG(WARNING) << "Ignoring failed disconnect while in state "
565 << GetStateString(state_);
566 }
567
568 // TODO(armansito): In either case, shill ends up thinking
569 // that it's disconnected, while for some reason the underlying
570 // modem might still actually be connected. In that case the UI
571 // would be reflecting an incorrect state and a further connection
572 // request would fail. We should perhaps tear down the modem and
573 // restart it here.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100574}
575
Darin Petkovbac96002011-08-09 13:22:00 -0700576void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700577 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700578 CHECK_EQ(kStateConnected, state_);
579 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700580 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700581 (flags & IFF_UP) != 0) {
582 LinkEvent(flags, IFF_UP);
583 return;
584 }
585 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700586 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Arman Uguray32c76402012-11-27 14:01:13 -0800587
588 // Set state to associating.
589 OnConnecting();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700590}
591
592void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
593 Device::LinkEvent(flags, change);
594 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700595 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700596 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800597 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700598 SelectService(service_);
599 SetServiceState(Service::kStateConfiguring);
600 } else {
601 LOG(ERROR) << "Unable to acquire DHCP config.";
602 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700603 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
Arman Uguray32c76402012-11-27 14:01:13 -0800604 LOG(INFO) << link_name() << " is down.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700605 SetState(kStateConnected);
Arman Uguray32c76402012-11-27 14:01:13 -0800606 DropConnection();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700607 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700608}
609
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400610void Cellular::OnDBusPropertiesChanged(
611 const string &interface,
612 const DBusPropertiesMap &changed_properties,
613 const vector<string> &invalidated_properties) {
614 capability_->OnDBusPropertiesChanged(interface,
615 changed_properties,
616 invalidated_properties);
617}
618
Darin Petkovae0c64e2011-11-15 15:50:27 +0100619void Cellular::set_home_provider(const Operator &oper) {
620 home_provider_.CopyFrom(oper);
621}
622
Darin Petkovac635a82012-01-10 16:51:58 +0100623string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700624 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100625 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
626}
627
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400628void Cellular::OnModemStateChanged(ModemState old_state,
629 ModemState new_state,
630 uint32 /*reason*/) {
631 if (old_state == new_state) {
632 return;
633 }
634 set_modem_state(new_state);
Thieu Le5218cf22012-11-26 11:52:57 -0800635 if (old_state >= kModemStateRegistered &&
636 new_state < kModemStateRegistered) {
637 capability_->SetUnregistered(new_state == kModemStateSearching);
638 HandleNewRegistrationState();
639 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400640 switch (new_state) {
641 case kModemStateDisabled:
642 SetEnabled(false);
643 break;
644 case kModemStateEnabled:
Thieu Le5218cf22012-11-26 11:52:57 -0800645 // Transition from Disabled to Enabled is handled in the
646 // DBusPropertiesChanged handler.
647 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Thieu Led0012052012-07-25 16:09:09 -0700648 // Intentionally falls through.
Thieu Le5218cf22012-11-26 11:52:57 -0800649 case kModemStateSearching:
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400650 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700651 // If the modem state changes from Connecting/Connected/Disconnecting
652 // to Registered/Enabled/Searching, then it's an indication that the
653 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400654 if (old_state == kModemStateConnected ||
655 old_state == kModemStateConnecting ||
656 old_state == kModemStateDisconnecting)
657 OnDisconnected();
658 break;
659 case kModemStateConnecting:
660 OnConnecting();
661 break;
662 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700663 if (old_state == kModemStateConnecting)
664 OnConnected();
665 else
666 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400667 break;
668 default:
669 break;
670 }
671}
672
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800673bool Cellular::IsActivating() const {
674 return capability_->IsActivating();
675}
676
Jason Glasgow7b461df2012-05-01 16:38:45 -0400677void Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
678 SLOG(Cellular, 2) << __func__
679 << "(" << allow_roaming_ << "->" << value << ")";
680 if (allow_roaming_ == value) {
681 return;
682 }
683 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200684 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400685
686 // Use AllowRoaming() instead of allow_roaming_ in order to
687 // incorporate provider preferences when evaluating if a disconnect
688 // is required.
689 if (!capability_->AllowRoaming() &&
690 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
691 Error error;
692 Disconnect(&error);
693 }
694 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
695}
696
Gary Moraina9fb3252012-05-31 12:05:31 -0700697void Cellular::StartTermination() {
Darin Petkov3ec55342012-09-28 14:04:44 +0200698 LOG(INFO) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -0700699 Error error;
700 Disconnect(&error);
701}
702
Arman Uguray539c4232012-09-11 10:00:22 -0700703bool Cellular::DisconnectCleanup() {
Christopher Wiley8a468902012-11-30 11:52:38 -0800704 bool succeeded = false;
Arman Uguray539c4232012-09-11 10:00:22 -0700705 if (state_ == kStateConnected || state_ == kStateLinked) {
706 SetState(kStateRegistered);
707 SetServiceFailureSilent(Service::kFailureUnknown);
708 DestroyIPConfig();
Christopher Wiley8a468902012-11-30 11:52:38 -0800709 succeeded = true;
Arman Uguray539c4232012-09-11 10:00:22 -0700710 }
Christopher Wiley8a468902012-11-30 11:52:38 -0800711 capability_->DisconnectCleanup();
712 return succeeded;
Arman Uguray539c4232012-09-11 10:00:22 -0700713}
Gary Moraina9fb3252012-05-31 12:05:31 -0700714
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700715} // namespace shill