blob: f5c7ce07fc88180fc719673cf841a5d4deb48ba1 [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>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070016#include <base/logging.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"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070025#include "shill/cellular_service.h"
26#include "shill/control_interface.h"
27#include "shill/device.h"
28#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070029#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070030#include "shill/event_dispatcher.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070031#include "shill/manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070032#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070033#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070034#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070035#include "shill/rtnl_handler.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070036#include "shill/scope_logger.h"
Jason Glasgow7b461df2012-05-01 16:38:45 -040037#include "shill/store_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080038#include "shill/technology.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070039
Eric Shienbrood3e20a232012-02-16 11:35:56 -050040using base::Bind;
Gary Moraina9fb3252012-05-31 12:05:31 -070041using base::Closure;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070042using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070043using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070044
45namespace shill {
46
Jason Glasgow7b461df2012-05-01 16:38:45 -040047// static
48const char Cellular::kAllowRoaming[] = "AllowRoaming";
49
Darin Petkov3335b372011-08-22 11:05:32 -070050Cellular::Operator::Operator() {
51 SetName("");
52 SetCode("");
53 SetCountry("");
54}
55
56Cellular::Operator::~Operator() {}
57
58void Cellular::Operator::CopyFrom(const Operator &oper) {
59 dict_ = oper.dict_;
60}
61
62const string &Cellular::Operator::GetName() const {
63 return dict_.find(flimflam::kOperatorNameKey)->second;
64}
65
66void Cellular::Operator::SetName(const string &name) {
67 dict_[flimflam::kOperatorNameKey] = name;
68}
69
70const string &Cellular::Operator::GetCode() const {
71 return dict_.find(flimflam::kOperatorCodeKey)->second;
72}
73
74void Cellular::Operator::SetCode(const string &code) {
75 dict_[flimflam::kOperatorCodeKey] = code;
76}
77
78const string &Cellular::Operator::GetCountry() const {
79 return dict_.find(flimflam::kOperatorCountryKey)->second;
80}
81
82void Cellular::Operator::SetCountry(const string &country) {
83 dict_[flimflam::kOperatorCountryKey] = country;
84}
85
86const Stringmap &Cellular::Operator::ToDict() const {
87 return dict_;
88}
89
Chris Masone3bd3c8c2011-06-13 08:20:26 -070090Cellular::Cellular(ControlInterface *control_interface,
91 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080092 Metrics *metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070093 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070094 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -070095 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -070096 int interface_index,
97 Type type,
98 const string &owner,
Jason Glasgowa585fc32012-06-06 11:04:09 -040099 const string &service,
Darin Petkov137884a2011-10-26 18:52:47 +0200100 const string &path,
Ben Chan3ecdf822012-08-06 12:29:23 -0700101 mobile_provider_db *provider_db,
102 ProxyFactory *proxy_factory)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700103 : Device(control_interface,
104 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -0800105 metrics,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700106 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700107 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700108 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -0800109 interface_index,
110 Technology::kCellular),
Thieu Le64b0fe52012-08-08 14:57:36 -0700111 weak_ptr_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700112 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700113 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700114 dbus_owner_(owner),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400115 dbus_service_(service),
Darin Petkove9d12e02011-07-27 15:09:37 -0700116 dbus_path_(path),
Jason Glasgow7b461df2012-05-01 16:38:45 -0400117 provider_db_(provider_db),
Ben Chan3ecdf822012-08-06 12:29:23 -0700118 proxy_factory_(proxy_factory),
Jason Glasgow7b461df2012-05-01 16:38:45 -0400119 allow_roaming_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700120 PropertyStore *store = this->mutable_store();
Jason Glasgowa585fc32012-06-06 11:04:09 -0400121 // TODO(jglasgow): kDBusConnectionProperty is deprecated.
Paul Stewartac4ac002011-08-26 12:04:26 -0700122 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
Jason Glasgowa585fc32012-06-06 11:04:09 -0400123 store->RegisterConstString(flimflam::kDBusServiceProperty, &dbus_service_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700124 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400125 HelpRegisterDerivedString(flimflam::kTechnologyFamilyProperty,
126 &Cellular::GetTechnologyFamily,
127 NULL);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400128 HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
129 &Cellular::GetAllowRoaming,
130 &Cellular::SetAllowRoaming);
Paul Stewartac4ac002011-08-26 12:04:26 -0700131 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700132 &home_provider_.ToDict());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500133 // For now, only a single capability is supported.
Ben Chan3ecdf822012-08-06 12:29:23 -0700134 InitCapability(type);
Chris Masoneb925cc82011-06-22 15:39:57 -0700135
Ben Chanfad4a0b2012-04-18 15:49:59 -0700136 SLOG(Cellular, 2) << "Cellular device " << this->link_name()
137 << " initialized.";
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700138}
139
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500140Cellular::~Cellular() {
141}
Darin Petkove9d12e02011-07-27 15:09:37 -0700142
Jason Glasgow7b461df2012-05-01 16:38:45 -0400143bool Cellular::Load(StoreInterface *storage) {
144 const string id = GetStorageIdentifier();
145 if (!storage->ContainsGroup(id)) {
146 LOG(WARNING) << "Device is not available in the persistent store: " << id;
147 return false;
148 }
149 storage->GetBool(id, kAllowRoaming, &allow_roaming_);
150 return Device::Load(storage);
151}
152
153bool Cellular::Save(StoreInterface *storage) {
154 const string id = GetStorageIdentifier();
155 storage->SetBool(id, kAllowRoaming, allow_roaming_);
156 return Device::Save(storage);
157}
158
Darin Petkovcc044422011-08-17 13:30:06 -0700159// static
160string Cellular::GetStateString(State state) {
161 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700162 case kStateDisabled: return "CellularStateDisabled";
163 case kStateEnabled: return "CellularStateEnabled";
164 case kStateRegistered: return "CellularStateRegistered";
165 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700166 case kStateLinked: return "CellularStateLinked";
167 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700168 }
Darin Petkovcc044422011-08-17 13:30:06 -0700169 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700170}
171
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400172string Cellular::GetTechnologyFamily(Error *error) {
173 return capability_->GetTypeString();
174}
175
Darin Petkov0828f5f2011-08-11 10:18:52 -0700176void Cellular::SetState(State state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700177 SLOG(Cellular, 2) << GetStateString(state_) << " -> "
178 << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700179 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700180}
181
Jason Glasgow7b461df2012-05-01 16:38:45 -0400182void Cellular::HelpRegisterDerivedBool(
183 const string &name,
184 bool(Cellular::*get)(Error *error),
185 void(Cellular::*set)(const bool &value, Error *error)) {
186 mutable_store()->RegisterDerivedBool(
187 name,
188 BoolAccessor(
189 new CustomAccessor<Cellular, bool>(this, get, set)));
190}
191
Eric Shienbrood0db6a9b2012-03-30 16:11:39 -0400192void Cellular::HelpRegisterDerivedString(
193 const string &name,
194 string(Cellular::*get)(Error *),
195 void(Cellular::*set)(const string&, Error *)) {
196 mutable_store()->RegisterDerivedString(
197 name,
198 StringAccessor(new CustomAccessor<Cellular, string>(this, get, set)));
199}
200
Eric Shienbrood9a245532012-03-07 14:20:39 -0500201void Cellular::Start(Error *error,
202 const EnabledStateChangedCallback &callback) {
Jason Glasgow4a490792012-04-10 15:02:05 -0400203 DCHECK(error);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700204 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500205 if (state_ != kStateDisabled) {
206 return;
207 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700208 ResultCallback cb = Bind(&Cellular::StartModemCallback,
209 weak_ptr_factory_.GetWeakPtr(),
210 callback);
211 capability_->StartModem(error, cb);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700212}
213
Eric Shienbrood9a245532012-03-07 14:20:39 -0500214void Cellular::Stop(Error *error,
215 const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700216 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le64b0fe52012-08-08 14:57:36 -0700217 ResultCallback cb = Bind(&Cellular::StopModemCallback,
218 weak_ptr_factory_.GetWeakPtr(),
219 callback);
220 capability_->StopModem(error, cb);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500221}
222
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400223bool Cellular::IsUnderlyingDeviceEnabled() const {
224 return IsEnabledModemState(modem_state_);
225}
226
Thieu Led0012052012-07-25 16:09:09 -0700227bool Cellular::IsModemRegistered() const {
228 return (modem_state_ == Cellular::kModemStateRegistered ||
229 modem_state_ == Cellular::kModemStateConnecting ||
230 modem_state_ == Cellular::kModemStateConnected);
231}
232
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400233// static
234bool Cellular::IsEnabledModemState(ModemState state) {
235 switch (state) {
236 case kModemStateUnknown:
237 case kModemStateDisabled:
238 case kModemStateInitializing:
239 case kModemStateLocked:
240 case kModemStateDisabling:
241 case kModemStateEnabling:
242 return false;
243 case kModemStateEnabled:
244 case kModemStateSearching:
245 case kModemStateRegistered:
246 case kModemStateDisconnecting:
247 case kModemStateConnecting:
248 case kModemStateConnected:
249 return true;
250 }
251 return false;
252}
253
Thieu Le37b90032012-05-15 15:18:41 -0700254void Cellular::StartModemCallback(const EnabledStateChangedCallback &callback,
255 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700256 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Gary Morainbaeefdf2012-04-30 14:53:35 -0700257 if (error.IsSuccess() && (state_ == kStateDisabled)) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500258 SetState(kStateEnabled);
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400259 // Registration state updates may have been ignored while the
260 // modem was not yet marked enabled.
261 HandleNewRegistrationState();
262 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500263 callback.Run(error);
264}
265
Thieu Le37b90032012-05-15 15:18:41 -0700266void Cellular::StopModemCallback(const EnabledStateChangedCallback &callback,
267 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700268 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Thieu Le37b90032012-05-15 15:18:41 -0700269 // Destroy the cellular service regardless of any errors that occur during
270 // the stop process since we do not know the state of the modem at this
271 // point.
272 DestroyService();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500273 if (state_ != kStateDisabled)
Eric Shienbrood9a245532012-03-07 14:20:39 -0500274 SetState(kStateDisabled);
275 callback.Run(error);
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700276}
277
Ben Chan3ecdf822012-08-06 12:29:23 -0700278void Cellular::InitCapability(Type type) {
Darin Petkov5f316f62011-11-18 12:10:26 +0100279 // TODO(petkov): Consider moving capability construction into a factory that's
280 // external to the Cellular class.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700281 SLOG(Cellular, 2) << __func__ << "(" << type << ")";
Darin Petkov5f316f62011-11-18 12:10:26 +0100282 switch (type) {
Darin Petkovdaf43862011-10-27 11:37:28 +0200283 case kTypeGSM:
Ben Chan3ecdf822012-08-06 12:29:23 -0700284 capability_.reset(new CellularCapabilityGSM(this, proxy_factory_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200285 break;
286 case kTypeCDMA:
Ben Chan3ecdf822012-08-06 12:29:23 -0700287 capability_.reset(new CellularCapabilityCDMA(this, proxy_factory_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200288 break;
David Rochbergfa1d31d2012-03-20 10:38:07 -0400289 case kTypeUniversal:
Ben Chan3ecdf822012-08-06 12:29:23 -0700290 capability_.reset(new CellularCapabilityUniversal(this, proxy_factory_));
David Rochbergfa1d31d2012-03-20 10:38:07 -0400291 break;
Darin Petkovdaf43862011-10-27 11:37:28 +0200292 default: NOTREACHED();
293 }
294}
295
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400296void Cellular::Activate(const string &carrier,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500297 Error *error, const ResultCallback &callback) {
298 capability_->Activate(carrier, error, callback);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700299}
300
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500301void Cellular::RegisterOnNetwork(const string &network_id,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500302 Error *error,
303 const ResultCallback &callback) {
304 capability_->RegisterOnNetwork(network_id, error, callback);
Darin Petkova3d3be52011-11-14 21:34:16 +0100305}
306
Eric Shienbrood9a245532012-03-07 14:20:39 -0500307void Cellular::RequirePIN(const string &pin, bool require,
308 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700309 SLOG(Cellular, 2) << __func__ << "(" << require << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500310 capability_->RequirePIN(pin, require, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700311}
312
Eric Shienbrood9a245532012-03-07 14:20:39 -0500313void Cellular::EnterPIN(const string &pin,
314 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700315 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500316 capability_->EnterPIN(pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700317}
318
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100319void Cellular::UnblockPIN(const string &unblock_code,
320 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500321 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700322 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500323 capability_->UnblockPIN(unblock_code, pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700324}
325
Eric Shienbrood9a245532012-03-07 14:20:39 -0500326void Cellular::ChangePIN(const string &old_pin, const string &new_pin,
327 Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700328 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500329 capability_->ChangePIN(old_pin, new_pin, error, callback);
Darin Petkove42e1012011-08-31 12:35:04 -0700330}
331
Eric Shienbrood9a245532012-03-07 14:20:39 -0500332void Cellular::Scan(Error *error) {
333 // TODO(ers): for now report immediate success or failure.
334 capability_->Scan(error, ResultCallback());
Darin Petkovceb68172011-07-29 14:47:48 -0700335}
336
Darin Petkovd9661952011-08-03 16:25:42 -0700337void Cellular::HandleNewRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700338 SLOG(Cellular, 2) << __func__ << ": " << GetStateString(state_);
Darin Petkovb72cf402011-11-22 14:51:39 +0100339 if (!capability_->IsRegistered()) {
Darin Petkov2c377382012-01-11 11:40:43 +0100340 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700341 if (state_ == kStateLinked ||
342 state_ == kStateConnected ||
343 state_ == kStateRegistered) {
344 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700345 }
346 return;
347 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500348 // In Disabled state, defer creating a service until fully
349 // enabled. UI will ignore the appearance of a new service
350 // on a disabled device.
351 if (state_ == kStateDisabled) {
352 return;
353 }
Darin Petkovd9661952011-08-03 16:25:42 -0700354 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700355 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700356 }
357 if (!service_.get()) {
Darin Petkovd9661952011-08-03 16:25:42 -0700358 CreateService();
359 }
Darin Petkov3e509242011-11-10 14:46:44 +0100360 capability_->GetSignalQuality();
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500361 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected)
362 OnConnected();
Darin Petkovb72cf402011-11-22 14:51:39 +0100363 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString());
364 service_->SetRoamingState(capability_->GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700365}
366
Darin Petkovd9661952011-08-03 16:25:42 -0700367void Cellular::HandleNewSignalQuality(uint32 strength) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700368 SLOG(Cellular, 2) << "Signal strength: " << strength;
Darin Petkovd78ee7e2012-01-12 11:21:10 +0100369 if (service_) {
370 service_->SetStrength(strength);
Darin Petkovd9661952011-08-03 16:25:42 -0700371 }
372}
373
374void Cellular::CreateService() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700375 SLOG(Cellular, 2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700376 CHECK(!service_.get());
377 service_ =
Thieu Le3426c8f2012-01-11 17:35:11 -0800378 new CellularService(control_interface(), dispatcher(), metrics(),
379 manager(), this);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100380 capability_->OnServiceCreated();
Darin Petkov31332412012-01-28 01:50:02 +0100381 manager()->RegisterService(service_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700382}
383
Darin Petkov2c377382012-01-11 11:40:43 +0100384void Cellular::DestroyService() {
Darin Petkova0a0efe2012-06-27 12:50:01 +0200385 LOG(INFO) << "Destroying service for device " << link_name();
Darin Petkov2c377382012-01-11 11:40:43 +0100386 DestroyIPConfig();
387 if (service_) {
388 manager()->DeregisterService(service_);
389 service_ = NULL;
390 }
391 SelectService(NULL);
392}
393
Darin Petkov4d6d9412011-08-24 13:19:54 -0700394void Cellular::Connect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700395 SLOG(Cellular, 2) << __func__;
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400396 if (state_ == kStateConnected || state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700397 Error::PopulateAndLog(error, Error::kAlreadyConnected,
398 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700399 return;
400 }
401 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700402
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400403 if (!capability_->AllowRoaming() &&
Darin Petkovd2045802011-08-23 11:09:25 -0700404 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700405 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
406 "Roaming disallowed; connection request ignored.");
Darin Petkovd2045802011-08-23 11:09:25 -0700407 return;
408 }
409
Darin Petkovc5f56562011-08-06 16:40:05 -0700410 DBusPropertiesMap properties;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100411 capability_->SetupConnectProperties(&properties);
Thieu Le64b0fe52012-08-08 14:57:36 -0700412 ResultCallback cb = Bind(&Cellular::OnConnectReply,
413 weak_ptr_factory_.GetWeakPtr());
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400414 OnConnecting();
Nathan Williamsb54974f2012-04-19 11:16:30 -0400415 capability_->Connect(properties, error, cb);
416}
417
418// Note that there's no ResultCallback argument to this,
419// since Connect() isn't yet passed one.
420void Cellular::OnConnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700421 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400422 if (error.IsSuccess())
423 OnConnected();
424 else
425 OnConnectFailed(error);
Darin Petkovc5f56562011-08-06 16:40:05 -0700426}
427
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400428void Cellular::OnConnecting() {
429 if (service_)
430 service_->SetState(Service::kStateAssociating);
431}
432
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500433void Cellular::OnConnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700434 SLOG(Cellular, 2) << __func__;
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400435 if (state_ == kStateConnected || state_ == kStateLinked) {
436 VLOG(2) << "Already connected";
437 return;
438 }
Gary Moraina9fb3252012-05-31 12:05:31 -0700439 Closure start_cb = Bind(&Cellular::StartTermination, this);
440 manager()->AddTerminationAction(FriendlyName(), start_cb);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700441 SetState(kStateConnected);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400442 if (!capability_->AllowRoaming() &&
Darin Petkov9c1dcef2012-02-07 15:58:26 +0100443 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
444 Disconnect(NULL);
445 } else {
446 EstablishLink();
447 }
Darin Petkovbac96002011-08-09 13:22:00 -0700448}
449
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400450void Cellular::OnConnectFailed(const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700451 if (service_)
452 service_->SetFailure(Service::kFailureUnknown);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500453}
454
Darin Petkovfb0625e2012-01-16 13:05:56 +0100455void Cellular::Disconnect(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700456 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500457 if (state_ != kStateConnected && state_ != kStateLinked) {
Darin Petkovfb0625e2012-01-16 13:05:56 +0100458 Error::PopulateAndLog(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500459 error, Error::kNotConnected, "Not connected; request ignored.");
Darin Petkovfb0625e2012-01-16 13:05:56 +0100460 return;
461 }
Thieu Le64b0fe52012-08-08 14:57:36 -0700462 ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
463 weak_ptr_factory_.GetWeakPtr());
Nathan Williamsb54974f2012-04-19 11:16:30 -0400464 capability_->Disconnect(error, cb);
465}
466
467// Note that there's no ResultCallback argument to this,
468// since Disconnect() isn't yet passed one.
469void Cellular::OnDisconnectReply(const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700470 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400471 if (error.IsSuccess())
472 OnDisconnected();
473 else
474 OnDisconnectFailed();
Gary Moraina9fb3252012-05-31 12:05:31 -0700475 manager()->TerminationActionComplete(FriendlyName());
476 manager()->RemoveTerminationAction(FriendlyName());
Darin Petkovfb0625e2012-01-16 13:05:56 +0100477}
478
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500479void Cellular::OnDisconnected() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700480 SLOG(Cellular, 2) << __func__;
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400481 if (state_ == kStateConnected || state_ == kStateLinked) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500482 SetState(kStateRegistered);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400483 SetServiceFailureSilent(Service::kFailureUnknown);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400484 DestroyIPConfig();
485 rtnl_handler()->SetInterfaceFlags(interface_index(), 0, IFF_UP);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400486 } else {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500487 LOG(WARNING) << "Disconnect occurred while in state "
488 << GetStateString(state_);
Eric Shienbroodcc95c5d2012-03-30 15:25:49 -0400489 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500490}
491
492void Cellular::OnDisconnectFailed() {
493 // TODO(ers): Signal failure.
Darin Petkovfb0625e2012-01-16 13:05:56 +0100494}
495
Darin Petkovbac96002011-08-09 13:22:00 -0700496void Cellular::EstablishLink() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700497 SLOG(Cellular, 2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700498 CHECK_EQ(kStateConnected, state_);
499 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700500 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700501 (flags & IFF_UP) != 0) {
502 LinkEvent(flags, IFF_UP);
503 return;
504 }
505 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700506 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700507}
508
509void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
510 Device::LinkEvent(flags, change);
511 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700512 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700513 SetState(kStateLinked);
Paul Stewart2bf1d352011-12-06 15:02:55 -0800514 if (AcquireIPConfig()) {
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700515 SelectService(service_);
516 SetServiceState(Service::kStateConfiguring);
517 } else {
518 LOG(ERROR) << "Unable to acquire DHCP config.";
519 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700520 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
521 SetState(kStateConnected);
Darin Petkov2c377382012-01-11 11:40:43 +0100522 DestroyService();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700523 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700524}
525
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400526void Cellular::OnDBusPropertiesChanged(
527 const string &interface,
528 const DBusPropertiesMap &changed_properties,
529 const vector<string> &invalidated_properties) {
530 capability_->OnDBusPropertiesChanged(interface,
531 changed_properties,
532 invalidated_properties);
533}
534
Darin Petkovae0c64e2011-11-15 15:50:27 +0100535void Cellular::set_home_provider(const Operator &oper) {
536 home_provider_.CopyFrom(oper);
537}
538
Darin Petkovac635a82012-01-10 16:51:58 +0100539string Cellular::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700540 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100541 return capability_.get() ? capability_->CreateFriendlyServiceName() : "";
542}
543
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400544void Cellular::OnModemStateChanged(ModemState old_state,
545 ModemState new_state,
546 uint32 /*reason*/) {
547 if (old_state == new_state) {
548 return;
549 }
550 set_modem_state(new_state);
551 switch (new_state) {
552 case kModemStateDisabled:
553 SetEnabled(false);
554 break;
555 case kModemStateEnabled:
556 case kModemStateSearching:
557 // Note: we only handle changes to Enabled from the Registered
558 // state here. Changes from Disabled to Enabled are handled in
559 // the DBusPropertiesChanged handler.
560 if (old_state == kModemStateRegistered) {
561 capability_->SetUnregistered(new_state == kModemStateSearching);
562 HandleNewRegistrationState();
Jason Glasgow7234ec32012-05-23 16:01:21 -0400563 } else {
Thieu Led0012052012-07-25 16:09:09 -0700564 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Enabled";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400565 }
Thieu Led0012052012-07-25 16:09:09 -0700566 // Intentionally falls through.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400567 case kModemStateRegistered:
Thieu Led0012052012-07-25 16:09:09 -0700568 // If the modem state changes from Connecting/Connected/Disconnecting
569 // to Registered/Enabled/Searching, then it's an indication that the
570 // modem has been disconnected or got disconnected by the network.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400571 if (old_state == kModemStateConnected ||
572 old_state == kModemStateConnecting ||
573 old_state == kModemStateDisconnecting)
574 OnDisconnected();
575 break;
576 case kModemStateConnecting:
577 OnConnecting();
578 break;
579 case kModemStateConnected:
Thieu Led0012052012-07-25 16:09:09 -0700580 if (old_state == kModemStateConnecting)
581 OnConnected();
582 else
583 SLOG(Cellular, 2) << __func__ << ": Ignoring state change to Connected";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400584 break;
585 default:
586 break;
587 }
588}
589
Jason Glasgow7b461df2012-05-01 16:38:45 -0400590void Cellular::SetAllowRoaming(const bool &value, Error */*error*/) {
591 SLOG(Cellular, 2) << __func__
592 << "(" << allow_roaming_ << "->" << value << ")";
593 if (allow_roaming_ == value) {
594 return;
595 }
596 allow_roaming_ = value;
Darin Petkove7c6ad32012-06-29 10:22:09 +0200597 manager()->UpdateDevice(this);
Jason Glasgow7b461df2012-05-01 16:38:45 -0400598
599 // Use AllowRoaming() instead of allow_roaming_ in order to
600 // incorporate provider preferences when evaluating if a disconnect
601 // is required.
602 if (!capability_->AllowRoaming() &&
603 capability_->GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
604 Error error;
605 Disconnect(&error);
606 }
607 adaptor()->EmitBoolChanged(flimflam::kCellularAllowRoamingProperty, value);
608}
609
Gary Moraina9fb3252012-05-31 12:05:31 -0700610void Cellular::StartTermination() {
611 Error error;
612 Disconnect(&error);
613}
614
615
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700616} // namespace shill