1#!/usr/bin/env python3 2# 3# Copyright 2019 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import itertools 18import re 19 20from acts import asserts 21from acts import utils 22from acts.controllers.access_point import setup_ap 23from acts.controllers.ap_lib import hostapd_constants 24from acts.controllers.ap_lib import hostapd_config 25from acts.controllers.ap_lib.hostapd_security import Security 26from acts.controllers.ap_lib.hostapd_utils import generate_random_password 27from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device 28from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest 29from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest 30 31FREQUENCY_24 = ['2.4GHz'] 32FREQUENCY_5 = ['5GHz'] 33CHANNEL_BANDWIDTH_20 = ['HT20'] 34CHANNEL_BANDWIDTH_40_LOWER = ['HT40-'] 35CHANNEL_BANDWIDTH_40_UPPER = ['HT40+'] 36SECURITY_OPEN = 'open' 37SECURITY_WPA2 = 'wpa2' 38LDPC = [hostapd_constants.N_CAPABILITY_LDPC, ''] 39TX_STBC = [hostapd_constants.N_CAPABILITY_TX_STBC, ''] 40RX_STBC = [hostapd_constants.N_CAPABILITY_RX_STBC1, ''] 41SGI_20 = [hostapd_constants.N_CAPABILITY_SGI20, ''] 42SGI_40 = [hostapd_constants.N_CAPABILITY_SGI40, ''] 43DSSS_CCK = [hostapd_constants.N_CAPABILITY_DSSS_CCK_40, ''] 44INTOLERANT_40 = [hostapd_constants.N_CAPABILITY_40_INTOLERANT, ''] 45MAX_AMPDU_7935 = [hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935, ''] 46SMPS = [hostapd_constants.N_CAPABILITY_SMPS_STATIC, ''] 47 48 49def generate_test_name(settings): 50 """Generates a string based on the n_capabilities for a test case 51 52 Args: 53 settings: A dictionary of hostapd constant n_capabilities. 54 55 Returns: 56 A string that represents a test case name. 57 """ 58 ret = [] 59 for cap in hostapd_constants.N_CAPABILITIES_MAPPING.keys(): 60 if cap in settings['n_capabilities']: 61 ret.append(hostapd_constants.N_CAPABILITIES_MAPPING[cap]) 62 return '%s_%s_%s_%s' % (settings['frequency'], settings['chbw'], 63 settings['security'], ''.join(ret)) 64 65 66class WlanPhyCompliance11NTest(AbstractDeviceWlanDeviceBaseTest): 67 """Tests for validating 11n PHYS. 68 69 Test Bed Requirement: 70 * One Android device or Fuchsia device 71 * One Access Point 72 """ 73 def __init__(self, controllers): 74 WifiBaseTest.__init__(self, controllers) 75 self.tests = [ 76 'test_11n_capabilities_24_HT20', 77 'test_11n_capabilities_24_HT40_lower', 78 'test_11n_capabilities_24_HT40_upper', 79 'test_11n_capabilities_5_HT20', 80 'test_11n_capabilities_5_HT40_lower', 81 'test_11n_capabilities_5_HT40_upper', 82 'test_11n_capabilities_24_HT20_wpa2', 83 'test_11n_capabilities_24_HT40_lower_wpa2', 84 'test_11n_capabilities_24_HT40_upper_wpa2', 85 'test_11n_capabilities_5_HT20_wpa2', 86 'test_11n_capabilities_5_HT40_lower_wpa2', 87 'test_11n_capabilities_5_HT40_upper_wpa2' 88 ] 89 if 'debug_11n_tests' in self.user_params: 90 self.tests.append('test_11n_capabilities_debug') 91 92 def setup_class(self): 93 super().setup_class() 94 if 'dut' in self.user_params: 95 if self.user_params['dut'] == 'fuchsia_devices': 96 self.dut = create_wlan_device(self.fuchsia_devices[0]) 97 elif self.user_params['dut'] == 'android_devices': 98 self.dut = create_wlan_device(self.android_devices[0]) 99 else: 100 raise ValueError('Invalid DUT specified in config. (%s)' % 101 self.user_params['dut']) 102 else: 103 # Default is an android device, just like the other tests 104 self.dut = create_wlan_device(self.android_devices[0]) 105 106 self.access_point = self.access_points[0] 107 self.access_point.stop_all_aps() 108 109 def setup_test(self): 110 if hasattr(self, "android_devices"): 111 for ad in self.android_devices: 112 ad.droid.wakeLockAcquireBright() 113 ad.droid.wakeUpNow() 114 self.dut.wifi_toggle_state(True) 115 116 def teardown_test(self): 117 if hasattr(self, "android_devices"): 118 for ad in self.android_devices: 119 ad.droid.wakeLockRelease() 120 ad.droid.goToSleepNow() 121 self.dut.turn_location_off_and_scan_toggle_off() 122 self.dut.disconnect() 123 self.dut.reset_wifi() 124 self.access_point.stop_all_aps() 125 126 def on_fail(self, test_name, begin_time): 127 super().on_fail(test_name, begin_time) 128 self.access_point.stop_all_aps() 129 130 def setup_and_connect(self, ap_settings): 131 """Generates a hostapd config, setups up the AP with that config, then 132 attempts to associate a DUT 133 134 Args: 135 ap_settings: A dictionary of hostapd constant n_capabilities. 136 """ 137 ssid = utils.rand_ascii_str(20) 138 security_profile = None 139 password = None 140 temp_n_capabilities = list(ap_settings['n_capabilities']) 141 n_capabilities = [] 142 for n_capability in temp_n_capabilities: 143 if n_capability in hostapd_constants.N_CAPABILITIES_MAPPING.keys(): 144 n_capabilities.append(n_capability) 145 146 if ap_settings['chbw'] == 'HT20' or ap_settings['chbw'] == 'HT40+': 147 if ap_settings['frequency'] == '2.4GHz': 148 channel = 1 149 elif ap_settings['frequency'] == '5GHz': 150 channel = 36 151 else: 152 raise ValueError('Invalid frequence: %s' % 153 ap_settings['frequency']) 154 155 elif ap_settings['chbw'] == 'HT40-': 156 if ap_settings['frequency'] == '2.4GHz': 157 channel = 11 158 elif ap_settings['frequency'] == '5GHz': 159 channel = 60 160 else: 161 raise ValueError('Invalid frequency: %s' % 162 ap_settings['frequency']) 163 164 else: 165 raise ValueError('Invalid channel bandwidth: %s' % 166 ap_settings['chbw']) 167 168 if ap_settings['chbw'] == 'HT40-' or ap_settings['chbw'] == 'HT40+': 169 if hostapd_config.ht40_plus_allowed(channel): 170 extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS 171 elif hostapd_config.ht40_minus_allowed(channel): 172 extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS 173 else: 174 raise ValueError('Invalid channel: %s' % channel) 175 n_capabilities.append(extended_channel) 176 177 if ap_settings['security'] == 'wpa2': 178 security_profile = Security( 179 security_mode=SECURITY_WPA2, 180 password=generate_random_password(length=20), 181 wpa_cipher='CCMP', 182 wpa2_cipher='CCMP') 183 password = security_profile.password 184 target_security = hostapd_constants.SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get( 185 ap_settings['security'], None) 186 setup_ap(access_point=self.access_point, 187 profile_name='whirlwind', 188 mode=hostapd_constants.MODE_11N_MIXED, 189 channel=channel, 190 n_capabilities=n_capabilities, 191 ac_capabilities=[], 192 force_wmm=True, 193 ssid=ssid, 194 security=security_profile, 195 password=password) 196 asserts.assert_true( 197 self.dut.associate(ssid, 198 target_pwd=password, 199 target_security=target_security), 200 'Failed to connect.') 201 202 def test_11n_capabilities_24_HT20(self): 203 test_list = [] 204 for combination in itertools.product(FREQUENCY_24, 205 CHANNEL_BANDWIDTH_20, LDPC, 206 TX_STBC, RX_STBC, SGI_20, 207 INTOLERANT_40, MAX_AMPDU_7935, 208 SMPS): 209 test_frequency = combination[0] 210 test_chbw = combination[1] 211 n_capabilities = combination[2:] 212 test_list.append({ 213 'frequency': test_frequency, 214 'chbw': test_chbw, 215 'security': SECURITY_OPEN, 216 'n_capabilities': n_capabilities 217 }) 218 self.run_generated_testcases(self.setup_and_connect, 219 settings=test_list, 220 name_func=generate_test_name) 221 222 def test_11n_capabilities_24_HT40_lower(self): 223 test_list = [] 224 for combination in itertools.product(FREQUENCY_24, 225 CHANNEL_BANDWIDTH_40_LOWER, LDPC, 226 TX_STBC, RX_STBC, SGI_20, SGI_40, 227 MAX_AMPDU_7935, SMPS, DSSS_CCK): 228 test_frequency = combination[0] 229 test_chbw = combination[1] 230 n_capabilities = combination[2:] 231 test_list.append({ 232 'frequency': test_frequency, 233 'chbw': test_chbw, 234 'security': SECURITY_OPEN, 235 'n_capabilities': n_capabilities 236 }) 237 self.run_generated_testcases(self.setup_and_connect, 238 settings=test_list, 239 name_func=generate_test_name) 240 241 def test_11n_capabilities_24_HT40_upper(self): 242 test_list = [] 243 for combination in itertools.product(FREQUENCY_24, 244 CHANNEL_BANDWIDTH_40_UPPER, LDPC, 245 TX_STBC, RX_STBC, SGI_20, SGI_40, 246 MAX_AMPDU_7935, SMPS, DSSS_CCK): 247 test_frequency = combination[0] 248 test_chbw = combination[1] 249 n_capabilities = combination[2:] 250 test_list.append({ 251 'frequency': test_frequency, 252 'chbw': test_chbw, 253 'security': SECURITY_OPEN, 254 'n_capabilities': n_capabilities 255 }) 256 self.run_generated_testcases(self.setup_and_connect, 257 settings=test_list, 258 name_func=generate_test_name) 259 260 def test_11n_capabilities_5_HT20(self): 261 test_list = [] 262 for combination in itertools.product(FREQUENCY_5, CHANNEL_BANDWIDTH_20, 263 LDPC, TX_STBC, RX_STBC, SGI_20, 264 INTOLERANT_40, MAX_AMPDU_7935, 265 SMPS): 266 test_frequency = combination[0] 267 test_chbw = combination[1] 268 n_capabilities = combination[2:] 269 test_list.append({ 270 'frequency': test_frequency, 271 'chbw': test_chbw, 272 'security': SECURITY_OPEN, 273 'n_capabilities': n_capabilities 274 }) 275 self.run_generated_testcases(self.setup_and_connect, 276 settings=test_list, 277 name_func=generate_test_name) 278 279 def test_11n_capabilities_5_HT40_lower(self): 280 test_list = [] 281 for combination in itertools.product(FREQUENCY_5, 282 CHANNEL_BANDWIDTH_40_LOWER, LDPC, 283 TX_STBC, RX_STBC, SGI_20, SGI_40, 284 MAX_AMPDU_7935, SMPS, DSSS_CCK): 285 test_frequency = combination[0] 286 test_chbw = combination[1] 287 n_capabilities = combination[2:] 288 test_list.append({ 289 'frequency': test_frequency, 290 'chbw': test_chbw, 291 'security': SECURITY_OPEN, 292 'n_capabilities': n_capabilities 293 }) 294 self.run_generated_testcases(self.setup_and_connect, 295 settings=test_list, 296 name_func=generate_test_name) 297 298 def test_11n_capabilities_5_HT40_upper(self): 299 test_list = [] 300 for combination in itertools.product(FREQUENCY_5, 301 CHANNEL_BANDWIDTH_40_UPPER, LDPC, 302 TX_STBC, RX_STBC, SGI_20, SGI_40, 303 MAX_AMPDU_7935, SMPS, DSSS_CCK): 304 test_frequency = combination[0] 305 test_chbw = combination[1] 306 n_capabilities = combination[2:] 307 test_list.append({ 308 'frequency': test_frequency, 309 'chbw': test_chbw, 310 'security': SECURITY_OPEN, 311 'n_capabilities': n_capabilities 312 }) 313 self.run_generated_testcases(self.setup_and_connect, 314 settings=test_list, 315 name_func=generate_test_name) 316 317 def test_11n_capabilities_24_HT20_wpa2(self): 318 test_list = [] 319 for combination in itertools.product(FREQUENCY_24, 320 CHANNEL_BANDWIDTH_20, LDPC, 321 TX_STBC, RX_STBC, SGI_20, 322 INTOLERANT_40, MAX_AMPDU_7935, 323 SMPS): 324 test_frequency = combination[0] 325 test_chbw = combination[1] 326 n_capabilities = combination[2:] 327 test_list.append({ 328 'frequency': test_frequency, 329 'chbw': test_chbw, 330 'security': SECURITY_WPA2, 331 'n_capabilities': n_capabilities 332 }) 333 self.run_generated_testcases(self.setup_and_connect, 334 settings=test_list, 335 name_func=generate_test_name) 336 337 def test_11n_capabilities_24_HT40_lower_wpa2(self): 338 test_list = [] 339 for combination in itertools.product(FREQUENCY_24, 340 CHANNEL_BANDWIDTH_40_LOWER, LDPC, 341 TX_STBC, RX_STBC, SGI_20, SGI_40, 342 MAX_AMPDU_7935, SMPS, DSSS_CCK): 343 test_frequency = combination[0] 344 test_chbw = combination[1] 345 n_capabilities = combination[2:] 346 test_list.append({ 347 'frequency': test_frequency, 348 'chbw': test_chbw, 349 'security': SECURITY_WPA2, 350 'n_capabilities': n_capabilities 351 }) 352 self.run_generated_testcases(self.setup_and_connect, 353 settings=test_list, 354 name_func=generate_test_name) 355 356 def test_11n_capabilities_24_HT40_upper_wpa2(self): 357 test_list = [] 358 for combination in itertools.product(FREQUENCY_24, 359 CHANNEL_BANDWIDTH_40_UPPER, LDPC, 360 TX_STBC, RX_STBC, SGI_20, SGI_40, 361 MAX_AMPDU_7935, SMPS, DSSS_CCK): 362 test_frequency = combination[0] 363 test_chbw = combination[1] 364 n_capabilities = combination[2:] 365 test_list.append({ 366 'frequency': test_frequency, 367 'chbw': test_chbw, 368 'security': SECURITY_WPA2, 369 'n_capabilities': n_capabilities 370 }) 371 self.run_generated_testcases(self.setup_and_connect, 372 settings=test_list, 373 name_func=generate_test_name) 374 375 def test_11n_capabilities_5_HT20_wpa2(self): 376 test_list = [] 377 for combination in itertools.product(FREQUENCY_5, CHANNEL_BANDWIDTH_20, 378 LDPC, TX_STBC, RX_STBC, SGI_20, 379 INTOLERANT_40, MAX_AMPDU_7935, 380 SMPS): 381 test_frequency = combination[0] 382 test_chbw = combination[1] 383 n_capabilities = combination[2:] 384 test_list.append({ 385 'frequency': test_frequency, 386 'chbw': test_chbw, 387 'security': SECURITY_WPA2, 388 'n_capabilities': n_capabilities 389 }) 390 self.run_generated_testcases(self.setup_and_connect, 391 settings=test_list, 392 name_func=generate_test_name) 393 394 def test_11n_capabilities_5_HT40_lower_wpa2(self): 395 test_list = [] 396 for combination in itertools.product(FREQUENCY_5, 397 CHANNEL_BANDWIDTH_40_LOWER, LDPC, 398 TX_STBC, RX_STBC, SGI_20, SGI_40, 399 MAX_AMPDU_7935, SMPS, DSSS_CCK): 400 test_frequency = combination[0] 401 test_chbw = combination[1] 402 n_capabilities = combination[2:] 403 test_list.append({ 404 'frequency': test_frequency, 405 'chbw': test_chbw, 406 'security': SECURITY_WPA2, 407 'n_capabilities': n_capabilities 408 }) 409 self.run_generated_testcases(self.setup_and_connect, 410 settings=test_list, 411 name_func=generate_test_name) 412 413 def test_11n_capabilities_5_HT40_upper_wpa2(self): 414 test_list = [] 415 for combination in itertools.product(FREQUENCY_5, 416 CHANNEL_BANDWIDTH_40_UPPER, LDPC, 417 TX_STBC, RX_STBC, SGI_20, SGI_40, 418 MAX_AMPDU_7935, SMPS, DSSS_CCK): 419 test_frequency = combination[0] 420 test_chbw = combination[1] 421 n_capabilities = combination[2:] 422 test_list.append({ 423 'frequency': test_frequency, 424 'chbw': test_chbw, 425 'security': SECURITY_WPA2, 426 'n_capabilities': n_capabilities 427 }) 428 self.run_generated_testcases(self.setup_and_connect, 429 settings=test_list, 430 name_func=generate_test_name) 431 432 def test_11n_capabilities_debug(self): 433 allowed_frequencies = FREQUENCY_5 + FREQUENCY_24 434 allowed_chbw = (CHANNEL_BANDWIDTH_20 + CHANNEL_BANDWIDTH_40_LOWER + 435 CHANNEL_BANDWIDTH_40_UPPER) 436 allowed_security = [SECURITY_WPA2, SECURITY_OPEN] 437 freq_chbw_sec = re.compile(r'(.*)_(.*)_(.*)_(\[.*\])?$') 438 for test_title in self.user_params['debug_11n_tests']: 439 test_list = [] 440 test_to_run = re.match(freq_chbw_sec, test_title) 441 if test_to_run: 442 test_frequency = test_to_run.group(1) 443 test_chbw = test_to_run.group(2) 444 security = test_to_run.group(3) 445 if (test_frequency in allowed_frequencies 446 and test_chbw in allowed_chbw 447 and security in allowed_security): 448 if test_to_run.group(4): 449 n_capabilities_str = test_to_run.group(4) 450 else: 451 n_capabilities_str = '' 452 n_capabilities_list = [] 453 if '[LDPC]' in n_capabilities_str: 454 n_capabilities_list.append( 455 hostapd_constants.N_CAPABILITY_LDPC) 456 if '[TX-STBC]' in n_capabilities_str: 457 n_capabilities_list.append( 458 hostapd_constants.N_CAPABILITY_TX_STBC) 459 if '[RX-STBC1]' in n_capabilities_str: 460 n_capabilities_list.append( 461 hostapd_constants.N_CAPABILITY_RX_STBC1) 462 if '[SHORT-GI-20]' in n_capabilities_str: 463 n_capabilities_list.append( 464 hostapd_constants.N_CAPABILITY_SGI20) 465 if '[SHORT-GI-40]' in n_capabilities_str: 466 n_capabilities_list.append( 467 hostapd_constants.N_CAPABILITY_SGI40) 468 if '[DSSS_CCK-40]' in n_capabilities_str: 469 n_capabilities_list.append( 470 hostapd_constants.N_CAPABILITY_DSSS_CCK_40) 471 if '[40-INTOLERANT]' in n_capabilities_str: 472 n_capabilities_list.append( 473 hostapd_constants.N_CAPABILITY_40_INTOLERANT) 474 if '[MAX-AMSDU-7935]' in n_capabilities_str: 475 n_capabilities_list.append( 476 hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935) 477 if '[SMPS-STATIC]' in n_capabilities_str: 478 n_capabilities_list.append( 479 hostapd_constants.N_CAPABILITY_SMPS_STATIC) 480 n_capabilities = tuple(n_capabilities_list) 481 test_list.append({ 482 'frequency': test_frequency, 483 'chbw': test_chbw, 484 'security': security, 485 'n_capabilities': n_capabilities 486 }) 487 self.run_generated_testcases(self.setup_and_connect, 488 settings=test_list, 489 name_func=generate_test_name) 490 else: 491 self.log.error('Invalid test (%s). Trying the next one.' % 492 test_title) 493 else: 494 self.log.error('Invalid test (%s). Trying the next one.' % 495 test_title) 496