1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import itertools 18import pprint 19import queue 20import time 21 22import acts.base_test 23import acts.signals as signals 24from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G 25import acts.test_utils.wifi.wifi_test_utils as wutils 26import acts.utils as utils 27 28from acts import asserts 29from acts.test_decorators import test_tracker_info 30from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest 31 32WifiEnums = wutils.WifiEnums 33# Default timeout used for reboot, toggle WiFi and Airplane mode, 34# for the system to settle down after the operation. 35DEFAULT_TIMEOUT = 10 36GET_MAC_ADDRESS= ("ip addr show wlan0" 37 "| grep 'link/ether'" 38 "| cut -d ' ' -f6") 39MAC_SETTING = "wifi_connected_mac_randomization_enabled" 40GET_MAC_RANDOMIZATION_STATUS = "settings get global {}".format(MAC_SETTING) 41TURN_ON_MAC_RANDOMIZATION = "settings put global {} 1".format(MAC_SETTING) 42TURN_OFF_MAC_RANDOMIZATION = "settings put global {} 0".format(MAC_SETTING) 43LOG_CLEAR = "logcat -c" 44LOG_GREP = "logcat -d | grep {}" 45 46class WifiConnectedMacRandomizationTest(WifiBaseTest): 47 """Tests for Connected MAC Randomization. 48 49 Test Bed Requirement: 50 * Two Android devices with the first one supporting MAC randomization. 51 * At least two Wi-Fi networks to connect to. 52 """ 53 54 def setup_class(self): 55 super().setup_class() 56 57 self.dut = self.android_devices[0] 58 self.dut_softap = self.android_devices[1] 59 wutils.wifi_test_device_init(self.dut) 60 wutils.wifi_test_device_init(self.dut_softap) 61 62 self.reset_mac_address_to_factory_mac() 63 self.dut.adb.shell(TURN_ON_MAC_RANDOMIZATION) 64 asserts.assert_equal( 65 self.dut.adb.shell(GET_MAC_RANDOMIZATION_STATUS), "1", 66 "Failed to enable Connected MAC Randomization on dut.") 67 68 req_params = ["reference_networks"] 69 opt_param = [] 70 self.unpack_userparams( 71 req_param_names=req_params, opt_param_names=opt_param) 72 73 if "AccessPoint" in self.user_params: 74 self.legacy_configure_ap_and_start() 75 76 asserts.assert_true( 77 self.reference_networks[0]["2g"], 78 "Need at least 1 2.4Ghz reference network with psk.") 79 asserts.assert_true( 80 self.reference_networks[0]["5g"], 81 "Need at least 1 5Ghz reference network with psk.") 82 self.wpapsk_2g = self.reference_networks[0]["2g"] 83 self.wpapsk_5g = self.reference_networks[0]["5g"] 84 85 def setup_test(self): 86 self.dut.droid.wakeLockAcquireBright() 87 self.dut.droid.wakeUpNow() 88 wutils.wifi_toggle_state(self.dut, True) 89 wutils.wifi_toggle_state(self.dut_softap, False) 90 91 def teardown_test(self): 92 self.dut.droid.wakeLockRelease() 93 self.dut.droid.goToSleepNow() 94 wutils.reset_wifi(self.dut) 95 wutils.reset_wifi(self.dut_softap) 96 97 def on_fail(self, test_name, begin_time): 98 self.dut.take_bug_report(test_name, begin_time) 99 self.dut.cat_adb_log(test_name, begin_time) 100 101 def teardown_class(self): 102 wutils.stop_wifi_tethering(self.dut_softap) 103 self.reset_mac_address_to_factory_mac() 104 if "AccessPoint" in self.user_params: 105 del self.user_params["reference_networks"] 106 del self.user_params["open_network"] 107 108 """Helper Functions""" 109 def get_current_mac_address(self, ad): 110 """Get the device's wlan0 MAC address. 111 112 Args: 113 ad: AndroidDevice to get MAC address of. 114 115 Returns: 116 A MAC address string in the format of "12:34:56:78:90:12". 117 """ 118 return ad.adb.shell(GET_MAC_ADDRESS) 119 120 def is_valid_randomized_mac_address(self, mac): 121 """Check if the given MAC address is a valid randomized MAC address. 122 123 Args: 124 mac: MAC address to check in the format of "12:34:56:78:90:12". 125 """ 126 asserts.assert_true( 127 mac != self.dut_factory_mac, 128 "Randomized MAC address is same as factory MAC address.") 129 first_byte = int(mac[:2], 16) 130 asserts.assert_equal(first_byte & 1, 0, "MAC address is not unicast.") 131 asserts.assert_equal(first_byte & 2, 2, "MAC address is not local.") 132 133 def reset_mac_address_to_factory_mac(self): 134 """Reset dut to and store factory MAC address by turning off 135 Connected MAC Randomization and rebooting dut. 136 """ 137 self.dut.adb.shell(TURN_OFF_MAC_RANDOMIZATION) 138 asserts.assert_equal( 139 self.dut.adb.shell(GET_MAC_RANDOMIZATION_STATUS), "0", 140 "Failed to disable Connected MAC Randomization on dut.") 141 self.dut.reboot() 142 time.sleep(DEFAULT_TIMEOUT) 143 self.dut_factory_mac = self.get_current_mac_address(self.dut) 144 145 def get_connection_data(self, ad, network): 146 """Connect and get network id and ssid info from connection data. 147 148 Args: 149 ad: AndroidDevice to use for connection 150 network: network info of the network to connect to 151 152 Returns: 153 A convenience dict with the connected network's ID and SSID. 154 """ 155 wutils.connect_to_wifi_network(ad, network) 156 connect_data = ad.droid.wifiGetConnectionInfo() 157 ssid_id_dict = dict() 158 ssid_id_dict[WifiEnums.NETID_KEY] = connect_data[WifiEnums.NETID_KEY] 159 ssid_id_dict[WifiEnums.SSID_KEY] = connect_data[WifiEnums.SSID_KEY] 160 return ssid_id_dict 161 162 """Tests""" 163 @test_tracker_info(uuid="") 164 def test_wifi_connection_2G_with_mac_randomization(self): 165 """Tests connection to 2G network with Connected MAC Randomization. 166 """ 167 wutils.connect_to_wifi_network(self.dut, self.wpapsk_2g) 168 mac = self.get_current_mac_address(self.dut) 169 self.is_valid_randomized_mac_address(mac) 170 171 @test_tracker_info(uuid="") 172 def test_wifi_connection_5G_with_mac_randomization(self): 173 """Tests connection to 5G network with Connected MAC Randomization. 174 """ 175 wutils.connect_to_wifi_network(self.dut, self.wpapsk_5g) 176 mac = self.get_current_mac_address(self.dut) 177 self.is_valid_randomized_mac_address(mac) 178 179 @test_tracker_info(uuid="") 180 def test_randomized_mac_persistent_between_connections(self): 181 """Tests that randomized MAC address assigned to each network is 182 persistent between connections. 183 184 Steps: 185 1. Connect to a 2GHz network. 186 2. Connect to a 5GHz network. 187 3. Reconnect to the 2GHz network using its network id. 188 4. Verify that MAC addresses in Steps 1 and 3 are equal. 189 5. Reconnect to the 5GHz network using its network id. 190 6. Verify that MAC addresses in Steps 2 and 5 are equal. 191 """ 192 connect_data_2g = self.get_connection_data(self.dut, self.wpapsk_2g) 193 old_mac_2g = self.get_current_mac_address(self.dut) 194 self.is_valid_randomized_mac_address(old_mac_2g) 195 196 connect_data_5g = self.get_connection_data(self.dut, self.wpapsk_5g) 197 old_mac_5g = self.get_current_mac_address(self.dut) 198 self.is_valid_randomized_mac_address(old_mac_5g) 199 200 asserts.assert_true( 201 old_mac_2g != old_mac_5g, 202 "Randomized MAC addresses for 2G and 5G networks are equal.") 203 204 reconnect_2g = wutils.connect_to_wifi_network_with_id( 205 self.dut, 206 connect_data_2g[WifiEnums.NETID_KEY], 207 connect_data_2g[WifiEnums.SSID_KEY]) 208 if not reconnect_2g: 209 raise signals.TestFailure("Device did not connect to the correct" 210 " 2GHz network.") 211 new_mac_2g = self.get_current_mac_address(self.dut) 212 asserts.assert_equal( 213 old_mac_2g, 214 new_mac_2g, 215 "Randomized MAC for 2G is not persistent between connections.") 216 217 reconnect_5g = wutils.connect_to_wifi_network_with_id( 218 self.dut, 219 connect_data_5g[WifiEnums.NETID_KEY], 220 connect_data_5g[WifiEnums.SSID_KEY]) 221 if not reconnect_5g: 222 raise signals.TestFailure("Device did not connect to the correct" 223 " 5GHz network.") 224 new_mac_5g = self.get_current_mac_address(self.dut) 225 asserts.assert_equal( 226 old_mac_5g, 227 new_mac_5g, 228 "Randomized MAC for 5G is not persistent between connections.") 229 230 @test_tracker_info(uuid="") 231 def test_randomized_mac_used_during_connection(self): 232 """Verify that the randomized MAC address and not the factory 233 MAC address is used during connection by checking the softap logs. 234 235 Steps: 236 1. Set up softAP on dut_softap. 237 2. Have dut connect to the softAp. 238 3. Verify that only randomized MAC appears in softAp logs. 239 """ 240 self.dut_softap.adb.shell(LOG_CLEAR) 241 config = wutils.create_softap_config() 242 wutils.start_wifi_tethering(self.dut_softap, 243 config[wutils.WifiEnums.SSID_KEY], 244 config[wutils.WifiEnums.PWD_KEY], 245 WIFI_CONFIG_APBAND_2G) 246 247 # Internet validation fails when dut_softap does not have a valid sim 248 # supporting softap. Since this test is not checking for internet 249 # validation, we suppress failure signals. 250 wutils.connect_to_wifi_network(self.dut, config, assert_on_fail=False) 251 mac = self.get_current_mac_address(self.dut) 252 wutils.stop_wifi_tethering(self.dut_softap) 253 254 self.is_valid_randomized_mac_address(mac) 255 log = self.dut_softap.adb.shell(LOG_GREP.format(mac)) 256 asserts.assert_true(len(log) > 0, "Randomized MAC not in log.") 257 log = self.dut_softap.adb.shell(LOG_GREP.format(self.dut_factory_mac)) 258 asserts.assert_true(len(log) == 0, "Factory MAC is in log.") 259