Home | History | Annotate | Download | only in network
      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 collections
      6 import copy
      7 import logging
      8 
      9 from autotest_lib.client.common_lib import error
     10 from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types
     11 
     12 
     13 class HostapConfig(object):
     14     """Parameters for router configuration."""
     15 
     16     # A mapping of frequency to channel number.  This includes some
     17     # frequencies used outside the US.
     18     CHANNEL_MAP = {2412: 1,
     19                    2417: 2,
     20                    2422: 3,
     21                    2427: 4,
     22                    2432: 5,
     23                    2437: 6,
     24                    2442: 7,
     25                    2447: 8,
     26                    2452: 9,
     27                    2457: 10,
     28                    2462: 11,
     29                    # 12, 13 are only legitimate outside the US.
     30                    2467: 12,
     31                    2472: 13,
     32                    # 14 is for Japan, DSSS and CCK only.
     33                    2484: 14,
     34                    # 34 valid in Japan.
     35                    5170: 34,
     36                    # 36-116 valid in the US, except 38, 42, and 46, which have
     37                    # mixed international support.
     38                    5180: 36,
     39                    5190: 38,
     40                    5200: 40,
     41                    5210: 42,
     42                    5220: 44,
     43                    5230: 46,
     44                    5240: 48,
     45                    5260: 52,
     46                    5280: 56,
     47                    5300: 60,
     48                    5320: 64,
     49                    5500: 100,
     50                    5520: 104,
     51                    5540: 108,
     52                    5560: 112,
     53                    5580: 116,
     54                    # 120, 124, 128 valid in Europe/Japan.
     55                    5600: 120,
     56                    5620: 124,
     57                    5640: 128,
     58                    # 132+ valid in US.
     59                    5660: 132,
     60                    5680: 136,
     61                    5700: 140,
     62                    # 144 is supported by a subset of WiFi chips
     63                    # (e.g. bcm4354, but not ath9k).
     64                    5720: 144,
     65                    5745: 149,
     66                    5765: 153,
     67                    5785: 157,
     68                    5805: 161,
     69                    5825: 165}
     70 
     71     MODE_11A = 'a'
     72     MODE_11B = 'b'
     73     MODE_11G = 'g'
     74     MODE_11N_MIXED = 'n-mixed'
     75     MODE_11N_PURE = 'n-only'
     76     MODE_11AC_MIXED = 'ac-mixed'
     77     MODE_11AC_PURE = 'ac-only'
     78 
     79     N_CAPABILITY_HT20 = object()
     80     N_CAPABILITY_HT40 = object()
     81     N_CAPABILITY_HT40_PLUS = object()
     82     N_CAPABILITY_HT40_MINUS = object()
     83     N_CAPABILITY_GREENFIELD = object()
     84     N_CAPABILITY_SGI20 = object()
     85     N_CAPABILITY_SGI40 = object()
     86     ALL_N_CAPABILITIES = [N_CAPABILITY_HT20,
     87                           N_CAPABILITY_HT40,
     88                           N_CAPABILITY_HT40_PLUS,
     89                           N_CAPABILITY_HT40_MINUS,
     90                           N_CAPABILITY_GREENFIELD,
     91                           N_CAPABILITY_SGI20,
     92                           N_CAPABILITY_SGI40]
     93 
     94     AC_CAPABILITY_VHT160 = object()
     95     AC_CAPABILITY_VHT160_80PLUS80 = object()
     96     AC_CAPABILITY_RXLDPC = object()
     97     AC_CAPABILITY_SHORT_GI_80 = object()
     98     AC_CAPABILITY_SHORT_GI_160 = object()
     99     AC_CAPABILITY_TX_STBC_2BY1 = object()
    100     AC_CAPABILITY_RX_STBC_1 = object()
    101     AC_CAPABILITY_RX_STBC_12 = object()
    102     AC_CAPABILITY_RX_STBC_123 = object()
    103     AC_CAPABILITY_RX_STBC_1234 = object()
    104     AC_CAPABILITY_SU_BEAMFORMER = object()
    105     AC_CAPABILITY_SU_BEAMFORMEE = object()
    106     AC_CAPABILITY_BF_ANTENNA_2 = object()
    107     AC_CAPABILITY_SOUNDING_DIMENSION_2 = object()
    108     AC_CAPABILITY_MU_BEAMFORMER = object()
    109     AC_CAPABILITY_MU_BEAMFORMEE = object()
    110     AC_CAPABILITY_VHT_TXOP_PS = object()
    111     AC_CAPABILITY_HTC_VHT = object()
    112     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP0 = object()
    113     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP1 = object()
    114     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP2 = object()
    115     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP3 = object()
    116     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP4 = object()
    117     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP5 = object()
    118     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP6 = object()
    119     AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7 = object()
    120     AC_CAPABILITY_VHT_LINK_ADAPT2 = object()
    121     AC_CAPABILITY_VHT_LINK_ADAPT3 = object()
    122     AC_CAPABILITY_RX_ANTENNA_PATTERN = object()
    123     AC_CAPABILITY_TX_ANTENNA_PATTERN = object()
    124     AC_CAPABILITIES_MAPPING = {
    125             AC_CAPABILITY_VHT160: '[VHT160]',
    126             AC_CAPABILITY_VHT160_80PLUS80: '[VHT160_80PLUS80]',
    127             AC_CAPABILITY_RXLDPC: '[RXLDPC]',
    128             AC_CAPABILITY_SHORT_GI_80: '[SHORT_GI_80]',
    129             AC_CAPABILITY_SHORT_GI_160: '[SHORT_GI_160]',
    130             AC_CAPABILITY_TX_STBC_2BY1: '[TX_STBC_2BY1',
    131             AC_CAPABILITY_RX_STBC_1: '[RX_STBC_1]',
    132             AC_CAPABILITY_RX_STBC_12: '[RX_STBC_12]',
    133             AC_CAPABILITY_RX_STBC_123: '[RX_STBC_123]',
    134             AC_CAPABILITY_RX_STBC_1234: '[RX_STBC_1234]',
    135             AC_CAPABILITY_SU_BEAMFORMER: '[SU_BEAMFORMER]',
    136             AC_CAPABILITY_SU_BEAMFORMEE: '[SU_BEAMFORMEE]',
    137             AC_CAPABILITY_BF_ANTENNA_2: '[BF_ANTENNA_2]',
    138             AC_CAPABILITY_SOUNDING_DIMENSION_2: '[SOUNDING_DIMENSION_2]',
    139             AC_CAPABILITY_MU_BEAMFORMER: '[MU_BEAMFORMER]',
    140             AC_CAPABILITY_MU_BEAMFORMEE: '[MU_BEAMFORMEE]',
    141             AC_CAPABILITY_VHT_TXOP_PS: '[VHT_TXOP_PS]',
    142             AC_CAPABILITY_HTC_VHT: '[HTC_VHT]',
    143             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP0: '[MAX_A_MPDU_LEN_EXP0]',
    144             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP1: '[MAX_A_MPDU_LEN_EXP1]',
    145             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP2: '[MAX_A_MPDU_LEN_EXP2]',
    146             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP3: '[MAX_A_MPDU_LEN_EXP3]',
    147             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP4: '[MAX_A_MPDU_LEN_EXP4]',
    148             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP5: '[MAX_A_MPDU_LEN_EXP5]',
    149             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP6: '[MAX_A_MPDU_LEN_EXP6]',
    150             AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7: '[MAX_A_MPDU_LEN_EXP7]',
    151             AC_CAPABILITY_VHT_LINK_ADAPT2: '[VHT_LINK_ADAPT2]',
    152             AC_CAPABILITY_VHT_LINK_ADAPT3: '[VHT_LINK_ADAPT3]',
    153             AC_CAPABILITY_RX_ANTENNA_PATTERN: '[RX_ANTENNA_PATTERN]',
    154             AC_CAPABILITY_TX_ANTENNA_PATTERN: '[TX_ANTENNA_PATTERN]'}
    155 
    156     VHT_CHANNEL_WIDTH_40 = object()
    157     VHT_CHANNEL_WIDTH_80 = object()
    158     VHT_CHANNEL_WIDTH_160 = object()
    159     VHT_CHANNEL_WIDTH_80_80 = object()
    160 
    161     # Human readable names for these channel widths.
    162     VHT_NAMES = {
    163         VHT_CHANNEL_WIDTH_40: 'VHT40',
    164         VHT_CHANNEL_WIDTH_80: 'VHT80',
    165         VHT_CHANNEL_WIDTH_160: 'VHT160',
    166         VHT_CHANNEL_WIDTH_80_80: 'VHT80+80',
    167     }
    168 
    169     # This is a loose merging of the rules for US and EU regulatory
    170     # domains as taken from IEEE Std 802.11-2012 Appendix E.  For instance,
    171     # we tolerate HT40 in channels 149-161 (not allowed in EU), but also
    172     # tolerate HT40+ on channel 7 (not allowed in the US).  We take the loose
    173     # definition so that we don't prohibit testing in either domain.
    174     HT40_ALLOW_MAP = {N_CAPABILITY_HT40_MINUS: range(6, 14) +
    175                                                range(40, 65, 8) +
    176                                                range(104, 137, 8) +
    177                                                [153, 161],
    178                       N_CAPABILITY_HT40_PLUS: range(1, 8) +
    179                                               range(36, 61, 8) +
    180                                               range(100, 133, 8) +
    181                                               [149, 157]}
    182 
    183     PMF_SUPPORT_DISABLED = 0
    184     PMF_SUPPORT_ENABLED = 1
    185     PMF_SUPPORT_REQUIRED = 2
    186     PMF_SUPPORT_VALUES = (PMF_SUPPORT_DISABLED,
    187                           PMF_SUPPORT_ENABLED,
    188                           PMF_SUPPORT_REQUIRED)
    189 
    190     DRIVER_NAME = 'nl80211'
    191 
    192 
    193     @staticmethod
    194     def get_channel_for_frequency(frequency):
    195         """Returns the channel number associated with a given frequency.
    196 
    197         @param value: int frequency in MHz.
    198 
    199         @return int frequency associated with the channel.
    200 
    201         """
    202         return HostapConfig.CHANNEL_MAP[frequency]
    203 
    204 
    205     @staticmethod
    206     def get_frequency_for_channel(channel):
    207         """Returns the frequency associated with a given channel number.
    208 
    209         @param value: int channel number.
    210 
    211         @return int frequency in MHz associated with the channel.
    212 
    213         """
    214         for frequency, channel_iter in HostapConfig.CHANNEL_MAP.iteritems():
    215             if channel == channel_iter:
    216                 return frequency
    217         else:
    218             raise error.TestFail('Unknown channel value: %r.' % channel)
    219 
    220 
    221     @property
    222     def _get_default_config(self):
    223         """@return dict of default options for hostapd."""
    224         return collections.OrderedDict([
    225                 ('hw_mode', 'g'),
    226                 ('logger_syslog', '-1'),
    227                 ('logger_syslog_level', '0'),
    228                 # default RTS and frag threshold to ``off''
    229                 ('rts_threshold', '2347'),
    230                 ('fragm_threshold', '2346'),
    231                 ('driver', self.DRIVER_NAME)])
    232 
    233 
    234     @property
    235     def _ht40_plus_allowed(self):
    236         """@return True iff HT40+ is enabled for this configuration."""
    237         channel_supported = (self.channel in
    238                              self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS])
    239         return ((self.N_CAPABILITY_HT40_PLUS in self._n_capabilities or
    240                  self.N_CAPABILITY_HT40 in self._n_capabilities) and
    241                 channel_supported)
    242 
    243 
    244     @property
    245     def _ht40_minus_allowed(self):
    246         """@return True iff HT40- is enabled for this configuration."""
    247         channel_supported = (self.channel in
    248                              self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS])
    249         return ((self.N_CAPABILITY_HT40_MINUS in self._n_capabilities or
    250                  self.N_CAPABILITY_HT40 in self._n_capabilities) and
    251                 channel_supported)
    252 
    253 
    254     @property
    255     def _hostapd_ht_capabilities(self):
    256         """@return string suitable for the ht_capab= line in a hostapd config"""
    257         ret = []
    258         if self._ht40_plus_allowed:
    259             ret.append('[HT40+]')
    260         elif self._ht40_minus_allowed:
    261             ret.append('[HT40-]')
    262         if self.N_CAPABILITY_GREENFIELD in self._n_capabilities:
    263             logging.warning('Greenfield flag is ignored for hostap...')
    264         if self.N_CAPABILITY_SGI20 in self._n_capabilities:
    265             ret.append('[SHORT-GI-20]')
    266         if self.N_CAPABILITY_SGI40 in self._n_capabilities:
    267             ret.append('[SHORT-GI-40]')
    268         return ''.join(ret)
    269 
    270 
    271     @property
    272     def _hostapd_vht_capabilities(self):
    273         """@return string suitable for the vht_capab= line in a hostapd config.
    274         """
    275         ret = []
    276         for cap in self.AC_CAPABILITIES_MAPPING.keys():
    277             if cap in self._ac_capabilities:
    278                 ret.append(self.AC_CAPABILITIES_MAPPING[cap])
    279         return ''.join(ret)
    280 
    281 
    282     @property
    283     def _require_ht(self):
    284         """@return True iff clients should be required to support HT."""
    285         # TODO(wiley) Why? (crbug.com/237370)
    286         logging.warning('Not enforcing pure N mode because Snow does '
    287                         'not seem to support it...')
    288         return False
    289 
    290 
    291     @property
    292     def require_vht(self):
    293         """@return True iff clients should be required to support VHT."""
    294         return self._mode == self.MODE_11AC_PURE
    295 
    296 
    297     @property
    298     def _hw_mode(self):
    299         """@return string hardware mode understood by hostapd."""
    300         if self._mode == self.MODE_11A:
    301             return self.MODE_11A
    302         if self._mode == self.MODE_11B:
    303             return self.MODE_11B
    304         if self._mode == self.MODE_11G:
    305             return self.MODE_11G
    306         if self._is_11n or self.is_11ac:
    307             # For their own historical reasons, hostapd wants it this way.
    308             if self._frequency > 5000:
    309                 return self.MODE_11A
    310 
    311             return self.MODE_11G
    312 
    313         raise error.TestFail('Invalid mode.')
    314 
    315 
    316     @property
    317     def _is_11n(self):
    318         """@return True iff we're trying to host an 802.11n network."""
    319         return self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE)
    320 
    321 
    322     @property
    323     def is_11ac(self):
    324         """@return True iff we're trying to host an 802.11ac network."""
    325         return self._mode in (self.MODE_11AC_MIXED, self.MODE_11AC_PURE)
    326 
    327 
    328     @property
    329     def channel(self):
    330         """@return int channel number for self.frequency."""
    331         return self.get_channel_for_frequency(self.frequency)
    332 
    333 
    334     @channel.setter
    335     def channel(self, value):
    336         """Sets the channel number to configure hostapd to listen on.
    337 
    338         @param value: int channel number.
    339 
    340         """
    341         self.frequency = self.get_frequency_for_channel(value)
    342 
    343 
    344     @property
    345     def frequency(self):
    346         """@return int frequency for hostapd to listen on."""
    347         return self._frequency
    348 
    349 
    350     @frequency.setter
    351     def frequency(self, value):
    352         """Sets the frequency for hostapd to listen on.
    353 
    354         @param value: int frequency in MHz.
    355 
    356         """
    357         if value not in self.CHANNEL_MAP or not self.supports_frequency(value):
    358             raise error.TestFail('Tried to set an invalid frequency: %r.' %
    359                                  value)
    360 
    361         self._frequency = value
    362 
    363 
    364     @property
    365     def ssid(self):
    366         """@return string SSID."""
    367         return self._ssid
    368 
    369 
    370     @ssid.setter
    371     def ssid(self, value):
    372         """Sets the ssid for the hostapd.
    373 
    374         @param value: string ssid name.
    375 
    376         """
    377         self._ssid = value
    378 
    379 
    380     @property
    381     def ht_packet_capture_mode(self):
    382         """Get an appropriate packet capture HT parameter.
    383 
    384         When we go to configure a raw monitor we need to configure
    385         the phy to listen on the correct channel.  Part of doing
    386         so is to specify the channel width for HT channels.  In the
    387         case that the AP is configured to be either HT40+ or HT40-,
    388         we could return the wrong parameter because we don't know which
    389         configuration will be chosen by hostap.
    390 
    391         @return string HT parameter for frequency configuration.
    392 
    393         """
    394         if not self._is_11n:
    395             return None
    396 
    397         if self._ht40_plus_allowed:
    398             return 'HT40+'
    399 
    400         if self._ht40_minus_allowed:
    401             return 'HT40-'
    402 
    403         return 'HT20'
    404 
    405 
    406     @property
    407     def perf_loggable_description(self):
    408         """@return string test description suitable for performance logging."""
    409         mode = 'mode%s' % (
    410                 self.printable_mode.replace('+', 'p').replace('-', 'm'))
    411         channel = 'ch%03d' % self.channel
    412         return '_'.join([channel, mode, self._security_config.security])
    413 
    414 
    415     @property
    416     def printable_mode(self):
    417         """@return human readable mode string."""
    418 
    419         # Note: VHT capture is not yet supported in ht_packet_capture_mode()
    420         # (nor cros.network.packet_capturer).
    421         if self.vht_channel_width is not None:
    422             return self.VHT_NAMES[self.vht_channel_width]
    423 
    424         if self._is_11n:
    425             return self.ht_packet_capture_mode
    426 
    427         return '11' + self._hw_mode.upper()
    428 
    429 
    430     @property
    431     def ssid_suffix(self):
    432         """@return meaningful suffix for SSID."""
    433         return 'ch%d' % self.channel
    434 
    435 
    436     @property
    437     def security_config(self):
    438         """@return SecurityConfig security config object"""
    439         return self._security_config
    440 
    441 
    442     @property
    443     def hide_ssid(self):
    444         """@return bool _hide_ssid flag."""
    445         return self._hide_ssid
    446 
    447 
    448     @property
    449     def beacon_footer(self):
    450         """@return bool _beacon_footer value."""
    451         return self._beacon_footer
    452 
    453 
    454     @property
    455     def scenario_name(self):
    456         """@return string _scenario_name value, or None."""
    457         return self._scenario_name
    458 
    459 
    460     @property
    461     def min_streams(self):
    462         """@return int _min_streams value, or None."""
    463         return self._min_streams
    464 
    465 
    466     @property
    467     def frag_threshold(self):
    468         """@return int frag threshold value, or None."""
    469         return self._frag_threshold
    470 
    471     @property
    472     def bridge(self):
    473         """@return string _bridge value, or None."""
    474         return self._bridge
    475 
    476     @property
    477     def use_bridge(self):
    478         """@return bool _use_bridge value, or None."""
    479         return self._use_bridge
    480 
    481     @property
    482     def max_stas(self):
    483         """@return int _max_stas value, or None."""
    484         return self._max_stas
    485 
    486     def __init__(self, mode=MODE_11B, channel=None, frequency=None,
    487                  n_capabilities=[], hide_ssid=None, beacon_interval=None,
    488                  dtim_period=None, frag_threshold=None, ssid=None, bssid=None,
    489                  force_wmm=None, security_config=None,
    490                  pmf_support=PMF_SUPPORT_DISABLED,
    491                  obss_interval=None,
    492                  vht_channel_width=None,
    493                  vht_center_channel=None,
    494                  ac_capabilities=[],
    495                  beacon_footer='',
    496                  spectrum_mgmt_required=None,
    497                  scenario_name=None,
    498                  min_streams=None,
    499                  nas_id=None,
    500                  mdid=None,
    501                  r1kh_id=None,
    502                  r0kh=None,
    503                  r1kh=None,
    504                  use_bridge=False,
    505                  max_stas=None):
    506         """Construct a HostapConfig.
    507 
    508         You may specify channel or frequency, but not both.  Both options
    509         are checked for validity (i.e. you can't specify an invalid channel
    510         or a frequency that will not be accepted).
    511 
    512         @param mode string MODE_11x defined above.
    513         @param channel int channel number.
    514         @param frequency int frequency of channel.
    515         @param n_capabilities list of N_CAPABILITY_x defined above.
    516         @param hide_ssid True if we should set up a hidden SSID.
    517         @param beacon_interval int beacon interval of AP.
    518         @param dtim_period int include a DTIM every |dtim_period| beacons.
    519         @param frag_threshold int maximum outgoing data frame size.
    520         @param ssid string up to 32 byte SSID overriding the router default.
    521         @param bssid string like 00:11:22:33:44:55.
    522         @param force_wmm True if we should force WMM on, False if we should
    523             force it off, None if we shouldn't force anything.
    524         @param security_config SecurityConfig object.
    525         @param pmf_support one of PMF_SUPPORT_* above.  Controls whether the
    526             client supports/must support 802.11w.
    527         @param obss_interval int interval in seconds that client should be
    528             required to do background scans for overlapping BSSes.
    529         @param vht_channel_width object channel width
    530         @param vht_center_channel int center channel of segment 0.
    531         @param ac_capabilities list of AC_CAPABILITY_x defined above.
    532         @param beacon_footer string containing (unvalidated) IE data to be
    533             placed at the end of the beacon.
    534         @param spectrum_mgmt_required True if we require the DUT to support
    535             spectrum management.
    536         @param scenario_name string to be included in file names, instead
    537             of the interface name.
    538         @param min_streams int number of spatial streams required.
    539         @param nas_id string for RADIUS messages (needed for 802.11r)
    540         @param mdid string used to indicate a group of APs for FT
    541         @param r1kh_id string PMK-R1 key holder id for FT
    542         @param r0kh string R0KHs in the same mobility domain
    543         @param r1kh string R1KHs in the same mobility domain
    544         @param use_bridge True if we should use a bridge
    545         @param max_stas int maximum number of STAs allowed to connect to AP.
    546 
    547         """
    548         super(HostapConfig, self).__init__()
    549         if channel is not None and frequency is not None:
    550             raise error.TestError('Specify either frequency or channel '
    551                                   'but not both.')
    552 
    553         self._wmm_enabled = False
    554         unknown_caps = [cap for cap in n_capabilities
    555                         if cap not in self.ALL_N_CAPABILITIES]
    556         if unknown_caps:
    557             raise error.TestError('Unknown capabilities: %r' % unknown_caps)
    558 
    559         self._n_capabilities = set(n_capabilities)
    560         if self._n_capabilities:
    561             self._wmm_enabled = True
    562         if self._n_capabilities and mode is None:
    563             mode = self.MODE_11N_PURE
    564         self._mode = mode
    565 
    566         self._frequency = None
    567         if channel:
    568             self.channel = channel
    569         elif frequency:
    570             self.frequency = frequency
    571         else:
    572             raise error.TestError('Specify either frequency or channel.')
    573 
    574         if not self.supports_frequency(self.frequency):
    575             raise error.TestFail('Configured a mode %s that does not support '
    576                                  'frequency %d' % (self._mode, self.frequency))
    577 
    578         self._hide_ssid = hide_ssid
    579         self._beacon_interval = beacon_interval
    580         self._dtim_period = dtim_period
    581         self._frag_threshold = frag_threshold
    582         if ssid and len(ssid) > 32:
    583             raise error.TestFail('Tried to specify SSID that was too long.')
    584 
    585         self._ssid = ssid
    586         self._bssid = bssid
    587         if force_wmm is not None:
    588             self._wmm_enabled = force_wmm
    589         if pmf_support not in self.PMF_SUPPORT_VALUES:
    590             raise error.TestFail('Invalid value for pmf_support: %r' %
    591                                  pmf_support)
    592 
    593         self._pmf_support = pmf_support
    594         self._security_config = (copy.copy(security_config) or
    595                                 xmlrpc_security_types.SecurityConfig())
    596         self._obss_interval = obss_interval
    597         if vht_channel_width == self.VHT_CHANNEL_WIDTH_40:
    598             self._vht_oper_chwidth = 0
    599         elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80:
    600             self._vht_oper_chwidth = 1
    601         elif vht_channel_width == self.VHT_CHANNEL_WIDTH_160:
    602             self._vht_oper_chwidth = 2
    603         elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80_80:
    604             self._vht_oper_chwidth = 3
    605         elif vht_channel_width is not None:
    606             raise error.TestFail('Invalid channel width')
    607         self.vht_channel_width = vht_channel_width
    608         # TODO(zqiu) Add checking for center channel based on the channel width
    609         # and operating channel.
    610         self._vht_oper_centr_freq_seg0_idx = vht_center_channel
    611         self._ac_capabilities = set(ac_capabilities)
    612         self._beacon_footer = beacon_footer
    613         self._spectrum_mgmt_required = spectrum_mgmt_required
    614         self._scenario_name = scenario_name
    615         self._min_streams = min_streams
    616         self._nas_id = nas_id
    617         self._mdid = mdid
    618         self._r1kh_id = r1kh_id
    619         self._r0kh = r0kh
    620         self._r1kh = r1kh
    621         self._bridge = None
    622         self._use_bridge = use_bridge
    623         # keep _max_stas in [0, 2007], as valid AIDs must be in [1, 2007]
    624         if max_stas is None:
    625             self._max_stas = None
    626         else:
    627             self._max_stas = max(0, min(max_stas, 2007))
    628 
    629 
    630     def __repr__(self):
    631         return ('%s(mode=%r, channel=%r, frequency=%r, '
    632                 'n_capabilities=%r, hide_ssid=%r, beacon_interval=%r, '
    633                 'dtim_period=%r, frag_threshold=%r, ssid=%r, bssid=%r, '
    634                 'wmm_enabled=%r, security_config=%r, '
    635                 'spectrum_mgmt_required=%r)' % (
    636                         self.__class__.__name__,
    637                         self._mode,
    638                         self.channel,
    639                         self.frequency,
    640                         self._n_capabilities,
    641                         self._hide_ssid,
    642                         self._beacon_interval,
    643                         self._dtim_period,
    644                         self._frag_threshold,
    645                         self._ssid,
    646                         self._bssid,
    647                         self._wmm_enabled,
    648                         self._security_config,
    649                         self._spectrum_mgmt_required))
    650 
    651 
    652     def supports_channel(self, value):
    653         """Check whether channel is supported by the current hardware mode.
    654 
    655         @param value: int channel to check.
    656         @return True iff the current mode supports the band of the channel.
    657 
    658         """
    659         for freq, channel in self.CHANNEL_MAP.iteritems():
    660             if channel == value:
    661                 return self.supports_frequency(freq)
    662 
    663         return False
    664 
    665 
    666     def supports_frequency(self, frequency):
    667         """Check whether frequency is supported by the current hardware mode.
    668 
    669         @param frequency: int frequency to check.
    670         @return True iff the current mode supports the band of the frequency.
    671 
    672         """
    673         if self._mode == self.MODE_11A and frequency < 5000:
    674             return False
    675 
    676         if self._mode in (self.MODE_11B, self.MODE_11G) and frequency > 5000:
    677             return False
    678 
    679         if frequency not in self.CHANNEL_MAP:
    680             return False
    681 
    682         channel = self.CHANNEL_MAP[frequency]
    683         supports_plus = (channel in
    684                          self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS])
    685         supports_minus = (channel in
    686                           self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS])
    687         if (self.N_CAPABILITY_HT40_PLUS in self._n_capabilities and
    688                 not supports_plus):
    689             return False
    690 
    691         if (self.N_CAPABILITY_HT40_MINUS in self._n_capabilities and
    692                 not supports_minus):
    693             return False
    694 
    695         if (self.N_CAPABILITY_HT40 in self._n_capabilities and
    696                 not supports_plus and not supports_minus):
    697             return False
    698 
    699         return True
    700 
    701 
    702     def generate_dict(self, interface, control_interface, ssid):
    703         """Generate config dictionary.
    704 
    705         Generate config dictionary for the given |interface|.
    706 
    707         @param interface: string interface to generate config dict for.
    708         @param control_interface: string control interface
    709         @param ssid: string SSID of the AP.
    710         @return dict of hostap configurations.
    711 
    712         """
    713         # Start with the default config parameters.
    714         conf = self._get_default_config
    715         conf['ssid'] = (self._ssid or ssid)
    716         if self._bssid:
    717             conf['bssid'] = self._bssid
    718         conf['channel'] = self.channel
    719         conf['hw_mode'] = self._hw_mode
    720         if self._hide_ssid:
    721             conf['ignore_broadcast_ssid'] = 1
    722         if self._is_11n or self.is_11ac:
    723             conf['ieee80211n'] = 1
    724             conf['ht_capab'] = self._hostapd_ht_capabilities
    725         if self.is_11ac:
    726             conf['ieee80211ac'] = 1
    727             conf['vht_oper_chwidth'] = self._vht_oper_chwidth
    728             conf['vht_oper_centr_freq_seg0_idx'] = \
    729                     self._vht_oper_centr_freq_seg0_idx
    730             conf['vht_capab'] = self._hostapd_vht_capabilities
    731         if self._wmm_enabled:
    732             conf['wmm_enabled'] = 1
    733         if self._require_ht:
    734             conf['require_ht'] = 1
    735         if self.require_vht:
    736             conf['require_vht'] = 1
    737         if self._beacon_interval:
    738             conf['beacon_int'] = self._beacon_interval
    739         if self._dtim_period:
    740             conf['dtim_period'] = self._dtim_period
    741         if self._frag_threshold:
    742             conf['fragm_threshold'] = self._frag_threshold
    743         if self._pmf_support:
    744             conf['ieee80211w'] = self._pmf_support
    745         if self._obss_interval:
    746             conf['obss_interval'] = self._obss_interval
    747         if self._nas_id:
    748             conf['nas_identifier'] = self._nas_id
    749         if self._mdid:
    750             conf['mobility_domain'] = self._mdid
    751         if self._r1kh_id:
    752             conf['r1_key_holder'] = self._r1kh_id
    753         if self._r0kh:
    754             conf['r0kh'] = self._r0kh
    755         if self._r1kh:
    756             conf['r1kh'] = self._r1kh
    757         if self._bridge:
    758             conf['bridge'] = self._bridge
    759         if self._max_stas is not None:
    760             conf['max_num_sta'] = self._max_stas
    761         conf['interface'] = interface
    762         conf['ctrl_interface'] = control_interface
    763         if self._spectrum_mgmt_required:
    764             # To set spectrum_mgmt_required, we must first set
    765             # local_pwr_constraint. And to set local_pwr_constraint,
    766             # we must first set ieee80211d. And to set ieee80211d, ...
    767             # Point being: order matters here.
    768             conf['country_code'] = 'US'  # Required for local_pwr_constraint
    769             conf['ieee80211d'] = 1  # Required for local_pwr_constraint
    770             conf['local_pwr_constraint'] = 0  # No local constraint
    771             conf['spectrum_mgmt_required'] = 1  # Requires local_pwr_constraint
    772         conf.update(self._security_config.get_hostapd_config())
    773         return conf
    774