HostapConfig refactor

Refactor HostapConfig class to have it generate config dictionary. Updated variables' name scope to internal when possible.

BUG=chromium:347346
TEST=Run full wifi_matfunc test suite.

Change-Id: Ibbfce87fc25b57da3e411517d5da7a0e9e77aa73
Reviewed-on: https://chromium-review.googlesource.com/188169
Tested-by: Peter Qiu <zqiu@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Peter Qiu <zqiu@chromium.org>
diff --git a/server/cros/network/hostap_config.py b/server/cros/network/hostap_config.py
index cf87bc3..2848274 100644
--- a/server/cros/network/hostap_config.py
+++ b/server/cros/network/hostap_config.py
@@ -104,6 +104,8 @@
                           PMF_SUPPORT_ENABLED,
                           PMF_SUPPORT_REQUIRED)
 
+    DRIVER_NAME = 'nl80211'
+
 
     @staticmethod
     def get_channel_for_frequency(frequency):
@@ -134,6 +136,89 @@
 
 
     @property
+    def _get_default_config(self):
+        """@return dict of default options for hostapd."""
+        return {'hw_mode': 'g',
+                'logger_syslog': '-1',
+                'logger_syslog_level': '0',
+                # default RTS and frag threshold to ``off''
+                'rts_threshold': '2347',
+                'fragm_threshold': '2346',
+                'driver': self.DRIVER_NAME }
+
+
+    @property
+    def _ht40_plus_allowed(self):
+        """@return True iff HT40+ is enabled for this configuration."""
+        channel_supported = (self.channel in
+                             self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS])
+        return ((self.N_CAPABILITY_HT40_PLUS in self._n_capabilities or
+                 self.N_CAPABILITY_HT40 in self._n_capabilities) and
+                channel_supported)
+
+
+    @property
+    def _ht40_minus_allowed(self):
+        """@return True iff HT40- is enabled for this configuration."""
+        channel_supported = (self.channel in
+                             self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS])
+        return ((self.N_CAPABILITY_HT40_MINUS in self._n_capabilities or
+                 self.N_CAPABILITY_HT40 in self._n_capabilities) and
+                channel_supported)
+
+
+    @property
+    def _hostapd_ht_capabilities(self):
+        """@return string suitable for the ht_capab= line in a hostapd config"""
+        ret = []
+        if self._ht40_plus_allowed:
+            ret.append('[HT40+]')
+        elif self._ht40_minus_allowed:
+            ret.append('[HT40-]')
+        if self.N_CAPABILITY_GREENFIELD in self._n_capabilities:
+            logging.warning('Greenfield flag is ignored for hostap...')
+        if self.N_CAPABILITY_SGI20 in self._n_capabilities:
+            ret.append('[SHORT-GI-20]')
+        if self.N_CAPABILITY_SGI40 in self._n_capabilities:
+            ret.append('[SHORT-GI-40]')
+        return ''.join(ret)
+
+
+    @property
+    def _require_ht(self):
+        """@return True iff clients should be required to support HT."""
+        # TODO(wiley) Why? (crbug.com/237370)
+        logging.warning('Not enforcing pure N mode because Snow does '
+                        'not seem to support it...')
+        return False
+
+
+    @property
+    def _hw_mode(self):
+        """@return string hardware mode understood by hostapd."""
+        if self._mode == self.MODE_11A:
+            return self.MODE_11A
+        if self._mode == self.MODE_11B:
+            return self.MODE_11B
+        if self._mode == self.MODE_11G:
+            return self.MODE_11G
+        if self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE):
+            # For their own historical reasons, hostapd wants it this way.
+            if self._frequency > 5000:
+                return self.MODE_11A
+
+            return self.MODE_11G
+
+        raise error.TestFail('Invalid mode.')
+
+
+    @property
+    def _is_11n(self):
+        """@return True iff we're trying to host an 802.11n network."""
+        return self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE)
+
+
+    @property
     def channel(self):
         """@return int channel number for self.frequency."""
         return self.get_channel_for_frequency(self.frequency)
@@ -170,40 +255,19 @@
 
 
     @property
-    def hostapd_ht_capabilities(self):
-        """@return string suitable for the ht_capab= line in a hostapd config"""
-        ret = []
-        if self.ht40_plus_allowed:
-            ret.append('[HT40+]')
-        elif self.ht40_minus_allowed:
-            ret.append('[HT40-]')
-        if self.N_CAPABILITY_GREENFIELD in self._n_capabilities:
-            logging.warning('Greenfield flag is ignored for hostap...')
-        if self.N_CAPABILITY_SGI20 in self._n_capabilities:
-            ret.append('[SHORT-GI-20]')
-        if self.N_CAPABILITY_SGI40 in self._n_capabilities:
-            ret.append('[SHORT-GI-40]')
-        return ''.join(ret)
+    def ssid(self):
+        """@return string SSID."""
+        return self._ssid
 
 
-    @property
-    def ht40_plus_allowed(self):
-        """@return True iff HT40+ is enabled for this configuration."""
-        channel_supported = (self.channel in
-                             self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS])
-        return ((self.N_CAPABILITY_HT40_PLUS in self._n_capabilities or
-                 self.N_CAPABILITY_HT40 in self._n_capabilities) and
-                channel_supported)
+    @ssid.setter
+    def ssid(self, value):
+        """Sets the ssid for the hostapd.
 
+        @param value: string ssid name.
 
-    @property
-    def ht40_minus_allowed(self):
-        """@return True iff HT40- is enabled for this configuration."""
-        channel_supported = (self.channel in
-                             self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS])
-        return ((self.N_CAPABILITY_HT40_MINUS in self._n_capabilities or
-                 self.N_CAPABILITY_HT40 in self._n_capabilities) and
-                channel_supported)
+        """
+        self._ssid = value
 
 
     @property
@@ -220,68 +284,34 @@
         @return string HT parameter for frequency configuration.
 
         """
-        if not self.is_11n:
+        if not self._is_11n:
             return None
 
-        if self.ht40_plus_allowed:
+        if self._ht40_plus_allowed:
             return 'HT40+'
 
-        if self.ht40_minus_allowed:
+        if self._ht40_minus_allowed:
             return 'HT40-'
 
         return 'HT20'
 
 
     @property
-    def hw_mode(self):
-        """@return string hardware mode understood by hostapd."""
-        if self._mode == self.MODE_11A:
-            return self.MODE_11A
-        if self._mode == self.MODE_11B:
-            return self.MODE_11B
-        if self._mode == self.MODE_11G:
-            return self.MODE_11G
-        if self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE):
-            # For their own historical reasons, hostapd wants it this way.
-            if self.frequency > 5000:
-                return self.MODE_11A
-
-            return self.MODE_11G
-
-        raise error.TestFail('Invalid mode.')
-
-
-    @property
-    def is_11n(self):
-        """@return True iff we're trying to host an 802.11n network."""
-        return self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE)
-
-
-    @property
     def perf_loggable_description(self):
         """@return string test description suitable for performance logging."""
         mode = 'mode%s' % (
                 self.printable_mode.replace('+', 'p').replace('-', 'm'))
         channel = 'ch%03d' % self.channel
-        return '_'.join([channel, mode, self.security_config.security])
+        return '_'.join([channel, mode, self._security_config.security])
 
 
     @property
     def printable_mode(self):
         """@return human readable mode string."""
-        if self.is_11n:
+        if self._is_11n:
             return self.ht_packet_capture_mode
 
-        return '11' + self.hw_mode.upper()
-
-
-    @property
-    def require_ht(self):
-        """@return True iff clients should be required to support HT."""
-        # TODO(wiley) Why? (crbug.com/237370)
-        logging.warning('Not enforcing pure N mode because Snow does '
-                        'not seem to support it...')
-        return False
+        return '11' + self._hw_mode.upper()
 
 
     @property
@@ -290,6 +320,18 @@
         return '_ch%d' % self.channel
 
 
+    @property
+    def security_config(self):
+        """@return SecurityConfig security config object"""
+        return self._security_config
+
+
+    @property
+    def hide_ssid(self):
+        """@return bool _hide_ssid flag."""
+        return self._hide_ssid
+
+
     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,
@@ -326,7 +368,7 @@
             raise error.TestError('Specify either frequency or channel '
                                   'but not both.')
 
-        self.wmm_enabled = False
+        self._wmm_enabled = False
         unknown_caps = [cap for cap in n_capabilities
                         if cap not in self.ALL_N_CAPABILITIES]
         if unknown_caps:
@@ -334,7 +376,7 @@
 
         self._n_capabilities = set(n_capabilities)
         if self._n_capabilities:
-            self.wmm_enabled = True
+            self._wmm_enabled = True
         if self._n_capabilities and mode is None:
             mode = self.MODE_11N_PURE
         self._mode = mode
@@ -351,25 +393,25 @@
             raise error.TestFail('Configured a mode %s that does not support '
                                  'frequency %d' % (self._mode, self.frequency))
 
-        self.hide_ssid = hide_ssid
-        self.beacon_interval = beacon_interval
-        self.dtim_period = dtim_period
-        self.frag_threshold = frag_threshold
+        self._hide_ssid = hide_ssid
+        self._beacon_interval = beacon_interval
+        self._dtim_period = dtim_period
+        self._frag_threshold = frag_threshold
         if ssid and len(ssid) > 32:
             raise error.TestFail('Tried to specify SSID that was too long.')
 
-        self.ssid = ssid
-        self.bssid = bssid
+        self._ssid = ssid
+        self._bssid = bssid
         if force_wmm is not None:
-            self.wmm_enabled = force_wmm
+            self._wmm_enabled = force_wmm
         if pmf_support not in self.PMF_SUPPORT_VALUES:
             raise error.TestFail('Invalid value for pmf_support: %r' %
                                  pmf_support)
 
-        self.pmf_support = pmf_support
-        self.security_config = (copy.copy(security_config) or
+        self._pmf_support = pmf_support
+        self._security_config = (copy.copy(security_config) or
                                 xmlrpc_security_types.SecurityConfig())
-        self.obss_interval = obss_interval
+        self._obss_interval = obss_interval
 
 
     def __repr__(self):
@@ -382,19 +424,14 @@
                         self.channel,
                         self.frequency,
                         self._n_capabilities,
-                        self.hide_ssid,
-                        self.beacon_interval,
-                        self.dtim_period,
-                        self.frag_threshold,
-                        self.ssid,
-                        self.bssid,
-                        self.wmm_enabled,
-                        self.security_config))
-
-
-    def get_security_hostapd_conf(self):
-        """@return dict of hostapd settings related to security."""
-        return self.security_config.get_hostapd_config()
+                        self._hide_ssid,
+                        self._beacon_interval,
+                        self._dtim_period,
+                        self._frag_threshold,
+                        self._ssid,
+                        self._bssid,
+                        self._wmm_enabled,
+                        self._security_config))
 
 
     def supports_channel(self, value):
@@ -445,3 +482,46 @@
             return False
 
         return True
+
+
+    def generate_dict(self, interface, control_interface, ssid):
+        """Generate config dictionary.
+
+        Generate config dictionary for the given |interface|.
+
+        @param interface: string interface to generate config dict for.
+        @param control_interface: string control interface
+        @param ssid: string SSID of the AP.
+        @return dict of hostap configurations.
+
+        """
+        # Start with the default config parameters.
+        conf = self._get_default_config
+        conf['ssid'] = (self._ssid or ssid)
+        if self._bssid:
+            conf['bssid'] = self._bssid
+        conf['channel'] = self.channel
+        conf['hw_mode'] = self._hw_mode
+        if self._hide_ssid:
+            conf['ignore_broadcast_ssid'] = 1
+        if self._is_11n:
+            conf['ieee80211n'] = 1
+            conf['ht_capab'] = self._hostapd_ht_capabilities
+        if self._wmm_enabled:
+            conf['wmm_enabled'] = 1
+        if self._require_ht:
+            conf['require_ht'] = 1
+        if self._beacon_interval:
+            conf['beacon_int'] = self._beacon_interval
+        if self._dtim_period:
+            conf['dtim_period'] = self._dtim_period
+        if self._frag_threshold:
+            conf['fragm_threshold'] = self._frag_threshold
+        if self._pmf_support:
+            conf['ieee80211w'] = self._pmf_support
+        if self._obss_interval:
+            conf['obss_interval'] = self._obss_interval
+        conf['interface'] = interface
+        conf['ctrl_interface'] = control_interface
+        conf.update(self._security_config.get_hostapd_config())
+        return conf
diff --git a/server/site_linux_router.py b/server/site_linux_router.py
index 4e64a8c..3670479 100644
--- a/server/site_linux_router.py
+++ b/server/site_linux_router.py
@@ -126,15 +126,12 @@
         return bool(self.local_servers)
 
 
-    def start_hostapd(self, hostapd_conf_dict, configuration):
+    def start_hostapd(self, configuration):
         """Start a hostapd instance described by conf.
 
-        @param hostapd_conf_dict dict of hostapd configuration parameters.
         @param configuration HostapConfig object.
 
         """
-        logging.info('Starting hostapd with parameters: %r',
-                     hostapd_conf_dict)
         # Figure out the correct interface.
         interface = self.get_wlanif(configuration.frequency, 'managed')
 
@@ -142,8 +139,10 @@
         log_file = self.HOSTAPD_LOG_FILE_PATTERN % interface
         pid_file = self.HOSTAPD_PID_FILE_PATTERN % interface
         control_interface = self.HOSTAPD_CONTROL_INTERFACE_PATTERN % interface
-        hostapd_conf_dict['interface'] = interface
-        hostapd_conf_dict['ctrl_interface'] = control_interface
+        hostapd_conf_dict = configuration.generate_dict(
+                interface, control_interface,
+                self._build_ssid(configuration.ssid_suffix))
+        logging.info('Starting hostapd with parameters: %r', hostapd_conf_dict)
 
         # Generate hostapd.conf.
         self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
@@ -240,18 +239,6 @@
         self.kill_hostapd_instance(None)
 
 
-    def __get_default_hostap_config(self):
-        """@return dict of default options for hostapd."""
-        return {'hw_mode': 'g',
-                'logger_syslog': '-1',
-                'logger_syslog_level': '0',
-                # default RTS and frag threshold to ``off''
-                'rts_threshold': '2347',
-                'fragm_threshold': '2346',
-                'driver': self.HOSTAPD_DRIVER_NAME,
-                'ssid': self._build_ssid('') }
-
-
     def _build_ssid(self, suffix):
         unique_salt = ''.join([random.choice(self.SUFFIX_LETTERS)
                                for x in range(5)])
@@ -270,35 +257,7 @@
         if multi_interface is None and (self.hostapd_instances or
                                         self.station_instances):
             self.deconfig()
-        # Start with the default hostapd config parameters.
-        conf = self.__get_default_hostap_config()
-        conf['ssid'] = (configuration.ssid or
-                        self._build_ssid(configuration.ssid_suffix))
-        if configuration.bssid:
-            conf['bssid'] = configuration.bssid
-        conf['channel'] = configuration.channel
-        conf['hw_mode'] = configuration.hw_mode
-        if configuration.hide_ssid:
-            conf['ignore_broadcast_ssid'] = 1
-        if configuration.is_11n:
-            conf['ieee80211n'] = 1
-            conf['ht_capab'] = configuration.hostapd_ht_capabilities
-        if configuration.wmm_enabled:
-            conf['wmm_enabled'] = 1
-        if configuration.require_ht:
-            conf['require_ht'] = 1
-        if configuration.beacon_interval:
-            conf['beacon_int'] = configuration.beacon_interval
-        if configuration.dtim_period:
-            conf['dtim_period'] = configuration.dtim_period
-        if configuration.frag_threshold:
-            conf['fragm_threshold'] = configuration.frag_threshold
-        if configuration.pmf_support:
-            conf['ieee80211w'] = configuration.pmf_support
-        if configuration.obss_interval:
-            conf['obss_interval'] = configuration.obss_interval
-        conf.update(configuration.get_security_hostapd_conf())
-        self.start_hostapd(conf, configuration)
+        self.start_hostapd(configuration)
         interface = self.hostapd_instances[-1]['interface']
         self.iw_runner.set_tx_power(interface, 'auto')
         self.start_local_server(interface)