blob: 0a5893292a1073ad5a43540817c017911b71de7a [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2022 The Fuchsia Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import itertools
from dataclasses import dataclass
from typing import Any, List, Optional
from mobly import asserts, test_runner
from mobly.records import TestResultRecord
from antlion import utils
from antlion.controllers.access_point import setup_ap
from antlion.controllers.ap_lib import hostapd_config, hostapd_constants
from antlion.controllers.ap_lib.hostapd_security import Security, SecurityMode
from antlion.controllers.ap_lib.hostapd_utils import generate_random_password
from antlion.test_utils.abstract_devices.wlan_device import create_wlan_device
from antlion.test_utils.wifi import base_test
FREQUENCY_24 = ["2.4GHz"]
FREQUENCY_5 = ["5GHz"]
CHANNEL_BANDWIDTH_20 = ["HT20"]
CHANNEL_BANDWIDTH_40_LOWER = ["HT40-"]
CHANNEL_BANDWIDTH_40_UPPER = ["HT40+"]
SECURITY_OPEN = "open"
SECURITY_WPA2 = "wpa2"
N_MODE = [hostapd_constants.MODE_11N_PURE, hostapd_constants.MODE_11N_MIXED]
LDPC = [hostapd_constants.N_CAPABILITY_LDPC, ""]
TX_STBC = [hostapd_constants.N_CAPABILITY_TX_STBC, ""]
RX_STBC = [hostapd_constants.N_CAPABILITY_RX_STBC1, ""]
SGI_20 = [hostapd_constants.N_CAPABILITY_SGI20, ""]
SGI_40 = [hostapd_constants.N_CAPABILITY_SGI40, ""]
DSSS_CCK = [hostapd_constants.N_CAPABILITY_DSSS_CCK_40, ""]
INTOLERANT_40 = [hostapd_constants.N_CAPABILITY_40_INTOLERANT, ""]
MAX_AMPDU_7935 = [hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935, ""]
SMPS = [hostapd_constants.N_CAPABILITY_SMPS_STATIC, ""]
@dataclass
class TestParams:
frequency: str
chbw: str
n_mode: str
security: SecurityMode
# TODO(http://b/290396383): Type AP capabilities as enums
n_capabilities: List[Any]
class WlanPhyCompliance11NTest(base_test.WifiBaseTest):
"""Tests for validating 11n PHYS.
Test Bed Requirement:
* One Android device or Fuchsia device
* One Access Point
"""
def __init__(self, controllers):
super().__init__(controllers)
def setup_generated_tests(self):
test_args: List[TestParams] = (
self._generate_24_HT20_test_args()
+ self._generate_24_HT40_lower_test_args()
+ self._generate_24_HT40_upper_test_args()
+ self._generate_5_HT20_test_args()
+ self._generate_5_HT40_lower_test_args()
+ self._generate_5_HT40_upper_test_args()
+ self._generate_24_HT20_wpa2_test_args()
+ self._generate_24_HT40_lower_wpa2_test_args()
+ self._generate_24_HT40_upper_wpa2_test_args()
+ self._generate_5_HT20_wpa2_test_args()
+ self._generate_5_HT40_lower_wpa2_test_args()
+ self._generate_5_HT40_upper_wpa2_test_args()
)
def generate_test_name(test: TestParams):
ret = []
for cap in hostapd_constants.N_CAPABILITIES_MAPPING.keys():
if cap in test.n_capabilities:
ret.append(hostapd_constants.N_CAPABILITIES_MAPPING[cap])
# '+' is used by Mobile Harness as special character, don't use it in test names
if test.chbw == "HT40-":
chbw = "HT40Lower"
elif test.chbw == "HT40+":
chbw = "HT40Upper"
else:
chbw = test.chbw
return f"test_11n_{test.frequency}_{chbw}_{test.security}_{test.n_mode}_{''.join(ret)}"
self.generate_tests(
test_logic=self.setup_and_connect,
name_func=generate_test_name,
arg_sets=test_args,
)
def setup_class(self):
super().setup_class()
device_type = self.user_params.get("dut", "fuchsia_devices")
if device_type == "fuchsia_devices":
self.dut = create_wlan_device(self.fuchsia_devices[0])
elif device_type == "android_devices":
self.dut = create_wlan_device(self.android_devices[0])
else:
raise ValueError(
f'Invalid "dut" type specified in config: "{device_type}".'
'Expected "fuchsia_devices" or "android_devices".'
)
self.access_point = self.access_points[0]
self.access_point.stop_all_aps()
def setup_test(self):
if hasattr(self, "android_devices"):
for ad in self.android_devices:
ad.droid.wakeLockAcquireBright()
ad.droid.wakeUpNow()
self.dut.wifi_toggle_state(True)
def teardown_test(self):
if hasattr(self, "android_devices"):
for ad in self.android_devices:
ad.droid.wakeLockRelease()
ad.droid.goToSleepNow()
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, record: TestResultRecord):
super().on_fail(record)
self.access_point.stop_all_aps()
def setup_and_connect(self, test: TestParams):
"""Start hostapd and associate the DUT.
Args:
ap_settings: A dictionary of hostapd constant n_capabilities.
"""
ssid = utils.rand_ascii_str(20)
security_profile = Security()
password: Optional[str] = None
n_capabilities = []
for n_capability in test.n_capabilities:
if n_capability in hostapd_constants.N_CAPABILITIES_MAPPING.keys():
n_capabilities.append(n_capability)
if test.chbw == "HT20" or test.chbw == "HT40+":
if test.frequency == "2.4GHz":
channel = 1
elif test.frequency == "5GHz":
channel = 36
else:
raise ValueError(f"Invalid frequence: {test.frequency}")
elif test.chbw == "HT40-":
if test.frequency == "2.4GHz":
channel = 11
elif test.frequency == "5GHz":
channel = 60
else:
raise ValueError(f"Invalid frequency: {test.frequency}")
else:
raise ValueError(f"Invalid channel bandwidth: {test.chbw}")
if test.chbw == "HT40-" or test.chbw == "HT40+":
if hostapd_config.ht40_plus_allowed(channel):
extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS
elif hostapd_config.ht40_minus_allowed(channel):
extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS
else:
raise ValueError(f"Invalid channel: {channel}")
n_capabilities.append(extended_channel)
if test.security is SecurityMode.WPA2:
security_profile = Security(
security_mode=SecurityMode.WPA2,
password=generate_random_password(length=20),
wpa_cipher="CCMP",
wpa2_cipher="CCMP",
)
password = security_profile.password
if test.n_mode not in N_MODE:
raise ValueError(f"Invalid n-mode: {test.n_mode}")
setup_ap(
access_point=self.access_point,
profile_name="whirlwind",
mode=test.n_mode,
channel=channel,
n_capabilities=n_capabilities,
ac_capabilities=[],
force_wmm=True,
ssid=ssid,
security=security_profile,
password=password,
)
asserts.assert_true(
self.dut.associate(
ssid,
target_pwd=password,
target_security=test.security,
),
"Failed to connect.",
)
def _generate_24_HT20_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_20,
N_MODE,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
INTOLERANT_40,
MAX_AMPDU_7935,
SMPS,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=combination[2],
security=SecurityMode.OPEN,
n_capabilities=list(combination[3:]),
)
)
return test_args
def _generate_24_HT40_lower_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_40_LOWER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.OPEN,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_24_HT40_upper_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_40_UPPER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.OPEN,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT20_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_20,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
INTOLERANT_40,
MAX_AMPDU_7935,
SMPS,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.OPEN,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT40_lower_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_40_LOWER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.OPEN,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT40_upper_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_40_UPPER,
N_MODE,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=combination[2],
security=SecurityMode.OPEN,
n_capabilities=list(combination[3:]),
)
)
return test_args
def _generate_24_HT20_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_20,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
INTOLERANT_40,
MAX_AMPDU_7935,
SMPS,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_24_HT40_lower_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_40_LOWER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_24_HT40_upper_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_24,
CHANNEL_BANDWIDTH_40_UPPER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT20_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_20,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
INTOLERANT_40,
MAX_AMPDU_7935,
SMPS,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT40_lower_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_40_LOWER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
def _generate_5_HT40_upper_wpa2_test_args(self) -> List[TestParams]:
test_args: List[TestParams] = []
for combination in itertools.product(
FREQUENCY_5,
CHANNEL_BANDWIDTH_40_UPPER,
LDPC,
TX_STBC,
RX_STBC,
SGI_20,
SGI_40,
MAX_AMPDU_7935,
SMPS,
DSSS_CCK,
):
test_args.append(
TestParams(
frequency=combination[0],
chbw=combination[1],
n_mode=hostapd_constants.MODE_11N_MIXED,
security=SecurityMode.WPA2,
n_capabilities=list(combination[2:]),
)
)
return test_args
if __name__ == "__main__":
test_runner.main()