Snap for 7357013 from a30388b8eb26e1212f4cecb7485f32adbfc82e92 to sc-v2-release
Change-Id: I07da1021ee2d4820e3625a615472fd78672526f6
diff --git a/apishim/30/com/android/networkstack/apishim/api30/SettingsShimImpl.java b/apishim/30/com/android/networkstack/apishim/api30/SettingsShimImpl.java
new file mode 100644
index 0000000..b8188c6
--- /dev/null
+++ b/apishim/30/com/android/networkstack/apishim/api30/SettingsShimImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.networkstack.apishim.api30;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.networkstack.apishim.common.SettingsShim;
+
+/**
+ * Implementation of {@link SettingsShim} for API 30.
+ */
+public class SettingsShimImpl implements SettingsShim {
+ protected SettingsShimImpl() { }
+
+ /**
+ * Get a new instance of {@link SettingsShim}.
+ *
+ * Use com.android.networkstack.apishim.SeetingsShim#newInstance()
+ * (non-API30 version) instead, to use the correct shims depending on build SDK.
+ */
+ public static SettingsShim newInstance() {
+ return new SettingsShimImpl();
+ }
+
+ @Override
+ public boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
+ @NonNull String callingPackage, @Nullable String callingAttributionTag,
+ boolean throwException) {
+ return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
+ throwException);
+ }
+}
diff --git a/apishim/31/com/android/networkstack/apishim/SettingsShimImpl.java b/apishim/31/com/android/networkstack/apishim/SettingsShimImpl.java
new file mode 100644
index 0000000..e15872f
--- /dev/null
+++ b/apishim/31/com/android/networkstack/apishim/SettingsShimImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.networkstack.apishim;
+
+import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.networkstack.apishim.common.SettingsShim;
+import com.android.networkstack.apishim.common.ShimUtils;
+
+/**
+ * Implementation of {@link SettingsShim} for API 31.
+ */
+public class SettingsShimImpl
+ extends com.android.networkstack.apishim.api30.SettingsShimImpl {
+ protected SettingsShimImpl() { }
+
+ /**
+ * Get a new instance of {@link SettingsShim}.
+ */
+ public static SettingsShim newInstance() {
+ if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.R)) {
+ return com.android.networkstack.apishim.api30.SettingsShimImpl
+ .newInstance();
+ }
+ return new SettingsShimImpl();
+ }
+
+ @Override
+ public boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
+ @NonNull String callingPackage, @Nullable String callingAttributionTag,
+ boolean throwException) {
+ // Since checkAndNoteWriteSettingsOperation with callingAttributionTag (S method) is not
+ // available in AOSP, calling R method (same as API 30 shim) temporary.
+ return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
+ throwException);
+ }
+}
diff --git a/apishim/common/com/android/networkstack/apishim/common/SettingsShim.java b/apishim/common/com/android/networkstack/apishim/common/SettingsShim.java
new file mode 100644
index 0000000..2453084
--- /dev/null
+++ b/apishim/common/com/android/networkstack/apishim/common/SettingsShim.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package com.android.networkstack.apishim.common;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Interce for accessing API methods in {@link android.provider.Settings} by different API level.
+ */
+public interface SettingsShim {
+ /**
+ * @see android.provider.Settings#checkAndNoteWriteSettingsOperation(Context, int, String,
+ * String, boolean)
+ */
+ boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
+ @NonNull String callingPackage, @Nullable String callingAttributionTag,
+ boolean throwException);
+}
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java
index 0bb4094..34469b8 100644
--- a/src/android/net/apf/ApfFilter.java
+++ b/src/android/net/apf/ApfFilter.java
@@ -27,6 +27,7 @@
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_RAW;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
@@ -285,8 +286,6 @@
private static final int ETH_ETHERTYPE_OFFSET = 12;
private static final int ETH_TYPE_MIN = 0x0600;
private static final int ETH_TYPE_MAX = 0xFFFF;
- private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
- {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
// TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
@@ -1254,7 +1253,7 @@
// Pass if unicast reply.
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
// Either a unicast request, a unicast reply, or a broadcast reply.
gen.defineLabel(checkTargetIPv4);
@@ -1350,7 +1349,7 @@
// TODO: can we invert this condition to fall through to the common pass case below?
maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
gen.addJump(mCountAndDropLabel);
} else {
@@ -1412,7 +1411,7 @@
// pass
// if it's ICMPv6 RS to any:
// drop
- // if it's ICMPv6 NA to ff02::1:
+ // if it's ICMPv6 NA to ff02::1 or ff02::2:
// drop
// if keepalive ack
// drop
@@ -1466,11 +1465,14 @@
gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
// If not neighbor announcements, skip filter.
gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
- // If to ff02::1, drop.
+ // Drop all multicast NA to ff02::/120.
+ // This is a way to cover ff02::1 and ff02::2 with a single JNEBS.
// TODO: Drop only if they don't contain the address of on-link neighbours.
+ final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15);
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
+ gen.addJumpIfBytesNotEqual(Register.R0, unsolicitedNaDropPrefix,
skipUnsolicitedMulticastNALabel);
+
maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
gen.addJump(mCountAndDropLabel);
gen.defineLabel(skipUnsolicitedMulticastNALabel);
@@ -1493,7 +1495,7 @@
* <li>Drop all broadcast non-IP non-ARP packets.
* <li>Pass all non-ICMPv6 IPv6 packets,
* <li>Pass all non-IPv4 and non-IPv6 packets,
- * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
+ * <li>Drop IPv6 ICMPv6 NAs to ff02::1 or ff02::2.
* <li>Drop IPv6 ICMPv6 RSs.
* <li>Filter IPv4 packets (see generateIPv4FilterLocked())
* <li>Filter IPv6 packets (see generateIPv6FilterLocked())
@@ -1569,7 +1571,7 @@
// Drop non-IP non-ARP broadcasts, pass the rest
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
gen.addJump(mCountAndDropLabel);
diff --git a/src/android/net/apf/ApfGenerator.java b/src/android/net/apf/ApfGenerator.java
index 44ce2db..bf4d910 100644
--- a/src/android/net/apf/ApfGenerator.java
+++ b/src/android/net/apf/ApfGenerator.java
@@ -752,7 +752,8 @@
/**
* Add an instruction to the end of the program to jump to {@code target} if the bytes of the
- * packet at an offset specified by {@code register} match {@code bytes}.
+ * packet at an offset specified by {@code register} don't match {@code bytes}, {@code register}
+ * must be R0.
*/
public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target)
throws IllegalInstructionException {
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 980c6d6..b719df2 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -18,13 +18,18 @@
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.dhcp.DhcpResultsParcelableUtil.toStableParcelable;
+import static android.net.util.NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION;
import static android.net.util.NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION;
+import static android.net.util.SocketUtils.makePacketSocketAddress;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_ARP;
import static android.system.OsConstants.ETH_P_IPV6;
import static android.system.OsConstants.SOCK_NONBLOCK;
import static android.system.OsConstants.SOCK_RAW;
+import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST;
import static com.android.net.module.util.NetworkStackConstants.VENDOR_SPECIFIC_IE_ID;
import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission;
@@ -91,6 +96,7 @@
import com.android.networkstack.apishim.SocketUtilsShimImpl;
import com.android.networkstack.apishim.common.NetworkInformationShim;
import com.android.networkstack.apishim.common.ShimUtils;
+import com.android.networkstack.arp.ArpPacket;
import com.android.networkstack.metrics.IpProvisioningMetrics;
import com.android.networkstack.packets.NeighborAdvertisement;
import com.android.server.NetworkObserverRegistry;
@@ -98,6 +104,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
@@ -839,6 +846,11 @@
false /* defaultEnabled */);
}
+ private boolean isGratuitousArpNaRoamingEnabled() {
+ return mDependencies.isFeatureEnabled(mContext, IPCLIENT_GARP_NA_ROAMING_VERSION,
+ false /* defaultEnabled */);
+ }
+
@Override
protected void onQuitting() {
mCallback.onQuit();
@@ -1423,30 +1435,47 @@
}
}
- private void sendGratuitousNA(final Inet6Address srcIp, final Inet6Address target) {
- final int flags = 0; // R=0, S=0, O=0
- final Inet6Address dstIp = IPV6_ADDR_ALL_ROUTERS_MULTICAST;
- // Ethernet multicast destination address: 33:33:00:00:00:02.
- final MacAddress dstMac = NetworkStackUtils.ipv6MulticastToEthernetMulticast(dstIp);
- final ByteBuffer packet = NeighborAdvertisement.build(mInterfaceParams.macAddr, dstMac,
- srcIp, dstIp, flags, target);
+ private void transmitPacket(final ByteBuffer packet, final SocketAddress sockAddress,
+ final String msg) {
FileDescriptor sock = null;
try {
sock = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0 /* protocol */);
- final SocketAddress sockAddress =
- SocketUtilsShimImpl.newInstance().makePacketSocketAddress(ETH_P_IPV6,
- mInterfaceParams.index, dstMac.toByteArray());
Os.sendto(sock, packet.array(), 0 /* byteOffset */, packet.limit() /* byteCount */,
0 /* flags */, sockAddress);
} catch (SocketException | ErrnoException e) {
- logError("Fail to send Gratuitous Neighbor Advertisement", e);
+ logError(msg, e);
} finally {
NetworkStackUtils.closeSocketQuietly(sock);
}
}
- private Inet6Address getIpv6LinkLocalAddress(final LinkProperties newLp) {
- Inet6Address src = null;
+ private void sendGratuitousNA(final Inet6Address srcIp, final Inet6Address targetIp) {
+ final int flags = 0; // R=0, S=0, O=0
+ final Inet6Address dstIp = IPV6_ADDR_ALL_ROUTERS_MULTICAST;
+ // Ethernet multicast destination address: 33:33:00:00:00:02.
+ final MacAddress dstMac = NetworkStackUtils.ipv6MulticastToEthernetMulticast(dstIp);
+ final ByteBuffer packet = NeighborAdvertisement.build(mInterfaceParams.macAddr, dstMac,
+ srcIp, dstIp, flags, targetIp);
+ final SocketAddress sockAddress =
+ SocketUtilsShimImpl.newInstance().makePacketSocketAddress(ETH_P_IPV6,
+ mInterfaceParams.index, dstMac.toByteArray());
+
+ transmitPacket(packet, sockAddress, "Failed to send Gratuitous Neighbor Advertisement");
+ }
+
+ private void sendGratuitousARP(final Inet4Address srcIp) {
+ final ByteBuffer packet = ArpPacket.buildArpPacket(ETHER_BROADCAST /* dstMac */,
+ mInterfaceParams.macAddr.toByteArray() /* srcMac */,
+ srcIp.getAddress() /* targetIp */,
+ ETHER_BROADCAST /* targetHwAddress */,
+ srcIp.getAddress() /* senderIp */, (short) ARP_REPLY);
+ final SocketAddress sockAddress =
+ makePacketSocketAddress(ETH_P_ARP, mInterfaceParams.index);
+
+ transmitPacket(packet, sockAddress, "Failed to send GARP");
+ }
+
+ private static Inet6Address getIpv6LinkLocalAddress(final LinkProperties newLp) {
for (LinkAddress la : newLp.getLinkAddresses()) {
if (!la.isIpv6()) continue;
final Inet6Address ip = (Inet6Address) la.getAddress();
@@ -1455,22 +1484,40 @@
return null;
}
- private void maybeSendGratuitousNAs(final LinkProperties newLp) {
- if (!newLp.hasGlobalIpv6Address() || !isGratuitousNaEnabled()) return;
+ private void maybeSendGratuitousNAs(final LinkProperties lp, boolean afterRoaming) {
+ if (!lp.hasGlobalIpv6Address()) return;
- final Inet6Address src = getIpv6LinkLocalAddress(newLp);
- if (src == null) return;
- for (LinkAddress la : newLp.getLinkAddresses()) {
+ final Inet6Address srcIp = getIpv6LinkLocalAddress(lp);
+ if (srcIp == null) return;
+
+ // TODO: add experiment with sending only one gratuitous NA packet instead of one
+ // packet per address.
+ for (LinkAddress la : lp.getLinkAddresses()) {
if (!la.isIpv6() || !la.isGlobalPreferred()) continue;
final Inet6Address targetIp = (Inet6Address) la.getAddress();
- // Already sent gratuitous NA with this target global IPv6 address.
- if (mGratuitousNaTargetAddresses.contains(targetIp)) continue;
+ // Already sent gratuitous NA with this target global IPv6 address. But for
+ // the L2 roaming case, device should always (re)transmit Gratuitous NA for
+ // each IPv6 global unicast address respectively after roaming.
+ if (!afterRoaming && mGratuitousNaTargetAddresses.contains(targetIp)) continue;
if (DBG) {
- Log.d(mTag, "send Gratuitous NA from " + src + ", target Address is "
- + targetIp);
+ mLog.log("send Gratuitous NA from " + srcIp.getHostAddress() + " for "
+ + targetIp.getHostAddress() + (afterRoaming ? " after roaming" : ""));
}
- sendGratuitousNA(src, targetIp);
- mGratuitousNaTargetAddresses.add(targetIp);
+ sendGratuitousNA(srcIp, targetIp);
+ if (!afterRoaming) mGratuitousNaTargetAddresses.add(targetIp);
+ }
+ }
+
+ private void maybeSendGratuitousARP(final LinkProperties lp) {
+ for (LinkAddress address : lp.getLinkAddresses()) {
+ if (address.getAddress() instanceof Inet4Address) {
+ final Inet4Address srcIp = (Inet4Address) address.getAddress();
+ if (DBG) {
+ mLog.log("send GARP for " + srcIp.getHostAddress() + " HW address: "
+ + mInterfaceParams.macAddr);
+ }
+ sendGratuitousARP(srcIp);
+ }
}
}
@@ -1484,7 +1531,9 @@
// Check if new assigned IPv6 GUA is available in the LinkProperties now. If so, initiate
// gratuitous multicast unsolicited Neighbor Advertisements as soon as possible to inform
// first-hop routers that the new GUA host is goning to use.
- maybeSendGratuitousNAs(newLp);
+ if (isGratuitousNaEnabled()) {
+ maybeSendGratuitousNAs(newLp, false /* isGratuitousNaAfterRoaming */);
+ }
// Either success IPv4 or IPv6 provisioning triggers new LinkProperties update,
// wait for the provisioning completion and record the latency.
@@ -1741,6 +1790,13 @@
// If the BSSID has not changed, there is nothing to do.
if (info.bssid.equals(mCurrentBssid)) return;
+ // Before trigger probing to the interesting neighbors, send Gratuitous ARP
+ // and Neighbor Advertisment in advance to propgate host's IPv4/v6 addresses.
+ if (isGratuitousArpNaRoamingEnabled()) {
+ maybeSendGratuitousARP(mLinkProperties);
+ maybeSendGratuitousNAs(mLinkProperties, true /* isGratuitousNaAfterRoaming */);
+ }
+
if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.probeAll();
}
diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java
index 6e32833..098ce2e 100755
--- a/src/android/net/util/NetworkStackUtils.java
+++ b/src/android/net/util/NetworkStackUtils.java
@@ -242,6 +242,13 @@
*/
public static final String IPCLIENT_GRATUITOUS_NA_VERSION = "ipclient_gratuitous_na_version";
+ /**
+ * Experiment flag to enable sending Gratuitous APR and Gratuitous Neighbor Advertisement for
+ * all assigned IPv4 and IPv6 GUAs after completing L2 roaming.
+ */
+ public static final String IPCLIENT_GARP_NA_ROAMING_VERSION =
+ "ipclient_garp_na_roaming_version";
+
static {
System.loadLibrary("networkstackutilsjni");
}
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index 985cb22..7bc6a49 100755
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -123,6 +123,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.stats.connectivity.ProbeResult;
@@ -218,6 +219,9 @@
private static final String TAG = NetworkMonitor.class.getSimpleName();
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ // TODO(b/185082309): For flaky test debug only, remove it after fixing.
+ private static final boolean DDBG_STALL = "cf_x86_auto-userdebug".equals(
+ SystemProperties.get("ro.build.flavor", ""));
private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
@@ -3218,6 +3222,10 @@
// considered in the evaluation happened in defined threshold time.
final long now = SystemClock.elapsedRealtime();
final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp;
+ if (DDBG_STALL) {
+ Log.d(TAG, "DSD.isDataStallSuspected, first="
+ + firstTimeoutTime + ", valid=" + validTime);
+ }
return (firstTimeoutTime < validTime);
}
@@ -3272,12 +3280,17 @@
int typeToCollect = 0;
final int notStall = -1;
- final StringJoiner msg = (DBG || VDBG_STALL) ? new StringJoiner(", ") : null;
+ final StringJoiner msg = (DBG || VDBG_STALL || DDBG_STALL) ? new StringJoiner(", ") : null;
// Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the
// possible traffic cost in metered network.
+ final long currentTime = SystemClock.elapsedRealtime();
if (!mNetworkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
- && (SystemClock.elapsedRealtime() - getLastProbeTime()
- < mDataStallMinEvaluateTime)) {
+ && (currentTime - getLastProbeTime() < mDataStallMinEvaluateTime)) {
+ if (DDBG_STALL) {
+ Log.d(TAG, "isDataStall: false, currentTime=" + currentTime
+ + ", lastProbeTime=" + getLastProbeTime()
+ + ", MinEvaluateTime=" + mDataStallMinEvaluateTime);
+ }
return false;
}
// Check TCP signal. Suspect it may be a data stall if :
@@ -3290,7 +3303,7 @@
} else if (tst.isDataStallSuspected()) {
typeToCollect |= DATA_STALL_EVALUATION_TYPE_TCP;
}
- if (DBG || VDBG_STALL) {
+ if (DBG || VDBG_STALL || DDBG_STALL) {
msg.add("tcp packets received=" + tst.getLatestReceivedCount())
.add("latest tcp fail rate=" + tst.getLatestPacketFailPercentage());
}
@@ -3307,7 +3320,7 @@
typeToCollect |= DATA_STALL_EVALUATION_TYPE_DNS;
logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND);
}
- if (DBG || VDBG_STALL) {
+ if (DBG || VDBG_STALL || DDBG_STALL) {
msg.add("consecutive dns timeout count=" + dsd.getConsecutiveTimeoutCount());
}
}
@@ -3332,7 +3345,7 @@
}
// log only data stall suspected.
- if ((DBG && (typeToCollect > 0)) || VDBG_STALL) {
+ if ((DBG && (typeToCollect > 0)) || VDBG_STALL || DDBG_STALL) {
log("isDataStall: result=" + typeToCollect + ", " + msg);
}
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
index 9dd97ff..e217e91 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
@@ -37,6 +37,7 @@
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.ETHER_ADDR_LEN;
+import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN;
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
@@ -1121,6 +1122,14 @@
assertEquals(packet.senderIp, CLIENT_ADDR);
}
+ private void assertGratuitousARP(final ArpPacket packet) {
+ assertEquals(packet.opCode, ARP_REPLY);
+ assertEquals(packet.senderIp, CLIENT_ADDR);
+ assertEquals(packet.targetIp, CLIENT_ADDR);
+ assertTrue(Arrays.equals(packet.senderHwAddress.toByteArray(), mClientMac));
+ assertTrue(Arrays.equals(packet.targetHwAddress.toByteArray(), ETHER_BROADCAST));
+ }
+
private void doIpAddressConflictDetectionTest(final boolean causeIpAddressConflict,
final boolean shouldReplyRapidCommitAck, final boolean isDhcpIpConflictDetectEnabled,
final boolean shouldResponseArpReply) throws Exception {
@@ -1537,6 +1546,16 @@
return addr.isGlobalPreferred() && hasFlag(addr, flag);
}
+ 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 ra = buildRaPacket(pio, rdnss);
+
+ return doIpv6OnlyProvisioning(inOrder, ra);
+ }
+
private LinkProperties doIpv6OnlyProvisioning(InOrder inOrder, ByteBuffer ra) throws Exception {
waitForRouterSolicitation();
mPacketReader.sendResponse(ra);
@@ -2234,6 +2253,14 @@
true /* expectMetered */);
}
+ private void forceLayer2Roaming() throws Exception {
+ final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable();
+ roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID);
+ roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY;
+ roamingInfo.cluster = TEST_DHCP_ROAM_CLUSTER;
+ mIIpClient.updateLayer2Information(roamingInfo);
+ }
+
private void doDhcpRoamingTest(final boolean hasMismatchedIpAddress, final String displayName,
final String ssid, final String bssid, final boolean expectRoaming) throws Exception {
long currentTime = System.currentTimeMillis();
@@ -2260,11 +2287,7 @@
assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
// simulate the roaming by updating bssid.
- final Layer2InformationParcelable roamingInfo = new Layer2InformationParcelable();
- roamingInfo.bssid = MacAddress.fromString(TEST_DHCP_ROAM_BSSID);
- roamingInfo.l2Key = TEST_DHCP_ROAM_L2KEY;
- roamingInfo.cluster = TEST_DHCP_ROAM_CLUSTER;
- mIpc.updateLayer2Information(roamingInfo);
+ forceLayer2Roaming();
currentTime = System.currentTimeMillis();
reset(mIpMemoryStore);
@@ -2338,18 +2361,7 @@
TEST_DHCP_ROAM_SSID, TEST_DEFAULT_BSSID, true /* expectRoaming */);
}
- private void doDualStackProvisioning() throws Exception {
- when(mCm.shouldAvoidBadWifi()).thenReturn(true);
-
- final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
- .withoutIpReachabilityMonitor()
- .build();
- // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
- // not strictly necessary.
- setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
- false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
- mIpc.startProvisioning(config);
-
+ private void performDualStackProvisioning() throws Exception {
final InOrder inOrder = inOrder(mCb);
final CompletableFuture<LinkProperties> lpFuture = new CompletableFuture<>();
final String dnsServer = "2001:4860:4860::64";
@@ -2376,6 +2388,21 @@
reset(mCb);
}
+ private void doDualStackProvisioning() throws Exception {
+ when(mCm.shouldAvoidBadWifi()).thenReturn(true);
+
+ final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+ .withoutIpReachabilityMonitor()
+ .build();
+ // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
+ // not strictly necessary.
+ setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
+ false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
+ mIpc.startProvisioning(config);
+
+ performDualStackProvisioning();
+ }
+
@Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
public void testIgnoreIpv6ProvisioningLoss() throws Exception {
doDualStackProvisioning();
@@ -2796,7 +2823,7 @@
}
@Test
- public void testGratuitousNa() throws Exception {
+ public void testGratuitousNaForNewGlobalUnicastAddresses() throws Exception {
final ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
.withoutIpReachabilityMonitor()
.withoutIPv4()
@@ -2807,13 +2834,7 @@
assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GRATUITOUS_NA_VERSION, false));
startIpClientProvisioning(config);
- 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 ra = buildRaPacket(pio, rdnss);
-
- doIpv6OnlyProvisioning(inOrder, ra);
+ doIpv6OnlyProvisioning();
final List<NeighborAdvertisement> naList = new ArrayList<>();
NeighborAdvertisement packet;
@@ -2823,4 +2844,104 @@
}
assertEquals(2, naList.size()); // privacy address and stable privacy address
}
+
+ private void startGratuitousArpAndNaAfterRoamingTest(boolean isGratuitousArpNaRoamingEnabled,
+ boolean hasIpv4, boolean hasIpv6) throws Exception {
+ final ScanResultInfo scanResultInfo =
+ makeScanResultInfo(TEST_DEFAULT_SSID, TEST_DEFAULT_BSSID);
+ final ProvisioningConfiguration.Builder prov = new ProvisioningConfiguration.Builder()
+ .withoutIpReachabilityMonitor()
+ .withScanResultInfo(scanResultInfo)
+ .withDisplayName("ssid");
+ if (!hasIpv4) prov.withoutIPv4();
+ if (!hasIpv6) prov.withoutIPv6();
+
+ // Enable rapid commit to accelerate DHCP handshake to shorten test duration,
+ // not strictly necessary.
+ setDhcpFeatures(false /* isDhcpLeaseCacheEnabled */, true /* isRapidCommitEnabled */,
+ false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
+ if (isGratuitousArpNaRoamingEnabled) {
+ setFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, true);
+ assertTrue(isFeatureEnabled(NetworkStackUtils.IPCLIENT_GARP_NA_ROAMING_VERSION, false));
+ }
+ startIpClientProvisioning(prov.build());
+ }
+
+ private void waitForGratuitousArpAndNaPacket(final List<ArpPacket> arpList,
+ final List<NeighborAdvertisement> naList) throws Exception {
+ NeighborAdvertisement na;
+ ArpPacket garp;
+ do {
+ na = getNextNeighborAdvertisement();
+ if (na != null) {
+ assertGratuitousNa(na);
+ naList.add(na);
+ }
+ garp = getNextArpPacket(TEST_TIMEOUT_MS);
+ if (garp != null) {
+ assertGratuitousARP(garp);
+ arpList.add(garp);
+ }
+ } while (na != null || garp != null);
+ }
+
+ @Test
+ public void testGratuitousArpAndNaAfterRoaming() throws Exception {
+ startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
+ true /* hasIpv4 */, true /* hasIpv6 */);
+ performDualStackProvisioning();
+ forceLayer2Roaming();
+
+ final List<ArpPacket> arpList = new ArrayList<>();
+ final List<NeighborAdvertisement> naList = new ArrayList<>();
+ waitForGratuitousArpAndNaPacket(arpList, naList);
+ assertEquals(2, naList.size()); // privacy address and stable privacy address
+ assertEquals(1, arpList.size()); // IPv4 address
+ }
+
+ @Test
+ public void testGratuitousArpAndNaAfterRoaming_disableExpFlag() throws Exception {
+ startGratuitousArpAndNaAfterRoamingTest(false /* isGratuitousArpNaRoamingEnabled */,
+ true /* hasIpv6 */, true /* hasIpv6 */);
+ performDualStackProvisioning();
+ forceLayer2Roaming();
+
+ final List<ArpPacket> arpList = new ArrayList<>();
+ final List<NeighborAdvertisement> naList = new ArrayList<>();
+ waitForGratuitousArpAndNaPacket(arpList, naList);
+ assertEquals(0, naList.size());
+ assertEquals(0, arpList.size());
+ }
+
+ @Test
+ public void testGratuitousArpAndNaAfterRoaming_IPv6OnlyNetwork() throws Exception {
+ startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
+ false /* hasIpv4 */, true /* hasIpv6 */);
+ doIpv6OnlyProvisioning();
+ forceLayer2Roaming();
+
+ final List<ArpPacket> arpList = new ArrayList<>();
+ final List<NeighborAdvertisement> naList = new ArrayList<>();
+ waitForGratuitousArpAndNaPacket(arpList, naList);
+ assertEquals(2, naList.size());
+ assertEquals(0, arpList.size());
+ }
+
+ @Test
+ public void testGratuitousArpAndNaAfterRoaming_IPv4OnlyNetwork() throws Exception {
+ startGratuitousArpAndNaAfterRoamingTest(true /* isGratuitousArpNaRoamingEnabled */,
+ true /* hasIpv4 */, false /* hasIpv6 */);
+
+ // Start IPv4 provisioning and wait until entire provisioning completes.
+ handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S,
+ true /* shouldReplyRapidCommitAck */, TEST_DEFAULT_MTU, null /* serverSentUrl */);
+ verifyIPv4OnlyProvisioningSuccess(Collections.singletonList(CLIENT_ADDR));
+ forceLayer2Roaming();
+
+ final List<ArpPacket> arpList = new ArrayList<>();
+ final List<NeighborAdvertisement> naList = new ArrayList<>();
+ waitForGratuitousArpAndNaPacket(arpList, naList);
+ assertEquals(0, naList.size());
+ assertEquals(1, arpList.size());
+ }
}
diff --git a/tests/unit/src/android/net/apf/ApfTest.java b/tests/unit/src/android/net/apf/ApfTest.java
index 416a6c3..b6de3a1 100644
--- a/tests/unit/src/android/net/apf/ApfTest.java
+++ b/tests/unit/src/android/net/apf/ApfTest.java
@@ -1056,6 +1056,10 @@
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
+ private static final byte[] IPV6_SOLICITED_NODE_MULTICAST_ADDRESS = {
+ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ (byte) 0xff, (byte) 0xab, (byte) 0xcd, (byte) 0xef,
+ };
private static final int ICMP6_TYPE_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
private static final int ICMP6_ROUTER_SOLICITATION = 133;
@@ -1241,6 +1245,14 @@
put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
assertDrop(program, packet.array());
+ // Verify ICMPv6 NA to ff02::2 is dropped
+ put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
+ assertDrop(program, packet.array());
+
+ // Verify ICMPv6 NA to Solicited-Node Multicast is passed
+ put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODE_MULTICAST_ADDRESS);
+ assertPass(program, packet.array());
+
// Verify ICMPv6 RS to any is dropped
packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
assertDrop(program, packet.array());