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