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