1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import logging 6 7 from autotest_lib.client.common_lib import error 8 from autotest_lib.client.common_lib.cros.network import tcpdump_analyzer 9 from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes 10 from autotest_lib.server.cros.network import hostap_config 11 from autotest_lib.server.cros.network import wifi_cell_test_base 12 13 14 class network_WiFi_LowInitialBitrates(wifi_cell_test_base.WiFiCellTestBase): 15 """Test that the WiFi chip honors our request to disable high bitrates.""" 16 version = 1 17 18 def check_bitrates_in_capture(self, pcap_result): 19 """ 20 Check that bitrates look like we expect in a packet capture. 21 22 The DUT should not send packets at high bitrates until after DHCP 23 negotiation is complete. If this is detected, fail the test. 24 25 @param pcap_result: RemoteCaptureResult tuple. 26 27 """ 28 logging.info('Analyzing packet capture...') 29 dut_src_display_filter = ('wlan.sa==%s' % 30 self.context.client.wifi_mac) 31 # Some chips use self-addressed frames to tune channel 32 # performance. They don't carry host-generated traffic, so 33 # filter them out. 34 dut_dst_display_filter = ('wlan.da==%s' % 35 self.context.client.wifi_mac) 36 # Get all the frames in chronological order. 37 frames = tcpdump_analyzer.get_frames( 38 pcap_result.local_pcap_path, 39 ('%s and not %s' % ( 40 dut_src_display_filter, dut_dst_display_filter)), 41 bad_fcs='include') 42 # Get just the DHCP related packets. 43 dhcp_frames = tcpdump_analyzer.get_frames( 44 pcap_result.local_pcap_path, 45 '%s and bootp' % dut_src_display_filter, 46 bad_fcs='include') 47 if not dhcp_frames: 48 raise error.TestFail('Packet capture did not contain a DHCP ' 49 'negotiation!') 50 51 for frame in frames: 52 if frame.time_datetime > dhcp_frames[-1].time_datetime: 53 # We're past the last DHCP packet, so higher bitrates are 54 # permissable and expected. 55 break 56 57 if frame.mcs_index is not None: 58 if frame.mcs_index > 1: 59 # wpa_supplicant should ask that all but the 2 lowest rates 60 # be disabled. 61 raise error.TestFail( 62 'Frame at %s was sent with MCS index %d.' % 63 (frame.time_string, frame.mcs_index)) 64 65 elif frame.bit_rate >= 12: 66 raise error.TestFail( 67 'Frame at %s was sent at %f Mbps.' % 68 (frame.time_string, frame.bit_rate)) 69 70 71 def run_once(self): 72 """Asserts that WiFi bitrates remain low during the association process. 73 74 Low bitrates mean that data transfer is slow, but reliable. This is 75 important since association usually includes some very time dependent 76 configuration state machines and no user expectation of high bandwidth. 77 78 """ 79 caps = [hostap_config.HostapConfig.N_CAPABILITY_GREENFIELD, 80 hostap_config.HostapConfig.N_CAPABILITY_HT40] 81 g_config = hostap_config.HostapConfig( 82 channel=6, 83 mode=hostap_config.HostapConfig.MODE_11G) 84 n_config = hostap_config.HostapConfig( 85 channel=44, 86 mode=hostap_config.HostapConfig.MODE_11N_PURE, 87 n_capabilities=caps) 88 for ap_config in (g_config, n_config): 89 self.context.configure(ap_config) 90 self.context.router.start_capture( 91 ap_config.frequency, 92 ht_type=ap_config.ht_packet_capture_mode) 93 assoc_params = xmlrpc_datatypes.AssociationParameters( 94 ssid=self.context.router.get_ssid()) 95 self.context.assert_connect_wifi(assoc_params) 96 self.context.assert_ping_from_dut() 97 results = self.context.router.stop_capture() 98 if len(results) != 1: 99 raise error.TestError('Expected to generate one packet ' 100 'capture but got %d captures instead.' % 101 len(results)) 102 103 client_ip = self.context.client.wifi_ip 104 self.check_bitrates_in_capture(results[0]) 105 self.context.client.shill.disconnect(assoc_params.ssid) 106 self.context.router.deconfig() 107