blob: c090baf4f2e262ccd6ba23958039be7947b1b444 [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
mukesh agrawal5d851b12013-07-11 14:09:41 -0700366void Cellular::DropConnection() {
367 if (ppp_device_) {
368 // For PPP dongles, IP configuration is handled on the |ppp_device_|,
369 // rather than the netdev plumbed into |this|.
370 ppp_device_->DropConnection();
371 } else {
372 Device::DropConnection();
373 }
374}
375
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700376void Cellular::OnNoNetworkRouting() {
377 SLOG(Cellular, 2) << __func__;
378 Device::OnNoNetworkRouting();
Arman Ugurayf84a4242013-04-09 20:01:07 -0700379
380 SLOG(Cellular, 2) << "Requesting active probe for out-of-credit detection.";
381 RequestConnectionHealthCheck();
382}
383
384void Cellular::OnConnectionHealthCheckerResult(
385 ConnectionHealthChecker::Result result) {
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700386 SLOG(Cellular, 2) << __func__ << "(Result = "
387 << ConnectionHealthChecker::ResultToString(result) << ")";
Arman Ugurayf84a4242013-04-09 20:01:07 -0700388
Prathmesh Prabhu3fd54bd2013-05-08 16:36:57 -0700389 if (result == ConnectionHealthChecker::kResultCongestedTxQueue) {
Arman Ugurayf84a4242013-04-09 20:01:07 -0700390 SLOG(Cellular, 2) << "Active probe determined possible out-of-credits "
391 << "scenario.";
392 if (service().get()) {
Thieu Le91fccf62013-04-22 15:23:16 -0700393 Metrics::CellularOutOfCreditsReason reason =
394 (result == ConnectionHealthChecker::kResultCongestedTxQueue) ?
395 Metrics::kCellularOutOfCreditsReasonTxCongested :
396 Metrics::kCellularOutOfCreditsReasonElongatedTimeWait;
397 metrics()->NotifyCellularOutOfCredits(reason);
398
Arman Ugurayf84a4242013-04-09 20:01:07 -0700399 service()->SetOutOfCredits(true);
400 SLOG(Cellular, 2) << "Disconnecting due to out-of-credit scenario.";
401 Error error;
402 service()->Disconnect(&error);
403 }
404 }
405}
406
407void Cellular::PortalDetectorCallback(const PortalDetector::Result &result) {
408 Device::PortalDetectorCallback(result);
409 if (result.status != PortalDetector::kStatusSuccess &&
410 capability_->ShouldDetectOutOfCredit()) {
411 SLOG(Cellular, 2) << "Portal detection failed. Launching active probe for "
412 << "out-of-credit detection.";
413 RequestConnectionHealthCheck();
414 }
Arman Ugurayd42d8ec2013-04-08 19:28:21 -0700415}
416
Wade Guthrie68d41092013-04-02 12:56:02 -0700417void Cellular::Scan(ScanType scan_type, Error *error) {
418 // |scan_type| is ignored because Cellular only does a full scan.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500419 // TODO(ers): for now report immediate success or failure.
420 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700421}
422
Darin Petkovd9661952011-08-03 16:25:42 -0700423void Cellular::HandleNewRegistrationState() {
mukesh agrawal9da07772013-05-15 14:15:17 -0700424 SLOG(Cellular, 2) << __func__
425 << ": (new state " << GetStateString(state_) << ")";
Ben Chan09fa2a02012-11-07 22:09:09 -0800426 if (capability_->IsServiceActivationRequired()) {
427 if (state_ == kStateEnabled && !service_.get()) {
Arman Uguray6bb252d2013-05-15 14:29:53 -0700428 SLOG(Cellular, 2) << "Service activation required. Creating dummy "
429 << "service.";
Ben Chan09fa2a02012-11-07 22:09:09 -0800430 CreateService();
431 }
432 return;
433 }
Darin Petkovb72cf402011-11-22 14:51:39 +0100434 if (!capability_->IsRegistered()) {
Thieu Le26fc01b2013-01-28 12:08:48 -0800435 if (!explicit_disconnect_ &&
436 (state_ == kStateLinked || state_ == kStateConnected) &&
437 service_.get())
438 metrics()->NotifyCellularDeviceDrop(
Thieu Le6c1e3bb2013-02-06 15:20:35 -0800439 interface_index(),
440 capability_->GetNetworkTechnologyString(),
441 service_->strength());
Darin Petkov2c377382012-01-11 11:40:43 +0100442 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700443 if (state_ == kStateLinked ||
444 state_ == kStateConnected ||
445 state_ == kStateRegistered) {
446 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700447 }
448 return;
449 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500450 // In Disabled state, defer creating a service until fully
451 // enabled. UI will ignore the appearance of a new service
452 // on a disabled device.
453 if (state_ == kStateDisabled) {
454 return;
455 }
Darin Petkovd9661952011-08-03 16:25:42 -0700456 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700457 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700458 }
459 if (!service_.get()) {
Thieu Le18c11072013-01-28 17:21:37 -0800460 metrics()->NotifyDeviceScanFinished(interface_index());
Darin Petkovd9661952011-08-03 16:25:42 -0700461 CreateService();
462 }
Darin Petkov3e509242011-11-10 14:46:44 +0100463 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500464 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
465 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100466 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
467 service_->SetRoamingState(capability_->GetRoamingStateString());
Christopher Wiley9169d252012-11-30 15:13:39 -0800468 manager()->UpdateService(service_);
Darin Petkovd9661952011-08-03 16:25:42 -0700469}
470
Darin Petkovd9661952011-08-03 16:25:42 -0700471void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700472 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100473 if (service_) {
474 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700475 }
476}
477
478void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700479 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700480 CHECK(!service_.get());
Prathmesh Prabhu0d36b4f2013-04-01 11:45:54 -0700481 service_ = new CellularService(modem_info_, this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100482 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100483 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700484}
485
Darin Petkov2c377382012-01-11 11:40:43 +0100486void Cellular::DestroyService() {
mukesh agrawal6813e762013-07-10 19:05:08 -0700487 SLOG(Cellular, 2) << __func__;
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100488 DropConnection();
Darin Petkov2c377382012-01-11 11:40:43 +0100489 if (service_) {
Darin Petkov457728b2013-01-09 09:49:08 +0100490 LOG(INFO) << "Deregistering cellular service " << service_->unique_name()
Darin Petkov0f5dfa02012-11-14 16:35:32 +0100491 << " for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100492 manager()->DeregisterService(service_);
493 service_ = NULL;
494 }
Darin Petkov2c377382012-01-11 11:40:43 +0100495}
496
Darin Petkov4d6d9412011-08-24 13:19:54 -0700497void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700498 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400499 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700500 Error::PopulateAndLog(error, Error::kAlreadyConnected,
501 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700502 return;
Thieu Lec7d8cd12013-02-13 11:38:14 -0800503 } else if (state_ != kStateRegistered) {
504 Error::PopulateAndLog(error, Error::kNotRegistered,
505 "Modem not registered; connection request ignored.");
506 return;
Darin Petkovc5f56562011-08-06 16:40:05 -0700507 }
Darin Petkovd2045802011-08-23 11:09:25 -0700508
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400509 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700510 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700511 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
512 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700513 return;
514 }
515
Darin Petkovc5f56562011-08-06 16:40:05 -0700516 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100517 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700518 ResultCallback cb = Bind(&Cellular::OnConnectReply,
519 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400520 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400521 capability_->Connect(properties, error, cb);
Thieu Le7cf36b02013-01-30 17:15:56 -0800522 if (!error->IsSuccess())
523 return;
524
525 bool is_auto_connecting = service_.get() && service_->is_auto_connecting();
526 metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400527}
528
529// Note that there's no ResultCallback argument to this,
530// since Connect() isn't yet passed one.
531void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700532 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Lecdb5a212013-01-25 11:17:18 -0800533 if (error.IsSuccess()) {
534 metrics()->NotifyDeviceConnectFinished(interface_index());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400535 OnConnected();
Thieu Lecdb5a212013-01-25 11:17:18 -0800536 } else {
Thieu Leb7aa5f72013-01-31 15:57:48 -0800537 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400538 OnConnectFailed(error);
Thieu Lecdb5a212013-01-25 11:17:18 -0800539 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700540}
541
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400542void Cellular::OnConnecting() {
543 if (service_)
544 service_->SetState(Service::kStateAssociating);
545}
546
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500547void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700548 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400549 if (state_ == kStateConnected || state_ == kStateLinked) {
Ben Chan09fa2a02012-11-07 22:09:09 -0800550 SLOG(Cellular, 2) << "Already connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400551 return;
552 }
Darin Petkov1c01bef2012-09-13 15:27:17 +0200553 Closure start_cb = Bind(&Cellular::StartTermination,
554 weak_ptr_factory_.GetWeakPtr());
Gary Moraina9fb3252012-05-31 12:05:31 -0700555 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700556 SetState(kStateConnected);
Thieu Led4974cd2013-05-23 10:39:28 -0700557 if (!service_) {
558 LOG(INFO) << "Disconnecting due to no cellular service.";
559 Disconnect(NULL);
560 } else if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100561 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Arman Uguray539c4232012-09-11 10:00:22 -0700562 LOG(INFO) << "Disconnecting due to roaming.";
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100563 Disconnect(NULL);
564 } else {
565 EstablishLink();
566 }
Darin Petkovbac96002011-08-09 13:22:00 -0700567}
568
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400569void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700570 if (service_)
571 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500572}
573
Christopher Wiley8a468902012-11-30 11:52:38 -0800574void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700575 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500576 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100577 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500578 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100579 return;
580 }
Thieu Le26fc01b2013-01-28 12:08:48 -0800581 explicit_disconnect_ = true;
Thieu Le64b0fe52012-08-08 14:57:36 -0700582 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
Christopher Wiley8a468902012-11-30 11:52:38 -0800583 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400584 capability_->Disconnect(error, cb);
585}
586
Christopher Wiley8a468902012-11-30 11:52:38 -0800587void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700588 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Thieu Le26fc01b2013-01-28 12:08:48 -0800589 explicit_disconnect_ = false;
Thieu Leb7aa5f72013-01-31 15:57:48 -0800590 if (error.IsSuccess()) {
Nathan Williamsb54974f2012-04-19 11:16:30 -0400591 OnDisconnected();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800592 } else {
593 metrics()->NotifyCellularDeviceFailure(error);
Nathan Williamsb54974f2012-04-19 11:16:30 -0400594 OnDisconnectFailed();
Thieu Leb7aa5f72013-01-31 15:57:48 -0800595 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700596 manager()->TerminationActionComplete(FriendlyName());
597 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100598}
599
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500600void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700601 SLOG(Cellular, 2) << __func__;
Arman Uguray539c4232012-09-11 10:00:22 -0700602 if (!DisconnectCleanup()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500603 LOG(WARNING) << "Disconnect occurred while in state "
604 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400605 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500606}
607
608void Cellular::OnDisconnectFailed() {
Arman Uguray539c4232012-09-11 10:00:22 -0700609 SLOG(Cellular, 2) << __func__;
610 // If the modem is in the disconnecting state, then
611 // the disconnect should eventually succeed, so do
612 // nothing.
613 if (modem_state_ == kModemStateDisconnecting) {
614 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting.";
615 return;
616 }
617
618 // OnDisconnectFailed got called because no bearers
619 // to disconnect were found. Which means that we shouldn't
620 // really remain in the connected/linked state if we
621 // are in one of those.
622 if (!DisconnectCleanup()) {
623 // otherwise, no-op
624 LOG(WARNING) << "Ignoring failed disconnect while in state "
625 << GetStateString(state_);
626 }
627
628 // TODO(armansito): In either case, shill ends up thinking
629 // that it's disconnected, while for some reason the underlying
630 // modem might still actually be connected. In that case the UI
631 // would be reflecting an incorrect state and a further connection
632 // request would fail. We should perhaps tear down the modem and
633 // restart it here.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100634}
635
Darin Petkovbac96002011-08-09 13:22:00 -0700636void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700637 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700638 CHECK_EQ(kStateConnected, state_);
639 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700640 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700641 (flags & IFF_UP) != 0) {
642 LinkEvent(flags, IFF_UP);
643 return;
644 }
645 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700646 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Arman Uguray32c76402012-11-27 14:01:13 -0800647
648 // Set state to associating.
649 OnConnecting();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700650}
651
652void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
653 Device::LinkEvent(flags, change);
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700654 if (ppp_task_) {
655 LOG(INFO) << "Ignoring LinkEvent on device with PPP interface.";
656 return;
657 }
658
Darin Petkov0828f5f2011-08-11 10:18:52 -0700659 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700660 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700661 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800662 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700663 SelectService(service_);
664 SetServiceState(Service::kStateConfiguring);
665 } else {
666 LOG(ERROR) << "Unable to acquire DHCP config.";
667 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700668 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
Arman Uguray32c76402012-11-27 14:01:13 -0800669 LOG(INFO) << link_name() << " is down.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700670 SetState(kStateConnected);
Arman Uguray32c76402012-11-27 14:01:13 -0800671 DropConnection();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700672 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700673}
674
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400675void Cellular::OnDBusPropertiesChanged(
676 const string &interface,
677 const DBusPropertiesMap &changed_properties,
678 const vector<string> &invalidated_properties) {
679 capability_->OnDBusPropertiesChanged(interface,
680 changed_properties,
681 invalidated_properties);
682}
683
Darin Petkovae0c64e2011-11-15 15:50:27 +0100684void Cellular::set_home_provider(const Operator &oper) {
685 home_provider_.CopyFrom(oper);
686}
687
Darin Petkovac635a82012-01-10 16:51:58 +0100688string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700689 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100690 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
691}
692
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400693void Cellular::OnModemStateChanged(ModemState old_state,
694 ModemState new_state,
695 uint32 /*reason*/) {
696 if (old_state == new_state) {
697 return;
698 }
699 set_modem_state(new_state);
Thieu Le5218cf22012-11-26 11:52:57 -0800700 if (old_state >= kModemStateRegistered &&
701 new_state < kModemStateRegistered) {
702 capability_->SetUnregistered(new_state == kModemStateSearching);
703 HandleNewRegistrationState();
704 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400705 switch (new_state) {
706 case kModemStateDisabled:
707 SetEnabled(false);
708 break;
709 case kModemStateEnabled:
Thieu Le5218cf22012-11-26 11:52:57 -0800710 // Transition from Disabled to Enabled is handled in the
711 // DBusPropertiesChanged handler.
712 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Thieu Led0012052012-07-25 16:09:09 -0700713 // Intentionally falls through.
Thieu Le5218cf22012-11-26 11:52:57 -0800714 case kModemStateSearching:
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400715 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700716 // If the modem state changes from Connecting/Connected/Disconnecting
717 // to Registered/Enabled/Searching, then it's an indication that the
718 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400719 if (old_state == kModemStateConnected ||
720 old_state == kModemStateConnecting ||
721 old_state == kModemStateDisconnecting)
722 OnDisconnected();
723 break;
724 case kModemStateConnecting:
725 OnConnecting();
726 break;
727 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700728 if (old_state == kModemStateConnecting)
729 OnConnected();
730 else
731 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400732 break;
733 default:
734 break;
735 }
736}
737
Christopher Wiley1582bdd2012-11-15 11:31:14 -0800738bool Cellular::IsActivating() const {
739 return capability_->IsActivating();
740}
741
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700742bool Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
Jason Glasgow7b461df2012-05-01 16:38:45 -0400743 SLOG(Cellular, 2) << __func__
744 << "(" << allow_roaming_ << "->" << value << ")";
745 if (allow_roaming_ == value) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700746 return false;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400747 }
748 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200749 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400750
751 // Use AllowRoaming() instead of allow_roaming_ in order to
752 // incorporate provider preferences when evaluating if a disconnect
753 // is required.
754 if (!capability_->AllowRoaming() &&
755 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
756 Error error;
757 Disconnect(&error);
758 }
759 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700760 return true;
Jason Glasgow7b461df2012-05-01 16:38:45 -0400761}
762
Gary Moraina9fb3252012-05-31 12:05:31 -0700763void Cellular::StartTermination() {
Darin Petkov3ec55342012-09-28 14:04:44 +0200764 LOG(INFO) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -0700765 Error error;
766 Disconnect(&error);
767}
768
Arman Uguray539c4232012-09-11 10:00:22 -0700769bool Cellular::DisconnectCleanup() {
Christopher Wiley8a468902012-11-30 11:52:38 -0800770 bool succeeded = false;
Arman Uguray539c4232012-09-11 10:00:22 -0700771 if (state_ == kStateConnected || state_ == kStateLinked) {
772 SetState(kStateRegistered);
773 SetServiceFailureSilent(Service::kFailureUnknown);
774 DestroyIPConfig();
Christopher Wiley8a468902012-11-30 11:52:38 -0800775 succeeded = true;
Arman Uguray539c4232012-09-11 10:00:22 -0700776 }
Christopher Wiley8a468902012-11-30 11:52:38 -0800777 capability_->DisconnectCleanup();
778 return succeeded;
Arman Uguray539c4232012-09-11 10:00:22 -0700779}
Gary Moraina9fb3252012-05-31 12:05:31 -0700780
mukesh agrawal9da07772013-05-15 14:15:17 -0700781void Cellular::StartPPP(const string &serial_device) {
mukesh agrawalfbc40d22013-06-28 00:25:13 -0700782 // Some PPP dongles also expose an Ethernet-like network device,
783 // using either cdc_ether, or cdc_ncm. dhcpcd may be running on that
784 // interface. If so, it will eventually time out, and cause us
785 // terminate the cellular connection. Avoid terminating the connection,
786 // by cancelling any such DHCP process.
787 DestroyIPConfig();
788
mukesh agrawal9da07772013-05-15 14:15:17 -0700789 base::Callback<void(pid_t, int)> death_callback(
790 Bind(&Cellular::OnPPPDied, weak_ptr_factory_.GetWeakPtr()));
791 vector<string> args;
792 map<string, string> environment;
793 Error error;
794 if (SLOG_IS_ON(PPP, 5)) {
795 args.push_back("debug");
796 }
797 args.push_back("nodetach");
798 args.push_back("nodefaultroute"); // Don't let pppd muck with routing table.
799 args.push_back("usepeerdns"); // Request DNS servers.
800 args.push_back("plugin"); // Goes with next arg.
801 args.push_back(PPPDevice::kPluginPath);
802 args.push_back(serial_device);
803 scoped_ptr<ExternalTask> new_ppp_task(
804 new ExternalTask(modem_info_->control_interface(),
805 modem_info_->glib(),
806 weak_ptr_factory_.GetWeakPtr(),
807 death_callback));
808 if (new_ppp_task->Start(
809 FilePath(PPPDevice::kDaemonPath), args, environment, &error)) {
810 LOG(INFO) << "Forked pppd process.";
811 ppp_task_ = new_ppp_task.Pass();
812 }
813}
814
815// called by |ppp_task_|
816void Cellular::GetLogin(string *user, string *password) {
817 LOG(INFO) << __func__;
mukesh agrawal3ffe52c2013-06-20 15:21:29 -0700818 if (!service()) {
819 LOG(ERROR) << __func__ << " with no service ";
820 return;
821 }
822 CHECK(user);
823 CHECK(password);
824 *user = service()->ppp_username();
825 *password = service()->ppp_password();
mukesh agrawal9da07772013-05-15 14:15:17 -0700826}
827
828// Called by |ppp_task_|.
829void Cellular::Notify(const string &reason,
830 const map<string, string> &dict) {
831 LOG(INFO) << __func__ << " " << reason << " on " << link_name();
832
833 if (reason != kPPPReasonConnect) {
834 DCHECK_EQ(kPPPReasonDisconnect, reason);
835 // DestroyLater, rather than while on stack.
836 ppp_task_.release()->DestroyLater(modem_info_->dispatcher());
837 // For now, assume PPP failures are due to authentication issues.
838 SetServiceFailure(Service::kFailurePPPAuth);
839 return;
840 }
841
842 string interface_name = PPPDevice::GetInterfaceName(dict);
843 DeviceInfo *device_info = modem_info_->manager()->device_info();
844 int interface_index = device_info->GetIndex(interface_name);
845 if (interface_index < 0) {
846 // TODO(quiche): Consider handling the race when the RTNL notification about
847 // the new PPP device has not been received yet. crbug.com/246832.
848 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
849 return;
850 }
851
852 if (!ppp_device_ || ppp_device_->interface_index() != interface_index) {
853 ppp_device_ = new PPPDevice(modem_info_->control_interface(),
854 modem_info_->dispatcher(),
855 modem_info_->metrics(),
856 modem_info_->manager(),
857 interface_name,
858 interface_index);
859 device_info->RegisterDevice(ppp_device_);
860 }
861
mukesh agrawal9da07772013-05-15 14:15:17 -0700862 CHECK(service_);
mukesh agrawal5d851b12013-07-11 14:09:41 -0700863 // For PPP, we only SelectService on the |ppp_device_|.
864 CHECK(!selected_service());
mukesh agrawal9da07772013-05-15 14:15:17 -0700865 const bool kBlackholeIPv6 = false;
866 ppp_device_->SetEnabled(true);
867 ppp_device_->SelectService(service_);
868 ppp_device_->UpdateIPConfigFromPPP(dict, kBlackholeIPv6);
869}
870
871void Cellular::OnPPPDied(pid_t pid, int exit) {
872 LOG(INFO) << __func__ << " on " << link_name();
873 Error error;
874 Disconnect(&error);
875}
876
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700877} // namespace shill