#!/usr/bin/env python3 # # Copyright 2021 - The Android Open Source Project # # 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 time from acts import asserts from acts import signals from acts.test_decorators import test_tracker_info import acts_contrib.test_utils.wifi.wifi_test_utils as wutils from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest from acts.controllers.ap_lib.hostapd_constants import BAND_2G from acts.controllers.ap_lib.hostapd_constants import BAND_5G from acts.controllers.ap_lib import hostapd_constants # TODO: Find a better way to get real country code and channels data. COUNTRY_5G_NOT_ALLOWED = ["JP", "GB", "DE"] WIFI_5G_NON_DFS_CHANNELS = [36, 38, 40, 42, 44, 46, 48, 149, 153, 157, 161, 165] WIFI_5G_DFS_CHANNELS = [52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140] WIFI_EU_SRD_CHANNELS = [149, 153, 157, 161, 165] BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5 WifiEnums = wutils.WifiEnums class WifiCountrySoftApAcsTest(WifiBaseTest): """WiFi WifiSoftApCountryAcsTest test class. Test Bed Requirement: * Android DUT x 1. * OpenWrt x 1. """ def setup_class(self): super().setup_class() self.dut = self.android_devices[0] self.client = self.android_devices[1] if "OpenWrtAP" in self.user_params: self.openwrt = self.access_points[0] self.openwrt.log.info("Rebooting OpenWrt") self.openwrt.reboot() self.openwrt.verify_wifi_status(timeout=60) req_params = [] opt_param = [] self.unpack_userparams( req_param_names=req_params, opt_param_names=opt_param) def setup_test(self): super().setup_test() for ad in self.android_devices: wutils.reset_wifi(ad) wutils.wifi_toggle_state(self.dut, True) wutils.wifi_toggle_state(self.client, True) def teardown_test(self): super().teardown_test() if self.dut.droid.wifiIsApEnabled(): wutils.stop_wifi_tethering(self.dut) for ad in self.android_devices: wutils.reset_wifi(ad) wutils.set_wifi_country_code( ad, wutils.WifiEnums.CountryCode.US) def teardown_class(self): super().teardown_class() for ad in self.android_devices: wutils.reset_wifi(ad) if "AccessPoint" in self.user_params: del self.user_params["reference_networks"] del self.user_params["open_network"] def is_bridgedap_supported(self, *args): return self.dut.droid.wifiIsBridgedApConcurrencySupported() def set_country_code_and_verify(self, ad, country_code): """ Set Country Code to DUT. Args: ad: An AndroidDevice object. country_code: String; 2 letter ISO country code, e,g,. "US". """ wutils.set_wifi_country_code(ad, country_code) # Wi-Fi OFF and ON to make sure country code take effect. wutils.wifi_toggle_state(ad, False) wutils.wifi_toggle_state(ad, True) country = ad.droid.wifiGetCountryCode() asserts.assert_true(country == country_code, "country code {} is not set".format(country_code)) ad.log.info("Country code set to : {}".format(country)) def connect_wifi_network(self, init_sta_band, init_sta_chan): """Enable OpenWrt with a 2G/5G channels and a DUT connect to it. Args: init_sta_band: String; "2g" or "5g". init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. Returns: ap_freq: Integer'; represent the frequency of the AP which the DUT connect to. """ # Enable a Wi-Fi network and DUT connect to it. if init_sta_band == BAND_2G: connect = BAND_2G channel_2g = init_sta_chan channel_5g = hostapd_constants.AP_DEFAULT_CHANNEL_5G elif init_sta_band == BAND_5G: connect = BAND_5G channel_2g = hostapd_constants.AP_DEFAULT_CHANNEL_2G channel_5g = init_sta_chan # Enable OpenWrt AP. if "OpenWrtAP" in self.user_params: self.openwrt = self.access_points[0] self.configure_openwrt_ap_and_start(wpa_network=True, channel_2g=channel_2g, channel_5g=channel_5g) self.ap1_2g = self.wpa_networks[0][BAND_2G] self.ap1_5g = self.wpa_networks[0][BAND_5G] self.openwrt.log.info("OpenWrt AP 2G: {}".format(self.ap1_2g)) self.openwrt.log.info("OpenWrt AP 5G: {}".format(self.ap1_5g)) if connect == BAND_2G: wutils.connect_to_wifi_network(self.dut, self.ap1_2g) elif connect == BAND_5G: wutils.connect_to_wifi_network(self.dut, self.ap1_5g) ap_freq = self.dut.droid.wifiGetConnectionInfo()["frequency"] self.dut.log.info("DUT connected to AP on freq: {}, chan: {}". format(ap_freq, WifiEnums.freq_to_channel[ap_freq])) return ap_freq def enable_softap(self, ad): """ Enable SoftAp of the DUT Args: ad: An AndroidDevice object. Returns: (freq1, freq2): Integer; a 2G frequency and a 5G frequency if DUT support BridgedAp. freq: Integer; a frequency from SoftAp. None, bandwidth: Just a placeholder, won't be used. Raises: TestFailure if no BridgedAp instances. """ # Enable SoftAp # Create SoftAp config. config = wutils.create_softap_config() # If DUT support BridgedAp, then two BridgedAp instances enabled. if self.dut.droid.wifiIsBridgedApConcurrencySupported(): wutils.save_wifi_soft_ap_config( ad, config, bands=[WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G, WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G]) # If DUT does not support BridgedAp, 2G OR 5G SoftAp enabled. else: if self.init_softap_band == BAND_2G: band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G elif self.init_softap_band == BAND_5G: band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_5G wutils.save_wifi_soft_ap_config(ad, config, band=band) wutils.start_wifi_tethering_saved_config(ad) time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS) # if DUT support BridgedAp: if ad.droid.wifiIsBridgedApConcurrencySupported(): callbackId = ad.droid.registerSoftApCallback() infos = wutils.get_current_softap_infos(ad, callbackId, True) ad.droid.unregisterSoftApCallback(callbackId) # if DUT BridgedAp has two instances, return two frequencies. if len(infos) == 2: freq_1 = infos[0]["frequency"] freq_2 = infos[1]["frequency"] return freq_1, freq_2 # if DUT BridgedAp has only one instances, return the frequency. elif len(infos) == 1: freq = infos[0]["frequency"] return freq, None else: raise signals.TestFailure("There should be SoftAp instance.") # if DUT does not support BridgedAp: else: # Return SoftAp frequency. callbackId = ad.droid.registerSoftApCallback() freq, bandwidth = wutils.get_current_softap_info(ad, callbackId, True) ad.log.info("SoftAp freq: {}".format(freq)) ad.droid.unregisterSoftApCallback(callbackId) return freq, bandwidth def collect_acs_failures(self, freq1, freq2, country, init_sta_band, init_sta_chan, init_softap_band): """ Verify SoftAp ACS rules and return error message when fail. Args: freq1: Integer; frequency from SoftAp. freq2: Integer; frequency from SoftAp. country: String; Two letters country code, e.g., "US". init_sta_band: String; "2g" or "5g". init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. init_softap_band: String: "2g" or "5g". Returns: List of string; contains failure messages. """ # If DUT support BridgedAp(Dual SoftAp). # Decide which is softap_2g_freq, which is softap_5g_freq self.softap_freq_1 = freq1 if self.dut.droid.wifiIsBridgedApConcurrencySupported(): self.softap_freq_2 = freq2 if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES: self.softap_2g_freq = self.softap_freq_1 elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES: self.softap_5g_freq = self.softap_freq_1 if self.softap_freq_2 in WifiEnums.ALL_2G_FREQUENCIES: self.softap_2g_freq = self.softap_freq_2 elif self.softap_freq_2 in WifiEnums.ALL_5G_FREQUENCIES: self.softap_5g_freq = self.softap_freq_2 # If DUT does not support BridgedAp(Dual SoftAp). # Decide the frequency is softap_2g_freq or softap_5g_freq else: if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES: self.softap_2g_freq = self.softap_freq_1 elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES: self.softap_5g_freq = self.softap_freq_1 # Verify ACS when SoftAp 2G enabled. failures = [] if init_softap_band == BAND_2G: if init_sta_band == BAND_2G: self.dut.log.info("Verifying 2G SoftAp chan == 2G STA chan") if self.softap_2g_freq != self.actual_sta_freq: failures.append("Expect 2G SoftAp chan == 2G STA chan") else: self.dut.log.info("Verifying SoftAp still operates on 2G") if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES: failures.append("Expect SoftAp still operates on 2G") # Verify ACS when SoftAp 5G enabled. elif init_softap_band == BAND_5G: if (country in COUNTRY_5G_NOT_ALLOWED or init_sta_chan in WIFI_5G_DFS_CHANNELS or init_sta_chan in WIFI_EU_SRD_CHANNELS): self.dut.log.info("Verifying SoftAp fallback to 2G") if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES: failures.append("Expect SoftAp fallback to 2G.") else: if init_sta_band == BAND_2G: self.dut.log.info("Verifying SoftAp still operates on 5G") if self.softap_5g_freq not in WifiEnums.ALL_5G_FREQUENCIES: failures.append("Expect SoftAp still operates on 5G.") elif init_sta_chan in WIFI_5G_NON_DFS_CHANNELS: self.dut.log.info("Verify 5G SoftAp chan == 5g STA chan") if self.softap_5g_freq != self.actual_sta_freq: failures.append("Expect 5G SoftAp chan == 5G STA chan") failures = "\n".join(failures) return failures def validate_country_softap_acs(self, country, init_sta_band, init_sta_chan, init_softap_band): """ Verify SoftAp ACS on certain country work as expected. Steps: Get country, STA band, STA channel from test case name. Set a country code to the DUT. Enable a Wi-Fi network. DUT connects to the Wi-Fi network. DUT enable SoftAp. P20 and previous Enable SoftAp (2G OR 5G). P21 and later: Enable BridgedAp (2G AND 5G) Get SoftAp(or BridgedAp) channel. Get AP channel. Verify Country SoftAp ACS. Args: country: String; Two letters country code, e.g., "US". init_sta_band: String; "2g" or "5g". init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. init_softap_band: String: "2g" or "5g". Returns: List of string; contains failure messages. """ self.init_softap_band = init_softap_band # Set a country code to the DUT. self.set_country_code_and_verify(self.dut, country) # Get DUT STA frequency. self.actual_sta_freq = self.connect_wifi_network(init_sta_band, init_sta_chan) # DUT Enable SoftAp. freq1, freq2 = self.enable_softap(self.dut) # Verify Country SoftAp ACS. return self.collect_acs_failures(freq1, freq2, country, init_sta_band, init_sta_chan, init_softap_band) # Tests @test_tracker_info(uuid="003c67f7-f4cc-4f04-ab34-28c71a7602d9") def test_country_us_softap_acs_sta_2g_ch_1_softap_2g(self): """Verify SoftAp ACS on STA 2G CH1 and SoftAp 2G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "2g", 1, "2g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="b3c0a7a4-150f-469c-9191-8d446b2e2593") def test_country_us_softap_acs_sta_5g_ch_36_softap_2g(self): """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 2G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "5g", 36, "2g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="7c660706-e63d-4753-bb6e-dacdf4c36cc0") def test_country_us_softap_acs_sta_5g_ch_132_softap_2g(self): """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 2G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "5g", 132, "2g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="31973348-852e-4cd7-9a72-6e8f333623c5") def test_country_de_softap_acs_sta_5g_ch_161_softap_2g(self): """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 2G in DE. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "5g", 161, "2g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="8ebba60c-a32c-46b3-b9da-411b1ef66288") def test_country_us_softap_acs_sta_2g_ch_1_softap_5g(self): """Verify SoftAp ACS on STA 2G CH1 and SoftAp 5G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "2g", 1, "5g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="503ece09-3030-4a69-ae15-320f5104ddd2") def test_country_us_softap_acs_sta_5g_ch_36_softap_5g(self): """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 5G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "5g", 36, "5g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="35a5f2f5-067d-4d67-aeb8-58fb253f4b97") def test_country_us_softap_acs_sta_5g_ch_132_softap_5g(self): """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 5G in US. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("US", "5g", 132, "5g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305") def test_country_de_softap_acs_sta_5g_ch_161_softap_5g(self): """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("DE", "5g", 161, "5g") asserts.assert_false(failures, str(failures)) @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305") def test_country_jp_softap_acs_sta_5g_ch_36_softap_5g(self): """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE. Steps: See docstring of validate_country_softap_acs().""" failures = self.validate_country_softap_acs("JP", "5g", 36, "5g") asserts.assert_false(failures, str(failures))