| # Copyright (c) 2013 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 |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib.cros.network import tcpdump_analyzer |
| from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes |
| from autotest_lib.server.cros.network import hostap_config |
| from autotest_lib.server.cros.network import wifi_cell_test_base |
| |
| |
| class network_WiFi_LowInitialBitrates(wifi_cell_test_base.WiFiCellTestBase): |
| """Test that the WiFi chip honors our request to disable high bitrates.""" |
| version = 1 |
| |
| def check_bitrates_in_capture(self, pcap_result): |
| """ |
| Check that bitrates look like we expect in a packet capture. |
| |
| The DUT should not send packets at high bitrates until after DHCP |
| negotiation is complete. If this is detected, fail the test. |
| |
| @param pcap_result: RemoteCaptureResult tuple. |
| |
| """ |
| logging.info('Analyzing packet capture...') |
| dut_src_display_filter = ('wlan.sa==%s' % |
| self.context.client.wifi_mac) |
| # Some chips use self-addressed frames to tune channel |
| # performance. They don't carry host-generated traffic, so |
| # filter them out. |
| dut_dst_display_filter = ('wlan.da==%s' % |
| self.context.client.wifi_mac) |
| # Get all the frames in chronological order. |
| frames = tcpdump_analyzer.get_frames( |
| pcap_result.local_pcap_path, |
| ('%s and not %s' % ( |
| dut_src_display_filter, dut_dst_display_filter)), |
| reject_bad_fcs=False) |
| # Get just the DHCP related packets. |
| dhcp_frames = tcpdump_analyzer.get_frames( |
| pcap_result.local_pcap_path, |
| '%s and bootp' % dut_src_display_filter, reject_bad_fcs=False) |
| if not dhcp_frames: |
| raise error.TestFail('Packet capture did not contain a DHCP ' |
| 'negotiation!') |
| |
| for frame in frames: |
| if frame.time_datetime > dhcp_frames[-1].time_datetime: |
| # We're past the last DHCP packet, so higher bitrates are |
| # permissable and expected. |
| break |
| |
| if frame.mcs_index is not None: |
| if frame.mcs_index > 1: |
| # wpa_supplicant should ask that all but the 2 lowest rates |
| # be disabled. |
| raise error.TestFail( |
| 'Frame at %s was sent with MCS index %d.' % |
| (frame.time_string, frame.mcs_index)) |
| |
| elif frame.bit_rate >= 12: |
| raise error.TestFail( |
| 'Frame at %s was sent at %f Mbps.' % |
| (frame.time_string, frame.bit_rate)) |
| |
| |
| def run_once(self): |
| """Asserts that WiFi bitrates remain low during the association process. |
| |
| Low bitrates mean that data transfer is slow, but reliable. This is |
| important since association usually includes some very time dependent |
| configuration state machines and no user expectation of high bandwidth. |
| |
| """ |
| caps = [hostap_config.HostapConfig.N_CAPABILITY_GREENFIELD, |
| hostap_config.HostapConfig.N_CAPABILITY_HT40] |
| g_config = hostap_config.HostapConfig( |
| channel=6, |
| mode=hostap_config.HostapConfig.MODE_11G) |
| n_config = hostap_config.HostapConfig( |
| channel=44, |
| mode=hostap_config.HostapConfig.MODE_11N_PURE, |
| n_capabilities=caps) |
| for ap_config in (g_config, n_config): |
| self.context.configure(ap_config) |
| self.context.capture_host.start_capture( |
| ap_config.frequency, |
| ht_type=ap_config.ht_packet_capture_mode) |
| assoc_params = xmlrpc_datatypes.AssociationParameters( |
| ssid=self.context.router.get_ssid()) |
| self.context.assert_connect_wifi(assoc_params) |
| self.context.assert_ping_from_dut() |
| 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)) |
| self.check_bitrates_in_capture(results[0]) |
| self.context.client.shill.disconnect(assoc_params.ssid) |
| self.context.router.deconfig() |