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 11 12 13class 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 # This is a loose merging of the rules for US and EU regulatory 162 # domains as taken from IEEE Std 802.11-2012 Appendix E. For instance, 163 # we tolerate HT40 in channels 149-161 (not allowed in EU), but also 164 # tolerate HT40+ on channel 7 (not allowed in the US). We take the loose 165 # definition so that we don't prohibit testing in either domain. 166 HT40_ALLOW_MAP = {N_CAPABILITY_HT40_MINUS: range(6, 14) + 167 range(40, 65, 8) + 168 range(104, 137, 8) + 169 [153, 161], 170 N_CAPABILITY_HT40_PLUS: range(1, 8) + 171 range(36, 61, 8) + 172 range(100, 133, 8) + 173 [149, 157]} 174 175 PMF_SUPPORT_DISABLED = 0 176 PMF_SUPPORT_ENABLED = 1 177 PMF_SUPPORT_REQUIRED = 2 178 PMF_SUPPORT_VALUES = (PMF_SUPPORT_DISABLED, 179 PMF_SUPPORT_ENABLED, 180 PMF_SUPPORT_REQUIRED) 181 182 DRIVER_NAME = 'nl80211' 183 184 185 @staticmethod 186 def get_channel_for_frequency(frequency): 187 """Returns the channel number associated with a given frequency. 188 189 @param value: int frequency in MHz. 190 191 @return int frequency associated with the channel. 192 193 """ 194 return HostapConfig.CHANNEL_MAP[frequency] 195 196 197 @staticmethod 198 def get_frequency_for_channel(channel): 199 """Returns the frequency associated with a given channel number. 200 201 @param value: int channel number. 202 203 @return int frequency in MHz associated with the channel. 204 205 """ 206 for frequency, channel_iter in HostapConfig.CHANNEL_MAP.iteritems(): 207 if channel == channel_iter: 208 return frequency 209 else: 210 raise error.TestFail('Unknown channel value: %r.' % channel) 211 212 213 @property 214 def _get_default_config(self): 215 """@return dict of default options for hostapd.""" 216 return collections.OrderedDict([ 217 ('hw_mode', 'g'), 218 ('logger_syslog', '-1'), 219 ('logger_syslog_level', '0'), 220 # default RTS and frag threshold to ``off'' 221 ('rts_threshold', '2347'), 222 ('fragm_threshold', '2346'), 223 ('driver', self.DRIVER_NAME)]) 224 225 226 @property 227 def _ht40_plus_allowed(self): 228 """@return True iff HT40+ is enabled for this configuration.""" 229 channel_supported = (self.channel in 230 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS]) 231 return ((self.N_CAPABILITY_HT40_PLUS in self._n_capabilities or 232 self.N_CAPABILITY_HT40 in self._n_capabilities) and 233 channel_supported) 234 235 236 @property 237 def _ht40_minus_allowed(self): 238 """@return True iff HT40- is enabled for this configuration.""" 239 channel_supported = (self.channel in 240 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS]) 241 return ((self.N_CAPABILITY_HT40_MINUS in self._n_capabilities or 242 self.N_CAPABILITY_HT40 in self._n_capabilities) and 243 channel_supported) 244 245 246 @property 247 def _hostapd_ht_capabilities(self): 248 """@return string suitable for the ht_capab= line in a hostapd config""" 249 ret = [] 250 if self._ht40_plus_allowed: 251 ret.append('[HT40+]') 252 elif self._ht40_minus_allowed: 253 ret.append('[HT40-]') 254 if self.N_CAPABILITY_GREENFIELD in self._n_capabilities: 255 logging.warning('Greenfield flag is ignored for hostap...') 256 if self.N_CAPABILITY_SGI20 in self._n_capabilities: 257 ret.append('[SHORT-GI-20]') 258 if self.N_CAPABILITY_SGI40 in self._n_capabilities: 259 ret.append('[SHORT-GI-40]') 260 return ''.join(ret) 261 262 263 @property 264 def _hostapd_vht_capabilities(self): 265 """@return string suitable for the vht_capab= line in a hostapd config. 266 """ 267 ret = [] 268 for cap in self.AC_CAPABILITIES_MAPPING.keys(): 269 if cap in self._ac_capabilities: 270 ret.append(self.AC_CAPABILITIES_MAPPING[cap]) 271 return ''.join(ret) 272 273 274 @property 275 def _require_ht(self): 276 """@return True iff clients should be required to support HT.""" 277 # TODO(wiley) Why? (crbug.com/237370) 278 logging.warning('Not enforcing pure N mode because Snow does ' 279 'not seem to support it...') 280 return False 281 282 283 @property 284 def _require_vht(self): 285 """@return True iff clients should be required to support VHT.""" 286 return self._mode == self.MODE_11AC_PURE 287 288 289 @property 290 def _hw_mode(self): 291 """@return string hardware mode understood by hostapd.""" 292 if self._mode == self.MODE_11A: 293 return self.MODE_11A 294 if self._mode == self.MODE_11B: 295 return self.MODE_11B 296 if self._mode == self.MODE_11G: 297 return self.MODE_11G 298 if self._is_11n or self.is_11ac: 299 # For their own historical reasons, hostapd wants it this way. 300 if self._frequency > 5000: 301 return self.MODE_11A 302 303 return self.MODE_11G 304 305 raise error.TestFail('Invalid mode.') 306 307 308 @property 309 def _is_11n(self): 310 """@return True iff we're trying to host an 802.11n network.""" 311 return self._mode in (self.MODE_11N_MIXED, self.MODE_11N_PURE) 312 313 314 @property 315 def is_11ac(self): 316 """@return True iff we're trying to host an 802.11ac network.""" 317 return self._mode in (self.MODE_11AC_MIXED, self.MODE_11AC_PURE) 318 319 320 @property 321 def channel(self): 322 """@return int channel number for self.frequency.""" 323 return self.get_channel_for_frequency(self.frequency) 324 325 326 @channel.setter 327 def channel(self, value): 328 """Sets the channel number to configure hostapd to listen on. 329 330 @param value: int channel number. 331 332 """ 333 self.frequency = self.get_frequency_for_channel(value) 334 335 336 @property 337 def frequency(self): 338 """@return int frequency for hostapd to listen on.""" 339 return self._frequency 340 341 342 @frequency.setter 343 def frequency(self, value): 344 """Sets the frequency for hostapd to listen on. 345 346 @param value: int frequency in MHz. 347 348 """ 349 if value not in self.CHANNEL_MAP or not self.supports_frequency(value): 350 raise error.TestFail('Tried to set an invalid frequency: %r.' % 351 value) 352 353 self._frequency = value 354 355 356 @property 357 def ssid(self): 358 """@return string SSID.""" 359 return self._ssid 360 361 362 @ssid.setter 363 def ssid(self, value): 364 """Sets the ssid for the hostapd. 365 366 @param value: string ssid name. 367 368 """ 369 self._ssid = value 370 371 372 @property 373 def ht_packet_capture_mode(self): 374 """Get an appropriate packet capture HT parameter. 375 376 When we go to configure a raw monitor we need to configure 377 the phy to listen on the correct channel. Part of doing 378 so is to specify the channel width for HT channels. In the 379 case that the AP is configured to be either HT40+ or HT40-, 380 we could return the wrong parameter because we don't know which 381 configuration will be chosen by hostap. 382 383 @return string HT parameter for frequency configuration. 384 385 """ 386 if not self._is_11n: 387 return None 388 389 if self._ht40_plus_allowed: 390 return 'HT40+' 391 392 if self._ht40_minus_allowed: 393 return 'HT40-' 394 395 return 'HT20' 396 397 398 @property 399 def perf_loggable_description(self): 400 """@return string test description suitable for performance logging.""" 401 mode = 'mode%s' % ( 402 self.printable_mode.replace('+', 'p').replace('-', 'm')) 403 channel = 'ch%03d' % self.channel 404 return '_'.join([channel, mode, self._security_config.security]) 405 406 407 @property 408 def printable_mode(self): 409 """@return human readable mode string.""" 410 if self._is_11n: 411 return self.ht_packet_capture_mode 412 413 return '11' + self._hw_mode.upper() 414 415 416 @property 417 def ssid_suffix(self): 418 """@return meaningful suffix for SSID.""" 419 return 'ch%d' % self.channel 420 421 422 @property 423 def security_config(self): 424 """@return SecurityConfig security config object""" 425 return self._security_config 426 427 428 @property 429 def hide_ssid(self): 430 """@return bool _hide_ssid flag.""" 431 return self._hide_ssid 432 433 434 @property 435 def beacon_footer(self): 436 """@return bool _beacon_footer value.""" 437 return self._beacon_footer 438 439 440 @property 441 def scenario_name(self): 442 """@return string _scenario_name value, or None.""" 443 return self._scenario_name 444 445 446 @property 447 def min_streams(self): 448 """@return int _min_streams value, or None.""" 449 return self._min_streams 450 451 452 @property 453 def frag_threshold(self): 454 """@return int frag threshold value, or None.""" 455 return self._frag_threshold 456 457 458 def __init__(self, mode=MODE_11B, channel=None, frequency=None, 459 n_capabilities=[], hide_ssid=None, beacon_interval=None, 460 dtim_period=None, frag_threshold=None, ssid=None, bssid=None, 461 force_wmm=None, security_config=None, 462 pmf_support=PMF_SUPPORT_DISABLED, 463 obss_interval=None, 464 vht_channel_width=None, 465 vht_center_channel=None, 466 ac_capabilities=[], 467 beacon_footer='', 468 spectrum_mgmt_required=None, 469 scenario_name=None, 470 min_streams=None): 471 """Construct a HostapConfig. 472 473 You may specify channel or frequency, but not both. Both options 474 are checked for validity (i.e. you can't specify an invalid channel 475 or a frequency that will not be accepted). 476 477 @param mode string MODE_11x defined above. 478 @param channel int channel number. 479 @param frequency int frequency of channel. 480 @param n_capabilities list of N_CAPABILITY_x defined above. 481 @param hide_ssid True if we should set up a hidden SSID. 482 @param beacon_interval int beacon interval of AP. 483 @param dtim_period int include a DTIM every |dtim_period| beacons. 484 @param frag_threshold int maximum outgoing data frame size. 485 @param ssid string up to 32 byte SSID overriding the router default. 486 @param bssid string like 00:11:22:33:44:55. 487 @param force_wmm True if we should force WMM on, False if we should 488 force it off, None if we shouldn't force anything. 489 @param security_config SecurityConfig object. 490 @param pmf_support one of PMF_SUPPORT_* above. Controls whether the 491 client supports/must support 802.11w. 492 @param obss_interval int interval in seconds that client should be 493 required to do background scans for overlapping BSSes. 494 @param vht_channel_width object channel width 495 @param vht_center_channel int center channel of segment 0. 496 @param ac_capabilities list of AC_CAPABILITY_x defined above. 497 @param beacon_footer string containing (unvalidated) IE data to be 498 placed at the end of the beacon. 499 @param spectrum_mgmt_required True if we require the DUT to support 500 spectrum management. 501 @param scenario_name string to be included in file names, instead 502 of the interface name. 503 @param min_streams int number of spatial streams required. 504 505 """ 506 super(HostapConfig, self).__init__() 507 if channel is not None and frequency is not None: 508 raise error.TestError('Specify either frequency or channel ' 509 'but not both.') 510 511 self._wmm_enabled = False 512 unknown_caps = [cap for cap in n_capabilities 513 if cap not in self.ALL_N_CAPABILITIES] 514 if unknown_caps: 515 raise error.TestError('Unknown capabilities: %r' % unknown_caps) 516 517 self._n_capabilities = set(n_capabilities) 518 if self._n_capabilities: 519 self._wmm_enabled = True 520 if self._n_capabilities and mode is None: 521 mode = self.MODE_11N_PURE 522 self._mode = mode 523 524 self._frequency = None 525 if channel: 526 self.channel = channel 527 elif frequency: 528 self.frequency = frequency 529 else: 530 raise error.TestError('Specify either frequency or channel.') 531 532 if not self.supports_frequency(self.frequency): 533 raise error.TestFail('Configured a mode %s that does not support ' 534 'frequency %d' % (self._mode, self.frequency)) 535 536 self._hide_ssid = hide_ssid 537 self._beacon_interval = beacon_interval 538 self._dtim_period = dtim_period 539 self._frag_threshold = frag_threshold 540 if ssid and len(ssid) > 32: 541 raise error.TestFail('Tried to specify SSID that was too long.') 542 543 self._ssid = ssid 544 self._bssid = bssid 545 if force_wmm is not None: 546 self._wmm_enabled = force_wmm 547 if pmf_support not in self.PMF_SUPPORT_VALUES: 548 raise error.TestFail('Invalid value for pmf_support: %r' % 549 pmf_support) 550 551 self._pmf_support = pmf_support 552 self._security_config = (copy.copy(security_config) or 553 xmlrpc_security_types.SecurityConfig()) 554 self._obss_interval = obss_interval 555 if vht_channel_width == self.VHT_CHANNEL_WIDTH_40: 556 self._vht_oper_chwidth = 0 557 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80: 558 self._vht_oper_chwidth = 1 559 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_160: 560 self._vht_oper_chwidth = 2 561 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80_80: 562 self._vht_oper_chwidth = 3 563 elif vht_channel_width is not None: 564 raise error.TestFail('Invalid channel width') 565 # TODO(zqiu) Add checking for center channel based on the channel width 566 # and operating channel. 567 self._vht_oper_centr_freq_seg0_idx = vht_center_channel 568 self._ac_capabilities = set(ac_capabilities) 569 self._beacon_footer = beacon_footer 570 self._spectrum_mgmt_required = spectrum_mgmt_required 571 self._scenario_name = scenario_name 572 self._min_streams = min_streams 573 574 575 def __repr__(self): 576 return ('%s(mode=%r, channel=%r, frequency=%r, ' 577 'n_capabilities=%r, hide_ssid=%r, beacon_interval=%r, ' 578 'dtim_period=%r, frag_threshold=%r, ssid=%r, bssid=%r, ' 579 'wmm_enabled=%r, security_config=%r, ' 580 'spectrum_mgmt_required=%r)' % ( 581 self.__class__.__name__, 582 self._mode, 583 self.channel, 584 self.frequency, 585 self._n_capabilities, 586 self._hide_ssid, 587 self._beacon_interval, 588 self._dtim_period, 589 self._frag_threshold, 590 self._ssid, 591 self._bssid, 592 self._wmm_enabled, 593 self._security_config, 594 self._spectrum_mgmt_required)) 595 596 597 def supports_channel(self, value): 598 """Check whether channel is supported by the current hardware mode. 599 600 @param value: int channel to check. 601 @return True iff the current mode supports the band of the channel. 602 603 """ 604 for freq, channel in self.CHANNEL_MAP.iteritems(): 605 if channel == value: 606 return self.supports_frequency(freq) 607 608 return False 609 610 611 def supports_frequency(self, frequency): 612 """Check whether frequency is supported by the current hardware mode. 613 614 @param frequency: int frequency to check. 615 @return True iff the current mode supports the band of the frequency. 616 617 """ 618 if self._mode == self.MODE_11A and frequency < 5000: 619 return False 620 621 if self._mode in (self.MODE_11B, self.MODE_11G) and frequency > 5000: 622 return False 623 624 if frequency not in self.CHANNEL_MAP: 625 return False 626 627 channel = self.CHANNEL_MAP[frequency] 628 supports_plus = (channel in 629 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS]) 630 supports_minus = (channel in 631 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS]) 632 if (self.N_CAPABILITY_HT40_PLUS in self._n_capabilities and 633 not supports_plus): 634 return False 635 636 if (self.N_CAPABILITY_HT40_MINUS in self._n_capabilities and 637 not supports_minus): 638 return False 639 640 if (self.N_CAPABILITY_HT40 in self._n_capabilities and 641 not supports_plus and not supports_minus): 642 return False 643 644 return True 645 646 647 def generate_dict(self, interface, control_interface, ssid): 648 """Generate config dictionary. 649 650 Generate config dictionary for the given |interface|. 651 652 @param interface: string interface to generate config dict for. 653 @param control_interface: string control interface 654 @param ssid: string SSID of the AP. 655 @return dict of hostap configurations. 656 657 """ 658 # Start with the default config parameters. 659 conf = self._get_default_config 660 conf['ssid'] = (self._ssid or ssid) 661 if self._bssid: 662 conf['bssid'] = self._bssid 663 conf['channel'] = self.channel 664 conf['hw_mode'] = self._hw_mode 665 if self._hide_ssid: 666 conf['ignore_broadcast_ssid'] = 1 667 if self._is_11n or self.is_11ac: 668 conf['ieee80211n'] = 1 669 conf['ht_capab'] = self._hostapd_ht_capabilities 670 if self.is_11ac: 671 conf['ieee80211ac'] = 1 672 conf['vht_oper_chwidth'] = self._vht_oper_chwidth 673 conf['vht_oper_centr_freq_seg0_idx'] = \ 674 self._vht_oper_centr_freq_seg0_idx 675 conf['vht_capab'] = self._hostapd_vht_capabilities 676 if self._wmm_enabled: 677 conf['wmm_enabled'] = 1 678 if self._require_ht: 679 conf['require_ht'] = 1 680 if self._require_vht: 681 conf['require_vht'] = 1 682 if self._beacon_interval: 683 conf['beacon_int'] = self._beacon_interval 684 if self._dtim_period: 685 conf['dtim_period'] = self._dtim_period 686 if self._frag_threshold: 687 conf['fragm_threshold'] = self._frag_threshold 688 if self._pmf_support: 689 conf['ieee80211w'] = self._pmf_support 690 if self._obss_interval: 691 conf['obss_interval'] = self._obss_interval 692 conf['interface'] = interface 693 conf['ctrl_interface'] = control_interface 694 if self._spectrum_mgmt_required: 695 # To set spectrum_mgmt_required, we must first set 696 # local_pwr_constraint. And to set local_pwr_constraint, 697 # we must first set ieee80211d. And to set ieee80211d, ... 698 # Point being: order matters here. 699 conf['country_code'] = 'US' # Required for local_pwr_constraint 700 conf['ieee80211d'] = 1 # Required for local_pwr_constraint 701 conf['local_pwr_constraint'] = 0 # No local constraint 702 conf['spectrum_mgmt_required'] = 1 # Requires local_pwr_constraint 703 conf.update(self._security_config.get_hostapd_config()) 704 return conf 705