Snap for 9679998 from 0bd4a252cd038d9c0e4adc4fd2f4785543cb76ff to sdk-release Change-Id: Ifdc48dc9e8956a6a7b67cec0ea7b4adc6659d16a
diff --git a/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java b/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java index 19ff9d3..b80cc32 100644 --- a/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java +++ b/apishim/30/com/android/networkstack/apishim/api30/ConstantsShim.java
@@ -46,4 +46,8 @@ public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; public static final int NET_CAPABILITY_ENTERPRISE = 29; public static final int TRANSPORT_TEST = 7; + + // Constants defined in android.content.pm.PackageManager + public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES = + "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES"; }
diff --git a/apishim/34/com/android/networkstack/apishim/ConstantsShim.java b/apishim/34/com/android/networkstack/apishim/ConstantsShim.java index 9df84d5..c946544 100644 --- a/apishim/34/com/android/networkstack/apishim/ConstantsShim.java +++ b/apishim/34/com/android/networkstack/apishim/ConstantsShim.java
@@ -16,6 +16,7 @@ package com.android.networkstack.apishim; +import android.content.pm.PackageManager; import android.os.Build; import androidx.annotation.RequiresApi; @@ -35,4 +36,8 @@ */ @VisibleForTesting public static final int VERSION = 34; + + // Constants defined in android.content.pm.PackageManager + public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES = + PackageManager.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES; }
diff --git a/src/android/net/ip/IpReachabilityMonitor.java b/src/android/net/ip/IpReachabilityMonitor.java index d16840d..b7cb9ce 100644 --- a/src/android/net/ip/IpReachabilityMonitor.java +++ b/src/android/net/ip/IpReachabilityMonitor.java
@@ -22,6 +22,8 @@ import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; +import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION; +import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION; import static com.android.networkstack.util.NetworkStackUtils.IP_REACHABILITY_MCAST_RESOLICIT_VERSION; import android.content.Context; @@ -233,6 +235,8 @@ @NonNull private final Callback mCallback; private final boolean mMulticastResolicitEnabled; + private final boolean mIgnoreIncompleteIpv6DnsServerEnabled; + private final boolean mIgnoreIncompleteIpv6DefaultRouterEnabled; public IpReachabilityMonitor( Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback, @@ -256,6 +260,12 @@ mDependencies = dependencies; mMulticastResolicitEnabled = dependencies.isFeatureEnabled(context, IP_REACHABILITY_MCAST_RESOLICIT_VERSION, false /* defaultEnabled */); + mIgnoreIncompleteIpv6DnsServerEnabled = dependencies.isFeatureEnabled(context, + IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, + false /* defaultEnabled */); + mIgnoreIncompleteIpv6DefaultRouterEnabled = dependencies.isFeatureEnabled(context, + IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, + false /* defaultEnabled */); mMetricsLog = metricsLog; mNetd = netd; Preconditions.checkNotNull(mNetd); @@ -286,7 +296,7 @@ // After both unicast probe and multicast probe(if mcast_resolicit is not 0) // attempts fail, trigger the neighbor lost event and disconnect. mLog.w("ALERT neighbor went from: " + prev + " to: " + event); - handleNeighborLost(event); + handleNeighborLost(prev, event); } else if (event.nudState == StructNdMsg.NUD_REACHABLE) { handleNeighborReachable(prev, event); } @@ -423,7 +433,22 @@ maybeRestoreNeighborParameters(); } - private void handleNeighborLost(NeighborEvent event) { + private boolean shouldIgnoreIncompleteIpv6Neighbor(@Nullable final NeighborEvent prev, + @NonNull final NeighborEvent event) { + // If it isn't IPv6 neighbor, return false. + if (!(event.ip instanceof Inet6Address)) return false; + + // If neighbor isn't in the watch list, return false. + if (!mNeighborWatchList.containsKey(event.ip)) return false; + + // For on-link IPv6 DNS server or default router that never ever responds to address + // resolution, kernel will send RTM_NEWNEIGH with NUD_FAILED to user space directly, + // and there is no netlink neighbor events related to this neighbor received before. + return (prev == null || event.nudState == StructNdMsg.NUD_FAILED); + } + + private void handleNeighborLost(@Nullable final NeighborEvent prev, + @NonNull final NeighborEvent event) { final LinkProperties whatIfLp = new LinkProperties(mLinkProperties); InetAddress ip = null; @@ -453,9 +478,39 @@ } } + final boolean ignoreIncompleteIpv6DnsServer = + mIgnoreIncompleteIpv6DnsServerEnabled + && isNeighborDnsServer(event) + && shouldIgnoreIncompleteIpv6Neighbor(prev, event); + + // Generally Router Advertisement should take SLLA option, then device won't do address + // resolution for default router's IPv6 link-local address automatically. But sometimes + // it may miss SLLA option, also add a flag to check these cases. + final boolean ignoreIncompleteIpv6DefaultRouter = + mIgnoreIncompleteIpv6DefaultRouterEnabled + && isNeighborDefaultRouter(event) + && shouldIgnoreIncompleteIpv6Neighbor(prev, event); + + // Only ignore the incomplete IPv6 neighbor iff IPv4 is still provisioned. For IPv6-only + // networks, we MUST not ignore any incomplete IPv6 neighbor. + final boolean ignoreIncompleteIpv6Neighbor = + (ignoreIncompleteIpv6DnsServer || ignoreIncompleteIpv6DefaultRouter) + && whatIfLp.isIpv4Provisioned(); + + // It's better to remove the incompleted on-link IPv6 DNS server or default router from + // watch list, otherwise, when wifi invokes probeAll later (e.g. post roam) to send probe + // to an incompleted on-link DNS server or default router, it should fail to send netlink + // message to kernel as there is no neighbor cache entry for it at all. + if (ignoreIncompleteIpv6Neighbor) { + Log.d(TAG, "remove incomplete IPv6 neighbor " + event.ip + + " which fails to respond to address resolution from watch list."); + mNeighborWatchList.remove(event.ip); + } + final boolean lostProvisioning = (mLinkProperties.isIpv4Provisioned() && !whatIfLp.isIpv4Provisioned()) - || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned()); + || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned() + && !ignoreIncompleteIpv6Neighbor); final NudEventType type = getNudFailureEventType(isFromProbe(), isNudFailureDueToRoam(), lostProvisioning);
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java index a3a58e6..60ebf78 100644 --- a/src/com/android/networkstack/netlink/TcpSocketTracker.java +++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -240,7 +240,7 @@ // Return true if there are more pending messages to read private boolean parseMessage(ByteBuffer bytes, int family, TcpStat stat, long time) { - if (!enoughBytesRemainForValidNlMsg(bytes)) { + if (!NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes)) { // This is unlikely to happen in real cases. Check this first for testing. Log.e(TAG, "Size is less than header size. Ignored."); return false; @@ -283,7 +283,7 @@ calculateLatestPacketsStat(info, mSocketInfos.get(cookie))); mSocketInfos.put(cookie, info); } - } while (enoughBytesRemainForValidNlMsg(bytes)); + } while (NetlinkUtils.enoughBytesRemainForValidNlMsg(bytes)); } catch (IllegalArgumentException | BufferUnderflowException e) { Log.wtf(TAG, "Unexpected socket info parsing, family " + family + " buffer:" + bytes + " " @@ -435,12 +435,6 @@ return mLatestReceivedCount; } - /** Check if the length and position of the given ByteBuffer is valid for a nlmsghdr message. */ - @VisibleForTesting - static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) { - return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE; - } - private static boolean isValidInetDiagMsgSize(final int nlMsgLen) { return nlMsgLen >= SOCKDIAG_MSG_HEADER_SIZE; }
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java index 5b329dd..0ae9589 100755 --- a/src/com/android/networkstack/util/NetworkStackUtils.java +++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -255,6 +255,20 @@ public static final String IP_REACHABILITY_MCAST_RESOLICIT_VERSION = "ip_reachability_mcast_resolicit_version"; + /** + * Experiment flag to attempt to ignore the on-link IPv6 DNS server which fails to respond to + * address resolution. + */ + public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION = + "ip_reachability_ignore_incompleted_ipv6_dns_server_version"; + + /** + * Experiment flag to attempt to ignore the IPv6 default router which fails to respond to + * address resolution. + */ + public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION = + "ip_reachability_ignore_incompleted_ipv6_default_router_version"; + static { System.loadLibrary("networkstackutilsjni"); }
diff --git a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java index 3cb651e..e36af57 100644 --- a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java +++ b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
@@ -18,6 +18,7 @@ import static android.Manifest.permission.MANAGE_TEST_NETWORKS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; @@ -36,7 +37,6 @@ import static android.net.dhcp.DhcpResultsParcelableUtil.fromStableParcelable; import static android.net.ip.IpClientLinkObserver.CLAT_PREFIX; import static android.net.ip.IpClientLinkObserver.CONFIG_SOCKET_RECV_BUFSIZE; -import static android.net.ip.IpReachabilityMonitor.MIN_NUD_SOLICIT_NUM; import static android.net.ip.IpReachabilityMonitor.NUD_MCAST_RESOLICIT_NUM; import static android.net.ip.IpReachabilityMonitor.nudEventTypeToInt; import static android.net.ipmemorystore.Status.SUCCESS; @@ -121,6 +121,7 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; +import android.net.Network; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkRequest; @@ -223,6 +224,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; +import java.net.DatagramPacket; +import java.net.DatagramSocket; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -384,6 +387,8 @@ private static final String IPV4_TEST_SUBNET_PREFIX = "192.168.1.0/24"; private static final String IPV4_ANY_ADDRESS_PREFIX = "0.0.0.0/0"; private static final String HOSTNAME = "testhostname"; + private static final String IPV6_OFF_LINK_DNS_SERVER = "2001:4860:4860::64"; + private static final String IPV6_ON_LINK_DNS_SERVER = "2001:db8:1::64"; private static final int TEST_DEFAULT_MTU = 1500; private static final int TEST_MIN_MTU = 1280; private static final MacAddress ROUTER_MAC = MacAddress.fromString("00:1A:11:22:33:44"); @@ -571,6 +576,10 @@ protected abstract void assertIpMemoryNeverStoreNetworkAttributes(String l2Key, long timeout); + protected abstract int readNudSolicitNumInSteadyStateFromResource(); + + protected abstract int readNudSolicitNumPostRoamingFromResource(); + protected final boolean testSkipped() { if (!useNetworkStackSignature() && !TestNetworkStackServiceClient.isSupported()) { fail("Device running root tests doesn't support TestNetworkStackServiceClient."); @@ -678,6 +687,7 @@ } if (mNetworkAgentThread != null) { mNetworkAgentThread.quitSafely(); + mNetworkAgentThread.join(); } teardownTapInterface(); mIIpClient.shutdown(); @@ -719,13 +729,14 @@ return iface; } - private void teardownTapInterface() { + private void teardownTapInterface() throws Exception { if (mPacketReader != null) { mHandler.post(() -> mPacketReader.stop()); // Also closes the socket mTapFd = null; } if (mPacketReaderThread != null) { mPacketReaderThread.quitSafely(); + mPacketReaderThread.join(); } } @@ -1585,6 +1596,7 @@ .addCapability(NET_CAPABILITY_NOT_SUSPENDED) .addCapability(NET_CAPABILITY_NOT_ROAMING) .addCapability(NET_CAPABILITY_NOT_VPN) + .addCapability(NET_CAPABILITY_NOT_RESTRICTED) .addTransportType(TRANSPORT_TEST) .setNetworkSpecifier(testNetworkSpecifier) .build(), @@ -1818,9 +1830,8 @@ private void sendRouterAdvertisement(boolean waitForRs, short lifetime, int valid, int preferred) throws Exception { - final String dnsServer = "2001:4860:4860::64"; final ByteBuffer pio = buildPioOption(valid, preferred, "2001:db8:1::/64"); - final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); + final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); sendRouterAdvertisement(waitForRs, lifetime, pio, rdnss); } @@ -1908,9 +1919,8 @@ private LinkProperties doIpv6OnlyProvisioning() throws Exception { final InOrder inOrder = inOrder(mCb); - final String dnsServer = "2001:4860:4860::64"; final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64"); - final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); + final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); final ByteBuffer slla = buildSllaOption(); final ByteBuffer ra = buildRaPacket(pio, rdnss, slla); @@ -2022,12 +2032,11 @@ .build(); startIpClientProvisioning(config); - final String dnsServer = "2001:4860:4860::64"; final IpPrefix prefix = new IpPrefix("64:ff9b::/96"); final IpPrefix otherPrefix = new IpPrefix("2001:db8:64::/96"); final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64"); - ByteBuffer rdnss = buildRdnssOption(600, dnsServer); + ByteBuffer rdnss = buildRdnssOption(600, IPV6_OFF_LINK_DNS_SERVER); ByteBuffer pref64 = new StructNdOptPref64(prefix, 600).toByteBuffer(); ByteBuffer ra = buildRaPacket(pio, rdnss, pref64); @@ -2827,15 +2836,22 @@ true /* shouldReplyNakOnRoam */); } - private void performDualStackProvisioning() throws Exception { - final InOrder inOrder = inOrder(mCb); - final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); - final String dnsServer = "2001:4860:4860::64"; + private LinkProperties performDualStackProvisioning() throws Exception { + final Inet6Address dnsServer = + (Inet6Address) InetAddresses.parseNumericAddress(IPV6_OFF_LINK_DNS_SERVER); final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64"); - final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); + final ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); final ByteBuffer slla = buildSllaOption(); final ByteBuffer ra = buildRaPacket(pio, rdnss, slla); + return performDualStackProvisioning(ra, dnsServer); + } + + private LinkProperties performDualStackProvisioning(final ByteBuffer ra, + final InetAddress dnsServer) throws Exception { + final InOrder inOrder = inOrder(mCb); + final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>(); + doIpv6OnlyProvisioning(inOrder, ra); // Start IPv4 provisioning and wait until entire provisioning completes. @@ -2849,10 +2865,10 @@ final LinkProperties lp = lpFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); assertNotNull(lp); - assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); + assertTrue(lp.getDnsServers().contains(dnsServer)); assertTrue(lp.getDnsServers().contains(SERVER_ADDR)); - clearInvocations(mCb); + return lp; } private void doDualStackProvisioning(boolean shouldDisableAcceptRa) throws Exception { @@ -3166,6 +3182,7 @@ } private void shutdownAndRecreateIpClient() throws Exception { + clearInvocations(mCb); mIpc.shutdown(); awaitIpClientShutdown(); mIpc = makeIpClient(); @@ -3792,7 +3809,8 @@ prepareIpReachabilityMonitorTest(); final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations(); - assertEquals(MIN_NUD_SOLICIT_NUM, nsList.size()); + final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource(); + assertEquals(expectedNudSolicitNum, nsList.size()); for (NeighborSolicitation ns : nsList) { assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */, ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); @@ -3835,13 +3853,14 @@ prepareIpReachabilityMonitorTest(true /* isMulticastResolicitEnabled */); final List<NeighborSolicitation> nsList = waitForMultipleNeighborSolicitations(); - int expectedSize = MIN_NUD_SOLICIT_NUM + NUD_MCAST_RESOLICIT_NUM; - assertEquals(expectedSize, nsList.size()); // 5 unicast NSes + 3 multicast NSes - for (NeighborSolicitation ns : nsList.subList(0, MIN_NUD_SOLICIT_NUM)) { + final int expectedNudSolicitNum = readNudSolicitNumPostRoamingFromResource(); + int expectedSize = expectedNudSolicitNum + NUD_MCAST_RESOLICIT_NUM; + assertEquals(expectedSize, nsList.size()); + for (NeighborSolicitation ns : nsList.subList(0, expectedNudSolicitNum)) { assertUnicastNeighborSolicitation(ns, ROUTER_MAC /* dstMac */, ROUTER_LINK_LOCAL /* dstIp */, ROUTER_LINK_LOCAL /* targetIp */); } - for (NeighborSolicitation ns : nsList.subList(MIN_NUD_SOLICIT_NUM, nsList.size())) { + for (NeighborSolicitation ns : nsList.subList(expectedNudSolicitNum, nsList.size())) { assertMulticastNeighborSolicitation(ns, ROUTER_LINK_LOCAL /* targetIp */); } } @@ -3904,6 +3923,132 @@ NudEventType.NUD_POST_ROAMING_MAC_ADDRESS_CHANGED); } + private void sendUdpPacketToNetwork(final Network network, final Inet6Address remoteIp, + int port, final byte[] data) throws Exception { + final DatagramSocket socket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY); + final DatagramPacket pkt = new DatagramPacket(data, data.length, remoteIp, port); + network.bindSocket(socket); + socket.send(pkt); + } + + private void runIpReachabilityMonitorAddressResolutionTest(final String dnsServer, + final Inet6Address targetIp, + final boolean isIgnoreIncompleteIpv6DnsServerEnabled, + final boolean isIgnoreIncompleteIpv6DefaultRouterEnabled, + final boolean expectNeighborLost) throws Exception { + // This mock is required, otherwise, IpReachabilityMonitor#avoidingBadLinks() will always + // return false, that results in the target tested IPv6 off-link DNS server won't be removed + // from LP and notifyLost won't be invoked. + when(mCm.shouldAvoidBadWifi()).thenReturn(true); + + mNetworkAgentThread = + new HandlerThread(IpClientIntegrationTestCommon.class.getSimpleName()); + mNetworkAgentThread.start(); + + setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */, + false /* isDhcpIpConflictDetectEnabled */, + false /* isIPv6OnlyPreferredEnabled */); + setFeatureEnabled( + NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION, + isIgnoreIncompleteIpv6DnsServerEnabled); + setFeatureEnabled( + NetworkStackUtils.IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION, + isIgnoreIncompleteIpv6DefaultRouterEnabled); + final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() + .build(); + startIpClientProvisioning(config); + verify(mCb, timeout(TEST_TIMEOUT_MS)).setFallbackMulticastFilter(false); + + final List<ByteBuffer> options = new ArrayList<ByteBuffer>(); + options.add(buildPioOption(3600, 1800, "2001:db8:1::/64")); // PIO + options.add(buildRdnssOption(3600, dnsServer)); // RDNSS + // If target IP of address resolution is default router's IPv6 link-local address, + // then we should not take SLLA option in RA. + if (!targetIp.equals(ROUTER_LINK_LOCAL)) { + options.add(buildSllaOption()); // SLLA + } + final ByteBuffer ra = buildRaPacket(options.toArray(new ByteBuffer[options.size()])); + final Inet6Address dnsServerIp = + (Inet6Address) InetAddresses.parseNumericAddress(dnsServer); + final LinkProperties lp = performDualStackProvisioning(ra, dnsServerIp); + runAsShell(MANAGE_TEST_NETWORKS, () -> createTestNetworkAgentAndRegister(lp)); + + // Send a UDP packet to IPv6 DNS server to trigger address resolution process for IPv6 + // on-link DNS server or default router(if the target is default router, we should pass + // in an IPv6 off-link DNS server such as 2001:db8:4860:4860::64). + final Random random = new Random(); + final byte[] data = new byte[100]; + random.nextBytes(data); + sendUdpPacketToNetwork(mNetworkAgent.getNetwork(), dnsServerIp, 1234 /* port */, data); + + // Wait for the multicast NSes but never respond to them, that results in the on-link + // DNS gets lost and onReachabilityLost callback will be invoked. + final List<NeighborSolicitation> nsList = new ArrayList<NeighborSolicitation>(); + NeighborSolicitation ns; + while ((ns = getNextNeighborSolicitation()) != null) { + // multicast NS for address resolution, IPv6 dst address in that NS is solicited-node + // multicast address based on the target IP, the target IP is either on-link IPv6 DNS + // server address or IPv6 link-local address of default gateway. + final LinkAddress actual = new LinkAddress(ns.nsHdr.target, 64); + final LinkAddress target = new LinkAddress(targetIp, 64); + if (actual.equals(target) && ns.ipv6Hdr.dstIp.isMulticastAddress()) { + nsList.add(ns); + } + } + assertFalse(nsList.isEmpty()); + + if (expectNeighborLost) { + assertNotifyNeighborLost(targetIp, NudEventType.NUD_ORGANIC_FAILED_CRITICAL); + } else { + assertNeverNotifyNeighborLost(); + } + } + + @Test + @SignatureRequiredTest(reason = "Need to mock NetworkAgent") + public void testIpReachabilityMonitor_incompleteIpv6DnsServerInDualStack() throws Exception { + final Inet6Address targetIp = + (Inet6Address) InetAddresses.parseNumericAddress(IPV6_ON_LINK_DNS_SERVER); + runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, + true /* isIgnoreIncompleteIpv6DnsServerEnabled */, + false /* isIgnoreIncompleteIpv6DefaultRouterEnabled */, + false /* expectNeighborLost */); + } + + @Test + @SignatureRequiredTest(reason = "Need to mock NetworkAgent") + public void testIpReachabilityMonitor_incompleteIpv6DnsServerInDualStack_flagoff() + throws Exception { + final Inet6Address targetIp = + (Inet6Address) InetAddresses.parseNumericAddress(IPV6_ON_LINK_DNS_SERVER); + runIpReachabilityMonitorAddressResolutionTest(IPV6_ON_LINK_DNS_SERVER, targetIp, + false /* isIgnoreIncompleteIpv6DnsServerEnabled */, + false /* isIgnoreIncompleteIpv6DefaultRouterEnabled */, + true /* expectNeighborLost */); + } + + @Test + @SignatureRequiredTest(reason = "Need to mock the NetworkAgent") + public void testIpReachabilityMonitor_incompleteIpv6DefaultRouterInDualStack() + throws Exception { + runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, + ROUTER_LINK_LOCAL /* targetIp */, + false /* isIgnoreIncompleteIpv6DnsServerEnabled */, + true /* isIgnoreIncompleteIpv6DefaultRouterEnabled */, + false /* expectNeighborLost */); + } + + @Test + @SignatureRequiredTest(reason = "Need to mock the NetworkAgent") + public void testIpReachabilityMonitor_incompleteIpv6DefaultRouterInDualStack_flagoff() + throws Exception { + runIpReachabilityMonitorAddressResolutionTest(IPV6_OFF_LINK_DNS_SERVER, + ROUTER_LINK_LOCAL /* targetIp */, + false /* isIgnoreIncompleteIpv6DnsServerEnabled */, + false /* isIgnoreIncompleteIpv6DefaultRouterEnabled */, + true /* expectNeighborLost */); + } + @Test public void testIPv6LinkLocalOnly() throws Exception { ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() @@ -3920,12 +4065,8 @@ assertEquals(0, lp.getDnsServers().size()); final List<LinkAddress> addresses = lp.getLinkAddresses(); assertEquals(1, addresses.size()); - assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); - assertEquals(1, lp.getRoutes().size()); - final RouteInfo route = lp.getRoutes().get(0); - assertNotNull(route); - assertTrue(route.getDestination().equals(new IpPrefix("fe80::/64"))); - assertTrue(route.getGateway().isAnyLocalAddress()); + assertTrue(addresses.get(0).getAddress().isLinkLocalAddress()); // only IPv6 link-local + assertTrue(hasRouteTo(lp, IPV6_LINK_LOCAL_PREFIX)); // fe80::/64 -> :: iface mtu 0 // Check that if an RA is received, no IP addresses, routes, or DNS servers are configured. // Instead of waiting some period of time for the RA to be received and checking the @@ -4077,16 +4218,15 @@ }); // Send large amount of RAs to overflow the netlink socket receive buffer. - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 200; i++) { sendBasicRouterAdvertisement(false /* waitRs */); } // Send another RA with a different IPv6 global prefix. This PIO option should be dropped // due to the ENOBUFS happens, it means IpClient shouldn't see the new IPv6 global prefix. - final String dnsServer = "2001:4860:4860::64"; final String prefix = "2001:db8:dead:beef::/64"; final ByteBuffer pio = buildPioOption(3600, 1800, prefix); - ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); + ByteBuffer rdnss = buildRdnssOption(3600, IPV6_OFF_LINK_DNS_SERVER); sendRouterAdvertisement(false /* waitForRs */, (short) 1800, pio, rdnss); // Unblock the IpClient handler and ENOBUFS should happen then.
diff --git a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt index 481bfdc..bff1088 100644 --- a/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt +++ b/tests/integration/common/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -35,8 +35,8 @@ private val TAG = "TestNetworkStackServiceClient" private val testNetworkStackServiceAction = "android.net.INetworkStackConnector.Test" private val context by lazy { InstrumentationRegistry.getInstrumentation().context } + private val component = getNetworkStackComponent(testNetworkStackServiceAction) private val networkStackVersion by lazy { - val component = getNetworkStackComponent(testNetworkStackServiceAction) val info = context.packageManager.getPackageInfo(component.packageName, 0 /* flags */) info.longVersionCode } @@ -88,4 +88,8 @@ fun disconnect() { InstrumentationRegistry.getInstrumentation().context.unbindService(serviceConnection) } + + fun getNetworkStackPackageName(): String { + return component.packageName + } }
diff --git a/tests/integration/root/android/net/ip/IpClientRootTest.kt b/tests/integration/root/android/net/ip/IpClientRootTest.kt index 7359e05..f1fa1c7 100644 --- a/tests/integration/root/android/net/ip/IpClientRootTest.kt +++ b/tests/integration/root/android/net/ip/IpClientRootTest.kt
@@ -22,8 +22,8 @@ import android.net.IIpMemoryStore import android.net.IIpMemoryStoreCallbacks import android.net.NetworkStackIpMemoryStore -import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener import android.net.ipmemorystore.NetworkAttributes +import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener import android.net.ipmemorystore.Status import android.net.networkstack.TestNetworkStackServiceClient import android.os.Process @@ -265,4 +265,19 @@ override fun storeNetworkAttributes(l2Key: String, na: NetworkAttributes) { mStore.storeNetworkAttributes(l2Key, na, null /* listener */) } + + private fun readNudSolicitNumFromResource(name: String): Int { + val packageName = nsClient.getNetworkStackPackageName() + val resource = mContext.createPackageContext(packageName, 0).getResources() + val id = resource.getIdentifier(name, "integer", packageName) + return resource.getInteger(id) + } + + override fun readNudSolicitNumInSteadyStateFromResource(): Int { + return readNudSolicitNumFromResource("config_nud_steadystate_solicit_num") + } + + override fun readNudSolicitNumPostRoamingFromResource(): Int { + return readNudSolicitNumFromResource("config_nud_postroaming_solicit_num") + } }
diff --git a/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt b/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt index c9e33b5..26938b6 100644 --- a/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt +++ b/tests/integration/signature/android/net/ip/IpClientSignatureTest.kt
@@ -21,9 +21,9 @@ import android.net.ipmemorystore.Status import android.net.ipmemorystore.Status.SUCCESS import android.util.ArrayMap +import org.mockito.ArgumentCaptor import org.mockito.Mockito.any import org.mockito.Mockito.doAnswer -import org.mockito.ArgumentCaptor import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.timeout @@ -33,6 +33,9 @@ * Tests for IpClient, run with signature permissions. */ class IpClientSignatureTest : IpClientIntegrationTestCommon() { + private val DEFAULT_NUD_SOLICIT_NUM_POST_ROAM = 5 + private val DEFAULT_NUD_SOLICIT_NUM_STEADY_STATE = 10 + private val mEnabledFeatures = ArrayMap<String, Boolean>() override fun makeIIpClient(ifaceName: String, cb: IIpClientCallbacks): IIpClient { @@ -68,4 +71,12 @@ true }.`when`(mIpMemoryStore).retrieveNetworkAttributes(eq(l2Key), any()) } + + override fun readNudSolicitNumInSteadyStateFromResource(): Int { + return DEFAULT_NUD_SOLICIT_NUM_STEADY_STATE + } + + override fun readNudSolicitNumPostRoamingFromResource(): Int { + return DEFAULT_NUD_SOLICIT_NUM_POST_ROAM + } }
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java index 85d3842..968acee 100644 --- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java +++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -54,6 +54,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.build.SdkLevel; +import com.android.net.module.util.netlink.NetlinkUtils; import com.android.net.module.util.netlink.StructNlMsgHdr; import com.android.networkstack.apishim.ConstantsShim; import com.android.testutils.DevSdkIgnoreRule; @@ -189,13 +190,13 @@ final ByteBuffer buffer = ByteBuffer.allocate(TEST_BUFFER_SIZE); buffer.position(TEST_BUFFER_SIZE - StructNlMsgHdr.STRUCT_SIZE); - assertTrue(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer)); + assertTrue(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer)); // Remaining buffer size is less than a valid StructNlMsgHdr size. buffer.position(TEST_BUFFER_SIZE - StructNlMsgHdr.STRUCT_SIZE + 1); - assertFalse(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer)); + assertFalse(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer)); buffer.position(TEST_BUFFER_SIZE); - assertFalse(TcpSocketTracker.enoughBytesRemainForValidNlMsg(buffer)); + assertFalse(NetlinkUtils.enoughBytesRemainForValidNlMsg(buffer)); } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // TCP info parsing is not supported on Q