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