summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Caruso <ejcaruso@google.com>2016-04-20 17:31:38 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-04-20 17:31:38 +0000
commit8733437ffd3cde78e25b2e861dc6999ab1f72cb1 (patch)
tree670516d8c8943620797704c6b1899519983312ec
parentccca155e889ebe4136b87e1e82a59247834c8002 (diff)
parent30039ff068dacecc03e6a717bece58eb34d7f5b0 (diff)
downloadshill-8733437ffd3cde78e25b2e861dc6999ab1f72cb1.tar.gz
shill: Add MAC address randomization property
am: 30039ff * commit '30039ff068dacecc03e6a717bece58eb34d7f5b0': shill: Add MAC address randomization property Change-Id: Id4a144307c75eb21cc962421817fb566ae8218f5
-rw-r--r--dbus/chromeos_supplicant_interface_proxy.cc23
-rw-r--r--dbus/chromeos_supplicant_interface_proxy.h2
-rw-r--r--dbus_bindings/supplicant-interface.dbus-xml5
-rw-r--r--supplicant/mock_supplicant_interface_proxy.h3
-rw-r--r--supplicant/supplicant_interface_proxy_interface.h2
-rw-r--r--wifi/wifi.cc70
-rw-r--r--wifi/wifi.h18
-rw-r--r--wifi/wifi_unittest.cc99
8 files changed, 222 insertions, 0 deletions
diff --git a/dbus/chromeos_supplicant_interface_proxy.cc b/dbus/chromeos_supplicant_interface_proxy.cc
index c93e4574..5b950d41 100644
--- a/dbus/chromeos_supplicant_interface_proxy.cc
+++ b/dbus/chromeos_supplicant_interface_proxy.cc
@@ -341,6 +341,29 @@ bool ChromeosSupplicantInterfaceProxy::SetHT40Enable(const string& network,
return true;
}
+bool ChromeosSupplicantInterfaceProxy::EnableMACAddressRandomization(
+ const std::vector<unsigned char>& mask) {
+ SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__;
+ brillo::ErrorPtr error;
+ if (!interface_proxy_->EnableMACAddressRandomization(mask, &error)) {
+ LOG(ERROR) << "Failed to enable MAC address randomization: "
+ << error->GetCode() << " " << error->GetMessage();
+ return false;
+ }
+ return true;
+}
+
+bool ChromeosSupplicantInterfaceProxy::DisableMACAddressRandomization() {
+ SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__;
+ brillo::ErrorPtr error;
+ if (!interface_proxy_->DisableMACAddressRandomization(&error)) {
+ LOG(ERROR) << "Failed to enable MAC address randomization: "
+ << error->GetCode() << " " << error->GetMessage();
+ return false;
+ }
+ return true;
+}
+
bool ChromeosSupplicantInterfaceProxy::TDLSDiscover(const string& peer) {
SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__ << ": " << peer;
brillo::ErrorPtr error;
diff --git a/dbus/chromeos_supplicant_interface_proxy.h b/dbus/chromeos_supplicant_interface_proxy.h
index bee0ed29..5e90e10b 100644
--- a/dbus/chromeos_supplicant_interface_proxy.h
+++ b/dbus/chromeos_supplicant_interface_proxy.h
@@ -66,6 +66,8 @@ class ChromeosSupplicantInterfaceProxy
bool TDLSStatus(const std::string& peer, std::string* status) override;
bool TDLSTeardown(const std::string& peer) override;
bool SetHT40Enable(const std::string& network, bool enable) override;
+ bool EnableMACAddressRandomization(const std::vector<unsigned char>& mask) override;
+ bool DisableMACAddressRandomization() override;
// The below set functions will always return true, since PropertySet::Set
// is an async method. Any failures will be logged in the callback.
bool SetFastReauth(bool enabled) override;
diff --git a/dbus_bindings/supplicant-interface.dbus-xml b/dbus_bindings/supplicant-interface.dbus-xml
index 8235b83f..d111b38c 100644
--- a/dbus_bindings/supplicant-interface.dbus-xml
+++ b/dbus_bindings/supplicant-interface.dbus-xml
@@ -70,6 +70,11 @@
<arg name="network" type="o" direction="in"/>
<arg name="enable" type="b" direction="in"/>
</method>
+ <method name="EnableMACAddressRandomization">
+ <arg name="mask" type="ay" direction="in"/>
+ </method>
+ <method name="DisableMACAddressRandomization">
+ </method>
<property name="Capabilities" type="a{sv}" access="read"/>
<property name="State" type="s" access="read"/>
<property name="Scanning" type="b" access="read"/>
diff --git a/supplicant/mock_supplicant_interface_proxy.h b/supplicant/mock_supplicant_interface_proxy.h
index f9db1bf4..5c507372 100644
--- a/supplicant/mock_supplicant_interface_proxy.h
+++ b/supplicant/mock_supplicant_interface_proxy.h
@@ -61,6 +61,9 @@ class MockSupplicantInterfaceProxy : public SupplicantInterfaceProxyInterface {
MOCK_METHOD2(TDLSStatus, bool(const std::string& peer, std::string* status));
MOCK_METHOD1(TDLSTeardown, bool(const std::string& peer));
MOCK_METHOD2(SetHT40Enable, bool(const std::string& network, bool enable));
+ MOCK_METHOD1(EnableMACAddressRandomization,
+ bool(const std::vector<unsigned char>& mask));
+ MOCK_METHOD0(DisableMACAddressRandomization, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockSupplicantInterfaceProxy);
diff --git a/supplicant/supplicant_interface_proxy_interface.h b/supplicant/supplicant_interface_proxy_interface.h
index e26279ee..8e4531e6 100644
--- a/supplicant/supplicant_interface_proxy_interface.h
+++ b/supplicant/supplicant_interface_proxy_interface.h
@@ -59,6 +59,8 @@ class SupplicantInterfaceProxyInterface {
std::string* status) = 0;
virtual bool TDLSTeardown(const std::string& peer) = 0;
virtual bool SetHT40Enable(const std::string& network, bool enable) = 0;
+ virtual bool EnableMACAddressRandomization(const std::vector<unsigned char>& mask) = 0;
+ virtual bool DisableMACAddressRandomization() = 0;
};
} // namespace shill
diff --git a/wifi/wifi.cc b/wifi/wifi.cc
index 1901c0e1..6a5b6428 100644
--- a/wifi/wifi.cc
+++ b/wifi/wifi.cc
@@ -117,6 +117,12 @@ const int WiFi::kPostScanFailedDelayMilliseconds = 10000;
// Invalid 802.11 disconnect reason code.
const int WiFi::kDefaultDisconnectReason = INT32_MAX;
+// The default random MAC mask is FF:FF:FF:00:00:00. Bits which are a 1 in
+// the mask stay the same during randomization, and bits which are 0 are
+// randomized. This mask means the OUI will remain unchanged but the last
+// three octets will be different.
+const std::vector<unsigned char> WiFi::kRandomMACMask{255, 255, 255, 0, 0, 0};
+
namespace {
bool IsPrintableAsciiChar(char c) {
return (c >= ' ' && c <= '~');
@@ -172,6 +178,8 @@ WiFi::WiFi(ControlInterface* control_interface,
min_frequencies_to_scan_(kMinumumFrequenciesToScan),
max_frequencies_to_scan_(std::numeric_limits<int>::max()),
scan_all_frequencies_(true),
+ random_mac_supported_(false),
+ random_mac_enabled_(false),
fraction_per_scan_(kDefaultFractionPerScan),
scan_state_(kScanIdle),
scan_method_(kScanMethodNone),
@@ -203,6 +211,10 @@ WiFi::WiFi(ControlInterface* control_interface,
kBgscanSignalThresholdProperty,
&WiFi::GetBgscanSignalThreshold,
&WiFi::SetBgscanSignalThreshold);
+ HelpRegisterDerivedBool(store,
+ kMACAddressRandomizationProperty,
+ &WiFi::GetRandomMACEnabled,
+ &WiFi::SetRandomMACEnabled);
store->RegisterDerivedKeyValueStore(
kLinkStatisticsProperty,
@@ -749,6 +761,30 @@ bool WiFi::SetScanInterval(const uint16_t& seconds, Error* /*error*/) {
return true;
}
+bool WiFi::GetRandomMACEnabled(Error* /*error*/) {
+ return random_mac_enabled_;
+}
+
+bool WiFi::SetRandomMACEnabled(const bool& enabled, Error* error) {
+ if (!random_mac_supported_) {
+ Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported,
+ "This WiFi device does not support MAC address randomization");
+ return false;
+ }
+ if (random_mac_enabled_ == enabled) {
+ return false;
+ }
+ if ((enabled &&
+ supplicant_interface_proxy_->EnableMACAddressRandomization(
+ kRandomMACMask)) ||
+ (!enabled &&
+ supplicant_interface_proxy_->DisableMACAddressRandomization())) {
+ random_mac_enabled_ = enabled;
+ return true;
+ }
+ return false;
+}
+
void WiFi::ClearBgscanMethod(const int& /*argument*/, Error* /*error*/) {
bgscan_method_.clear();
}
@@ -1165,6 +1201,27 @@ bool WiFi::ParseWiphyIndex(const Nl80211Message& nl80211_message) {
return true;
}
+void WiFi::ParseFeatureFlags(const Nl80211Message& nl80211_message) {
+ // Verify NL80211_CMD_NEW_WIPHY.
+ if (nl80211_message.command() != NewWiphyMessage::kCommand) {
+ LOG(ERROR) << "Received unexpected command: " << nl80211_message.command();
+ return;
+ }
+
+ uint32_t flags;
+ if (!nl80211_message.const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_FEATURE_FLAGS, &flags)) {
+ LOG(WARNING) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_FEATURE_FLAGS";
+ return;
+ }
+
+ random_mac_supported_ =
+ (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) &&
+ (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR);
+ SLOG(this, 7) << __func__ << ": "
+ << "Supports random MAC: " << random_mac_supported_;
+}
+
void WiFi::OnScanStarted(const NetlinkMessage& netlink_message) {
// We only handle scan triggers in this handler, which is are nl80211 messages
// with the NL80211_CMD_TRIGGER_SCAN command.
@@ -1736,6 +1793,16 @@ void WiFi::HelpRegisterDerivedUint16(
Uint16Accessor(new CustomAccessor<WiFi, uint16_t>(this, get, set)));
}
+void WiFi::HelpRegisterDerivedBool(
+ PropertyStore* store,
+ const string& name,
+ bool(WiFi::*get)(Error* error),
+ bool(WiFi::*set)(const bool& value, Error* error)) {
+ store->RegisterDerivedBool(
+ name,
+ BoolAccessor(new CustomAccessor<WiFi, bool>(this, get, set)));
+}
+
void WiFi::HelpRegisterConstDerivedBool(
PropertyStore* store,
const string& name,
@@ -2317,6 +2384,9 @@ void WiFi::OnNewWiphy(const Nl80211Message& nl80211_message) {
wake_on_wifi_->OnWiphyIndexReceived(wiphy_index_);
}
+ // This checks NL80211_ATTR_FEATURE_FLAGS.
+ ParseFeatureFlags(nl80211_message);
+
// The attributes, for this message, are complicated.
// NL80211_ATTR_BANDS contains an array of bands...
AttributeListConstRefPtr wiphy_bands;
diff --git a/wifi/wifi.h b/wifi/wifi.h
index 14072c6a..be45052d 100644
--- a/wifi/wifi.h
+++ b/wifi/wifi.h
@@ -372,6 +372,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface {
// Used to distinguish between a disconnect reason explicitly set by
// supplicant and a default.
static const int kDefaultDisconnectReason;
+ // Used when enabling MAC randomization to request that the OUI remain constant
+ // and the last three octets are randomized.
+ static const std::vector<unsigned char> kRandomMACMask;
void GetPhyInfo();
void AppendBgscan(WiFiService* service,
@@ -406,6 +409,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface {
bool SetScanInterval(const uint16_t& seconds, Error* error);
void ClearBgscanMethod(const int& argument, Error* error);
+ bool GetRandomMACEnabled(Error* error);
+ bool SetRandomMACEnabled(const bool& enabled, Error* error);
+
void CurrentBSSChanged(const std::string& new_bss);
void DisconnectReasonChanged(const int32_t new_disconnect_reason);
// Return the RPC identifier associated with the wpa_supplicant network
@@ -458,6 +464,11 @@ class WiFi : public Device, public SupplicantEventDelegateInterface {
const std::string& name,
uint16_t(WiFi::*get)(Error* error),
bool(WiFi::*set)(const uint16_t& value, Error* error));
+ void HelpRegisterDerivedBool(
+ PropertyStore* store,
+ const std::string& name,
+ bool(WiFi::*get)(Error* error),
+ bool(WiFi::*set)(const bool& value, Error* error));
void HelpRegisterConstDerivedBool(
PropertyStore* store,
const std::string& name,
@@ -602,6 +613,10 @@ class WiFi : public Device, public SupplicantEventDelegateInterface {
// Returns true iff the wiphy index was parsed successfully, false otherwise.
bool ParseWiphyIndex(const Nl80211Message& nl80211_message);
+ // Given a NL80211_CMD_NEW_WIPHY message |nl80211_message|, parses the
+ // feature flags and sets members of this WiFi class appropriately.
+ void ParseFeatureFlags(const Nl80211Message& nl80211_message);
+
// Callback invoked when the kernel broadcasts a notification that a scan has
// started.
virtual void OnScanStarted(const NetlinkMessage& netlink_message);
@@ -691,6 +706,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface {
size_t max_frequencies_to_scan_;
bool scan_all_frequencies_;
+ bool random_mac_supported_;
+ bool random_mac_enabled_;
+
// Holds the list of scan results waiting to be processed and a cancelable
// closure for processing the pending tasks in PendingScanResultsHandler().
std::unique_ptr<PendingScanResults> pending_scan_results_;
diff --git a/wifi/wifi_unittest.cc b/wifi/wifi_unittest.cc
index bf81af31..61545319 100644
--- a/wifi/wifi_unittest.cc
+++ b/wifi/wifi_unittest.cc
@@ -611,6 +611,12 @@ class WiFiObjectTest : public ::testing::TestWithParam<string> {
.WillByDefault(Return(true));
ON_CALL(*supplicant_interface_proxy_.get(), Scan(_))
.WillByDefault(Return(true));
+ ON_CALL(*supplicant_interface_proxy_.get(),
+ EnableMACAddressRandomization(_))
+ .WillByDefault(Return(true));
+ ON_CALL(*supplicant_interface_proxy_.get(),
+ DisableMACAddressRandomization())
+ .WillByDefault(Return(true));
ON_CALL(*supplicant_network_proxy_.get(), SetEnabled(_))
.WillByDefault(Return(true));
@@ -1272,6 +1278,25 @@ class WiFiObjectTest : public ::testing::TestWithParam<string> {
void SetWiphyIndex(uint32_t index) { wifi_->wiphy_index_ = index; }
+ void ParseFeatureFlags(const Nl80211Message& nl80211_message) {
+ wifi_->ParseFeatureFlags(nl80211_message);
+ }
+
+ bool GetRandomMACSupported() { return wifi_->random_mac_supported_; }
+
+ void SetRandomMACSupported(bool supported) {
+ wifi_->random_mac_supported_ = supported;
+ }
+
+ bool GetRandomMACEnabled() { return wifi_->random_mac_enabled_; }
+
+ void SetRandomMACEnabled(bool enabled) {
+ Error error;
+ wifi_->SetRandomMACEnabled(enabled, &error);
+ }
+
+ std::vector<unsigned char> GetRandomMACMask() { return WiFi::kRandomMACMask; }
+
std::set<uint16_t>* GetAllScanFrequencies() {
return &wifi_->all_scan_frequencies_;
}
@@ -4181,6 +4206,80 @@ TEST_F(WiFiMainTest, ParseWiphyIndex_Failure) {
EXPECT_CALL(*wake_on_wifi_, OnWiphyIndexReceived(_)).Times(0);
}
+TEST_F(WiFiMainTest, ParseFeatureFlags_RandomMACSupport) {
+ NewWiphyMessage msg;
+ NetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg));
+ msg.InitFromPacket(&packet, NetlinkMessage::MessageContext());
+ // Make sure the feature is marked unsupported
+ uint32_t flags;
+ msg.const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_FEATURE_FLAGS, &flags);
+ flags &= ~(NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR);
+ msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags);
+ ParseFeatureFlags(msg);
+ EXPECT_FALSE(GetRandomMACSupported());
+
+ // Make sure the feature is marked supported
+ msg.const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_FEATURE_FLAGS, &flags);
+ flags |= (NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR);
+ msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags);
+ ParseFeatureFlags(msg);
+ EXPECT_TRUE(GetRandomMACSupported());
+}
+
+TEST_F(WiFiMainTest, RandomMACProperty_Unsupported) {
+ StartWiFi();
+ SetRandomMACSupported(false);
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(),
+ EnableMACAddressRandomization(_)).Times(0);
+ SetRandomMACEnabled(true);
+ EXPECT_FALSE(GetRandomMACEnabled());
+}
+
+TEST_F(WiFiMainTest, RandomMACProperty_Supported) {
+ StartWiFi();
+ SetRandomMACSupported(true);
+
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(),
+ EnableMACAddressRandomization(GetRandomMACMask())).Times(1);
+ SetRandomMACEnabled(true);
+ EXPECT_TRUE(GetRandomMACEnabled());
+
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(),
+ DisableMACAddressRandomization()).Times(1);
+ SetRandomMACEnabled(false);
+ EXPECT_FALSE(GetRandomMACEnabled());
+}
+
+TEST_F(WiFiMainTest, RandomMACProperty_SupplicantFailed) {
+ StartWiFi();
+ SetRandomMACSupported(true);
+
+ // Test wpa_supplicant failing to enable random MAC.
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(),
+ EnableMACAddressRandomization(GetRandomMACMask()))
+ .WillOnce(Return(false));
+ SetRandomMACEnabled(true);
+ EXPECT_FALSE(GetRandomMACEnabled());
+
+ // Enable random MAC.
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ SetRandomMACEnabled(true);
+
+ // Test wpa_supplicant failing to disable random MAC.
+ Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy());
+ EXPECT_CALL(*GetSupplicantInterfaceProxy(),
+ DisableMACAddressRandomization()).WillOnce(Return(false));
+ SetRandomMACEnabled(false);
+ EXPECT_TRUE(GetRandomMACEnabled());
+}
+
TEST_F(WiFiMainTest, OnScanStarted_ActiveScan) {
SetWiphyIndex(kScanTriggerMsgWiphyIndex);
TriggerScanMessage msg;