shill: Bring the interface up when the modem is connected.
BUG=chromium-os:18855
TEST=unit tests, tested on device
Change-Id: I91581fbedc959bf4dce63f09d64b920f12a14b53
Reviewed-on: http://gerrit.chromium.org/gerrit/5925
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 1fafe60..666b9f5 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -4,6 +4,9 @@
#include "shill/cellular.h"
+#include <netinet/in.h>
+#include <linux/if.h>
+
#include <string>
#include <utility>
#include <vector>
@@ -22,6 +25,7 @@
#include "shill/profile.h"
#include "shill/property_accessor.h"
#include "shill/proxy_factory.h"
+#include "shill/rtnl_handler.h"
#include "shill/shill_event.h"
using std::make_pair;
@@ -111,7 +115,6 @@
modem_state_(kModemStateUnknown),
dbus_owner_(owner),
dbus_path_(path),
- service_registered_(false),
task_factory_(this),
allow_roaming_(false),
prl_version_(0),
@@ -151,25 +154,35 @@
Cellular::~Cellular() {}
-std::string Cellular::GetTypeString() {
+string Cellular::GetTypeString() {
switch (type_) {
case kTypeGSM: return "CellularTypeGSM";
case kTypeCDMA: return "CellularTypeCDMA";
- default: return StringPrintf("CellularTypeUnknown-%d", type_);
+ default: NOTREACHED();
}
+ return StringPrintf("CellularTypeUnknown-%d", type_);
}
-std::string Cellular::GetStateString() {
+string Cellular::GetStateString() {
switch (state_) {
case kStateDisabled: return "CellularStateDisabled";
case kStateEnabled: return "CellularStateEnabled";
case kStateRegistered: return "CellularStateRegistered";
case kStateConnected: return "CellularStateConnected";
- default: return StringPrintf("CellularStateUnknown-%d", state_);
+ case kStateLinked: return "CellularStateLinked";
+ default: NOTREACHED();
}
+ return StringPrintf("CellularStateUnknown-%d", state_);
+}
+
+void Cellular::SetState(State state) {
+ VLOG(2) << "Current state: " << GetStateString();
+ state_ = state;
+ VLOG(2) << "New state: " << GetStateString();
}
void Cellular::Start() {
+ LOG(INFO) << "Start";
VLOG(2) << __func__ << ": " << GetStateString();
InitProxies();
EnableModem();
@@ -183,9 +196,6 @@
}
GetModemInfo();
GetModemRegistrationState();
- if (modem_state_ == kModemStateConnected) {
- EstablishLink();
- }
// TODO(petkov): Device::Start();
}
@@ -195,11 +205,13 @@
cdma_proxy_.reset();
manager_->DeregisterService(service_);
service_ = NULL; // Breaks a reference cycle.
- state_ = kStateDisabled;
+ SetState(kStateDisabled);
+ RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index_, 0, IFF_UP);
// TODO(petkov): Device::Stop();
}
void Cellular::InitProxies() {
+ LOG(INFO) << "InitProxies";
proxy_.reset(
ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
simple_proxy_.reset(
@@ -222,7 +234,7 @@
CHECK_EQ(kStateDisabled, state_);
// TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
proxy_->Enable(true);
- state_ = kStateEnabled;
+ SetState(kStateEnabled);
}
void Cellular::GetModemStatus() {
@@ -314,27 +326,39 @@
}
void Cellular::HandleNewRegistrationState() {
+ dispatcher_->PostTask(
+ task_factory_.NewRunnableMethod(
+ &Cellular::HandleNewRegistrationStateTask));
+}
+
+void Cellular::HandleNewRegistrationStateTask() {
VLOG(2) << __func__;
if (!IsModemRegistered()) {
service_ = NULL;
- if (state_ == kStateConnected || state_ == kStateRegistered) {
- state_ = kStateEnabled;
+ if (state_ == kStateLinked ||
+ state_ == kStateConnected ||
+ state_ == kStateRegistered) {
+ SetState(kStateEnabled);
}
return;
}
-
if (state_ == kStateEnabled) {
- state_ = kStateRegistered;
+ SetState(kStateRegistered);
}
if (!service_.get()) {
// For now, no endpoint is created. Revisit if necessary.
CreateService();
}
GetModemSignalQuality();
+ if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
+ SetState(kStateConnected);
+ EstablishLink();
+ }
// TODO(petkov): Update the service.
}
void Cellular::GetModemSignalQuality() {
+ VLOG(2) << __func__;
uint32 strength = 0;
switch (type_) {
case kTypeGSM:
@@ -349,6 +373,7 @@
}
uint32 Cellular::GetCDMASignalQuality() {
+ VLOG(2) << __func__;
CHECK_EQ(kTypeCDMA, type_);
// TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
return cdma_proxy_->GetSignalQuality();
@@ -368,6 +393,7 @@
}
void Cellular::CreateService() {
+ VLOG(2) << __func__;
CHECK(!service_.get());
service_ =
new CellularService(control_interface_, dispatcher_, manager_, this);
@@ -382,7 +408,8 @@
void Cellular::Connect() {
VLOG(2) << __func__;
- if (state_ == kStateConnected) {
+ if (state_ == kStateConnected ||
+ state_ == kStateLinked) {
return;
}
CHECK_EQ(kStateRegistered, state_);
@@ -409,14 +436,37 @@
VLOG(2) << __func__;
// TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
simple_proxy_->Connect(properties);
+ SetState(kStateConnected);
EstablishLink();
}
void Cellular::EstablishLink() {
VLOG(2) << __func__;
- CHECK_EQ(kStateRegistered, state_);
- state_ = kStateConnected;
- // TODO(petkov): Bring the network interface up.
+ CHECK_EQ(kStateConnected, state_);
+ unsigned int flags = 0;
+ if (manager_->device_info()->GetFlags(interface_index_, &flags) &&
+ (flags & IFF_UP) != 0) {
+ LinkEvent(flags, IFF_UP);
+ return;
+ }
+ // TODO(petkov): Provide a timeout for a failed link-up request.
+ RTNLHandler::GetInstance()->SetInterfaceFlags(
+ interface_index_, IFF_UP, IFF_UP);
+}
+
+void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
+ Device::LinkEvent(flags, change);
+ if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
+ LOG(INFO) << link_name_ << " is up.";
+ SetState(kStateLinked);
+ manager_->RegisterService(service_);
+ // TODO(petkov): For GSM, remember the APN.
+ // TODO(petkov): Acquire IP.
+ } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
+ SetState(kStateConnected);
+ manager_->DeregisterService(service_);
+ // TODO(petkov): Release IP.
+ }
}
void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,