blob: 1f1d4cf9db3020925ed4300b3f0300b444c4690e [file] [log] [blame]
from acts import asserts
from acts import base_test
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.net import net_test_utils as nutils
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from scapy.all import get_if_raw_hwaddr
from scapy.layers.dns import DNS, DNSQR
from scapy.layers.inet import IP, ICMP, UDP, TCP, RandShort, sr1
from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
DUMSYS_CMD = "dumpsys connectivity tethering"
UPSTREAM_WANTED_STRING = "Upstream wanted"
CURRENT_UPSTREAM_STRING = "Current upstream interface"
SSID = wutils.WifiEnums.SSID_KEY
GOOGLE_DNS_IP_ADDRESS = "8.8.8.8"
DEFAULT_DOMAIN_NAME = "www.google.com"
DEFAULT_DOMAIN_NAME_IPV4 = "ipv4.google.com"
DEFAULT_DOMAIN_NAME_IPV6 = "ipv6.google.com"
class UsbTetheringTest(base_test.BaseTestClass):
"""Tests for USB tethering.
Prerequisite:
1. Android phone should connect to the desktop with USB cable
2. DUT should be able to connect to cellular network and Wi-Fi network
3. Set the CAP_NET_RAW capability before run the test.
e.g., `sudo setcap cap_net_raw=eip /usr/local/bin/act.py`
"""
def setup_class(self):
self.dut = self.android_devices[0]
self.USB_TETHERED = False
nutils.verify_lte_data_and_tethering_supported(self.dut)
nutils.set_cap_net_raw_capability()
req_params = ("wifi_network",)
self.unpack_userparams(req_params)
# Enable USB tethering and get the USB network interface
iflist_before = nutils.get_if_list()
serial = self.dut.device_info['serial']
nutils.start_usb_tethering(self.dut)
self.dut.recreate_services(serial)
self.iface = nutils.wait_for_new_iface(iflist_before)
if not self.check_upstream_ready():
raise asserts.fail("Upstream interface is not active.")
def teardown_class(self):
nutils.stop_usb_tethering(self.dut)
self.USB_TETHERED = False
wutils.reset_wifi(self.dut)
def on_fail(self, test_name, begin_time):
self.dut.take_bug_report(test_name, begin_time)
@test_tracker_info(uuid="d4da7695-4342-4564-b7b0-0a30895f23eb")
def test_icmp_connectivity(self):
"""Tests connectivity under ICMP.
Steps:
1. Enable USB tethering on Android devices
2. Generate ICMP packet and send to target IP address
3. Verify that the response contains an ICMP layer
"""
icmp = IP(dst=GOOGLE_DNS_IP_ADDRESS)/ICMP()
resp = sr1(icmp, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(ICMP),
"Failed to send ICMP: " + resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="0dc7d049-11bf-42f9-918a-263f4470a7e8")
def test_icmpv6_connectivity(self):
"""Tests connectivity under ICMPv6.
Steps:
1. Enable USB tethering on Android devices
2. Generate ICMPv6 echo request packet and send to target URL
3. Verify that the response contains an IPv6 layer
"""
icmpv6 = IPv6(dst=DEFAULT_DOMAIN_NAME_IPV6)/ICMPv6EchoRequest()
resp = sr1(icmpv6, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(IPv6),
"Failed to send ICMPv6: " + resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="34aaffb8-8dd4-4a1f-a158-2732b8df5e59")
def test_dns_query_connectivity(self):
"""Tests connectivity of DNS query.
Steps:
1. Enable USB tethering on Android devices
2. Generate DNS query and send to target DNS server
3. Verify that the response contains a DNS layer
"""
dnsqr = IP(dst=GOOGLE_DNS_IP_ADDRESS) \
/UDP(sport=RandShort(), dport=53) \
/DNS(rd=1, qd=DNSQR(qname=DEFAULT_DOMAIN_NAME))
resp = sr1(dnsqr, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(DNS),
"Failed to send DNS query: " + resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="b9bed0fa-3178-4456-92e0-736b3a8cc181")
def test_tcp_connectivity(self):
"""Tests connectivity under TCP.
Steps:
1. Enable USB tethering on Android devices
2. Generate TCP packet and send to target URL
3. Verify that the response contains a TCP layer
"""
tcp = IP(dst=DEFAULT_DOMAIN_NAME)/TCP(dport=[80, 443])
resp = sr1(tcp, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(TCP),
"Failed to send TCP packet:" + resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="5e2f31f4-0b18-44be-a1ba-d82bf9050996")
def test_tcp_ipv6_connectivity(self):
"""Tests connectivity under IPv6.
Steps:
1. Enable USB tethering on Android devices
2. Generate IPv6 packet and send to target URL (e.g., ipv6.google.com)
3. Verify that the response contains an IPv6 layer
"""
tcp_ipv6 = IPv6(dst=DEFAULT_DOMAIN_NAME_IPV6)/TCP(dport=[80, 443])
resp = sr1(tcp_ipv6, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(IPv6),
"Failed to send TCP packet over IPv6, resp: " +
resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="96115afb-e0d3-40a8-8f04-b64cedc6588f")
def test_http_connectivity(self):
"""Tests connectivity under HTTP.
Steps:
1. Enable USB tethering on Android devices
2. Implement TCP 3-way handshake to simulate HTTP GET
3. Verify that the 3-way handshake works and response contains a TCP layer
"""
syn_ack = sr1(IP(dst=DEFAULT_DOMAIN_NAME)
/ TCP(dport=80, flags="S"), timeout=2, iface=self.iface)
get_str = "GET / HTTP/1.1\r\nHost: " + DEFAULT_DOMAIN_NAME + "\r\n\r\n"
req = IP(dst=DEFAULT_DOMAIN_NAME)/TCP(dport=80, sport=syn_ack[TCP].dport,
seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq + 1, flags="A")/get_str
resp = sr1(req, timeout=2, iface=self.iface)
asserts.assert_true(
resp and resp.haslayer(TCP),
"Failed to send HTTP request, resp: " +
resp.show(dump=True) if resp else "null")
@test_tracker_info(uuid="140a064b-1ab0-4a92-8bdb-e52dde03d5b8")
def test_usb_tethering_over_wifi(self):
"""Tests connectivity over Wi-Fi.
Steps:
1. Connects to a Wi-Fi network
2. Enable USB tethering
3. Verifies Wi-Fi is preferred upstream over data connection
"""
wutils.start_wifi_connection_scan_and_ensure_network_found(
self.dut, self.wifi_network[SSID])
wutils.wifi_connect(self.dut, self.wifi_network)
wifi_network = self.dut.droid.connectivityGetActiveNetwork()
self.log.info("wifi network %s" % wifi_network)
self.USB_TETHERED = True
self.real_hwaddr = get_if_raw_hwaddr(self.iface)
output = self.dut.adb.shell(DUMSYS_CMD)
for line in output.split("\n"):
if UPSTREAM_WANTED_STRING in line:
asserts.assert_true("true" in line, "Upstream interface is not active")
self.log.info("Upstream interface is active")
if CURRENT_UPSTREAM_STRING in line:
asserts.assert_true("wlan" in line, "WiFi is not the upstream "
"interface")
self.log.info("WiFi is the upstream interface")
def check_upstream_ready(self, retry=3):
"""Check the upstream is activated
Check the upstream is activated with retry
"""
for i in range(0, retry):
output = self.dut.adb.shell(DUMSYS_CMD)
for line in output.split("\n"):
if UPSTREAM_WANTED_STRING in line:
if "true" in line:
self.log.info("Upstream interface is active")
elif i == retry:
return False
return True