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 xmlrpc_datatypes 9 from autotest_lib.server.cros.network import hostap_config 10 from autotest_lib.server.cros.network import wifi_cell_test_base 11 12 13 class network_WiFi_MissingBeacons(wifi_cell_test_base.WiFiCellTestBase): 14 """Test how a DUT behaves when an AP disappears suddenly. 15 16 Connects a DUT to an AP, then kills the AP in such a way that no de-auth 17 message is sent. Asserts that the DUT marks itself as disconnected from 18 the AP within MAX_DISCONNECT_TIME_SECONDS. 19 20 """ 21 22 version = 1 23 24 MAX_DISCONNECT_TIME_SECONDS = 20 25 26 27 def _assert_disconnect(self, ssid): 28 """Assert that we disconnect from |ssid| MAX_DISCONNECT_TIME_SECONDS. 29 30 @param ssid: string ssid of network we expect to be disconnected from. 31 32 """ 33 # Leave some margin of seconds to check how long it actually 34 # takes to disconnect should we fail to disconnect in time. 35 timeout_seconds = self.MAX_DISCONNECT_TIME_SECONDS + 10 36 logging.info('Waiting %.2f seconds for client to notice the missing ' 37 'AP.', timeout_seconds) 38 result = self.context.client.wait_for_service_states( 39 ssid, ['idle'], timeout_seconds=timeout_seconds) 40 success, state, duration_seconds = result 41 if not success or duration_seconds > self.MAX_DISCONNECT_TIME_SECONDS: 42 raise error.TestFail('Timed out waiting disconnect in %f ' 43 'seconds. Ended in %s' % 44 (duration_seconds, state)) 45 else: 46 logging.info('Client detected the AP absence in %.2f seconds', 47 duration_seconds) 48 # It seems redundant to disconnect a service that is already 49 # disconnected, but it prevents shill from attempting to re-connect 50 # and foiling future connection attempts. 51 self.context.client.shill.disconnect(ssid) 52 53 54 def run_once(self): 55 """Body of the test.""" 56 ap_config = hostap_config.HostapConfig(channel=1) 57 self.context.configure(ap_config) 58 ssid = self.context.router.get_ssid() 59 client_config = xmlrpc_datatypes.AssociationParameters(ssid=ssid) 60 self.context.assert_connect_wifi(client_config) 61 self.context.assert_ping_from_dut() 62 # Take down the AP interface, which looks like the AP "disappeared" 63 # from the DUT's point of view. This is also much faster than actually 64 # tearing down the AP, which allows us to watch for the client reporting 65 # itself as disconnected. 66 self.context.router.set_ap_interface_down() 67 self._assert_disconnect(ssid) 68 self.context.router.deconfig_aps() 69 logging.info('Repeating test with a client scan just before AP death.') 70 self.context.configure(ap_config) 71 ssid = self.context.router.get_ssid() 72 client_config = xmlrpc_datatypes.AssociationParameters(ssid=ssid) 73 self.context.assert_connect_wifi(client_config) 74 self.context.assert_ping_from_dut() 75 self.context.client.scan(frequencies=[], ssids=[]) 76 self.context.router.set_ap_interface_down() 77 self._assert_disconnect(ssid) 78 self.context.router.deconfig_aps() 79