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