Merge "Add yuyanghuang@ to OWNERS_core_networking_xts for APF firmware tests" into main
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
index c19a124..5d49fa3 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
@@ -22,7 +22,6 @@
import static com.android.net.module.util.netlink.NetlinkConstants.IFF_UP;
import static com.android.net.module.util.netlink.NetlinkConstants.RTM_GETLINK;
import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
-import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST_ACK;
import android.net.MacAddress;
@@ -307,7 +306,7 @@
}
return RtNetlinkLinkMessage.build(
- new StructNlMsgHdr(0, RTM_GETLINK, NLM_F_REQUEST, sequenceNumber),
+ new StructNlMsgHdr(0, RTM_GETLINK, NLM_F_REQUEST_ACK, sequenceNumber),
new StructIfinfoMsg((short) AF_UNSPEC, (short) 0, interfaceIndex, 0, 0),
DEFAULT_MTU, null, null);
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
index 13710b1..08cab03 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/RtNetlinkLinkMessageTest.java
@@ -290,7 +290,7 @@
@Test
public void testCreateGetLinkMessage() {
final String expectedHexBytes =
- "20000000120001006824000000000000" // struct nlmsghdr
+ "20000000120005006824000000000000" // struct nlmsghdr
+ "00000000080000000000000000000000"; // struct ifinfomsg
final String interfaceName = "wlan0";
final int interfaceIndex = 8;
diff --git a/thread/service/java/com/android/server/thread/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java
index 520a434..2f2a5d1 100644
--- a/thread/service/java/com/android/server/thread/TunInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java
@@ -326,12 +326,13 @@
private static LinkAddress newLinkAddress(
Ipv6AddressInfo addressInfo, boolean hasActiveOmrAddress) {
// Mesh-local addresses and OMR address have the same scope, to distinguish them we set
- // mesh-local addresses as deprecated when there is an active OMR address.
+ // mesh-local addresses as deprecated when there is an active OMR address. If OMR address
+ // is missing, only ML-EID in mesh-local addresses will be set preferred.
// For OMR address and link-local address we only use the value isPreferred set by
// ot-daemon.
boolean isPreferred = addressInfo.isPreferred;
- if (addressInfo.isMeshLocal && hasActiveOmrAddress) {
- isPreferred = false;
+ if (addressInfo.isMeshLocal) {
+ isPreferred = (!hasActiveOmrAddress && addressInfo.isMeshLocalEid);
}
final long deprecationTimeMillis =
diff --git a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
index 5ba76b8..5be8f49 100644
--- a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
+++ b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
@@ -19,12 +19,10 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.thread.ThreadNetworkController;
import android.net.thread.ThreadNetworkManager;
import android.os.Build;
@@ -41,8 +39,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
/** Tests for {@link ThreadNetworkManager}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index 195f6d2..5b07e0a 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -22,12 +22,14 @@
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_STOPPED;
import static android.net.thread.utils.IntegrationTestUtils.CALLBACK_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
+import static android.net.thread.utils.IntegrationTestUtils.getIpv6Addresses;
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
import static android.net.thread.utils.IntegrationTestUtils.getPrefixesFromNetData;
import static android.net.thread.utils.IntegrationTestUtils.getThreadNetwork;
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
import static android.net.thread.utils.ThreadNetworkControllerWrapper.JOIN_TIMEOUT;
+import static android.os.SystemClock.elapsedRealtime;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
@@ -38,6 +40,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -46,23 +49,26 @@
import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
-import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.thread.utils.FullThreadDevice;
import android.net.thread.utils.OtDaemonController;
+import android.net.thread.utils.TapTestNetworkTracker;
import android.net.thread.utils.ThreadFeatureCheckerRule;
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresSimulationThreadDevice;
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
import android.net.thread.utils.ThreadNetworkControllerWrapper;
import android.net.thread.utils.ThreadStateListener;
+import android.os.HandlerThread;
import android.os.SystemClock;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.LargeTest;
+import com.google.common.collect.FluentIterable;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -102,6 +108,12 @@
private static final Duration NETWORK_CALLBACK_TIMEOUT = Duration.ofSeconds(10);
+ // The duration between attached and OMR address shows up on thread-wpan
+ private static final Duration OMR_LINK_ADDR_TIMEOUT = Duration.ofSeconds(30);
+
+ // The duration between attached and addresses show up on thread-wpan
+ private static final Duration LINK_ADDR_TIMEOUT = Duration.ofSeconds(2);
+
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
private static final byte[] DEFAULT_DATASET_TLVS =
base16().decode(
@@ -128,6 +140,8 @@
ThreadNetworkControllerWrapper.newInstance(mContext);
private OtDaemonController mOtCtl;
private FullThreadDevice mFtd;
+ private HandlerThread mHandlerThread;
+ private TapTestNetworkTracker mTestNetworkTracker;
public final boolean mIsBorderRouterEnabled;
private final ThreadConfiguration mConfig;
@@ -152,6 +166,14 @@
mController.setEnabledAndWait(true);
mController.setConfigurationAndWait(mConfig);
mController.leaveAndWait();
+
+ mHandlerThread = new HandlerThread("ThreadIntegrationTest");
+ mHandlerThread.start();
+
+ mTestNetworkTracker = new TapTestNetworkTracker(mContext, mHandlerThread.getLooper());
+ assertThat(mTestNetworkTracker).isNotNull();
+ mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
+
mFtd = new FullThreadDevice(10 /* nodeId */);
}
@@ -159,6 +181,13 @@
public void tearDown() throws Exception {
ThreadStateListener.stopAllListeners();
+ if (mTestNetworkTracker != null) {
+ mTestNetworkTracker.tearDown();
+ }
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ mHandlerThread.join();
+ }
mController.setTestNetworkAsUpstreamAndWait(null);
mController.leaveAndWait();
@@ -265,23 +294,51 @@
}
@Test
- public void joinNetworkWithBrDisabled_meshLocalAddressesArePreferred() throws Exception {
- // When BR feature is disabled, there is no OMR address, so the mesh-local addresses are
- // expected to be preferred.
- mOtCtl.executeCommand("br disable");
+ public void joinNetwork_borderRouterEnabled_allMlAddrAreNotPreferredAndOmrIsPreferred()
+ throws Exception {
+ assumeTrue(mConfig.isBorderRouterEnabled());
+
+ mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
mController.joinAndWait(DEFAULT_DATASET);
+ waitFor(
+ () -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getOmrAddress()),
+ OMR_LINK_ADDR_TIMEOUT);
IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
- List<LinkAddress> linkAddresses = getIpv6LinkAddresses("thread-wpan");
- for (LinkAddress address : linkAddresses) {
- if (meshLocalPrefix.contains(address.getAddress())) {
- assertThat(address.getDeprecationTime())
- .isGreaterThan(SystemClock.elapsedRealtime());
- assertThat(address.isPreferred()).isTrue();
- }
- }
+ var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
+ var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
+ assertThat(meshLocalAddrs).isNotEmpty();
+ assertThat(meshLocalAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
+ assertThat(meshLocalAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
+ .isTrue();
+ var omrAddrs = linkAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getOmrAddress()));
+ assertThat(omrAddrs).hasSize(1);
+ assertThat(omrAddrs.get(0).isPreferred()).isTrue();
+ assertThat(omrAddrs.get(0).getDeprecationTime() > elapsedRealtime()).isTrue();
+ }
- mOtCtl.executeCommand("br enable");
+ @Test
+ public void joinNetwork_borderRouterDisabled_onlyMlEidIsPreferred() throws Exception {
+ assumeFalse(mConfig.isBorderRouterEnabled());
+
+ mController.joinAndWait(DEFAULT_DATASET);
+ waitFor(
+ () -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getMlEid()),
+ LINK_ADDR_TIMEOUT);
+
+ IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
+ var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
+ var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
+ var mlEidAddrs = meshLocalAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getMlEid()));
+ var nonMlEidAddrs = meshLocalAddrs.filter(addr -> !mlEidAddrs.contains(addr));
+ assertThat(mlEidAddrs).hasSize(1);
+ assertThat(mlEidAddrs.allMatch(addr -> addr.isPreferred())).isTrue();
+ assertThat(mlEidAddrs.allMatch(addr -> addr.getDeprecationTime() > elapsedRealtime()))
+ .isTrue();
+ assertThat(nonMlEidAddrs).isNotEmpty();
+ assertThat(nonMlEidAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
+ assertThat(nonMlEidAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
+ .isTrue();
}
@Test
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
index f41e903..f7b4d19 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
@@ -479,6 +479,12 @@
return addresses
}
+ /** Returns the list of [InetAddress] of the given network. */
+ @JvmStatic
+ fun getIpv6Addresses(interfaceName: String): List<InetAddress> {
+ return getIpv6LinkAddresses(interfaceName).map { it.address }
+ }
+
/** Return the first discovered service of `serviceType`. */
@JvmStatic
@Throws(Exception::class)
diff --git a/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java b/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
index 272685f..d35b94e 100644
--- a/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
+++ b/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
@@ -24,9 +24,11 @@
import com.android.compatibility.common.util.SystemUtil;
import java.net.Inet6Address;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Wrapper of the "/system/bin/ot-ctl" which can be used to send CLI commands to ot-daemon to
@@ -72,6 +74,25 @@
.toList();
}
+ /** Returns the OMR address of this device or {@code null} if it doesn't exist. */
+ @Nullable
+ public Inet6Address getOmrAddress() {
+ List<Inet6Address> allAddresses = new ArrayList<>(getAddresses());
+ allAddresses.removeAll(getMeshLocalAddresses());
+
+ List<Inet6Address> omrAddresses =
+ allAddresses.stream()
+ .filter(addr -> !addr.isLinkLocalAddress())
+ .collect(Collectors.toList());
+ if (omrAddresses.isEmpty()) {
+ return null;
+ } else if (omrAddresses.size() > 1) {
+ throw new IllegalStateException();
+ }
+
+ return omrAddresses.getFirst();
+ }
+
/** Returns {@code true} if the Thread interface is up. */
public boolean isInterfaceUp() {
String output = executeCommand("ifconfig");