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 def __init__(self, mode=MODE_11B, channel=None, frequency=None, 453 n_capabilities=[], hide_ssid=None, beacon_interval=None, 454 dtim_period=None, frag_threshold=None, ssid=None, bssid=None, 455 force_wmm=None, security_config=None, 456 pmf_support=PMF_SUPPORT_DISABLED, 457 obss_interval=None, 458 vht_channel_width=None, 459 vht_center_channel=None, 460 ac_capabilities=[], 461 beacon_footer='', 462 spectrum_mgmt_required=None, 463 scenario_name=None, 464 min_streams=None): 465 """Construct a HostapConfig. 466 467 You may specify channel or frequency, but not both. Both options 468 are checked for validity (i.e. you can't specify an invalid channel 469 or a frequency that will not be accepted). 470 471 @param mode string MODE_11x defined above. 472 @param channel int channel number. 473 @param frequency int frequency of channel. 474 @param n_capabilities list of N_CAPABILITY_x defined above. 475 @param hide_ssid True if we should set up a hidden SSID. 476 @param beacon_interval int beacon interval of AP. 477 @param dtim_period int include a DTIM every |dtim_period| beacons. 478 @param frag_threshold int maximum outgoing data frame size. 479 @param ssid string up to 32 byte SSID overriding the router default. 480 @param bssid string like 00:11:22:33:44:55. 481 @param force_wmm True if we should force WMM on, False if we should 482 force it off, None if we shouldn't force anything. 483 @param security_config SecurityConfig object. 484 @param pmf_support one of PMF_SUPPORT_* above. Controls whether the 485 client supports/must support 802.11w. 486 @param obss_interval int interval in seconds that client should be 487 required to do background scans for overlapping BSSes. 488 @param vht_channel_width object channel width 489 @param vht_center_channel int center channel of segment 0. 490 @param ac_capabilities list of AC_CAPABILITY_x defined above. 491 @param beacon_footer string containing (unvalidated) IE data to be 492 placed at the end of the beacon. 493 @param spectrum_mgmt_required True if we require the DUT to support 494 spectrum management. 495 @param scenario_name string to be included in file names, instead 496 of the interface name. 497 @param min_streams int number of spatial streams required. 498 499 """ 500 super(HostapConfig, self).__init__() 501 if channel is not None and frequency is not None: 502 raise error.TestError('Specify either frequency or channel ' 503 'but not both.') 504 505 self._wmm_enabled = False 506 unknown_caps = [cap for cap in n_capabilities 507 if cap not in self.ALL_N_CAPABILITIES] 508 if unknown_caps: 509 raise error.TestError('Unknown capabilities: %r' % unknown_caps) 510 511 self._n_capabilities = set(n_capabilities) 512 if self._n_capabilities: 513 self._wmm_enabled = True 514 if self._n_capabilities and mode is None: 515 mode = self.MODE_11N_PURE 516 self._mode = mode 517 518 self._frequency = None 519 if channel: 520 self.channel = channel 521 elif frequency: 522 self.frequency = frequency 523 else: 524 raise error.TestError('Specify either frequency or channel.') 525 526 if not self.supports_frequency(self.frequency): 527 raise error.TestFail('Configured a mode %s that does not support ' 528 'frequency %d' % (self._mode, self.frequency)) 529 530 self._hide_ssid = hide_ssid 531 self._beacon_interval = beacon_interval 532 self._dtim_period = dtim_period 533 self._frag_threshold = frag_threshold 534 if ssid and len(ssid) > 32: 535 raise error.TestFail('Tried to specify SSID that was too long.') 536 537 self._ssid = ssid 538 self._bssid = bssid 539 if force_wmm is not None: 540 self._wmm_enabled = force_wmm 541 if pmf_support not in self.PMF_SUPPORT_VALUES: 542 raise error.TestFail('Invalid value for pmf_support: %r' % 543 pmf_support) 544 545 self._pmf_support = pmf_support 546 self._security_config = (copy.copy(security_config) or 547 xmlrpc_security_types.SecurityConfig()) 548 self._obss_interval = obss_interval 549 if vht_channel_width == self.VHT_CHANNEL_WIDTH_40: 550 self._vht_oper_chwidth = 0 551 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80: 552 self._vht_oper_chwidth = 1 553 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_160: 554 self._vht_oper_chwidth = 2 555 elif vht_channel_width == self.VHT_CHANNEL_WIDTH_80_80: 556 self._vht_oper_chwidth = 3 557 elif vht_channel_width is not None: 558 raise error.TestFail('Invalid channel width') 559 # TODO(zqiu) Add checking for center channel based on the channel width 560 # and operating channel. 561 self._vht_oper_centr_freq_seg0_idx = vht_center_channel 562 self._ac_capabilities = set(ac_capabilities) 563 self._beacon_footer = beacon_footer 564 self._spectrum_mgmt_required = spectrum_mgmt_required 565 self._scenario_name = scenario_name 566 self._min_streams = min_streams 567 568 569 def __repr__(self): 570 return ('%s(mode=%r, channel=%r, frequency=%r, ' 571 'n_capabilities=%r, hide_ssid=%r, beacon_interval=%r, ' 572 'dtim_period=%r, frag_threshold=%r, ssid=%r, bssid=%r, ' 573 'wmm_enabled=%r, security_config=%r, ' 574 'spectrum_mgmt_required=%r)' % ( 575 self.__class__.__name__, 576 self._mode, 577 self.channel, 578 self.frequency, 579 self._n_capabilities, 580 self._hide_ssid, 581 self._beacon_interval, 582 self._dtim_period, 583 self._frag_threshold, 584 self._ssid, 585 self._bssid, 586 self._wmm_enabled, 587 self._security_config, 588 self._spectrum_mgmt_required)) 589 590 591 def supports_channel(self, value): 592 """Check whether channel is supported by the current hardware mode. 593 594 @param value: int channel to check. 595 @return True iff the current mode supports the band of the channel. 596 597 """ 598 for freq, channel in self.CHANNEL_MAP.iteritems(): 599 if channel == value: 600 return self.supports_frequency(freq) 601 602 return False 603 604 605 def supports_frequency(self, frequency): 606 """Check whether frequency is supported by the current hardware mode. 607 608 @param frequency: int frequency to check. 609 @return True iff the current mode supports the band of the frequency. 610 611 """ 612 if self._mode == self.MODE_11A and frequency < 5000: 613 return False 614 615 if self._mode in (self.MODE_11B, self.MODE_11G) and frequency > 5000: 616 return False 617 618 if frequency not in self.CHANNEL_MAP: 619 return False 620 621 channel = self.CHANNEL_MAP[frequency] 622 supports_plus = (channel in 623 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_PLUS]) 624 supports_minus = (channel in 625 self.HT40_ALLOW_MAP[self.N_CAPABILITY_HT40_MINUS]) 626 if (self.N_CAPABILITY_HT40_PLUS in self._n_capabilities and 627 not supports_plus): 628 return False 629 630 if (self.N_CAPABILITY_HT40_MINUS in self._n_capabilities and 631 not supports_minus): 632 return False 633 634 if (self.N_CAPABILITY_HT40 in self._n_capabilities and 635 not supports_plus and not supports_minus): 636 return False 637 638 return True 639 640 641 def generate_dict(self, interface, control_interface, ssid): 642 """Generate config dictionary. 643 644 Generate config dictionary for the given |interface|. 645 646 @param interface: string interface to generate config dict for. 647 @param control_interface: string control interface 648 @param ssid: string SSID of the AP. 649 @return dict of hostap configurations. 650 651 """ 652 # Start with the default config parameters. 653 conf = self._get_default_config 654 conf['ssid'] = (self._ssid or ssid) 655 if self._bssid: 656 conf['bssid'] = self._bssid 657 conf['channel'] = self.channel 658 conf['hw_mode'] = self._hw_mode 659 if self._hide_ssid: 660 conf['ignore_broadcast_ssid'] = 1 661 if self._is_11n or self.is_11ac: 662 conf['ieee80211n'] = 1 663 conf['ht_capab'] = self._hostapd_ht_capabilities 664 if self.is_11ac: 665 conf['ieee80211ac'] = 1 666 conf['vht_oper_chwidth'] = self._vht_oper_chwidth 667 conf['vht_oper_centr_freq_seg0_idx'] = \ 668 self._vht_oper_centr_freq_seg0_idx 669 conf['vht_capab'] = self._hostapd_vht_capabilities 670 if self._wmm_enabled: 671 conf['wmm_enabled'] = 1 672 if self._require_ht: 673 conf['require_ht'] = 1 674 if self._require_vht: 675 conf['require_vht'] = 1 676 if self._beacon_interval: 677 conf['beacon_int'] = self._beacon_interval 678 if self._dtim_period: 679 conf['dtim_period'] = self._dtim_period 680 if self._frag_threshold: 681 conf['fragm_threshold'] = self._frag_threshold 682 if self._pmf_support: 683 conf['ieee80211w'] = self._pmf_support 684 if self._obss_interval: 685 conf['obss_interval'] = self._obss_interval 686 conf['interface'] = interface 687 conf['ctrl_interface'] = control_interface 688 if self._spectrum_mgmt_required: 689 # To set spectrum_mgmt_required, we must first set 690 # local_pwr_constraint. And to set local_pwr_constraint, 691 # we must first set ieee80211d. And to set ieee80211d, ... 692 # Point being: order matters here. 693 conf['country_code'] = 'US' # Required for local_pwr_constraint 694 conf['ieee80211d'] = 1 # Required for local_pwr_constraint 695 conf['local_pwr_constraint'] = 0 # No local constraint 696 conf['spectrum_mgmt_required'] = 1 # Requires local_pwr_constraint 697 conf.update(self._security_config.get_hostapd_config()) 698 return conf 699