Snap for 6001391 from 8ee5b28804b96b7f7eba7a47893e4c8a2169a5c8 to qt-aml-resolv-release
Change-Id: I43031b34e34373548c130d6b48876a641b9c463f
diff --git a/Android.bp b/Android.bp
index f17412d..762ace9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,20 +19,26 @@
// (InProcessNetworkStack). The following structure is used to create the build rules:
//
// NetworkStackAndroidLibraryDefaults <-- common defaults for android libs
-// / \
-// +NetworkStackApiStableShims --> / \ <-- +NetworkStackApiCurrentShims
-// +NetworkStackApiStableLevel / \ +NetworkStackApiCurrentLevel
-// / \
-// NetworkStackApiStableLib NetworkStackApiCurrentLib <-- android libs w/ all code
-// | | (also used in unit tests)
-// | <-- +NetworkStackAppDefaults --> |
-// | (APK build params) |
-// | |
-// | <-- +NetworkStackApiStableLevel | <-- +NetworkStackApiCurrentLevel
-// | |
-// | |
-// NetworkStackApiStable NetworkStack, InProcessNetworkStack, <-- output APKs
-// TestNetworkStack
+// / \
+// +NetworkStackApiStableShims --> / \ <-- +NetworkStackApiCurrentShims
+// +NetworkStackApiStableLevel / \ +NetworkStackApiCurrentLevel
+// +jarjar apistub.api[latest].* / \ +module src/
+// to apistub.* / \
+// / \
+// NetworkStackApiStableDependencies \
+// / \ android libs w/ all code
+// +module src/ --> / \ (also used in unit tests)
+// / \ |
+// NetworkStackApiStableLib NetworkStackApiCurrentLib <--*
+// | |
+// | <-- +NetworkStackAppDefaults --> |
+// | (APK build params) |
+// | |
+// | <-- +NetworkStackApiStableLevel | <-- +NetworkStackApiCurrentLevel
+// | |
+// | |
+// NetworkStackApiStable NetworkStack, InProcessNetworkStack, <-- APKs
+// TestNetworkStack
// Common defaults to define SDK level
java_defaults {
@@ -43,22 +49,29 @@
java_defaults {
name: "NetworkStackApiStableLevel",
- sdk_version: "system_current", // TODO: change to system_29
+ sdk_version: "system_29",
min_sdk_version: "28",
}
-// Java libraries for the API shims
+// Filegroups for the API shims
filegroup {
name: "NetworkStackApiCurrentShims",
srcs: [
- "apishim/current/**/*.java"
+ "apishim/common/**/*.java",
+ "apishim/29/**/*.java",
+ "apishim/current/**/*.java",
+ ":net-module-utils-srcs",
],
}
+// API stable shims only include the compat package, but it is jarjared to replace the non-compat
+// package
filegroup {
name: "NetworkStackApiStableShims",
srcs: [
- "apishim/29/**/*.java"
+ "apishim/common/**/*.java",
+ "apishim/29/**/*.java",
+ ":net-module-utils-srcs",
],
}
@@ -67,7 +80,6 @@
java_defaults {
name: "NetworkStackAndroidLibraryDefaults",
srcs: [
- "src/**/*.java",
":framework-networkstack-shared-srcs",
":services-networkstack-shared-srcs",
":statslog-networkstack-java-gen",
@@ -80,25 +92,38 @@
"networkstackprotosnano",
"captiveportal-lib",
],
- manifest: "AndroidManifestBase.xml",
plugins: ["java_api_finder"],
}
// The versions of the android library containing network stack code compiled for each SDK variant
+// API current uses the sources of the API current shims directly.
+// This allows API current code to be treated identically to code in src/ (it will be moved
+// there eventually), and to use the compat shim as fallback on older devices.
android_library {
name: "NetworkStackApiCurrentLib",
defaults: ["NetworkStackApiCurrentLevel", "NetworkStackAndroidLibraryDefaults"],
- srcs: [
- ":NetworkStackApiCurrentShims",
- ],
+ srcs: [":NetworkStackApiCurrentShims", "src/**/*.java"],
+ manifest: "AndroidManifestBase.xml",
+}
+
+// For API stable, first build the dependencies using jarjar compat rules, then build the sources
+// linking with the dependencies.
+java_library {
+ name: "NetworkStackApiStableDependencies",
+ defaults: ["NetworkStackApiStableLevel", "NetworkStackAndroidLibraryDefaults"],
+ srcs: [":NetworkStackApiStableShims"],
+ jarjar_rules: "apishim/jarjar-rules-compat.txt",
}
android_library {
name: "NetworkStackApiStableLib",
- defaults: ["NetworkStackApiStableLevel", "NetworkStackAndroidLibraryDefaults"],
- srcs: [
- ":NetworkStackApiStableShims",
+ defaults: ["NetworkStackApiStableLevel"],
+ srcs: ["src/**/*.java"],
+ // API stable uses a jarjared version of the shims
+ static_libs: [
+ "NetworkStackApiStableDependencies",
],
+ manifest: "AndroidManifestBase.xml",
}
// Common defaults for compiling the actual APK, based on the NetworkStackApiXBase android libraries
@@ -126,7 +151,7 @@
certificate: "platform",
manifest: "AndroidManifest_InProcess.xml",
// InProcessNetworkStack is a replacement for NetworkStack
- overrides: ["NetworkStack"],
+ overrides: ["NetworkStack", "NetworkStackNext"],
// The permission configuration *must* be included to ensure security of the device
// The InProcessNetworkStack goes together with the PlatformCaptivePortalLogin, which replaces
// the default CaptivePortalLogin.
@@ -135,7 +160,7 @@
// Updatable network stack packaged as an application
android_app {
- name: "NetworkStack",
+ name: "NetworkStackNext",
defaults: ["NetworkStackAppDefaults", "NetworkStackApiCurrentLevel"],
static_libs: ["NetworkStackApiCurrentLib"],
certificate: "networkstack",
@@ -146,7 +171,7 @@
// Updatable network stack for finalized API
android_app {
- name: "NetworkStackApiStable",
+ name: "NetworkStack",
defaults: ["NetworkStackAppDefaults", "NetworkStackApiStableLevel"],
static_libs: ["NetworkStackApiStableLib"],
certificate: "networkstack",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 249e510..9628b3f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack"
android:sharedUserId="android.uid.networkstack"
- android:versionCode="290000000"
+ android:versionCode="299900000"
android:versionName="2019-09"
>
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 43a1bd0..6c79f20 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -45,6 +45,8 @@
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/CaptivePortalLogin)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/NetworkStack)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/NetworkStackApiStable)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/TEST_MAPPING b/TEST_MAPPING
index e5c8117..48370c0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "NetworkStackTests"
+ },
+ {
+ "name": "NetworkStackNextTests"
}
],
"postsubmit": [
diff --git a/apishim/29/com/android/networkstack/apishim/SocketUtilsShimImpl.java b/apishim/29/com/android/networkstack/apishim/api29/SocketUtilsShimImpl.java
similarity index 70%
rename from apishim/29/com/android/networkstack/apishim/SocketUtilsShimImpl.java
rename to apishim/29/com/android/networkstack/apishim/api29/SocketUtilsShimImpl.java
index 0e41e19..be12662 100644
--- a/apishim/29/com/android/networkstack/apishim/SocketUtilsShimImpl.java
+++ b/apishim/29/com/android/networkstack/apishim/api29/SocketUtilsShimImpl.java
@@ -14,18 +14,32 @@
* limitations under the License.
*/
-package com.android.networkstack.apishim;
+package com.android.networkstack.apishim.api29;
import android.net.util.SocketUtils;
import androidx.annotation.NonNull;
+import com.android.networkstack.apishim.SocketUtilsShim;
+
import java.net.SocketAddress;
/**
* Implementation of SocketUtilsShim for API 29.
*/
public class SocketUtilsShimImpl implements SocketUtilsShim {
+ protected SocketUtilsShimImpl() {}
+
+ /**
+ * Get a new instance of {@link SocketUtilsShim}.
+ *
+ * Use com.android.networkstack.apishim.SocketUtilsShim#newInstance()
+ * (non-API29 version) instead, to use the correct shims depending on build SDK.
+ */
+ public static SocketUtilsShim newInstance() {
+ return new SocketUtilsShimImpl();
+ }
+
@NonNull
@Override
public SocketAddress makePacketSocketAddress(
diff --git a/apishim/current/com/android/networkstack/apishim/SocketUtilsShimImpl.java b/apishim/30/com/android/networkstack/apishim/SocketUtilsShimImpl.java
similarity index 68%
rename from apishim/current/com/android/networkstack/apishim/SocketUtilsShimImpl.java
rename to apishim/30/com/android/networkstack/apishim/SocketUtilsShimImpl.java
index 92f8438..9516e7c 100644
--- a/apishim/current/com/android/networkstack/apishim/SocketUtilsShimImpl.java
+++ b/apishim/30/com/android/networkstack/apishim/SocketUtilsShimImpl.java
@@ -17,6 +17,7 @@
package com.android.networkstack.apishim;
import android.net.util.SocketUtils;
+import android.os.Build;
import androidx.annotation.NonNull;
@@ -25,7 +26,20 @@
/**
* Implementation of {@link SocketUtilsShim} for API 30.
*/
-public class SocketUtilsShimImpl implements SocketUtilsShim {
+public class SocketUtilsShimImpl
+ extends com.android.networkstack.apishim.api29.SocketUtilsShimImpl {
+ protected SocketUtilsShimImpl() {}
+
+ /**
+ * Get a new instance of {@link SocketUtilsShim}.
+ */
+ public static SocketUtilsShim newInstance() {
+ if (!ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q)) {
+ return com.android.networkstack.apishim.api29.SocketUtilsShimImpl.newInstance();
+ }
+ return new SocketUtilsShimImpl();
+ }
+
@NonNull
@Override
public SocketAddress makePacketSocketAddress(
diff --git a/apishim/common/com/android/networkstack/apishim/ShimUtils.java b/apishim/common/com/android/networkstack/apishim/ShimUtils.java
new file mode 100644
index 0000000..e9b5305
--- /dev/null
+++ b/apishim/common/com/android/networkstack/apishim/ShimUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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.os.Build;
+
+/**
+ * Utility class for API shims.
+ */
+public final class ShimUtils {
+ /**
+ * Check whether the device release or development API level is strictly higher than the passed
+ * in level.
+ *
+ * On a development build (codename != REL), the device will have the same API level as the
+ * last stable release, even though some additional APIs may be available. In this method the
+ * device API level is considered to be higher if the device supports a stable SDK with a higher
+ * version number, or if the device supports a development version of a SDK that has a higher
+ * version number.
+ *
+ * @return True if the device supports an SDK that has or will have a higher version number,
+ * even if still in development.
+ */
+ public static boolean isReleaseOrDevelopmentApiAbove(int apiLevel) {
+ // In-development API n+1 will have SDK_INT == n and CODENAME != REL.
+ // Stable API n has SDK_INT == n and CODENAME == REL.
+ final int devApiLevel = Build.VERSION.SDK_INT
+ + ("REL".equals(Build.VERSION.CODENAME) ? 0 : 1);
+ return devApiLevel > apiLevel;
+ }
+}
diff --git a/src/com/android/networkstack/apishim/SocketUtilsShim.java b/apishim/common/com/android/networkstack/apishim/SocketUtilsShim.java
similarity index 72%
rename from src/com/android/networkstack/apishim/SocketUtilsShim.java
rename to apishim/common/com/android/networkstack/apishim/SocketUtilsShim.java
index 34b5f40..33cb5f8 100644
--- a/src/com/android/networkstack/apishim/SocketUtilsShim.java
+++ b/apishim/common/com/android/networkstack/apishim/SocketUtilsShim.java
@@ -30,18 +30,6 @@
*/
public interface SocketUtilsShim {
/**
- * Create a new instance of SocketUtilsShim.
- */
- @NonNull
- static SocketUtilsShim newInstance() {
- // TODO: when the R API is finalized, rename the API 29 shim to SocketUtilsCompat, and
- // return it here instead of SocketUtilsShimImpl for devices with Build.VERSION <= 29.
- // For now, the switch between implementations is done at build time (swapping the java file
- // with another), since production modules should not be built with a non-finalized API.
- return new SocketUtilsShimImpl();
- }
-
- /**
* @see android.net.util.SocketUtils#makePacketSocketAddress(int, int, byte[])
*/
@NonNull
diff --git a/apishim/jarjar-rules-compat.txt b/apishim/jarjar-rules-compat.txt
new file mode 100644
index 0000000..3e54c12
--- /dev/null
+++ b/apishim/jarjar-rules-compat.txt
@@ -0,0 +1,7 @@
+# jarjar rules to use on API stable builds.
+# Use the latest stable apishim package as the main apishim package, to replace and avoid building
+# the unstable, non-compatibility shims.
+# Once API 30 is stable, apishim/30/com.android.networkstack.apishim should be moved to the
+# com.android.networkstack.apishim.api30 package, a new apishim/31/com.android.networkstack.apishim
+# package should be created, and this rule should reference api30.
+rule com.android.networkstack.apishim.api29.** com.android.networkstack.apishim.@1
\ No newline at end of file
diff --git a/common/moduleutils/Android.bp b/common/moduleutils/Android.bp
new file mode 100644
index 0000000..6117149
--- /dev/null
+++ b/common/moduleutils/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2019 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.
+//
+
+// Shared utility sources to be used by multiple network modules
+filegroup {
+ name: "net-module-utils-srcs",
+ srcs: ["src/**/*.java"],
+}
\ No newline at end of file
diff --git a/src/android/net/util/SharedLog.java b/common/moduleutils/src/android/net/util/SharedLog.java
similarity index 100%
rename from src/android/net/util/SharedLog.java
rename to common/moduleutils/src/android/net/util/SharedLog.java
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp
index c82f751..12c5355 100644
--- a/common/networkstackclient/Android.bp
+++ b/common/networkstackclient/Android.bp
@@ -87,6 +87,6 @@
],
static_libs: [
"ipmemorystore-aidl-interfaces-V3-java",
- "networkstack-aidl-interfaces-java",
+ "networkstack-aidl-interfaces-unstable-java",
],
}
diff --git a/src/android/net/NetworkStackIpMemoryStore.java b/src/android/net/NetworkStackIpMemoryStore.java
index 41715b2..850faaf 100644
--- a/src/android/net/NetworkStackIpMemoryStore.java
+++ b/src/android/net/NetworkStackIpMemoryStore.java
@@ -16,9 +16,10 @@
package android.net;
-import android.annotation.NonNull;
import android.content.Context;
+import androidx.annotation.NonNull;
+
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java
index 2f74ad6..165e37b 100644
--- a/src/android/net/apf/ApfFilter.java
+++ b/src/android/net/apf/ApfFilter.java
@@ -33,7 +33,6 @@
import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
import static com.android.server.util.NetworkStackConstants.IPV6_ADDR_LEN;
-import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -59,6 +58,8 @@
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
@@ -104,6 +105,7 @@
public boolean multicastFilter;
public boolean ieee802_3Filter;
public int[] ethTypeBlackList;
+ public int minRdnssLifetimeSec;
}
// Enums describing the outcome of receiving an RA packet.
@@ -357,6 +359,9 @@
private final boolean mDrop802_3Frames;
private final int[] mEthTypeBlackList;
+ // Ignore non-zero RDNSS lifetimes below this value.
+ private final int mMinRdnssLifetimeSec;
+
// Detects doze mode state transitions.
private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
@Override
@@ -387,6 +392,7 @@
mInterfaceParams = ifParams;
mMulticastFilter = config.multicastFilter;
mDrop802_3Frames = config.ieee802_3Filter;
+ mMinRdnssLifetimeSec = config.minRdnssLifetimeSec;
mContext = context;
if (mApfCapabilities.hasDataAccess()) {
@@ -513,9 +519,9 @@
public final Type type;
/** Offset into the packet at which this section begins. */
public final int start;
- /** Length of this section. */
+ /** Length of this section in bytes. */
public final int length;
- /** If this is a lifetime, the ICMP option that the defined it. 0 for router lifetime. */
+ /** If this is a lifetime, the ICMP option that defined it. 0 for router lifetime. */
public final int option;
/** If this is a lifetime, the lifetime value. */
public final long lifetime;
@@ -747,6 +753,19 @@
return lifetime;
}
+ // http://b/66928272 http://b/65056012
+ // DnsServerRepository ignores RDNSS servers with lifetimes that are too low. Ignore these
+ // lifetimes for the purpose of filter lifetime calculations.
+ private boolean shouldIgnoreLifetime(int optionType, long lifetime) {
+ return optionType == ICMP6_RDNSS_OPTION_TYPE
+ && lifetime != 0 && lifetime < mMinRdnssLifetimeSec;
+ }
+
+ private boolean isRelevantLifetime(PacketSection section) {
+ return section.type == PacketSection.Type.LIFETIME
+ && !shouldIgnoreLifetime(section.option, section.lifetime);
+ }
+
// Note that this parses RA and may throw InvalidRaException (from
// Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
@@ -784,8 +803,9 @@
addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, 0, routerLifetime);
builder.updateRouterLifetime(routerLifetime);
- // Ensures that the RA is not truncated.
- mPacket.position(ICMP6_RA_OPTION_OFFSET);
+ // Add remaining fields (reachable time and retransmission timer) to match section.
+ addMatchUntil(ICMP6_RA_OPTION_OFFSET);
+
while (mPacket.hasRemaining()) {
final int position = mPacket.position();
final int optionType = getUint8(mPacket, position);
@@ -796,7 +816,7 @@
mPrefixOptionOffsets.add(position);
// Parse valid lifetime
- addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+ addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
lifetime = getUint32(mPacket, mPacket.position());
addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
ICMP6_PREFIX_OPTION_TYPE, lifetime);
@@ -860,7 +880,7 @@
long minLifetime() {
long minLifetime = Long.MAX_VALUE;
for (PacketSection section : mPacketSections) {
- if (section.type == PacketSection.Type.LIFETIME) {
+ if (isRelevantLifetime(section)) {
minLifetime = Math.min(minLifetime, section.lifetime);
}
}
@@ -900,9 +920,10 @@
section.start + section.length),
nextFilterLabel);
}
+
// Generate code to test the lifetimes haven't gone down too far.
- // The packet is accepted if any of its lifetimes are lower than filterLifetime.
- if (section.type == PacketSection.Type.LIFETIME) {
+ // The packet is accepted if any non-ignored lifetime is lower than filterLifetime.
+ if (isRelevantLifetime(section)) {
switch (section.length) {
case 4: gen.addLoad32(Register.R0, section.start); break;
case 2: gen.addLoad16(Register.R0, section.start); break;
@@ -1911,6 +1932,7 @@
pw.println("Capabilities: " + mApfCapabilities);
pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
+ pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec);
try {
pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
} catch (UnknownHostException|NullPointerException e) {}
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java
index e88c7cc..0d56d63 100644
--- a/src/android/net/dhcp/DhcpClient.java
+++ b/src/android/net/dhcp/DhcpClient.java
@@ -46,8 +46,6 @@
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.net.DhcpResults;
import android.net.InetAddresses;
@@ -73,6 +71,9 @@
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.util.MessageUtils;
@@ -829,41 +830,19 @@
(leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0;
}
- /**
- * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
- * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
- * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
- * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
- * state.
- *
- * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
- * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
- * sent by the receive thread. They may also set mTimeout and implement timeout.
- */
- abstract class PacketRetransmittingState extends LoggingState {
-
- private int mTimer;
+ abstract class TimeoutState extends LoggingState {
protected int mTimeout = 0;
@Override
public void enter() {
super.enter();
- initTimer();
maybeInitTimeout();
- sendMessage(CMD_KICK);
}
@Override
public boolean processMessage(Message message) {
super.processMessage(message);
switch (message.what) {
- case CMD_KICK:
- sendPacket();
- scheduleKick();
- return HANDLED;
- case CMD_RECEIVED_PACKET:
- receivePacket((DhcpPacket) message.obj);
- return HANDLED;
case CMD_TIMEOUT:
timeout();
return HANDLED;
@@ -875,12 +854,66 @@
@Override
public void exit() {
super.exit();
- mKickAlarm.cancel();
mTimeoutAlarm.cancel();
}
- abstract protected boolean sendPacket();
- abstract protected void receivePacket(DhcpPacket packet);
+ protected abstract void timeout();
+ private void maybeInitTimeout() {
+ if (mTimeout > 0) {
+ long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
+ mTimeoutAlarm.schedule(alarmTime);
+ }
+ }
+ }
+
+ /**
+ * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
+ * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
+ * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
+ * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
+ * state.
+ *
+ * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
+ * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
+ * sent by the receive thread. They may also set mTimeout and implement timeout.
+ */
+ abstract class PacketRetransmittingState extends TimeoutState {
+ private int mTimer;
+
+ @Override
+ public void enter() {
+ super.enter();
+ initTimer();
+ sendMessage(CMD_KICK);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (super.processMessage(message) == HANDLED) {
+ return HANDLED;
+ }
+
+ switch (message.what) {
+ case CMD_KICK:
+ sendPacket();
+ scheduleKick();
+ return HANDLED;
+ case CMD_RECEIVED_PACKET:
+ receivePacket((DhcpPacket) message.obj);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ mKickAlarm.cancel();
+ }
+
+ protected abstract boolean sendPacket();
+ protected abstract void receivePacket(DhcpPacket packet);
protected void timeout() {}
protected void initTimer() {
@@ -903,13 +936,6 @@
mTimer = MAX_TIMEOUT_MS;
}
}
-
- protected void maybeInitTimeout() {
- if (mTimeout > 0) {
- long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
- mTimeoutAlarm.schedule(alarmTime);
- }
- }
}
class ObtainingConfigurationState extends LoggingState {
@@ -1167,7 +1193,7 @@
startNewTransaction();
}
- abstract protected Inet4Address packetDestination();
+ protected abstract Inet4Address packetDestination();
protected boolean sendPacket() {
return sendRequestPacket(
diff --git a/src/android/net/dhcp/DhcpLease.java b/src/android/net/dhcp/DhcpLease.java
index 6849cfa..37d9cc0 100644
--- a/src/android/net/dhcp/DhcpLease.java
+++ b/src/android/net/dhcp/DhcpLease.java
@@ -16,12 +16,13 @@
package android.net.dhcp;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.MacAddress;
import android.os.SystemClock;
import android.text.TextUtils;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.util.HexDump;
import java.net.Inet4Address;
diff --git a/src/android/net/dhcp/DhcpLeaseRepository.java b/src/android/net/dhcp/DhcpLeaseRepository.java
index 0a15cd7..d22193b 100644
--- a/src/android/net/dhcp/DhcpLeaseRepository.java
+++ b/src/android/net/dhcp/DhcpLeaseRepository.java
@@ -27,14 +27,15 @@
import static java.lang.Math.min;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.MacAddress;
import android.net.dhcp.DhcpServer.Clock;
import android.net.util.SharedLog;
import android.util.ArrayMap;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java
index 79e1c4f..efce6a5 100644
--- a/src/android/net/dhcp/DhcpPacket.java
+++ b/src/android/net/dhcp/DhcpPacket.java
@@ -3,7 +3,6 @@
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.metrics.DhcpErrorEvent;
@@ -13,7 +12,8 @@
import android.system.OsConstants;
import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
diff --git a/src/android/net/dhcp/DhcpPacketListener.java b/src/android/net/dhcp/DhcpPacketListener.java
index 97d26c7..c9235da 100644
--- a/src/android/net/dhcp/DhcpPacketListener.java
+++ b/src/android/net/dhcp/DhcpPacketListener.java
@@ -16,12 +16,13 @@
package android.net.dhcp;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.util.FdEventsReader;
import android.os.Handler;
import android.system.Os;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.io.FileDescriptor;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
diff --git a/src/android/net/dhcp/DhcpServer.java b/src/android/net/dhcp/DhcpServer.java
index f75fe18..37dd972 100644
--- a/src/android/net/dhcp/DhcpServer.java
+++ b/src/android/net/dhcp/DhcpServer.java
@@ -38,8 +38,6 @@
import static java.lang.Integer.toUnsignedLong;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.INetworkStackStatusCallback;
import android.net.MacAddress;
import android.net.TrafficStats;
@@ -57,7 +55,10 @@
import android.text.TextUtils;
import android.util.Pair;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.util.HexDump;
import java.io.FileDescriptor;
diff --git a/src/android/net/dhcp/DhcpServingParams.java b/src/android/net/dhcp/DhcpServingParams.java
index 230b693..eafe44e 100644
--- a/src/android/net/dhcp/DhcpServingParams.java
+++ b/src/android/net/dhcp/DhcpServingParams.java
@@ -25,13 +25,14 @@
import static java.lang.Integer.toUnsignedLong;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.shared.Inet4AddressUtils;
import android.util.ArraySet;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.net.Inet4Address;
import java.util.Arrays;
import java.util.Collections;
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java
index 98e1e49..8808ee2 100644
--- a/src/android/net/ip/IpClient.java
+++ b/src/android/net/ip/IpClient.java
@@ -18,10 +18,10 @@
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
+import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission;
-import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpResults;
@@ -43,7 +43,9 @@
import android.net.shared.InitialConfiguration;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
+import android.net.util.NetworkStackUtils;
import android.net.util.SharedLog;
+import android.os.Build;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.Message;
@@ -56,6 +58,8 @@
import android.util.Pair;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IState;
import com.android.internal.util.IndentingPrintWriter;
@@ -64,6 +68,7 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
+import com.android.networkstack.apishim.ShimUtils;
import com.android.server.NetworkObserverRegistry;
import com.android.server.NetworkStackService.NetworkStackServiceManager;
@@ -312,9 +317,15 @@
// IpClient shares a handler with DhcpClient: commands must not overlap
public static final int DHCPCLIENT_CMD_BASE = 1000;
+ // Settings and default values.
private static final int MAX_LOG_RECORDS = 500;
private static final int MAX_PACKET_RECORDS = 100;
+ @VisibleForTesting
+ static final String CONFIG_MIN_RDNSS_LIFETIME = "ipclient_min_rdnss_lifetime";
+ private static final int DEFAULT_MIN_RDNSS_LIFETIME =
+ ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q) ? 120 : 0;
+
private static final boolean NO_CALLBACKS = false;
private static final boolean SEND_CALLBACKS = true;
@@ -354,6 +365,9 @@
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
private final InterfaceController mInterfaceCtrl;
+ // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled.
+ private final int mMinRdnssLifetimeSec;
+
private InterfaceParams mInterfaceParams;
/**
@@ -410,6 +424,14 @@
NetworkStackIpMemoryStore ipMemoryStore) {
return new DhcpClient.Dependencies(ipMemoryStore);
}
+
+ /**
+ * Read an integer DeviceConfig property.
+ */
+ public int getDeviceConfigPropertyInt(String name, int defaultValue) {
+ return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name,
+ defaultValue);
+ }
}
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
@@ -448,9 +470,15 @@
mNetd = deps.getNetd(mContext);
mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
+ mMinRdnssLifetimeSec = mDependencies.getDeviceConfigPropertyInt(
+ CONFIG_MIN_RDNSS_LIFETIME, DEFAULT_MIN_RDNSS_LIFETIME);
+
+ IpClientLinkObserver.Configuration config = new IpClientLinkObserver.Configuration(
+ mMinRdnssLifetimeSec);
+
mLinkObserver = new IpClientLinkObserver(
mInterfaceName,
- () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
+ () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED), config) {
@Override
public void onInterfaceAdded(String iface) {
super.onInterfaceAdded(iface);
@@ -1499,6 +1527,7 @@
// Get the Configuration for ApfFilter from Context
apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
+ apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec;
mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java
index 8ad99aa..02bf5f0 100644
--- a/src/android/net/ip/IpClientLinkObserver.java
+++ b/src/android/net/ip/IpClientLinkObserver.java
@@ -71,20 +71,31 @@
void update();
}
+ /** Configuration parameters for IpClientLinkObserver. */
+ public static class Configuration {
+ public final int minRdnssLifetime;
+
+ public Configuration(int minRdnssLifetime) {
+ this.minRdnssLifetime = minRdnssLifetime;
+ }
+ }
+
private final String mInterfaceName;
private final Callback mCallback;
private final LinkProperties mLinkProperties;
private DnsServerRepository mDnsServerRepository;
+ private final Configuration mConfig;
private static final boolean DBG = false;
- public IpClientLinkObserver(String iface, Callback callback) {
+ public IpClientLinkObserver(String iface, Callback callback, Configuration config) {
mTag = "NetlinkTracker/" + iface;
mInterfaceName = iface;
mCallback = callback;
mLinkProperties = new LinkProperties();
mLinkProperties.setInterfaceName(mInterfaceName);
- mDnsServerRepository = new DnsServerRepository();
+ mConfig = config;
+ mDnsServerRepository = new DnsServerRepository(config.minRdnssLifetime);
}
private void maybeLog(String operation, String iface, LinkAddress address) {
@@ -197,7 +208,7 @@
// Clear the repository before clearing mLinkProperties. That way, if a clear() happens
// while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
// mLinkProperties, as desired.
- mDnsServerRepository = new DnsServerRepository();
+ mDnsServerRepository = new DnsServerRepository(mConfig.minRdnssLifetime);
mLinkProperties.clear();
mLinkProperties.setInterfaceName(mInterfaceName);
}
@@ -260,10 +271,16 @@
*/
private HashMap<InetAddress, DnsServerEntry> mIndex;
- DnsServerRepository() {
+ /**
+ * Minimum (non-zero) RDNSS lifetime to accept.
+ */
+ private final int mMinLifetime;
+
+ DnsServerRepository(int minLifetime) {
mCurrentServers = new HashSet<>();
mAllServers = new ArrayList<>(NUM_SERVERS);
mIndex = new HashMap<>(NUM_SERVERS);
+ mMinLifetime = minLifetime;
}
/** Sets the DNS servers of the provided LinkProperties object to the current servers. */
@@ -277,6 +294,9 @@
* @param addresses the string representations of the IP addresses of DNS servers to use.
*/
public synchronized boolean addServers(long lifetime, String[] addresses) {
+ // If the servers are below the minimum lifetime, don't change anything.
+ if (lifetime != 0 && lifetime < mMinLifetime) return false;
+
// The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
// Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
// (136 years) is close enough.
@@ -326,7 +346,7 @@
// Prune excess or expired entries.
for (int i = mAllServers.size() - 1; i >= 0; i--) {
- if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
+ if (i >= NUM_SERVERS || mAllServers.get(i).expiry <= now) {
DnsServerEntry removed = mAllServers.remove(i);
mIndex.remove(removed.address);
changed |= mCurrentServers.remove(removed.address);
diff --git a/src/android/net/util/FdEventsReader.java b/src/android/net/util/FdEventsReader.java
index e82c69b..5a1154f 100644
--- a/src/android/net/util/FdEventsReader.java
+++ b/src/android/net/util/FdEventsReader.java
@@ -19,14 +19,15 @@
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.system.ErrnoException;
import android.system.OsConstants;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.io.FileDescriptor;
import java.io.IOException;
diff --git a/src/android/net/util/NetworkStackUtils.java b/src/android/net/util/NetworkStackUtils.java
index 0a18c0e..b2deefd 100644
--- a/src/android/net/util/NetworkStackUtils.java
+++ b/src/android/net/util/NetworkStackUtils.java
@@ -16,14 +16,15 @@
package android.net.util;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.provider.DeviceConfig;
import android.util.Log;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Inet4Address;
diff --git a/src/com/android/networkstack/metrics/DataStallDetectionStats.java b/src/com/android/networkstack/metrics/DataStallDetectionStats.java
index 2523ecd..7a1f9ac 100644
--- a/src/com/android/networkstack/metrics/DataStallDetectionStats.java
+++ b/src/com/android/networkstack/metrics/DataStallDetectionStats.java
@@ -16,11 +16,12 @@
package com.android.networkstack.metrics;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.util.NetworkStackUtils;
import android.net.wifi.WifiInfo;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.util.HexDump;
import com.android.server.connectivity.nano.CellularData;
import com.android.server.connectivity.nano.DataStallEventProto;
diff --git a/src/com/android/networkstack/metrics/DataStallStatsUtils.java b/src/com/android/networkstack/metrics/DataStallStatsUtils.java
index 59e8fd3..e7a6c3d 100644
--- a/src/com/android/networkstack/metrics/DataStallStatsUtils.java
+++ b/src/com/android/networkstack/metrics/DataStallStatsUtils.java
@@ -16,11 +16,11 @@
package com.android.networkstack.metrics;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.captiveportal.CaptivePortalProbeResult;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.util.HexDump;
diff --git a/src/com/android/networkstack/util/DnsUtils.java b/src/com/android/networkstack/util/DnsUtils.java
index 759807b..c47ccc1 100644
--- a/src/com/android/networkstack/util/DnsUtils.java
+++ b/src/com/android/networkstack/util/DnsUtils.java
@@ -20,14 +20,15 @@
import static android.net.DnsResolver.TYPE_A;
import static android.net.DnsResolver.TYPE_AAAA;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.DnsResolver;
import android.net.Network;
import android.net.TrafficStats;
import android.net.util.Stopwatch;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.util.TrafficStatsConstants;
import com.android.server.connectivity.NetworkMonitor.DnsLogFunc;
diff --git a/src/com/android/server/NetworkObserverRegistry.java b/src/com/android/server/NetworkObserverRegistry.java
index b83bc5c..dcb42c0 100644
--- a/src/com/android/server/NetworkObserverRegistry.java
+++ b/src/com/android/server/NetworkObserverRegistry.java
@@ -17,7 +17,6 @@
import static android.net.RouteInfo.RTN_UNICAST;
-import android.annotation.NonNull;
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
import android.net.InetAddresses;
@@ -28,6 +27,8 @@
import android.os.RemoteException;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
diff --git a/src/com/android/server/NetworkStackService.java b/src/com/android/server/NetworkStackService.java
index 9e5ed74..74a5da0 100644
--- a/src/com/android/server/NetworkStackService.java
+++ b/src/com/android/server/NetworkStackService.java
@@ -22,8 +22,6 @@
import static com.android.server.util.PermissionUtil.checkDumpPermission;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -49,6 +47,8 @@
import android.os.RemoteException;
import android.util.ArraySet;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.annotations.GuardedBy;
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java
index e08170a..bda0c9a 100644
--- a/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -68,8 +68,6 @@
import static com.android.networkstack.util.DnsUtils.PRIVATE_DNS_PROBE_HOST_SUFFIX;
import static com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -115,6 +113,8 @@
import android.util.Pair;
import androidx.annotation.ArrayRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index 4896ef2..834aa2d 100644
--- a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -19,8 +19,6 @@
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -34,6 +32,9 @@
import android.net.ipmemorystore.Status;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
diff --git a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index 55ab8d4..8d57d61 100644
--- a/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ b/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -24,8 +24,6 @@
import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
@@ -44,6 +42,9 @@
import android.os.RemoteException;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
diff --git a/src/com/android/server/connectivity/ipmemorystore/Utils.java b/src/com/android/server/connectivity/ipmemorystore/Utils.java
index 9cbf490..d8a46ed 100644
--- a/src/com/android/server/connectivity/ipmemorystore/Utils.java
+++ b/src/com/android/server/connectivity/ipmemorystore/Utils.java
@@ -16,10 +16,11 @@
package com.android.server.connectivity.ipmemorystore;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.net.ipmemorystore.Blob;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
/** {@hide} */
public class Utils {
/** Pretty print */
diff --git a/src/com/android/server/util/NetworkStackConstants.java b/src/com/android/server/util/NetworkStackConstants.java
index 3174a9b..c011b6a 100644
--- a/src/com/android/server/util/NetworkStackConstants.java
+++ b/src/com/android/server/util/NetworkStackConstants.java
@@ -95,6 +95,7 @@
*/
public static final int IPV6_ADDR_LEN = 16;
public static final int IPV6_HEADER_LEN = 40;
+ public static final int IPV6_LEN_OFFSET = 4;
public static final int IPV6_PROTOCOL_OFFSET = 6;
public static final int IPV6_SRC_ADDR_OFFSET = 8;
public static final int IPV6_DST_ADDR_OFFSET = 24;
@@ -108,6 +109,7 @@
* - https://tools.ietf.org/html/rfc4861
*/
public static final int ICMPV6_HEADER_MIN_LEN = 4;
+ public static final int ICMPV6_CHECKSUM_OFFSET = 2;
public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
public static final int ICMPV6_ROUTER_SOLICITATION = 133;
@@ -116,9 +118,14 @@
public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8;
public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8;
- public static final int ICMPV6_ND_OPTION_SLLA = 1;
- public static final int ICMPV6_ND_OPTION_TLLA = 2;
- public static final int ICMPV6_ND_OPTION_MTU = 5;
+ public static final int ICMPV6_ND_OPTION_SLLA = 1;
+ public static final int ICMPV6_ND_OPTION_TLLA = 2;
+ public static final int ICMPV6_ND_OPTION_PIO = 3;
+ public static final int ICMPV6_ND_OPTION_MTU = 5;
+ public static final int ICMPV6_ND_OPTION_RDNSS = 25;
+
+
+ public static final int ICMPV6_RA_HEADER_LEN = 16;
/**
* UDP constants.
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
index f32171c..f34c26e 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java
@@ -26,6 +26,24 @@
import static android.net.ipmemorystore.Status.SUCCESS;
import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+
+import static com.android.internal.util.BitUtils.uint16;
+import static com.android.server.util.NetworkStackConstants.ETHER_HEADER_LEN;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_IPV6;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_CHECKSUM_OFFSET;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_RA_HEADER_LEN;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
+import static com.android.server.util.NetworkStackConstants.IPV6_HEADER_LEN;
+import static com.android.server.util.NetworkStackConstants.IPV6_LEN_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET;
import static junit.framework.Assert.fail;
@@ -37,6 +55,7 @@
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -50,7 +69,9 @@
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InetAddresses;
+import android.net.IpPrefix;
import android.net.LinkProperties;
+import android.net.MacAddress;
import android.net.NetworkStackIpMemoryStore;
import android.net.TestNetworkInterface;
import android.net.TestNetworkManager;
@@ -63,6 +84,7 @@
import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener;
import android.net.ipmemorystore.Status;
import android.net.shared.ProvisioningConfiguration;
+import android.net.util.IpUtils;
import android.net.util.NetworkStackUtils;
import android.net.util.PacketReader;
import android.os.Handler;
@@ -96,10 +118,12 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet4Address;
+import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -212,6 +236,8 @@
private class Dependencies extends IpClient.Dependencies {
private boolean mIsDhcpLeaseCacheEnabled;
private boolean mIsDhcpRapidCommitEnabled;
+ // Can't use SparseIntArray, it doesn't have an easy way to know if a key is not present.
+ private HashMap<String, Integer> mIntConfigProperties = new HashMap<>();
public void setDhcpLeaseCacheEnabled(final boolean enable) {
mIsDhcpLeaseCacheEnabled = enable;
@@ -251,6 +277,19 @@
}
};
}
+
+ @Override
+ public int getDeviceConfigPropertyInt(String name, int defaultValue) {
+ Integer value = mIntConfigProperties.get(name);
+ if (value == null) {
+ throw new IllegalStateException("Non-mocked device config property " + name);
+ }
+ return value;
+ }
+
+ public void setDeviceConfigProperty(String name, int value) {
+ mIntConfigProperties.put(name, value);
+ }
}
@Before
@@ -265,6 +304,8 @@
when(mNetworkStackServiceManager.getIpMemoryStoreService())
.thenReturn(mIpMemoryStoreService);
+ mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67);
+
setUpTapInterface();
setUpIpClient();
}
@@ -385,7 +426,10 @@
private void sendResponse(final ByteBuffer packet) throws IOException {
try (FileOutputStream out = new FileOutputStream(mPacketReader.createFd())) {
- out.write(packet.array());
+ byte[] packetBytes = new byte[packet.limit()];
+ packet.get(packetBytes);
+ packet.flip(); // So we can reuse it in the future.
+ out.write(packetBytes);
}
}
@@ -693,4 +737,180 @@
verify(mCb).onProvisioningFailure(any());
verify(mCb, never()).setNeighborDiscoveryOffload(true);
}
-}
+
+ private boolean isRouterSolicitation(final byte[] packetBytes) {
+ ByteBuffer packet = ByteBuffer.wrap(packetBytes);
+ return packet.getShort(ETHER_TYPE_OFFSET) == (short) ETH_P_IPV6
+ && packet.get(ETHER_HEADER_LEN + IPV6_PROTOCOL_OFFSET) == (byte) IPPROTO_ICMPV6
+ && packet.get(ETHER_HEADER_LEN + IPV6_HEADER_LEN)
+ == (byte) ICMPV6_ROUTER_SOLICITATION;
+ }
+
+ private void waitForRouterSolicitation() throws ParseException {
+ byte[] packet;
+ while ((packet = mPacketReader.popPacket(PACKET_TIMEOUT_MS)) != null) {
+ if (isRouterSolicitation(packet)) return;
+ }
+ fail("No router solicitation received on interface within timeout");
+ }
+
+ // TODO: move this and the following method to a common location and use them in ApfTest.
+ private static ByteBuffer buildPioOption(int valid, int preferred, String prefixString)
+ throws Exception {
+ final int optLen = 4;
+ IpPrefix prefix = new IpPrefix(prefixString);
+ ByteBuffer option = ByteBuffer.allocate(optLen * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR);
+ option.put((byte) ICMPV6_ND_OPTION_PIO); // Type
+ option.put((byte) optLen); // Length in 8-byte units
+ option.put((byte) prefix.getPrefixLength()); // Prefix length
+ option.put((byte) 0b11000000); // L = 1, A = 1
+ option.putInt(valid);
+ option.putInt(preferred);
+ option.putInt(0); // Reserved
+ option.put(prefix.getRawAddress());
+ option.flip();
+ return option;
+ }
+
+ private static ByteBuffer buildRdnssOption(int lifetime, String... servers) throws Exception {
+ final int optLen = 1 + 2 * servers.length;
+ ByteBuffer option = ByteBuffer.allocate(optLen * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR);
+ option.put((byte) ICMPV6_ND_OPTION_RDNSS); // Type
+ option.put((byte) optLen); // Length in 8-byte units
+ option.putShort((short) 0); // Reserved
+ option.putInt(lifetime); // Lifetime
+ for (String server : servers) {
+ option.put(InetAddress.getByName(server).getAddress());
+ }
+ option.flip();
+ return option;
+ }
+
+ // HACK: these functions are here because IpUtils#transportChecksum is private. Even if we made
+ // that public, it won't be available on Q devices, and this test needs to run on Q devices.
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static int checksumFold(int sum) {
+ while (sum > 0xffff) {
+ sum = (sum >> 16) + (sum & 0xffff);
+ }
+ return sum;
+ }
+
+ private static short checksumAdjust(short checksum, short oldWord, short newWord) {
+ checksum = (short) ~checksum;
+ int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
+ return (short) ~tempSum;
+ }
+
+ private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
+ int transportLen) {
+ // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
+ // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
+ // checksum adjustment for the change in the next header byte.
+ short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
+ return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
+ }
+
+ private static ByteBuffer buildRaPacket(ByteBuffer... options) throws Exception {
+ final MacAddress srcMac = MacAddress.fromString("33:33:00:00:00:01");
+ final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06");
+ final byte[] routerLinkLocal = InetAddresses.parseNumericAddress("fe80::1").getAddress();
+ final byte[] allNodes = InetAddresses.parseNumericAddress("ff02::1").getAddress();
+
+ final ByteBuffer packet = ByteBuffer.allocate(TEST_DEFAULT_MTU);
+ int icmpLen = ICMPV6_RA_HEADER_LEN;
+
+ // Ethernet header.
+ packet.put(srcMac.toByteArray());
+ packet.put(dstMac.toByteArray());
+ packet.putShort((short) ETHER_TYPE_IPV6);
+
+ // IPv6 header.
+ packet.putInt(0x600abcde); // Version, traffic class, flowlabel
+ packet.putShort((short) 0); // Length, TBD
+ packet.put((byte) IPPROTO_ICMPV6); // Next header
+ packet.put((byte) 0xff); // Hop limit
+ packet.put(routerLinkLocal); // Source address
+ packet.put(allNodes); // Destination address
+
+ // Router advertisement.
+ packet.put((byte) ICMPV6_ROUTER_ADVERTISEMENT); // ICMP type
+ packet.put((byte) 0); // ICMP code
+ packet.putShort((short) 0); // Checksum, TBD
+ packet.put((byte) 0); // Hop limit, unspecified
+ packet.put((byte) 0); // M=0, O=0
+ packet.putShort((short) 1800); // Router lifetime
+ packet.putInt(0); // Reachable time, unspecified
+ packet.putInt(100); // Retrans time 100ms.
+
+ for (ByteBuffer option : options) {
+ packet.put(option);
+ option.clear(); // So we can reuse it in a future packet.
+ icmpLen += option.capacity();
+ }
+
+ // Populate length and checksum fields.
+ final int transportOffset = ETHER_HEADER_LEN + IPV6_HEADER_LEN;
+ final short checksum = icmpv6Checksum(packet, ETHER_HEADER_LEN, transportOffset, icmpLen);
+ packet.putShort(ETHER_HEADER_LEN + IPV6_LEN_OFFSET, (short) icmpLen);
+ packet.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum);
+
+ packet.flip();
+ return packet;
+ }
+
+ @Test
+ public void testRaRdnss() throws Exception {
+ // Speed up the test by removing router_solicitation_delay.
+ // We don't need to restore the default value because the interface is removed in tearDown.
+ // TODO: speed up further by not waiting for RA but keying off first IPv6 packet.
+ mNetd.setProcSysNet(INetd.IPV6, INetd.CONF, mIfaceName, "router_solicitation_delay", "0");
+
+ ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+ .withoutIpReachabilityMonitor()
+ .withoutIPv4()
+ .build();
+ mIpc.startProvisioning(config);
+
+ final String dnsServer = "2001:4860:4860::64";
+ final String lowlifeDnsServer = "2001:4860:4860::6464";
+
+ final ByteBuffer pio = buildPioOption(600, 300, "2001:db8:1::/64");
+ ByteBuffer rdnss1 = buildRdnssOption(60, lowlifeDnsServer);
+ ByteBuffer rdnss2 = buildRdnssOption(600, dnsServer);
+ ByteBuffer ra = buildRaPacket(pio, rdnss1, rdnss2);
+
+ waitForRouterSolicitation();
+ sendResponse(ra);
+
+ ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class);
+ verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture());
+ LinkProperties lp = captor.getValue();
+
+ // Expect that DNS servers with lifetimes below CONFIG_MIN_RDNSS_LIFETIME are not accepted.
+ assertNotNull(lp);
+ assertEquals(1, lp.getDnsServers().size());
+ assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
+ reset(mCb);
+
+ // If the RDNSS lifetime is above the minimum, the DNS server is accepted.
+ rdnss1 = buildRdnssOption(68, lowlifeDnsServer);
+ ra = buildRaPacket(pio, rdnss1, rdnss2);
+ sendResponse(ra);
+ verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture());
+ lp = captor.getValue();
+ assertNotNull(lp);
+ assertEquals(2, lp.getDnsServers().size());
+ assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer)));
+ assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer)));
+ reset(mCb);
+
+ // Expect that setting RDNSS lifetime of 0 causes loss of provisioning.
+ rdnss1 = buildRdnssOption(0, dnsServer);
+ rdnss2 = buildRdnssOption(0, lowlifeDnsServer);
+ ra = buildRaPacket(pio, rdnss1, rdnss2);
+ sendResponse(ra);
+
+ verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture());
+ lp = captor.getValue();
+ }}
diff --git a/tests/lib/Android.bp b/tests/lib/Android.bp
index 1db4054..249088f 100644
--- a/tests/lib/Android.bp
+++ b/tests/lib/Android.bp
@@ -15,6 +15,19 @@
//
java_library {
+ name: "net-tests-utils-multivariant",
+ srcs: [
+ "multivariant/**/*.java",
+ "multivariant/**/*.kt",
+ ],
+ host_supported: true,
+ static_libs: [
+ "kotlin-test",
+ "junit",
+ ],
+}
+
+java_library {
name: "net-tests-utils",
srcs: [
"src/**/*.java",
@@ -22,8 +35,7 @@
],
defaults: ["lib_mockito_extended"],
static_libs: [
- "kotlin-test",
- "junit",
+ "net-tests-utils-multivariant",
],
}
diff --git a/tests/lib/src/com/android/testutils/ConcurrentUtils.kt b/tests/lib/multivariant/com/android/testutils/ConcurrentUtils.kt
similarity index 100%
rename from tests/lib/src/com/android/testutils/ConcurrentUtils.kt
rename to tests/lib/multivariant/com/android/testutils/ConcurrentUtils.kt
diff --git a/tests/lib/src/com/android/testutils/ExceptionUtils.java b/tests/lib/multivariant/com/android/testutils/ExceptionUtils.java
similarity index 100%
rename from tests/lib/src/com/android/testutils/ExceptionUtils.java
rename to tests/lib/multivariant/com/android/testutils/ExceptionUtils.java
diff --git a/tests/lib/multivariant/com/android/testutils/FileUtils.kt b/tests/lib/multivariant/com/android/testutils/FileUtils.kt
new file mode 100644
index 0000000..678f977
--- /dev/null
+++ b/tests/lib/multivariant/com/android/testutils/FileUtils.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.testutils
+
+// This function is private because the 2 is hardcoded here, and is not correct if not called
+// directly from __LINE__ or __FILE__.
+private fun callerStackTrace(): StackTraceElement = try {
+ throw RuntimeException()
+} catch (e: RuntimeException) {
+ e.stackTrace[2] // 0 is here, 1 is get() in __FILE__ or __LINE__
+}
+val __FILE__: String get() = callerStackTrace().fileName
+val __LINE__: Int get() = callerStackTrace().lineNumber
diff --git a/tests/lib/src/com/android/testutils/MiscAsserts.kt b/tests/lib/multivariant/com/android/testutils/MiscAsserts.kt
similarity index 98%
rename from tests/lib/src/com/android/testutils/MiscAsserts.kt
rename to tests/lib/multivariant/com/android/testutils/MiscAsserts.kt
index 5019dcd..17540a8 100644
--- a/tests/lib/src/com/android/testutils/MiscAsserts.kt
+++ b/tests/lib/multivariant/com/android/testutils/MiscAsserts.kt
@@ -16,7 +16,6 @@
package com.android.testutils
-import android.util.Log
import com.android.testutils.ExceptionUtils.ThrowingRunnable
import java.lang.reflect.Modifier
import kotlin.system.measureTimeMillis
@@ -80,7 +79,6 @@
fun assertRunsInAtMost(descr: String, timeLimit: Long, fn: () -> Unit) {
val timeTaken = measureTimeMillis(fn)
val msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit)
- Log.d(TAG, msg)
assertTrue(timeTaken <= timeLimit, msg)
}
diff --git a/tests/lib/src/com/android/testutils/TrackRecord.kt b/tests/lib/multivariant/com/android/testutils/TrackRecord.kt
similarity index 100%
rename from tests/lib/src/com/android/testutils/TrackRecord.kt
rename to tests/lib/multivariant/com/android/testutils/TrackRecord.kt
diff --git a/tests/lib/src/com/android/testutils/FileUtils.kt b/tests/lib/src/com/android/testutils/FileUtils.kt
deleted file mode 100644
index edd8d83..0000000
--- a/tests/lib/src/com/android/testutils/FileUtils.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.android.testutils
-
-// This function is private because the 2 is hardcoded here, and is not correct if not called
-// directly from __LINE__ or __FILE__.
-private fun callerStackTrace(): StackTraceElement = try {
- throw RuntimeException()
-} catch (e: RuntimeException) {
- e.stackTrace[2] // 0 is here, 1 is get() in __FILE__ or __LINE__
-}
-val __FILE__: String get() = callerStackTrace().fileName
-val __LINE__: Int get() = callerStackTrace().lineNumber
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 03bcf95..a63bc61 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -14,18 +14,16 @@
// limitations under the License.
//
-android_test {
- name: "NetworkStackTests",
+java_defaults {
+ name: "NetworkStackTestsDefaults",
certificate: "platform",
srcs: ["src/**/*.java", "src/**/*.kt"],
- test_suites: ["device-tests"],
resource_dirs: ["res"],
static_libs: [
"androidx.test.rules",
"kotlin-reflect",
"mockito-target-extended-minus-junit4",
"net-tests-utils",
- "NetworkStackApiCurrentLib",
"testables",
],
libs: [
@@ -42,6 +40,21 @@
],
}
+android_test {
+ name: "NetworkStackNextTests",
+ srcs: [], // TODO: tests that only apply to the current, non-stable API can be added here
+ test_suites: ["device-tests"],
+ defaults: ["NetworkStackTestsDefaults"],
+ static_libs: ["NetworkStackApiCurrentLib"],
+}
+
+android_test {
+ name: "NetworkStackTests",
+ test_suites: ["device-tests"],
+ defaults: ["NetworkStackTestsDefaults"],
+ static_libs: ["NetworkStackApiStableLib"],
+}
+
// Additional dependencies of libnetworkstackutilsjni that are not provided by the system when
// running as a test application.
// Using java_defaults as jni_libs does not support filegroups.
@@ -80,6 +93,6 @@
"libutilscallstack",
"libziparchive",
"libz",
- "netd_aidl_interface-V2-cpp",
+ "netd_aidl_interface-cpp",
],
}
diff --git a/tests/unit/jni/Android.bp b/tests/unit/jni/Android.bp
index 9520520..4bef7c8 100644
--- a/tests/unit/jni/Android.bp
+++ b/tests/unit/jni/Android.bp
@@ -32,7 +32,7 @@
"liblog",
"libcutils",
"libnativehelper",
- "netd_aidl_interface-V2-cpp",
+ "netd_aidl_interface-cpp",
],
static_libs: [
"libapf",
diff --git a/tests/unit/res/raw/test.db b/tests/unit/res/raw/test.db
new file mode 100644
index 0000000..05cc77b
--- /dev/null
+++ b/tests/unit/res/raw/test.db
Binary files differ
diff --git a/tests/unit/src/android/net/apf/ApfTest.java b/tests/unit/src/android/net/apf/ApfTest.java
index 8b02b49..006ad19 100644
--- a/tests/unit/src/android/net/apf/ApfTest.java
+++ b/tests/unit/src/android/net/apf/ApfTest.java
@@ -130,6 +130,8 @@
private static final boolean DROP_802_3_FRAMES = true;
private static final boolean ALLOW_802_3_FRAMES = false;
+ private static final int MIN_RDNSS_LIFETIME_SEC = 0;
+
// Constants for opcode encoding
private static final byte LI_OP = (byte)(13 << 3);
private static final byte LDDW_OP = (byte)(22 << 3);
@@ -146,6 +148,8 @@
config.multicastFilter = ALLOW_MULTICAST;
config.ieee802_3Filter = ALLOW_802_3_FRAMES;
config.ethTypeBlackList = new int[0];
+ config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC;
+ config.minRdnssLifetimeSec = 67;
return config;
}
@@ -1008,15 +1012,16 @@
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+ private static final int IP_HEADER_OFFSET = ETH_HEADER_LEN;
+
private static final int IPV4_HEADER_LEN = 20;
- private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
- private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
- private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
- private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
- private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+ private static final int IPV4_TOTAL_LENGTH_OFFSET = IP_HEADER_OFFSET + 2;
+ private static final int IPV4_PROTOCOL_OFFSET = IP_HEADER_OFFSET + 9;
+ private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
+ private static final int IPV4_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 16;
private static final int IPV4_TCP_HEADER_LEN = 20;
- private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
+ private static final int IPV4_TCP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
@@ -1024,7 +1029,7 @@
private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13;
- private static final int IPV4_UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;;
+ private static final int IPV4_UDP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0;
private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4;
@@ -1033,11 +1038,11 @@
{(byte) 255, (byte) 255, (byte) 255, (byte) 255};
private static final int IPV6_HEADER_LEN = 40;
- private static final int IPV6_PAYLOAD_LENGTH_OFFSET = ETH_HEADER_LEN + 4;
- private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
- private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
- private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
- private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ private static final int IPV6_PAYLOAD_LENGTH_OFFSET = IP_HEADER_OFFSET + 4;
+ private static final int IPV6_NEXT_HEADER_OFFSET = IP_HEADER_OFFSET + 6;
+ private static final int IPV6_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 8;
+ private static final int IPV6_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 24;
+ private static final int IPV6_TCP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
@@ -1048,19 +1053,23 @@
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 int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ private static final int ICMP6_TYPE_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
private static final int ICMP6_ROUTER_SOLICITATION = 133;
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
private static final int ICMP6_RA_HEADER_LEN = 16;
- private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
private static final int ICMP6_RA_CHECKSUM_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
+ IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2;
+ private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+ IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6;
+ private static final int ICMP6_RA_REACHABLE_TIME_OFFSET =
+ IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8;
+ private static final int ICMP6_RA_RETRANSMISSION_TIMER_OFFSET =
+ IP_HEADER_OFFSET + IPV6_HEADER_LEN + 12;
private static final int ICMP6_RA_OPTION_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+ IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
private static final int ICMP6_PREFIX_OPTION_LEN = 32;
@@ -1124,6 +1133,30 @@
return apfFilter;
}
+ private static void setIpv4VersionFields(ByteBuffer packet) {
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
+ packet.put(IP_HEADER_OFFSET, (byte) 0x45);
+ }
+
+ private static void setIpv6VersionFields(ByteBuffer packet) {
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
+ packet.put(IP_HEADER_OFFSET, (byte) 0x60);
+ }
+
+ private static ByteBuffer makeIpv4Packet(int proto) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ setIpv4VersionFields(packet);
+ packet.put(IPV4_PROTOCOL_OFFSET, (byte) proto);
+ return packet;
+ }
+
+ private static ByteBuffer makeIpv6Packet(int nextHeader) {
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ setIpv6VersionFields(packet);
+ packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) nextHeader);
+ return packet;
+ }
+
@Test
public void testApfFilterIPv4() throws Exception {
MockIpClientCallback ipClientCallback = new MockIpClientCallback();
@@ -1157,7 +1190,7 @@
// Verify multicast/broadcast IPv4, not DHCP to us, is dropped
put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
assertDrop(program, packet.array());
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
+ packet.put(IP_HEADER_OFFSET, (byte) 0x45);
assertDrop(program, packet.array());
packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
assertDrop(program, packet.array());
@@ -1189,8 +1222,7 @@
byte[] program = ipClientCallback.getApfProgram();
// Verify empty IPv6 packet is passed
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ ByteBuffer packet = makeIpv6Packet(IPPROTO_UDP);
assertPass(program, packet.array());
// Verify empty ICMPv6 packet is passed
@@ -1234,28 +1266,25 @@
byte[] program = ipClientCallback.getApfProgram();
// Construct IPv4 and IPv6 multicast packets.
- ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
- mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ ByteBuffer mcastv4packet = makeIpv4Packet(IPPROTO_UDP);
put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
- ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
- mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
+ ByteBuffer mcastv6packet = makeIpv6Packet(IPPROTO_UDP);
put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
// Construct IPv4 broadcast packet.
- ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
+ ByteBuffer bcastv4packet1 = makeIpv4Packet(IPPROTO_UDP);
bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
- ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
+ ByteBuffer bcastv4packet2 = makeIpv4Packet(IPPROTO_UDP);
bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
// Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
- ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
+ ByteBuffer bcastv4unicastl2packet = makeIpv4Packet(IPPROTO_UDP);
bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
@@ -1314,9 +1343,7 @@
// Construct a multicast ICMPv6 ECHO request.
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+ ByteBuffer packet = makeIpv6Packet(IPPROTO_ICMPV6);
packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
@@ -1333,6 +1360,8 @@
// However, we should still let through all other ICMPv6 types.
ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
+ setIpv6VersionFields(packet);
+ packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
assertPass(ipClientCallback.getApfProgram(), raPacket.array());
@@ -1357,11 +1386,11 @@
assertPass(program, packet.array());
// Verify empty packet with IPv4 is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ setIpv4VersionFields(packet);
assertPass(program, packet.array());
// Verify empty IPv6 packet is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ setIpv6VersionFields(packet);
assertPass(program, packet.array());
// Now turn on the filter
@@ -1377,11 +1406,11 @@
assertDrop(program, packet.array());
// Verify that IPv4 (as example of Ethernet II) frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ setIpv4VersionFields(packet);
assertPass(program, packet.array());
// Verify that IPv6 (as example of Ethernet II) frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ setIpv6VersionFields(packet);
assertPass(program, packet.array());
apfFilter.shutdown();
@@ -1404,11 +1433,11 @@
assertPass(program, packet.array());
// Verify empty packet with IPv4 is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ setIpv4VersionFields(packet);
assertPass(program, packet.array());
// Verify empty IPv6 packet is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ setIpv6VersionFields(packet);
assertPass(program, packet.array());
// Now add IPv4 to the black list
@@ -1419,11 +1448,11 @@
program = ipClientCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ setIpv4VersionFields(packet);
assertDrop(program, packet.array());
// Verify that IPv6 frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ setIpv6VersionFields(packet);
assertPass(program, packet.array());
// Now let us have both IPv4 and IPv6 in the black list
@@ -1434,11 +1463,11 @@
program = ipClientCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+ setIpv4VersionFields(packet);
assertDrop(program, packet.array());
// Verify that IPv6 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ setIpv6VersionFields(packet);
assertDrop(program, packet.array());
apfFilter.shutdown();
@@ -1572,18 +1601,18 @@
// src: 10.0.0.6, port: 54321
// dst: 10.0.0.5, port: 12345
assertDrop(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
// Verify IPv4 non-keepalive ack packet from the same source address is passed
assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
// Verify IPv4 packet from another address is passed
assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+ ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
// Remove IPv4 keepalive filter
@@ -1611,15 +1640,15 @@
// src: 2404:0:0:0:0:0:faf2, port: 54321
// dst: 2404:0:0:0:0:0:faf1, port: 12345
assertDrop(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+ ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1));
// Verify IPv6 non-keepalive ack packet from the same source address is passed
assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+ ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum + 100, seqNum));
// Verify IPv6 packet from another address is passed
assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+ ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
anotherDstPort, anotherSeqNum, anotherAckNum));
// Remove IPv6 keepalive filter
@@ -1634,30 +1663,30 @@
// src: 10.0.0.6, port: 54321
// dst: 10.0.0.5, port: 12345
assertDrop(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
// Verify IPv4 non-keepalive ack packet from the same source address is passed
assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
// Verify IPv4 packet from another address is passed
assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+ ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
// Verify IPv6 keepalive ack packet is dropped
// src: 2404:0:0:0:0:0:faf2, port: 54321
// dst: 2404:0:0:0:0:0:faf1, port: 12345
assertDrop(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+ ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1));
// Verify IPv6 non-keepalive ack packet from the same source address is passed
assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+ ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum + 100, seqNum));
// Verify IPv6 packet from another address is passed
assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+ ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
anotherDstPort, anotherSeqNum, anotherAckNum));
// Remove keepalive filters
@@ -1671,32 +1700,29 @@
// Verify IPv4, IPv6 packets are passed
assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+ ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
dstPort, srcPort, ackNum, seqNum + 1));
assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
+ ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
+ ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
dstPort, anotherSeqNum, anotherAckNum));
apfFilter.shutdown();
}
- private static byte[] ipv4Packet(byte[] sip, byte[] dip, int sport,
+ private static byte[] ipv4TcpPacket(byte[] sip, byte[] dip, int sport,
int dport, int seq, int ack, int dataLength) {
final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
- // ether type
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
- // IPv4 header
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
+ // Ethertype and IPv4 header
+ setIpv4VersionFields(packet);
packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP);
put(packet, IPV4_SRC_ADDR_OFFSET, sip);
@@ -1713,10 +1739,11 @@
return packet.array();
}
- private static byte[] ipv6Packet(byte[] sip, byte[] tip, int sport,
+ private static byte[] ipv6TcpPacket(byte[] sip, byte[] tip, int sport,
int dport, int seq, int ack) {
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
+ setIpv6VersionFields(packet);
+ packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_TCP);
put(packet, IPV6_SRC_ADDR_OFFSET, sip);
put(packet, IPV6_DEST_ADDR_OFFSET, tip);
packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
@@ -1787,11 +1814,8 @@
final int udpLength = UDP_HEADER_LEN + dataLength;
ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
- // ether type
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
- // IPv4 header
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
+ // Ethertype and IPv4 header
+ setIpv4VersionFields(packet);
packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
put(packet, IPV4_SRC_ADDR_OFFSET, sip);
@@ -1927,13 +1951,13 @@
assertDrop(program, packet.array());
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
- // Verify other changes to RA make it not match filter
- final byte originalFirstByte = packet.get(0);
- packet.put(0, (byte)-1);
+ // Verify other changes to RA (e.g., a change in the source address) make it not match.
+ final int offset = IPV6_SRC_ADDR_OFFSET + 5;
+ final byte originalByte = packet.get(offset);
+ packet.put(offset, (byte) (~originalByte));
assertPass(program, packet.array());
- packet.put(0, (byte)0);
+ packet.put(offset, originalByte);
assertDrop(program, packet.array());
- packet.put(0, originalFirstByte);
}
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
@@ -1984,6 +2008,25 @@
ipClientCallback.assertNoProgramUpdate();
}
+ private ByteBuffer makeBaseRaPacket() {
+ ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
+ final int ROUTER_LIFETIME = 1000;
+ final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
+ // IPv6, traffic class = 0, flow label = 0x12345
+ final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
+
+ basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
+ basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
+ VERSION_TRAFFIC_CLASS_FLOW_LABEL);
+ basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
+ basePacket.put(ICMP6_TYPE_OFFSET, (byte) ICMP6_ROUTER_ADVERTISEMENT);
+ basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short) ROUTER_LIFETIME);
+ basePacket.position(IPV6_DEST_ADDR_OFFSET);
+ basePacket.put(IPV6_ALL_NODES_ADDRESS);
+
+ return basePacket;
+ }
+
@Test
public void testApfFilterRa() throws Exception {
MockIpClientCallback ipClientCallback = new MockIpClientCallback();
@@ -2005,15 +2048,7 @@
final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
// Verify RA is passed the first time
- ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
- basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
- VERSION_TRAFFIC_CLASS_FLOW_LABEL);
- basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
- basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
- basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
- basePacket.position(IPV6_DEST_ADDR_OFFSET);
- basePacket.put(IPV6_ALL_NODES_ADDRESS);
+ ByteBuffer basePacket = makeBaseRaPacket();
assertPass(program, basePacket.array());
verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
@@ -2059,6 +2094,16 @@
verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
+ final int lowLifetime = 60;
+ ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap(
+ new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
+ basePacket.clear();
+ lowLifetimeRdnssOptionPacket.put(basePacket);
+ addRdnssOption(lowLifetimeRdnssOptionPacket, lowLifetime, "2620:fe::9");
+ verifyRaLifetime(apfFilter, ipClientCallback, lowLifetimeRdnssOptionPacket,
+ ROUTER_LIFETIME);
+ verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, lowLifetime, -1));
+
ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
basePacket.clear();
@@ -2067,6 +2112,16 @@
verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
+ // Check that RIOs differing only in the first 4 bytes are different.
+ ByteBuffer similarRouteInfoOptionPacket = ByteBuffer.wrap(
+ new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
+ basePacket.clear();
+ similarRouteInfoOptionPacket.put(basePacket);
+ addRioOption(similarRouteInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/64");
+ // Packet should be passed because it is different.
+ program = ipClientCallback.getApfProgram();
+ assertPass(program, similarRouteInfoOptionPacket.array());
+
ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
basePacket.clear();
@@ -2082,12 +2137,13 @@
verifyRaLifetime(apfFilter, ipClientCallback, largeRaPacket, 300);
verifyRaEvent(new RaEvent(1800, 600, 300, 1200, 7200, -1));
- // Verify that current program filters all the RAs:
+ // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10).
program = ipClientCallback.getApfProgram();
verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
+ verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME);
verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
verifyRaLifetime(program, largeRaPacket, 300);
@@ -2095,6 +2151,46 @@
apfFilter.shutdown();
}
+ @Test
+ public void testRaWithDifferentReachableTimeAndRetransTimer() throws Exception {
+ final MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+ final ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+ byte[] program = ipClientCallback.getApfProgram();
+ final int RA_REACHABLE_TIME = 1800;
+ final int RA_RETRANSMISSION_TIMER = 1234;
+
+ // Create an Ra packet without options
+ // Reachable time = 1800, retransmission timer = 1234
+ ByteBuffer raPacket = makeBaseRaPacket();
+ raPacket.position(ICMP6_RA_REACHABLE_TIME_OFFSET);
+ raPacket.putInt(RA_REACHABLE_TIME);
+ raPacket.putInt(RA_RETRANSMISSION_TIMER);
+ // First RA passes filter
+ assertPass(program, raPacket.array());
+
+ // Assume apf is shown the given RA, it generates program to filter it.
+ ipClientCallback.resetApfProgramWait();
+ apfFilter.pretendPacketReceived(raPacket.array());
+ program = ipClientCallback.getApfProgram();
+ assertDrop(program, raPacket.array());
+
+ // A packet with different reachable time should be passed.
+ // Reachable time = 2300, retransmission timer = 1234
+ raPacket.clear();
+ raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME + 500);
+ assertPass(program, raPacket.array());
+
+ // A packet with different retransmission timer should be passed.
+ // Reachable time = 1800, retransmission timer = 2234
+ raPacket.clear();
+ raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME);
+ raPacket.putInt(ICMP6_RA_RETRANSMISSION_TIMER_OFFSET, RA_RETRANSMISSION_TIMER + 1000);
+ assertPass(program, raPacket.array());
+ }
+
/**
* Stage a file for testing, i.e. make it native accessible. Given a resource ID,
* copy that resource into the app's data directory and return the path to it.
diff --git a/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index ba86fcf..4e34969 100644
--- a/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -48,6 +48,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.networkstack.tests.R;
+
+import libcore.io.Streams;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +60,9 @@
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -73,12 +80,15 @@
public class IpMemoryStoreServiceTest {
private static final String TEST_CLIENT_ID = "testClientId";
private static final String TEST_DATA_NAME = "testData";
+ private static final String TEST_DATABASE_NAME = "test.db";
private static final int TEST_DATABASE_SIZE_THRESHOLD = 100 * 1024; //100KB
private static final int DEFAULT_TIMEOUT_MS = 5000;
private static final int LONG_TIMEOUT_MS = 30000;
private static final int FAKE_KEY_COUNT = 20;
private static final long LEASE_EXPIRY_NULL = -1L;
+ private static final long UNIX_TIME_MS_2000_01_01 = 946652400000L;
+ private static final long UNIX_TIME_MS_2100_01_01 = 4102412400000L;
private static final int MTU_NULL = -1;
private static final String[] FAKE_KEYS;
private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
@@ -103,7 +113,7 @@
MockitoAnnotations.initMocks(this);
final Context context = InstrumentationRegistry.getContext();
final File dir = context.getFilesDir();
- mDbFile = new File(dir, "test.db");
+ mDbFile = new File(dir, TEST_DATABASE_NAME);
doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
doReturn(mMockJobScheduler).when(mMockContext)
.getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -129,6 +139,16 @@
mDbFile.delete();
}
+ private void copyTestData(final File file) throws Exception {
+ try (
+ InputStream in = InstrumentationRegistry.getContext()
+ .getResources().openRawResource(R.raw.test);
+ OutputStream out = new FileOutputStream(file)
+ ) {
+ Streams.copy(in, out);
+ }
+ }
+
/** Helper method to build test network attributes */
private static NetworkAttributes.Builder buildTestNetworkAttributes(
final Inet4Address ipAddress, final long expiry, final String hint,
@@ -321,20 +341,32 @@
})));
}
- /** Insert large data that db size will be over threshold for maintenance test usage. */
- private void insertFakeDataAndOverThreshold() {
+ /**
+ * This method is used to generate test.db file.
+ *
+ * Here are the steps to update the test.db file if you need to change value in DB.
+ * 1. Create a new test like "testGenerateDB" and have only one line code "generateFakeData()".
+ * 2. Comment out "mDbFile.delete()" in tearDown() method.
+ * 3. Run "atest IpMemoryStoreServiceTest#testGenerateDB".
+ * 4. Run "adb root; adb pull /data/data/com.android.server.networkstack.tests/files/test.db
+ * $YOUR_CODE_BASE/package/module/NetworkStack/tests/unit/res/raw/test.db".
+ *
+ */
+ private void generateFakeData() {
+ final int fakeDataCount = 1000;
+ final int expiredRecordsCount = 100;
try {
final NetworkAttributes.Builder na = buildTestNetworkAttributes(
(Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
"hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
219);
final long time = System.currentTimeMillis() - 1;
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < fakeDataCount; i++) {
int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
mService.mDb,
"fakeKey" + i,
- // Let first 100 records get expiry.
- i < 100 ? time : time + TimeUnit.HOURS.toMillis(i),
+ i < expiredRecordsCount
+ ? UNIX_TIME_MS_2000_01_01 : UNIX_TIME_MS_2100_01_01 + i,
na.build());
assertEquals(errorCode, Status.SUCCESS);
@@ -344,7 +376,7 @@
assertEquals(errorCode, Status.SUCCESS);
}
- // After added 5000 records, db size is larger than fake threshold(100KB).
+ // After inserted fake data, db size should be larger than threshold.
assertTrue(mService.isDbSizeOverThreshold());
} catch (final UnknownHostException e) {
fail("Insert fake data fail");
@@ -634,8 +666,10 @@
}
@Test
- public void testFullMaintenance() {
- insertFakeDataAndOverThreshold();
+ public void testFullMaintenance() throws Exception {
+ copyTestData(mDbFile);
+ // After inserted test data, db size should be larger than threshold.
+ assertTrue(mService.isDbSizeOverThreshold());
final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
// Do full maintenance and then db size should go down and meet the threshold.
@@ -651,8 +685,10 @@
}
@Test
- public void testInterruptMaintenance() {
- insertFakeDataAndOverThreshold();
+ public void testInterruptMaintenance() throws Exception {
+ copyTestData(mDbFile);
+ // After inserted test data, db size should be larger than threshold.
+ assertTrue(mService.isDbSizeOverThreshold());
final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);