1#!/usr/bin/env python3 2# 3# Copyright 2021 - 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 time 18from acts import asserts 19from acts import signals 20from acts.test_decorators import test_tracker_info 21import acts_contrib.test_utils.wifi.wifi_test_utils as wutils 22from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest 23from acts.controllers.ap_lib.hostapd_constants import BAND_2G 24from acts.controllers.ap_lib.hostapd_constants import BAND_5G 25from acts.controllers.ap_lib import hostapd_constants 26 27# TODO: Find a better way to get real country code and channels data. 28COUNTRY_5G_NOT_ALLOWED = ["JP", "GB", "DE"] 29WIFI_5G_NON_DFS_CHANNELS = [36, 38, 40, 42, 44, 46, 48, 149, 153, 157, 161, 165] 30WIFI_5G_DFS_CHANNELS = [52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140] 31WIFI_EU_SRD_CHANNELS = [149, 153, 157, 161, 165] 32 33BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5 34WifiEnums = wutils.WifiEnums 35 36 37class WifiCountrySoftApAcsTest(WifiBaseTest): 38 """WiFi WifiSoftApCountryAcsTest test class. 39 40 Test Bed Requirement: 41 * Android DUT x 1. 42 * OpenWrt x 1. 43 """ 44 45 def setup_class(self): 46 super().setup_class() 47 48 self.dut = self.android_devices[0] 49 self.client = self.android_devices[1] 50 51 req_params = [] 52 opt_param = ["cnss_diag_file", "pixel_models"] 53 54 self.unpack_userparams( 55 req_param_names=req_params, opt_param_names=opt_param) 56 57 def setup_test(self): 58 super().setup_test() 59 for ad in self.android_devices: 60 wutils.reset_wifi(ad) 61 wutils.wifi_toggle_state(self.dut, True) 62 wutils.wifi_toggle_state(self.client, True) 63 64 def teardown_test(self): 65 super().teardown_test() 66 if self.dut.droid.wifiIsApEnabled(): 67 wutils.stop_wifi_tethering(self.dut) 68 69 for ad in self.android_devices: 70 wutils.reset_wifi(ad) 71 wutils.set_wifi_country_code( 72 ad, wutils.WifiEnums.CountryCode.US) 73 74 def teardown_class(self): 75 super().teardown_class() 76 for ad in self.android_devices: 77 wutils.reset_wifi(ad) 78 79 if "AccessPoint" in self.user_params: 80 del self.user_params["reference_networks"] 81 del self.user_params["open_network"] 82 83 def is_bridgedap_supported(self, *args): 84 return self.dut.droid.wifiIsBridgedApConcurrencySupported() 85 86 def set_country_code_and_verify(self, ad, country_code): 87 """ Set Country Code to DUT. 88 89 Args: 90 ad: An AndroidDevice object. 91 country_code: String; 2 letter ISO country code, e,g,. "US". 92 """ 93 wutils.set_wifi_country_code(ad, country_code) 94 # Wi-Fi OFF and ON to make sure country code take effect. 95 wutils.wifi_toggle_state(ad, False) 96 wutils.wifi_toggle_state(ad, True) 97 98 country = ad.droid.wifiGetCountryCode() 99 asserts.assert_true(country == country_code, 100 "country code {} is not set".format(country_code)) 101 ad.log.info("Country code set to : {}".format(country)) 102 103 def connect_wifi_network(self, init_sta_band, init_sta_chan): 104 """Enable OpenWrt with a 2G/5G channels and a DUT connect to it. 105 106 Args: 107 init_sta_band: String; "2g" or "5g". 108 init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. 109 110 Returns: 111 ap_freq: Integer'; represent the frequency of the AP which 112 the DUT connect to. 113 """ 114 115 # Enable a Wi-Fi network and DUT connect to it. 116 if init_sta_band == BAND_2G: 117 connect = BAND_2G 118 channel_2g = init_sta_chan 119 channel_5g = hostapd_constants.AP_DEFAULT_CHANNEL_5G 120 elif init_sta_band == BAND_5G: 121 connect = BAND_5G 122 channel_2g = hostapd_constants.AP_DEFAULT_CHANNEL_2G 123 channel_5g = init_sta_chan 124 125 # Enable OpenWrt AP. 126 if "OpenWrtAP" in self.user_params: 127 self.openwrt = self.access_points[0] 128 self.configure_openwrt_ap_and_start(wpa_network=True, 129 channel_2g=channel_2g, 130 channel_5g=channel_5g) 131 self.ap1_2g = self.wpa_networks[0][BAND_2G] 132 self.ap1_5g = self.wpa_networks[0][BAND_5G] 133 134 self.openwrt.log.info("OpenWrt AP 2G: {}".format(self.ap1_2g)) 135 self.openwrt.log.info("OpenWrt AP 5G: {}".format(self.ap1_5g)) 136 137 if connect == BAND_2G: 138 wutils.connect_to_wifi_network(self.dut, self.ap1_2g) 139 elif connect == BAND_5G: 140 wutils.connect_to_wifi_network(self.dut, self.ap1_5g) 141 142 ap_freq = self.dut.droid.wifiGetConnectionInfo()["frequency"] 143 self.dut.log.info("DUT connected to AP on freq: {}, chan: {}". 144 format(ap_freq, WifiEnums.freq_to_channel[ap_freq])) 145 return ap_freq 146 147 def enable_softap(self, ad): 148 """ Enable SoftAp of the DUT 149 150 Args: 151 ad: An AndroidDevice object. 152 153 Returns: 154 (freq1, freq2): Integer; a 2G frequency and a 5G frequency if DUT 155 support BridgedAp. 156 freq: Integer; a frequency from SoftAp. 157 None, bandwidth: Just a placeholder, won't be used. 158 159 Raises: 160 TestFailure if no BridgedAp instances. 161 """ 162 # Enable SoftAp 163 # Create SoftAp config. 164 config = wutils.create_softap_config() 165 # If DUT support BridgedAp, then two BridgedAp instances enabled. 166 if self.dut.droid.wifiIsBridgedApConcurrencySupported(): 167 wutils.save_wifi_soft_ap_config( 168 ad, 169 config, 170 bands=[WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G, 171 WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G]) 172 # If DUT does not support BridgedAp, 2G OR 5G SoftAp enabled. 173 else: 174 if self.init_softap_band == BAND_2G: 175 band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G 176 elif self.init_softap_band == BAND_5G: 177 band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_5G 178 wutils.save_wifi_soft_ap_config(ad, config, band=band) 179 wutils.start_wifi_tethering_saved_config(ad) 180 time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS) 181 182 # if DUT support BridgedAp: 183 if ad.droid.wifiIsBridgedApConcurrencySupported(): 184 callbackId = ad.droid.registerSoftApCallback() 185 infos = wutils.get_current_softap_infos(ad, callbackId, True) 186 ad.droid.unregisterSoftApCallback(callbackId) 187 # if DUT BridgedAp has two instances, return two frequencies. 188 if len(infos) == 2: 189 freq_1 = infos[0]["frequency"] 190 freq_2 = infos[1]["frequency"] 191 return freq_1, freq_2 192 # if DUT BridgedAp has only one instances, return the frequency. 193 elif len(infos) == 1: 194 freq = infos[0]["frequency"] 195 return freq, None 196 else: 197 raise signals.TestFailure("There should be SoftAp instance.") 198 # if DUT does not support BridgedAp: 199 else: 200 # Return SoftAp frequency. 201 callbackId = ad.droid.registerSoftApCallback() 202 freq, bandwidth = wutils.get_current_softap_info(ad, callbackId, 203 True) 204 ad.log.info("SoftAp freq: {}".format(freq)) 205 ad.droid.unregisterSoftApCallback(callbackId) 206 return freq, bandwidth 207 208 def collect_acs_failures(self, freq1, freq2, country, init_sta_band, 209 init_sta_chan, init_softap_band): 210 """ Verify SoftAp ACS rules and return error message when fail. 211 212 Args: 213 freq1: Integer; frequency from SoftAp. 214 freq2: Integer; frequency from SoftAp. 215 country: String; Two letters country code, e.g., "US". 216 init_sta_band: String; "2g" or "5g". 217 init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. 218 init_softap_band: String: "2g" or "5g". 219 220 Returns: List of string; contains failure messages. 221 """ 222 # If DUT support BridgedAp(Dual SoftAp). 223 # Decide which is softap_2g_freq, which is softap_5g_freq 224 self.softap_freq_1 = freq1 225 if self.dut.droid.wifiIsBridgedApConcurrencySupported(): 226 self.softap_freq_2 = freq2 227 if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES: 228 self.softap_2g_freq = self.softap_freq_1 229 elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES: 230 self.softap_5g_freq = self.softap_freq_1 231 if self.softap_freq_2 in WifiEnums.ALL_2G_FREQUENCIES: 232 self.softap_2g_freq = self.softap_freq_2 233 elif self.softap_freq_2 in WifiEnums.ALL_5G_FREQUENCIES: 234 self.softap_5g_freq = self.softap_freq_2 235 # If DUT does not support BridgedAp(Dual SoftAp). 236 # Decide the frequency is softap_2g_freq or softap_5g_freq 237 else: 238 if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES: 239 self.softap_2g_freq = self.softap_freq_1 240 elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES: 241 self.softap_5g_freq = self.softap_freq_1 242 243 # Verify ACS when SoftAp 2G enabled. 244 failures = [] 245 if init_softap_band == BAND_2G: 246 if init_sta_band == BAND_2G: 247 self.dut.log.info("Verifying 2G SoftAp chan == 2G STA chan") 248 if self.softap_2g_freq != self.actual_sta_freq: 249 failures.append("Expect 2G SoftAp chan == 2G STA chan") 250 else: 251 self.dut.log.info("Verifying SoftAp still operates on 2G") 252 if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES: 253 failures.append("Expect SoftAp still operates on 2G") 254 255 # Verify ACS when SoftAp 5G enabled. 256 elif init_softap_band == BAND_5G: 257 if (country in COUNTRY_5G_NOT_ALLOWED or 258 init_sta_chan in WIFI_5G_DFS_CHANNELS or 259 init_sta_chan in WIFI_EU_SRD_CHANNELS): 260 self.dut.log.info("Verifying SoftAp fallback to 2G") 261 if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES: 262 failures.append("Expect SoftAp fallback to 2G.") 263 else: 264 if init_sta_band == BAND_2G: 265 self.dut.log.info("Verifying SoftAp still operates on 5G") 266 if self.softap_5g_freq not in WifiEnums.ALL_5G_FREQUENCIES: 267 failures.append("Expect SoftAp still operates on 5G.") 268 elif init_sta_chan in WIFI_5G_NON_DFS_CHANNELS: 269 self.dut.log.info("Verify 5G SoftAp chan == 5g STA chan") 270 if self.softap_5g_freq != self.actual_sta_freq: 271 failures.append("Expect 5G SoftAp chan == 5G STA chan") 272 failures = "\n".join(failures) 273 return failures 274 275 def validate_country_softap_acs(self, country, init_sta_band, 276 init_sta_chan, init_softap_band): 277 """ Verify SoftAp ACS on certain country work as expected. 278 279 Steps: 280 Get country, STA band, STA channel from test case name. 281 Set a country code to the DUT. 282 Enable a Wi-Fi network. 283 DUT connects to the Wi-Fi network. 284 DUT enable SoftAp. 285 P20 and previous 286 Enable SoftAp (2G OR 5G). 287 P21 and later: 288 Enable BridgedAp (2G AND 5G) 289 Get SoftAp(or BridgedAp) channel. 290 Get AP channel. 291 Verify Country SoftAp ACS. 292 293 Args: 294 country: String; Two letters country code, e.g., "US". 295 init_sta_band: String; "2g" or "5g". 296 init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel. 297 init_softap_band: String: "2g" or "5g". 298 299 Returns: List of string; contains failure messages. 300 """ 301 # Set a country code to the DUT. 302 self.set_country_code_and_verify(self.dut, country) 303 # Get DUT STA frequency. 304 self.actual_sta_freq = self.connect_wifi_network(init_sta_band, 305 init_sta_chan) 306 # DUT Enable SoftAp. 307 freq1, freq2 = self.enable_softap(self.dut) 308 # Verify Country SoftAp ACS. 309 return self.collect_acs_failures(freq1, freq2, country, init_sta_band, 310 init_sta_chan, init_softap_band) 311 312 # Tests 313 314 @test_tracker_info(uuid="003c67f7-f4cc-4f04-ab34-28c71a7602d9") 315 def test_country_us_softap_acs_sta_2g_ch_1_softap_2g(self): 316 """Verify SoftAp ACS on STA 2G CH1 and SoftAp 2G in US. 317 Steps: See docstring of validate_country_softap_acs().""" 318 failures = self.validate_country_softap_acs("US", "2g", 1, "2g") 319 asserts.assert_false(failures, str(failures)) 320 321 @test_tracker_info(uuid="b3c0a7a4-150f-469c-9191-8d446b2e2593") 322 def test_country_us_softap_acs_sta_5g_ch_36_softap_2g(self): 323 """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 2G in US. 324 Steps: See docstring of validate_country_softap_acs().""" 325 failures = self.validate_country_softap_acs("US", "5g", 36, "2g") 326 asserts.assert_false(failures, str(failures)) 327 328 @test_tracker_info(uuid="7c660706-e63d-4753-bb6e-dacdf4c36cc0") 329 def test_country_us_softap_acs_sta_5g_ch_132_softap_2g(self): 330 """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 2G in US. 331 Steps: See docstring of validate_country_softap_acs().""" 332 failures = self.validate_country_softap_acs("US", "5g", 132, "2g") 333 asserts.assert_false(failures, str(failures)) 334 335 @test_tracker_info(uuid="31973348-852e-4cd7-9a72-6e8f333623c5") 336 def test_country_de_softap_acs_sta_5g_ch_161_softap_2g(self): 337 """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 2G in DE. 338 Steps: See docstring of validate_country_softap_acs().""" 339 failures = self.validate_country_softap_acs("US", "5g", 161, "2g") 340 asserts.assert_false(failures, str(failures)) 341 342 @test_tracker_info(uuid="8ebba60c-a32c-46b3-b9da-411b1ef66288") 343 def test_country_us_softap_acs_sta_2g_ch_1_softap_5g(self): 344 """Verify SoftAp ACS on STA 2G CH1 and SoftAp 5G in US. 345 Steps: See docstring of validate_country_softap_acs().""" 346 failures = self.validate_country_softap_acs("US", "2g", 1, "5g") 347 asserts.assert_false(failures, str(failures)) 348 349 @test_tracker_info(uuid="503ece09-3030-4a69-ae15-320f5104ddd2") 350 def test_country_us_softap_acs_sta_5g_ch_36_softap_5g(self): 351 """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 5G in US. 352 Steps: See docstring of validate_country_softap_acs().""" 353 failures = self.validate_country_softap_acs("US", "5g", 36, "5g") 354 asserts.assert_false(failures, str(failures)) 355 356 @test_tracker_info(uuid="35a5f2f5-067d-4d67-aeb8-58fb253f4b97") 357 def test_country_us_softap_acs_sta_5g_ch_132_softap_5g(self): 358 """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 5G in US. 359 Steps: See docstring of validate_country_softap_acs().""" 360 failures = self.validate_country_softap_acs("US", "5g", 132, "5g") 361 asserts.assert_false(failures, str(failures)) 362 363 @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305") 364 def test_country_de_softap_acs_sta_5g_ch_161_softap_5g(self): 365 """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE. 366 Steps: See docstring of validate_country_softap_acs().""" 367 failures = self.validate_country_softap_acs("DE", "5g", 161, "5g") 368 asserts.assert_false(failures, str(failures)) 369 370 @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305") 371 def test_country_jp_softap_acs_sta_5g_ch_36_softap_5g(self): 372 """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE. 373 Steps: See docstring of validate_country_softap_acs().""" 374 failures = self.validate_country_softap_acs("JP", "5g", 36, "5g") 375 asserts.assert_false(failures, str(failures)) 376