network_WiFi_VerifyRouter: Support pcap device verification.

In b/172221785, we noticed a pcap device that cannot communicate with
DUT and router. In some tests, we rely on a health pcap to provide
packet capture result to verify the behavior. It would be helpful if
VerifyRouter test can also sanitize pcap device.

Also, we started to use pcap as router in some test, so verify pcap
can be more important if we add more tests using it.

Extend the test to support verifying pcap device and add a separate
control file for it.

BUG=b:172221785
TEST=test_that network_WiFi_VerifyRouter
TEST=test_that network_WiFi_VerifyRouter.pcap

Change-Id: I9fc5e6224c8077ee1125b94cea0c2d75746b919f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2534410
Tested-by: Yen-lin Lai <yenlinlai@google.com>
Reviewed-by: Shuo-Peng Liao <deanliao@chromium.org>
Commit-Queue: Yen-lin Lai <yenlinlai@google.com>
diff --git a/server/site_tests/network_WiFi_VerifyRouter/control.pcap b/server/site_tests/network_WiFi_VerifyRouter/control.pcap
new file mode 100644
index 0000000..cf8be2b
--- /dev/null
+++ b/server/site_tests/network_WiFi_VerifyRouter/control.pcap
@@ -0,0 +1,25 @@
+# Copyright (c) 2020 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 = 'yenlinlai'
+NAME = 'network_WiFi_VerifyRouter.pcap'
+TIME = 'SHORT'
+TEST_TYPE = 'Server'
+DEPENDENCIES = 'wificell'
+ATTRIBUTES = 'suite:wifi_update_router'
+
+DOC = """
+This test checks that a dual radio router is working correctly.
+"""
+
+
+def run(machine):
+    host = hosts.create_host(machine)
+    job.run_test('network_WiFi_VerifyRouter',
+                 host=host,
+                 raw_cmdline_args=args,
+                 additional_params=True) # Verify pcap_host
+
+
+parallel_simple(run, machines)
diff --git a/server/site_tests/network_WiFi_VerifyRouter/network_WiFi_VerifyRouter.py b/server/site_tests/network_WiFi_VerifyRouter/network_WiFi_VerifyRouter.py
index 62bd319..385326e 100644
--- a/server/site_tests/network_WiFi_VerifyRouter/network_WiFi_VerifyRouter.py
+++ b/server/site_tests/network_WiFi_VerifyRouter/network_WiFi_VerifyRouter.py
@@ -29,6 +29,24 @@
     # another arbitrary threshold.
     ANTENNA_VARIANCE_THRESHOLD = 15
 
+    def parse_additional_arguments(self, commandline_args, additional_params):
+        """Hook into super class to take control files parameters.
+
+        @param commandline_args dict of parsed parameters from the autotest.
+        @param additional_params bool if the test should verify pcap_host
+                instead of router.
+
+        """
+        if additional_params:
+            self._verify_pcap = additional_params
+        else:
+            self._verify_pcap = False
+
+    def warmup(self, *args, **kwargs):
+        # This test requires pcap_as_router to be True.
+        kwargs['pcap_as_router'] = True
+        super(network_WiFi_VerifyRouter, self).warmup(*args, **kwargs)
+
     def _connect(self, wifi_params):
         assoc_result = xmlrpc_datatypes.deserialize(
                 self.context.client.shill.connect_wifi(wifi_params))
@@ -82,6 +100,12 @@
 
         return None
 
+    @property
+    def target(self):
+        """Return the LinuxRouter object of the device to verify."""
+        if self._verify_pcap:
+            return self.context.pcap_host
+        return self.context.router
 
     def _antenna_test(self, bitmap, channel):
         """Test that we can connect on |channel|, with given antenna |bitmap|.
@@ -113,9 +137,10 @@
         @param channel: int Wifi channel to conduct test on
 
         """
+
         # Antenna can only be configured when the wireless interface is down.
-        self.context.router.deconfig()
-        self.context.router.disable_antennas_except(bitmap)
+        self.target.deconfig()
+        self.target.disable_antennas_except(bitmap)
         # This seems to increase the probability that our association
         # attempts pass.  It is the very definition of a dark incantation.
         time.sleep(5)
@@ -123,8 +148,11 @@
         # radios.
         n_mode = hostap_config.HostapConfig.MODE_11N_MIXED
         ap_config = hostap_config.HostapConfig(channel=channel, mode=n_mode)
-        self.context.configure(ap_config)
-        self.context.configure(ap_config, multi_interface=True)
+        self.context.configure(ap_config, configure_pcap=self._verify_pcap)
+        self.context.configure(
+                ap_config,
+                multi_interface=True,
+                configure_pcap=self._verify_pcap)
         failures = []
         # Verify connectivity to both APs. As the APs are spread
         # across radios, this exercises multiple radios.
@@ -134,7 +162,7 @@
             logging.info('Connecting to AP with settings %s.',
                          context_message)
             client_conf = xmlrpc_datatypes.AssociationParameters(
-                    ssid=self.context.router.get_ssid(instance=instance))
+                    ssid=self.target.get_ssid(instance=instance))
             if self._connect(client_conf):
                 failure = self._check_signal_levels(instance, bitmap, channel)
                 if failure:
@@ -143,7 +171,7 @@
                 failures.append('%s: Failed to connect.' % context_message)
             # Don't automatically reconnect to this AP.
             self.context.client.shill.disconnect(
-                    self.context.router.get_ssid(instance=instance))
+                    self.target.get_ssid(instance=instance))
         return failures
 
 
@@ -155,9 +183,10 @@
         """
         self.context.router.deconfig()
         self.context.router.enable_all_antennas()
+        self.context.pcap_host.deconfig()
+        self.context.pcap_host.enable_all_antennas()
         super(network_WiFi_VerifyRouter, self).cleanup()
 
-
     def run_once(self):
         """Verify that all radios on this router are functional."""
         all_failures = []
@@ -170,7 +199,7 @@
         # now.
         # TODO: communicate this back from the driver better, so we don't have
         # to build an exception list.
-        if self.context.router.board == "gale":
+        if self.target.board == "gale":
             bitmaps = (self.ANTENNAS_BOTH, self.ANTENNAS_1)
         else:
             bitmaps = (self.ANTENNAS_BOTH, self.ANTENNAS_1, self.ANTENNAS_2)