blob: 678f75bb72f220d0635100bfaa25adab8b842dbe [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"
Chris Masone7aa5f902011-07-11 11:13:35 -070036#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070037#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070038#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070039#include "shill/rtnl_handler.h"
Jason Glasgow7b461df2012-05-01 16:38:45 -040040#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080041#include "shill/technology.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070042
Eric Shienbrood3e20a232012-02-16 11:35:56 -050043using base::Bind;
Gary Moraina9fb3252012-05-31 12:05:31 -070044using base::Closure;
mukesh agrawal9da07772013-05-15 14:15:17 -070045using base::FilePath;
46using std::map;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070047using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070048using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070049
50namespace shill {
51
Jason Glasgow7b461df2012-05-01 16:38:45 -040052// static
53const char Cellular::kAllowRoaming[] = "AllowRoaming";
54
Darin Petkov3335b372011-08-22 11:05:32 -070055Cellular::Operator::Operator() {
56 SetName("");
57 SetCode("");
58 SetCountry("");
59}
60
61Cellular::Operator::~Operator() {}
62
63void Cellular::Operator::CopyFrom(const Operator &oper) {
64 dict_ = oper.dict_;
65}
66
67const string &Cellular::Operator::GetName() const {
68 return dict_.find(flimflam::kOperatorNameKey)->second;
69}
70
71void Cellular::Operator::SetName(const string &name) {
72 dict_[flimflam::kOperatorNameKey] = name;
73}
74
75const string &Cellular::Operator::GetCode() const {
76 return dict_.find(flimflam::kOperatorCodeKey)->second;
77}
78
79void Cellular::Operator::SetCode(const string &code) {
80 dict_[flimflam::kOperatorCodeKey] = code;
81}
82
83const string &Cellular::Operator::GetCountry() const {
84 return dict_.find(flimflam::kOperatorCountryKey)->second;
85}
86
87void Cellular::Operator::SetCountry(const string &country) {
88 dict_[flimflam::kOperatorCountryKey] = country;
89}
90
91const Stringmap &Cellular::Operator::ToDict() const {
92 return dict_;
93}
94
Prathmesh Prabhu27526f12013-03-25 19:42:18 -070095Cellular::Cellular(ModemInfo *modem_info,
Darin Petkove9d12e02011-07-27 15:09:37 -070096 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070097 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070098 int interface_index,
99 Type type,
100 const string &owner,
Jason Glasgowa585fc32012-06-06 11:04:09 -0400101 const string &service,
Darin Petkov137884a2011-10-26 18:52:47 +0200102 const string &path,
Ben Chan3ecdf822012-08-06 12:29:23 -0700103 ProxyFactory *proxy_factory)
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700104 : Device(modem_info->control_interface(),
105 modem_info->dispatcher(),
106 modem_info->metrics(),
107 modem_info->manager(),
Darin Petkove9d12e02011-07-27 15:09:37 -0700108 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700109 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800110 interface_index,
111 Technology::kCellular),
Thieu Le64b0fe52012-08-08 14:57:36 -0700112 weak_ptr_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700113 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700114 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700115 dbus_owner_(owner),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400116 dbus_service_(service),
Darin Petkove9d12e02011-07-27 15:09:37 -0700117 dbus_path_(path),
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700118 modem_info_(modem_info),
Ben Chan3ecdf822012-08-06 12:29:23 -0700119 proxy_factory_(proxy_factory),
Thieu Le26fc01b2013-01-28 12:08:48 -0800120 allow_roaming_(false),
121 explicit_disconnect_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700122 PropertyStore *store = this->mutable_store();
Jason Glasgowa585fc32012-06-06 11:04:09 -0400123 // TODO(jglasgow): kDBusConnectionProperty is deprecated.
Paul Stewartac4ac002011-08-26 12:04:26 -0700124 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
Jason Glasgowa585fc32012-06-06 11:04:09 -0400125 store->RegisterConstString(flimflam::kDBusServiceProperty, &dbus_service_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700126 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700127 HelpRegisterConstDerivedString(flimflam::kTechnologyFamilyProperty,
128 &Cellular::GetTechnologyFamily);
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());
Arman Ugurayc7b15602013-02-16 00:56:18 -0800134
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500135 // For now, only a single capability is supported.
Ben Chan3ecdf822012-08-06 12:29:23 -0700136 InitCapability(type);
Chris Masoneb925cc82011-06-22 15:39:57 -0700137
Ben Chanfad4a0b2012-04-18 15:49:59 -0700138 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
139 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700140}
141
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500142Cellular::~Cellular() {
143}
Darin Petkove9d12e02011-07-27 15:09:37 -0700144
Jason Glasgow7b461df2012-05-01 16:38:45 -0400145bool Cellular::Load(StoreInterface *storage) {
146 const string id = GetStorageIdentifier();
147 if (!storage->ContainsGroup(id)) {
148 LOG(WARNING) << "Device is not available in the persistent store: " << id;
149 return false;
150 }
151 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
152 return Device::Load(storage);
153}
154
155bool Cellular::Save(StoreInterface *storage) {
156 const string id = GetStorageIdentifier();
157 storage->SetBool(id, kAllowRoaming, allow_roaming_);
158 return Device::Save(storage);
159}
160
Darin Petkovcc044422011-08-17 13:30:06 -0700161// static
162string Cellular::GetStateString(State state) {
163 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700164 case kStateDisabled: return "CellularStateDisabled";
165 case kStateEnabled: return "CellularStateEnabled";
166 case kStateRegistered: return "CellularStateRegistered";
167 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700168 case kStateLinked: return "CellularStateLinked";
169 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700170 }
Darin Petkovcc044422011-08-17 13:30:06 -0700171 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700172}
173
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400174string Cellular::GetTechnologyFamily(Error *error) {
175 return capability_->GetTypeString();
176}
177
Darin Petkov0828f5f2011-08-11 10:18:52 -0700178void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700179 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
180 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700181 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700182}
183
Jason Glasgow7b461df2012-05-01 16:38:45 -0400184void Cellular::HelpRegisterDerivedBool(
185 const string &name,
186 bool(Cellular::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700187 bool(Cellular::*set)(const bool &value, Error *error)) {
Jason Glasgow7b461df2012-05-01 16:38:45 -0400188 mutable_store()->RegisterDerivedBool(
189 name,
190 BoolAccessor(
191 new CustomAccessor<Cellular, bool>(this, get, set)));
192}
193
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700194void Cellular::HelpRegisterConstDerivedString(
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400195 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700196 string(Cellular::*get)(Error *)) {
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400197 mutable_store()->RegisterDerivedString(
198 name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700199 StringAccessor(new CustomAccessor<Cellular, string>(this, get, NULL)));
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400200}
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 Le26fc01b2013-01-28 12:08:48 -0800218 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700219 ResultCallback cb = Bind(&Cellular::StopModemCallback,
220 weak_ptr_factory_.GetWeakPtr(),
221 callback);
222 capability_->StopModem(error, cb);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500223}
224
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400225bool Cellular::IsUnderlyingDeviceEnabled() const {
226 return IsEnabledModemState(modem_state_);
227}
228
Thieu Led0012052012-07-25 16:09:09 -0700229bool Cellular::IsModemRegistered() const {
230 return (modem_state_ == Cellular::kModemStateRegistered ||
231 modem_state_ == Cellular::kModemStateConnecting ||
232 modem_state_ == Cellular::kModemStateConnected);
233}
234
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400235// static
236bool Cellular::IsEnabledModemState(ModemState state) {
237 switch (state) {
238 case kModemStateUnknown:
239 case kModemStateDisabled:
240 case kModemStateInitializing:
241 case kModemStateLocked:
242 case kModemStateDisabling:
243 case kModemStateEnabling:
244 return false;
245 case kModemStateEnabled:
246 case kModemStateSearching:
247 case kModemStateRegistered:
248 case kModemStateDisconnecting:
249 case kModemStateConnecting:
250 case kModemStateConnected:
251 return true;
252 }
253 return false;
254}
255
Thieu Le37b90032012-05-15 15:18:41 -0700256void Cellular::StartModemCallback(const EnabledStateChangedCallback &callback,
257 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700258 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700259 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500260 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400261 // Registration state updates may have been ignored while the
262 // modem was not yet marked enabled.
263 HandleNewRegistrationState();
Arman Ugurayf84a4242013-04-09 20:01:07 -0700264 if (capability_->ShouldDetectOutOfCredit())
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700265 set_traffic_monitor_enabled(true);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400266 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500267 callback.Run(error);
268}
269
Thieu Le37b90032012-05-15 15:18:41 -0700270void Cellular::StopModemCallback(const EnabledStateChangedCallback &callback,
271 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700272 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le26fc01b2013-01-28 12:08:48 -0800273 explicit_disconnect_ = false;
Thieu Le37b90032012-05-15 15:18:41 -0700274 // Destroy the cellular service regardless of any errors that occur during
275 // the stop process since we do not know the state of the modem at this
276 // point.
277 DestroyService();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500278 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500279 SetState(kStateDisabled);
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700280 set_traffic_monitor_enabled(false);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500281 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700282}
283
Ben Chan3ecdf822012-08-06 12:29:23 -0700284void Cellular::InitCapability(Type type) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100285 // TODO(petkov): Consider moving capability construction into a factory that's
286 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700287 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100288 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200289 case kTypeGSM:
Thieu Lece4483e2013-01-23 15:12:03 -0800290 capability_.reset(new CellularCapabilityGSM(this,
291 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700292 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200293 break;
294 case kTypeCDMA:
Thieu Lece4483e2013-01-23 15:12:03 -0800295 capability_.reset(new CellularCapabilityCDMA(this,
296 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700297 modem_info_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200298 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400299 case kTypeUniversal:
Arman Ugurayc7b15602013-02-16 00:56:18 -0800300 capability_.reset(new CellularCapabilityUniversal(
301 this,
302 proxy_factory_,
Prathmesh Prabhu27526f12013-03-25 19:42:18 -0700303 modem_info_));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400304 break;
Arman Uguray72fab6a2013-01-10 19:32:42 -0800305 case kTypeUniversalCDMA:
306 capability_.reset(new CellularCapabilityUniversalCDMA(
307 this,
308 proxy_factory_,
309 modem_info_));
310 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200311 default: NOTREACHED();
312 }
313}
314
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400315void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500316 Error *error, const ResultCallback &callback) {
317 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700318}
319
Arman Ugurayc7b15602013-02-16 00:56:18 -0800320void Cellular::CompleteActivation(Error *error) {
321 capability_->CompleteActivation(error);
322}
323
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500324void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500325 Error *error,
326 const ResultCallback &callback) {
327 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100328}
329
Eric Shienbrood9a245532012-03-07 14:20:39 -0500330void Cellular::RequirePIN(const string &pin, bool require,
331 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700332 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500333 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700334}
335
Eric Shienbrood9a245532012-03-07 14:20:39 -0500336void Cellular::EnterPIN(const string &pin,
337 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700338 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500339 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700340}
341
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100342void Cellular::UnblockPIN(const string &unblock_code,
343 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500344 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700345 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500346 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700347}
348
Eric Shienbrood9a245532012-03-07 14:20:39 -0500349void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
350 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700351 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500352 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700353}
354
Ben Chan5d0d32c2013-01-08 02:05:29 -0800355void Cellular::Reset(Error *error, const ResultCallback &callback) {
356 SLOG(Cellular, 2) << __func__;
357 capability_->Reset(error, callback);
358}
359
Darin Petkovc37a9c42012-09-06 15:28:22 +0200360void Cellular::SetCarrier(const string &carrier,
361 Error *error, const ResultCallback &callback) {
362 SLOG(Cellular, 2) << __func__ << "(" << carrier << ")";
363 capability_->SetCarrier(carrier, error, callback);
364}
365
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700366void Cellular::OnNoNetworkRouting() {
367 SLOG(Cellular, 2) << __func__;
368 Device::OnNoNetworkRouting();
Arman Ugurayf84a4242013-04-09 20:01:07 -0700369
370 SLOG(Cellular, 2) << "Requesting active probe for out-of-credit detection.";
371 RequestConnectionHealthCheck();
372}
373
374void Cellular::OnConnectionHealthCheckerResult(
375 ConnectionHealthChecker::Result result) {
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700376 SLOG(Cellular, 2) << __func__ << "(Result = "
377 << ConnectionHealthChecker::ResultToString(result) << ")";
Arman Ugurayf84a4242013-04-09 20:01:07 -0700378
Prathmesh Prabhu3fd54bd2013-05-08 16:36:57 -0700379 if (result == ConnectionHealthChecker::kResultCongestedTxQueue) {
Arman Ugurayf84a4242013-04-09 20:01:07 -0700380 SLOG(Cellular, 2) << "Active probe determined possible out-of-credits "
381 << "scenario.";
382 if (service().get()) {
Thieu Le91fccf62013-04-22 15:23:16 -0700383 Metrics::CellularOutOfCreditsReason reason =
384 (result == ConnectionHealthChecker::kResultCongestedTxQueue) ?
385 Metrics::kCellularOutOfCreditsReasonTxCongested :
386 Metrics::kCellularOutOfCreditsReasonElongatedTimeWait;
387 metrics()->NotifyCellularOutOfCredits(reason);
388
Arman Ugurayf84a4242013-04-09 20:01:07 -0700389 service()->SetOutOfCredits(true);
390 SLOG(Cellular, 2) << "Disconnecting due to out-of-credit scenario.";
391 Error error;
392 service()->Disconnect(&error);
393 }
394 }
395}
396
397void Cellular::PortalDetectorCallback(const PortalDetector::Result &result) {
398 Device::PortalDetectorCallback(result);
399 if (result.status != PortalDetector::kStatusSuccess &&
400 capability_->ShouldDetectOutOfCredit()) {
401 SLOG(Cellular, 2) << "Portal detection failed. Launching active probe for "
402 << "out-of-credit detection.";
403 RequestConnectionHealthCheck();
404 }
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700405}
406
Wade Guthrie68d41092013-04-02 12:56:02 -0700407void Cellular::Scan(ScanType scan_type, Error *error) {
408 // |scan_type| is ignored because Cellular only does a full scan.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500409 // TODO(ers): for now report immediate success or failure.
410 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700411}
412
Darin Petkovd9661952011-08-03 16:25:42 -0700413void Cellular::HandleNewRegistrationState() {
mukesh agrawal9da07772013-05-15 14:15:17 -0700414 SLOG(Cellular, 2) << __func__
415 << ": (new state " << GetStateString(state_) << ")";
Ben Chan09fa2a02012-11-07 22:09:09 -0800416 if (capability_->IsServiceActivationRequired()) {
417 if (state_ == kStateEnabled && !service_.get()) {
Arman Uguray6bb252d2013-05-15 14:29:53 -0700418 SLOG(Cellular, 2) << "Service activation required. Creating dummy "
419 << "service.";
Ben Chan09fa2a02012-11-07 22:09:09 -0800420 CreateService();
421 }
422 return;
423 }
Darin Petkovb72cf402011-11-22 14:51:39 +0100424 if (!capability_->IsRegistered()) {
Thieu Le26fc01b2013-01-28 12:08:48 -0800425 if (!explicit_disconnect_ &&
426 (state_ == kStateLinked || state_ == kStateConnected) &&
427 service_.get())
428 metrics()->NotifyCellularDeviceDrop(
Thieu Le6c1e3bb2013-02-06 15:20:35 -0800429 interface_index(),
430 capability_->GetNetworkTechnologyString(),
431 service_->strength());
Darin Petkov2c377382012-01-11 11:40:43 +0100432 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700433 if (state_ == kStateLinked ||
434 state_ == kStateConnected ||
435 state_ == kStateRegistered) {
436 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700437 }
438 return;
439 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500440 // In Disabled state, defer creating a service until fully
441 // enabled. UI will ignore the appearance of a new service
442 // on a disabled device.
443 if (state_ == kStateDisabled) {
444 return;
445 }
Darin Petkovd9661952011-08-03 16:25:42 -0700446 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700447 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700448 }
449 if (!service_.get()) {
Thieu Le18c11072013-01-28 17:21:37 -0800450 metrics()->NotifyDeviceScanFinished(interface_index());
Darin Petkovd9661952011-08-03 16:25:42 -0700451 CreateService();
452 }
Darin Petkov3e509242011-11-10 14:46:44 +0100453 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500454 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
455 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100456 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
457 service_->SetRoamingState(capability_->GetRoamingStateString());
Christopher Wiley9169d252012-11-30 15:13:39 -0800458 manager()->UpdateService(service_);
Darin Petkovd9661952011-08-03 16:25:42 -0700459}
460
Darin Petkovd9661952011-08-03 16:25:42 -0700461void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700462 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100463 if (service_) {
464 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700465 }
466}
467
468void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700469 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700470 CHECK(!service_.get());
Prathmesh Prabhu0d36b4f2013-04-01 11:45:54 -0700471 service_ = new CellularService(modem_info_, this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100472 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100473 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700474}
475
Darin Petkov2c377382012-01-11 11:40:43 +0100476void Cellular::DestroyService() {
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100477 DropConnection();
Darin Petkov2c377382012-01-11 11:40:43 +0100478 if (service_) {
Darin Petkov457728b2013-01-09 09:49:08 +0100479 LOG(INFO) << "Deregistering cellular service " << service_->unique_name()
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100480 << " for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100481 manager()->DeregisterService(service_);
482 service_ = NULL;
483 }
Darin Petkov2c377382012-01-11 11:40:43 +0100484}
485
Darin Petkov4d6d9412011-08-24 13:19:54 -0700486void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700487 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400488 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700489 Error::PopulateAndLog(error, Error::kAlreadyConnected,
490 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700491 return;
Thieu Lec7d8cd12013-02-13 11:38:14 -0800492 } else if (state_ != kStateRegistered) {
493 Error::PopulateAndLog(error, Error::kNotRegistered,
494 "Modem not registered; connection request ignored.");
495 return;
Darin Petkovc5f56562011-08-06 16:40:05 -0700496 }
Darin Petkovd2045802011-08-23 11:09:25 -0700497
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400498 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700499 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700500 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
501 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700502 return;
503 }
504
Darin Petkovc5f56562011-08-06 16:40:05 -0700505 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100506 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700507 ResultCallback cb = Bind(&Cellular::OnConnectReply,
508 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400509 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400510 capability_->Connect(properties, error, cb);
Thieu Le7cf36b02013-01-30 17:15:56 -0800511 if (!error->IsSuccess())
512 return;
513
514 bool is_auto_connecting = service_.get() && service_->is_auto_connecting();
515 metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400516}
517
518// Note that there's no ResultCallback argument to this,
519// since Connect() isn't yet passed one.
520void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700521 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Lecdb5a212013-01-25 11:17:18 -0800522 if (error.IsSuccess()) {
523 metrics()->NotifyDeviceConnectFinished(interface_index());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400524 OnConnected();
Thieu Lecdb5a212013-01-25 11:17:18 -0800525 } else {
Thieu Leb7aa5f72013-01-31 15:57:48 -0800526 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400527 OnConnectFailed(error);
Thieu Lecdb5a212013-01-25 11:17:18 -0800528 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700529}
530
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400531void Cellular::OnConnecting() {
532 if (service_)
533 service_->SetState(Service::kStateAssociating);
534}
535
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500536void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700537 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400538 if (state_ == kStateConnected || state_ == kStateLinked) {
Ben Chan09fa2a02012-11-07 22:09:09 -0800539 SLOG(Cellular, 2) << "Already connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400540 return;
541 }
Darin Petkov1c01bef2012-09-13 15:27:17 +0200542 Closure start_cb = Bind(&Cellular::StartTermination,
543 weak_ptr_factory_.GetWeakPtr());
Gary Moraina9fb3252012-05-31 12:05:31 -0700544 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700545 SetState(kStateConnected);
Thieu Led4974cd2013-05-23 10:39:28 -0700546 if (!service_) {
547 LOG(INFO) << "Disconnecting due to no cellular service.";
548 Disconnect(NULL);
549 } else if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100550 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Arman Uguray539c4232012-09-11 10:00:22 -0700551 LOG(INFO) << "Disconnecting due to roaming.";
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100552 Disconnect(NULL);
553 } else {
554 EstablishLink();
555 }
Darin Petkovbac96002011-08-09 13:22:00 -0700556}
557
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400558void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700559 if (service_)
560 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500561}
562
Christopher Wiley8a468902012-11-30 11:52:38 -0800563void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700564 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500565 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100566 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500567 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100568 return;
569 }
Thieu Le26fc01b2013-01-28 12:08:48 -0800570 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700571 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
Christopher Wiley8a468902012-11-30 11:52:38 -0800572 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400573 capability_->Disconnect(error, cb);
574}
575
Christopher Wiley8a468902012-11-30 11:52:38 -0800576void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700577 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Le26fc01b2013-01-28 12:08:48 -0800578 explicit_disconnect_ = false;
Thieu Leb7aa5f72013-01-31 15:57:48 -0800579 if (error.IsSuccess()) {
Nathan Williamsb54974f2012-04-19 11:16:30 -0400580 OnDisconnected();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800581 } else {
582 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400583 OnDisconnectFailed();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800584 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700585 manager()->TerminationActionComplete(FriendlyName());
586 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100587}
588
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500589void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700590 SLOG(Cellular, 2) << __func__;
Arman Uguray539c4232012-09-11 10:00:22 -0700591 if (!DisconnectCleanup()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500592 LOG(WARNING) << "Disconnect occurred while in state "
593 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400594 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500595}
596
597void Cellular::OnDisconnectFailed() {
Arman Uguray539c4232012-09-11 10:00:22 -0700598 SLOG(Cellular, 2) << __func__;
599 // If the modem is in the disconnecting state, then
600 // the disconnect should eventually succeed, so do
601 // nothing.
602 if (modem_state_ == kModemStateDisconnecting) {
603 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
604 return;
605 }
606
607 // OnDisconnectFailed got called because no bearers
608 // to disconnect were found. Which means that we shouldn't
609 // really remain in the connected/linked state if we
610 // are in one of those.
611 if (!DisconnectCleanup()) {
612 // otherwise, no-op
613 LOG(WARNING) << "Ignoring failed disconnect while in state "
614 << GetStateString(state_);
615 }
616
617 // TODO(armansito): In either case, shill ends up thinking
618 // that it's disconnected, while for some reason the underlying
619 // modem might still actually be connected. In that case the UI
620 // would be reflecting an incorrect state and a further connection
621 // request would fail. We should perhaps tear down the modem and
622 // restart it here.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100623}
624
Darin Petkovbac96002011-08-09 13:22:00 -0700625void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700626 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700627 CHECK_EQ(kStateConnected, state_);
628 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700629 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700630 (flags & IFF_UP) != 0) {
631 LinkEvent(flags, IFF_UP);
632 return;
633 }
634 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700635 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Arman Uguray32c76402012-11-27 14:01:13 -0800636
637 // Set state to associating.
638 OnConnecting();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700639}
640
641void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
642 Device::LinkEvent(flags, change);
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700643 if (ppp_task_) {
644 LOG(INFO) << "Ignoring LinkEvent on device with PPP interface.";
645 return;
646 }
647
Darin Petkov0828f5f2011-08-11 10:18:52 -0700648 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700649 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700650 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800651 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700652 SelectService(service_);
653 SetServiceState(Service::kStateConfiguring);
654 } else {
655 LOG(ERROR) << "Unable to acquire DHCP config.";
656 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700657 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
Arman Uguray32c76402012-11-27 14:01:13 -0800658 LOG(INFO) << link_name() << " is down.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700659 SetState(kStateConnected);
Arman Uguray32c76402012-11-27 14:01:13 -0800660 DropConnection();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700661 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700662}
663
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400664void Cellular::OnDBusPropertiesChanged(
665 const string &interface,
666 const DBusPropertiesMap &changed_properties,
667 const vector<string> &invalidated_properties) {
668 capability_->OnDBusPropertiesChanged(interface,
669 changed_properties,
670 invalidated_properties);
671}
672
Darin Petkovae0c64e2011-11-15 15:50:27 +0100673void Cellular::set_home_provider(const Operator &oper) {
674 home_provider_.CopyFrom(oper);
675}
676
Darin Petkovac635a82012-01-10 16:51:58 +0100677string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700678 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100679 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
680}
681
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400682void Cellular::OnModemStateChanged(ModemState old_state,
683 ModemState new_state,
684 uint32 /*reason*/) {
685 if (old_state == new_state) {
686 return;
687 }
688 set_modem_state(new_state);
Thieu Le5218cf22012-11-26 11:52:57 -0800689 if (old_state >= kModemStateRegistered &&
690 new_state < kModemStateRegistered) {
691 capability_->SetUnregistered(new_state == kModemStateSearching);
692 HandleNewRegistrationState();
693 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400694 switch (new_state) {
695 case kModemStateDisabled:
696 SetEnabled(false);
697 break;
698 case kModemStateEnabled:
Thieu Le5218cf22012-11-26 11:52:57 -0800699 // Transition from Disabled to Enabled is handled in the
700 // DBusPropertiesChanged handler.
701 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Thieu Led0012052012-07-25 16:09:09 -0700702 // Intentionally falls through.
Thieu Le5218cf22012-11-26 11:52:57 -0800703 case kModemStateSearching:
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400704 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700705 // If the modem state changes from Connecting/Connected/Disconnecting
706 // to Registered/Enabled/Searching, then it's an indication that the
707 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400708 if (old_state == kModemStateConnected ||
709 old_state == kModemStateConnecting ||
710 old_state == kModemStateDisconnecting)
711 OnDisconnected();
712 break;
713 case kModemStateConnecting:
714 OnConnecting();
715 break;
716 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700717 if (old_state == kModemStateConnecting)
718 OnConnected();
719 else
720 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400721 break;
722 default:
723 break;
724 }
725}
726
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800727bool Cellular::IsActivating() const {
728 return capability_->IsActivating();
729}
730
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700731bool Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
Jason Glasgow7b461df2012-05-01 16:38:45 -0400732 SLOG(Cellular, 2) << __func__
733 << "(" << allow_roaming_ << "->" << value << ")";
734 if (allow_roaming_ == value) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700735 return false;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400736 }
737 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200738 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400739
740 // Use AllowRoaming() instead of allow_roaming_ in order to
741 // incorporate provider preferences when evaluating if a disconnect
742 // is required.
743 if (!capability_->AllowRoaming() &&
744 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
745 Error error;
746 Disconnect(&error);
747 }
748 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700749 return true;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400750}
751
Gary Moraina9fb3252012-05-31 12:05:31 -0700752void Cellular::StartTermination() {
Darin Petkov3ec55342012-09-28 14:04:44 +0200753 LOG(INFO) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -0700754 Error error;
755 Disconnect(&error);
756}
757
Arman Uguray539c4232012-09-11 10:00:22 -0700758bool Cellular::DisconnectCleanup() {
Christopher Wiley8a468902012-11-30 11:52:38 -0800759 bool succeeded = false;
Arman Uguray539c4232012-09-11 10:00:22 -0700760 if (state_ == kStateConnected || state_ == kStateLinked) {
761 SetState(kStateRegistered);
762 SetServiceFailureSilent(Service::kFailureUnknown);
763 DestroyIPConfig();
Christopher Wiley8a468902012-11-30 11:52:38 -0800764 succeeded = true;
Arman Uguray539c4232012-09-11 10:00:22 -0700765 }
Christopher Wiley8a468902012-11-30 11:52:38 -0800766 capability_->DisconnectCleanup();
767 return succeeded;
Arman Uguray539c4232012-09-11 10:00:22 -0700768}
Gary Moraina9fb3252012-05-31 12:05:31 -0700769
mukesh agrawal9da07772013-05-15 14:15:17 -0700770void Cellular::StartPPP(const string &serial_device) {
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700771 // Some PPP dongles also expose an Ethernet-like network device,
772 // using either cdc_ether, or cdc_ncm. dhcpcd may be running on that
773 // interface. If so, it will eventually time out, and cause us
774 // terminate the cellular connection. Avoid terminating the connection,
775 // by cancelling any such DHCP process.
776 DestroyIPConfig();
777
mukesh agrawal9da07772013-05-15 14:15:17 -0700778 base::Callback<void(pid_t, int)> death_callback(
779 Bind(&Cellular::OnPPPDied, weak_ptr_factory_.GetWeakPtr()));
780 vector<string> args;
781 map<string, string> environment;
782 Error error;
783 if (SLOG_IS_ON(PPP, 5)) {
784 args.push_back("debug");
785 }
786 args.push_back("nodetach");
787 args.push_back("nodefaultroute"); // Don't let pppd muck with routing table.
788 args.push_back("usepeerdns"); // Request DNS servers.
789 args.push_back("plugin"); // Goes with next arg.
790 args.push_back(PPPDevice::kPluginPath);
791 args.push_back(serial_device);
792 scoped_ptr<ExternalTask> new_ppp_task(
793 new ExternalTask(modem_info_->control_interface(),
794 modem_info_->glib(),
795 weak_ptr_factory_.GetWeakPtr(),
796 death_callback));
797 if (new_ppp_task->Start(
798 FilePath(PPPDevice::kDaemonPath), args, environment, &error)) {
799 LOG(INFO) << "Forked pppd process.";
800 ppp_task_ = new_ppp_task.Pass();
801 }
802}
803
804// called by |ppp_task_|
805void Cellular::GetLogin(string *user, string *password) {
806 LOG(INFO) << __func__;
mukesh agrawal3ffe52c2013-06-20 15:21:29 -0700807 if (!service()) {
808 LOG(ERROR) << __func__ << " with no service ";
809 return;
810 }
811 CHECK(user);
812 CHECK(password);
813 *user = service()->ppp_username();
814 *password = service()->ppp_password();
mukesh agrawal9da07772013-05-15 14:15:17 -0700815}
816
817// Called by |ppp_task_|.
818void Cellular::Notify(const string &reason,
819 const map<string, string> &dict) {
820 LOG(INFO) << __func__ << " " << reason << " on " << link_name();
821
822 if (reason != kPPPReasonConnect) {
823 DCHECK_EQ(kPPPReasonDisconnect, reason);
824 // DestroyLater, rather than while on stack.
825 ppp_task_.release()->DestroyLater(modem_info_->dispatcher());
826 // For now, assume PPP failures are due to authentication issues.
827 SetServiceFailure(Service::kFailurePPPAuth);
828 return;
829 }
830
831 string interface_name = PPPDevice::GetInterfaceName(dict);
832 DeviceInfo *device_info = modem_info_->manager()->device_info();
833 int interface_index = device_info->GetIndex(interface_name);
834 if (interface_index < 0) {
835 // TODO(quiche): Consider handling the race when the RTNL notification about
836 // the new PPP device has not been received yet. crbug.com/246832.
837 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
838 return;
839 }
840
841 if (!ppp_device_ || ppp_device_->interface_index() != interface_index) {
842 ppp_device_ = new PPPDevice(modem_info_->control_interface(),
843 modem_info_->dispatcher(),
844 modem_info_->metrics(),
845 modem_info_->manager(),
846 interface_name,
847 interface_index);
848 device_info->RegisterDevice(ppp_device_);
849 }
850
851 // TODO(quiche): Consider if we should have a separate Service for the
852 // PPPDevice. (crbug.com/246456)
853 CHECK(service_);
854 const bool kBlackholeIPv6 = false;
855 ppp_device_->SetEnabled(true);
856 ppp_device_->SelectService(service_);
857 ppp_device_->UpdateIPConfigFromPPP(dict, kBlackholeIPv6);
858}
859
860void Cellular::OnPPPDied(pid_t pid, int exit) {
861 LOG(INFO) << __func__ << " on " << link_name();
862 Error error;
863 Disconnect(&error);
864}
865
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700866} // namespace shill