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