site_linux_router: Check router fragmentation threshold after setting it.

ath10k firmware (on whirlwind routers) doesn't support setting
fragmentation threshold so check and return TestNAError if the
setting was ignored.

BUG=chromium:753177
TEST=network_WiFi_RxFrag (on panther, stumpy, whirlwind)

Change-Id: I71494c7382e225fed5b5bf339fb7e93cd1f86705
Reviewed-on: https://chromium-review.googlesource.com/696133
Commit-Ready: Edward Hill <ecgh@chromium.org>
Tested-by: Edward Hill <ecgh@chromium.org>
Reviewed-by: Brian Norris <briannorris@chromium.org>
diff --git a/client/common_lib/cros/network/iw_runner.py b/client/common_lib/cros/network/iw_runner.py
index 580393d..fd2bf8b 100644
--- a/client/common_lib/cros/network/iw_runner.py
+++ b/client/common_lib/cros/network/iw_runner.py
@@ -933,3 +933,18 @@
                 if frequency in band.frequencies:
                     return True
         return False
+
+
+    def get_fragmentation_threshold(self, phy):
+        """Returns the fragmentation threshold for |phy|.
+
+        @param phy: phy name
+        """
+        ret = self._run('%s phy %s info' % (self._command_iw, phy))
+        frag_regex = r'^\s+Fragmentation threshold:\s+([0-9]+)$'
+        match = re.search(frag_regex, ret.stdout, re.MULTILINE)
+
+        if match:
+            return int(match.group(1))
+
+        return None
diff --git a/client/common_lib/cros/network/iw_runner_unittest.py b/client/common_lib/cros/network/iw_runner_unittest.py
index e93c81a..6b0dbb5 100755
--- a/client/common_lib/cros/network/iw_runner_unittest.py
+++ b/client/common_lib/cros/network/iw_runner_unittest.py
@@ -288,6 +288,18 @@
 
     INFO_IFACE = 'wlan-2400mhz'
 
+    PHY_INFO_FRAGMENTATION = str(
+        'Wiphy phy1\n'
+        '        max # scan SSIDs: 20\n'
+        '        max scan IEs length: 425 bytes\n'
+        '        Fragmentation threshold: 256\n'
+        '        Retry short limit: 7\n'
+        '        Retry long limit: 4\n')
+
+    INFO_PHY = 'phy1'
+
+    PHY_FRAGMENTATION_THRESHOLD = 256
+
 
     def verify_values(self, iw_bss_1, iw_bss_2):
         """Checks all of the IWBss values
@@ -443,5 +455,14 @@
             self.RADIO_CONFIG_AP_MODE)
 
 
+    def test_fragmentation_threshold(self):
+        """Test fragmentation threshold parsing."""
+        host = self.host(self.PHY_INFO_FRAGMENTATION)
+        runner = iw_runner.IwRunner(remote_host=host)
+        self.assertEquals(
+            runner.get_fragmentation_threshold(self.INFO_PHY),
+            self.PHY_FRAGMENTATION_THRESHOLD)
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/server/cros/network/hostap_config.py b/server/cros/network/hostap_config.py
index c9ed94e..473c2c7 100644
--- a/server/cros/network/hostap_config.py
+++ b/server/cros/network/hostap_config.py
@@ -449,6 +449,12 @@
         return self._min_streams
 
 
+    @property
+    def frag_threshold(self):
+        """@return int frag threshold value, or None."""
+        return self._frag_threshold
+
+
     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,
diff --git a/server/site_linux_router.py b/server/site_linux_router.py
index fa51a04..9ef78c6 100644
--- a/server/site_linux_router.py
+++ b/server/site_linux_router.py
@@ -262,6 +262,7 @@
         else:
             interface = self.get_wlanif(
                 configuration.frequency, 'managed', configuration.min_streams)
+        phy_name = self.iw_runner.get_interface(interface).phy
 
         conf_file = self.HOSTAPD_CONF_FILE_PATTERN % interface
         log_file = self.HOSTAPD_LOG_FILE_PATTERN % interface
@@ -279,8 +280,7 @@
 
         # Run hostapd.
         logging.info('Starting hostapd on %s(%s) channel=%s...',
-                     interface, self.iw_runner.get_interface(interface).phy,
-                     configuration.channel)
+                     interface, phy_name, configuration.channel)
         self.router.run('rm %s' % log_file, ignore_status=True)
         self.router.run('stop wpasupplicant', ignore_status=True)
         start_command = '%s -dd -t %s > %s 2> %s & echo $!' % (
@@ -325,6 +325,12 @@
             raise error.TestFail('Timed out while waiting for hostapd '
                                  'to start.')
 
+        if configuration.frag_threshold:
+            threshold = self.iw_runner.get_fragmentation_threshold(phy_name)
+            if threshold != configuration.frag_threshold:
+                raise error.TestNAError('Router does not support setting '
+                                        'fragmentation threshold')
+
 
     def _kill_process_instance(self,
                                process,
diff --git a/server/site_tests/network_WiFi_RxFrag/network_WiFi_RxFrag.py b/server/site_tests/network_WiFi_RxFrag/network_WiFi_RxFrag.py
index 4cb5b4a..8951907 100644
--- a/server/site_tests/network_WiFi_RxFrag/network_WiFi_RxFrag.py
+++ b/server/site_tests/network_WiFi_RxFrag/network_WiFi_RxFrag.py
@@ -24,9 +24,9 @@
 
         """
 
-        # TODO (crbug.com/753177): autodetect this with 'iw phy' -- existing
-        # images (7849.0.2016_01_20_2103) don't know that they're broken, so we
-        # need this at least until those are phased out.
+        # Whirlwind routers don't support fragmentation, and older builds
+        # (up to 7849.0.2016_01_20_2103) don't know that they don't, so check
+        # here using board name.
         if self.context.router.board == "whirlwind":
             raise error.TestNAError('Whirlwind AP does not support frag threshold')