wifi(implementation): Set randomized MAC address for AP
Add the plumbing required for setting a random MAC address on AP
startup. The random MAC address is created once for the lifetime of
the daemon and then reused for any further AP creation. This would
ensure that the MAC address is changed on every reboot.
The feature is turned on by default, devices will need to set the
|WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION| in their .mk file to
disable the feature at compile time.
Bug: 78353419
Test: ./hardware/interfaces/wifi/1.3/default/tests/runtests.sh
Change-Id: I054d5249c20cc582b76966313135295873cd0b61
diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk
index eb07a9a..7ebea4f 100644
--- a/wifi/1.3/default/Android.mk
+++ b/wifi/1.3/default/Android.mk
@@ -33,6 +33,9 @@
ifdef WIFI_HIDL_FEATURE_DISABLE_AP
LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+endif
# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
LOCAL_SRC_FILES := \
@@ -144,6 +147,7 @@
tests/mock_wifi_legacy_hal.cpp \
tests/mock_wifi_mode_controller.cpp \
tests/ringbuffer_unit_tests.cpp \
+ tests/wifi_ap_iface_unit_tests.cpp \
tests/wifi_chip_unit_tests.cpp
LOCAL_STATIC_LIBRARIES := \
libgmock \
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.h b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
index 8b0baa4..ee12b54 100644
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
@@ -34,6 +34,7 @@
MockWifiFeatureFlags();
MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+ MOCK_METHOD0(isApMacRandomizationDisabled, bool());
};
} // namespace feature_flags
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.h b/wifi/1.3/default/tests/mock_wifi_iface_util.h
index 6fb8f71..87ab5db 100644
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.h
+++ b/wifi/1.3/default/tests/mock_wifi_iface_util.h
@@ -35,6 +35,7 @@
std::array<uint8_t, 6>(const std::string&));
MOCK_METHOD2(setMacAddress,
bool(const std::string&, const std::array<uint8_t, 6>&));
+ MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
};
} // namespace iface_util
} // namespace implementation
diff --git a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
new file mode 100644
index 0000000..28e028b
--- /dev/null
+++ b/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_ap_iface.h"
+
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_3 {
+namespace implementation {
+
+class WifiApIfaceTest : public Test {
+ protected:
+ std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+ new NiceMock<legacy_hal::MockWifiLegacyHal>};
+ std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+ new NiceMock<iface_util::MockWifiIfaceUtil>};
+ std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
+ feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+};
+
+TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) {
+ EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
+ .WillOnce(testing::Return(false));
+ EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress())
+ .WillOnce(testing::Return(std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}));
+ EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_))
+ .WillOnce(testing::Return(true));
+ sp<WifiApIface> ap_iface =
+ new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
+}
+
+TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) {
+ EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
+ .WillOnce(testing::Return(true));
+ EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0);
+ EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0);
+ sp<WifiApIface> ap_iface =
+ new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
+}
+} // namespace implementation
+} // namespace V1_3
+} // namespace wifi
+} // namespace hardware
+} // namespace android
diff --git a/wifi/1.3/default/wifi_ap_iface.cpp b/wifi/1.3/default/wifi_ap_iface.cpp
index 025ece3..9a8681a 100644
--- a/wifi/1.3/default/wifi_ap_iface.cpp
+++ b/wifi/1.3/default/wifi_ap_iface.cpp
@@ -31,11 +31,26 @@
WifiApIface::WifiApIface(
const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
: ifname_(ifname),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
- is_valid_(true) {}
+ feature_flags_(feature_flags),
+ is_valid_(true) {
+ if (feature_flags_.lock()->isApMacRandomizationDisabled()) {
+ LOG(INFO) << "AP MAC randomization disabled";
+ return;
+ }
+ LOG(INFO) << "AP MAC randomization enabled";
+ // Set random MAC address
+ std::array<uint8_t, 6> randomized_mac =
+ iface_util_.lock()->getOrCreateRandomMacAddress();
+ bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac);
+ if (!status) {
+ LOG(ERROR) << "Failed to set random mac address";
+ }
+}
void WifiApIface::invalidate() {
legacy_hal_.reset();
diff --git a/wifi/1.3/default/wifi_ap_iface.h b/wifi/1.3/default/wifi_ap_iface.h
index 6dbfc18..98c5c9c 100644
--- a/wifi/1.3/default/wifi_ap_iface.h
+++ b/wifi/1.3/default/wifi_ap_iface.h
@@ -20,8 +20,8 @@
#include <android-base/macros.h>
#include <android/hardware/wifi/1.0/IWifiApIface.h>
+#include "wifi_feature_flags.h"
#include "wifi_iface_util.h"
-
#include "wifi_legacy_hal.h"
namespace android {
@@ -36,9 +36,11 @@
*/
class WifiApIface : public V1_0::IWifiApIface {
public:
- WifiApIface(const std::string& ifname,
- const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
- const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+ WifiApIface(
+ const std::string& ifname,
+ const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+ const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+ const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
@@ -63,6 +65,7 @@
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+ std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiApIface);
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
index 9640a61..906f14a 100644
--- a/wifi/1.3/default/wifi_chip.cpp
+++ b/wifi/1.3/default/wifi_chip.cpp
@@ -777,7 +777,8 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = allocateApOrStaIfaceName();
- sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
+ sp<WifiApIface> iface =
+ new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.3/default/wifi_feature_flags.cpp
index 17b3bee..7212cfa 100644
--- a/wifi/1.3/default/wifi_feature_flags.cpp
+++ b/wifi/1.3/default/wifi_feature_flags.cpp
@@ -144,12 +144,22 @@
#undef P2P
#undef NAN
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+static const bool wifiHidlFeatureDisableApMacRandomization = true;
+#else
+static const bool wifiHidlFeatureDisableApMacRandomization = false;
+#endif // WIFI_HIDL_FEATURE_DISABLE_AP
+
WifiFeatureFlags::WifiFeatureFlags() {}
std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
return kChipModes;
}
+bool WifiFeatureFlags::isApMacRandomizationDisabled() {
+ return wifiHidlFeatureDisableApMacRandomization;
+}
+
} // namespace feature_flags
} // namespace implementation
} // namespace V1_3
diff --git a/wifi/1.3/default/wifi_feature_flags.h b/wifi/1.3/default/wifi_feature_flags.h
index b99a416..3ae6920 100644
--- a/wifi/1.3/default/wifi_feature_flags.h
+++ b/wifi/1.3/default/wifi_feature_flags.h
@@ -43,6 +43,7 @@
virtual ~WifiFeatureFlags() = default;
virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+ virtual bool isApMacRandomizationDisabled();
};
} // namespace feature_flags
diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.3/default/wifi_iface_util.cpp
index 39fa1e8..164aca7 100644
--- a/wifi/1.3/default/wifi_iface_util.cpp
+++ b/wifi/1.3/default/wifi_iface_util.cpp
@@ -27,7 +27,7 @@
namespace implementation {
namespace iface_util {
-WifiIfaceUtil::WifiIfaceUtil() {}
+WifiIfaceUtil::WifiIfaceUtil() : random_mac_address_(nullptr) {}
std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
const std::string& iface_name) {
@@ -52,6 +52,19 @@
return true;
}
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+ if (random_mac_address_) {
+ return *random_mac_address_.get();
+ }
+ random_mac_address_ =
+ std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+ return *random_mac_address_.get();
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+ // TODO: Generate random MAC address here.
+ return {};
+}
} // namespace iface_util
} // namespace implementation
} // namespace V1_3
diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.3/default/wifi_iface_util.h
index 9495322..b238234 100644
--- a/wifi/1.3/default/wifi_iface_util.h
+++ b/wifi/1.3/default/wifi_iface_util.h
@@ -40,9 +40,16 @@
const std::string& iface_name);
virtual bool setMacAddress(const std::string& iface_name,
const std::array<uint8_t, 6>& mac);
+ // Get or create a random MAC address. The MAC address returned from
+ // this method will remain the same throughout the lifetime of the HAL
+ // daemon. (So, changes on every reboot)
+ virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
private:
+ std::array<uint8_t, 6> createRandomMacAddress();
+
wifi_system::InterfaceTool iface_tool_;
+ std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
};
} // namespace iface_util