blob: 42312f66d9b21e8580dee985dddaf2c30868c25d [file] [log] [blame]
Bindu Mahadev36725332019-01-29 12:23:21 -08001#!/usr/bin/env python3.4
2#
3# Copyright 2019 - 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
24import acts.test_utils.wifi.wifi_test_utils as wutils
25import acts.utils
26
27from acts import asserts
28from acts.test_decorators import test_tracker_info
29from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
30from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
31from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
Bindu Mahadev2941f482019-03-18 16:46:08 -070032from scapy.all import *
Bindu Mahadev36725332019-01-29 12:23:21 -080033
34WifiEnums = wutils.WifiEnums
35
36# Default timeout used for reboot, toggle WiFi and Airplane mode,
37# for the system to settle down after the operation.
38DEFAULT_TIMEOUT = 10
Bindu Mahadev2941f482019-03-18 16:46:08 -070039SHORT_TIMEOUT = 5
Bindu Mahadev36725332019-01-29 12:23:21 -080040
41# Constants for WiFi state change operations.
42FORGET = 1
43TOGGLE = 2
44REBOOT_DUT = 3
45REBOOT_AP = 4
46
47# MAC Randomization setting constants.
48RANDOMIZATION_NONE = 0
49RANDOMIZATION_PERSISTENT = 1
50
51
52class WifiMacRandomizationTest(WifiBaseTest):
53 """Tests for APIs in Android's WifiManager class.
54
55 Test Bed Requirement:
56 * Atleast one Android device and atleast two Access Points.
57 * Several Wi-Fi networks visible to the device.
58 """
59
60 def __init__(self, controllers):
61 WifiBaseTest.__init__(self, controllers)
62
63 def setup_class(self):
64 self.dut = self.android_devices[0]
65 self.dut_client = self.android_devices[1]
66 wutils.wifi_test_device_init(self.dut)
67 wutils.wifi_test_device_init(self.dut_client)
68 req_params = []
69 opt_param = [
70 "open_network", "reference_networks", "wep_networks"
71 ]
72 self.unpack_userparams(
73 req_param_names=req_params, opt_param_names=opt_param)
74
75 if "AccessPoint" in self.user_params:
76 if "AccessPoint" in self.user_params:
77 self.legacy_configure_ap_and_start(wep_network=True, ap_count=2)
78
79 asserts.assert_true(
80 len(self.reference_networks) > 0,
81 "Need at least one reference network with psk.")
82
83 wutils.wifi_toggle_state(self.dut, True)
84 wutils.wifi_toggle_state(self.dut_client, True)
85 self.wpapsk_2g = self.reference_networks[0]["2g"]
86 self.wpapsk_5g = self.reference_networks[0]["5g"]
87 self.wep_2g = self.wep_networks[0]["2g"]
88 self.wep_5g = self.wep_networks[0]["5g"]
89 self.open_2g = self.open_network[0]["2g"]
90 self.open_5g = self.open_network[0]["5g"]
91
92 def setup_test(self):
93 for ad in self.android_devices:
94 ad.droid.wakeLockAcquireBright()
95 ad.droid.wakeUpNow()
96 wutils.wifi_toggle_state(ad, True)
97
98 def teardown_test(self):
99 for ad in self.android_devices:
100 ad.droid.wakeLockRelease()
101 ad.droid.goToSleepNow()
102 wutils.reset_wifi(self.dut)
103 wutils.reset_wifi(self.dut_client)
104
105 def on_fail(self, test_name, begin_time):
106 pass
107 #self.dut.cat_adb_log(test_name, begin_time)
108 #self.dut.take_bug_report(test_name, begin_time)
109
110 def teardown_class(self):
111 if "AccessPoint" in self.user_params:
112 del self.user_params["reference_networks"]
113 del self.user_params["open_network"]
114 del self.user_params["wep_networks"]
115
116
117 """Helper Functions"""
118
119
120 def get_randomized_mac(self, network):
121 """Get the randomized MAC address.
122
123 Args:
124 network: dict, network information.
125
126 Returns:
127 The randomized MAC address string for the network.
128
129 """
130 return self.dut.droid.wifigetRandomizedMacAddress(network)
131
132 def connect_to_network_and_verify_mac_randomization(self, network,
133 status=RANDOMIZATION_PERSISTENT):
134 """Connect to the given network and verify MAC.
135
136 Args:
137 network: dict, the network information.
138 status: int, MAC randomization level.
139
140 Returns:
141 The randomized MAC addresss string.
142
143 """
144 wutils.connect_to_wifi_network(self.dut, network)
145 return self.verify_mac_randomization(network, status=status)
146
147 def verify_mac_randomization_and_add_to_list(self, network, mac_list):
148 """Connect to a network and populate it's MAC in a reference list,
149 that will be used to verify any repeated MAC addresses.
150
151 Args:
152 network: dict, the network information.
153 mac_list: list of MAC addresss strings.
154
155 """
156 rand_mac = self.connect_to_network_and_verify_mac_randomization(
157 network)
158 if rand_mac in mac_list:
159 raise signals.TestFailure('A new Randomized MAC was not generated '
160 ' for this network %s.' % network)
161 mac_list.append(rand_mac)
162
163 def verify_mac_randomization(self, network, status=RANDOMIZATION_PERSISTENT):
164 """Get the various types of MAC addresses for the device and verify.
165
166 Args:
167 network: dict, the network information.
168 status: int, MAC randomization level.
169
170 Returns:
171 The randomized MAC address string for the network.
172
173 """
174 network_info = self.dut.droid.wifiGetConnectionInfo()
175 factory_mac = self.dut.droid.wifigetFactorymacAddresses()[0]
176 randomized_mac = self.get_randomized_mac(network)
177 default_mac = network_info['mac_address']
178 self.log.info("Factory MAC = %s\nRandomized MAC = %s\nDefault MAC = %s" %
179 (factory_mac, randomized_mac, default_mac))
180
181 if status == RANDOMIZATION_NONE:
182 asserts.assert_true(default_mac == factory_mac, "Connection is not "
183 "using Factory MAC as the default MAC.")
184 message = ('Randomized MAC and Factory MAC are the same. '
185 'Randomized MAC = %s, Factory MAC = %s' % (randomized_mac, factory_mac))
186 asserts.assert_true(randomized_mac != factory_mac, message)
187
188 message = ('Connection is not using randomized MAC as the default MAC. '
189 'Randomized MAC = %s, Deafult MAC = %s' % (randomized_mac, default_mac))
190 # Uncomment after b/123355618 is resolved.
191 #asserts.assert_true(randomized_mac == default_mac, message)
Bindu Mahadev2941f482019-03-18 16:46:08 -0700192 self.factory_mac = factory_mac
Bindu Mahadev36725332019-01-29 12:23:21 -0800193 return randomized_mac
194
195 def check_mac_persistence(self, network, condition):
196 """Check if the MAC is persistent after carrying out specific operations
197 like forget WiFi, toggle WiFi, reboot device and AP.
198
199 Args:
200 network: dict, The network information.
201 condition: int, value to trigger certain operation on the device.
202
203 Raises:
204 TestFaikure is the MAC is not persistent.
205
206 """
207 rand_mac1 = self.connect_to_network_and_verify_mac_randomization(network)
208
209 if condition == FORGET:
210 wutils.wifi_forget_network(self.dut, network['SSID'])
211
212 elif condition == TOGGLE:
213 wutils.wifi_toggle_state(self.dut, False)
214 wutils.wifi_toggle_state(self.dut, True)
215
216 elif condition == REBOOT_DUT:
217 self.dut.reboot()
218 time.sleep(DEFAULT_TIMEOUT)
219
220 elif condition == REBOOT_AP:
221 wutils.turn_ap_off(self, 1)
222 time.sleep(DEFAULT_TIMEOUT)
223 wutils.turn_ap_on(self, 1)
224 time.sleep(DEFAULT_TIMEOUT)
225
226 rand_mac2 = self.connect_to_network_and_verify_mac_randomization(network)
227
228 if rand_mac1 != rand_mac2:
229 raise signals.TestFailure('Randomized MAC is not persistent after '
230 'forgetting networ. Old MAC = %s New MAC'
231 ' = %s' % (rand_mac1, rand_mac2))
232
233 """Tests"""
234
235
236 @test_tracker_info(uuid="2dd0a05e-a318-45a6-81cd-962e098fa242")
237 def test_set_mac_randomization_to_none(self):
238 network = self.wpapsk_2g
239 # Set macRandomizationSetting to RANDOMIZATION_NONE.
240 network["macRand"] = RANDOMIZATION_NONE
241 self.connect_to_network_and_verify_mac_randomization(network,
242 status=RANDOMIZATION_NONE)
243
244 @test_tracker_info(uuid="d9e64202-02d5-421a-967c-42e45f1f7f91")
245 def test_mac_randomization_wpapsk(self):
246 """Verify MAC randomization for a WPA network.
247
248 Steps:
249 1. Connect to WPA network.
250 2. Get the Factory, Randomized and Default MACs.
251 3. Verify randomized MAC is the default MAC for the device.
252
253 """
254 self.connect_to_network_and_verify_mac_randomization(self.wpapsk_2g)
255
256 @test_tracker_info(uuid="b5be7c53-2edf-449e-ba70-a1fb7acf735e")
257 def test_mac_randomization_wep(self):
258 """Verify MAC randomization for a WEP network.
259
260 Steps:
261 1. Connect to WEP network.
262 2. Get the Factory, Randomized and Default MACs.
263 3. Verify randomized MAC is the default MAC for the device.
264
265 """
266 self.connect_to_network_and_verify_mac_randomization(self.wep_2g)
267
268 @test_tracker_info(uuid="f5347ac0-68d5-4882-a58d-1bd0d575503c")
269 def test_mac_randomization_open(self):
270 """Verify MAC randomization for a open network.
271
272 Steps:
273 1. Connect to open network.
274 2. Get the Factory, Randomized and Default MACs.
275 3. Verify randomized MAC is the default MAC for the device.
276
277 """
278 self.connect_to_network_and_verify_mac_randomization(self.open_2g)
279
280 @test_tracker_info(uuid="5d260421-2adf-4ace-b281-3d15aec39b2a")
281 def test_persistent_mac_after_forget(self):
282 """Check if MAC is persistent after forgetting/adding a network.
283
284 Steps:
285 1. Connect to WPA network and get the randomized MAC.
286 2. Forget the network.
287 3. Connect to the same network again.
288 4. Verify randomized MAC has not changed.
289
290 """
291 self.check_mac_persistence(self.wpapsk_2g, FORGET)
292
293 @test_tracker_info(uuid="09d40a93-ead2-45ca-9905-14b05fd79f34")
294 def test_persistent_mac_after_toggle(self):
295 """Check if MAC is persistent after toggling WiFi network.
296
297 Steps:
298 1. Connect to WPA network and get the randomized MAC.
299 2. Turn WiFi ON/OFF.
300 3. Connect to the same network again.
301 4. Verify randomized MAC has not changed.
302
303 """
304 self.check_mac_persistence(self.wpapsk_2g, TOGGLE)
305
306 @test_tracker_info(uuid="a514f-8562-44e8-bfe0-4ecab9af165b")
307 def test_persistent_mac_after_device_reboot(self):
308 """Check if MAC is persistent after a device reboot.
309
310 Steps:
311 1. Connect to WPA network and get the randomized MAC.
312 2. Reboot DUT.
313 3. Connect to the same network again.
314 4. Verify randomized MAC has not changed.
315
316 """
317 self.check_mac_persistence(self.wpapsk_2g, REBOOT_DUT)
318
Bindu Mahadevb2312682019-03-13 15:44:14 -0700319 # Disable reboot test for debugging purpose.
320 #@test_tracker_info(uuid="82d691a0-22e4-4a3d-9596-e150531fcd34")
321 def persistent_mac_after_ap_reboot(self):
Bindu Mahadev36725332019-01-29 12:23:21 -0800322 """Check if MAC is persistent after AP reboots itself.
323
324 Steps:
325 1. Connect to WPA network and get the randomized MAC.
326 2. Reboot AP(basically restart hostapd in our case).
327 3. Connect to the same network again.
328 4. Verify randomized MAC has not changed.
329
330 """
331 self.check_mac_persistence(self.wpapsk_2g, REBOOT_AP)
332
333 @test_tracker_info(uuid="e1f33dbc-808c-4e61-8a4a-3a72c1f63c7e")
334 def test_mac_randomization_multiple_networks(self):
335 """Connect to multiple networks and verify same MAC.
336
337 Steps:
338 1. Connect to network A, get randomizd MAC.
339 2. Conenct to network B, get randomized MAC.
340 3. Connect back to network A and verify same MAC.
341 4. Connect back to network B and verify same MAC.
342
343 """
344 mac_list = list()
345
346 # Connect to two different networks and get randomized MAC addresses.
347 self.verify_mac_randomization_and_add_to_list(self.wpapsk_2g, mac_list)
348 self.verify_mac_randomization_and_add_to_list(self.open_2g, mac_list)
349
350 # Connect to the previous network and check MAC is persistent.
351 mac_wpapsk = self.connect_to_network_and_verify_mac_randomization(
352 self.wpapsk_2g)
353 msg = ('Randomized MAC is not persistent for this network %s. Old MAC = '
354 '%s \nNew MAC = %s')
355 if mac_wpapsk != mac_list[0]:
356 raise signals.TestFailure(msg % (self.wpapsk_5g, mac_list[0], mac_wpapsk))
357 mac_open = self.connect_to_network_and_verify_mac_randomization(
358 self.open_2g)
359 if mac_open != mac_list[1]:
360 raise signals.TestFailure(msg %(self.open_5g, mac_list[1], mac_open))
361
362 @test_tracker_info(uuid="edb5a0e5-7f3b-4147-b1d3-48ad7ad9799e")
363 def test_mac_randomization_differnet_APs(self):
364 """Verify randomization using two different APs.
365
366 Steps:
367 1. Connect to network A on AP1, get the randomized MAC.
368 2. Connect to network B on AP2, get the randomized MAC.
369 3. Veirfy the two MACs are different.
370
371 """
372 ap1 = self.wpapsk_2g
373 ap2 = self.reference_networks[1]["5g"]
374 mac_ap1 = self.connect_to_network_and_verify_mac_randomization(ap1)
375 mac_ap2 = self.connect_to_network_and_verify_mac_randomization(ap2)
376 if ap1 == ap2:
377 raise signals.TestFailure("Same MAC address was generated for both "
378 "APs: %s" % mac_ap1)
379
380 @test_tracker_info(uuid="b815e9ce-bccd-4fc3-9774-1e1bc123a2a8")
381 def test_mac_randomization_ap_sta(self):
382 """Bring up STA and softAP and verify MAC randomization.
383
384 Steps:
385 1. Connect to a network and get randomized MAC.
386 2. Bring up softAP on the DUT.
387 3. Connect to softAP network on the client and get MAC.
388 4. Verify AP and STA use different randomized MACs.
389
390 """
391 self.dut.droid.wifiSetCountryCode(wutils.WifiEnums.CountryCode.US)
392 self.dut_client.droid.wifiSetCountryCode(wutils.WifiEnums.CountryCode.US)
393 mac_sta = self.connect_to_network_and_verify_mac_randomization(
394 self.wpapsk_2g)
395 softap = wutils.start_softap_and_verify(self, WIFI_CONFIG_APBAND_2G)
396 wutils.connect_to_wifi_network(self.dut_client, softap)
397 softap_info = self.dut_client.droid.wifiGetConnectionInfo()
398 mac_ap = softap_info['mac_address']
399 if mac_sta == mac_ap:
400 raise signals.TestFailure("Same MAC address was used for both "
401 "AP and STA: %s" % mac_sta)
402
403 @test_tracker_info(uuid="3ca3f911-29f1-41fb-b836-4d25eac1669f")
404 def test_roaming_mac_randomization(self):
405 """test MAC randomization in the roaming scenario.
406
407 Steps:
408 1. Connect to network A on AP1, get randomized MAC.
409 2. Set AP1 to MAX attenuation so that we roam to AP2.
410 3. Wait for device to roam to AP2 and get randomized MAC.
411 4. Veirfy that the device uses same AMC for both APs.
412
413 """
414 AP1_network = self.reference_networks[0]["5g"]
415 AP2_network = self.reference_networks[1]["5g"]
416 wutils.set_attns(self.attenuators, "AP1_on_AP2_off")
417 mac_before_roam = self.connect_to_network_and_verify_mac_randomization(
418 AP1_network)
419 wutils.trigger_roaming_and_validate(self.dut, self.attenuators,
420 "AP1_off_AP2_on", AP2_network)
421 mac_after_roam = self.get_randomized_mac(AP2_network)
422 if mac_after_roam != mac_before_roam:
423 raise signals.TestFailure("Randomized MAC address changed after "
424 "roaming from AP1 to AP2.\nMAC before roam = %s\nMAC after "
425 "roam = %s" %(mac_before_roam, mac_after_roam))
426 wutils.trigger_roaming_and_validate(self.dut, self.attenuators,
427 "AP1_on_AP2_off", AP1_network)
428 mac_after_roam = self.get_randomized_mac(AP1_network)
429 if mac_after_roam != mac_before_roam:
430 raise signals.TestFailure("Randomized MAC address changed after "
431 "roaming from AP1 to AP2.\nMAC before roam = %s\nMAC after "
432 "roam = %s" %(mac_before_roam, mac_after_roam))
Bindu Mahadev2941f482019-03-18 16:46:08 -0700433
434 @test_tracker_info(uuid="17b12f1a-7c62-4188-b5a5-52d7a0bb7849")
435 def test_check_mac_in_sniffer(self):
436 """Test to ensure Factory MAC is not exposed, using sniffer data.
437
438 Steps:
439 1. Configure and start the sniffer on 5GHz band.
440 2. Connect to 5GHz network, ping, get the Factory MAC.
441 3. Stop the sniffer.
442 4. Invoke scapy to read the .pcap file.
443 5. Read each packet summary and make sure Factory AMC is not used.
444
445 """
446 if hasattr(self, 'packet_capture'):
447 self.pcap_procs = wutils.start_pcap(
448 self.packet_capture[0], 'dual', self.log_path, self.test_name)
449 time.sleep(SHORT_TIMEOUT)
450 network = self.wpapsk_5g
451 rand_mac = self.connect_to_network_and_verify_mac_randomization(network)
452 pcap_fname = os.path.join(self.log_path, self.test_name,
453 (self.test_name + '_5G.pcap'))
454 wutils.stop_pcap(self.packet_capture[0], self.pcap_procs, False)
455 time.sleep(SHORT_TIMEOUT)
456 packets = rdpcap(pcap_fname)
457 for pkt in packets:
458 self.log.debug("Packet Summary = %s" % pkt.summary())
459 if self.factory_mac in pkt.summary():
460 raise signals.TestFailure("Caught Factory MAC in packet sniffer."
461 "Packet = %s" % pkt.show())