Merge changes Iade99eeb,I3ede46f5 am: 0c0cbd3c04
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2116175 Change-Id: Iee24c11be3b23cd75a11c465ef6225a7f5411387 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -26,7 +26,8 @@ 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.isIcmpv6Type;
|
import static android.net.TetheringTester.isExpectedIcmpv6Packet;
|
||||||
|
import static android.net.TetheringTester.isExpectedUdpPacket;
|
||||||
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;
|
||||||
import static android.system.OsConstants.IPPROTO_UDP;
|
import static android.system.OsConstants.IPPROTO_UDP;
|
||||||
@@ -82,10 +83,7 @@ import com.android.net.module.util.bpf.Tether4Key;
|
|||||||
import com.android.net.module.util.bpf.Tether4Value;
|
import com.android.net.module.util.bpf.Tether4Value;
|
||||||
import com.android.net.module.util.bpf.TetherStatsKey;
|
import com.android.net.module.util.bpf.TetherStatsKey;
|
||||||
import com.android.net.module.util.bpf.TetherStatsValue;
|
import com.android.net.module.util.bpf.TetherStatsValue;
|
||||||
import com.android.net.module.util.structs.EthernetHeader;
|
|
||||||
import com.android.net.module.util.structs.Ipv4Header;
|
|
||||||
import com.android.net.module.util.structs.Ipv6Header;
|
import com.android.net.module.util.structs.Ipv6Header;
|
||||||
import com.android.net.module.util.structs.UdpHeader;
|
|
||||||
import com.android.testutils.DevSdkIgnoreRule;
|
import com.android.testutils.DevSdkIgnoreRule;
|
||||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
|
||||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
||||||
@@ -332,7 +330,7 @@ public class EthernetTetheringTest {
|
|||||||
final long deadline = SystemClock.uptimeMillis() + timeoutMs;
|
final long deadline = SystemClock.uptimeMillis() + timeoutMs;
|
||||||
do {
|
do {
|
||||||
byte[] pkt = reader.popPacket(timeoutMs);
|
byte[] pkt = reader.popPacket(timeoutMs);
|
||||||
if (isIcmpv6Type(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
|
if (isExpectedIcmpv6Packet(pkt, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return;
|
||||||
|
|
||||||
timeoutMs = deadline - SystemClock.uptimeMillis();
|
timeoutMs = deadline - SystemClock.uptimeMillis();
|
||||||
} while (timeoutMs > 0);
|
} while (timeoutMs > 0);
|
||||||
@@ -792,38 +790,11 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIcmpv6Echo() throws Exception {
|
public void testIcmpv6Echo() throws Exception {
|
||||||
assumeFalse(mEm.isAvailable());
|
runPing6Test(initTetheringTester(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
|
||||||
|
toList(TEST_IP4_DNS, TEST_IP6_DNS)));
|
||||||
// MyTetheringEventCallback currently only support await first available upstream. Tethering
|
|
||||||
// may select internet network as upstream if test network is not available and not be
|
|
||||||
// preferred yet. Create test upstream network before enable tethering.
|
|
||||||
mUpstreamTracker = createTestUpstream(toList(TEST_IP4_ADDR, TEST_IP6_ADDR),
|
|
||||||
toList(TEST_IP4_DNS, TEST_IP6_DNS));
|
|
||||||
|
|
||||||
mDownstreamIface = createTestInterface();
|
|
||||||
mEm.setIncludeTestInterfaces(true);
|
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
|
||||||
|
|
||||||
mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
|
|
||||||
mUpstreamTracker.getNetwork());
|
|
||||||
assertEquals("onUpstreamChanged for unexpected network", mUpstreamTracker.getNetwork(),
|
|
||||||
mTetheringEventCallback.awaitUpstreamChanged());
|
|
||||||
|
|
||||||
mDownstreamReader = makePacketReader(mDownstreamIface);
|
|
||||||
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
|
|
||||||
|
|
||||||
runPing6Test(new TetheringTester(mDownstreamReader, mUpstreamReader));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runPing6Test(TetheringTester tester) throws Exception {
|
private void runPing6Test(TetheringTester tester) throws Exception {
|
||||||
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
|
||||||
// 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.
|
|
||||||
tester.waitForIpv6TetherConnectivityVerified();
|
|
||||||
|
|
||||||
TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString("1:2:3:4:5:6"),
|
TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString("1:2:3:4:5:6"),
|
||||||
true /* hasIpv6 */);
|
true /* hasIpv6 */);
|
||||||
Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
|
Inet6Address remoteIp6Addr = (Inet6Address) parseNumericAddress("2400:222:222::222");
|
||||||
@@ -832,14 +803,14 @@ public class EthernetTetheringTest {
|
|||||||
tester.verifyUpload(request, p -> {
|
tester.verifyUpload(request, 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 isExpectedIcmpv6Packet(p, false /* hasEth */, ICMPV6_ECHO_REQUEST_TYPE);
|
||||||
});
|
});
|
||||||
|
|
||||||
ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
|
ByteBuffer reply = Ipv6Utils.buildEchoReplyPacket(remoteIp6Addr, tethered.ipv6Addr);
|
||||||
tester.verifyDownload(reply, p -> {
|
tester.verifyDownload(reply, 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 isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ECHO_REPLY_TYPE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,28 +843,6 @@ public class EthernetTetheringTest {
|
|||||||
private static final ByteBuffer PAYLOAD3 =
|
private static final ByteBuffer PAYLOAD3 =
|
||||||
ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
|
ByteBuffer.wrap(new byte[] { (byte) 0x9a, (byte) 0xbc });
|
||||||
|
|
||||||
private boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEther,
|
|
||||||
boolean isIpv4, @NonNull final ByteBuffer payload) {
|
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
|
|
||||||
|
|
||||||
if (hasEther) {
|
|
||||||
if (Struct.parse(EthernetHeader.class, buf) == null) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isIpv4) {
|
|
||||||
if (Struct.parse(Ipv4Header.class, buf) == null) return false;
|
|
||||||
} else {
|
|
||||||
if (Struct.parse(Ipv6Header.class, buf) == null) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Struct.parse(UdpHeader.class, buf) == null) return false;
|
|
||||||
|
|
||||||
if (buf.remaining() != payload.limit()) return false;
|
|
||||||
|
|
||||||
return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
|
|
||||||
payload.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private ByteBuffer buildUdpPacket(
|
private ByteBuffer buildUdpPacket(
|
||||||
@Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
|
@Nullable final MacAddress srcMac, @Nullable final MacAddress dstMac,
|
||||||
@@ -1092,8 +1041,8 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeTethering(List<LinkAddress> upstreamAddresses, List<InetAddress> upstreamDnses)
|
private TetheringTester initTetheringTester(List<LinkAddress> upstreamAddresses,
|
||||||
throws Exception {
|
List<InetAddress> upstreamDnses) throws Exception {
|
||||||
assumeFalse(mEm.isAvailable());
|
assumeFalse(mEm.isAvailable());
|
||||||
|
|
||||||
// MyTetheringEventCallback currently only support await first available upstream. Tethering
|
// MyTetheringEventCallback currently only support await first available upstream. Tethering
|
||||||
@@ -1104,9 +1053,9 @@ public class EthernetTetheringTest {
|
|||||||
mDownstreamIface = createTestInterface();
|
mDownstreamIface = createTestInterface();
|
||||||
mEm.setIncludeTestInterfaces(true);
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
final String iface = mTetheredInterfaceRequester.getInterface();
|
// Make sure EtherentTracker use "mDownstreamIface" as server mode interface.
|
||||||
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
mDownstreamIface.getInterfaceName(), iface);
|
mDownstreamIface.getInterfaceName(), mTetheredInterfaceRequester.getInterface());
|
||||||
|
|
||||||
mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
|
mTetheringEventCallback = enableEthernetTethering(mDownstreamIface.getInterfaceName(),
|
||||||
mUpstreamTracker.getNetwork());
|
mUpstreamTracker.getNetwork());
|
||||||
@@ -1115,13 +1064,23 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
mDownstreamReader = makePacketReader(mDownstreamIface);
|
mDownstreamReader = makePacketReader(mDownstreamIface);
|
||||||
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
|
mUpstreamReader = makePacketReader(mUpstreamTracker.getTestIface());
|
||||||
|
|
||||||
|
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
|
||||||
|
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, make
|
||||||
|
// sure tethering already have ipv6 connectivity before testing.
|
||||||
|
if (cm.getLinkProperties(mUpstreamTracker.getNetwork()).hasGlobalIpv6Address()) {
|
||||||
|
waitForRouterAdvertisement(mDownstreamReader, mDownstreamIface.getInterfaceName(),
|
||||||
|
WAIT_RA_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TetheringTester(mDownstreamReader, mUpstreamReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@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));
|
runUdp4Test(initTetheringTester(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)),
|
||||||
runUdp4Test(new TetheringTester(mDownstreamReader, mUpstreamReader), false /* usingBpf */);
|
false /* usingBpf */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
|
private static boolean isUdpOffloadSupportedByKernel(final String kernelVersion) {
|
||||||
@@ -1155,14 +1114,13 @@ public class EthernetTetheringTest {
|
|||||||
@Test
|
@Test
|
||||||
@IgnoreUpTo(Build.VERSION_CODES.R)
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
public void testTetherUdpV4AfterR() throws Exception {
|
public void testTetherUdpV4AfterR() throws Exception {
|
||||||
initializeTethering(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS));
|
|
||||||
final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
|
final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
|
||||||
boolean usingBpf = isUdpOffloadSupportedByKernel(kernelVersion);
|
boolean usingBpf = isUdpOffloadSupportedByKernel(kernelVersion);
|
||||||
if (!usingBpf) {
|
if (!usingBpf) {
|
||||||
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, mUpstreamReader), usingBpf);
|
runUdp4Test(initTetheringTester(toList(TEST_IP4_ADDR), toList(TEST_IP4_DNS)), usingBpf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -1264,11 +1222,6 @@ public class EthernetTetheringTest {
|
|||||||
// packet.
|
// packet.
|
||||||
//
|
//
|
||||||
private void runClatUdpTest(TetheringTester tester) throws Exception {
|
private void runClatUdpTest(TetheringTester tester) throws Exception {
|
||||||
// Currently tethering don't have API to tell when ipv6 tethering is available. Thus, let
|
|
||||||
// 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.
|
|
||||||
tester.waitForIpv6TetherConnectivityVerified();
|
|
||||||
|
|
||||||
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
|
final TetheredDevice tethered = tester.createTetheredDevice(MacAddress.fromString(
|
||||||
"1:2:3:4:5:6"), true /* hasIpv6 */);
|
"1:2:3:4:5:6"), true /* hasIpv6 */);
|
||||||
|
|
||||||
@@ -1304,8 +1257,7 @@ public class EthernetTetheringTest {
|
|||||||
@IgnoreUpTo(Build.VERSION_CODES.R)
|
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||||
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));
|
runClatUdpTest(initTetheringTester(toList(TEST_IP6_ADDR), toList(TEST_IP6_DNS)));
|
||||||
runClatUdpTest(new TetheringTester(mDownstreamReader, mUpstreamReader));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> List<T> toList(T... array) {
|
private <T> List<T> toList(T... array) {
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ package android.net;
|
|||||||
|
|
||||||
import static android.net.InetAddresses.parseNumericAddress;
|
import static android.net.InetAddresses.parseNumericAddress;
|
||||||
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||||
|
import static android.system.OsConstants.IPPROTO_UDP;
|
||||||
|
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
|
import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
|
import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
|
||||||
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV4;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
|
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
|
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
|
||||||
@@ -49,11 +51,13 @@ import com.android.net.module.util.Ipv6Utils;
|
|||||||
import com.android.net.module.util.Struct;
|
import com.android.net.module.util.Struct;
|
||||||
import com.android.net.module.util.structs.EthernetHeader;
|
import com.android.net.module.util.structs.EthernetHeader;
|
||||||
import com.android.net.module.util.structs.Icmpv6Header;
|
import com.android.net.module.util.structs.Icmpv6Header;
|
||||||
|
import com.android.net.module.util.structs.Ipv4Header;
|
||||||
import com.android.net.module.util.structs.Ipv6Header;
|
import com.android.net.module.util.structs.Ipv6Header;
|
||||||
import com.android.net.module.util.structs.LlaOption;
|
import com.android.net.module.util.structs.LlaOption;
|
||||||
import com.android.net.module.util.structs.NsHeader;
|
import com.android.net.module.util.structs.NsHeader;
|
||||||
import com.android.net.module.util.structs.PrefixInformationOption;
|
import com.android.net.module.util.structs.PrefixInformationOption;
|
||||||
import com.android.net.module.util.structs.RaHeader;
|
import com.android.net.module.util.structs.RaHeader;
|
||||||
|
import com.android.net.module.util.structs.UdpHeader;
|
||||||
import com.android.networkstack.arp.ArpPacket;
|
import com.android.networkstack.arp.ArpPacket;
|
||||||
import com.android.testutils.TapPacketReader;
|
import com.android.testutils.TapPacketReader;
|
||||||
|
|
||||||
@@ -62,6 +66,7 @@ import java.net.Inet6Address;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
@@ -252,25 +257,11 @@ public final class TetheringTester {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForIpv6TetherConnectivityVerified() throws Exception {
|
|
||||||
Log.d(TAG, "Waiting RA multicast");
|
|
||||||
|
|
||||||
// Wait for RA multicast message from router to confirm that the IPv6 tethering
|
|
||||||
// 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.
|
|
||||||
for (int i = 0; i < READ_RA_ATTEMPTS; i++) {
|
|
||||||
final byte[] raPacket = getDownloadPacket((p) -> {
|
|
||||||
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
|
||||||
});
|
|
||||||
if (raPacket != null) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Could not get RA multicast packet after " + READ_RA_ATTEMPTS + " attempts");
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<PrefixInformationOption> getRaPrefixOptions(byte[] packet) {
|
private List<PrefixInformationOption> getRaPrefixOptions(byte[] packet) {
|
||||||
ByteBuffer buf = ByteBuffer.wrap(packet);
|
ByteBuffer buf = ByteBuffer.wrap(packet);
|
||||||
if (!isIcmpv6Type(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) return null;
|
if (!isExpectedIcmpv6Packet(buf, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT)) {
|
||||||
|
fail("Parsing RA packet fail");
|
||||||
|
}
|
||||||
|
|
||||||
Struct.parse(RaHeader.class, buf);
|
Struct.parse(RaHeader.class, buf);
|
||||||
final ArrayList<PrefixInformationOption> pioList = new ArrayList<>();
|
final ArrayList<PrefixInformationOption> pioList = new ArrayList<>();
|
||||||
@@ -298,7 +289,7 @@ public final class TetheringTester {
|
|||||||
sendRsPacket(srcMac, dstMac);
|
sendRsPacket(srcMac, dstMac);
|
||||||
|
|
||||||
final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
|
final byte[] raPacket = verifyPacketNotNull("Receive RA fail", getDownloadPacket(p -> {
|
||||||
return isIcmpv6Type(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
return isExpectedIcmpv6Packet(p, true /* hasEth */, ICMPV6_ROUTER_ADVERTISEMENT);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
|
final List<PrefixInformationOption> options = getRaPrefixOptions(raPacket);
|
||||||
@@ -316,7 +307,7 @@ public final class TetheringTester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fail("Could not get ipv6 address");
|
fail("No available ipv6 prefix");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,23 +351,18 @@ public final class TetheringTester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isIcmpv6Type(byte[] packet, boolean hasEth, int type) {
|
public static boolean isExpectedIcmpv6Packet(byte[] packet, boolean hasEth, int type) {
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(packet);
|
final ByteBuffer buf = ByteBuffer.wrap(packet);
|
||||||
return isIcmpv6Type(buf, hasEth, type);
|
return isExpectedIcmpv6Packet(buf, hasEth, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isIcmpv6Type(ByteBuffer buf, boolean hasEth, int type) {
|
private static boolean isExpectedIcmpv6Packet(ByteBuffer buf, boolean hasEth, int type) {
|
||||||
try {
|
try {
|
||||||
if (hasEth) {
|
if (hasEth && !hasExpectedEtherHeader(buf, false /* isIpv4 */)) return false;
|
||||||
final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf);
|
|
||||||
if (ethHdr.etherType != ETHER_TYPE_IPV6) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf);
|
if (!hasExpectedIpHeader(buf, false /* isIpv4 */, IPPROTO_ICMPV6)) return false;
|
||||||
if (ipv6Hdr.nextHeader != (byte) IPPROTO_ICMPV6) return false;
|
|
||||||
|
|
||||||
final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, buf);
|
return Struct.parse(Icmpv6Header.class, buf).type == (short) type;
|
||||||
return icmpv6Hdr.type == (short) type;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Parsing packet fail means it is not icmpv6 packet.
|
// Parsing packet fail means it is not icmpv6 packet.
|
||||||
}
|
}
|
||||||
@@ -384,6 +370,42 @@ public final class TetheringTester {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasExpectedEtherHeader(@NonNull final ByteBuffer buf, boolean isIpv4)
|
||||||
|
throws Exception {
|
||||||
|
final int expected = isIpv4 ? ETHER_TYPE_IPV4 : ETHER_TYPE_IPV6;
|
||||||
|
|
||||||
|
return Struct.parse(EthernetHeader.class, buf).etherType == expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasExpectedIpHeader(@NonNull final ByteBuffer buf, boolean isIpv4,
|
||||||
|
int ipProto) throws Exception {
|
||||||
|
if (isIpv4) {
|
||||||
|
return Struct.parse(Ipv4Header.class, buf).protocol == (byte) ipProto;
|
||||||
|
} else {
|
||||||
|
return Struct.parse(Ipv6Header.class, buf).nextHeader == (byte) ipProto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isExpectedUdpPacket(@NonNull final byte[] rawPacket, boolean hasEth,
|
||||||
|
boolean isIpv4, @NonNull final ByteBuffer payload) {
|
||||||
|
final ByteBuffer buf = ByteBuffer.wrap(rawPacket);
|
||||||
|
try {
|
||||||
|
if (hasEth && !hasExpectedEtherHeader(buf, isIpv4)) return false;
|
||||||
|
|
||||||
|
if (!hasExpectedIpHeader(buf, isIpv4, IPPROTO_UDP)) return false;
|
||||||
|
|
||||||
|
if (Struct.parse(UdpHeader.class, buf) == null) return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Parsing packet fail means it is not udp packet.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.remaining() != payload.limit()) return false;
|
||||||
|
|
||||||
|
return Arrays.equals(Arrays.copyOfRange(buf.array(), buf.position(), buf.limit()),
|
||||||
|
payload.array());
|
||||||
|
}
|
||||||
|
|
||||||
private void sendUploadPacket(ByteBuffer packet) throws Exception {
|
private void sendUploadPacket(ByteBuffer packet) throws Exception {
|
||||||
mDownstreamReader.sendResponse(packet);
|
mDownstreamReader.sendResponse(packet);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user