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