Add checkTruncatedBeacon WiFi test

This tests that a client can connect to an AP even if the AP is
outputting a malformed, truncated beacon.

CQ-DEPEND=CL:232480
BUG=chrome-os-partner:33662
TEST=Run this test, on both ath9k and WP2 based cells

Change-Id: I3cf9f70fcf6445af250ff65d051816c486aee3f0
Reviewed-on: https://chromium-review.googlesource.com/232610
Reviewed-by: Peter Qiu <zqiu@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/server/cros/network/hostap_config.py b/server/cros/network/hostap_config.py
index 6e3ecc2..c5f32e8 100644
--- a/server/cros/network/hostap_config.py
+++ b/server/cros/network/hostap_config.py
@@ -424,6 +424,12 @@
         return self._hide_ssid
 
 
+    @property
+    def beacon_footer(self):
+        """@return bool _beacon_footer value."""
+        return self._beacon_footer
+
+
     def __init__(self, mode=MODE_11B, channel=None, frequency=None,
                  n_capabilities=[], hide_ssid=None, beacon_interval=None,
                  dtim_period=None, frag_threshold=None, ssid=None, bssid=None,
@@ -432,7 +438,8 @@
                  obss_interval=None,
                  vht_channel_width=None,
                  vht_center_channel=None,
-                 ac_capabilities=[]):
+                 ac_capabilities=[],
+                 beacon_footer=''):
         """Construct a HostapConfig.
 
         You may specify channel or frequency, but not both.  Both options
@@ -459,6 +466,8 @@
         @param vht_channel_width object channel width
         @param vht_center_channel int center channel of segment 0.
         @param ac_capabilities list of AC_CAPABILITY_x defined above.
+        @param beacon_footer string containing (unvalidated) IE data to be
+            placed at the end of the beacon.
 
         """
         super(HostapConfig, self).__init__()
@@ -524,6 +533,7 @@
         # and operating channel.
         self._vht_oper_centr_freq_seg0_idx = vht_center_channel
         self._ac_capabilities = set(ac_capabilities)
+        self._beacon_footer = beacon_footer
 
 
     def __repr__(self):
diff --git a/server/site_linux_router.py b/server/site_linux_router.py
index 0c98544..df0944d 100644
--- a/server/site_linux_router.py
+++ b/server/site_linux_router.py
@@ -393,6 +393,7 @@
         self.start_hostapd(configuration)
         interface = self.hostapd_instances[-1].interface
         self.iw_runner.set_tx_power(interface, 'auto')
+        self.set_beacon_footer(interface, configuration.beacon_footer)
         self.start_local_server(interface)
         logging.info('AP configured.')
 
@@ -912,3 +913,19 @@
                       's.sendto(sys.stdin.read(), (\'%s\', %d))"' %
                       (dest_ip, UDP_DISCARD_PORT),
                       stdin=magic_packet)
+
+
+    def set_beacon_footer(self, interface, footer=''):
+        """Sets the beacon footer (appended IE information) for this interface.
+
+        @param interface string interface to set the footer on.
+        @param footer string footer to be set on the interface.
+
+        """
+        footer_file = ('/sys/kernel/debug/ieee80211/%s/beacon_footer' %
+                       self.iw_runner.get_interface(interface).phy)
+        if self.router.run('test -e %s' % footer_file,
+                           ignore_status=True).exit_status != 0:
+            logging.info('Beacon footer file does not exist.  Ignoring.')
+            return
+        self.host.run('echo -ne %s > %s' % ('%r' % footer, footer_file))
diff --git a/server/site_tests/network_WiFi_SimpleConnect/control.wifi_checkTruncatedBeacon b/server/site_tests/network_WiFi_SimpleConnect/control.wifi_checkTruncatedBeacon
new file mode 100644
index 0000000..11af821
--- /dev/null
+++ b/server/site_tests/network_WiFi_SimpleConnect/control.wifi_checkTruncatedBeacon
@@ -0,0 +1,37 @@
+# Copyright 2014 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.
+
+AUTHOR = 'wiley, pstew, quiche'
+NAME = 'network_WiFi_SimpleConnect.wifi_checkTruncatedBeacon'
+TIME = 'SHORT'
+TEST_TYPE = 'Server'
+SUITE = 'wifi_matfunc, wifi_correctness_cros_core, wifi_release'
+DEPENDENCIES = 'wificell'
+
+DOC = """
+This test attempts to verify that we can connect to a router that sends
+corrupted beacons.  In this particular case, the beacon data is truncated.
+"""
+
+
+from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
+from autotest_lib.server.cros.network import hostap_config
+
+
+def run(machine):
+    b_mode = hostap_config.HostapConfig.MODE_11B
+    # This is an incomplete vendor-specific beacon IE (one byte short).
+    beacon_footer = '\xdd\x0b\0\x1a\x11\x01\0\0\0\0\0\0'
+    configurations = [(hostap_config.HostapConfig(channel=1, mode=b_mode,
+                                                  beacon_footer=beacon_footer),
+                       xmlrpc_datatypes.AssociationParameters())]
+    host = hosts.create_host(machine)
+    job.run_test('network_WiFi_SimpleConnect',
+                 tag=NAME.split('.')[1],
+                 host=host,
+                 raw_cmdline_args=args,
+                 additional_params=configurations)
+
+
+parallel_simple(run, machines)