blob: e5560a0d0f6babf6e4197da3a8e8e6967024c8b0 [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>
mukesh agrawal9da07772013-05-15 14:15:17 -070016#include <base/file_path.h>
Darin Petkove9d12e02011-07-27 15:09:37 -070017#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070018#include <chromeos/dbus/service_constants.h>
Darin Petkov137884a2011-10-26 18:52:47 +020019#include <mobile_provider.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070020
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050021#include "shill/adaptor_interfaces.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020022#include "shill/cellular_capability_cdma.h"
23#include "shill/cellular_capability_gsm.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040024#include "shill/cellular_capability_universal.h"
Arman Uguray72fab6a2013-01-10 19:32:42 -080025#include "shill/cellular_capability_universal_cdma.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070026#include "shill/cellular_service.h"
27#include "shill/control_interface.h"
28#include "shill/device.h"
29#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070030#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070031#include "shill/event_dispatcher.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070032#include "shill/external_task.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070033#include "shill/logging.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070034#include "shill/manager.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070035#include "shill/ppp_device.h"
mukesh agrawalf407d592013-07-31 11:37:57 -070036#include "shill/ppp_device_factory.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070037#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070038#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070039#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070040#include "shill/rtnl_handler.h"
Jason Glasgow7b461df2012-05-01 16:38:45 -040041#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080042#include "shill/technology.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070043
Eric Shienbrood3e20a232012-02-16 11:35:56 -050044using base::Bind;
Gary Moraina9fb3252012-05-31 12:05:31 -070045using base::Closure;
mukesh agrawal9da07772013-05-15 14:15:17 -070046using base::FilePath;
47using std::map;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070048using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070049using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070050
51namespace shill {
52
Jason Glasgow7b461df2012-05-01 16:38:45 -040053// static
54const char Cellular::kAllowRoaming[] = "AllowRoaming";
55
Darin Petkov3335b372011-08-22 11:05:32 -070056Cellular::Operator::Operator() {
57 SetName("");
58 SetCode("");
59 SetCountry("");
60}
61
62Cellular::Operator::~Operator() {}
63
64void Cellular::Operator::CopyFrom(const Operator &oper) {
65 dict_ = oper.dict_;
66}
67
68const string &Cellular::Operator::GetName() const {
69 return dict_.find(flimflam::kOperatorNameKey)->second;
70}
71
72void Cellular::Operator::SetName(const string &name) {
73 dict_[flimflam::kOperatorNameKey] = name;
74}
75
76const string &Cellular::Operator::GetCode() const {
77 return dict_.find(flimflam::kOperatorCodeKey)->second;
78}
79
80void Cellular::Operator::SetCode(const string &code) {
81 dict_[flimflam::kOperatorCodeKey] = code;
82}
83
84const string &Cellular::Operator::GetCountry() const {
85 return dict_.find(flimflam::kOperatorCountryKey)->second;
86}
87
88void Cellular::Operator::SetCountry(const string &country) {
89 dict_[flimflam::kOperatorCountryKey] = country;
90}
91
92const Stringmap &Cellular::Operator::ToDict() const {
93 return dict_;
94}
95
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070096Cellular::Cellular(ModemInfo *modem_info,
Darin Petkove9d12e02011-07-27 15:09:37 -070097 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070098 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070099 int interface_index,
100 Type type,
101 const string &owner,
Jason Glasgowa585fc32012-06-06 11:04:09 -0400102 const string &service,
Darin Petkov137884a2011-10-26 18:52:47 +0200103 const string &path,
Ben Chan3ecdf822012-08-06 12:29:23 -0700104 ProxyFactory *proxy_factory)
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700105 : Device(modem_info->control_interface(),
106 modem_info->dispatcher(),
107 modem_info->metrics(),
108 modem_info->manager(),
Darin Petkove9d12e02011-07-27 15:09:37 -0700109 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700110 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800111 interface_index,
112 Technology::kCellular),
Thieu Le64b0fe52012-08-08 14:57:36 -0700113 weak_ptr_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700114 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700115 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700116 dbus_owner_(owner),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400117 dbus_service_(service),
Darin Petkove9d12e02011-07-27 15:09:37 -0700118 dbus_path_(path),
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700119 modem_info_(modem_info),
Ben Chan3ecdf822012-08-06 12:29:23 -0700120 proxy_factory_(proxy_factory),
mukesh agrawalf407d592013-07-31 11:37:57 -0700121 ppp_device_factory_(PPPDeviceFactory::GetInstance()),
Thieu Le26fc01b2013-01-28 12:08:48 -0800122 allow_roaming_(false),
mukesh agrawalfc362912013-08-06 18:10:07 -0700123 explicit_disconnect_(false),
124 is_ppp_authenticating_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700125 PropertyStore *store = this->mutable_store();
Jason Glasgowa585fc32012-06-06 11:04:09 -0400126 // TODO(jglasgow): kDBusConnectionProperty is deprecated.
Paul Stewartac4ac002011-08-26 12:04:26 -0700127 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
Jason Glasgowa585fc32012-06-06 11:04:09 -0400128 store->RegisterConstString(flimflam::kDBusServiceProperty, &dbus_service_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700129 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700130 HelpRegisterConstDerivedString(flimflam::kTechnologyFamilyProperty,
131 &Cellular::GetTechnologyFamily);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400132 HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
133 &Cellular::GetAllowRoaming,
134 &Cellular::SetAllowRoaming);
Paul Stewartac4ac002011-08-26 12:04:26 -0700135 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700136 &home_provider_.ToDict());
Arman Ugurayc7b15602013-02-16 00:56:18 -0800137
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500138 // For now, only a single capability is supported.
Ben Chan3ecdf822012-08-06 12:29:23 -0700139 InitCapability(type);
Chris Masoneb925cc82011-06-22 15:39:57 -0700140
Ben Chanfad4a0b2012-04-18 15:49:59 -0700141 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
142 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700143}
144
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500145Cellular::~Cellular() {
146}
Darin Petkove9d12e02011-07-27 15:09:37 -0700147
Jason Glasgow7b461df2012-05-01 16:38:45 -0400148bool Cellular::Load(StoreInterface *storage) {
149 const string id = GetStorageIdentifier();
150 if (!storage->ContainsGroup(id)) {
151 LOG(WARNING) << "Device is not available in the persistent store: " << id;
152 return false;
153 }
154 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
155 return Device::Load(storage);
156}
157
158bool Cellular::Save(StoreInterface *storage) {
159 const string id = GetStorageIdentifier();
160 storage->SetBool(id, kAllowRoaming, allow_roaming_);
161 return Device::Save(storage);
162}
163
Darin Petkovcc044422011-08-17 13:30:06 -0700164// static
165string Cellular::GetStateString(State state) {
166 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700167 case kStateDisabled: return "CellularStateDisabled";
168 case kStateEnabled: return "CellularStateEnabled";
169 case kStateRegistered: return "CellularStateRegistered";
170 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700171 case kStateLinked: return "CellularStateLinked";
172 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700173 }
Darin Petkovcc044422011-08-17 13:30:06 -0700174 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700175}
176
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400177string Cellular::GetTechnologyFamily(Error *error) {
178 return capability_->GetTypeString();
179}
180
Darin Petkov0828f5f2011-08-11 10:18:52 -0700181void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700182 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
183 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700184 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700185}
186
Jason Glasgow7b461df2012-05-01 16:38:45 -0400187void Cellular::HelpRegisterDerivedBool(
188 const string &name,
189 bool(Cellular::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700190 bool(Cellular::*set)(const bool &value, Error *error)) {
Jason Glasgow7b461df2012-05-01 16:38:45 -0400191 mutable_store()->RegisterDerivedBool(
192 name,
193 BoolAccessor(
194 new CustomAccessor<Cellular, bool>(this, get, set)));
195}
196
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700197void Cellular::HelpRegisterConstDerivedString(
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400198 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700199 string(Cellular::*get)(Error *)) {
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400200 mutable_store()->RegisterDerivedString(
201 name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700202 StringAccessor(new CustomAccessor<Cellular, string>(this, get, NULL)));
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400203}
204
Eric Shienbrood9a245532012-03-07 14:20:39 -0500205void Cellular::Start(Error *error,
206 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400207 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700208 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500209 if (state_ != kStateDisabled) {
210 return;
211 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700212 ResultCallback cb = Bind(&Cellular::StartModemCallback,
213 weak_ptr_factory_.GetWeakPtr(),
214 callback);
215 capability_->StartModem(error, cb);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700216}
217
Eric Shienbrood9a245532012-03-07 14:20:39 -0500218void Cellular::Stop(Error *error,
219 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700220 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le26fc01b2013-01-28 12:08:48 -0800221 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700222 ResultCallback cb = Bind(&Cellular::StopModemCallback,
223 weak_ptr_factory_.GetWeakPtr(),
224 callback);
225 capability_->StopModem(error, cb);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500226}
227
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400228bool Cellular::IsUnderlyingDeviceEnabled() const {
229 return IsEnabledModemState(modem_state_);
230}
231
Thieu Led0012052012-07-25 16:09:09 -0700232bool Cellular::IsModemRegistered() const {
233 return (modem_state_ == Cellular::kModemStateRegistered ||
234 modem_state_ == Cellular::kModemStateConnecting ||
235 modem_state_ == Cellular::kModemStateConnected);
236}
237
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400238// static
239bool Cellular::IsEnabledModemState(ModemState state) {
240 switch (state) {
241 case kModemStateUnknown:
242 case kModemStateDisabled:
243 case kModemStateInitializing:
244 case kModemStateLocked:
245 case kModemStateDisabling:
246 case kModemStateEnabling:
247 return false;
248 case kModemStateEnabled:
249 case kModemStateSearching:
250 case kModemStateRegistered:
251 case kModemStateDisconnecting:
252 case kModemStateConnecting:
253 case kModemStateConnected:
254 return true;
255 }
256 return false;
257}
258
Thieu Le37b90032012-05-15 15:18:41 -0700259void Cellular::StartModemCallback(const EnabledStateChangedCallback &callback,
260 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700261 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700262 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500263 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400264 // Registration state updates may have been ignored while the
265 // modem was not yet marked enabled.
266 HandleNewRegistrationState();
Arman Ugurayf84a4242013-04-09 20:01:07 -0700267 if (capability_->ShouldDetectOutOfCredit())
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700268 set_traffic_monitor_enabled(true);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400269 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500270 callback.Run(error);
271}
272
Thieu Le37b90032012-05-15 15:18:41 -0700273void Cellular::StopModemCallback(const EnabledStateChangedCallback &callback,
274 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700275 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le26fc01b2013-01-28 12:08:48 -0800276 explicit_disconnect_ = false;
Thieu Le37b90032012-05-15 15:18:41 -0700277 // Destroy the cellular service regardless of any errors that occur during
278 // the stop process since we do not know the state of the modem at this
279 // point.
280 DestroyService();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500281 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500282 SetState(kStateDisabled);
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700283 set_traffic_monitor_enabled(false);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500284 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700285}
286
Ben Chan3ecdf822012-08-06 12:29:23 -0700287void Cellular::InitCapability(Type type) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100288 // TODO(petkov): Consider moving capability construction into a factory that's
289 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700290 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100291 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200292 case kTypeGSM:
Thieu Lece4483e2013-01-23 15:12:03 -0800293 capability_.reset(new CellularCapabilityGSM(this,
294 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700295 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200296 break;
297 case kTypeCDMA:
Thieu Lece4483e2013-01-23 15:12:03 -0800298 capability_.reset(new CellularCapabilityCDMA(this,
299 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700300 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200301 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400302 case kTypeUniversal:
Arman Ugurayc7b15602013-02-16 00:56:18 -0800303 capability_.reset(new CellularCapabilityUniversal(
304 this,
305 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700306 modem_info_));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400307 break;
Arman Uguray72fab6a2013-01-10 19:32:42 -0800308 case kTypeUniversalCDMA:
309 capability_.reset(new CellularCapabilityUniversalCDMA(
310 this,
311 proxy_factory_,
312 modem_info_));
313 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200314 default: NOTREACHED();
315 }
316}
317
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400318void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500319 Error *error, const ResultCallback &callback) {
320 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700321}
322
Arman Ugurayc7b15602013-02-16 00:56:18 -0800323void Cellular::CompleteActivation(Error *error) {
324 capability_->CompleteActivation(error);
325}
326
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500327void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500328 Error *error,
329 const ResultCallback &callback) {
330 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100331}
332
Eric Shienbrood9a245532012-03-07 14:20:39 -0500333void Cellular::RequirePIN(const string &pin, bool require,
334 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700335 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500336 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700337}
338
Eric Shienbrood9a245532012-03-07 14:20:39 -0500339void Cellular::EnterPIN(const string &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_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700343}
344
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100345void Cellular::UnblockPIN(const string &unblock_code,
346 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500347 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700348 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500349 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700350}
351
Eric Shienbrood9a245532012-03-07 14:20:39 -0500352void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
353 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700354 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500355 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700356}
357
Ben Chan5d0d32c2013-01-08 02:05:29 -0800358void Cellular::Reset(Error *error, const ResultCallback &callback) {
359 SLOG(Cellular, 2) << __func__;
360 capability_->Reset(error, callback);
361}
362
Darin Petkovc37a9c42012-09-06 15:28:22 +0200363void Cellular::SetCarrier(const string &carrier,
364 Error *error, const ResultCallback &callback) {
365 SLOG(Cellular, 2) << __func__ << "(" << carrier << ")";
366 capability_->SetCarrier(carrier, error, callback);
367}
368
mukesh agrawal5d851b12013-07-11 14:09:41 -0700369void Cellular::DropConnection() {
370 if (ppp_device_) {
371 // For PPP dongles, IP configuration is handled on the |ppp_device_|,
372 // rather than the netdev plumbed into |this|.
373 ppp_device_->DropConnection();
374 } else {
375 Device::DropConnection();
376 }
377}
378
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700379void Cellular::SetServiceState(Service::ConnectState state) {
380 if (ppp_device_) {
381 ppp_device_->SetServiceState(state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700382 } else if (selected_service()) {
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700383 Device::SetServiceState(state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700384 } else if (service_) {
385 service_->SetState(state);
386 } else {
387 LOG(WARNING) << "State change with no Service.";
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700388 }
389}
390
391void Cellular::SetServiceFailure(Service::ConnectFailure failure_state) {
392 if (ppp_device_) {
393 ppp_device_->SetServiceFailure(failure_state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700394 } else if (selected_service()) {
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700395 Device::SetServiceFailure(failure_state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700396 } else if (service_) {
397 service_->SetFailure(failure_state);
398 } else {
399 LOG(WARNING) << "State change with no Service.";
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700400 }
401}
402
403void Cellular::SetServiceFailureSilent(Service::ConnectFailure failure_state) {
404 if (ppp_device_) {
405 ppp_device_->SetServiceFailureSilent(failure_state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700406 } else if (selected_service()) {
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700407 Device::SetServiceFailureSilent(failure_state);
mukesh agrawalfc362912013-08-06 18:10:07 -0700408 } else if (service_) {
409 service_->SetFailureSilent(failure_state);
410 } else {
411 LOG(WARNING) << "State change with no Service.";
mukesh agrawal0381f9a2013-07-11 16:41:52 -0700412 }
413}
414
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700415void Cellular::OnNoNetworkRouting() {
416 SLOG(Cellular, 2) << __func__;
417 Device::OnNoNetworkRouting();
Arman Ugurayf84a4242013-04-09 20:01:07 -0700418
419 SLOG(Cellular, 2) << "Requesting active probe for out-of-credit detection.";
420 RequestConnectionHealthCheck();
421}
422
423void Cellular::OnConnectionHealthCheckerResult(
424 ConnectionHealthChecker::Result result) {
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700425 SLOG(Cellular, 2) << __func__ << "(Result = "
426 << ConnectionHealthChecker::ResultToString(result) << ")";
Arman Ugurayf84a4242013-04-09 20:01:07 -0700427
Prathmesh Prabhu3fd54bd2013-05-08 16:36:57 -0700428 if (result == ConnectionHealthChecker::kResultCongestedTxQueue) {
Arman Ugurayf84a4242013-04-09 20:01:07 -0700429 SLOG(Cellular, 2) << "Active probe determined possible out-of-credits "
430 << "scenario.";
431 if (service().get()) {
Thieu Le91fccf62013-04-22 15:23:16 -0700432 Metrics::CellularOutOfCreditsReason reason =
433 (result == ConnectionHealthChecker::kResultCongestedTxQueue) ?
434 Metrics::kCellularOutOfCreditsReasonTxCongested :
435 Metrics::kCellularOutOfCreditsReasonElongatedTimeWait;
436 metrics()->NotifyCellularOutOfCredits(reason);
437
Arman Ugurayf84a4242013-04-09 20:01:07 -0700438 service()->SetOutOfCredits(true);
439 SLOG(Cellular, 2) << "Disconnecting due to out-of-credit scenario.";
440 Error error;
441 service()->Disconnect(&error);
442 }
443 }
444}
445
446void Cellular::PortalDetectorCallback(const PortalDetector::Result &result) {
447 Device::PortalDetectorCallback(result);
448 if (result.status != PortalDetector::kStatusSuccess &&
449 capability_->ShouldDetectOutOfCredit()) {
450 SLOG(Cellular, 2) << "Portal detection failed. Launching active probe for "
451 << "out-of-credit detection.";
452 RequestConnectionHealthCheck();
453 }
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700454}
455
Wade Guthrie4823f4f2013-07-25 10:03:03 -0700456void Cellular::Scan(ScanType /*scan_type*/, Error *error,
457 const string &/*reason*/) {
Wade Guthrie68d41092013-04-02 12:56:02 -0700458 // |scan_type| is ignored because Cellular only does a full scan.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500459 // TODO(ers): for now report immediate success or failure.
460 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700461}
462
Darin Petkovd9661952011-08-03 16:25:42 -0700463void Cellular::HandleNewRegistrationState() {
mukesh agrawal9da07772013-05-15 14:15:17 -0700464 SLOG(Cellular, 2) << __func__
465 << ": (new state " << GetStateString(state_) << ")";
Ben Chan09fa2a02012-11-07 22:09:09 -0800466 if (capability_->IsServiceActivationRequired()) {
467 if (state_ == kStateEnabled && !service_.get()) {
Arman Uguray6bb252d2013-05-15 14:29:53 -0700468 SLOG(Cellular, 2) << "Service activation required. Creating dummy "
469 << "service.";
Ben Chan09fa2a02012-11-07 22:09:09 -0800470 CreateService();
471 }
472 return;
473 }
Darin Petkovb72cf402011-11-22 14:51:39 +0100474 if (!capability_->IsRegistered()) {
Thieu Le26fc01b2013-01-28 12:08:48 -0800475 if (!explicit_disconnect_ &&
476 (state_ == kStateLinked || state_ == kStateConnected) &&
477 service_.get())
478 metrics()->NotifyCellularDeviceDrop(
Thieu Le6c1e3bb2013-02-06 15:20:35 -0800479 interface_index(),
480 capability_->GetNetworkTechnologyString(),
481 service_->strength());
Darin Petkov2c377382012-01-11 11:40:43 +0100482 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700483 if (state_ == kStateLinked ||
484 state_ == kStateConnected ||
485 state_ == kStateRegistered) {
486 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700487 }
488 return;
489 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500490 // In Disabled state, defer creating a service until fully
491 // enabled. UI will ignore the appearance of a new service
492 // on a disabled device.
493 if (state_ == kStateDisabled) {
494 return;
495 }
Darin Petkovd9661952011-08-03 16:25:42 -0700496 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700497 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700498 }
499 if (!service_.get()) {
Thieu Le18c11072013-01-28 17:21:37 -0800500 metrics()->NotifyDeviceScanFinished(interface_index());
Darin Petkovd9661952011-08-03 16:25:42 -0700501 CreateService();
502 }
Darin Petkov3e509242011-11-10 14:46:44 +0100503 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500504 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
505 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100506 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
507 service_->SetRoamingState(capability_->GetRoamingStateString());
Christopher Wiley9169d252012-11-30 15:13:39 -0800508 manager()->UpdateService(service_);
Darin Petkovd9661952011-08-03 16:25:42 -0700509}
510
Darin Petkovd9661952011-08-03 16:25:42 -0700511void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700512 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100513 if (service_) {
514 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700515 }
516}
517
518void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700519 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700520 CHECK(!service_.get());
Prathmesh Prabhu0d36b4f2013-04-01 11:45:54 -0700521 service_ = new CellularService(modem_info_, this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100522 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100523 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700524}
525
Darin Petkov2c377382012-01-11 11:40:43 +0100526void Cellular::DestroyService() {
mukesh agrawal6813e762013-07-10 19:05:08 -0700527 SLOG(Cellular, 2) << __func__;
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100528 DropConnection();
Darin Petkov2c377382012-01-11 11:40:43 +0100529 if (service_) {
Darin Petkov457728b2013-01-09 09:49:08 +0100530 LOG(INFO) << "Deregistering cellular service " << service_->unique_name()
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100531 << " for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100532 manager()->DeregisterService(service_);
533 service_ = NULL;
534 }
Darin Petkov2c377382012-01-11 11:40:43 +0100535}
536
Darin Petkov4d6d9412011-08-24 13:19:54 -0700537void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700538 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400539 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700540 Error::PopulateAndLog(error, Error::kAlreadyConnected,
541 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700542 return;
Thieu Lec7d8cd12013-02-13 11:38:14 -0800543 } else if (state_ != kStateRegistered) {
544 Error::PopulateAndLog(error, Error::kNotRegistered,
545 "Modem not registered; connection request ignored.");
546 return;
Darin Petkovc5f56562011-08-06 16:40:05 -0700547 }
Darin Petkovd2045802011-08-23 11:09:25 -0700548
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400549 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700550 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700551 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
552 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700553 return;
554 }
555
Darin Petkovc5f56562011-08-06 16:40:05 -0700556 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100557 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700558 ResultCallback cb = Bind(&Cellular::OnConnectReply,
559 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400560 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400561 capability_->Connect(properties, error, cb);
Thieu Le7cf36b02013-01-30 17:15:56 -0800562 if (!error->IsSuccess())
563 return;
564
565 bool is_auto_connecting = service_.get() && service_->is_auto_connecting();
566 metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400567}
568
569// Note that there's no ResultCallback argument to this,
570// since Connect() isn't yet passed one.
571void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700572 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Lecdb5a212013-01-25 11:17:18 -0800573 if (error.IsSuccess()) {
574 metrics()->NotifyDeviceConnectFinished(interface_index());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400575 OnConnected();
Thieu Lecdb5a212013-01-25 11:17:18 -0800576 } else {
Thieu Leb7aa5f72013-01-31 15:57:48 -0800577 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400578 OnConnectFailed(error);
Thieu Lecdb5a212013-01-25 11:17:18 -0800579 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700580}
581
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400582void Cellular::OnConnecting() {
583 if (service_)
584 service_->SetState(Service::kStateAssociating);
585}
586
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500587void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700588 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400589 if (state_ == kStateConnected || state_ == kStateLinked) {
Ben Chan09fa2a02012-11-07 22:09:09 -0800590 SLOG(Cellular, 2) << "Already connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400591 return;
592 }
Darin Petkov1c01bef2012-09-13 15:27:17 +0200593 Closure start_cb = Bind(&Cellular::StartTermination,
594 weak_ptr_factory_.GetWeakPtr());
Gary Moraina9fb3252012-05-31 12:05:31 -0700595 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700596 SetState(kStateConnected);
Thieu Led4974cd2013-05-23 10:39:28 -0700597 if (!service_) {
598 LOG(INFO) << "Disconnecting due to no cellular service.";
599 Disconnect(NULL);
600 } else if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100601 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Arman Uguray539c4232012-09-11 10:00:22 -0700602 LOG(INFO) << "Disconnecting due to roaming.";
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100603 Disconnect(NULL);
604 } else {
605 EstablishLink();
606 }
Darin Petkovbac96002011-08-09 13:22:00 -0700607}
608
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400609void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700610 if (service_)
611 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500612}
613
Christopher Wiley8a468902012-11-30 11:52:38 -0800614void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700615 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500616 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100617 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500618 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100619 return;
620 }
Thieu Le26fc01b2013-01-28 12:08:48 -0800621 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700622 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
Christopher Wiley8a468902012-11-30 11:52:38 -0800623 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400624 capability_->Disconnect(error, cb);
625}
626
Christopher Wiley8a468902012-11-30 11:52:38 -0800627void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700628 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Le26fc01b2013-01-28 12:08:48 -0800629 explicit_disconnect_ = false;
Thieu Leb7aa5f72013-01-31 15:57:48 -0800630 if (error.IsSuccess()) {
Nathan Williamsb54974f2012-04-19 11:16:30 -0400631 OnDisconnected();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800632 } else {
633 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400634 OnDisconnectFailed();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800635 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700636 manager()->TerminationActionComplete(FriendlyName());
637 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100638}
639
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500640void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700641 SLOG(Cellular, 2) << __func__;
Arman Uguray539c4232012-09-11 10:00:22 -0700642 if (!DisconnectCleanup()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500643 LOG(WARNING) << "Disconnect occurred while in state "
644 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400645 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500646}
647
648void Cellular::OnDisconnectFailed() {
Arman Uguray539c4232012-09-11 10:00:22 -0700649 SLOG(Cellular, 2) << __func__;
650 // If the modem is in the disconnecting state, then
651 // the disconnect should eventually succeed, so do
652 // nothing.
653 if (modem_state_ == kModemStateDisconnecting) {
654 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
655 return;
656 }
657
658 // OnDisconnectFailed got called because no bearers
659 // to disconnect were found. Which means that we shouldn't
660 // really remain in the connected/linked state if we
661 // are in one of those.
662 if (!DisconnectCleanup()) {
663 // otherwise, no-op
664 LOG(WARNING) << "Ignoring failed disconnect while in state "
665 << GetStateString(state_);
666 }
667
668 // TODO(armansito): In either case, shill ends up thinking
669 // that it's disconnected, while for some reason the underlying
670 // modem might still actually be connected. In that case the UI
671 // would be reflecting an incorrect state and a further connection
672 // request would fail. We should perhaps tear down the modem and
673 // restart it here.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100674}
675
Darin Petkovbac96002011-08-09 13:22:00 -0700676void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700677 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700678 CHECK_EQ(kStateConnected, state_);
679 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700680 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700681 (flags & IFF_UP) != 0) {
682 LinkEvent(flags, IFF_UP);
683 return;
684 }
685 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700686 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Arman Uguray32c76402012-11-27 14:01:13 -0800687
688 // Set state to associating.
689 OnConnecting();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700690}
691
692void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
693 Device::LinkEvent(flags, change);
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700694 if (ppp_task_) {
695 LOG(INFO) << "Ignoring LinkEvent on device with PPP interface.";
696 return;
697 }
698
Darin Petkov0828f5f2011-08-11 10:18:52 -0700699 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700700 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700701 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800702 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700703 SelectService(service_);
704 SetServiceState(Service::kStateConfiguring);
705 } else {
706 LOG(ERROR) << "Unable to acquire DHCP config.";
707 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700708 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
Arman Uguray32c76402012-11-27 14:01:13 -0800709 LOG(INFO) << link_name() << " is down.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700710 SetState(kStateConnected);
Arman Uguray32c76402012-11-27 14:01:13 -0800711 DropConnection();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700712 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700713}
714
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400715void Cellular::OnDBusPropertiesChanged(
716 const string &interface,
717 const DBusPropertiesMap &changed_properties,
718 const vector<string> &invalidated_properties) {
719 capability_->OnDBusPropertiesChanged(interface,
720 changed_properties,
721 invalidated_properties);
722}
723
Darin Petkovae0c64e2011-11-15 15:50:27 +0100724void Cellular::set_home_provider(const Operator &oper) {
725 home_provider_.CopyFrom(oper);
726}
727
Darin Petkovac635a82012-01-10 16:51:58 +0100728string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700729 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100730 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
731}
732
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400733void Cellular::OnModemStateChanged(ModemState old_state,
734 ModemState new_state,
735 uint32 /*reason*/) {
736 if (old_state == new_state) {
737 return;
738 }
739 set_modem_state(new_state);
Thieu Le5218cf22012-11-26 11:52:57 -0800740 if (old_state >= kModemStateRegistered &&
741 new_state < kModemStateRegistered) {
742 capability_->SetUnregistered(new_state == kModemStateSearching);
743 HandleNewRegistrationState();
744 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400745 switch (new_state) {
746 case kModemStateDisabled:
747 SetEnabled(false);
748 break;
749 case kModemStateEnabled:
Thieu Le5218cf22012-11-26 11:52:57 -0800750 // Transition from Disabled to Enabled is handled in the
751 // DBusPropertiesChanged handler.
752 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Thieu Led0012052012-07-25 16:09:09 -0700753 // Intentionally falls through.
Thieu Le5218cf22012-11-26 11:52:57 -0800754 case kModemStateSearching:
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400755 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700756 // If the modem state changes from Connecting/Connected/Disconnecting
757 // to Registered/Enabled/Searching, then it's an indication that the
758 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400759 if (old_state == kModemStateConnected ||
760 old_state == kModemStateConnecting ||
761 old_state == kModemStateDisconnecting)
762 OnDisconnected();
763 break;
764 case kModemStateConnecting:
765 OnConnecting();
766 break;
767 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700768 if (old_state == kModemStateConnecting)
769 OnConnected();
770 else
771 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400772 break;
773 default:
774 break;
775 }
776}
777
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800778bool Cellular::IsActivating() const {
779 return capability_->IsActivating();
780}
781
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700782bool Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
Jason Glasgow7b461df2012-05-01 16:38:45 -0400783 SLOG(Cellular, 2) << __func__
784 << "(" << allow_roaming_ << "->" << value << ")";
785 if (allow_roaming_ == value) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700786 return false;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400787 }
788 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200789 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400790
791 // Use AllowRoaming() instead of allow_roaming_ in order to
792 // incorporate provider preferences when evaluating if a disconnect
793 // is required.
794 if (!capability_->AllowRoaming() &&
795 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
796 Error error;
797 Disconnect(&error);
798 }
799 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700800 return true;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400801}
802
Gary Moraina9fb3252012-05-31 12:05:31 -0700803void Cellular::StartTermination() {
Darin Petkov3ec55342012-09-28 14:04:44 +0200804 LOG(INFO) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -0700805 Error error;
806 Disconnect(&error);
807}
808
Arman Uguray539c4232012-09-11 10:00:22 -0700809bool Cellular::DisconnectCleanup() {
Christopher Wiley8a468902012-11-30 11:52:38 -0800810 bool succeeded = false;
Arman Uguray539c4232012-09-11 10:00:22 -0700811 if (state_ == kStateConnected || state_ == kStateLinked) {
812 SetState(kStateRegistered);
813 SetServiceFailureSilent(Service::kFailureUnknown);
814 DestroyIPConfig();
Christopher Wiley8a468902012-11-30 11:52:38 -0800815 succeeded = true;
Arman Uguray539c4232012-09-11 10:00:22 -0700816 }
Christopher Wiley8a468902012-11-30 11:52:38 -0800817 capability_->DisconnectCleanup();
818 return succeeded;
Arman Uguray539c4232012-09-11 10:00:22 -0700819}
Gary Moraina9fb3252012-05-31 12:05:31 -0700820
mukesh agrawal9da07772013-05-15 14:15:17 -0700821void Cellular::StartPPP(const string &serial_device) {
mukesh agrawalfc362912013-08-06 18:10:07 -0700822 SLOG(PPP, 2) << __func__ << " on " << serial_device;
mukesh agrawal35ec8402013-07-19 14:49:08 -0700823 // Detach any SelectedService from this device. It will be grafted onto
824 // the PPPDevice after PPP is up (in Cellular::Notify).
825 //
826 // This has two important effects: 1) kills dhcpcd if it is running.
827 // 2) stops Cellular::LinkEvent from driving changes to the
828 // SelectedService.
829 if (selected_service()) {
830 CHECK_EQ(service_.get(), selected_service().get());
831 // Save and restore |service_| state, as DropConnection calls
832 // SelectService, and SelectService will move selected_service()
833 // to kStateIdle.
834 Service::ConnectState original_state(service_->state());
835 Device::DropConnection(); // Don't redirect to PPPDevice.
836 service_->SetState(original_state);
837 } else {
838 CHECK(!ipconfig()); // Shouldn't have ipconfig without selected_service().
839 }
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700840
mukesh agrawal9da07772013-05-15 14:15:17 -0700841 base::Callback<void(pid_t, int)> death_callback(
842 Bind(&Cellular::OnPPPDied, weak_ptr_factory_.GetWeakPtr()));
843 vector<string> args;
844 map<string, string> environment;
845 Error error;
846 if (SLOG_IS_ON(PPP, 5)) {
847 args.push_back("debug");
848 }
849 args.push_back("nodetach");
850 args.push_back("nodefaultroute"); // Don't let pppd muck with routing table.
851 args.push_back("usepeerdns"); // Request DNS servers.
852 args.push_back("plugin"); // Goes with next arg.
853 args.push_back(PPPDevice::kPluginPath);
854 args.push_back(serial_device);
mukesh agrawalfc362912013-08-06 18:10:07 -0700855 is_ppp_authenticating_ = false;
mukesh agrawal9da07772013-05-15 14:15:17 -0700856 scoped_ptr<ExternalTask> new_ppp_task(
857 new ExternalTask(modem_info_->control_interface(),
858 modem_info_->glib(),
859 weak_ptr_factory_.GetWeakPtr(),
860 death_callback));
861 if (new_ppp_task->Start(
862 FilePath(PPPDevice::kDaemonPath), args, environment, &error)) {
863 LOG(INFO) << "Forked pppd process.";
864 ppp_task_ = new_ppp_task.Pass();
865 }
866}
867
868// called by |ppp_task_|
869void Cellular::GetLogin(string *user, string *password) {
mukesh agrawalfc362912013-08-06 18:10:07 -0700870 SLOG(PPP, 2) << __func__;
mukesh agrawal3ffe52c2013-06-20 15:21:29 -0700871 if (!service()) {
872 LOG(ERROR) << __func__ << " with no service ";
873 return;
874 }
875 CHECK(user);
876 CHECK(password);
877 *user = service()->ppp_username();
878 *password = service()->ppp_password();
mukesh agrawal9da07772013-05-15 14:15:17 -0700879}
880
881// Called by |ppp_task_|.
882void Cellular::Notify(const string &reason,
883 const map<string, string> &dict) {
mukesh agrawalfc362912013-08-06 18:10:07 -0700884 SLOG(PPP, 2) << __func__ << " " << reason << " on " << link_name();
mukesh agrawal9da07772013-05-15 14:15:17 -0700885
mukesh agrawalfc362912013-08-06 18:10:07 -0700886 if (reason == kPPPReasonAuthenticating) {
887 OnPPPAuthenticating();
888 } else if (reason == kPPPReasonAuthenticated) {
889 OnPPPAuthenticated();
890 } else if (reason == kPPPReasonConnect) {
891 OnPPPConnected(dict);
892 } else if (reason == kPPPReasonDisconnect) {
893 OnPPPDisconnected();
894 } else {
895 NOTREACHED();
mukesh agrawal9da07772013-05-15 14:15:17 -0700896 }
mukesh agrawalfc362912013-08-06 18:10:07 -0700897}
mukesh agrawal9da07772013-05-15 14:15:17 -0700898
mukesh agrawalfc362912013-08-06 18:10:07 -0700899void Cellular::OnPPPAuthenticated() {
900 SLOG(PPP, 2) << __func__;
901 is_ppp_authenticating_ = false;
902}
903
904void Cellular::OnPPPAuthenticating() {
905 SLOG(PPP, 2) << __func__;
906 is_ppp_authenticating_ = true;
907}
908
909void Cellular::OnPPPConnected(const map<string, string> &params) {
910 SLOG(PPP, 2) << __func__;
911 string interface_name = PPPDevice::GetInterfaceName(params);
mukesh agrawal9da07772013-05-15 14:15:17 -0700912 DeviceInfo *device_info = modem_info_->manager()->device_info();
913 int interface_index = device_info->GetIndex(interface_name);
914 if (interface_index < 0) {
915 // TODO(quiche): Consider handling the race when the RTNL notification about
916 // the new PPP device has not been received yet. crbug.com/246832.
917 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
918 return;
919 }
920
921 if (!ppp_device_ || ppp_device_->interface_index() != interface_index) {
mukesh agrawalf407d592013-07-31 11:37:57 -0700922 if (ppp_device_) {
923 ppp_device_->SelectService(NULL); // No longer drives |service_|.
924 }
925 ppp_device_ = ppp_device_factory_->CreatePPPDevice(
926 modem_info_->control_interface(),
927 modem_info_->dispatcher(),
928 modem_info_->metrics(),
929 modem_info_->manager(),
930 interface_name,
931 interface_index);
mukesh agrawal9da07772013-05-15 14:15:17 -0700932 device_info->RegisterDevice(ppp_device_);
933 }
934
mukesh agrawal9da07772013-05-15 14:15:17 -0700935 CHECK(service_);
mukesh agrawal5d851b12013-07-11 14:09:41 -0700936 // For PPP, we only SelectService on the |ppp_device_|.
937 CHECK(!selected_service());
mukesh agrawal9da07772013-05-15 14:15:17 -0700938 const bool kBlackholeIPv6 = false;
939 ppp_device_->SetEnabled(true);
940 ppp_device_->SelectService(service_);
mukesh agrawalfc362912013-08-06 18:10:07 -0700941 ppp_device_->UpdateIPConfigFromPPP(params, kBlackholeIPv6);
942}
943
944void Cellular::OnPPPDisconnected() {
945 SLOG(PPP, 2) << __func__;
946 // DestroyLater, rather than while on stack.
947 ppp_task_.release()->DestroyLater(modem_info_->dispatcher());
948 if (is_ppp_authenticating_) {
949 SetServiceFailure(Service::kFailurePPPAuth);
950 } else {
951 // TODO(quiche): Don't set failure if we disconnected intentionally.
952 SetServiceFailure(Service::kFailureUnknown);
953 }
954 return;
mukesh agrawal9da07772013-05-15 14:15:17 -0700955}
956
957void Cellular::OnPPPDied(pid_t pid, int exit) {
958 LOG(INFO) << __func__ << " on " << link_name();
959 Error error;
960 Disconnect(&error);
961}
962
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700963} // namespace shill