network_WiFi_MissingBeacons: bring down AP interface to simulate AP disapperance

This is a much lightweight operation compare to the full AP teardown
(which takes more than 5 seconds to complete). This fix a possible race
where the wifi service is already removed from shill by the time we check
the state of that service. Also provides more accurate estimate for how
fast the client respond to beacon loss when AP disappears.

BUG=chromium:466355
TEST=Run this test

Change-Id: I056baae85c2ce6b0db25af56a3dc6780f94635d5
Reviewed-on: https://chromium-review.googlesource.com/259871
Reviewed-by: Zeping Qiu <zqiu@chromium.org>
Commit-Queue: Zeping Qiu <zqiu@chromium.org>
Tested-by: Zeping Qiu <zqiu@chromium.org>
diff --git a/server/site_linux_router.py b/server/site_linux_router.py
index 9e8dddc..e465514 100644
--- a/server/site_linux_router.py
+++ b/server/site_linux_router.py
@@ -689,6 +689,16 @@
                              ignore_status=True)
 
 
+    def set_ap_interface_down(self, instance=0):
+        """Bring down the hostapd interface.
+
+        @param instance int router instance number.
+
+        """
+        self.host.run('%s link set %s down' %
+                      (self.cmd_ip, self.get_hostapd_interface(instance)))
+
+
     def confirm_pmksa_cache_use(self, instance=0):
         """Verify that the PMKSA auth was cached on a hostapd instance.
 
diff --git a/server/site_tests/network_WiFi_MissingBeacons/network_WiFi_MissingBeacons.py b/server/site_tests/network_WiFi_MissingBeacons/network_WiFi_MissingBeacons.py
index 22a5616..3e5e53d 100644
--- a/server/site_tests/network_WiFi_MissingBeacons/network_WiFi_MissingBeacons.py
+++ b/server/site_tests/network_WiFi_MissingBeacons/network_WiFi_MissingBeacons.py
@@ -59,8 +59,13 @@
         client_config = xmlrpc_datatypes.AssociationParameters(ssid=ssid)
         self.context.assert_connect_wifi(client_config)
         self.context.assert_ping_from_dut()
-        self.context.router.deconfig_aps(silent=True)
+        # Take down the AP interface, which looks like the AP "disappeared"
+        # from the DUT's point of view.  This is also much faster than actually
+        # tearing down the AP, which allows us to watch for the client reporting
+        # itself as disconnected.
+        self.context.router.set_ap_interface_down()
         self._assert_disconnect(ssid)
+        self.context.router.deconfig_aps()
         logging.info('Repeating test with a client scan just before AP death.')
         self.context.configure(ap_config)
         ssid = self.context.router.get_ssid()
@@ -68,5 +73,6 @@
         self.context.assert_connect_wifi(client_config)
         self.context.assert_ping_from_dut()
         self.context.client.scan(frequencies=[], ssids=[])
-        self.context.router.deconfig_aps(silent=True)
+        self.context.router.set_ap_interface_down()
         self._assert_disconnect(ssid)
+        self.context.router.deconfig_aps()