1# Copyright (C) 2024 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import base64 16import uuid 17 18from mobly import asserts 19from mobly.controllers import android_device 20 21 22class UpstreamType: 23 NONE = 0 24 CELLULAR = 1 25 WIFI = 2 26 27 28def generate_uuid32_base64() -> str: 29 """Generates a UUID32 and encodes it in Base64. 30 31 Returns: 32 str: The Base64-encoded UUID32 string. Which is 22 characters. 33 """ 34 # Strip padding characters to make it safer for hotspot name length limit. 35 return base64.b64encode(uuid.uuid1().bytes).decode("utf-8").strip("=") 36 37 38def assume_hotspot_test_preconditions( 39 server_device: android_device, 40 client_device: android_device, 41 upstream_type: UpstreamType, 42) -> None: 43 server = server_device.connectivity_multi_devices_snippet 44 client = client_device.connectivity_multi_devices_snippet 45 46 # Assert pre-conditions specific to each upstream type. 47 asserts.skip_if(not client.hasWifiFeature(), "Client requires Wifi feature") 48 asserts.skip_if( 49 not server.hasHotspotFeature(), "Server requires hotspot feature" 50 ) 51 if upstream_type == UpstreamType.CELLULAR: 52 asserts.skip_if( 53 not server.hasTelephonyFeature(), "Server requires Telephony feature" 54 ) 55 elif upstream_type == UpstreamType.WIFI: 56 asserts.skip_if( 57 not server.isStaApConcurrencySupported(), 58 "Server requires Wifi AP + STA concurrency", 59 ) 60 elif upstream_type == UpstreamType.NONE: 61 pass 62 else: 63 raise ValueError(f"Invalid upstream type: {upstream_type}") 64 65 66def setup_hotspot_and_client_for_upstream_type( 67 server_device: android_device, 68 client_device: android_device, 69 upstream_type: UpstreamType, 70) -> (str, int): 71 """Setup the hotspot with a connected client with the specified upstream type. 72 73 This creates a hotspot, make the client connect 74 to it, and verify the packet is forwarded by the hotspot. 75 And returns interface name of both if successful. 76 """ 77 server = server_device.connectivity_multi_devices_snippet 78 client = client_device.connectivity_multi_devices_snippet 79 80 if upstream_type == UpstreamType.CELLULAR: 81 server.requestCellularAndEnsureDefault() 82 elif upstream_type == UpstreamType.WIFI: 83 server.ensureWifiIsDefault() 84 elif upstream_type == UpstreamType.NONE: 85 pass 86 else: 87 raise ValueError(f"Invalid upstream type: {upstream_type}") 88 89 # Generate ssid/passphrase with random characters to make sure nearby devices won't 90 # connect unexpectedly. Note that total length of ssid cannot go over 32. 91 test_ssid = "HOTSPOT-" + generate_uuid32_base64() 92 test_passphrase = generate_uuid32_base64() 93 94 # Create a hotspot with fixed SSID and password. 95 hotspot_interface = server.startHotspot(test_ssid, test_passphrase) 96 97 # Make the client connects to the hotspot. 98 client_network = client.connectToWifi(test_ssid, test_passphrase) 99 100 return hotspot_interface, client_network 101 102 103def cleanup_tethering_for_upstream_type( 104 server_device: android_device, upstream_type: UpstreamType 105) -> None: 106 server = server_device.connectivity_multi_devices_snippet 107 if upstream_type == UpstreamType.CELLULAR: 108 server.unregisterAll() 109 # Teardown the hotspot. 110 server.stopAllTethering() 111 # Some test cases would disable wifi, e.g. cellular upstream tests. 112 # Reconnect to it if feasible. 113 server.reconnectWifiIfSupported() 114