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 __init__(self, controllers): 55 WifiBaseTest.__init__(self, controllers) 56 57 def setup_class(self): 58 self.dut = self.android_devices[0] 59 self.dut_softap = self.android_devices[1] 60 wutils.wifi_test_device_init(self.dut) 61 wutils.wifi_test_device_init(self.dut_softap) 62 63 self.reset_mac_address_to_factory_mac() 64 self.dut.adb.shell(TURN_ON_MAC_RANDOMIZATION) 65 asserts.assert_equal( 66 self.dut.adb.shell(GET_MAC_RANDOMIZATION_STATUS), "1", 67 "Failed to enable Connected MAC Randomization on dut.") 68 69 req_params = ["reference_networks"] 70 opt_param = [] 71 self.unpack_userparams( 72 req_param_names=req_params, opt_param_names=opt_param) 73 74 if "AccessPoint" in self.user_params: 75 self.legacy_configure_ap_and_start() 76 77 asserts.assert_true( 78 self.reference_networks[0]["2g"], 79 "Need at least 1 2.4Ghz reference network with psk.") 80 asserts.assert_true( 81 self.reference_networks[0]["5g"], 82 "Need at least 1 5Ghz reference network with psk.") 83 self.wpapsk_2g = self.reference_networks[0]["2g"] 84 self.wpapsk_5g = self.reference_networks[0]["5g"] 85 86 def setup_test(self): 87 self.dut.droid.wakeLockAcquireBright() 88 self.dut.droid.wakeUpNow() 89 wutils.wifi_toggle_state(self.dut, True) 90 wutils.wifi_toggle_state(self.dut_softap, False) 91 92 def teardown_test(self): 93 self.dut.droid.wakeLockRelease() 94 self.dut.droid.goToSleepNow() 95 wutils.reset_wifi(self.dut) 96 wutils.reset_wifi(self.dut_softap) 97 98 def on_fail(self, test_name, begin_time): 99 self.dut.take_bug_report(test_name, begin_time) 100 self.dut.cat_adb_log(test_name, begin_time) 101 102 def teardown_class(self): 103 wutils.stop_wifi_tethering(self.dut_softap) 104 self.reset_mac_address_to_factory_mac() 105 if "AccessPoint" in self.user_params: 106 del self.user_params["reference_networks"] 107 del self.user_params["open_network"] 108 109 """Helper Functions""" 110 def get_current_mac_address(self, ad): 111 """Get the device's wlan0 MAC address. 112 113 Args: 114 ad: AndroidDevice to get MAC address of. 115 116 Returns: 117 A MAC address string in the format of "12:34:56:78:90:12". 118 """ 119 return ad.adb.shell(GET_MAC_ADDRESS) 120 121 def is_valid_randomized_mac_address(self, mac): 122 """Check if the given MAC address is a valid randomized MAC address. 123 124 Args: 125 mac: MAC address to check in the format of "12:34:56:78:90:12". 126 """ 127 asserts.assert_true( 128 mac != self.dut_factory_mac, 129 "Randomized MAC address is same as factory MAC address.") 130 first_byte = int(mac[:2], 16) 131 asserts.assert_equal(first_byte & 1, 0, "MAC address is not unicast.") 132 asserts.assert_equal(first_byte & 2, 2, "MAC address is not local.") 133 134 def reset_mac_address_to_factory_mac(self): 135 """Reset dut to and store factory MAC address by turning off 136 Connected MAC Randomization and rebooting dut. 137 """ 138 self.dut.adb.shell(TURN_OFF_MAC_RANDOMIZATION) 139 asserts.assert_equal( 140 self.dut.adb.shell(GET_MAC_RANDOMIZATION_STATUS), "0", 141 "Failed to disable Connected MAC Randomization on dut.") 142 self.dut.reboot() 143 time.sleep(DEFAULT_TIMEOUT) 144 self.dut_factory_mac = self.get_current_mac_address(self.dut) 145 146 def get_connection_data(self, ad, network): 147 """Connect and get network id and ssid info from connection data. 148 149 Args: 150 ad: AndroidDevice to use for connection 151 network: network info of the network to connect to 152 153 Returns: 154 A convenience dict with the connected network's ID and SSID. 155 """ 156 wutils.connect_to_wifi_network(ad, network) 157 connect_data = ad.droid.wifiGetConnectionInfo() 158 ssid_id_dict = dict() 159 ssid_id_dict[WifiEnums.NETID_KEY] = connect_data[WifiEnums.NETID_KEY] 160 ssid_id_dict[WifiEnums.SSID_KEY] = connect_data[WifiEnums.SSID_KEY] 161 return ssid_id_dict 162 163 """Tests""" 164 @test_tracker_info(uuid="") 165 def test_wifi_connection_2G_with_mac_randomization(self): 166 """Tests connection to 2G network with Connected MAC Randomization. 167 """ 168 wutils.connect_to_wifi_network(self.dut, self.wpapsk_2g) 169 mac = self.get_current_mac_address(self.dut) 170 self.is_valid_randomized_mac_address(mac) 171 172 @test_tracker_info(uuid="") 173 def test_wifi_connection_5G_with_mac_randomization(self): 174 """Tests connection to 5G network with Connected MAC Randomization. 175 """ 176 wutils.connect_to_wifi_network(self.dut, self.wpapsk_5g) 177 mac = self.get_current_mac_address(self.dut) 178 self.is_valid_randomized_mac_address(mac) 179 180 @test_tracker_info(uuid="") 181 def test_randomized_mac_persistent_between_connections(self): 182 """Tests that randomized MAC address assigned to each network is 183 persistent between connections. 184 185 Steps: 186 1. Connect to a 2GHz network. 187 2. Connect to a 5GHz network. 188 3. Reconnect to the 2GHz network using its network id. 189 4. Verify that MAC addresses in Steps 1 and 3 are equal. 190 5. Reconnect to the 5GHz network using its network id. 191 6. Verify that MAC addresses in Steps 2 and 5 are equal. 192 """ 193 connect_data_2g = self.get_connection_data(self.dut, self.wpapsk_2g) 194 old_mac_2g = self.get_current_mac_address(self.dut) 195 self.is_valid_randomized_mac_address(old_mac_2g) 196 197 connect_data_5g = self.get_connection_data(self.dut, self.wpapsk_5g) 198 old_mac_5g = self.get_current_mac_address(self.dut) 199 self.is_valid_randomized_mac_address(old_mac_5g) 200 201 asserts.assert_true( 202 old_mac_2g != old_mac_5g, 203 "Randomized MAC addresses for 2G and 5G networks are equal.") 204 205 reconnect_2g = wutils.connect_to_wifi_network_with_id( 206 self.dut, 207 connect_data_2g[WifiEnums.NETID_KEY], 208 connect_data_2g[WifiEnums.SSID_KEY]) 209 if not reconnect_2g: 210 raise signals.TestFailure("Device did not connect to the correct" 211 " 2GHz network.") 212 new_mac_2g = self.get_current_mac_address(self.dut) 213 asserts.assert_equal( 214 old_mac_2g, 215 new_mac_2g, 216 "Randomized MAC for 2G is not persistent between connections.") 217 218 reconnect_5g = wutils.connect_to_wifi_network_with_id( 219 self.dut, 220 connect_data_5g[WifiEnums.NETID_KEY], 221 connect_data_5g[WifiEnums.SSID_KEY]) 222 if not reconnect_5g: 223 raise signals.TestFailure("Device did not connect to the correct" 224 " 5GHz network.") 225 new_mac_5g = self.get_current_mac_address(self.dut) 226 asserts.assert_equal( 227 old_mac_5g, 228 new_mac_5g, 229 "Randomized MAC for 5G is not persistent between connections.") 230 231 @test_tracker_info(uuid="") 232 def test_randomized_mac_used_during_connection(self): 233 """Verify that the randomized MAC address and not the factory 234 MAC address is used during connection by checking the softap logs. 235 236 Steps: 237 1. Set up softAP on dut_softap. 238 2. Have dut connect to the softAp. 239 3. Verify that only randomized MAC appears in softAp logs. 240 """ 241 self.dut_softap.adb.shell(LOG_CLEAR) 242 config = wutils.create_softap_config() 243 wutils.start_wifi_tethering(self.dut_softap, 244 config[wutils.WifiEnums.SSID_KEY], 245 config[wutils.WifiEnums.PWD_KEY], 246 WIFI_CONFIG_APBAND_2G) 247 248 # Internet validation fails when dut_softap does not have a valid sim 249 # supporting softap. Since this test is not checking for internet 250 # validation, we suppress failure signals. 251 wutils.connect_to_wifi_network(self.dut, config, assert_on_fail=False) 252 mac = self.get_current_mac_address(self.dut) 253 wutils.stop_wifi_tethering(self.dut_softap) 254 255 self.is_valid_randomized_mac_address(mac) 256 log = self.dut_softap.adb.shell(LOG_GREP.format(mac)) 257 asserts.assert_true(len(log) > 0, "Randomized MAC not in log.") 258 log = self.dut_softap.adb.shell(LOG_GREP.format(self.dut_factory_mac)) 259 asserts.assert_true(len(log) == 0, "Factory MAC is in log.") 260