| # Copyright 2017 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib.cros.network import tcpdump_analyzer |
| from autotest_lib.server.cros.network import hostap_config |
| from autotest_lib.server.cros.network import wifi_cell_test_base |
| |
| class RandomMACAddressTestBase(wifi_cell_test_base.WiFiCellTestBase): |
| """An abstract base class for MAC address randomization tests in WiFi cells. |
| |
| MAC address randomization tests will test the ability of the DUT to |
| successfully randomize the MAC address it sends in probe requests when |
| such a feature is supported and configured, and that it does not do so |
| otherwise. |
| """ |
| |
| # Approximate number of seconds to perform a full scan. |
| REQUEST_SCAN_DELAY = 5 |
| |
| # Default number of shill scans to run. |
| DEFAULT_NUM_SCANS = 5 |
| |
| def initialize(self, host): |
| """Generate the HostapConfig used by the AP.""" |
| self._ap_config = hostap_config.HostapConfig(channel=1) |
| |
| |
| def warmup(self, host, raw_cmdline_args, additional_params=None): |
| super(RandomMACAddressTestBase, self).warmup( |
| host, raw_cmdline_args, additional_params) |
| |
| self.context.configure(self._ap_config) |
| |
| |
| def start_capture(self): |
| """ |
| Start packet capture. |
| """ |
| logging.debug('Starting packet capture') |
| self.context.capture_host.start_capture( |
| self._ap_config.frequency, |
| width_type=self._ap_config.packet_capture_mode) |
| |
| |
| def request_scans(self, num_scans=DEFAULT_NUM_SCANS): |
| """ |
| Helper to request a few scans with the configured randomization. |
| |
| @param num_scans: The number of scans to perform. |
| """ |
| for _ in range(num_scans): |
| # Request scan through shill rather than iw because iw won't |
| # set the random MAC flag in the scan request netlink packet. |
| self.context.client.shill.request_scan() |
| time.sleep(self.REQUEST_SCAN_DELAY) |
| |
| |
| def _frame_matches_ssid(self, frame): |
| # Empty string is a wildcard SSID. |
| return frame.ssid == '' or frame.ssid == self.context.router.get_ssid() |
| |
| |
| def stop_capture_and_get_probe_requests(self): |
| """ |
| Stop packet capture and return probe requests from the DUT. |
| have the hardware MAC address. |
| """ |
| logging.debug('Stopping packet capture') |
| results = self.context.capture_host.stop_capture() |
| if len(results) != 1: |
| raise error.TestError('Expected to generate one packet ' |
| 'capture but got %d captures instead.', |
| len(results)) |
| |
| logging.debug('Analyzing packet capture...') |
| # Get all the frames in chronological order. |
| frames = tcpdump_analyzer.get_frames( |
| results[0].local_pcap_path, |
| tcpdump_analyzer.WLAN_PROBE_REQ_ACCEPTOR, reject_bad_fcs=True, |
| reject_low_signal=True) |
| |
| return [frame for frame in frames if self._frame_matches_ssid(frame)] |