[Tests]ACTS Tests for MAC randomization feature.
Bug: 122915559
Test: Ran locally.
Change-Id: I66b13995dde9525eafb4a7e70184513d1a0b80d2
diff --git a/acts/tests/google/wifi/WifiMacRandomizationTest.py b/acts/tests/google/wifi/WifiMacRandomizationTest.py
new file mode 100755
index 0000000..eaafb95
--- /dev/null
+++ b/acts/tests/google/wifi/WifiMacRandomizationTest.py
@@ -0,0 +1,429 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 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.
+
+import itertools
+import pprint
+import queue
+import time
+
+import acts.base_test
+import acts.signals as signals
+import acts.test_utils.wifi.wifi_test_utils as wutils
+import acts.utils
+
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+WifiEnums = wutils.WifiEnums
+
+# Default timeout used for reboot, toggle WiFi and Airplane mode,
+# for the system to settle down after the operation.
+DEFAULT_TIMEOUT = 10
+
+# Constants for WiFi state change operations.
+FORGET = 1
+TOGGLE = 2
+REBOOT_DUT = 3
+REBOOT_AP = 4
+
+# MAC Randomization setting constants.
+RANDOMIZATION_NONE = 0
+RANDOMIZATION_PERSISTENT = 1
+
+
+class WifiMacRandomizationTest(WifiBaseTest):
+ """Tests for APIs in Android's WifiManager class.
+
+ Test Bed Requirement:
+ * Atleast one Android device and atleast two Access Points.
+ * Several Wi-Fi networks visible to the device.
+ """
+
+ def __init__(self, controllers):
+ WifiBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ self.dut = self.android_devices[0]
+ self.dut_client = self.android_devices[1]
+ wutils.wifi_test_device_init(self.dut)
+ wutils.wifi_test_device_init(self.dut_client)
+ req_params = []
+ opt_param = [
+ "open_network", "reference_networks", "wep_networks"
+ ]
+ self.unpack_userparams(
+ req_param_names=req_params, opt_param_names=opt_param)
+
+ if "AccessPoint" in self.user_params:
+ if "AccessPoint" in self.user_params:
+ self.legacy_configure_ap_and_start(wep_network=True, ap_count=2)
+
+ asserts.assert_true(
+ len(self.reference_networks) > 0,
+ "Need at least one reference network with psk.")
+
+ wutils.wifi_toggle_state(self.dut, True)
+ wutils.wifi_toggle_state(self.dut_client, True)
+ self.wpapsk_2g = self.reference_networks[0]["2g"]
+ self.wpapsk_5g = self.reference_networks[0]["5g"]
+ self.wep_2g = self.wep_networks[0]["2g"]
+ self.wep_5g = self.wep_networks[0]["5g"]
+ self.open_2g = self.open_network[0]["2g"]
+ self.open_5g = self.open_network[0]["5g"]
+
+ def setup_test(self):
+ for ad in self.android_devices:
+ ad.droid.wakeLockAcquireBright()
+ ad.droid.wakeUpNow()
+ wutils.wifi_toggle_state(ad, True)
+
+ def teardown_test(self):
+ for ad in self.android_devices:
+ ad.droid.wakeLockRelease()
+ ad.droid.goToSleepNow()
+ wutils.reset_wifi(self.dut)
+ wutils.reset_wifi(self.dut_client)
+
+ def on_fail(self, test_name, begin_time):
+ pass
+ #self.dut.cat_adb_log(test_name, begin_time)
+ #self.dut.take_bug_report(test_name, begin_time)
+
+ def teardown_class(self):
+ if "AccessPoint" in self.user_params:
+ del self.user_params["reference_networks"]
+ del self.user_params["open_network"]
+ del self.user_params["wep_networks"]
+
+
+ """Helper Functions"""
+
+
+ def get_randomized_mac(self, network):
+ """Get the randomized MAC address.
+
+ Args:
+ network: dict, network information.
+
+ Returns:
+ The randomized MAC address string for the network.
+
+ """
+ return self.dut.droid.wifigetRandomizedMacAddress(network)
+
+ def connect_to_network_and_verify_mac_randomization(self, network,
+ status=RANDOMIZATION_PERSISTENT):
+ """Connect to the given network and verify MAC.
+
+ Args:
+ network: dict, the network information.
+ status: int, MAC randomization level.
+
+ Returns:
+ The randomized MAC addresss string.
+
+ """
+ wutils.connect_to_wifi_network(self.dut, network)
+ return self.verify_mac_randomization(network, status=status)
+
+ def verify_mac_randomization_and_add_to_list(self, network, mac_list):
+ """Connect to a network and populate it's MAC in a reference list,
+ that will be used to verify any repeated MAC addresses.
+
+ Args:
+ network: dict, the network information.
+ mac_list: list of MAC addresss strings.
+
+ """
+ rand_mac = self.connect_to_network_and_verify_mac_randomization(
+ network)
+ if rand_mac in mac_list:
+ raise signals.TestFailure('A new Randomized MAC was not generated '
+ ' for this network %s.' % network)
+ mac_list.append(rand_mac)
+
+ def verify_mac_randomization(self, network, status=RANDOMIZATION_PERSISTENT):
+ """Get the various types of MAC addresses for the device and verify.
+
+ Args:
+ network: dict, the network information.
+ status: int, MAC randomization level.
+
+ Returns:
+ The randomized MAC address string for the network.
+
+ """
+ network_info = self.dut.droid.wifiGetConnectionInfo()
+ factory_mac = self.dut.droid.wifigetFactorymacAddresses()[0]
+ randomized_mac = self.get_randomized_mac(network)
+ default_mac = network_info['mac_address']
+ self.log.info("Factory MAC = %s\nRandomized MAC = %s\nDefault MAC = %s" %
+ (factory_mac, randomized_mac, default_mac))
+
+ if status == RANDOMIZATION_NONE:
+ asserts.assert_true(default_mac == factory_mac, "Connection is not "
+ "using Factory MAC as the default MAC.")
+ message = ('Randomized MAC and Factory MAC are the same. '
+ 'Randomized MAC = %s, Factory MAC = %s' % (randomized_mac, factory_mac))
+ asserts.assert_true(randomized_mac != factory_mac, message)
+
+ message = ('Connection is not using randomized MAC as the default MAC. '
+ 'Randomized MAC = %s, Deafult MAC = %s' % (randomized_mac, default_mac))
+ # Uncomment after b/123355618 is resolved.
+ #asserts.assert_true(randomized_mac == default_mac, message)
+
+ return randomized_mac
+
+ def check_mac_persistence(self, network, condition):
+ """Check if the MAC is persistent after carrying out specific operations
+ like forget WiFi, toggle WiFi, reboot device and AP.
+
+ Args:
+ network: dict, The network information.
+ condition: int, value to trigger certain operation on the device.
+
+ Raises:
+ TestFaikure is the MAC is not persistent.
+
+ """
+ rand_mac1 = self.connect_to_network_and_verify_mac_randomization(network)
+
+ if condition == FORGET:
+ wutils.wifi_forget_network(self.dut, network['SSID'])
+
+ elif condition == TOGGLE:
+ wutils.wifi_toggle_state(self.dut, False)
+ wutils.wifi_toggle_state(self.dut, True)
+
+ elif condition == REBOOT_DUT:
+ self.dut.reboot()
+ time.sleep(DEFAULT_TIMEOUT)
+
+ elif condition == REBOOT_AP:
+ wutils.turn_ap_off(self, 1)
+ time.sleep(DEFAULT_TIMEOUT)
+ wutils.turn_ap_on(self, 1)
+ time.sleep(DEFAULT_TIMEOUT)
+
+ rand_mac2 = self.connect_to_network_and_verify_mac_randomization(network)
+
+ if rand_mac1 != rand_mac2:
+ raise signals.TestFailure('Randomized MAC is not persistent after '
+ 'forgetting networ. Old MAC = %s New MAC'
+ ' = %s' % (rand_mac1, rand_mac2))
+
+ """Tests"""
+
+
+ @test_tracker_info(uuid="2dd0a05e-a318-45a6-81cd-962e098fa242")
+ def test_set_mac_randomization_to_none(self):
+ network = self.wpapsk_2g
+ # Set macRandomizationSetting to RANDOMIZATION_NONE.
+ network["macRand"] = RANDOMIZATION_NONE
+ self.connect_to_network_and_verify_mac_randomization(network,
+ status=RANDOMIZATION_NONE)
+
+ @test_tracker_info(uuid="d9e64202-02d5-421a-967c-42e45f1f7f91")
+ def test_mac_randomization_wpapsk(self):
+ """Verify MAC randomization for a WPA network.
+
+ Steps:
+ 1. Connect to WPA network.
+ 2. Get the Factory, Randomized and Default MACs.
+ 3. Verify randomized MAC is the default MAC for the device.
+
+ """
+ self.connect_to_network_and_verify_mac_randomization(self.wpapsk_2g)
+
+ @test_tracker_info(uuid="b5be7c53-2edf-449e-ba70-a1fb7acf735e")
+ def test_mac_randomization_wep(self):
+ """Verify MAC randomization for a WEP network.
+
+ Steps:
+ 1. Connect to WEP network.
+ 2. Get the Factory, Randomized and Default MACs.
+ 3. Verify randomized MAC is the default MAC for the device.
+
+ """
+ self.connect_to_network_and_verify_mac_randomization(self.wep_2g)
+
+ @test_tracker_info(uuid="f5347ac0-68d5-4882-a58d-1bd0d575503c")
+ def test_mac_randomization_open(self):
+ """Verify MAC randomization for a open network.
+
+ Steps:
+ 1. Connect to open network.
+ 2. Get the Factory, Randomized and Default MACs.
+ 3. Verify randomized MAC is the default MAC for the device.
+
+ """
+ self.connect_to_network_and_verify_mac_randomization(self.open_2g)
+
+ @test_tracker_info(uuid="5d260421-2adf-4ace-b281-3d15aec39b2a")
+ def test_persistent_mac_after_forget(self):
+ """Check if MAC is persistent after forgetting/adding a network.
+
+ Steps:
+ 1. Connect to WPA network and get the randomized MAC.
+ 2. Forget the network.
+ 3. Connect to the same network again.
+ 4. Verify randomized MAC has not changed.
+
+ """
+ self.check_mac_persistence(self.wpapsk_2g, FORGET)
+
+ @test_tracker_info(uuid="09d40a93-ead2-45ca-9905-14b05fd79f34")
+ def test_persistent_mac_after_toggle(self):
+ """Check if MAC is persistent after toggling WiFi network.
+
+ Steps:
+ 1. Connect to WPA network and get the randomized MAC.
+ 2. Turn WiFi ON/OFF.
+ 3. Connect to the same network again.
+ 4. Verify randomized MAC has not changed.
+
+ """
+ self.check_mac_persistence(self.wpapsk_2g, TOGGLE)
+
+ @test_tracker_info(uuid="a514f-8562-44e8-bfe0-4ecab9af165b")
+ def test_persistent_mac_after_device_reboot(self):
+ """Check if MAC is persistent after a device reboot.
+
+ Steps:
+ 1. Connect to WPA network and get the randomized MAC.
+ 2. Reboot DUT.
+ 3. Connect to the same network again.
+ 4. Verify randomized MAC has not changed.
+
+ """
+ self.check_mac_persistence(self.wpapsk_2g, REBOOT_DUT)
+
+ @test_tracker_info(uuid="82d691a0-22e4-4a3d-9596-e150531fcd34")
+ def test_persistent_mac_after_ap_reboot(self):
+ """Check if MAC is persistent after AP reboots itself.
+
+ Steps:
+ 1. Connect to WPA network and get the randomized MAC.
+ 2. Reboot AP(basically restart hostapd in our case).
+ 3. Connect to the same network again.
+ 4. Verify randomized MAC has not changed.
+
+ """
+ self.check_mac_persistence(self.wpapsk_2g, REBOOT_AP)
+
+ @test_tracker_info(uuid="e1f33dbc-808c-4e61-8a4a-3a72c1f63c7e")
+ def test_mac_randomization_multiple_networks(self):
+ """Connect to multiple networks and verify same MAC.
+
+ Steps:
+ 1. Connect to network A, get randomizd MAC.
+ 2. Conenct to network B, get randomized MAC.
+ 3. Connect back to network A and verify same MAC.
+ 4. Connect back to network B and verify same MAC.
+
+ """
+ mac_list = list()
+
+ # Connect to two different networks and get randomized MAC addresses.
+ self.verify_mac_randomization_and_add_to_list(self.wpapsk_2g, mac_list)
+ self.verify_mac_randomization_and_add_to_list(self.open_2g, mac_list)
+
+ # Connect to the previous network and check MAC is persistent.
+ mac_wpapsk = self.connect_to_network_and_verify_mac_randomization(
+ self.wpapsk_2g)
+ msg = ('Randomized MAC is not persistent for this network %s. Old MAC = '
+ '%s \nNew MAC = %s')
+ if mac_wpapsk != mac_list[0]:
+ raise signals.TestFailure(msg % (self.wpapsk_5g, mac_list[0], mac_wpapsk))
+ mac_open = self.connect_to_network_and_verify_mac_randomization(
+ self.open_2g)
+ if mac_open != mac_list[1]:
+ raise signals.TestFailure(msg %(self.open_5g, mac_list[1], mac_open))
+
+ @test_tracker_info(uuid="edb5a0e5-7f3b-4147-b1d3-48ad7ad9799e")
+ def test_mac_randomization_differnet_APs(self):
+ """Verify randomization using two different APs.
+
+ Steps:
+ 1. Connect to network A on AP1, get the randomized MAC.
+ 2. Connect to network B on AP2, get the randomized MAC.
+ 3. Veirfy the two MACs are different.
+
+ """
+ ap1 = self.wpapsk_2g
+ ap2 = self.reference_networks[1]["5g"]
+ mac_ap1 = self.connect_to_network_and_verify_mac_randomization(ap1)
+ mac_ap2 = self.connect_to_network_and_verify_mac_randomization(ap2)
+ if ap1 == ap2:
+ raise signals.TestFailure("Same MAC address was generated for both "
+ "APs: %s" % mac_ap1)
+
+ @test_tracker_info(uuid="b815e9ce-bccd-4fc3-9774-1e1bc123a2a8")
+ def test_mac_randomization_ap_sta(self):
+ """Bring up STA and softAP and verify MAC randomization.
+
+ Steps:
+ 1. Connect to a network and get randomized MAC.
+ 2. Bring up softAP on the DUT.
+ 3. Connect to softAP network on the client and get MAC.
+ 4. Verify AP and STA use different randomized MACs.
+
+ """
+ self.dut.droid.wifiSetCountryCode(wutils.WifiEnums.CountryCode.US)
+ self.dut_client.droid.wifiSetCountryCode(wutils.WifiEnums.CountryCode.US)
+ mac_sta = self.connect_to_network_and_verify_mac_randomization(
+ self.wpapsk_2g)
+ softap = wutils.start_softap_and_verify(self, WIFI_CONFIG_APBAND_2G)
+ wutils.connect_to_wifi_network(self.dut_client, softap)
+ softap_info = self.dut_client.droid.wifiGetConnectionInfo()
+ mac_ap = softap_info['mac_address']
+ if mac_sta == mac_ap:
+ raise signals.TestFailure("Same MAC address was used for both "
+ "AP and STA: %s" % mac_sta)
+
+ @test_tracker_info(uuid="3ca3f911-29f1-41fb-b836-4d25eac1669f")
+ def test_roaming_mac_randomization(self):
+ """test MAC randomization in the roaming scenario.
+
+ Steps:
+ 1. Connect to network A on AP1, get randomized MAC.
+ 2. Set AP1 to MAX attenuation so that we roam to AP2.
+ 3. Wait for device to roam to AP2 and get randomized MAC.
+ 4. Veirfy that the device uses same AMC for both APs.
+
+ """
+ AP1_network = self.reference_networks[0]["5g"]
+ AP2_network = self.reference_networks[1]["5g"]
+ wutils.set_attns(self.attenuators, "AP1_on_AP2_off")
+ mac_before_roam = self.connect_to_network_and_verify_mac_randomization(
+ AP1_network)
+ wutils.trigger_roaming_and_validate(self.dut, self.attenuators,
+ "AP1_off_AP2_on", AP2_network)
+ mac_after_roam = self.get_randomized_mac(AP2_network)
+ if mac_after_roam != mac_before_roam:
+ raise signals.TestFailure("Randomized MAC address changed after "
+ "roaming from AP1 to AP2.\nMAC before roam = %s\nMAC after "
+ "roam = %s" %(mac_before_roam, mac_after_roam))
+ wutils.trigger_roaming_and_validate(self.dut, self.attenuators,
+ "AP1_on_AP2_off", AP1_network)
+ mac_after_roam = self.get_randomized_mac(AP1_network)
+ if mac_after_roam != mac_before_roam:
+ raise signals.TestFailure("Randomized MAC address changed after "
+ "roaming from AP1 to AP2.\nMAC before roam = %s\nMAC after "
+ "roam = %s" %(mac_before_roam, mac_after_roam))