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
5import logging
6
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib.cros.network import tcpdump_analyzer
9from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
10from autotest_lib.server.cros.network import hostap_config
11from autotest_lib.server.cros.network import wifi_cell_test_base
12
13
14class 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.capture_host.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.capture_host.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