shill: Add CellularCapabilityUniversal
Add the CellularCapabilityUniversal class so that shill can talk to a
ModemManager1 DBUS interface. Ensure that a modems can be created
with either the new or the old modem manager running.
Register to receive DBus property changes from ModemManager1
BUG=chromium-os:28596, chromium-os:26650
TEST=Run unit tests, test that modem is created with Y3300
Change-Id: I8717318e944589bc85e763bd7234336559256dbc
Reviewed-on: https://gerrit.chromium.org/gerrit/19888
Commit-Ready: Jason Glasgow <jglasgow@chromium.org>
Reviewed-by: Jason Glasgow <jglasgow@chromium.org>
Tested-by: Jason Glasgow <jglasgow@chromium.org>
diff --git a/Makefile b/Makefile
index f06688a..f6ef921 100644
--- a/Makefile
+++ b/Makefile
@@ -105,7 +105,9 @@
cellular.o \
cellular_capability.o \
cellular_capability_cdma.o \
+ cellular_capability_classic.o \
cellular_capability_gsm.o \
+ cellular_capability_universal.o \
cellular_error.o \
cellular_service.o \
connection.o \
@@ -212,8 +214,8 @@
async_connection_unittest.o \
byte_string_unittest.o \
cellular_capability_cdma_unittest.o \
+ cellular_capability_classic_unittest.o \
cellular_capability_gsm_unittest.o \
- cellular_capability_unittest.o \
cellular_service_unittest.o \
cellular_unittest.o \
crypto_des_cbc_unittest.o \
@@ -290,6 +292,7 @@
mock_vpn_service.o \
mock_wifi.o \
mock_wifi_service.o \
+ modem_1_unittest.o \
modem_info_unittest.o \
modem_manager_unittest.o \
modem_unittest.o \
diff --git a/cellular.cc b/cellular.cc
index d7058e6..34a4c3f 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -15,12 +15,12 @@
#include <base/logging.h>
#include <base/stringprintf.h>
#include <chromeos/dbus/service_constants.h>
-#include <mm/mm-modem.h>
#include <mobile_provider.h>
#include "shill/adaptor_interfaces.h"
#include "shill/cellular_capability_cdma.h"
#include "shill/cellular_capability_gsm.h"
+#include "shill/cellular_capability_universal.h"
#include "shill/cellular_service.h"
#include "shill/control_interface.h"
#include "shill/device.h"
@@ -35,8 +35,6 @@
#include "shill/technology.h"
using base::Bind;
-using base::Closure;
-using std::map;
using std::string;
using std::vector;
@@ -210,13 +208,13 @@
capability_.reset(new CellularCapabilityCDMA(this, proxy_factory));
break;
case kTypeUniversal:
- LOG(ERROR) << "Cannot InitCapability on MM1 modem";
+ capability_.reset(new CellularCapabilityUniversal(this, proxy_factory));
break;
default: NOTREACHED();
}
}
-void Cellular::Activate(const std::string &carrier,
+void Cellular::Activate(const string &carrier,
Error *error, const ResultCallback &callback) {
capability_->Activate(carrier, error, callback);
}
@@ -327,7 +325,7 @@
}
CHECK_EQ(kStateRegistered, state_);
- if (!capability_->allow_roaming() &&
+ if (!capability_->AllowRoaming() &&
service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
"Roaming disallowed; connection request ignored.");
@@ -344,7 +342,7 @@
void Cellular::OnConnected() {
VLOG(2) << __func__;
SetState(kStateConnected);
- if (!capability_->allow_roaming() &&
+ if (!capability_->AllowRoaming() &&
service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Disconnect(NULL);
} else {
@@ -413,6 +411,15 @@
}
}
+void Cellular::OnDBusPropertiesChanged(
+ const string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const vector<string> &invalidated_properties) {
+ capability_->OnDBusPropertiesChanged(interface,
+ changed_properties,
+ invalidated_properties);
+}
+
void Cellular::OnModemManagerPropertiesChanged(
const DBusPropertiesMap &properties) {
capability_->OnModemManagerPropertiesChanged(properties);
diff --git a/cellular.h b/cellular.h
index 1c31831..472fa48 100644
--- a/cellular.h
+++ b/cellular.h
@@ -6,6 +6,7 @@
#define SHILL_CELLULAR_
#include <string>
+#include <vector>
#include <base/basictypes.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
@@ -143,6 +144,10 @@
// destroying or updating the CellularService.
void HandleNewRegistrationState();
+ virtual void OnDBusPropertiesChanged(
+ const std::string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const std::vector<std::string> &invalidated_properties);
virtual void OnModemManagerPropertiesChanged(
const DBusPropertiesMap &properties);
@@ -181,6 +186,7 @@
friend class CellularCapabilityTest;
friend class CellularCapabilityCDMATest;
friend class CellularCapabilityGSMTest;
+ friend class CellularServiceTest;
friend class ModemTest;
FRIEND_TEST(CellularCapabilityCDMATest, CreateFriendlyServiceName);
FRIEND_TEST(CellularCapabilityCDMATest, GetRegistrationState);
diff --git a/cellular_capability.cc b/cellular_capability.cc
index f5d7630..3259f93 100644
--- a/cellular_capability.cc
+++ b/cellular_capability.cc
@@ -10,20 +10,12 @@
#include "shill/cellular.h"
#include "shill/error.h"
#include "shill/property_accessor.h"
-#include "shill/proxy_factory.h"
-using base::Bind;
-using base::Callback;
using base::Closure;
using std::string;
namespace shill {
-const char CellularCapability::kConnectPropertyApn[] = "apn";
-const char CellularCapability::kConnectPropertyApnUsername[] = "username";
-const char CellularCapability::kConnectPropertyApnPassword[] = "password";
-const char CellularCapability::kConnectPropertyHomeOnly[] = "home_only";
-const char CellularCapability::kConnectPropertyPhoneNumber[] = "number";
const char CellularCapability::kPropertyIMSI[] = "imsi";
// All timeout values are in milliseconds
const int CellularCapability::kTimeoutActivate = 120000;
@@ -35,30 +27,12 @@
CellularCapability::CellularCapability(Cellular *cellular,
ProxyFactory *proxy_factory)
- : allow_roaming_(false),
- scanning_supported_(false),
- cellular_(cellular),
+ : cellular_(cellular),
proxy_factory_(proxy_factory),
- weak_ptr_factory_(this) {
- PropertyStore *store = cellular->mutable_store();
- store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
+ allow_roaming_(false) {
HelpRegisterDerivedBool(flimflam::kCellularAllowRoamingProperty,
&CellularCapability::GetAllowRoaming,
&CellularCapability::SetAllowRoaming);
- store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
- &scanning_supported_);
- store->RegisterConstString(flimflam::kEsnProperty, &esn_);
- store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
- &firmware_revision_);
- store->RegisterConstString(flimflam::kHardwareRevisionProperty,
- &hardware_revision_);
- store->RegisterConstString(flimflam::kImeiProperty, &imei_);
- store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
- store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
- store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
- store->RegisterConstString(flimflam::kMeidProperty, &meid_);
- store->RegisterConstString(flimflam::kMinProperty, &min_);
- store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
}
CellularCapability::~CellularCapability() {}
@@ -79,7 +53,11 @@
return;
}
allow_roaming_ = value;
- if (!value && GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
+ // Use AllowRoaming() instead of allow_roaming_ in order to
+ // incorporate provider preferences when evaluating if a disconnect
+ // is required.
+ if (!AllowRoaming() &&
+ GetRoamingStateString() == flimflam::kRoamingStateRoaming) {
Error error;
cellular()->Disconnect(&error);
}
@@ -108,34 +86,6 @@
callback.Run(error);
}
-void CellularCapability::InitProxies() {
- VLOG(2) << __func__;
- proxy_.reset(proxy_factory()->CreateModemProxy(
- cellular()->dbus_path(), cellular()->dbus_owner()));
- simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
- cellular()->dbus_path(), cellular()->dbus_owner()));
- proxy_->set_state_changed_callback(
- Bind(&CellularCapability::OnModemStateChangedSignal,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CellularCapability::ReleaseProxies() {
- VLOG(2) << __func__;
- proxy_.reset();
- simple_proxy_.reset();
-}
-
-void CellularCapability::FinishEnable(const ResultCallback &callback) {
- callback.Run(Error());
- GetRegistrationState();
- GetSignalQuality();
-}
-
-void CellularCapability::FinishDisable(const ResultCallback &callback) {
- ReleaseProxies();
- callback.Run(Error());
-}
-
void CellularCapability::OnUnsupportedOperation(
const char *operation,
Error *error) {
@@ -144,97 +94,6 @@
Error::PopulateAndLog(error, Error::kNotSupported, message);
}
-// always called from an async context
-void CellularCapability::EnableModem(const ResultCallback &callback) {
- VLOG(2) << __func__;
- CHECK(!callback.is_null());
- Error error;
- proxy_->Enable(true, &error, callback, kTimeoutEnable);
- if (error.IsFailure())
- callback.Run(error);
-}
-
-// always called from an async context
-void CellularCapability::DisableModem(const ResultCallback &callback) {
- VLOG(2) << __func__;
- CHECK(!callback.is_null());
- Error error;
- proxy_->Enable(false, &error, callback, kTimeoutDefault);
- if (error.IsFailure())
- callback.Run(error);
-}
-
-// always called from an async context
-void CellularCapability::GetModemStatus(const ResultCallback &callback) {
- VLOG(2) << __func__;
- CHECK(!callback.is_null());
- DBusPropertyMapCallback cb = Bind(&CellularCapability::OnGetModemStatusReply,
- weak_ptr_factory_.GetWeakPtr(), callback);
- Error error;
- simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
- if (error.IsFailure())
- callback.Run(error);
-}
-
-// always called from an async context
-void CellularCapability::GetModemInfo(const ResultCallback &callback) {
- VLOG(2) << __func__;
- CHECK(!callback.is_null());
- ModemInfoCallback cb = Bind(&CellularCapability::OnGetModemInfoReply,
- weak_ptr_factory_.GetWeakPtr(), callback);
- Error error;
- proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
- if (error.IsFailure())
- callback.Run(error);
-}
-
-void CellularCapability::StopModem(Error *error,
- const ResultCallback &callback) {
- VLOG(2) << __func__;
-
- CellularTaskList *tasks = new CellularTaskList();
- ResultCallback cb =
- Bind(&CellularCapability::StepCompletedCallback,
- weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
- ResultCallback cb_ignore_error =
- Bind(&CellularCapability::StepCompletedCallback,
- weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
- tasks->push_back(Bind(&CellularCapability::Disconnect,
- weak_ptr_factory_.GetWeakPtr(),
- static_cast<Error *>(NULL), cb_ignore_error));
- tasks->push_back(Bind(&CellularCapability::DisableModem,
- weak_ptr_factory_.GetWeakPtr(), cb));
- tasks->push_back(Bind(&CellularCapability::FinishDisable,
- weak_ptr_factory_.GetWeakPtr(), cb));
-
- RunNextStep(tasks);
-}
-
-void CellularCapability::Connect(const DBusPropertiesMap &properties,
- Error *error,
- const ResultCallback &callback) {
- VLOG(2) << __func__;
- ResultCallback cb = Bind(&CellularCapability::OnConnectReply,
- weak_ptr_factory_.GetWeakPtr(),
- callback);
- simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
-}
-
-void CellularCapability::Disconnect(Error *error,
- const ResultCallback &callback) {
- VLOG(2) << __func__;
- ResultCallback cb = Bind(&CellularCapability::OnDisconnectReply,
- weak_ptr_factory_.GetWeakPtr(),
- callback);
- proxy_->Disconnect(error, cb, kTimeoutDefault);
-}
-
-void CellularCapability::Activate(const string &/*carrier*/,
- Error *error,
- const ResultCallback &/*callback*/) {
- OnUnsupportedOperation(__func__, error);
-}
-
void CellularCapability::RegisterOnNetwork(
const string &/*network_id*/,
Error *error, const ResultCallback &/*callback*/) {
@@ -273,91 +132,4 @@
OnUnsupportedOperation(__func__, error);
}
-void CellularCapability::OnGetModemStatusReply(
- const ResultCallback &callback,
- const DBusPropertiesMap &props,
- const Error &error) {
- VLOG(2) << __func__ << " " << props.size() << " props. error " << error;
- if (error.IsSuccess()) {
- DBusProperties::GetString(props, "carrier", &carrier_);
- DBusProperties::GetString(props, "meid", &meid_);
- DBusProperties::GetString(props, "imei", &imei_);
- DBusProperties::GetString(props, kPropertyIMSI, &imsi_);
- DBusProperties::GetString(props, "esn", &esn_);
- DBusProperties::GetString(props, "mdn", &mdn_);
- DBusProperties::GetString(props, "min", &min_);
- DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
-
- uint32 state;
- if (DBusProperties::GetUint32(props, "state", &state))
- cellular()->set_modem_state(static_cast<Cellular::ModemState>(state));
-
- UpdateStatus(props);
- }
- callback.Run(error);
-}
-
-void CellularCapability::OnGetModemInfoReply(
- const ResultCallback &callback,
- const ModemHardwareInfo &info,
- const Error &error) {
- VLOG(2) << __func__ << "(" << error << ")";
- if (error.IsSuccess()) {
- manufacturer_ = info._1;
- model_id_ = info._2;
- hardware_revision_ = info._3;
- VLOG(2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
- << info._3;
- }
- callback.Run(error);
-}
-
-// TODO(ers): use the supplied callback when Connect is fully asynchronous
-void CellularCapability::OnConnectReply(const ResultCallback &callback,
- const Error &error) {
- VLOG(2) << __func__ << "(" << error << ")";
- if (error.IsSuccess())
- cellular()->OnConnected();
- else
- cellular()->OnConnectFailed(error);
- if (!callback.is_null())
- callback.Run(error);
-}
-
-// TODO(ers): use the supplied callback when Disonnect is fully asynchronous
-void CellularCapability::OnDisconnectReply(const ResultCallback &callback,
- const Error &error) {
- VLOG(2) << __func__ << "(" << error << ")";
- if (error.IsSuccess())
- cellular()->OnDisconnected();
- else
- cellular()->OnDisconnectFailed();
- if (!callback.is_null())
- callback.Run(error);
-}
-
-void CellularCapability::OnModemStateChangedSignal(
- uint32 old_state, uint32 new_state, uint32 reason) {
- VLOG(2) << __func__ << "(" << old_state << ", " << new_state << ", "
- << reason << ")";
- // TODO(petkov): Complete this (crosbug.com/19662)
-#if 0
- modem_state_ = static_cast<ModemState>(new_state);
- if (old_state == new_state) {
- return;
- }
- switch (new_state) {
- case kModemStateEnabled:
- if (old_state == kModemStateDisabled ||
- old_state == kModemStateEnabling) {
- Start();
- }
- // TODO(petkov): Handle the case when the state is downgraded to Enabled.
- break;
- default:
- break;
- }
-#endif
-}
-
} // namespace shill
diff --git a/cellular_capability.h b/cellular_capability.h
index ef0060f..52b7b08 100644
--- a/cellular_capability.h
+++ b/cellular_capability.h
@@ -11,26 +11,56 @@
#include <base/basictypes.h>
#include <base/callback.h>
#include <base/memory/scoped_ptr.h>
-#include <base/memory/weak_ptr.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include "shill/callbacks.h"
#include "shill/dbus_properties.h"
-#include "shill/modem_proxy_interface.h"
-#include "shill/modem_simple_proxy_interface.h"
namespace shill {
class Cellular;
class Error;
-class EventDispatcher;
class ProxyFactory;
typedef std::vector<base::Closure> CellularTaskList;
// Cellular devices instantiate subclasses of CellularCapability that
// handle the specific modem technologies and capabilities.
+//
+// The CellularCapability is directly subclassed by:
+// * CelllularCapabilityUniversal which handles all modems managed by
+// a modem manager using the the org.chromium.ModemManager1 DBUS
+// interface
+// * CellularCapabilityClassic which handles all modems managed by a
+// modem manager using the older org.chromium.ModemManager DBUS
+// interface. This class is further subclassed to represent CDMA
+// and GSM modems
+//
+// Pictorially:
+//
+// CellularCapability
+// |
+// |-- CellularCapabilityUniversal
+// |
+// |-- CellularCapabilityClassic
+// |
+// |-- CellularCapabilityGSM
+// |
+// |-- CellularCapabilityCDMA
+//
class CellularCapability {
public:
+
+ // SimLockStatus represents the fields in the Cellular.SIMLockStatus
+ // DBUS property of the shill device.
+ struct SimLockStatus {
+ SimLockStatus() : enabled(false), retries_left(0) {}
+
+ bool enabled;
+ std::string lock_type;
+ uint32 retries_left;
+ };
+
static const int kTimeoutActivate;
static const int kTimeoutConnect;
static const int kTimeoutDefault;
@@ -38,14 +68,8 @@
static const int kTimeoutRegister;
static const int kTimeoutScan;
- static const char kConnectPropertyApn[];
- static const char kConnectPropertyApnUsername[];
- static const char kConnectPropertyApnPassword[];
- static const char kConnectPropertyHomeOnly[];
- static const char kConnectPropertyPhoneNumber[];
static const char kPropertyIMSI[];
-
// |cellular| is the parent Cellular device.
CellularCapability(Cellular *cellular, ProxyFactory *proxy_factory);
virtual ~CellularCapability();
@@ -60,8 +84,6 @@
virtual void SetupConnectProperties(DBusPropertiesMap *properties) = 0;
- bool allow_roaming() const { return allow_roaming_; }
-
// StartModem attempts to put the modem in a state in which it is
// usable for creating services and establishing connections (if
// network conditions permit). It potentially consists of multiple
@@ -75,21 +97,21 @@
// StopModem disconnects and disables a modem asynchronously.
// |callback| is invoked when this completes and the result is passed
// to the callback.
- virtual void StopModem(Error *error, const ResultCallback &callback);
+ virtual void StopModem(Error *error, const ResultCallback &callback) = 0;
virtual void Connect(const DBusPropertiesMap &properties, Error *error,
- const ResultCallback &callback);
- virtual void Disconnect(Error *error, const ResultCallback &callback);
+ const ResultCallback &callback) = 0;
+ virtual void Disconnect(Error *error, const ResultCallback &callback) = 0;
// Activates the modem. Returns an Error on failure.
// The default implementation fails by returning a kNotSupported error
// to the caller.
virtual void Activate(const std::string &carrier,
- Error *error, const ResultCallback &callback);
+ Error *error, const ResultCallback &callback) = 0;
// Network registration.
virtual void RegisterOnNetwork(const std::string &network_id,
Error *error,
- const ResultCallback &callback);
+ const ResultCallback &callback) = 0;
virtual bool IsRegistered() = 0;
virtual std::string CreateFriendlyServiceName() = 0;
@@ -106,8 +128,25 @@
const std::string &new_pin,
Error *error, const ResultCallback &callback);
- // Network scanning. The default implementation fails by invoking
- // the reply handler with an error.
+ // Asks the modem to scan for networks.
+ //
+ // The default implementation fails by filling error with
+ // kNotSupported.
+ //
+ // Subclasses should implement this by fetching scan results
+ // asynchronously. When the results are ready, update the
+ // flimflam::kFoundNetworksProperty and send a property change
+ // notification. Finally, callback must be invoked to inform the
+ // caller that the scan has completed.
+ //
+ // Errors are not generally reported, but on error the
+ // kFoundNetworksProperty should be cleared and a property change
+ // notification sent out.
+ //
+ // TODO(jglasgow): Refactor to reuse code by putting notification
+ // logic into Cellular or CellularCapability.
+ //
+ // TODO(jglasgow): Implement real error handling.
virtual void Scan(Error *error, const ResultCallback &callback);
// Returns an empty string if the network technology is unknown.
@@ -119,31 +158,29 @@
virtual std::string GetTypeString() const = 0;
+ virtual void OnDBusPropertiesChanged(
+ const std::string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const std::vector<std::string> &invalidated_properties) = 0;
virtual void OnModemManagerPropertiesChanged(
const DBusPropertiesMap &properties) = 0;
- protected:
- // The following five methods are only ever called as
- // callbacks (from the main loop), which is why they
- // don't take an Error * argument.
- virtual void EnableModem(const ResultCallback &callback);
- virtual void DisableModem(const ResultCallback &callback);
- virtual void GetModemStatus(const ResultCallback &callback);
- virtual void GetModemInfo(const ResultCallback &callback);
- virtual void GetProperties(const ResultCallback &callback) = 0;
+ // Should this device allow roaming?
+ // The decision to allow roaming or not is based on the home
+ // provider as well as on the user modifiable "allow_roaming"
+ // property.
+ virtual bool AllowRoaming() = 0;
+ protected:
virtual void GetRegistrationState() = 0;
- void FinishEnable(const ResultCallback &callback);
- void FinishDisable(const ResultCallback &callback);
- virtual void InitProxies();
- virtual void ReleaseProxies();
+ // Releases all proxies held by the object. This is most useful
+ // during unit tests.
+ virtual void ReleaseProxies() = 0;
static void OnUnsupportedOperation(const char *operation, Error *error);
- virtual void OnConnectReply(const ResultCallback &callback,
- const Error &error);
- // Run the next task in a list.
+ // Runs the next task in a list.
// Precondition: |tasks| is not empty.
void RunNextStep(CellularTaskList *tasks);
// StepCompletedCallback is called after a task completes.
@@ -154,73 +191,34 @@
// the result of the just-completed task.
void StepCompletedCallback(const ResultCallback &callback, bool ignore_error,
CellularTaskList *tasks, const Error &error);
- // Properties
- bool allow_roaming_;
- bool scanning_supported_;
- std::string carrier_;
- std::string meid_;
- std::string imei_;
- std::string imsi_;
- std::string esn_;
- std::string mdn_;
- std::string min_;
- std::string model_id_;
- std::string manufacturer_;
- std::string firmware_revision_;
- std::string hardware_revision_;
+
+ // accessor for subclasses to read the allow roaming property
+ bool allow_roaming_property() const { return allow_roaming_; }
private:
friend class CellularCapabilityGSMTest;
friend class CellularCapabilityTest;
friend class CellularTest;
- FRIEND_TEST(CellularCapabilityGSMTest, SetStorageIdentifier);
- FRIEND_TEST(CellularCapabilityGSMTest, UpdateStatus);
FRIEND_TEST(CellularCapabilityTest, AllowRoaming);
- FRIEND_TEST(CellularCapabilityTest, EnableModemFail);
- FRIEND_TEST(CellularCapabilityTest, EnableModemSucceed);
- FRIEND_TEST(CellularCapabilityTest, FinishEnable);
- FRIEND_TEST(CellularCapabilityTest, GetModemInfo);
- FRIEND_TEST(CellularCapabilityTest, GetModemStatus);
- FRIEND_TEST(CellularCapabilityTest, TryApns);
- FRIEND_TEST(CellularServiceTest, FriendlyName);
- FRIEND_TEST(CellularTest, StartCDMARegister);
- FRIEND_TEST(CellularTest, StartConnected);
- FRIEND_TEST(CellularTest, StartGSMRegister);
- FRIEND_TEST(CellularTest, StartLinked);
FRIEND_TEST(CellularTest, Connect);
- FRIEND_TEST(CellularTest, ConnectFailure);
- FRIEND_TEST(CellularTest, Disconnect);
+ FRIEND_TEST(CellularTest, TearDown);
void HelpRegisterDerivedBool(
const std::string &name,
bool(CellularCapability::*get)(Error *error),
void(CellularCapability::*set)(const bool &value, Error *error));
+ // DBUS accessors to read/modify the allow roaming property
bool GetAllowRoaming(Error */*error*/) { return allow_roaming_; }
void SetAllowRoaming(const bool &value, Error *error);
- // Method reply and signal callbacks from Modem interface
- virtual void OnModemStateChangedSignal(
- uint32 old_state, uint32 new_state, uint32 reason);
- virtual void OnGetModemInfoReply(const ResultCallback &callback,
- const ModemHardwareInfo &info,
- const Error &error);
-
- // Method reply callbacks from Modem.Simple interface
- virtual void OnGetModemStatusReply(const ResultCallback &callback,
- const DBusPropertiesMap &props,
- const Error &error);
- virtual void OnDisconnectReply(const ResultCallback &callback,
- const Error &error);
-
Cellular *cellular_;
// Store cached copies of singletons for speed/ease of testing.
ProxyFactory *proxy_factory_;
- scoped_ptr<ModemProxyInterface> proxy_;
- scoped_ptr<ModemSimpleProxyInterface> simple_proxy_;
- base::WeakPtrFactory<CellularCapability> weak_ptr_factory_;
+ // User preference to allow or disallow roaming
+ bool allow_roaming_;
DISALLOW_COPY_AND_ASSIGN(CellularCapability);
};
diff --git a/cellular_capability_cdma.cc b/cellular_capability_cdma.cc
index 1db4837..801f688 100644
--- a/cellular_capability_cdma.cc
+++ b/cellular_capability_cdma.cc
@@ -26,7 +26,7 @@
CellularCapabilityCDMA::CellularCapabilityCDMA(Cellular *cellular,
ProxyFactory *proxy_factory)
- : CellularCapability(cellular, proxy_factory),
+ : CellularCapabilityClassic(cellular, proxy_factory),
weak_ptr_factory_(this),
activation_state_(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
registration_state_evdo_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
@@ -38,7 +38,7 @@
}
void CellularCapabilityCDMA::InitProxies() {
- CellularCapability::InitProxies();
+ CellularCapabilityClassic::InitProxies();
proxy_.reset(proxy_factory()->CreateModemCDMAProxy(
cellular()->dbus_path(), cellular()->dbus_owner()));
proxy_->set_signal_quality_callback(
@@ -76,10 +76,15 @@
}
void CellularCapabilityCDMA::ReleaseProxies() {
- CellularCapability::ReleaseProxies();
+ CellularCapabilityClassic::ReleaseProxies();
proxy_.reset();
}
+bool CellularCapabilityCDMA::AllowRoaming() {
+ return allow_roaming_property();
+}
+
+
void CellularCapabilityCDMA::OnServiceCreated() {
VLOG(2) << __func__;
cellular()->service()->SetOLP(olp_);
diff --git a/cellular_capability_cdma.h b/cellular_capability_cdma.h
index 1dc2cf2..d38dca3 100644
--- a/cellular_capability_cdma.h
+++ b/cellular_capability_cdma.h
@@ -9,13 +9,16 @@
#include <base/memory/weak_ptr.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include <string>
+
#include "shill/cellular_capability.h"
+#include "shill/cellular_capability_classic.h"
#include "shill/cellular_service.h"
#include "shill/modem_cdma_proxy_interface.h"
namespace shill {
-class CellularCapabilityCDMA : public CellularCapability {
+class CellularCapabilityCDMA : public CellularCapabilityClassic {
public:
CellularCapabilityCDMA(Cellular *cellular, ProxyFactory *proxy_factory);
@@ -46,6 +49,7 @@
protected:
virtual void InitProxies();
virtual void ReleaseProxies();
+ virtual bool AllowRoaming();
private:
friend class CellularCapabilityCDMATest;
diff --git a/cellular_capability_classic.cc b/cellular_capability_classic.cc
new file mode 100644
index 0000000..be8a9ae
--- /dev/null
+++ b/cellular_capability_classic.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/cellular_capability_classic.h"
+
+#include <base/bind.h>
+#include <chromeos/dbus/service_constants.h>
+
+#include "shill/cellular.h"
+#include "shill/error.h"
+#include "shill/property_accessor.h"
+#include "shill/proxy_factory.h"
+
+using base::Bind;
+using base::Callback;
+using base::Closure;
+using std::string;
+
+namespace shill {
+
+const char CellularCapabilityClassic::kConnectPropertyApn[] = "apn";
+const char CellularCapabilityClassic::kConnectPropertyApnUsername[] =
+ "username";
+const char CellularCapabilityClassic::kConnectPropertyApnPassword[] =
+ "password";
+const char CellularCapabilityClassic::kConnectPropertyHomeOnly[] = "home_only";
+const char CellularCapabilityClassic::kConnectPropertyPhoneNumber[] = "number";
+
+CellularCapabilityClassic::CellularCapabilityClassic(
+ Cellular *cellular,
+ ProxyFactory *proxy_factory)
+ : CellularCapability(cellular, proxy_factory),
+ weak_ptr_factory_(this) {
+ PropertyStore *store = cellular->mutable_store();
+ store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
+ store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
+ &scanning_supported_);
+ store->RegisterConstString(flimflam::kEsnProperty, &esn_);
+ store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
+ &firmware_revision_);
+ store->RegisterConstString(flimflam::kHardwareRevisionProperty,
+ &hardware_revision_);
+ store->RegisterConstString(flimflam::kImeiProperty, &imei_);
+ store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
+ store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
+ store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
+ store->RegisterConstString(flimflam::kMeidProperty, &meid_);
+ store->RegisterConstString(flimflam::kMinProperty, &min_);
+ store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
+}
+
+CellularCapabilityClassic::~CellularCapabilityClassic() {}
+
+void CellularCapabilityClassic::InitProxies() {
+ VLOG(2) << __func__;
+ proxy_.reset(proxy_factory()->CreateModemProxy(
+ cellular()->dbus_path(), cellular()->dbus_owner()));
+ simple_proxy_.reset(proxy_factory()->CreateModemSimpleProxy(
+ cellular()->dbus_path(), cellular()->dbus_owner()));
+ proxy_->set_state_changed_callback(
+ Bind(&CellularCapabilityClassic::OnModemStateChangedSignal,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CellularCapabilityClassic::ReleaseProxies() {
+ VLOG(2) << __func__;
+ proxy_.reset();
+ simple_proxy_.reset();
+}
+
+void CellularCapabilityClassic::FinishEnable(const ResultCallback &callback) {
+ callback.Run(Error());
+ GetRegistrationState();
+ GetSignalQuality();
+}
+
+void CellularCapabilityClassic::FinishDisable(const ResultCallback &callback) {
+ ReleaseProxies();
+ callback.Run(Error());
+}
+
+void CellularCapabilityClassic::OnUnsupportedOperation(
+ const char *operation,
+ Error *error) {
+ string message("The ");
+ message.append(operation).append(" operation is not supported.");
+ Error::PopulateAndLog(error, Error::kNotSupported, message);
+}
+
+// always called from an async context
+void CellularCapabilityClassic::EnableModem(const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ CHECK(!callback.is_null());
+ Error error;
+ proxy_->Enable(true, &error, callback, kTimeoutEnable);
+ if (error.IsFailure())
+ callback.Run(error);
+}
+
+// always called from an async context
+void CellularCapabilityClassic::DisableModem(const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ CHECK(!callback.is_null());
+ Error error;
+ proxy_->Enable(false, &error, callback, kTimeoutDefault);
+ if (error.IsFailure())
+ callback.Run(error);
+}
+
+// always called from an async context
+void CellularCapabilityClassic::GetModemStatus(const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ CHECK(!callback.is_null());
+ DBusPropertyMapCallback cb = Bind(
+ &CellularCapabilityClassic::OnGetModemStatusReply,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ Error error;
+ simple_proxy_->GetModemStatus(&error, cb, kTimeoutDefault);
+ if (error.IsFailure())
+ callback.Run(error);
+}
+
+// always called from an async context
+void CellularCapabilityClassic::GetModemInfo(const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ CHECK(!callback.is_null());
+ ModemInfoCallback cb = Bind(&CellularCapabilityClassic::OnGetModemInfoReply,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ Error error;
+ proxy_->GetModemInfo(&error, cb, kTimeoutDefault);
+ if (error.IsFailure())
+ callback.Run(error);
+}
+
+void CellularCapabilityClassic::StopModem(Error *error,
+ const ResultCallback &callback) {
+ VLOG(2) << __func__;
+
+ CellularTaskList *tasks = new CellularTaskList();
+ ResultCallback cb =
+ Bind(&CellularCapabilityClassic::StepCompletedCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
+ ResultCallback cb_ignore_error =
+ Bind(&CellularCapabilityClassic::StepCompletedCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
+ tasks->push_back(Bind(&CellularCapabilityClassic::Disconnect,
+ weak_ptr_factory_.GetWeakPtr(),
+ static_cast<Error *>(NULL), cb_ignore_error));
+ tasks->push_back(Bind(&CellularCapabilityClassic::DisableModem,
+ weak_ptr_factory_.GetWeakPtr(), cb));
+ tasks->push_back(Bind(&CellularCapabilityClassic::FinishDisable,
+ weak_ptr_factory_.GetWeakPtr(), cb));
+
+ RunNextStep(tasks);
+}
+
+void CellularCapabilityClassic::Connect(const DBusPropertiesMap &properties,
+ Error *error,
+ const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ ResultCallback cb = Bind(&CellularCapabilityClassic::OnConnectReply,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback);
+ simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
+}
+
+void CellularCapabilityClassic::Disconnect(Error *error,
+ const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ ResultCallback cb = Bind(&CellularCapabilityClassic::OnDisconnectReply,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback);
+ proxy_->Disconnect(error, cb, kTimeoutDefault);
+}
+
+void CellularCapabilityClassic::Activate(const string &/*carrier*/,
+ Error *error,
+ const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::RegisterOnNetwork(
+ const string &/*network_id*/,
+ Error *error, const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::RequirePIN(const std::string &/*pin*/,
+ bool /*require*/,
+ Error *error,
+ const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::EnterPIN(const string &/*pin*/,
+ Error *error,
+ const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::UnblockPIN(const string &/*unblock_code*/,
+ const string &/*pin*/,
+ Error *error,
+ const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::ChangePIN(const string &/*old_pin*/,
+ const string &/*new_pin*/,
+ Error *error,
+ const ResultCallback &/*callback*/) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::Scan(Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityClassic::OnDBusPropertiesChanged(
+ const std::string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const std::vector<std::string> &invalidated_properties) {
+ DCHECK(false) << "Unexpected call to OnDBusPropertiesChanged.";
+}
+
+void CellularCapabilityClassic::OnGetModemStatusReply(
+ const ResultCallback &callback,
+ const DBusPropertiesMap &props,
+ const Error &error) {
+ VLOG(2) << __func__ << " " << props.size() << " props. error " << error;
+ if (error.IsSuccess()) {
+ DBusProperties::GetString(props, "carrier", &carrier_);
+ DBusProperties::GetString(props, "meid", &meid_);
+ DBusProperties::GetString(props, "imei", &imei_);
+ DBusProperties::GetString(props, kPropertyIMSI, &imsi_);
+ DBusProperties::GetString(props, "esn", &esn_);
+ DBusProperties::GetString(props, "mdn", &mdn_);
+ DBusProperties::GetString(props, "min", &min_);
+ DBusProperties::GetString(props, "firmware_revision", &firmware_revision_);
+
+ uint32 state;
+ if (DBusProperties::GetUint32(props, "state", &state))
+ cellular()->set_modem_state(static_cast<Cellular::ModemState>(state));
+
+ UpdateStatus(props);
+ }
+ callback.Run(error);
+}
+
+void CellularCapabilityClassic::OnGetModemInfoReply(
+ const ResultCallback &callback,
+ const ModemHardwareInfo &info,
+ const Error &error) {
+ VLOG(2) << __func__ << "(" << error << ")";
+ if (error.IsSuccess()) {
+ manufacturer_ = info._1;
+ model_id_ = info._2;
+ hardware_revision_ = info._3;
+ VLOG(2) << __func__ << ": " << info._1 << ", " << info._2 << ", "
+ << info._3;
+ }
+ callback.Run(error);
+}
+
+// TODO(ers): use the supplied callback when Connect is fully asynchronous
+void CellularCapabilityClassic::OnConnectReply(const ResultCallback &callback,
+ const Error &error) {
+ VLOG(2) << __func__ << "(" << error << ")";
+ if (error.IsSuccess())
+ cellular()->OnConnected();
+ else
+ cellular()->OnConnectFailed(error);
+ if (!callback.is_null())
+ callback.Run(error);
+}
+
+// TODO(ers): use the supplied callback when Disonnect is fully asynchronous
+void CellularCapabilityClassic::OnDisconnectReply(
+ const ResultCallback &callback,
+ const Error &error) {
+ VLOG(2) << __func__ << "(" << error << ")";
+ if (error.IsSuccess())
+ cellular()->OnDisconnected();
+ else
+ cellular()->OnDisconnectFailed();
+ if (!callback.is_null())
+ callback.Run(error);
+}
+
+void CellularCapabilityClassic::OnModemStateChangedSignal(
+ uint32 old_state, uint32 new_state, uint32 reason) {
+ VLOG(2) << __func__ << "(" << old_state << ", " << new_state << ", "
+ << reason << ")";
+ // TODO(petkov): Complete this (crosbug.com/19662)
+#if 0
+ modem_state_ = static_cast<ModemState>(new_state);
+ if (old_state == new_state) {
+ return;
+ }
+ switch (new_state) {
+ case kModemStateEnabled:
+ if (old_state == kModemStateDisabled ||
+ old_state == kModemStateEnabling) {
+ Start();
+ }
+ // TODO(petkov): Handle the case when the state is downgraded to Enabled.
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+} // namespace shill
diff --git a/cellular_capability_classic.h b/cellular_capability_classic.h
new file mode 100644
index 0000000..a796ffa
--- /dev/null
+++ b/cellular_capability_classic.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_CELLULAR_CAPABILITY_CLASSIC_
+#define SHILL_CELLULAR_CAPABILITY_CLASSIC_
+
+#include <string>
+#include <vector>
+
+#include <base/basictypes.h>
+#include <base/callback.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/memory/weak_ptr.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+
+#include "shill/cellular_capability.h"
+#include "shill/dbus_properties.h"
+#include "shill/modem_proxy_interface.h"
+#include "shill/modem_simple_proxy_interface.h"
+
+namespace shill {
+
+class Cellular;
+class Error;
+class EventDispatcher;
+class ProxyFactory;
+
+// CellularCapabilityClassic handles modems using the
+// org.chromium.ModemManager DBUS interface.
+class CellularCapabilityClassic : public CellularCapability {
+ public:
+ static const char kConnectPropertyApn[];
+ static const char kConnectPropertyApnUsername[];
+ static const char kConnectPropertyApnPassword[];
+ static const char kConnectPropertyHomeOnly[];
+ static const char kConnectPropertyPhoneNumber[];
+
+ // |cellular| is the parent Cellular device.
+ CellularCapabilityClassic(Cellular *cellular, ProxyFactory *proxy_factory);
+ virtual ~CellularCapabilityClassic();
+
+ virtual void StopModem(Error *error, const ResultCallback &callback);
+ virtual void Connect(const DBusPropertiesMap &properties, Error *error,
+ const ResultCallback &callback);
+ virtual void Disconnect(Error *error, const ResultCallback &callback);
+
+ virtual void Activate(const std::string &carrier,
+ Error *error, const ResultCallback &callback);
+
+ // Network registration.
+ virtual void RegisterOnNetwork(const std::string &network_id,
+ Error *error,
+ const ResultCallback &callback);
+
+ // PIN management. The default implementation fails by returning an error.
+ virtual void RequirePIN(const std::string &pin, bool require,
+ Error *error, const ResultCallback &callback);
+ virtual void EnterPIN(const std::string &pin,
+ Error *error, const ResultCallback &callback);
+ virtual void UnblockPIN(const std::string &unblock_code,
+ const std::string &pin,
+ Error *error, const ResultCallback &callback);
+ virtual void ChangePIN(const std::string &old_pin,
+ const std::string &new_pin,
+ Error *error, const ResultCallback &callback);
+
+ virtual void Scan(Error *error, const ResultCallback &callback);
+
+ virtual void OnDBusPropertiesChanged(
+ const std::string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const std::vector<std::string> &invalidated_properties);
+
+ protected:
+ // The following five methods are only ever called as
+ // callbacks (from the main loop), which is why they
+ // don't take an Error * argument.
+ virtual void EnableModem(const ResultCallback &callback);
+ virtual void DisableModem(const ResultCallback &callback);
+ virtual void GetModemStatus(const ResultCallback &callback);
+ virtual void GetModemInfo(const ResultCallback &callback);
+ virtual void GetProperties(const ResultCallback &callback) = 0;
+
+ void FinishEnable(const ResultCallback &callback);
+ void FinishDisable(const ResultCallback &callback);
+ virtual void InitProxies();
+ virtual void ReleaseProxies();
+
+ static void OnUnsupportedOperation(const char *operation, Error *error);
+
+ virtual void OnConnectReply(const ResultCallback &callback,
+ const Error &error);
+
+ // Properties
+ bool scanning_supported_;
+ std::string meid_;
+ std::string imsi_;
+ std::string imei_;
+ std::string esn_;
+ std::string mdn_;
+ std::string min_;
+ std::string model_id_;
+ std::string manufacturer_;
+ std::string firmware_revision_;
+ std::string hardware_revision_;
+ std::string carrier_;
+
+ private:
+ friend class CellularTest;
+ friend class CellularCapabilityTest;
+ friend class CellularCapabilityGSMTest;
+ FRIEND_TEST(CellularCapabilityGSMTest, SetProxy);
+ FRIEND_TEST(CellularCapabilityGSMTest, SetStorageIdentifier);
+ FRIEND_TEST(CellularCapabilityGSMTest, UpdateStatus);
+ FRIEND_TEST(CellularCapabilityTest, AllowRoaming);
+ FRIEND_TEST(CellularCapabilityTest, EnableModemFail);
+ FRIEND_TEST(CellularCapabilityTest, EnableModemSucceed);
+ FRIEND_TEST(CellularCapabilityTest, FinishEnable);
+ FRIEND_TEST(CellularCapabilityTest, GetModemInfo);
+ FRIEND_TEST(CellularCapabilityTest, GetModemStatus);
+ FRIEND_TEST(CellularCapabilityTest, TryApns);
+ FRIEND_TEST(CellularServiceTest, FriendlyName);
+ FRIEND_TEST(CellularTest, StartCDMARegister);
+ FRIEND_TEST(CellularTest, StartConnected);
+ FRIEND_TEST(CellularTest, StartGSMRegister);
+ FRIEND_TEST(CellularTest, StartLinked);
+ FRIEND_TEST(CellularTest, Connect);
+ FRIEND_TEST(CellularTest, ConnectFailure);
+ FRIEND_TEST(CellularTest, Disconnect);
+
+ void HelpRegisterDerivedBool(
+ const std::string &name,
+ bool(CellularCapability::*get)(Error *error),
+ void(CellularCapability::*set)(const bool &value, Error *error));
+
+ // Method reply and signal callbacks from Modem interface
+ virtual void OnModemStateChangedSignal(
+ uint32 old_state, uint32 new_state, uint32 reason);
+ virtual void OnGetModemInfoReply(const ResultCallback &callback,
+ const ModemHardwareInfo &info,
+ const Error &error);
+
+ // Method reply callbacks from Modem.Simple interface
+ virtual void OnGetModemStatusReply(const ResultCallback &callback,
+ const DBusPropertiesMap &props,
+ const Error &error);
+ virtual void OnDisconnectReply(const ResultCallback &callback,
+ const Error &error);
+
+ Cellular *cellular_;
+ base::WeakPtrFactory<CellularCapabilityClassic> weak_ptr_factory_;
+
+ scoped_ptr<ModemProxyInterface> proxy_;
+ scoped_ptr<ModemSimpleProxyInterface> simple_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(CellularCapabilityClassic);
+};
+
+} // namespace shill
+
+#endif // SHILL_CELLULAR_CAPABILITY_CLASSIC_
diff --git a/cellular_capability_unittest.cc b/cellular_capability_classic_unittest.cc
similarity index 97%
rename from cellular_capability_unittest.cc
rename to cellular_capability_classic_unittest.cc
index 474c080..ad5ea4a 100644
--- a/cellular_capability_unittest.cc
+++ b/cellular_capability_classic_unittest.cc
@@ -79,7 +79,9 @@
virtual void SetUp() {
static_cast<Device *>(cellular_)->rtnl_handler_ = &rtnl_handler_;
- capability_ = cellular_->capability_.get();
+
+ capability_ = dynamic_cast<CellularCapabilityClassic *>(
+ cellular_->capability_.get());
device_adaptor_ =
dynamic_cast<NiceMock<DeviceMockAdaptor> *>(cellular_->adaptor());
}
@@ -199,7 +201,8 @@
void SetCellularType(Cellular::Type type) {
cellular_->InitCapability(type, &proxy_factory_);
- capability_ = cellular_->capability_.get();
+ capability_ = dynamic_cast<CellularCapabilityClassic *>(
+ cellular_->capability_.get());
}
NiceMockControl control_;
@@ -215,7 +218,7 @@
scoped_ptr<MockModemGSMCardProxy> gsm_card_proxy_;
scoped_ptr<MockModemGSMNetworkProxy> gsm_network_proxy_;
TestProxyFactory proxy_factory_;
- CellularCapability *capability_; // Owned by |cellular_|.
+ CellularCapabilityClassic *capability_; // Owned by |cellular_|.
NiceMock<DeviceMockAdaptor> *device_adaptor_; // Owned by |cellular_|.
mobile_provider_db *provider_db_;
};
diff --git a/cellular_capability_gsm.cc b/cellular_capability_gsm.cc
index bfda762..461b3bf 100644
--- a/cellular_capability_gsm.cc
+++ b/cellular_capability_gsm.cc
@@ -44,7 +44,7 @@
CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
ProxyFactory *proxy_factory)
- : CellularCapability(cellular, proxy_factory),
+ : CellularCapabilityClassic(cellular, proxy_factory),
weak_ptr_factory_(this),
registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
@@ -90,7 +90,7 @@
}
void CellularCapabilityGSM::InitProxies() {
- CellularCapability::InitProxies();
+ CellularCapabilityClassic::InitProxies();
card_proxy_.reset(
proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
cellular()->dbus_owner()));
@@ -145,7 +145,7 @@
void CellularCapabilityGSM::ReleaseProxies() {
VLOG(2) << __func__;
- CellularCapability::ReleaseProxies();
+ CellularCapabilityClassic::ReleaseProxies();
card_proxy_.reset();
network_proxy_.reset();
}
@@ -201,7 +201,7 @@
(*properties)[kConnectPropertyPhoneNumber].writer().append_string(
kPhoneNumber);
- if (!allow_roaming_)
+ if (!AllowRoaming())
(*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
if (!apn_try_list_.empty()) {
@@ -242,7 +242,13 @@
cellular()->service()->SetLastGoodApn(apn_try_list_.front());
apn_try_list_.clear();
}
- CellularCapability::OnConnectReply(callback, error);
+ CellularCapabilityClassic::OnConnectReply(callback, error);
+}
+
+bool CellularCapabilityGSM::AllowRoaming() {
+ bool requires_roaming =
+ home_provider_ ? home_provider_->requires_roaming : false;
+ return requires_roaming || allow_roaming_property();
}
// always called from an async context
@@ -569,14 +575,18 @@
const GSMScanResults &results,
const Error &error) {
VLOG(2) << __func__;
- if (error.IsFailure()) {
- callback.Run(error);
- return;
- }
+
+ // Error handling is weak. The current expectation is that on any
+ // error, found_networks_ should be cleared and a property change
+ // notification sent out.
+ //
+ // TODO(jglasgow): fix error handling
found_networks_.clear();
- for (GSMScanResults::const_iterator it = results.begin();
- it != results.end(); ++it) {
- found_networks_.push_back(ParseScanResult(*it));
+ if (!error.IsFailure()) {
+ for (GSMScanResults::const_iterator it = results.begin();
+ it != results.end(); ++it) {
+ found_networks_.push_back(ParseScanResult(*it));
+ }
}
cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
found_networks_);
diff --git a/cellular_capability_gsm.h b/cellular_capability_gsm.h
index 413a270..ec9260a 100644
--- a/cellular_capability_gsm.h
+++ b/cellular_capability_gsm.h
@@ -6,6 +6,7 @@
#define SHILL_CELLULAR_CAPABILITY_GSM_
#include <deque>
+#include <string>
#include <base/memory/scoped_ptr.h>
#include <base/memory/weak_ptr.h>
@@ -14,6 +15,7 @@
#include "shill/accessor_interface.h"
#include "shill/cellular.h"
#include "shill/cellular_capability.h"
+#include "shill/cellular_capability_classic.h"
#include "shill/modem_gsm_card_proxy_interface.h"
#include "shill/modem_gsm_network_proxy_interface.h"
@@ -21,7 +23,7 @@
namespace shill {
-class CellularCapabilityGSM : public CellularCapability {
+class CellularCapabilityGSM : public CellularCapabilityClassic {
public:
CellularCapabilityGSM(Cellular *cellular, ProxyFactory *proxy_factory);
@@ -75,6 +77,8 @@
virtual void OnConnectReply(const ResultCallback &callback,
const Error &error);
+ virtual bool AllowRoaming();
+
private:
friend class CellularTest;
friend class CellularCapabilityGSMTest;
diff --git a/cellular_capability_universal.cc b/cellular_capability_universal.cc
new file mode 100644
index 0000000..85956b3
--- /dev/null
+++ b/cellular_capability_universal.cc
@@ -0,0 +1,806 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/cellular_capability_universal.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <base/string_number_conversions.h>
+#include <base/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
+#include <mobile_provider.h>
+#include <mm/ModemManager-names.h>
+
+#include <string>
+#include <vector>
+
+#include "shill/adaptor_interfaces.h"
+#include "shill/cellular_service.h"
+#include "shill/error.h"
+#include "shill/property_accessor.h"
+#include "shill/proxy_factory.h"
+
+#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
+#error "Do not include mm-modem.h"
+#endif
+
+// The following are constants that should be found in
+// mm/ModemManager-names.h The are reproduced here as #define because
+// that is how they will appear eventually in ModemManager-names.h
+#define MM_MODEM_SIMPLE_CONNECT_PIN "pin"
+#define MM_MODEM_SIMPLE_CONNECT_OPERATOR_ID "operator-id"
+#define MM_MODEM_SIMPLE_CONNECT_BANDS "bands"
+#define MM_MODEM_SIMPLE_CONNECT_ALLWOED_MODES "allowed-modes"
+#define MM_MODEM_SIMPLE_CONNECT_PREFERRED_MODE "preferred-mode"
+#define MM_MODEM_SIMPLE_CONNECT_APN "apn"
+#define MM_MODEM_SIMPLE_CONNECT_IP_TYPE "ip-type"
+#define MM_MODEM_SIMPLE_CONNECT_USER "user"
+#define MM_MODEM_SIMPLE_CONNECT_PASSWORD "password"
+#define MM_MODEM_SIMPLE_CONNECT_NUMBER "number"
+#define MM_MODEM_SIMPLE_CONNECT_ALLOW_ROAMING "allow-roaming"
+#define MM_MODEM_SIMPLE_CONNECT_RM_PROTOCOL "rm-protocol"
+
+using base::Bind;
+using std::string;
+using std::vector;
+
+namespace shill {
+
+// static
+unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
+
+static const char kPhoneNumber[] = "*99#";
+
+static string AccessTechnologyToString(uint32 access_technologies) {
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
+ return flimflam::kNetworkTechnologyLte;
+ if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
+ MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
+ MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
+ return flimflam::kNetworkTechnologyEvdo;
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
+ return flimflam::kNetworkTechnology1Xrtt;
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
+ return flimflam::kNetworkTechnologyHspaPlus;
+ if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
+ MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
+ MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
+ return flimflam::kNetworkTechnologyHspa;
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
+ return flimflam::kNetworkTechnologyUmts;
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
+ return flimflam::kNetworkTechnologyEdge;
+ if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
+ return flimflam::kNetworkTechnologyGprs;
+ if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
+ MM_MODEM_ACCESS_TECHNOLOGY_GSM))
+ return flimflam::kNetworkTechnologyGsm;
+ return "";
+}
+
+CellularCapabilityUniversal::CellularCapabilityUniversal(
+ Cellular *cellular,
+ ProxyFactory *proxy_factory)
+ : CellularCapability(cellular, proxy_factory),
+ weak_ptr_factory_(this),
+ registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
+ cdma_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
+ access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
+ home_provider_(NULL),
+ scanning_supported_(true),
+ scanning_(false),
+ scan_interval_(0) {
+ VLOG(2) << "Cellular capability constructed: Universal";
+ PropertyStore *store = cellular->mutable_store();
+
+ store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
+ store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
+ &scanning_supported_);
+ store->RegisterConstString(flimflam::kEsnProperty, &esn_);
+ store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
+ &firmware_revision_);
+ store->RegisterConstString(flimflam::kHardwareRevisionProperty,
+ &hardware_revision_);
+ store->RegisterConstString(flimflam::kImeiProperty, &imei_);
+ store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
+ store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
+ store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
+ store->RegisterConstString(flimflam::kMeidProperty, &meid_);
+ store->RegisterConstString(flimflam::kMinProperty, &min_);
+ store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
+ store->RegisterConstString(flimflam::kSelectedNetworkProperty,
+ &selected_network_);
+ store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
+ &found_networks_);
+ store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
+ store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
+ HelpRegisterDerivedKeyValueStore(
+ flimflam::kSIMLockStatusProperty,
+ &CellularCapabilityUniversal::SimLockStatusToProperty,
+ NULL);
+ store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
+ &apn_list_);
+}
+
+KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
+ Error */*error*/) {
+ KeyValueStore status;
+ status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
+ status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
+ status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
+ sim_lock_status_.retries_left);
+ return status;
+}
+
+void CellularCapabilityUniversal::HelpRegisterDerivedKeyValueStore(
+ const string &name,
+ KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
+ void(CellularCapabilityUniversal::*set)(
+ const KeyValueStore &value, Error *error)) {
+ cellular()->mutable_store()->RegisterDerivedKeyValueStore(
+ name,
+ KeyValueStoreAccessor(
+ new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
+ this, get, set)));
+}
+
+void CellularCapabilityUniversal::InitProxies() {
+ modem_3gpp_proxy_.reset(
+ proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
+ cellular()->dbus_owner()));
+ modem_cdma_proxy_.reset(
+ proxy_factory()->CreateMM1ModemModemCdmaProxy(cellular()->dbus_path(),
+ cellular()->dbus_owner()));
+ modem_proxy_.reset(
+ proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
+ cellular()->dbus_owner()));
+ modem_simple_proxy_.reset(
+ proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
+ cellular()->dbus_owner()));
+ // Do not create a SIM proxy until the device is enabled because we
+ // do not yet know the object path of the sim object.
+
+ // TODO(jglasgow): register callbacks
+}
+
+void CellularCapabilityUniversal::StartModem(Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityUniversal::StopModem(Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
+ Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityUniversal::Disconnect(Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityUniversal::Activate(const std::string &carrier,
+ Error *error,
+ const ResultCallback &callback) {
+ OnUnsupportedOperation(__func__, error);
+}
+
+void CellularCapabilityUniversal::ReleaseProxies() {
+ VLOG(2) << __func__;
+ modem_3gpp_proxy_.reset();
+ modem_cdma_proxy_.reset();
+ modem_proxy_.reset();
+ modem_simple_proxy_.reset();
+ sim_proxy_.reset();
+}
+
+void CellularCapabilityUniversal::OnServiceCreated() {
+ // If IMSI is available, base the service's storage identifier on it.
+ if (!imsi_.empty()) {
+ cellular()->service()->SetStorageIdentifier(
+ string(flimflam::kTypeCellular) + "_" +
+ cellular()->address() + "_" + imsi_);
+ }
+ cellular()->service()->SetActivationState(
+ flimflam::kActivationStateActivated);
+ UpdateServingOperator();
+}
+
+void CellularCapabilityUniversal::UpdateStatus(
+ const DBusPropertiesMap &properties) {
+ if (ContainsKey(properties, kPropertyIMSI)) {
+ SetHomeProvider();
+ }
+}
+
+// Create the list of APNs to try, in the following order:
+// - last APN that resulted in a successful connection attempt on the
+// current network (if any)
+// - the APN, if any, that was set by the user
+// - the list of APNs found in the mobile broadband provider DB for the
+// home provider associated with the current SIM
+// - as a last resort, attempt to connect with no APN
+void CellularCapabilityUniversal::SetupApnTryList() {
+ apn_try_list_.clear();
+
+ DCHECK(cellular()->service().get());
+ const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
+ if (apn_info)
+ apn_try_list_.push_back(*apn_info);
+
+ apn_info = cellular()->service()->GetUserSpecifiedApn();
+ if (apn_info)
+ apn_try_list_.push_back(*apn_info);
+
+ apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
+}
+
+void CellularCapabilityUniversal::SetupConnectProperties(
+ DBusPropertiesMap *properties) {
+ SetupApnTryList();
+ FillConnectPropertyMap(properties);
+}
+
+void CellularCapabilityUniversal::FillConnectPropertyMap(
+ DBusPropertiesMap *properties) {
+
+ // TODO(jglasgow): Is this really needed anymore?
+ (*properties)[MM_MODEM_SIMPLE_CONNECT_NUMBER].writer().append_string(
+ kPhoneNumber);
+
+ (*properties)[MM_MODEM_SIMPLE_CONNECT_ALLOW_ROAMING].writer().append_bool(
+ AllowRoaming());
+
+ if (!apn_try_list_.empty()) {
+ // Leave the APN at the front of the list, so that it can be recorded
+ // if the connect attempt succeeds.
+ Stringmap apn_info = apn_try_list_.front();
+ VLOG(2) << __func__ << ": Using APN " << apn_info[flimflam::kApnProperty];
+ (*properties)[MM_MODEM_SIMPLE_CONNECT_APN].writer().append_string(
+ apn_info[flimflam::kApnProperty].c_str());
+ if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
+ (*properties)[MM_MODEM_SIMPLE_CONNECT_USER].writer().append_string(
+ apn_info[flimflam::kApnUsernameProperty].c_str());
+ if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
+ (*properties)[MM_MODEM_SIMPLE_CONNECT_PASSWORD].writer().append_string(
+ apn_info[flimflam::kApnPasswordProperty].c_str());
+ }
+}
+
+void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
+ const Error &error) {
+ if (error.IsFailure()) {
+ cellular()->service()->ClearLastGoodApn();
+ // The APN that was just tried (and failed) is still at the
+ // front of the list, about to be removed. If the list is empty
+ // after that, try one last time without an APN. This may succeed
+ // with some modems in some cases.
+ if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
+ apn_try_list_.pop_front();
+ VLOG(2) << "Connect failed with invalid APN, " << apn_try_list_.size()
+ << " remaining APNs to try";
+ DBusPropertiesMap props;
+ FillConnectPropertyMap(&props);
+ Error error;
+ Connect(props, &error, callback);
+ return;
+ }
+ cellular()->OnConnectFailed(error);
+ } else {
+ if (!apn_try_list_.empty()) {
+ cellular()->service()->SetLastGoodApn(apn_try_list_.front());
+ apn_try_list_.clear();
+ }
+ cellular()->OnConnected();
+ }
+
+ if (!callback.is_null())
+ callback.Run(error);
+}
+
+bool CellularCapabilityUniversal::AllowRoaming() {
+ bool requires_roaming =
+ home_provider_ ? home_provider_->requires_roaming : false;
+ return requires_roaming || allow_roaming_property();
+}
+
+void CellularCapabilityUniversal::GetRegistrationState() {
+ VLOG(2) << __func__;
+ string operator_code;
+ string operator_name;
+
+ const MMModem3gppRegistrationState state =
+ static_cast<MMModem3gppRegistrationState>(
+ modem_3gpp_proxy_->RegistrationState());
+ if (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
+ operator_code = modem_3gpp_proxy_->OperatorCode();
+ operator_name = modem_3gpp_proxy_->OperatorName();
+ }
+ On3GPPRegistrationChanged(state, operator_code, operator_name);
+}
+
+void CellularCapabilityUniversal::GetProperties(
+ const ResultCallback &callback) {
+ VLOG(2) << __func__;
+
+ // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
+ uint32 technologies = modem_proxy_->AccessTechnologies();
+ // TODO(jglasgow): figure out the most likely one that we are using....
+ SetAccessTechnologies(technologies);
+ VLOG(2) << "AccessTechnologies: " << technologies;
+
+ // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
+ uint32 locks = modem_3gpp_proxy_->EnabledFacilityLocks();
+ sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
+ VLOG(2) << "GSM EnabledFacilityLocks: " << locks;
+
+ // TODO(jglasgow): Switch to asynchronous calls (crosbug.com/17583).
+ const DBus::Struct<unsigned int, bool> quality =
+ modem_proxy_->SignalQuality();
+ OnSignalQualityChanged(quality._1);
+
+ // TODO(jglasgow): Switch to asynchronous calls (crosbug.com/17583).
+ if (imei_.empty()) {
+ imei_ = modem_3gpp_proxy_->Imei();
+ }
+ if (imsi_.empty()) {
+ imsi_ = sim_proxy_->Imsi();
+ }
+ if (spn_.empty()) {
+ spn_ = sim_proxy_->OperatorName();
+ // TODO(jglasgow): May eventually want to get SPDI, etc
+ }
+ if (mdn_.empty()) {
+ // TODO(jglasgow): use OwnNumbers()
+ }
+ GetRegistrationState();
+
+ callback.Run(Error());
+}
+
+string CellularCapabilityUniversal::CreateFriendlyServiceName() {
+ VLOG(2) << __func__;
+ if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
+ !cellular()->home_provider().GetName().empty()) {
+ return cellular()->home_provider().GetName();
+ }
+ if (!serving_operator_.GetName().empty()) {
+ return serving_operator_.GetName();
+ }
+ if (!carrier_.empty()) {
+ return carrier_;
+ }
+ if (!serving_operator_.GetCode().empty()) {
+ return "cellular_" + serving_operator_.GetCode();
+ }
+ return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
+}
+
+void CellularCapabilityUniversal::SetHomeProvider() {
+ VLOG(2) << __func__ << "(IMSI: " << imsi_
+ << " SPN: " << spn_ << ")";
+ // TODO(petkov): The test for NULL provider_db should be done by
+ // mobile_provider_lookup_best_match.
+ if (imsi_.empty() || !cellular()->provider_db()) {
+ return;
+ }
+ mobile_provider *provider =
+ mobile_provider_lookup_best_match(
+ cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
+ if (!provider) {
+ VLOG(2) << "GSM provider not found.";
+ return;
+ }
+ home_provider_ = provider;
+ Cellular::Operator oper;
+ if (provider->networks) {
+ oper.SetCode(provider->networks[0]);
+ }
+ if (provider->country) {
+ oper.SetCountry(provider->country);
+ }
+ if (spn_.empty()) {
+ const char *name = mobile_provider_get_name(provider);
+ if (name) {
+ oper.SetName(name);
+ }
+ } else {
+ oper.SetName(spn_);
+ }
+ cellular()->set_home_provider(oper);
+ InitAPNList();
+}
+
+void CellularCapabilityUniversal::UpdateOperatorInfo() {
+ VLOG(2) << __func__;
+ const string &network_id = serving_operator_.GetCode();
+ if (!network_id.empty()) {
+ VLOG(2) << "Looking up network id: " << network_id;
+ mobile_provider *provider =
+ mobile_provider_lookup_by_network(cellular()->provider_db(),
+ network_id.c_str());
+ if (provider) {
+ const char *provider_name = mobile_provider_get_name(provider);
+ if (provider_name && *provider_name) {
+ serving_operator_.SetName(provider_name);
+ if (provider->country) {
+ serving_operator_.SetCountry(provider->country);
+ }
+ VLOG(2) << "Operator name: " << serving_operator_.GetName()
+ << ", country: " << serving_operator_.GetCountry();
+ }
+ } else {
+ VLOG(2) << "GSM provider not found.";
+ }
+ }
+ UpdateServingOperator();
+}
+
+void CellularCapabilityUniversal::UpdateServingOperator() {
+ VLOG(2) << __func__;
+ if (cellular()->service().get()) {
+ cellular()->service()->SetServingOperator(serving_operator_);
+ }
+}
+
+void CellularCapabilityUniversal::InitAPNList() {
+ VLOG(2) << __func__;
+ if (!home_provider_) {
+ return;
+ }
+ apn_list_.clear();
+ for (int i = 0; i < home_provider_->num_apns; ++i) {
+ Stringmap props;
+ mobile_apn *apn = home_provider_->apns[i];
+ if (apn->value) {
+ props[flimflam::kApnProperty] = apn->value;
+ }
+ if (apn->username) {
+ props[flimflam::kApnUsernameProperty] = apn->username;
+ }
+ if (apn->password) {
+ props[flimflam::kApnPasswordProperty] = apn->password;
+ }
+ // Find the first localized and non-localized name, if any.
+ const localized_name *lname = NULL;
+ const localized_name *name = NULL;
+ for (int j = 0; j < apn->num_names; ++j) {
+ if (apn->names[j]->lang) {
+ if (!lname) {
+ lname = apn->names[j];
+ }
+ } else if (!name) {
+ name = apn->names[j];
+ }
+ }
+ if (name) {
+ props[flimflam::kApnNameProperty] = name->name;
+ }
+ if (lname) {
+ props[flimflam::kApnLocalizedNameProperty] = lname->name;
+ props[flimflam::kApnLanguageProperty] = lname->lang;
+ }
+ apn_list_.push_back(props);
+ }
+ cellular()->adaptor()->EmitStringmapsChanged(
+ flimflam::kCellularApnListProperty, apn_list_);
+}
+
+// always called from an async context
+void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
+ VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
+ CHECK(!callback.is_null());
+ Error error;
+ ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
+ if (error.IsFailure())
+ callback.Run(error);
+}
+
+void CellularCapabilityUniversal::RegisterOnNetwork(
+ const string &network_id,
+ Error *error,
+ const ResultCallback &callback) {
+ VLOG(2) << __func__ << "(" << network_id << ")";
+ CHECK(error);
+ desired_network_ = network_id;
+ ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
+}
+
+void CellularCapabilityUniversal::OnRegisterReply(
+ const ResultCallback &callback,
+ const Error &error) {
+ VLOG(2) << __func__ << "(" << error << ")";
+
+ if (error.IsSuccess()) {
+ selected_network_ = desired_network_;
+ desired_network_.clear();
+ callback.Run(error);
+ return;
+ }
+ // If registration on the desired network failed,
+ // try to register on the home network.
+ if (!desired_network_.empty()) {
+ desired_network_.clear();
+ selected_network_.clear();
+ LOG(INFO) << "Couldn't register on selected network, trying home network";
+ Register(callback);
+ return;
+ }
+ callback.Run(error);
+}
+
+bool CellularCapabilityUniversal::IsRegistered() {
+ return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
+ registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
+}
+
+void CellularCapabilityUniversal::RequirePIN(
+ const std::string &pin, bool require,
+ Error *error, const ResultCallback &callback) {
+ CHECK(error);
+ sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
+}
+
+void CellularCapabilityUniversal::EnterPIN(const string &pin,
+ Error *error,
+ const ResultCallback &callback) {
+ CHECK(error);
+ sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
+}
+
+void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
+ const string &pin,
+ Error *error,
+ const ResultCallback &callback) {
+ CHECK(error);
+ sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
+}
+
+void CellularCapabilityUniversal::ChangePIN(
+ const string &old_pin, const string &new_pin,
+ Error *error, const ResultCallback &callback) {
+ CHECK(error);
+ sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
+}
+
+void CellularCapabilityUniversal::Scan(Error *error,
+ const ResultCallback &callback) {
+ VLOG(2) << __func__;
+ // TODO(petkov): Defer scan requests if a scan is in progress already.
+ CHECK(error);
+ DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
+}
+
+void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
+ const ScanResults &results,
+ const Error &error) {
+ VLOG(2) << __func__;
+
+ // Error handling is weak. The current expectation is that on any
+ // error, found_networks_ should be cleared and a property change
+ // notification sent out.
+ //
+ // TODO(jglasgow): fix error handling
+ found_networks_.clear();
+ if (!error.IsFailure()) {
+ for (ScanResults::const_iterator it = results.begin();
+ it != results.end(); ++it) {
+ found_networks_.push_back(ParseScanResult(*it));
+ }
+ }
+ cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
+ found_networks_);
+ callback.Run(error);
+}
+
+Stringmap CellularCapabilityUniversal::ParseScanResult(
+ const ScanResult &result) {
+
+ static const char kStatusProperty[] = "status";
+ static const char kOperatorLongProperty[] = "operator-long";
+ static const char kOperatorShortProperty[] = "operator-short";
+ static const char kOperatorCodeProperty[] = "operator-code";
+ static const char kOperatorAccessTechnologyProperty[] = "access-technology";
+
+ /* ScanResults contain the following keys:
+
+ "status"
+ A MMModem3gppNetworkAvailability value representing network
+ availability status, given as an unsigned integer (signature "u").
+ This key will always be present.
+
+ "operator-long"
+ Long-format name of operator, given as a string value (signature
+ "s"). If the name is unknown, this field should not be present.
+
+ "operator-short"
+ Short-format name of operator, given as a string value
+ (signature "s"). If the name is unknown, this field should not
+ be present.
+
+ "operator-code"
+ Mobile code of the operator, given as a string value (signature
+ "s"). Returned in the format "MCCMNC", where MCC is the
+ three-digit ITU E.212 Mobile Country Code and MNC is the two- or
+ three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
+
+ "access-technology"
+ A MMModemAccessTechnology value representing the generic access
+ technology used by this mobile network, given as an unsigned
+ integer (signature "u").
+ */
+ Stringmap parsed;
+
+ uint32 status;
+ if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
+ // numerical values are taken from 3GPP TS 27.007 Section 7.3.
+ static const char * const kStatusString[] = {
+ "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
+ "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
+ "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
+ "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
+ };
+ parsed[flimflam::kStatusProperty] = kStatusString[status];
+ }
+
+ uint32 tech; // MMModemAccessTechnology
+ if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
+ &tech)) {
+ parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
+ }
+
+ string operator_long, operator_short, operator_code;
+ if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
+ parsed[flimflam::kLongNameProperty] = operator_long;
+ if (DBusProperties::GetString(result, kOperatorShortProperty,
+ &operator_short))
+ parsed[flimflam::kShortNameProperty] = operator_short;
+ if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
+ parsed[flimflam::kNetworkIdProperty] = operator_code;
+
+ // If the long name is not available but the network ID is, look up the long
+ // name in the mobile provider database.
+ if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
+ parsed[flimflam::kLongNameProperty].empty()) &&
+ ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
+ mobile_provider *provider =
+ mobile_provider_lookup_by_network(
+ cellular()->provider_db(),
+ parsed[flimflam::kNetworkIdProperty].c_str());
+ if (provider) {
+ const char *long_name = mobile_provider_get_name(provider);
+ if (long_name && *long_name) {
+ parsed[flimflam::kLongNameProperty] = long_name;
+ }
+ }
+ }
+ return parsed;
+}
+
+void CellularCapabilityUniversal::SetAccessTechnologies(
+ uint32 access_technologies) {
+ access_technologies_ = access_technologies;
+ if (cellular()->service().get()) {
+ cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
+ }
+}
+
+string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
+ // Order is imnportant. Return the highest speed technology
+ // TODO(jglasgow): change shill interfaces to a capability model
+
+ return AccessTechnologyToString(access_technologies_);
+}
+
+string CellularCapabilityUniversal::GetRoamingStateString() const {
+ switch (registration_state_) {
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
+ return flimflam::kRoamingStateHome;
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
+ return flimflam::kRoamingStateRoaming;
+ default:
+ break;
+ }
+ return flimflam::kRoamingStateUnknown;
+}
+
+void CellularCapabilityUniversal::GetSignalQuality() {
+ // TODO(jglasgow): implement
+ NOTIMPLEMENTED();
+}
+
+void CellularCapabilityUniversal::OnModemManagerPropertiesChanged(
+ const DBusPropertiesMap &properties) {
+
+ // TODO(jglasgow): When CreateDeviceFromModemProperties is fixed DCHECK
+ LOG(ERROR) << "Unexpected call to OnModemPropertiesChanged.";
+
+ uint32 access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
+ if (DBusProperties::GetUint32(properties,
+ MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
+ &access_technologies)) {
+ SetAccessTechnologies(access_technologies);
+ }
+ // Unlockrequired and SimLock
+ bool emit = false;
+
+ uint32_t lock_required; // This is really of type MMModemLock
+ if (DBusProperties::GetUint32(properties,
+ MM_MODEM_PROPERTY_UNLOCKREQUIRED,
+ &lock_required)) {
+ // TODO(jglasgow): set sim_lock_status_.lock_type
+ emit = true;
+ }
+ // TODO(jglasgow): Update PIN retries which are a{uu} and require parsing
+ // Get the property MM_MODEM_PROPERTY_UNLOCKRETRIES
+ // Set sim_lock_status_.retries_left
+
+ if (emit) {
+ cellular()->adaptor()->EmitKeyValueStoreChanged(
+ flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
+ }
+}
+
+void CellularCapabilityUniversal::OnDBusPropertiesChanged(
+ const string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const vector<std::string> &invalidated_properties) {
+ // TODO(jglasgow): implement properties changed handling
+ NOTIMPLEMENTED();
+}
+
+void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
+ const DBusPropertiesMap &properties) {
+ bool emit = false;
+ uint32 locks = 0;
+ if (DBusProperties::GetUint32(
+ properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
+ &locks)) {
+ sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
+ emit = true;
+ }
+ // TODO(jglasgow): coordinate with changes to Modem properties
+ if (emit) {
+ cellular()->adaptor()->EmitKeyValueStoreChanged(
+ flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
+ }
+}
+
+void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
+ // TODO(petkov): Implement this.
+ NOTIMPLEMENTED();
+}
+
+void CellularCapabilityUniversal::On3GPPRegistrationChanged(
+ MMModem3gppRegistrationState state,
+ const string &operator_code,
+ const string &operator_name) {
+ VLOG(2) << __func__ << ": regstate=" << state
+ << ", opercode=" << operator_code
+ << ", opername=" << operator_name;
+ registration_state_ = state;
+ serving_operator_.SetCode(operator_code);
+ serving_operator_.SetName(operator_name);
+ UpdateOperatorInfo();
+ cellular()->HandleNewRegistrationState();
+}
+
+void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
+ cellular()->HandleNewSignalQuality(quality);
+}
+
+} // namespace shill
diff --git a/cellular_capability_universal.h b/cellular_capability_universal.h
new file mode 100644
index 0000000..5592f05
--- /dev/null
+++ b/cellular_capability_universal.h
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_CELLULAR_CAPABILITY_UNIVERSAL_
+#define SHILL_CELLULAR_CAPABILITY_UNIVERSAL_
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <base/memory/scoped_ptr.h>
+#include <base/memory/weak_ptr.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include <mm/ModemManager-enums.h>
+
+#include "shill/accessor_interface.h"
+#include "shill/cellular.h"
+#include "shill/cellular_capability.h"
+#include "shill/mm1_modem_modem3gpp_proxy_interface.h"
+#include "shill/mm1_modem_modemcdma_proxy_interface.h"
+#include "shill/mm1_modem_proxy_interface.h"
+#include "shill/mm1_modem_simple_proxy_interface.h"
+#include "shill/mm1_sim_proxy_interface.h"
+
+
+struct mobile_provider;
+
+namespace shill {
+
+// CellularCapabilityUniversal handles modems using the
+// org.chromium.ModemManager1 DBUS interface. This class is used for
+// all types of modems, i.e. CDMA, GSM, and LTE modems.
+class CellularCapabilityUniversal : public CellularCapability {
+ public:
+ typedef std::vector<DBusPropertiesMap> ScanResults;
+ typedef DBusPropertiesMap ScanResult;
+
+ CellularCapabilityUniversal(Cellular *cellular, ProxyFactory *proxy_factory);
+
+ // Inherited from CellularCapability.
+ virtual void StartModem(Error *error, const ResultCallback &callback);
+ virtual void StopModem(Error *error, const ResultCallback &callback);
+ virtual void Connect(const DBusPropertiesMap &properties, Error *error,
+ const ResultCallback &callback);
+ virtual void Disconnect(Error *error, const ResultCallback &callback);
+ virtual void Activate(const std::string &carrier,
+ Error *error, const ResultCallback &callback);
+
+ virtual void OnServiceCreated();
+ virtual void UpdateStatus(const DBusPropertiesMap &properties);
+ virtual void SetupConnectProperties(DBusPropertiesMap *properties);
+ virtual void GetRegistrationState();
+ virtual void GetProperties(const ResultCallback &callback);
+ virtual void Register(const ResultCallback &callback);
+
+ virtual void RegisterOnNetwork(const std::string &network_id,
+ Error *error,
+ const ResultCallback &callback);
+ virtual bool IsRegistered();
+ virtual std::string CreateFriendlyServiceName();
+ virtual void RequirePIN(const std::string &pin, bool require,
+ Error *error, const ResultCallback &callback);
+ virtual void EnterPIN(const std::string &pin,
+ Error *error, const ResultCallback &callback);
+ virtual void UnblockPIN(const std::string &unblock_code,
+ const std::string &pin,
+ Error *error, const ResultCallback &callback);
+ virtual void ChangePIN(const std::string &old_pin,
+ const std::string &new_pin,
+ Error *error, const ResultCallback &callback);
+
+ virtual void Scan(Error *error, const ResultCallback &callback);
+ virtual std::string GetNetworkTechnologyString() const;
+ virtual std::string GetRoamingStateString() const;
+ virtual std::string GetTypeString() const { return "Universal"; }
+
+ virtual void GetSignalQuality();
+ virtual void OnModemManagerPropertiesChanged(
+ const DBusPropertiesMap &properties);
+ virtual void OnDBusPropertiesChanged(
+ const std::string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const std::vector<std::string> &invalidated_properties);
+ virtual void OnModem3GPPPropertiesChanged(
+ const DBusPropertiesMap &properties);
+
+ protected:
+ virtual void InitProxies();
+ virtual void ReleaseProxies();
+ // Override OnConnectReply in order to handle the possibility of
+ // retrying the Connect operation.
+ virtual void OnConnectReply(const ResultCallback &callback,
+ const Error &error);
+
+ virtual bool AllowRoaming();
+
+ private:
+ friend class CellularTest;
+ friend class CellularCapabilityUniversalTest;
+ friend class CellularCapabilityTest;
+ FRIEND_TEST(CellularCapabilityUniversalTest, CreateDeviceFromProperties);
+ FRIEND_TEST(CellularCapabilityUniversalTest, CreateFriendlyServiceName);
+ FRIEND_TEST(CellularCapabilityUniversalTest, GetIMEI);
+ FRIEND_TEST(CellularCapabilityUniversalTest, GetIMSI);
+ FRIEND_TEST(CellularCapabilityUniversalTest, GetMSISDN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, GetSPN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, RequirePIN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, EnterPIN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, UnblockPIN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, ChangePIN);
+ FRIEND_TEST(CellularCapabilityUniversalTest, InitAPNList);
+ FRIEND_TEST(CellularCapabilityUniversalTest, ParseScanResult);
+ FRIEND_TEST(CellularCapabilityUniversalTest, ParseScanResultProviderLookup);
+ FRIEND_TEST(CellularCapabilityUniversalTest, RegisterOnNetwork);
+ FRIEND_TEST(CellularCapabilityUniversalTest, Scan);
+ FRIEND_TEST(CellularCapabilityUniversalTest, SetAccessTechnologies);
+ FRIEND_TEST(CellularCapabilityUniversalTest, SetHomeProvider);
+ FRIEND_TEST(CellularCapabilityUniversalTest, UpdateOperatorInfo);
+ FRIEND_TEST(CellularCapabilityUniversalTest, GetRegistrationState);
+ FRIEND_TEST(CellularCapabilityUniversalTest, OnModemManagerPropertiesChanged);
+ FRIEND_TEST(CellularCapabilityUniversalTest, SetupApnTryList);
+ FRIEND_TEST(CellularCapabilityTest, AllowRoaming);
+ FRIEND_TEST(CellularCapabilityTest, TryApns);
+ FRIEND_TEST(CellularTest, StartUniversalRegister);
+ FRIEND_TEST(ModemTest, CreateDeviceFromProperties);
+
+ // TOOD(jglasgow): document what this does!!!!!
+ void SetAccessTechnologies(uint32 access_technologies);
+
+ // Sets the upper level information about the home cellular provider from the
+ // modem's IMSI and SPN.
+ void SetHomeProvider();
+
+ // Updates the Universal operator name and country based on a newly
+ // obtained network id.
+ void UpdateOperatorInfo();
+
+ // Updates the serving operator on the active service.
+ void UpdateServingOperator();
+
+ // Initializes the |apn_list_| property based on the current |home_provider_|.
+ void InitAPNList();
+
+ Stringmap ParseScanResult(const ScanResult &result);
+
+ KeyValueStore SimLockStatusToProperty(Error *error);
+
+ void SetupApnTryList();
+ void FillConnectPropertyMap(DBusPropertiesMap *properties);
+
+ void HelpRegisterDerivedKeyValueStore(
+ const std::string &name,
+ KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
+ void(CellularCapabilityUniversal::*set)(
+ const KeyValueStore &value, Error *error));
+
+ // Signal callbacks
+ virtual void OnNetworkModeSignal(uint32 mode);
+
+ // Property Change notification handlers
+ // TODO(jglasgow): install generic property change notification handler
+ virtual void On3GPPRegistrationChanged(MMModem3gppRegistrationState state,
+ const std::string &operator_code,
+ const std::string &operator_name);
+ virtual void OnSignalQualityChanged(uint32 quality);
+
+ // Method callbacks
+ virtual void OnRegisterReply(const ResultCallback &callback,
+ const Error &error);
+ virtual void OnScanReply(const ResultCallback &callback,
+ const ScanResults &results,
+ const Error &error);
+
+ scoped_ptr<mm1::ModemModem3gppProxyInterface> modem_3gpp_proxy_;
+ scoped_ptr<mm1::ModemModemCdmaProxyInterface> modem_cdma_proxy_;
+ scoped_ptr<mm1::ModemProxyInterface> modem_proxy_;
+ scoped_ptr<mm1::ModemSimpleProxyInterface> modem_simple_proxy_;
+ scoped_ptr<mm1::SimProxyInterface> sim_proxy_;
+
+ base::WeakPtrFactory<CellularCapabilityUniversal> weak_ptr_factory_;
+
+ MMModem3gppRegistrationState registration_state_;
+ MMModemCdmaRegistrationState cdma_registration_state_;
+ uint32 access_technologies_; // Bits based on MMModemAccessTechnology
+ Cellular::Operator serving_operator_;
+ std::string spn_;
+ mobile_provider *home_provider_;
+ std::string desired_network_;
+
+ // Properties.
+ std::string carrier_;
+ std::string esn_;
+ std::string firmware_revision_;
+ std::string hardware_revision_;
+ std::string imei_;
+ std::string imsi_;
+ std::string manufacturer_;
+ std::string mdn_;
+ std::string meid_;
+ std::string min_;
+ std::string model_id_;
+ std::string selected_network_;
+ Stringmaps found_networks_;
+ std::deque<Stringmap> apn_try_list_;
+ bool scanning_supported_;
+ bool scanning_;
+ uint16 scan_interval_;
+ SimLockStatus sim_lock_status_;
+ Stringmaps apn_list_;
+
+ static unsigned int friendly_service_name_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CellularCapabilityUniversal);
+};
+
+} // namespace shill
+
+#endif // SHILL_CELLULAR_CAPABILITY_UNIVERSAL_
diff --git a/cellular_error.cc b/cellular_error.cc
index ca404e3..aa5f45a 100644
--- a/cellular_error.cc
+++ b/cellular_error.cc
@@ -4,6 +4,8 @@
#include "shill/cellular_error.h"
+#include <string>
+
#include <base/logging.h>
#include <mm/mm-modem.h>
diff --git a/cellular_service_unittest.cc b/cellular_service_unittest.cc
index d1ed64f..95fd44d 100644
--- a/cellular_service_unittest.cc
+++ b/cellular_service_unittest.cc
@@ -8,6 +8,7 @@
#include <gtest/gtest.h>
#include "shill/cellular_capability.h"
+#include "shill/cellular_capability_gsm.h"
#include "shill/nice_mock_control.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_metrics.h"
@@ -47,6 +48,10 @@
dynamic_cast<NiceMock<ServiceMockAdaptor> *>(service_->adaptor());
}
+ CellularCapabilityGSM *GetCapabilityGSM() {
+ return dynamic_cast<CellularCapabilityGSM *>(device_->capability_.get());
+ }
+
protected:
static const char kAddress[];
@@ -79,7 +84,7 @@
TEST_F(CellularServiceTest, FriendlyName) {
static const char kCarrier[] = "Cellular Carrier";
- device_->capability_->carrier_ = kCarrier;
+ GetCapabilityGSM()->carrier_ = kCarrier;
service_ = new CellularService(&control_, NULL, &metrics_, NULL, device_);
EXPECT_EQ(kCarrier, service_->friendly_name());
}
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 0d85ae3..3a5fbcd 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -14,6 +14,7 @@
#include <mobile_provider.h>
#include "shill/cellular_capability_cdma.h"
+#include "shill/cellular_capability_classic.h"
#include "shill/cellular_capability_gsm.h"
#include "shill/cellular_service.h"
#include "shill/error.h"
@@ -325,6 +326,11 @@
device_->InitCapability(type, &proxy_factory_);
}
+ CellularCapabilityClassic *GetCapabilityClassic() {
+ return dynamic_cast<CellularCapabilityClassic *>(
+ device_->capability_.get());
+ }
+
CellularCapabilityCDMA *GetCapabilityCDMA() {
return dynamic_cast<CellularCapabilityCDMA *>(device_->capability_.get());
}
@@ -387,8 +393,8 @@
Error error;
device_->Start(&error, Bind(&CellularTest::TestCallback, Unretained(this)));
dispatcher_.DispatchPendingEvents();
- EXPECT_EQ(kMEID, device_->capability_->meid_);
- EXPECT_EQ(kTestCarrier, device_->capability_->carrier_);
+ EXPECT_EQ(kMEID, GetCapabilityClassic()->meid_);
+ EXPECT_EQ(kTestCarrier, GetCapabilityClassic()->carrier_);
EXPECT_EQ(Cellular::kStateRegistered, device_->state_);
ASSERT_TRUE(device_->service_.get());
EXPECT_EQ(flimflam::kNetworkTechnology1Xrtt,
@@ -440,10 +446,10 @@
device_->Start(&error, Bind(&CellularTest::TestCallback, Unretained(this)));
EXPECT_TRUE(error.IsSuccess());
dispatcher_.DispatchPendingEvents();
- EXPECT_EQ(kIMEI, device_->capability_->imei_);
- EXPECT_EQ(kIMSI, device_->capability_->imsi_);
+ EXPECT_EQ(kIMEI, GetCapabilityGSM()->imei_);
+ EXPECT_EQ(kIMSI, GetCapabilityGSM()->imsi_);
EXPECT_EQ(kTestCarrier, GetCapabilityGSM()->spn_);
- EXPECT_EQ(kMSISDN, device_->capability_->mdn_);
+ EXPECT_EQ(kMSISDN, GetCapabilityGSM()->mdn_);
EXPECT_EQ(Cellular::kStateRegistered, device_->state_);
ASSERT_TRUE(device_->service_.get());
EXPECT_EQ(flimflam::kNetworkTechnologyEdge,
@@ -461,7 +467,7 @@
.WillOnce(Return(true));
SetCellularType(Cellular::kTypeCDMA);
device_->set_modem_state(Cellular::kModemStateConnected);
- device_->capability_->meid_ = kMEID;
+ GetCapabilityClassic()->meid_ = kMEID;
ExpectCdmaStartModem(flimflam::kNetworkTechnologyEvdo);
Error error;
device_->Start(&error, Bind(&CellularTest::TestCallback, Unretained(this)));
@@ -475,7 +481,7 @@
.WillOnce(DoAll(SetArgumentPointee<1>(IFF_UP), Return(true)));
SetCellularType(Cellular::kTypeCDMA);
device_->set_modem_state(Cellular::kModemStateConnected);
- device_->capability_->meid_ = kMEID;
+ GetCapabilityClassic()->meid_ = kMEID;
ExpectCdmaStartModem(flimflam::kNetworkTechnologyEvdo);
EXPECT_CALL(dhcp_provider_, CreateConfig(kTestDeviceName, _))
.WillOnce(Return(dhcp_config_));
@@ -508,7 +514,8 @@
namespace {
MATCHER(ContainsPhoneNumber, "") {
- return ContainsKey(arg, CellularCapability::kConnectPropertyPhoneNumber);
+ return ContainsKey(arg,
+ CellularCapabilityClassic::kConnectPropertyPhoneNumber);
}
} // namespace
@@ -542,7 +549,7 @@
CellularCapability::kTimeoutConnect))
.Times(2)
.WillRepeatedly(Invoke(this, &CellularTest::InvokeConnect));
- device_->capability_->simple_proxy_.reset(simple_proxy_.release());
+ GetCapabilityClassic()->simple_proxy_.reset(simple_proxy_.release());
device_->service_->roaming_state_ = flimflam::kRoamingStateHome;
device_->state_ = Cellular::kStateRegistered;
device_->Connect(&error);
@@ -570,7 +577,7 @@
EXPECT_CALL(*proxy_,
Disconnect(_, _, CellularCapability::kTimeoutDefault))
.WillOnce(Invoke(this, &CellularTest::InvokeDisconnect));
- device_->capability_->proxy_.reset(proxy_.release());
+ GetCapabilityClassic()->proxy_.reset(proxy_.release());
device_->Disconnect(&error);
EXPECT_TRUE(error.IsSuccess());
EXPECT_EQ(Cellular::kStateRegistered, device_->state_);
@@ -585,7 +592,7 @@
EXPECT_CALL(*simple_proxy_,
Connect(_, _, _, CellularCapability::kTimeoutConnect))
.WillOnce(Invoke(this, &CellularTest::InvokeConnectFail));
- device_->capability_->simple_proxy_.reset(simple_proxy_.release());
+ GetCapabilityClassic()->simple_proxy_.reset(simple_proxy_.release());
Error error;
device_->Connect(&error);
EXPECT_EQ(Service::kStateFailure, device_->service_->state());
diff --git a/mm1_modem_proxy.cc b/mm1_modem_proxy.cc
index def4fe1..4ba6541 100644
--- a/mm1_modem_proxy.cc
+++ b/mm1_modem_proxy.cc
@@ -243,7 +243,8 @@
void ModemProxy::Proxy::StateChanged(const int32_t &old,
const int32_t &_new,
const uint32_t &reason) {
- state_changed_callback_.Run(old, _new, reason);
+ if (!state_changed_callback_.is_null())
+ state_changed_callback_.Run(old, _new, reason);
}
// Method callbacks inherited from
diff --git a/modem.cc b/modem.cc
index 899918a..a9f2e55 100644
--- a/modem.cc
+++ b/modem.cc
@@ -40,7 +40,8 @@
provider_db_(provider_db),
type_(Cellular::kTypeInvalid),
pending_device_info_(false),
- rtnl_handler_(RTNLHandler::GetInstance()) {
+ rtnl_handler_(RTNLHandler::GetInstance()),
+ proxy_factory_(ProxyFactory::GetInstance()) {
LOG(INFO) << "Modem created: " << owner << " at " << path;
}
@@ -52,9 +53,7 @@
void Modem::Init() {
dbus_properties_proxy_.reset(
- ProxyFactory::GetInstance()->CreateDBusPropertiesProxy(this,
- path(),
- owner()));
+ proxy_factory_->CreateDBusPropertiesProxy(this, path(), owner()));
}
void Modem::OnDeviceInfoAvailable(const string &link_name) {
@@ -121,17 +120,18 @@
return;
}
- if (type_ == Cellular::kTypeUniversal) {
- // TODO(rochberg):
- LOG(ERROR) << "Cannot construct Cellular object for MM1";
- return;
- }
-
string address = address_bytes.HexEncode();
device_ = ConstructCellular(link_name_, address, interface_index);
- uint32 modem_state = Cellular::kModemStateUnknown;
- DBusProperties::GetUint32(modem_properties, kPropertyState, &modem_state);
+ // Note: 0 happens to map to Cellular::kModemStateUnknown for all
+ // types of modems
+ uint32 modem_state = 0;
+ // TODO(jglasgow): refactor to avoid explicit if on modem type. The
+ // ModemManager1 interface type is an "i" not a "u". Handle that
+ // during refactoring.
+ if (type_ != Cellular::kTypeUniversal)
+ DBusProperties::GetUint32(modem_properties, kPropertyState, &modem_state);
+
device_->set_modem_state(ConvertMmToCellularModemState(modem_state));
// Give the device a chance to extract any capability-specific properties.
@@ -141,10 +141,14 @@
}
void Modem::OnDBusPropertiesChanged(
- const string &/*interface*/,
- const DBusPropertiesMap &/*changed_properties*/,
- const vector<string> &/*invalidated_properties*/) {
- // Ignored.
+ const string &interface,
+ const DBusPropertiesMap &changed_properties,
+ const vector<string> &invalidated_properties) {
+ if (device().get()) {
+ device()->OnDBusPropertiesChanged(interface,
+ changed_properties,
+ invalidated_properties);
+ }
}
void Modem::OnModemManagerPropertiesChanged(
diff --git a/modem.h b/modem.h
index 0eb684c..92789ff 100644
--- a/modem.h
+++ b/modem.h
@@ -9,6 +9,7 @@
#include <vector>
#include <base/basictypes.h>
+#include <base/file_util.h>
#include <base/memory/scoped_ptr.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
@@ -82,7 +83,11 @@
private:
friend class ModemTest;
+ friend class Modem1Test;
+ FRIEND_TEST(Modem1Test, Init);
+ FRIEND_TEST(Modem1Test, CreateDeviceMM1);
FRIEND_TEST(ModemManager1Test, Connect);
+ FRIEND_TEST(ModemManager1Test, AddRemoveInterfaces);
FRIEND_TEST(ModemManagerClassicTest, Connect);
FRIEND_TEST(ModemManagerCoreTest, ShouldAddModem);
FRIEND_TEST(ModemTest, CreateDeviceEarlyFailures);
@@ -120,6 +125,9 @@
bool pending_device_info_;
RTNLHandler *rtnl_handler_;
+ // Store cached copies of singletons for speed/ease of testing.
+ ProxyFactory *proxy_factory_;
+
DISALLOW_COPY_AND_ASSIGN(Modem);
};
@@ -148,8 +156,6 @@
};
class Modem1 : public Modem {
- // TODO(rochberg) Need to register to receive DBus property changes.
- // crosbug.com/28596
public:
Modem1(const std::string &owner,
const std::string &path,
@@ -170,6 +176,10 @@
std::string *name) const;
private:
+ friend class Modem1Test;
+
+ FilePath netfiles_path_; // Used for testing
+
DISALLOW_COPY_AND_ASSIGN(Modem1);
};
diff --git a/modem_1.cc b/modem_1.cc
index e8fc65f..df71d67 100644
--- a/modem_1.cc
+++ b/modem_1.cc
@@ -14,6 +14,11 @@
namespace shill {
+namespace {
+// The default place where the system keeps symbolic links for network device
+const char kDefaultNetfilesPath[] = "/sys/class/net";
+} // namespace {}
+
Modem1::Modem1(const string &owner,
const string &path,
ControlInterface *control_interface,
@@ -22,7 +27,8 @@
Manager *manager,
mobile_provider_db *provider_db)
: Modem(owner, path, control_interface, dispatcher, metrics, manager,
- provider_db) {
+ provider_db),
+ netfiles_path_(kDefaultNetfilesPath) {
}
Modem1::~Modem1() {}
@@ -52,7 +58,7 @@
string *name) const {
string device_prop;
if (!DBusProperties::GetString(modem_props,
- Modem::kPropertyLinkName,
+ MM_MODEM_PROPERTY_DEVICE,
&device_prop)) {
return false;
}
@@ -61,16 +67,15 @@
// /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-2
FilePath device_path(device_prop);
- // Each entry in /sys/class/net has the name of a network interface
- // and is a symlink into the actual device structure:
+ // Each entry in |netfiles_path_" (typically /sys/class/net)
+ // has the name of a network interface and is a symlink into the
+ // actual device structure:
// eth0 -> ../../devices/pci0000:00/0000:00:1c.5/0000:01:00.0/net/eth0
// Iterate over all of these and see if any of them point into
// subdirectories of the sysfs path from the Device property.
- FilePath netfiles_path("/sys/class/net");
-
// FileEnumerator warns that it is a blocking interface; that
// shouldn't be a problem here.
- file_util::FileEnumerator netfiles(netfiles_path,
+ file_util::FileEnumerator netfiles(netfiles_path_,
false, // don't recurse
file_util::FileEnumerator::DIRECTORIES);
for (FilePath link = netfiles.Next(); !link.empty(); link = netfiles.Next()) {
@@ -78,7 +83,7 @@
if (!file_util::ReadSymbolicLink(link, &target))
continue;
if (!target.IsAbsolute())
- target = netfiles_path.Append(target);
+ target = netfiles_path_.Append(target);
if (file_util::ContainsPath(device_path, target)) {
*name = link.BaseName().value();
return true;
@@ -99,6 +104,8 @@
// We cannot check the IP method to make sure it's not PPP. The IP
// method will be checked later when the bearer object is fetched.
+ // TODO(jglasgow): We should pass i_to_p because there are lots of
+ // properties we might want
CreateDeviceFromModemProperties(modem_properties->second);
}
diff --git a/modem_1_unittest.cc b/modem_1_unittest.cc
new file mode 100644
index 0000000..b50370a
--- /dev/null
+++ b/modem_1_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/modem.h"
+
+#include <base/scoped_temp_dir.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <mm/ModemManager-enums.h>
+#include <mm/ModemManager-names.h>
+
+#include "shill/dbus_property_matchers.h"
+#include "shill/event_dispatcher.h"
+#include "shill/manager.h"
+#include "shill/mock_cellular.h"
+#include "shill/mock_control.h"
+#include "shill/mock_dbus_properties_proxy.h"
+#include "shill/mock_device_info.h"
+#include "shill/mock_glib.h"
+#include "shill/mock_manager.h"
+#include "shill/mock_metrics.h"
+#include "shill/mock_rtnl_handler.h"
+#include "shill/proxy_factory.h"
+#include "shill/rtnl_handler.h"
+
+using std::string;
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::Test;
+
+namespace shill {
+
+namespace {
+
+const int kTestInterfaceIndex = 5;
+const char kLinkName[] = "usb0";
+const char kOwner[] = ":1.18";
+const char kPath[] = "/org/chromium/ModemManager/Gobi/0";
+const unsigned char kAddress[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+const char kAddressAsString[] = "000102030405";
+
+} // namespace
+
+class Modem1Test : public Test {
+ public:
+ Modem1Test()
+ : manager_(&control_interface_, &dispatcher_, &metrics_, &glib_),
+ info_(&control_interface_, &dispatcher_, &metrics_, &manager_),
+ proxy_(new MockDBusPropertiesProxy()),
+ proxy_factory_(this),
+ modem_(
+ new Modem1(
+ kOwner,
+ kPath,
+ &control_interface_,
+ &dispatcher_,
+ &metrics_,
+ &manager_,
+ static_cast<mobile_provider_db *>(NULL))) {}
+ virtual void SetUp();
+ virtual void TearDown();
+
+ void ReplaceSingletons() {
+ modem_->rtnl_handler_ = &rtnl_handler_;
+ modem_->proxy_factory_ = &proxy_factory_;
+ }
+
+ protected:
+ class TestProxyFactory : public ProxyFactory {
+ public:
+ explicit TestProxyFactory(Modem1Test *test) : test_(test) {}
+
+ virtual DBusPropertiesProxyInterface *CreateDBusPropertiesProxy(
+ DBusPropertiesProxyDelegate */*delegate*/,
+ const string &/*path*/,
+ const string &/*service*/) {
+ return test_->proxy_.release();
+ }
+
+ private:
+ Modem1Test *test_;
+ };
+
+ MockGLib glib_;
+ MockControl control_interface_;
+ EventDispatcher dispatcher_;
+ MockMetrics metrics_;
+ MockManager manager_;
+ MockDeviceInfo info_;
+ scoped_ptr<MockDBusPropertiesProxy> proxy_;
+ TestProxyFactory proxy_factory_;
+ scoped_ptr<Modem1> modem_;
+ MockRTNLHandler rtnl_handler_;
+ ByteString expected_address_;
+ ScopedTempDir temp_dir_;
+ string device_;
+};
+
+void Modem1Test::SetUp() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ modem_->netfiles_path_ = temp_dir_.path();
+ device_ = temp_dir_.path().Append("devices").Append(kLinkName).value();
+ FilePath device_dir = FilePath(device_).Append("1-2/3-4");
+ ASSERT_TRUE(file_util::CreateDirectory(device_dir));
+ FilePath symlink(temp_dir_.path().Append(kLinkName));
+ ASSERT_TRUE(file_util::CreateSymbolicLink(device_dir, symlink));
+
+ EXPECT_EQ(kOwner, modem_->owner_);
+ EXPECT_EQ(kPath, modem_->path_);
+ ReplaceSingletons();
+ expected_address_ = ByteString(kAddress, arraysize(kAddress));
+
+ EXPECT_CALL(rtnl_handler_, GetInterfaceIndex(kLinkName)).
+ WillRepeatedly(Return(kTestInterfaceIndex));
+
+ EXPECT_CALL(manager_, device_info()).WillRepeatedly(Return(&info_));
+ EXPECT_CALL(info_, GetMACAddress(kTestInterfaceIndex, _)).
+ WillOnce(DoAll(SetArgumentPointee<1>(expected_address_),
+ Return(true)));
+}
+
+void Modem1Test::TearDown() {
+ modem_.reset();
+}
+
+TEST_F(Modem1Test, CreateDeviceMM1) {
+ DBusInterfaceToProperties i_to_p;
+ DBusPropertiesMap modem_properties;
+ DBus::Variant lock;
+ lock.writer().append_uint32(MM_MODEM_LOCK_NONE);
+ modem_properties[MM_MODEM_PROPERTY_UNLOCKREQUIRED] = lock;
+ DBus::Variant device_variant;
+ device_variant.writer().append_string(device_.c_str());
+ modem_properties[MM_MODEM_PROPERTY_DEVICE] = device_variant;
+ i_to_p[MM_DBUS_INTERFACE_MODEM] = modem_properties;
+
+ modem_->CreateDeviceMM1(i_to_p);
+ EXPECT_TRUE(modem_->device().get());
+}
+
+} // namespace shill
diff --git a/modem_unittest.cc b/modem_unittest.cc
index 9e609e2..e9430ac 100644
--- a/modem_unittest.cc
+++ b/modem_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "shill/modem.h"
+
#include <vector>
#include <gmock/gmock.h>
@@ -24,7 +26,6 @@
#include "shill/mock_metrics.h"
#include "shill/mock_modem.h"
#include "shill/mock_rtnl_handler.h"
-#include "shill/modem.h"
#include "shill/proxy_factory.h"
#include "shill/rtnl_handler.h"
@@ -80,8 +81,6 @@
modem_->rtnl_handler_ = &rtnl_handler_;
}
- void ExpectLinkRelatedCalls();
-
protected:
class TestProxyFactory : public ProxyFactory {
public: