1#!/usr/bin/env python3.4 2# 3# Copyright 2018 - 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 logging 18import pprint 19import time 20import re 21 22from acts import asserts 23from acts import base_test 24from acts.controllers.ap_lib import hostapd_constants 25import acts.signals as signals 26from acts.test_decorators import test_tracker_info 27from acts.controllers.iperf_server import IPerfServer 28from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G 29from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G 30import acts_contrib.test_utils.wifi.wifi_test_utils as wutils 31from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest 32import acts.utils as utils 33import acts_contrib.test_utils.tel.tel_test_utils as tel_utils 34 35 36WifiEnums = wutils.WifiEnums 37WLAN = "wlan0" 38# Channels to configure the AP for various test scenarios. 39WIFI_NETWORK_AP_CHANNEL_2G = 1 40WIFI_NETWORK_AP_CHANNEL_5G = 36 41WIFI_NETWORK_AP_CHANNEL_5G_DFS = 132 42 43 44class WifiStaApConcurrencyTest(WifiBaseTest): 45 """Tests for STA + AP concurrency scenarios. 46 47 Test Bed Requirement: 48 * Two Android devices (For AP) 49 * One Wi-Fi network visible to the device (for STA). 50 """ 51 52 def setup_class(self): 53 super().setup_class() 54 self.dut = self.android_devices[0] 55 self.dut_client = self.android_devices[1] 56 57 # Do a simple version of init - mainly just sync the time and enable 58 # verbose logging. This test will fail if the DUT has a sim and cell 59 # data is disabled. We would also like to test with phones in less 60 # constrained states (or add variations where we specifically 61 # constrain). 62 utils.require_sl4a(self.android_devices) 63 64 for ad in self.android_devices: 65 wutils.wifi_test_device_init(ad) 66 utils.sync_device_time(ad) 67 # Set country code explicitly to "US". 68 wutils.set_wifi_country_code(ad, WifiEnums.CountryCode.US) 69 # Enable verbose logging on the duts. 70 ad.droid.wifiEnableVerboseLogging(1) 71 72 req_params = ["dbs_supported_models", 73 "wifi6_models"] 74 self.unpack_userparams(req_param_names=req_params,) 75 76 self.iperf_server_port = wutils.get_iperf_server_port() 77 try: 78 self.iperf_server = IPerfServer(self.iperf_server_port) 79 self.iperf_server.start() 80 logging.info(f"IPerf server started on {self.iperf_server_port}") 81 except Exception as e: 82 raise signals.TestFailure("Failed to start iperf3 server: %s" % e) 83 84 def setup_test(self): 85 asserts.skip_if( 86 self.dut.model not in self.dbs_supported_models, 87 "Device %s does not support dual interfaces" % self.dut.model) 88 89 super().setup_test() 90 for ad in self.android_devices: 91 ad.droid.wakeLockAcquireBright() 92 ad.droid.wakeUpNow() 93 self.turn_location_off_and_scan_toggle_off() 94 95 def teardown_test(self): 96 super().teardown_test() 97 # Prevent the stop wifi tethering failure to block ap close 98 try: 99 wutils.stop_wifi_tethering(self.dut) 100 except signals.TestFailure: 101 pass 102 for ad in self.android_devices: 103 ad.droid.wakeLockRelease() 104 ad.droid.goToSleepNow() 105 wutils.reset_wifi(ad) 106 self.turn_location_on_and_scan_toggle_on() 107 wutils.wifi_toggle_state(self.dut, True) 108 self.access_points[0].close() 109 if "AccessPoint" in self.user_params: 110 try: 111 del self.user_params["reference_networks"] 112 del self.user_params["open_network"] 113 except KeyError as e: 114 self.log.warn("There is no 'reference_network' or " 115 "'open_network' to delete") 116 117 def teardown_class(self): 118 self.iperf_server.stop() 119 120 ### Helper Functions ### 121 122 def configure_ap(self, hidden=False, channel_2g=None, channel_5g=None): 123 """Configure and bring up AP on required channel. 124 125 Args: 126 channel_2g: The channel number to use for 2GHz network. 127 channel_5g: The channel number to use for 5GHz network. 128 129 """ 130 if not channel_2g: 131 channel_2g = hostapd_constants.AP_DEFAULT_CHANNEL_2G 132 if not channel_5g: 133 channel_5g = hostapd_constants.AP_DEFAULT_CHANNEL_5G 134 if "AccessPoint" in self.user_params: 135 self.legacy_configure_ap_and_start(channel_2g=channel_2g, 136 channel_5g=channel_5g, 137 hidden=hidden) 138 elif "OpenWrtAP" in self.user_params: 139 self.configure_openwrt_ap_and_start(open_network=True, 140 channel_2g=channel_2g, 141 channel_5g=channel_5g, 142 hidden=hidden) 143 self.open_2g = self.open_network[0]["2g"] 144 self.open_5g = self.open_network[0]["5g"] 145 146 def turn_location_on_and_scan_toggle_on(self): 147 """Turns on wifi location scans.""" 148 utils.set_location_service(self.dut, True) 149 self.dut.droid.wifiScannerToggleAlwaysAvailable(True) 150 msg = "Failed to turn on location service's scan." 151 asserts.assert_true(self.dut.droid.wifiScannerIsAlwaysAvailable(), msg) 152 153 def turn_location_off_and_scan_toggle_off(self): 154 """Turns off wifi location scans.""" 155 utils.set_location_service(self.dut, False) 156 self.dut.droid.wifiScannerToggleAlwaysAvailable(False) 157 msg = "Failed to turn off location service's scan." 158 asserts.assert_false(self.dut.droid.wifiScannerIsAlwaysAvailable(), msg) 159 160 def run_iperf_client(self, params): 161 """Run iperf traffic after connection. 162 163 Args: 164 params: A tuple of network info and AndroidDevice object. 165 """ 166 if "iperf_server_address" in self.user_params: 167 wait_time = 5 168 network, ad = params 169 ssid = network[WifiEnums.SSID_KEY] 170 # Use local host as iperf server. 171 self.iperf_server_address = wutils.get_host_iperf_ipv4_address(ad) 172 asserts.assert_true(self.iperf_server_address, "The host has no " 173 "available IPv4 address for iperf client to " 174 "connect to.") 175 176 ad.log.info("Starting iperf traffic through {} to {} port:{}". 177 format(ssid, self.iperf_server_address, 178 self.iperf_server_port)) 179 time.sleep(wait_time) 180 port_arg = "-p {}".format(self.iperf_server_port) 181 success, data = ad.run_iperf_client(self.iperf_server_address, 182 port_arg) 183 self.log.debug(pprint.pformat(data)) 184 asserts.assert_true(success, "Error occurred in iPerf traffic.") 185 186 def create_softap_config(self): 187 """Create a softap config with ssid and password.""" 188 ap_ssid = "softap_" + utils.rand_ascii_str(8) 189 ap_password = utils.rand_ascii_str(8) 190 self.dut.log.info("softap setup: %s %s", ap_ssid, ap_password) 191 config = {wutils.WifiEnums.SSID_KEY: ap_ssid} 192 config[wutils.WifiEnums.PWD_KEY] = ap_password 193 return config 194 195 def start_softap_and_verify(self, band, check_connectivity=True): 196 """Test startup of softap. 197 198 1. Bring up AP mode. 199 2. Verify SoftAP active using the client device. 200 201 Args: 202 band: wifi band to start soft ap on 203 check_connectivity: If set, verify internet connectivity 204 205 Returns: 206 Softap config 207 """ 208 config = self.create_softap_config() 209 wutils.start_wifi_tethering(self.dut, 210 config[WifiEnums.SSID_KEY], 211 config[WifiEnums.PWD_KEY], 212 band) 213 for ad in self.android_devices[1:]: 214 wutils.connect_to_wifi_network( 215 ad, config, check_connectivity=check_connectivity) 216 wutils.verify_11ax_softap(self.dut, ad, self.wifi6_models) 217 return config 218 219 def connect_to_wifi_network_and_start_softap(self, nw_params, 220 softap_band, 221 hidden=False): 222 """Test concurrent wifi connection and softap. 223 224 This helper method first makes a wifi connection and then starts SoftAp. 225 1. Bring up wifi. 226 2. Establish connection to a network. 227 3. Bring up softap and verify AP can be connected by a client device. 228 4. Run iperf on the wifi/softap connection to the network. 229 230 Args: 231 nw_params: Params for network STA connection. 232 softap_band: Band for the AP. 233 234 Raises: 235 TestError if there is iperf traffic connection error. 236 """ 237 wutils.connect_to_wifi_network(self.dut, nw_params, hidden=hidden) 238 wutils.verify_11ax_wifi_connection( 239 self.dut, self.wifi6_models, "wifi6_ap" in self.user_params) 240 softap_config = self.start_softap_and_verify(softap_band) 241 try: 242 self.run_iperf_client((nw_params, self.dut)) 243 self.run_iperf_client((softap_config, self.dut_client)) 244 except: 245 raise signals.TestError("Check if the iperf Server {} is " 246 "up and running and the Port {} is " 247 "listening for requests." 248 .format(self.iperf_server_address, 249 self.iperf_server_port)) 250 251 if len(self.android_devices) > 2: 252 self.log.info("Testbed has extra devices, do more validation") 253 self.verify_traffic_between_dut_clients( 254 self.dut_client, self.android_devices[2]) 255 256 asserts.assert_true(self.dut.droid.wifiCheckState(), 257 "Wifi is not reported as running") 258 asserts.assert_true(self.dut.droid.wifiIsApEnabled(), 259 "SoftAp is not reported as running") 260 261 def start_softap_and_connect_to_wifi_network( 262 self, nw_params, softap_band, 263 num_of_scan_tries=wutils.DEFAULT_SCAN_TRIES): 264 """Test concurrent wifi connection and softap. 265 266 This helper method first starts SoftAp and then makes a wifi connection. 267 1. Bring up softap and verify AP can be connected by a client device. 268 2. Bring up wifi. 269 3. Establish connection to a network. 270 4. Run iperf on the wifi/softap connection to the network. 271 5. Verify wifi state and softap state. 272 273 Args: 274 nw_params: Params for network STA connection. 275 softap_band: Band for the AP. 276 num_of_scan_tries: Number of tries to connect to wifi network 277 """ 278 softap_config = self.start_softap_and_verify(softap_band, False) 279 wutils.connect_to_wifi_network( 280 self.dut, nw_params, num_of_scan_tries=num_of_scan_tries) 281 wutils.verify_11ax_wifi_connection( 282 self.dut, self.wifi6_models, "wifi6_ap" in self.user_params) 283 self.run_iperf_client((nw_params, self.dut)) 284 self.run_iperf_client((softap_config, self.dut_client)) 285 286 if len(self.android_devices) > 2: 287 self.log.info("Testbed has extra devices, do more validation") 288 self.verify_traffic_between_dut_clients( 289 self.dut, self.android_devices[2]) 290 291 asserts.assert_true(self.dut.droid.wifiCheckState(), 292 "Wifi is not reported as running") 293 asserts.assert_true(self.dut.droid.wifiIsApEnabled(), 294 "SoftAp is not reported as running") 295 296 def verify_traffic_between_dut_clients(self, ad1, ad2, num_of_tries=2): 297 """Test the clients that connect to DUT's softap can ping each other. 298 299 Args: 300 ad1: DUT 1 301 ad2: DUT 2 302 num_of_tries: the retry times of ping test. 303 """ 304 ad1_ip = ad1.droid.connectivityGetIPv4Addresses(WLAN)[0] 305 ad2_ip = ad2.droid.connectivityGetIPv4Addresses(WLAN)[0] 306 # Ping each other 307 for _ in range(num_of_tries): 308 if utils.adb_shell_ping(ad1, count=10, dest_ip=ad2_ip, timeout=20): 309 break 310 else: 311 asserts.fail("%s ping %s failed" % (ad1.serial, ad2_ip)) 312 for _ in range(num_of_tries): 313 if utils.adb_shell_ping(ad2, count=10, dest_ip=ad1_ip, timeout=20): 314 break 315 else: 316 asserts.fail("%s ping %s failed" % (ad2.serial, ad1_ip)) 317 318 def softap_change_band(self, ad): 319 """ 320 Switch DUT SoftAp to 5G band if currently in 2G. 321 Switch DUT SoftAp to 2G band if currently in 5G. 322 """ 323 wlan1_freq = int(self.get_wlan1_status(self.dut)['freq']) 324 if wlan1_freq in wutils.WifiEnums.ALL_5G_FREQUENCIES: 325 band = WIFI_CONFIG_APBAND_2G 326 elif wlan1_freq in wutils.WifiEnums.ALL_2G_FREQUENCIES: 327 band = WIFI_CONFIG_APBAND_5G 328 wutils.stop_wifi_tethering(ad) 329 self.start_softap_and_verify(band) 330 331 def get_wlan1_status(self, ad): 332 """ get wlan1 interface status""" 333 get_wlan1 = 'hostapd_cli status' 334 out_wlan1 = ad.adb.shell(get_wlan1) 335 out_wlan1 = dict(re.findall(r'(\S+)=(".*?"|\S+)', out_wlan1)) 336 return out_wlan1 337 338 def enable_mobile_data(self, ad): 339 """Make sure that cell data is enabled if there is a sim present.""" 340 init_sim_state = tel_utils.is_sim_ready(self.log, ad) 341 if init_sim_state: 342 if not ad.droid.telephonyIsDataEnabled(): 343 ad.droid.telephonyToggleDataConnection(True) 344 asserts.assert_true(ad.droid.telephonyIsDataEnabled(), 345 "Failed to enable Mobile Data") 346 else: 347 raise signals.TestSkip("Please insert sim card with " 348 "Mobile Data enabled before test") 349 350 ### Tests ### 351 352 @test_tracker_info(uuid="c396e7ac-cf22-4736-a623-aa6d3c50193a") 353 def test_wifi_connection_2G_softap_2G(self): 354 """Test connection to 2G network followed by SoftAp on 2G.""" 355 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 356 self.connect_to_wifi_network_and_start_softap( 357 self.open_2g, WIFI_CONFIG_APBAND_2G) 358 359 @test_tracker_info(uuid="1cd6120d-3db4-4624-9bae-55c976533a48") 360 def test_wifi_connection_5G_softap_5G(self): 361 """Test connection to 5G network followed by SoftAp on 5G.""" 362 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 363 self.connect_to_wifi_network_and_start_softap( 364 self.open_5g, WIFI_CONFIG_APBAND_5G) 365 366 @test_tracker_info(uuid="5f980007-3490-413e-b94e-7700ffab8534") 367 def test_wifi_connection_5G_DFS_softap_5G(self): 368 """Test connection to 5G DFS network followed by SoftAp on 5G.""" 369 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G_DFS) 370 self.connect_to_wifi_network_and_start_softap( 371 self.open_5g, WIFI_CONFIG_APBAND_5G) 372 373 @test_tracker_info(uuid="d05d5d44-c738-4372-9f01-ce2a640a2f25") 374 def test_wifi_connection_5G_softap_2G(self): 375 """Test connection to 5G network followed by SoftAp on 2G.""" 376 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 377 self.connect_to_wifi_network_and_start_softap( 378 self.open_5g, WIFI_CONFIG_APBAND_2G) 379 380 @test_tracker_info(uuid="909ac713-1ad3-4dad-9be3-ad60f00ed25e") 381 def test_wifi_connection_5G_DFS_softap_2G(self): 382 """Test connection to 5G DFS network followed by SoftAp on 2G.""" 383 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G_DFS) 384 self.connect_to_wifi_network_and_start_softap( 385 self.open_5g, WIFI_CONFIG_APBAND_2G) 386 387 @test_tracker_info(uuid="e8de724a-25d3-4801-94cc-22e9e0ecc8d1") 388 def test_wifi_connection_2G_softap_5G(self): 389 """Test connection to 2G network followed by SoftAp on 5G.""" 390 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 391 self.connect_to_wifi_network_and_start_softap( 392 self.open_2g, WIFI_CONFIG_APBAND_5G) 393 394 @test_tracker_info(uuid="647f4e17-5c7a-4249-98af-f791d163a39f") 395 def test_wifi_connection_5G_softap_2G_with_location_scan_on(self): 396 """Test connection to 5G network, SoftAp on 2G with location scan on.""" 397 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 398 self.turn_location_on_and_scan_toggle_on() 399 self.connect_to_wifi_network_and_start_softap( 400 self.open_5g, WIFI_CONFIG_APBAND_2G) 401 # Now toggle wifi off & ensure we can still scan. 402 wutils.wifi_toggle_state(self.dut, False) 403 wutils.start_wifi_connection_scan_and_ensure_network_found( 404 self.dut, self.open_5g[WifiEnums.SSID_KEY]) 405 406 @test_tracker_info(uuid="4aa56c11-e5bc-480b-bd61-4b4ee577a5da") 407 def test_softap_2G_wifi_connection_2G(self): 408 """Test SoftAp on 2G followed by connection to 2G network.""" 409 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 410 self.start_softap_and_connect_to_wifi_network( 411 self.open_2g, WIFI_CONFIG_APBAND_2G) 412 413 @test_tracker_info(uuid="5f954957-ad20-4de1-b20c-6c97d0463bdd") 414 def test_softap_5G_wifi_connection_5G(self): 415 """Test SoftAp on 5G followed by connection to 5G network.""" 416 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 417 self.start_softap_and_connect_to_wifi_network( 418 self.open_5g, WIFI_CONFIG_APBAND_5G) 419 420 @test_tracker_info(uuid="1306aafc-a07e-4654-ba78-674f90cf748e") 421 def test_softap_5G_wifi_connection_5G_DFS(self): 422 """Test SoftAp on 5G followed by connection to 5G DFS network.""" 423 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G_DFS) 424 # Set scan tries to 10 to fit the 32ms limitation. 425 # SoftAp uses CTS2SELF frame to go offchannel for scan, and max duration 426 # we can set in CTS2SELF frame is 32ms. 427 # Since DUT SAP is enabled and clients are connect to the SAP, firmware 428 # is allocating only 28ms for passive scan in DFS channel for offchannel 429 # scan operation. We need to increase scan tries to get beacons from AP. 430 self.start_softap_and_connect_to_wifi_network( 431 self.open_5g, WIFI_CONFIG_APBAND_5G, num_of_scan_tries=10) 432 433 @test_tracker_info(uuid="5e28e8b5-3faa-4cff-a782-13a796d7f572") 434 def test_softap_5G_wifi_connection_2G(self): 435 """Test SoftAp on 5G followed by connection to 2G network.""" 436 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 437 self.start_softap_and_connect_to_wifi_network( 438 self.open_2g, WIFI_CONFIG_APBAND_5G) 439 440 @test_tracker_info(uuid="a2c62bc6-9ccd-4bc4-8a23-9a1b5d0b4b5c") 441 def test_softap_2G_wifi_connection_5G(self): 442 """Test SoftAp on 2G followed by connection to 5G network.""" 443 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 444 self.start_softap_and_connect_to_wifi_network( 445 self.open_5g, WIFI_CONFIG_APBAND_2G) 446 447 @test_tracker_info(uuid="75400685-a9d9-4091-8af3-97bd539c246a") 448 def test_softap_2G_wifi_connection_5G_DFS(self): 449 """Test SoftAp on 2G followed by connection to 5G DFS network.""" 450 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G_DFS) 451 self.start_softap_and_connect_to_wifi_network( 452 self.open_5g, WIFI_CONFIG_APBAND_2G) 453 454 @test_tracker_info(uuid="aa23a3fc-31a1-4d5c-8cf5-2eb9fdf9e7ce") 455 def test_softap_5G_wifi_connection_2G_with_location_scan_on(self): 456 """Test SoftAp on 5G, connection to 2G network with location scan on.""" 457 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 458 self.turn_location_on_and_scan_toggle_on() 459 self.start_softap_and_connect_to_wifi_network( 460 self.open_2g, WIFI_CONFIG_APBAND_5G) 461 # Now toggle wifi off & ensure we can still scan. 462 wutils.wifi_toggle_state(self.dut, False) 463 wutils.start_wifi_connection_scan_and_ensure_network_found( 464 self.dut, self.open_2g[WifiEnums.SSID_KEY]) 465 466 @test_tracker_info(uuid="9decb951-4500-4476-8161-f4054760f709") 467 def test_wifi_connection_2G_softap_2G_to_softap_5g(self): 468 """Test connection to 2G network followed by SoftAp on 2G, 469 and switch SoftAp to 5G.""" 470 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G) 471 self.connect_to_wifi_network_and_start_softap( 472 self.open_2g, WIFI_CONFIG_APBAND_2G) 473 self.softap_change_band(self.dut) 474 475 @test_tracker_info(uuid="e17e0fb8-2c1d-4f3c-af2a-7374485f210c") 476 def test_wifi_connection_5G_softap_2G_to_softap_5g(self): 477 """Test connection to 5G network followed by SoftAp on 2G, 478 and switch SoftAp to 5G.""" 479 self.configure_ap(channel_5g=WIFI_NETWORK_AP_CHANNEL_5G) 480 self.connect_to_wifi_network_and_start_softap( 481 self.open_2g, WIFI_CONFIG_APBAND_2G) 482 self.softap_change_band(self.dut) 483 484 @test_tracker_info(uuid="d549a18e-73d9-45e7-b4df-b59446c4b833") 485 def test_wifi_connection_hidden_2g_softap_2G_to_softap_5g(self): 486 """Test connection to a hidden 2G network on Channel 1 and 487 followed by SoftAp on 2G, and switch SoftAp to 5G. 488 1. Connect to a hidden 2.4G Wi-Fi AP(channel 1) 489 2. DUT turn on 2.4G hotspot and client connect to DUT 490 3. Change AP Band of DUT Hotspot from 2.4GHz to 5GHz 491 Expected results: Both DUT and Hotspot client can access the Internet 492 """ 493 self.configure_ap(channel_2g=WIFI_NETWORK_AP_CHANNEL_2G, hidden=True) 494 self.connect_to_wifi_network_and_start_softap( 495 self.open_2g, 496 WIFI_CONFIG_APBAND_2G, 497 hidden=True) 498 self.softap_change_band(self.dut) 499