shill: WiFi: Add TDLS operations to Device RPC API
Add a "PerformTDLSOperation" method to the Device API. This is
only implemented in WiFi, which dispatches to the various TDLS
methods available on the supplicant proxy.
CQ-DEPEND=CL:176670
BUG=chromium:316758
TEST=Unit tests
Change-Id: I9c2179111fe61d5f520ced5f1f6561c01d9aeeb7
Reviewed-on: https://chromium-review.googlesource.com/176720
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
diff --git a/dbus_bindings/org.chromium.flimflam.Device.xml b/dbus_bindings/org.chromium.flimflam.Device.xml
index 8120263..c76cbd6 100644
--- a/dbus_bindings/org.chromium.flimflam.Device.xml
+++ b/dbus_bindings/org.chromium.flimflam.Device.xml
@@ -38,6 +38,11 @@
<arg type="s" direction="in"/>
<arg type="s" direction="in"/>
</method>
+ <method name="PerformTDLSOperation">
+ <arg type="s" direction="in"/>
+ <arg type="s" direction="in"/>
+ <arg type="s" direction="out"/>
+ </method>
<method name="Reset"/>
<method name="ResetByteCounters"/>
<method name="SetCarrier">
diff --git a/device.cc b/device.cc
index 70e95cb..a93b99b 100644
--- a/device.cc
+++ b/device.cc
@@ -647,6 +647,12 @@
return true;
}
+string Device::PerformTDLSOperation(const string &/* operation */,
+ const string &/* peer */,
+ Error */* error */) {
+ return "";
+}
+
void Device::ResetByteCounters() {
manager_->device_info()->GetByteCounts(
interface_index_, &receive_byte_offset_, &transmit_byte_offset_);
diff --git a/device.h b/device.h
index 95f8ff8..0c1995a 100644
--- a/device.h
+++ b/device.h
@@ -172,6 +172,16 @@
virtual uint64 GetReceiveByteCount();
virtual uint64 GetTransmitByteCount();
+ // Perform a TDLS |operation| on the underlying device, with respect
+ // to a given |peer|. The string returned is empty for any operation
+ // other than kTDLSOperationStatus, which returns the state of the
+ // TDLS link with |peer|. This method is only valid for WiFi devices,
+ // but needs to be declared here since it is part of the Device RPC
+ // API.
+ virtual std::string PerformTDLSOperation(const std::string &operation,
+ const std::string &peer,
+ Error *error);
+
// Reset the persisted byte counters associated with the device.
void ResetByteCounters();
diff --git a/device_dbus_adaptor.cc b/device_dbus_adaptor.cc
index f415c9d..49f22e4 100644
--- a/device_dbus_adaptor.cc
+++ b/device_dbus_adaptor.cc
@@ -179,6 +179,15 @@
ReturnResultOrDefer(tag, e, &error);
}
+string DeviceDBusAdaptor::PerformTDLSOperation(const string &operation,
+ const string &peer,
+ DBus::Error &error) {
+ Error e;
+ string return_value = device_->PerformTDLSOperation(operation, peer, &e);
+ e.ToDBusError(&error);
+ return return_value;
+}
+
void DeviceDBusAdaptor::ResetByteCounters(DBus::Error &error) {
device_->ResetByteCounters();
}
diff --git a/device_dbus_adaptor.h b/device_dbus_adaptor.h
index 24be142..0663d0b 100644
--- a/device_dbus_adaptor.h
+++ b/device_dbus_adaptor.h
@@ -66,6 +66,9 @@
virtual void ChangePin(const std::string &old_pin,
const std::string &new_pin,
::DBus::Error &error);
+ virtual std::string PerformTDLSOperation(const std::string &operation,
+ const std::string &peer,
+ ::DBus::Error &error);
virtual void Reset(::DBus::Error &error);
virtual void ResetByteCounters(::DBus::Error &error);
virtual void SetCarrier(const std::string &carrier, ::DBus::Error &error);
diff --git a/device_unittest.cc b/device_unittest.cc
index ef2a942..2d57f43 100644
--- a/device_unittest.cc
+++ b/device_unittest.cc
@@ -689,6 +689,11 @@
EXPECT_FALSE(device_->ShouldUseMinimalDHCPConfig());
}
+TEST_F(DeviceTest, PerformTDLSOperation) {
+ EXPECT_EQ("",
+ device_->PerformTDLSOperation("do something", "to someone", NULL));
+}
+
class DevicePortalDetectionTest : public DeviceTest {
public:
DevicePortalDetectionTest()
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 2c2bdcd..6370b18 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -169,6 +169,26 @@
Reset the device's persisted counters of transmitted
+ string PerformTDLSOperation(string operation,
+ string peer) [readwrite]
+
+ (WiFi only) Perform a TDLS operation on a peer
+ station. The |peer| argument should be a mac
+ address specified in traditional colon-separated
+ hexidecimal notation, e.g., "aa:bb:cc:dd:ee:ff".
+ algorithm. The |operation| parameter should
+ be one of the following:
+
+ "Discover" : Perform TDLS discovery with |peer|.
+ "Setup" : Setup TDLS peering with |peer|.
+ "Status" : Return TDLS status for |peer|.
+ "Teardown" : Tear down TDLS peering with |peer|.
+
+ The method returns without an error if the operation
+ is initiated successfully with the supplicant, but
+ before it is clear whether the operation actually
+ succeeded.
+
Signals PropertyChanged(string name, variant value)
This signal indicates a changed value of the given
diff --git a/wifi.cc b/wifi.cc
index 4723290..7593cf8 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -2418,6 +2418,7 @@
try {
supplicant_interface_proxy_->TDLSDiscover(peer);
} catch (const DBus::Error &e) { // NOLINT
+ LOG(ERROR) << "exception while performing TDLS discover: " << e.what();
return false;
}
return true;
@@ -2427,6 +2428,7 @@
try {
supplicant_interface_proxy_->TDLSSetup(peer);
} catch (const DBus::Error &e) { // NOLINT
+ LOG(ERROR) << "exception while performing TDLS setup: " << e.what();
return false;
}
return true;
@@ -2436,6 +2438,7 @@
try {
return supplicant_interface_proxy_->TDLSStatus(peer);
} catch (const DBus::Error &e) { // NOLINT
+ LOG(ERROR) << "exception while getting TDLS status: " << e.what();
return "";
}
}
@@ -2444,9 +2447,54 @@
try {
supplicant_interface_proxy_->TDLSTeardown(peer);
} catch (const DBus::Error &e) { // NOLINT
+ LOG(ERROR) << "exception while performing TDLS teardown: " << e.what();
return false;
}
return true;
}
+string WiFi::PerformTDLSOperation(const string &operation,
+ const string &peer,
+ Error *error) {
+ bool success = false;
+
+ SLOG(WiFi, 2) << "TDLS command received: " << operation
+ << " for peer " << peer;
+ if (operation == kTDLSDiscoverOperation) {
+ success = TDLSDiscover(peer);
+ } else if (operation == kTDLSSetupOperation) {
+ success = TDLSSetup(peer);
+ } else if (operation == kTDLSStatusOperation) {
+ string supplicant_status = TDLSStatus(peer);
+ SLOG(WiFi, 2) << "TDLS status returned: " << supplicant_status;
+ if (!supplicant_status.empty()) {
+ if (supplicant_status == WPASupplicant::kTDLSStateConnected) {
+ return kTDLSConnectedState;
+ } else if (supplicant_status == WPASupplicant::kTDLSStateDisabled) {
+ return kTDLSDisabledState;
+ } else if (supplicant_status ==
+ WPASupplicant::kTDLSStatePeerDoesNotExist) {
+ return kTDLSNonexistentState;
+ } else if (supplicant_status ==
+ WPASupplicant::kTDLSStatePeerNotConnected) {
+ return kTDLSDisconnectedState;
+ } else {
+ return kTDLSUnknownState;
+ }
+ }
+ } else if (operation == kTDLSTeardownOperation) {
+ success = TDLSTeardown(peer);
+ } else {
+ error->Populate(Error::kInvalidArguments, "Unknown operation");
+ return "";
+ }
+
+ if (!success) {
+ Error::PopulateAndLog(error, Error::kOperationFailed,
+ "TDLS operation failed");
+ }
+
+ return "";
+}
+
} // namespace shill
diff --git a/wifi.h b/wifi.h
index 2f26271..8e844ec 100644
--- a/wifi.h
+++ b/wifi.h
@@ -212,6 +212,10 @@
// initiated successfully.
bool TDLSTeardown(const std::string &peer);
+ // Perform TDLS |operation| on |peer|.
+ virtual std::string PerformTDLSOperation(const std::string &operation,
+ const std::string &peer,
+ Error *error) override;
private:
enum ScanMethod {
kScanMethodNone,
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index d728777..8851d53 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -843,6 +843,12 @@
return wifi_->TDLSTeardown(peer);
}
+ string PerformTDLSOperation(const string &operation,
+ const string &peer,
+ Error *error) {
+ return wifi_->PerformTDLSOperation(operation, peer, error);
+ }
+
void TimeoutPendingConnection() {
wifi_->PendingTimeoutHandler();
}
@@ -3396,7 +3402,7 @@
ExpectScanIdle();
}
-TEST_F(WiFiMainTest, TDLS) {
+TEST_F(WiFiMainTest, TDLSInterfaceFunctions) {
StartWiFi();
const char kPeer[] = "peer";
@@ -3442,4 +3448,101 @@
Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
}
+TEST_F(WiFiMainTest, PerformTDLSOperation) {
+ StartWiFi();
+ const char kPeer[] = "peer";
+
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation("Do the thing", kPeer, &error));
+ EXPECT_EQ(Error::kInvalidArguments, error.type());
+ }
+
+ // This is the same test as TDLSInterfaceFunctions above, but using the
+ // method called by the RPC adapter.
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(), TDLSDiscover(StrEq(kPeer)))
+ .WillOnce(Return())
+ .WillOnce(Throw(
+ DBus::Error(
+ "fi.w1.wpa_supplicant1.UnknownError",
+ "test threw fi.w1.wpa_supplicant1.UnknownError")));
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSDiscoverOperation, kPeer, &error));
+ EXPECT_TRUE(error.IsSuccess());
+ }
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSDiscoverOperation, kPeer, &error));
+ EXPECT_EQ(Error::kOperationFailed, error.type());
+ }
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(), TDLSSetup(StrEq(kPeer)))
+ .WillOnce(Return())
+ .WillOnce(Throw(
+ DBus::Error(
+ "fi.w1.wpa_supplicant1.UnknownError",
+ "test threw fi.w1.wpa_supplicant1.UnknownError")));
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSSetupOperation, kPeer, &error));
+ EXPECT_TRUE(error.IsSuccess());
+ }
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSSetupOperation, kPeer, &error));
+ EXPECT_EQ(Error::kOperationFailed, error.type());
+ }
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+
+
+ const map<string, string> kTDLSStatusMap {
+ { "Baby, I don't care", kTDLSUnknownState },
+ { WPASupplicant::kTDLSStateConnected, kTDLSConnectedState },
+ { WPASupplicant::kTDLSStateDisabled, kTDLSDisabledState },
+ { WPASupplicant::kTDLSStatePeerDoesNotExist, kTDLSNonexistentState },
+ { WPASupplicant::kTDLSStatePeerNotConnected, kTDLSDisconnectedState },
+ };
+
+ for (const auto &it : kTDLSStatusMap) {
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(), TDLSStatus(StrEq(kPeer)))
+ .WillOnce(Return(it.first));
+ Error error;
+ EXPECT_EQ(it.second,
+ PerformTDLSOperation(kTDLSStatusOperation, kPeer, &error));
+ EXPECT_TRUE(error.IsSuccess());
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ }
+
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(), TDLSStatus(StrEq(kPeer)))
+ .WillOnce(Throw(
+ DBus::Error(
+ "fi.w1.wpa_supplicant1.UnknownError",
+ "test threw fi.w1.wpa_supplicant1.UnknownError")));
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSStatusOperation, kPeer, &error));
+ EXPECT_EQ(Error::kOperationFailed, error.type());
+ }
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(), TDLSTeardown(StrEq(kPeer)))
+ .WillOnce(Return())
+ .WillOnce(Throw(
+ DBus::Error(
+ "fi.w1.wpa_supplicant1.UnknownError",
+ "test threw fi.w1.wpa_supplicant1.UnknownError")));
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSTeardownOperation, kPeer, &error));
+ EXPECT_TRUE(error.IsSuccess());
+ }
+ {
+ Error error;
+ EXPECT_EQ("", PerformTDLSOperation(kTDLSTeardownOperation, kPeer, &error));
+ EXPECT_EQ(Error::kOperationFailed, error.type());
+ }
+}
+
} // namespace shill
diff --git a/wpa_supplicant.cc b/wpa_supplicant.cc
index d7a4acc..91a8493 100644
--- a/wpa_supplicant.cc
+++ b/wpa_supplicant.cc
@@ -132,6 +132,11 @@
const char WPASupplicant::kSecurityModeRSN[] = "RSN";
const char WPASupplicant::kSecurityModeWPA[] = "WPA";
+const char WPASupplicant::kTDLSStateConnected[] = "connected";
+const char WPASupplicant::kTDLSStateDisabled[] = "disabled";
+const char WPASupplicant::kTDLSStatePeerDoesNotExist[] = "peer does not exist";
+const char WPASupplicant::kTDLSStatePeerNotConnected[] = "peer not connected";
+
const uint32_t WPASupplicant::kDefaultEngine = 1;
const uint32_t WPASupplicant::kNetworkIeee80211wDisabled = 0;
const uint32_t WPASupplicant::kNetworkIeee80211wEnabled = 1;
diff --git a/wpa_supplicant.h b/wpa_supplicant.h
index 9736bc0..7736bd1 100644
--- a/wpa_supplicant.h
+++ b/wpa_supplicant.h
@@ -122,6 +122,10 @@
static const char kSecurityMethodPropertyKeyManagement[];
static const char kSecurityModeRSN[];
static const char kSecurityModeWPA[];
+ static const char kTDLSStateConnected[];
+ static const char kTDLSStateDisabled[];
+ static const char kTDLSStatePeerDoesNotExist[];
+ static const char kTDLSStatePeerNotConnected[];
static const uint32_t kDefaultEngine;
static const uint32_t kNetworkIeee80211wDisabled;