Merge "[TestOnly]Remove RemoteResponder from TetheringTester"
This commit is contained in:
@@ -26,7 +26,6 @@ import static android.net.InetAddresses.parseNumericAddress;
|
|||||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
||||||
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||||
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||||
import static android.net.TetheringTester.RemoteResponder;
|
|
||||||
import static android.net.TetheringTester.isIcmpv6Type;
|
import static android.net.TetheringTester.isIcmpv6Type;
|
||||||
import static android.system.OsConstants.IPPROTO_IP;
|
import static android.system.OsConstants.IPPROTO_IP;
|
||||||
import static android.system.OsConstants.IPPROTO_IPV6;
|
import static android.system.OsConstants.IPPROTO_IPV6;
|
||||||
@@ -816,10 +815,10 @@ public class EthernetTetheringTest {
|
|||||||
mDownstreamReader = makePacketReader(mDownstreamIface);
|
mDownstreamReader = makePacketReader(mDownstreamIface);
|
||||||
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
|
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
|
||||||
|
|
||||||
runPing6Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader));
|
runPing6Test(new TetheringTester(mDownstreamReader, mUpstreamReader));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runPing6Test(TetheringTester tester, RemoteResponder remote) throws Exception {
|
private void runPing6Test(TetheringTester tester) throws Exception {
|
||||||
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
||||||
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
|
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
|
||||||
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
|
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
|
||||||
@@ -830,24 +829,18 @@ public class EthernetTetheringTest {
|
|||||||
Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
|
Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
|
||||||
ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
|
ByteBuffer request = Ipv6Utils.buildEchoRequestPacket(tethered.macAddr,
|
||||||
tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
|
tethered.routerMacAddr, tethered.ipv6Addr, remoteIp6Addr);
|
||||||
tester.sendPacket(request);
|
tester.verifyUpload(request, p -> {
|
||||||
|
|
||||||
final byte[] echoRequest = remote.getNextMatchedPacket((p) -> {
|
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
|
|
||||||
return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
|
return isIcmpv6Type(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
|
||||||
});
|
});
|
||||||
assertNotNull("No icmpv6 echo request in upstream", echoRequest);
|
|
||||||
|
|
||||||
ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
|
ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
|
||||||
remote.sendPacket(reply);
|
tester.verifyDownload(reply, p -> {
|
||||||
|
|
||||||
final byte[] echoReply = tester.getNextMatchedPacket((p) -> {
|
|
||||||
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
||||||
|
|
||||||
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
|
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
|
||||||
});
|
});
|
||||||
assertNotNull("No icmpv6 echo reply in downstream", echoReply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test network topology:
|
// Test network topology:
|
||||||
@@ -964,7 +957,7 @@ public class EthernetTetheringTest {
|
|||||||
// TODO: remove this verification once upstream connected notification race is fixed.
|
// TODO: remove this verification once upstream connected notification race is fixed.
|
||||||
// See #runUdp4Test.
|
// See #runUdp4Test.
|
||||||
private boolean isIpv4TetherConnectivityVerified(TetheringTester tester,
|
private boolean isIpv4TetherConnectivityVerified(TetheringTester tester,
|
||||||
RemoteResponder remote, TetheredDevice tethered) throws Exception {
|
TetheredDevice tethered) throws Exception {
|
||||||
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
|
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
|
||||||
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
||||||
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
||||||
@@ -972,8 +965,7 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
// Send a UDP packet from client and check the packet can be found on upstream interface.
|
// Send a UDP packet from client and check the packet can be found on upstream interface.
|
||||||
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
|
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
|
||||||
tester.sendPacket(probePacket);
|
byte[] expectedPacket = tester.testUpload(probePacket, p -> {
|
||||||
byte[] expectedPacket = remote.getNextMatchedPacket(p -> {
|
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */,
|
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */,
|
||||||
TEST_REACHABILITY_PAYLOAD);
|
TEST_REACHABILITY_PAYLOAD);
|
||||||
@@ -983,8 +975,7 @@ public class EthernetTetheringTest {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runUdp4Test(TetheringTester tester, RemoteResponder remote, boolean usingBpf)
|
private void runUdp4Test(TetheringTester tester, boolean usingBpf) throws Exception {
|
||||||
throws Exception {
|
|
||||||
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
|
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
|
||||||
"1:2:3:4:5:6"), false /* hasIpv6 */);
|
"1:2:3:4:5:6"), false /* hasIpv6 */);
|
||||||
|
|
||||||
@@ -994,14 +985,14 @@ public class EthernetTetheringTest {
|
|||||||
// For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
|
// For short term plan, consider using IPv6 RA to get MAC address because the prefix comes
|
||||||
// from upstream. That can guarantee that the routing is ready. Long term plan is that
|
// from upstream. That can guarantee that the routing is ready. Long term plan is that
|
||||||
// refactors upstream connected notification from async to sync.
|
// refactors upstream connected notification from async to sync.
|
||||||
assertTrue(isIpv4TetherConnectivityVerified(tester, remote, tethered));
|
assertTrue(isIpv4TetherConnectivityVerified(tester, tethered));
|
||||||
|
|
||||||
// Send a UDP packet in original direction.
|
// Send a UDP packet in original direction.
|
||||||
final ByteBuffer originalPacket = buildUdpPacket(tethered.macAddr,
|
final ByteBuffer originalPacket = buildUdpPacket(tethered.macAddr,
|
||||||
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
||||||
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
||||||
PAYLOAD /* payload */);
|
PAYLOAD /* payload */);
|
||||||
tester.verifyUpload(remote, originalPacket, p -> {
|
tester.verifyUpload(originalPacket, p -> {
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
|
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
|
||||||
});
|
});
|
||||||
@@ -1011,7 +1002,7 @@ public class EthernetTetheringTest {
|
|||||||
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_IP4_ADDR /* srcIp */,
|
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_IP4_ADDR /* srcIp */,
|
||||||
publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
|
publicIp4Addr /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
|
||||||
PAYLOAD2 /* payload */);
|
PAYLOAD2 /* payload */);
|
||||||
remote.verifyDownload(tester, replyPacket, p -> {
|
tester.verifyDownload(replyPacket, p -> {
|
||||||
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
||||||
});
|
});
|
||||||
@@ -1030,7 +1021,7 @@ public class EthernetTetheringTest {
|
|||||||
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
||||||
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
|
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */,
|
||||||
REMOTE_PORT /* dstPort */, PAYLOAD3 /* payload */);
|
REMOTE_PORT /* dstPort */, PAYLOAD3 /* payload */);
|
||||||
tester.verifyUpload(remote, originalPacket2, p -> {
|
tester.verifyUpload(originalPacket2, p -> {
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD3);
|
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD3);
|
||||||
});
|
});
|
||||||
@@ -1066,7 +1057,7 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
// Send packets on original direction.
|
// Send packets on original direction.
|
||||||
for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
|
for (int i = 0; i < TX_UDP_PACKET_COUNT; i++) {
|
||||||
tester.verifyUpload(remote, originalPacket, p -> {
|
tester.verifyUpload(originalPacket, p -> {
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
|
return isExpectedUdpPacket(p, false /* hasEther */, true /* isIpv4 */, PAYLOAD);
|
||||||
});
|
});
|
||||||
@@ -1074,7 +1065,7 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
// Send packets on reply direction.
|
// Send packets on reply direction.
|
||||||
for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
|
for (int i = 0; i < RX_UDP_PACKET_COUNT; i++) {
|
||||||
remote.verifyDownload(tester, replyPacket, p -> {
|
tester.verifyDownload(replyPacket, p -> {
|
||||||
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
||||||
});
|
});
|
||||||
@@ -1130,8 +1121,7 @@ public class EthernetTetheringTest {
|
|||||||
@IgnoreAfter(Build.VERSION_CODES.R)
|
@IgnoreAfter(Build.VERSION_CODES.R)
|
||||||
public void testTetherUdpV4UpToR() throws Exception {
|
public void testTetherUdpV4UpToR() throws Exception {
|
||||||
initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
|
initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
|
||||||
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
|
runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), false /* usingBpf */);
|
||||||
false /* usingBpf */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
|
private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
|
||||||
@@ -1172,8 +1162,7 @@ public class EthernetTetheringTest {
|
|||||||
Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
|
Log.i(TAG, "testTetherUdpV4AfterR will skip BPF offload test for kernel "
|
||||||
+ kernelVersion);
|
+ kernelVersion);
|
||||||
}
|
}
|
||||||
runUdp4Test(new TetheringTester(mDownstreamReader), new RemoteResponder(mUpstreamReader),
|
runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), usingBpf);
|
||||||
usingBpf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -1233,8 +1222,8 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Inet6Address getClatIpv6Address(TetheringTester tester,
|
private Inet6Address getClatIpv6Address(TetheringTester tester, TetheredDevice tethered)
|
||||||
RemoteResponder remote, TetheredDevice tethered) throws Exception {
|
throws Exception {
|
||||||
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
|
final ByteBuffer probePacket = buildUdpPacket(tethered.macAddr,
|
||||||
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
||||||
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
||||||
@@ -1245,8 +1234,7 @@ public class EthernetTetheringTest {
|
|||||||
// packet.
|
// packet.
|
||||||
byte[] expectedPacket = null;
|
byte[] expectedPacket = null;
|
||||||
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
|
for (int i = 0; i < TETHER_REACHABILITY_ATTEMPTS; i++) {
|
||||||
tester.sendPacket(probePacket);
|
expectedPacket = tester.verifyUpload(probePacket, p -> {
|
||||||
expectedPacket = remote.getNextMatchedPacket(p -> {
|
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */,
|
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */,
|
||||||
TEST_REACHABILITY_PAYLOAD);
|
TEST_REACHABILITY_PAYLOAD);
|
||||||
@@ -1275,8 +1263,7 @@ public class EthernetTetheringTest {
|
|||||||
// sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
|
// sending out an IPv4 packet and extracting the source address from CLAT translated IPv6
|
||||||
// packet.
|
// packet.
|
||||||
//
|
//
|
||||||
private void runClatUdpTest(TetheringTester tester, RemoteResponder remote)
|
private void runClatUdpTest(TetheringTester tester) throws Exception {
|
||||||
throws Exception {
|
|
||||||
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
||||||
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
|
// TetheringTester test ipv6 tethering connectivity before testing ipv6.
|
||||||
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
|
// TODO: move to a common place to avoid that every IPv6 test needs to call this function.
|
||||||
@@ -1286,7 +1273,7 @@ public class EthernetTetheringTest {
|
|||||||
"1:2:3:4:5:6"), true /* hasIpv6 */);
|
"1:2:3:4:5:6"), true /* hasIpv6 */);
|
||||||
|
|
||||||
// Get CLAT IPv6 address.
|
// Get CLAT IPv6 address.
|
||||||
final Inet6Address clatAddr6 = getClatIpv6Address(tester, remote, tethered);
|
final Inet6Address clatAddr6 = getClatIpv6Address(tester, tethered);
|
||||||
assertNotNull(clatAddr6);
|
assertNotNull(clatAddr6);
|
||||||
|
|
||||||
// Send an IPv4 UDP packet in original direction.
|
// Send an IPv4 UDP packet in original direction.
|
||||||
@@ -1295,7 +1282,7 @@ public class EthernetTetheringTest {
|
|||||||
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
tethered.routerMacAddr, tethered.ipv4Addr /* srcIp */,
|
||||||
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
REMOTE_IP4_ADDR /* dstIp */, LOCAL_PORT /* srcPort */, REMOTE_PORT /* dstPort */,
|
||||||
PAYLOAD /* payload */);
|
PAYLOAD /* payload */);
|
||||||
tester.verifyUpload(remote, originalPacket, p -> {
|
tester.verifyUpload(originalPacket, p -> {
|
||||||
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in upstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, PAYLOAD);
|
return isExpectedUdpPacket(p, false /* hasEther */, false /* isIpv4 */, PAYLOAD);
|
||||||
});
|
});
|
||||||
@@ -1305,7 +1292,7 @@ public class EthernetTetheringTest {
|
|||||||
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_NAT64_ADDR /* srcIp */,
|
final ByteBuffer replyPacket = buildUdpPacket(REMOTE_NAT64_ADDR /* srcIp */,
|
||||||
clatAddr6 /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
|
clatAddr6 /* dstIp */, REMOTE_PORT /* srcPort */, LOCAL_PORT /* dstPort */,
|
||||||
PAYLOAD2 /* payload */);
|
PAYLOAD2 /* payload */);
|
||||||
remote.verifyDownload(tester, replyPacket, p -> {
|
tester.verifyDownload(replyPacket, p -> {
|
||||||
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
Log.d(TAG, "Packet in downstream: " + dumpHexString(p));
|
||||||
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
return isExpectedUdpPacket(p, true /* hasEther */, true /* isIpv4 */, PAYLOAD2);
|
||||||
});
|
});
|
||||||
@@ -1318,8 +1305,7 @@ public class EthernetTetheringTest {
|
|||||||
public void testTetherClatUdp() throws Exception {
|
public void testTetherClatUdp() throws Exception {
|
||||||
// CLAT only starts on IPv6 only network.
|
// CLAT only starts on IPv6 only network.
|
||||||
initializeTethering(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS));
|
initializeTethering(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS));
|
||||||
runClatUdpTest(new TetheringTester(mDownstreamReader),
|
runClatUdpTest(new TetheringTester(mDownstreamReader, mUpstreamReader));
|
||||||
new RemoteResponder(mUpstreamReader));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> List<T> toList(T... array) {
|
private <T> List<T> toList(T... array) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket;
|
|||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.net.module.util.Ipv6Utils;
|
import com.android.net.module.util.Ipv6Utils;
|
||||||
@@ -88,11 +89,17 @@ public final class TetheringTester {
|
|||||||
|
|
||||||
private final ArrayMap<MacAddress, TetheredDevice> mTetheredDevices;
|
private final ArrayMap<MacAddress, TetheredDevice> mTetheredDevices;
|
||||||
private final TapPacketReader mDownstreamReader;
|
private final TapPacketReader mDownstreamReader;
|
||||||
|
private final TapPacketReader mUpstreamReader;
|
||||||
|
|
||||||
public TetheringTester(TapPacketReader downstream) {
|
public TetheringTester(TapPacketReader downstream) {
|
||||||
|
this(downstream, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TetheringTester(TapPacketReader downstream, TapPacketReader upstream) {
|
||||||
if (downstream == null) fail("Downstream reader could not be NULL");
|
if (downstream == null) fail("Downstream reader could not be NULL");
|
||||||
|
|
||||||
mDownstreamReader = downstream;
|
mDownstreamReader = downstream;
|
||||||
|
mUpstreamReader = upstream;
|
||||||
mTetheredDevices = new ArrayMap<>();
|
mTetheredDevices = new ArrayMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +177,7 @@ public final class TetheringTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DhcpPacket getNextDhcpPacket() throws Exception {
|
private DhcpPacket getNextDhcpPacket() throws Exception {
|
||||||
final byte[] packet = getNextMatchedPacket((p) -> {
|
final byte[] packet = getDownloadPacket((p) -> {
|
||||||
// Test whether this is DHCP packet.
|
// Test whether this is DHCP packet.
|
||||||
try {
|
try {
|
||||||
DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
|
DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
|
||||||
@@ -213,7 +220,7 @@ public final class TetheringTester {
|
|||||||
tethered.ipv4Addr.getAddress() /* sender IP */,
|
tethered.ipv4Addr.getAddress() /* sender IP */,
|
||||||
(short) ARP_REPLY);
|
(short) ARP_REPLY);
|
||||||
try {
|
try {
|
||||||
sendPacket(arpReply);
|
sendUploadPacket(arpReply);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
fail("Failed to reply ARP for " + tethered.ipv4Addr);
|
fail("Failed to reply ARP for " + tethered.ipv4Addr);
|
||||||
}
|
}
|
||||||
@@ -227,9 +234,9 @@ public final class TetheringTester {
|
|||||||
tetherMac.toByteArray() /* srcMac */, routerIp.getAddress() /* target IP */,
|
tetherMac.toByteArray() /* srcMac */, routerIp.getAddress() /* target IP */,
|
||||||
new byte[ETHER_ADDR_LEN] /* target HW address */,
|
new byte[ETHER_ADDR_LEN] /* target HW address */,
|
||||||
tetherIp.getAddress() /* sender IP */, (short) ARP_REQUEST);
|
tetherIp.getAddress() /* sender IP */, (short) ARP_REQUEST);
|
||||||
sendPacket(arpProbe);
|
sendUploadPacket(arpProbe);
|
||||||
|
|
||||||
final byte[] packet = getNextMatchedPacket((p) -> {
|
final byte[] packet = getDownloadPacket((p) -> {
|
||||||
final ArpPacket arpPacket = parseArpPacket(p);
|
final ArpPacket arpPacket = parseArpPacket(p);
|
||||||
if (arpPacket == null || arpPacket.opCode != ARP_REPLY) return false;
|
if (arpPacket == null || arpPacket.opCode != ARP_REPLY) return false;
|
||||||
return arpPacket.targetIp.equals(tetherIp);
|
return arpPacket.targetIp.equals(tetherIp);
|
||||||
@@ -252,7 +259,7 @@ public final class TetheringTester {
|
|||||||
// connectivity is ready. We don't extract the router mac address from RA because
|
// connectivity is ready. We don't extract the router mac address from RA because
|
||||||
// we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp.
|
// we get the router mac address from IPv4 ARP packet. See #getRouterMacAddressFromArp.
|
||||||
for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
|
for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
|
||||||
final byte[] raPacket = getNextMatchedPacket((p) -> {
|
final byte[] raPacket = getDownloadPacket((p) -> {
|
||||||
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
||||||
});
|
});
|
||||||
if (raPacket != null) return;
|
if (raPacket != null) return;
|
||||||
@@ -290,13 +297,10 @@ public final class TetheringTester {
|
|||||||
private Inet6Address runSlaac(MacAddress srcMac, MacAddress dstMac) throws Exception {
|
private Inet6Address runSlaac(MacAddress srcMac, MacAddress dstMac) throws Exception {
|
||||||
sendRsPacket(srcMac, dstMac);
|
sendRsPacket(srcMac, dstMac);
|
||||||
|
|
||||||
final byte[] raPacket = getNextMatchedPacket((p) -> {
|
final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
|
||||||
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
||||||
});
|
}));
|
||||||
|
|
||||||
if (raPacket == null) {
|
|
||||||
fail("Could not get ra for prefix options");
|
|
||||||
}
|
|
||||||
final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
|
final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
|
||||||
|
|
||||||
for (PrefixInformationOption pio : options) {
|
for (PrefixInformationOption pio : options) {
|
||||||
@@ -322,7 +326,7 @@ public final class TetheringTester {
|
|||||||
ByteBuffer rs = Ipv6Utils.buildRsPacket(srcMac, dstMac, (Inet6Address) LINK_LOCAL,
|
ByteBuffer rs = Ipv6Utils.buildRsPacket(srcMac, dstMac, (Inet6Address) LINK_LOCAL,
|
||||||
IPV6_ADDR_ALL_NODES_MULTICAST, slla);
|
IPV6_ADDR_ALL_NODES_MULTICAST, slla);
|
||||||
|
|
||||||
sendPacket(rs);
|
sendUploadPacket(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeReplyNa(byte[] packet) {
|
private void maybeReplyNa(byte[] packet) {
|
||||||
@@ -347,7 +351,7 @@ public final class TetheringTester {
|
|||||||
ByteBuffer ns = Ipv6Utils.buildNaPacket(tethered.macAddr, tethered.routerMacAddr,
|
ByteBuffer ns = Ipv6Utils.buildNaPacket(tethered.macAddr, tethered.routerMacAddr,
|
||||||
nsHdr.target, ipv6Hdr.srcIp, flags, nsHdr.target, tlla);
|
nsHdr.target, ipv6Hdr.srcIp, flags, nsHdr.target, tlla);
|
||||||
try {
|
try {
|
||||||
sendPacket(ns);
|
sendUploadPacket(ns);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
fail("Failed to reply NA for " + tethered.ipv6Addr);
|
fail("Failed to reply NA for " + tethered.ipv6Addr);
|
||||||
}
|
}
|
||||||
@@ -380,11 +384,17 @@ public final class TetheringTester {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacket(ByteBuffer packet) throws Exception {
|
private void sendUploadPacket(ByteBuffer packet) throws Exception {
|
||||||
mDownstreamReader.sendResponse(packet);
|
mDownstreamReader.sendResponse(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getNextMatchedPacket(Predicate<byte[]> filter) {
|
private void sendDownloadPacket(ByteBuffer packet) throws Exception {
|
||||||
|
assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
|
||||||
|
|
||||||
|
mUpstreamReader.sendResponse(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getDownloadPacket(Predicate<byte[]> filter) {
|
||||||
byte[] packet;
|
byte[] packet;
|
||||||
while ((packet = mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS)) != null) {
|
while ((packet = mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS)) != null) {
|
||||||
if (filter.test(packet)) return packet;
|
if (filter.test(packet)) return packet;
|
||||||
@@ -396,30 +406,34 @@ public final class TetheringTester {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyUpload(final RemoteResponder dst, final ByteBuffer packet,
|
private byte[] getUploadPacket(Predicate<byte[]> filter) {
|
||||||
final Predicate<byte[]> filter) throws Exception {
|
assertNotNull("Can't deal with upstream interface in local only mode", mUpstreamReader);
|
||||||
sendPacket(packet);
|
|
||||||
assertNotNull("Upload fail", dst.getNextMatchedPacket(filter));
|
return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RemoteResponder {
|
private @NonNull byte[] verifyPacketNotNull(String message, @Nullable byte[] packet) {
|
||||||
final TapPacketReader mUpstreamReader;
|
assertNotNull(message, packet);
|
||||||
public RemoteResponder(TapPacketReader reader) {
|
|
||||||
mUpstreamReader = reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendPacket(ByteBuffer packet) throws Exception {
|
return packet;
|
||||||
mUpstreamReader.sendResponse(packet);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getNextMatchedPacket(Predicate<byte[]> filter) throws Exception {
|
public byte[] testUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
|
||||||
return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
|
throws Exception {
|
||||||
}
|
sendUploadPacket(packet);
|
||||||
|
|
||||||
public void verifyDownload(final TetheringTester dst, final ByteBuffer packet,
|
return getUploadPacket(filter);
|
||||||
final Predicate<byte[]> filter) throws Exception {
|
}
|
||||||
sendPacket(packet);
|
|
||||||
assertNotNull("Download fail", dst.getNextMatchedPacket(filter));
|
public byte[] verifyUpload(final ByteBuffer packet, final Predicate<byte[]> filter)
|
||||||
}
|
throws Exception {
|
||||||
|
return verifyPacketNotNull("Upload fail", testUpload(packet, filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] verifyDownload(final ByteBuffer packet, final Predicate<byte[]> filter)
|
||||||
|
throws Exception {
|
||||||
|
sendDownloadPacket(packet);
|
||||||
|
|
||||||
|
return verifyPacketNotNull("Download fail", getDownloadPacket(filter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user