Merge "PrivateAddress: Clarify the dependency" into main
diff --git a/OWNERS_core_networking b/OWNERS_core_networking
index 6d8ed4a..078ccde 100644
--- a/OWNERS_core_networking
+++ b/OWNERS_core_networking
@@ -1,12 +1,13 @@
 jchalard@google.com
 junyulai@google.com
 lorenzo@google.com
-martinwu@google.com
 maze@google.com
 motomuman@google.com
 paulhu@google.com
 prohr@google.com
 reminv@google.com
-satk@google.com
 xiaom@google.com
 yuyanghuang@google.com
+
+martinwu@google.com #{LAST_RESORT_SUGGESTION}
+satk@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index f369458..9a049c7 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -59,6 +59,9 @@
 #include "bpf/BpfUtils.h"
 #include "bpf_map_def.h"
 
+// The following matches bpf_helpers.h, which is only for inclusion in bpf code
+#define BPFLOADER_MAINLINE_VERSION 42u
+
 using android::base::EndsWith;
 using android::base::GetIntProperty;
 using android::base::GetProperty;
@@ -1154,7 +1157,10 @@
         ALOGV("map_fd found at %d is %d in %s", i, mapFds[i].get(), elfPath);
 
     ret = readCodeSections(elfFile, cs);
-    if (ret == -ENOENT) return 0;  // no programs defined in this .o
+    // BPF .o's with no programs are only supported by mainline netbpfload,
+    // make sure .o's targeting non-mainline (ie. S) bpfloader don't show up.
+    if (ret == -ENOENT && bpfLoaderMinVer >= BPFLOADER_MAINLINE_VERSION)
+        return 0;
     if (ret) {
         ALOGE("Couldn't read all code sections in %s", elfPath);
         return ret;
@@ -1419,7 +1425,7 @@
     const bool has_platform_netbpfload_rc = exists("/system/etc/init/netbpfload.rc");
 
     // Version of Network BpfLoader depends on the Android OS version
-    unsigned int bpfloader_ver = 42u;    // [42] BPFLOADER_MAINLINE_VERSION
+    unsigned int bpfloader_ver = BPFLOADER_MAINLINE_VERSION;  // [42u]
     if (isAtLeastT) ++bpfloader_ver;     // [43] BPFLOADER_MAINLINE_T_VERSION
     if (isAtLeastU) ++bpfloader_ver;     // [44] BPFLOADER_MAINLINE_U_VERSION
     if (runningAsRoot) ++bpfloader_ver;  // [45] BPFLOADER_MAINLINE_U_QPR3_VERSION
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index 541a375..f34159e 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -30,6 +30,7 @@
 import static android.system.OsConstants.SO_RCVTIMEO;
 import static android.system.OsConstants.SO_SNDTIMEO;
 
+import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
 import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
 import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
 import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR;
@@ -57,6 +58,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 
 /**
@@ -225,6 +227,96 @@
     }
 
     /**
+     * Sends an RTM_NEWLINK message to kernel to set a network interface up or down.
+     *
+     * @param ifName  The name of the network interface to modify.
+     * @param isUp    {@code true} to set the interface up, {@code false} to set it down.
+     * @return {@code true} if the request was successfully sent, {@code false} otherwise.
+     */
+    public static boolean sendRtmSetLinkStateRequest(@NonNull String ifName, boolean isUp) {
+        final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createSetLinkStateMessage(
+                ifName, 1 /*sequenceNumber*/, isUp);
+        if (msg == null) {
+            return false;
+        }
+
+        final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
+        try {
+            NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, bytes);
+            return true;
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Fail to set the interface " + ifName + " " + (isUp ? "up" : "down"), e);
+            return false;
+        }
+    }
+
+    /**
+     * Sends an RTM_NEWLINK message to kernel to rename a network interface.
+     *
+     * @param ifName     The current name of the network interface.
+     * @param newIfName  The new name to assign to the interface.
+     * @return {@code true} if the request was successfully sent, {@code false} otherwise.
+     */
+    public static boolean sendRtmSetLinkNameRequest(
+            @NonNull String ifName, @NonNull String newIfName) {
+        final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createSetLinkNameMessage(
+                ifName, 1 /*sequenceNumber*/, newIfName);
+        if (msg == null) {
+            return false;
+        }
+
+        final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
+        try {
+            NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, bytes);
+            return true;
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Fail to rename the interface from " + ifName + " to " + newIfName, e);
+            return false;
+        }
+    }
+
+    /**
+     * Gets the information of a network interface using a Netlink message.
+     * <p>
+     * This method sends a Netlink message to the kernel to request information about the specified
+     * network interface and returns a {@link RtNetlinkLinkMessage} containing the interface status.
+     *
+     * @param ifName The name of the network interface to query.
+     * @return An {@link RtNetlinkLinkMessage} containing the interface status, or {@code null} if
+     *         the interface does not exist or an error occurred during the query.
+     */
+    @Nullable
+    public static RtNetlinkLinkMessage getLinkRequest(@NonNull String ifName) {
+        final int ifIndex = new OsAccess().if_nametoindex(ifName);
+        if (ifIndex == OsAccess.INVALID_INTERFACE_INDEX) {
+            return null;
+        }
+
+        final AtomicReference<RtNetlinkLinkMessage> recvMsg = new AtomicReference<>();
+        final Consumer<RtNetlinkLinkMessage> handleNlMsg = (msg) -> {
+            if (msg.getHeader().nlmsg_type == RTM_NEWLINK
+                    && msg.getIfinfoHeader().index == ifIndex) {
+                recvMsg.set(msg);
+            }
+        };
+
+        final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createGetLinkMessage(
+                ifName, 1 /*sequenceNumber*/);
+        if (msg == null) {
+            return null;
+        }
+
+        final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
+        try {
+            NetlinkUtils.getAndProcessNetlinkDumpMessages(
+                    bytes, NETLINK_ROUTE, RtNetlinkLinkMessage.class, handleNlMsg);
+        } catch (SocketException | InterruptedIOException | ErrnoException e) {
+            // Nothing we can do here.
+        }
+        return recvMsg.get();
+    }
+
+    /**
      * Create netlink socket with the given netlink protocol type and buffersize.
      *
      * @param nlProto the netlink protocol
diff --git a/staticlibs/testutils/host/python/apf_test_base.py b/staticlibs/testutils/host/python/apf_test_base.py
index 891876b..9a30978 100644
--- a/staticlibs/testutils/host/python/apf_test_base.py
+++ b/staticlibs/testutils/host/python/apf_test_base.py
@@ -50,9 +50,6 @@
     self.server_mac_address = apf_utils.get_hardware_address(
         self.serverDevice, self.server_iface_name
     )
-    self.client_mac_address = apf_utils.get_hardware_address(
-        self.clientDevice, self.client_iface_name
-    )
 
     # Enable doze mode to activate APF.
     adb_utils.set_doze_mode(self.clientDevice, True)
diff --git a/tests/cts/multidevices/apfv4_test.py b/tests/cts/multidevices/apfv4_test.py
index aa535fd..7795be5 100644
--- a/tests/cts/multidevices/apfv4_test.py
+++ b/tests/cts/multidevices/apfv4_test.py
@@ -53,7 +53,7 @@
   )  # Declare inputs for state_str and expected_result.
   def test_apf_drop_ethertype_not_allowed(self, blocked_ether_type):
     # Ethernet header (14 bytes).
-    packet = self.client_mac_address.replace(":", "")  # Destination MAC
+    packet = ETHER_BROADCAST_ADDR  # Destination MAC (broadcast)
     packet += self.server_mac_address.replace(":", "")  # Source MAC
     packet += blocked_ether_type
 
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
index d801fba..ab2fb99 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsDiscoveryManagerTests.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -499,7 +500,7 @@
         verify(executorProvider).shutdownExecutorService(mockExecutorService);
         verify(mockServiceTypeClientType1Network1).stopSendAndReceive(mockListenerOne);
         verify(socketClient).stopDiscovery();
-        verify(mockServiceCache).removeServices(cacheKey);
+        verify(mockServiceCache, timeout(DEFAULT_TIMEOUT)).removeServices(cacheKey);
     }
 
     @Test
@@ -523,7 +524,7 @@
         runOnHandler(() -> callback.onSocketDestroyed(SOCKET_KEY_NETWORK_1));
         verify(mockServiceTypeClientType1Network1).notifySocketDestroyed();
         verify(executorProvider).shutdownExecutorService(mockExecutorService);
-        verify(mockServiceCache).removeServices(cacheKey);
+        verify(mockServiceCache, timeout(DEFAULT_TIMEOUT)).removeServices(cacheKey);
     }
 
     private MdnsPacket createMdnsPacket(String serviceType) {