|  | #  Copyright (C) 2024 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. | 
|  | # | 
|  | #  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 base64 | 
|  | import uuid | 
|  |  | 
|  | from mobly import asserts | 
|  | from mobly.controllers import android_device | 
|  |  | 
|  |  | 
|  | class UpstreamType: | 
|  | CELLULAR = 1 | 
|  | WIFI = 2 | 
|  |  | 
|  |  | 
|  | def generate_uuid32_base64() -> str: | 
|  | """Generates a UUID32 and encodes it in Base64. | 
|  |  | 
|  | Returns: | 
|  | str: The Base64-encoded UUID32 string. Which is 22 characters. | 
|  | """ | 
|  | # Strip padding characters to make it safer for hotspot name length limit. | 
|  | return base64.b64encode(uuid.uuid1().bytes).decode("utf-8").strip("=") | 
|  |  | 
|  |  | 
|  | def setup_hotspot_and_client_for_upstream_type( | 
|  | server_device: android_device, | 
|  | client_device: android_device, | 
|  | upstream_type: UpstreamType, | 
|  | ) -> (str, int): | 
|  | """Setup the hotspot with a connected client with the specified upstream type. | 
|  |  | 
|  | This creates a hotspot, make the client connect | 
|  | to it, and verify the packet is forwarded by the hotspot. | 
|  | And returns interface name of both if successful. | 
|  | """ | 
|  | server = server_device.connectivity_multi_devices_snippet | 
|  | client = client_device.connectivity_multi_devices_snippet | 
|  |  | 
|  | # Assert pre-conditions specific to each upstream type. | 
|  | asserts.skip_if(not client.hasWifiFeature(), "Client requires Wifi feature") | 
|  | asserts.skip_if( | 
|  | not server.hasHotspotFeature(), "Server requires hotspot feature" | 
|  | ) | 
|  | if upstream_type == UpstreamType.CELLULAR: | 
|  | asserts.skip_if( | 
|  | not server.hasTelephonyFeature(), "Server requires Telephony feature" | 
|  | ) | 
|  | server.requestCellularAndEnsureDefault() | 
|  | elif upstream_type == UpstreamType.WIFI: | 
|  | asserts.skip_if( | 
|  | not server.isStaApConcurrencySupported(), | 
|  | "Server requires Wifi AP + STA concurrency", | 
|  | ) | 
|  | server.ensureWifiIsDefault() | 
|  | else: | 
|  | raise ValueError(f"Invalid upstream type: {upstream_type}") | 
|  |  | 
|  | # Generate ssid/passphrase with random characters to make sure nearby devices won't | 
|  | # connect unexpectedly. Note that total length of ssid cannot go over 32. | 
|  | test_ssid = "HOTSPOT-" + generate_uuid32_base64() | 
|  | test_passphrase = generate_uuid32_base64() | 
|  |  | 
|  | # Create a hotspot with fixed SSID and password. | 
|  | hotspot_interface = server.startHotspot(test_ssid, test_passphrase) | 
|  |  | 
|  | # Make the client connects to the hotspot. | 
|  | client_network = client.connectToWifi(test_ssid, test_passphrase) | 
|  |  | 
|  | return hotspot_interface, client_network | 
|  |  | 
|  |  | 
|  | def cleanup_tethering_for_upstream_type( | 
|  | server_device: android_device, upstream_type: UpstreamType | 
|  | ) -> None: | 
|  | server = server_device.connectivity_multi_devices_snippet | 
|  | if upstream_type == UpstreamType.CELLULAR: | 
|  | server.unrequestCellular() | 
|  | # Teardown the hotspot. | 
|  | server.stopAllTethering() |