Snap for 8005954 from e38570e4b4f573cff262a6313fb577bd93ad873d to sdk-release

Change-Id: Ie846e219bd34c562242c3f19f937afc30f0e1ef7
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 8e87250..c34fbcf 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -228,19 +228,6 @@
 
 static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction) {
     uint32_t sock_uid = bpf_get_socket_uid(skb);
-    // Always allow and never count clat traffic. Only the IPv4 traffic on the stacked
-    // interface is accounted for and subject to usage restrictions.
-    if (sock_uid == AID_CLAT) {
-        return BPF_PASS;
-    }
-
-    int match = bpf_owner_match(skb, sock_uid, direction);
-    if ((direction == BPF_EGRESS) && (match == BPF_DROP)) {
-        // If an outbound packet is going to be dropped, we do not count that
-        // traffic.
-        return match;
-    }
-
     uint64_t cookie = bpf_get_socket_cookie(skb);
     UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
     uint32_t uid, tag;
@@ -252,6 +239,20 @@
         tag = 0;
     }
 
+    // Always allow and never count clat traffic. Only the IPv4 traffic on the stacked
+    // interface is accounted for and subject to usage restrictions.
+    // TODO: remove sock_uid check once Nat464Xlat javaland adds the socket tag AID_CLAT for clat.
+    if (sock_uid == AID_CLAT || uid == AID_CLAT) {
+        return BPF_PASS;
+    }
+
+    int match = bpf_owner_match(skb, sock_uid, direction);
+    if ((direction == BPF_EGRESS) && (match == BPF_DROP)) {
+        // If an outbound packet is going to be dropped, we do not count that
+        // traffic.
+        return match;
+    }
+
 // Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
 // Keep TAG_SYSTEM_DNS in sync with DnsResolver/include/netd_resolv/resolv.h
 // and TrafficStatsConstants.java
@@ -305,8 +306,14 @@
     // Clat daemon does not generate new traffic, all its traffic is accounted for already
     // on the v4-* interfaces (except for the 20 (or 28) extra bytes of IPv6 vs IPv4 overhead,
     // but that can be corrected for later when merging v4-foo stats into interface foo's).
+    // TODO: remove sock_uid check once Nat464Xlat javaland adds the socket tag AID_CLAT for clat.
     uint32_t sock_uid = bpf_get_socket_uid(skb);
     if (sock_uid == AID_CLAT) return BPF_NOMATCH;
+    if (sock_uid == AID_SYSTEM) {
+        uint64_t cookie = bpf_get_socket_cookie(skb);
+        UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
+        if (utag && utag->uid == AID_CLAT) return BPF_NOMATCH;
+    }
 
     uint32_t key = skb->ifindex;
     update_iface_stats_map(skb, BPF_EGRESS, &key);
diff --git a/server/Android.bp b/server/Android.bp
index c3b2bfc..1ac04fe 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -84,6 +84,9 @@
         "netd_aidl_interface-V7-cpp",
         "netd_event_listener_interface-V1-cpp",
     ],
+    static_libs: [
+        "libip_checksum",
+    ],
     aidl: {
         export_aidl_headers: true,
         local_include_dirs: ["binder"],
@@ -130,6 +133,7 @@
         "oemnetd_aidl_interface-cpp",
     ],
     static_libs: [
+        "libip_checksum",
         "libnetd_server",
     ],
     srcs: [
@@ -222,6 +226,7 @@
     ],
     static_libs: [
         "libgmock",
+        "libip_checksum",
         "libnetd_server",
         "libnetd_test_tun_interface",
         "libqtaguid",
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index 747aea9..1b7a22c 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -43,7 +43,7 @@
 #include "netdutils/DumpWriter.h"
 
 extern "C" {
-#include "netutils/checksum.h"
+#include "checksum.h"
 }
 
 #include "Fwmark.h"
@@ -565,8 +565,7 @@
 
     maybeStopBpf(*tracker);
 
-    kill(tracker->pid, SIGTERM);
-    waitpid(tracker->pid, nullptr, 0);
+    ::stopProcess(tracker->pid, "clatd");
 
     setIptablesDropRule(false, tracker->iface, tracker->pfx96String, tracker->v6Str);
     mClatdTrackers.erase(interface);
diff --git a/server/ClatdControllerTest.cpp b/server/ClatdControllerTest.cpp
index d3a2aa7..2e5de02 100644
--- a/server/ClatdControllerTest.cpp
+++ b/server/ClatdControllerTest.cpp
@@ -27,7 +27,7 @@
 #include <netutils/ifc.h>
 
 extern "C" {
-#include <netutils/checksum.h>
+#include <checksum.h>
 }
 
 #include "ClatdController.h"
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index 7504fb9..2ce50df 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -416,37 +416,6 @@
     setOnAllInterfaces(ipv6_proc_path, "use_optimistic", value);
 }
 
-StatusOr<std::vector<std::string>> InterfaceController::getIfaceNames() {
-    std::vector<std::string> ifaceNames;
-    DIR* d;
-    struct dirent* de;
-
-    if (!(d = opendir("/sys/class/net"))) {
-        return statusFromErrno(errno, "Cannot open iface directory");
-    }
-    while ((de = readdir(d))) {
-        if ((de->d_type != DT_DIR) && (de->d_type != DT_LNK)) continue;
-        if (de->d_name[0] == '.') continue;
-        ifaceNames.push_back(std::string(de->d_name));
-    }
-    closedir(d);
-    return ifaceNames;
-}
-
-StatusOr<std::map<std::string, uint32_t>> InterfaceController::getIfaceList() {
-    std::map<std::string, uint32_t> ifacePairs;
-
-    ASSIGN_OR_RETURN(auto ifaceNames, getIfaceNames());
-
-    for (const auto& name : ifaceNames) {
-        uint32_t ifaceIndex = if_nametoindex(name.c_str());
-        if (ifaceIndex) {
-            ifacePairs.insert(std::pair<std::string, uint32_t>(name, ifaceIndex));
-        }
-    }
-    return ifacePairs;
-}
-
 namespace {
 
 std::string hwAddrToStr(unsigned char* hwaddr) {
diff --git a/server/InterfaceController.h b/server/InterfaceController.h
index e21c75d..e9dce01 100644
--- a/server/InterfaceController.h
+++ b/server/InterfaceController.h
@@ -59,9 +59,6 @@
     static int setParameter(const char* family, const char* which, const char* ifName,
                             const char* parameter, const char* value);
 
-    static android::netdutils::StatusOr<std::vector<std::string>> getIfaceNames();
-    static android::netdutils::StatusOr<std::map<std::string, uint32_t>> getIfaceList();
-
     static std::mutex mutex;
 
   private:
diff --git a/server/InterfaceControllerTest.cpp b/server/InterfaceControllerTest.cpp
index 78d507f..006018d 100644
--- a/server/InterfaceControllerTest.cpp
+++ b/server/InterfaceControllerTest.cpp
@@ -22,6 +22,7 @@
 #include <gtest/gtest.h>
 
 #include <netdutils/MockSyscalls.h>
+#include <netdutils/Utils.h>
 
 #include "InterfaceController.h"
 
@@ -36,14 +37,16 @@
 namespace {
 
 using netdutils::Fd;
+using netdutils::getIfaceList;
+using netdutils::getIfaceNames;
+using netdutils::makeSlice;
 using netdutils::ScopedMockSyscalls;
 using netdutils::Slice;
 using netdutils::Status;
+using netdutils::statusFromErrno;
 using netdutils::StatusOr;
 using netdutils::UniqueFd;
-using netdutils::makeSlice;
 using netdutils::status::ok;
-using netdutils::statusFromErrno;
 
 constexpr Fd kDevRandomFd(777);
 constexpr Fd kStableSecretFd(9999);
@@ -179,7 +182,7 @@
 class GetIfaceListTest : public testing::Test {};
 
 TEST_F(GetIfaceListTest, IfaceNames) {
-    StatusOr<std::vector<std::string>> ifaceNames = InterfaceController::getIfaceNames();
+    StatusOr<std::vector<std::string>> ifaceNames = getIfaceNames();
     EXPECT_EQ(ok, ifaceNames.status());
     struct ifaddrs *ifaddr, *ifa;
     EXPECT_EQ(0, getifaddrs(&ifaddr));
@@ -192,7 +195,7 @@
 }
 
 TEST_F(GetIfaceListTest, IfaceExist) {
-    StatusOr<std::map<std::string, uint32_t>> ifaceMap = InterfaceController::getIfaceList();
+    StatusOr<std::map<std::string, uint32_t>> ifaceMap = getIfaceList();
     EXPECT_EQ(ok, ifaceMap.status());
     struct ifaddrs *ifaddr, *ifa;
     EXPECT_EQ(0, getifaddrs(&ifaddr));
diff --git a/server/IptablesRestoreController.cpp b/server/IptablesRestoreController.cpp
index b37c7c6..f7ba200 100644
--- a/server/IptablesRestoreController.cpp
+++ b/server/IptablesRestoreController.cpp
@@ -27,6 +27,7 @@
 #include <netdutils/Syscalls.h>
 
 #include "Controllers.h"
+#include "NetdConstants.h"
 
 using android::netdutils::StatusOr;
 using android::netdutils::sSyscalls;
@@ -44,7 +45,9 @@
 
 class IptablesProcess {
 public:
-    IptablesProcess(pid_t pid, int stdIn, int stdOut, int stdErr) :
+    IptablesProcess(const IptablesRestoreController::IptablesProcessType type,
+            pid_t pid, int stdIn, int stdOut, int stdErr) :
+        type(type),
         pid(pid),
         stdIn(stdIn),
         processTerminated(false) {
@@ -76,34 +79,13 @@
         // process was killed by something else on the system). In both cases, it's safe to send the
         // PID a SIGTERM, because the PID continues to exist until its parent (i.e., us) calls
         // waitpid on it, so there's no risk that the PID is reused.
-        int err = kill(pid, SIGTERM);
-        if (err) {
-            err = errno;
-        }
-
-        if (err == ESRCH) {
-            // This means that someone else inside netd but outside this class called waitpid(),
-            // which is a programming error. There's no point in calling waitpid() here since we
-            // know that the process is gone.
-            ALOGE("iptables child process %d unexpectedly disappeared", pid);
-            processTerminated = true;
-            return;
-        }
-
-        if (err) {
-            ALOGE("Error killing iptables child process %d: %s", pid, strerror(err));
-        }
-
-        int status;
-        if (waitpid(pid, &status, 0) == -1) {
-            ALOGE("Error waiting for iptables child process %d: %s", pid, strerror(errno));
-        } else {
-            ALOGW("iptables-restore process %d terminated status=%d", pid, status);
-        }
+        ::stopProcess(pid, (type == IptablesRestoreController::IPTABLES_PROCESS) ?
+                "iptables-restore" : "ip6tables-restore");
 
         processTerminated = true;
     }
 
+    const IptablesRestoreController::IptablesProcessType type;
     const pid_t pid;  // NOLINT(misc-non-private-member-variables-in-classes)
     const int stdIn;  // NOLINT(misc-non-private-member-variables-in-classes)
 
@@ -197,7 +179,8 @@
         ALOGW("close() failed: %s", strerror(errno));
     }
 
-    return new IptablesProcess(child_pid.value(), stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
+    return new IptablesProcess(type,
+            child_pid.value(), stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
 }
 
 // TODO: Return -errno on failure instead of -1.
diff --git a/server/NetdConstants.cpp b/server/NetdConstants.cpp
index f3898f5..6de164f 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -171,3 +171,37 @@
         ALOGE("Can't set control socket %s to FD_CLOEXEC", sock);
     }
 }
+
+// SIGTERM with timeout first, if fail, SIGKILL
+void stopProcess(int pid, const char* processName) {
+    int err = kill(pid, SIGTERM);
+    if (err) {
+        err = errno;
+    }
+    if (err == ESRCH) {
+        // This means that someone else inside netd called this helper function,
+        // which is a programming error. There's no point in calling waitpid() here since we
+        // know that the process is gone.
+        ALOGE("%s child process %d unexpectedly disappeared", processName, pid);
+        return;
+    }
+    if (err) {
+        ALOGE("Error killing %s child process %d: %s", processName, pid, strerror(err));
+    }
+    int status = 0;
+    int ret = 0;
+    for (int count = 0; ret == 0 && count < 50; count++) {
+        usleep(100000); // sleep 0.1s to wait for process stop.
+        ret = waitpid(pid, &status, WNOHANG);
+    }
+    if (ret == 0) {
+        ALOGE("Failed to SIGTERM %s pid=%d, try SIGKILL", processName, pid);
+        kill(pid, SIGKILL);
+        ret = waitpid(pid, &status, 0);
+    }
+    if (ret == -1) {
+        ALOGE("Error waiting for %s child process %d: %s", processName, pid, strerror(errno));
+    } else {
+        ALOGD("%s process %d terminated status=%d", processName, pid, status);
+    }
+}
diff --git a/server/NetdConstants.h b/server/NetdConstants.h
index 2bcc44d..6951239 100644
--- a/server/NetdConstants.h
+++ b/server/NetdConstants.h
@@ -41,6 +41,8 @@
 void blockSigpipe();
 void setCloseOnExec(const char *sock);
 
+void stopProcess(int pid, const char* processName);
+
 // TODO: use std::size() instead.
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 1a8d820..7ef24c7 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -32,6 +32,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <netdutils/DumpWriter.h>
+#include <netdutils/Utils.h>
 #include <utils/Errors.h>
 #include <utils/String16.h>
 
@@ -58,6 +59,7 @@
 using android::net::UidRangeParcel;
 using android::net::netd::aidl::NativeUidRangeConfig;
 using android::netdutils::DumpWriter;
+using android::netdutils::getIfaceNames;
 using android::netdutils::ScopedIndent;
 using android::netdutils::Status;
 using android::os::ParcelFileDescriptor;
@@ -921,7 +923,7 @@
 
 binder::Status NetdNativeService::interfaceGetList(std::vector<std::string>* interfaceListResult) {
     NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-    const auto& ifaceList = InterfaceController::getIfaceNames();
+    const auto& ifaceList = getIfaceNames();
 
     interfaceListResult->clear();
     interfaceListResult->reserve(ifaceList.value().size());
diff --git a/server/NetlinkCommands.cpp b/server/NetlinkCommands.cpp
index acefa8e..7cb08d8 100644
--- a/server/NetlinkCommands.cpp
+++ b/server/NetlinkCommands.cpp
@@ -84,6 +84,11 @@
 // Returns -errno if there was an error or if the kernel reported an error.
 OPTNONE int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen,
                                const NetlinkDumpCallback* callback) {
+    int sock = openNetlinkSocket(NETLINK_ROUTE);
+    if (sock < 0) {
+        return sock;
+    }
+
     nlmsghdr nlmsg = {
         .nlmsg_type = action,
         .nlmsg_flags = flags,
@@ -94,14 +99,11 @@
         nlmsg.nlmsg_len += iov[i].iov_len;
     }
 
-    int sock = openNetlinkSocket(NETLINK_ROUTE);
-    if (sock < 0) {
-        return sock;
-    }
-
+    ssize_t writevRet = writev(sock, iov, iovlen);
+    // Don't let pointers to the stack escape.
+    iov[0] = {nullptr, 0};
     int ret = 0;
-
-    if (writev(sock, iov, iovlen) == -1) {
+    if (writevRet == -1) {
         ret = -errno;
         ALOGE("netlink socket connect/writev failed (%s)", strerror(-ret));
         close(sock);
diff --git a/server/Network.cpp b/server/Network.cpp
index 72a1545..85f942f 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -86,7 +86,7 @@
 // Check if the user has been added to this network. If yes, the highest priority of matching
 // setting is returned by subPriority. Thus caller can make choice among several matching
 // networks.
-bool Network::appliesToUser(uid_t uid, uint32_t* subPriority) const {
+bool Network::appliesToUser(uid_t uid, int32_t* subPriority) const {
     for (const auto& [priority, uidRanges] : mUidRangeMap) {
         if (uidRanges.hasUid(uid)) {
             *subPriority = priority;
@@ -96,7 +96,7 @@
     return false;
 }
 
-void Network::addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+void Network::addToUidRangeMap(const UidRanges& uidRanges, int32_t subPriority) {
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end()) {
         iter->second.add(uidRanges);
@@ -105,7 +105,7 @@
     }
 }
 
-void Network::removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+void Network::removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPriority) {
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end()) {
         iter->second.remove(uidRanges);
@@ -113,11 +113,11 @@
             mUidRangeMap.erase(subPriority);
         }
     } else {
-        ALOGW("uidRanges with priority %u not found", subPriority);
+        ALOGW("uidRanges with priority %d not found", subPriority);
     }
 }
 
-bool Network::canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const {
+bool Network::canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const {
     if (uidRanges.overlapsSelf()) {
         ALOGE("uid range %s overlaps self", uidRanges.toString().c_str());
         return false;
@@ -125,7 +125,7 @@
 
     auto iter = mUidRangeMap.find(subPriority);
     if (iter != mUidRangeMap.end() && uidRanges.overlaps(iter->second)) {
-        ALOGE("uid range %s overlaps priority %u %s", uidRanges.toString().c_str(), subPriority,
+        ALOGE("uid range %s overlaps priority %d %s", uidRanges.toString().c_str(), subPriority,
               iter->second.toString().c_str());
         return false;
     }
diff --git a/server/Network.h b/server/Network.h
index aa1b21a..a217f5c 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -24,7 +24,7 @@
 
 namespace android::net {
 
-typedef std::map<uint32_t, UidRanges> UidRangeMap;
+typedef std::map<int32_t, UidRanges> UidRangeMap;
 
 // A Network represents a collection of interfaces participating as a single administrative unit.
 class Network {
@@ -47,11 +47,11 @@
 
     std::string toString() const;
     std::string uidRangesToString() const;
-    bool appliesToUser(uid_t uid, uint32_t* subPriority) const;
-    [[nodiscard]] virtual int addUsers(const UidRanges&, uint32_t /*subPriority*/) {
+    bool appliesToUser(uid_t uid, int32_t* subPriority) const;
+    [[nodiscard]] virtual int addUsers(const UidRanges&, int32_t /*subPriority*/) {
         return -EINVAL;
     };
-    [[nodiscard]] virtual int removeUsers(const UidRanges&, uint32_t /*subPriority*/) {
+    [[nodiscard]] virtual int removeUsers(const UidRanges&, int32_t /*subPriority*/) {
         return -EINVAL;
     };
     bool isSecure() const;
@@ -59,18 +59,18 @@
     virtual bool isUnreachable() { return false; }
     virtual bool isVirtual() { return false; }
     virtual bool canAddUsers() { return false; }
-    virtual bool isValidSubPriority(uint32_t /*priority*/) { return false; }
-    virtual void addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
-    virtual void removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
+    virtual bool isValidSubPriority(int32_t /*priority*/) { return false; }
+    virtual void addToUidRangeMap(const UidRanges& uidRanges, int32_t subPriority);
+    virtual void removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPriority);
 
 protected:
     explicit Network(unsigned netId, bool mSecure = false);
-    bool canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const;
+    bool canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const;
 
     const unsigned mNetId;
     std::set<std::string> mInterfaces;
     // Each subsidiary priority maps to a set of UID ranges of a feature.
-    std::map<uint32_t, UidRanges> mUidRangeMap;
+    std::map<int32_t, UidRanges> mUidRangeMap;
     const bool mSecure;
 
 private:
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 827aa4f..3f337a7 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -42,11 +42,13 @@
 #include "UnreachableNetwork.h"
 #include "VirtualNetwork.h"
 #include "netdutils/DumpWriter.h"
+#include "netdutils/Utils.h"
 #include "netid_client.h"
 
 #define DBG 0
 
 using android::netdutils::DumpWriter;
+using android::netdutils::getIfaceNames;
 
 namespace android::net {
 
@@ -150,7 +152,7 @@
     // TODO: perhaps only remove the clsact on the interface which is added by
     // RouteController::addInterfaceToPhysicalNetwork. Currently, the netd only
     // attach the clsact to the interface for the physical network.
-    const auto& ifaces = InterfaceController::getIfaceNames();
+    const auto& ifaces = getIfaceNames();
     if (isOk(ifaces)) {
         for (const std::string& iface : ifaces.value()) {
             if (int ifIndex = if_nametoindex(iface.c_str())) {
@@ -617,7 +619,7 @@
 }  // namespace
 
 int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
-                                         uint32_t subPriority) {
+                                         int32_t subPriority) {
     ScopedWLock lock(mRWLock);
     Network* network = getNetworkLocked(netId);
     if (int ret = isWrongNetworkForUidRanges(netId, network)) {
@@ -627,7 +629,7 @@
 }
 
 int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
-                                              uint32_t subPriority) {
+                                              int32_t subPriority) {
     ScopedWLock lock(mRWLock);
     Network* network = getNetworkLocked(netId);
     if (int ret = isWrongNetworkForUidRanges(netId, network)) {
@@ -799,7 +801,7 @@
 }
 
 VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
-    uint32_t subPriority;
+    int32_t subPriority;
     for (const auto& [_, network] : mNetworks) {
         if (network->isVirtual() && network->appliesToUser(uid, &subPriority)) {
             return static_cast<VirtualNetwork*>(network);
@@ -814,9 +816,9 @@
 // undefined. That is a configuration error.
 Network* NetworkController::getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const {
     Network* bestNetwork = nullptr;
-    unsigned bestSubPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
+    int32_t bestSubPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
     for (const auto& [netId, network] : mNetworks) {
-        uint32_t subPriority;
+        int32_t subPriority;
         if (!network->isPhysical() && !network->isUnreachable()) continue;
         if (!network->appliesToUser(uid, &subPriority)) continue;
         if (subPriority < bestSubPriority) {
@@ -852,7 +854,7 @@
         return 0;
     }
     // If the UID wants to use a VPN, it can do so if and only if the VPN applies to the UID.
-    uint32_t subPriority;
+    int32_t subPriority;
     if (network->isVirtual()) {
         return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
     }
diff --git a/server/NetworkController.h b/server/NetworkController.h
index a61ac39..fdba317 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -120,9 +120,9 @@
                                                const std::vector<unsigned>& netIds);
 
     [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
-                                        uint32_t subPriority);
+                                        int32_t subPriority);
     [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
-                                             uint32_t subPriority);
+                                             int32_t subPriority);
 
     // |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
     // route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index f270317..4eb22cc 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -164,7 +164,7 @@
     return 0;
 }
 
-int PhysicalNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int PhysicalNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
@@ -181,7 +181,7 @@
     return 0;
 }
 
-int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     for (const std::string& interface : mInterfaces) {
@@ -236,9 +236,12 @@
     return 0;
 }
 
-bool PhysicalNetwork::isValidSubPriority(uint32_t priority) {
-    return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
-           priority <= UidRanges::LOWEST_SUB_PRIORITY;
+bool PhysicalNetwork::isValidSubPriority(int32_t priority) {
+    // RESERVED_SUB_PRIORITY and INT_MAX are for special purpose.
+    return priority == UidRanges::RESERVED_SUB_PRIORITY ||
+           (priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
+            priority <= UidRanges::LOWEST_SUB_PRIORITY) ||
+           priority == INT_MAX;
 }
 
 }  // namespace android::net
diff --git a/server/PhysicalNetwork.h b/server/PhysicalNetwork.h
index d9461b2..f114cca 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -42,8 +42,8 @@
 
     [[nodiscard]] int addAsDefault();
     [[nodiscard]] int removeAsDefault();
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+    [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
     bool isPhysical() override { return true; }
     bool canAddUsers() override { return true; }
 
@@ -53,7 +53,7 @@
     [[nodiscard]] int removeInterface(const std::string& interface) override;
     int destroySocketsLackingPermission(Permission permission);
     void invalidateRouteCache(const std::string& interface);
-    bool isValidSubPriority(uint32_t priority) override;
+    bool isValidSubPriority(int32_t priority) override;
 
     Delegate* const mDelegate;
     Permission mPermission;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index bea7c13..c290db9 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -239,10 +239,15 @@
 //   range (inclusive). Otherwise, the rule matches packets from all UIDs.
 //
 // Returns 0 on success or negative errno on failure.
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint8_t ruleType,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint8_t ruleType,
                                       uint32_t table, uint32_t fwmark, uint32_t mask,
                                       const char* iif, const char* oif, uid_t uidStart,
                                       uid_t uidEnd) {
+    if (priority < 0) {
+        ALOGE("invalid IP-rule priority %d", priority);
+        return -ERANGE;
+    }
+
     // Ensure that if you set a bit in the fwmark, it's not being ignored by the mask.
     if (fwmark & ~mask) {
         ALOGE("mask 0x%x does not select all the bits set in fwmark 0x%x", mask, fwmark);
@@ -326,14 +331,14 @@
     return 0;
 }
 
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint32_t table,
                                       uint32_t fwmark, uint32_t mask, const char* iif,
                                       const char* oif, uid_t uidStart, uid_t uidEnd) {
     return modifyIpRule(action, priority, FR_ACT_TO_TBL, table, fwmark, mask, iif, oif, uidStart,
                         uidEnd);
 }
 
-[[nodiscard]] static int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+[[nodiscard]] static int modifyIpRule(uint16_t action, int32_t priority, uint32_t table,
                                       uint32_t fwmark, uint32_t mask) {
     return modifyIpRule(action, priority, table, fwmark, mask, IIF_NONE, OIF_NONE, INVALID_UID,
                         INVALID_UID);
@@ -486,14 +491,14 @@
 // have, if they are subject to this VPN, their traffic has to go through it. Allows the traffic to
 // bypass the VPN if the protectedFromVpn bit is set.
 [[nodiscard]] static int modifyVpnUidRangeRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
-                                               uint32_t subPriority, bool secure, bool add) {
+                                               int32_t subPriority, bool secure, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
     fwmark.protectedFromVpn = false;
     mask.protectedFromVpn = true;
 
-    uint32_t priority;
+    int32_t priority;
 
     if (secure) {
         priority = RULE_PRIORITY_SECURE_VPN;
@@ -539,7 +544,7 @@
 // modifyNetworkPermission().
 [[nodiscard]] static int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
                                                    Permission permission, uid_t uidStart,
-                                                   uid_t uidEnd, uint32_t subPriority, bool add) {
+                                                   uid_t uidEnd, int32_t subPriority, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
@@ -563,7 +568,7 @@
 // the outgoing interface (typically for link-local communications).
 [[nodiscard]] static int modifyOutputInterfaceRules(const char* interface, uint32_t table,
                                                     Permission permission, uid_t uidStart,
-                                                    uid_t uidEnd, uint32_t subPriority, bool add) {
+                                                    uid_t uidEnd, int32_t subPriority, bool add) {
     Fwmark fwmark;
     Fwmark mask;
 
@@ -735,7 +740,7 @@
 }
 
 [[nodiscard]] static int modifyUidNetworkRule(unsigned netId, uint32_t table, uid_t uidStart,
-                                              uid_t uidEnd, uint32_t subPriority, bool add,
+                                              uid_t uidEnd, int32_t subPriority, bool add,
                                               bool explicitSelect) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
@@ -763,7 +768,7 @@
 }
 
 [[nodiscard]] static int modifyUidDefaultNetworkRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
-                                                     uint32_t subPriority, bool add) {
+                                                     int32_t subPriority, bool add) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
         return -EUSERS;
@@ -854,7 +859,7 @@
 }
 
 [[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd,
-                                                  uint32_t subPriority, bool add,
+                                                  int32_t subPriority, bool add,
                                                   bool explicitSelect) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
@@ -882,7 +887,7 @@
 }
 
 [[nodiscard]] static int modifyUidDefaultUnreachableRule(uid_t uidStart, uid_t uidEnd,
-                                                         uint32_t subPriority, bool add) {
+                                                         int32_t subPriority, bool add) {
     if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
         ALOGE("modifyUidDefaultUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
         return -EUSERS;
diff --git a/server/RouteController.h b/server/RouteController.h
index 039ef3c..9b7b15c 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -30,11 +30,11 @@
 namespace android::net {
 
 // clang-format off
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM     = 10000;
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF        = 11000;
-const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL     = 12000;
-const uint32_t RULE_PRIORITY_SECURE_VPN              = 13000;
-const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN        = 14000;
+constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM     = 10000;
+constexpr int32_t RULE_PRIORITY_VPN_OVERRIDE_OIF        = 11000;
+constexpr int32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL     = 12000;
+constexpr int32_t RULE_PRIORITY_SECURE_VPN              = 13000;
+constexpr int32_t RULE_PRIORITY_PROHIBIT_NON_VPN        = 14000;
 // Rules used when applications explicitly select a network that they have permission to use only
 // because they are in the list of UID ranges for that network.
 //
@@ -42,21 +42,21 @@
 // not have the necessary permission bits in the fwmark. We cannot just give any socket on any of
 // these networks the permission bits, because if the UID that created the socket loses access to
 // the network, then the socket must not match any rule that selects that network.
-const uint32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK    = 15000;
-const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK        = 16000;
-const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE        = 17000;
-const uint32_t RULE_PRIORITY_LEGACY_SYSTEM           = 18000;
-const uint32_t RULE_PRIORITY_LEGACY_NETWORK          = 19000;
-const uint32_t RULE_PRIORITY_LOCAL_NETWORK           = 20000;
-const uint32_t RULE_PRIORITY_TETHERING               = 21000;
+constexpr int32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK    = 15000;
+constexpr int32_t RULE_PRIORITY_EXPLICIT_NETWORK        = 16000;
+constexpr int32_t RULE_PRIORITY_OUTPUT_INTERFACE        = 17000;
+constexpr int32_t RULE_PRIORITY_LEGACY_SYSTEM           = 18000;
+constexpr int32_t RULE_PRIORITY_LEGACY_NETWORK          = 19000;
+constexpr int32_t RULE_PRIORITY_LOCAL_NETWORK           = 20000;
+constexpr int32_t RULE_PRIORITY_TETHERING               = 21000;
 // Implicit rules for sockets that connected on a given network because the network was the default
 // network for the UID.
-const uint32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK    = 22000;
-const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK        = 23000;
-const uint32_t RULE_PRIORITY_BYPASSABLE_VPN          = 24000;
+constexpr int32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK    = 22000;
+constexpr int32_t RULE_PRIORITY_IMPLICIT_NETWORK        = 23000;
+constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN          = 24000;
 // reserved for RULE_PRIORITY_UID_VPN_FALLTHROUGH    = 25000;
-const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH         = 26000;
-const uint32_t RULE_PRIORITY_UID_DEFAULT_NETWORK     = 27000;
+constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH         = 26000;
+constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK     = 27000;
 // Rule used when framework wants to disable default network from specified applications. There will
 // be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and
 // UID_DEFAULT_NETWORK when framework is switching user preferences.
@@ -71,9 +71,9 @@
 // The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by
 // ConnectivityService that it has a network in step 1 of the second case. But if it tries to use
 // the network, it will not work. That will potentially cause a user-visible error.
-const uint32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 28000;
-const uint32_t RULE_PRIORITY_DEFAULT_NETWORK         = 29000;
-const uint32_t RULE_PRIORITY_UNREACHABLE             = 32000;
+constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 28000;
+constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK         = 29000;
+constexpr int32_t RULE_PRIORITY_UNREACHABLE             = 32000;
 // clang-format on
 
 class UidRanges;
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index e2b6d7c..49ca8d7 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -133,7 +133,10 @@
     }
     request.nlh.nlmsg_len = len;
 
-    if (writev(mSock, iov, iovcnt) != (ssize_t) len) {
+    ssize_t writevRet = writev(mSock, iov, iovcnt);
+    // Don't let pointers to the stack escape.
+    iov[0] = {nullptr, 0};
+    if (writevRet != (ssize_t)len) {
         return -errno;
     }
 
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index d21c9a4..7919357 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -350,8 +350,7 @@
 
     ALOGD("Stopping tethering services");
 
-    kill(mDaemonPid, SIGTERM);
-    waitpid(mDaemonPid, nullptr, 0);
+    ::stopProcess(mDaemonPid, "tethering(dnsmasq)");
     mDaemonPid = 0;
     close(mDaemonFd);
     mDaemonFd = -1;
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 37adcda..002831f 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -42,11 +42,11 @@
 
 #include <netdutils/Misc.h>
 #include <netdutils/Syscalls.h>
+#include <netdutils/Utils.h>
 #include <processgroup/processgroup.h>
 #include "TrafficController.h"
 #include "bpf/BpfMap.h"
 
-#include "InterfaceController.h"
 #include "NetlinkListener.h"
 #include "netdutils/DumpWriter.h"
 #include "qtaguid/qtaguid.h"
@@ -63,6 +63,7 @@
 using bpf::synchronizeKernelRCU;
 using netdutils::DumpWriter;
 using netdutils::extract;
+using netdutils::getIfaceList;
 using netdutils::ScopedIndent;
 using netdutils::Slice;
 using netdutils::sSyscalls;
@@ -267,7 +268,7 @@
     // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
     // already running, so it will call addInterface() when any new interface appears.
     std::map<std::string, uint32_t> ifacePairs;
-    ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
+    ASSIGN_OR_RETURN(ifacePairs, getIfaceList());
     for (const auto& ifacePair:ifacePairs) {
         addInterface(ifacePair.first.c_str(), ifacePair.second);
     }
diff --git a/server/UidRanges.h b/server/UidRanges.h
index 5ecb464..d9cb31a 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -28,6 +28,7 @@
 
 class UidRanges {
 public:
+    static constexpr int RESERVED_SUB_PRIORITY = -1;
     static constexpr int DEFAULT_SUB_PRIORITY = 0;
     static constexpr int LOWEST_SUB_PRIORITY = 999;
 
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
index 2f801f0..fdebec3 100644
--- a/server/UnreachableNetwork.cpp
+++ b/server/UnreachableNetwork.cpp
@@ -26,7 +26,7 @@
 // The unreachable network is used to reject traffic. It is used for system purposes only.
 UnreachableNetwork::UnreachableNetwork(unsigned netId) : Network(netId) {}
 
-int UnreachableNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int UnreachableNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
@@ -40,7 +40,7 @@
     return 0;
 }
 
-int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     int ret =
@@ -53,9 +53,12 @@
     return 0;
 }
 
-bool UnreachableNetwork::isValidSubPriority(uint32_t priority) {
-    return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
-           priority <= UidRanges::LOWEST_SUB_PRIORITY;
+bool UnreachableNetwork::isValidSubPriority(int32_t priority) {
+    // RESERVED_SUB_PRIORITY and INT_MAX are for special purpose.
+    return priority == UidRanges::RESERVED_SUB_PRIORITY ||
+           (priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
+            priority <= UidRanges::LOWEST_SUB_PRIORITY) ||
+           priority == INT_MAX;
 }
 
 }  // namespace net
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
index f1547d6..d2cefde 100644
--- a/server/UnreachableNetwork.h
+++ b/server/UnreachableNetwork.h
@@ -23,14 +23,14 @@
 class UnreachableNetwork : public Network {
   public:
     explicit UnreachableNetwork(unsigned netId);
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+    [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
     bool isUnreachable() override { return true; }
     bool canAddUsers() override { return true; }
 
   private:
     std::string getTypeString() const override { return "UNREACHABLE"; };
-    bool isValidSubPriority(uint32_t priority) override;
+    bool isValidSubPriority(int32_t priority) override;
 };
 
 }  // namespace android::net
\ No newline at end of file
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 1906e20..acd715d 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -31,7 +31,7 @@
 
 VirtualNetwork::~VirtualNetwork() {}
 
-int VirtualNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int VirtualNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
         return -EINVAL;
     }
@@ -48,7 +48,7 @@
     return 0;
 }
 
-int VirtualNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority) {
     if (!isValidSubPriority(subPriority)) return -EINVAL;
 
     for (const std::string& interface : mInterfaces) {
@@ -89,7 +89,7 @@
     return 0;
 }
 
-bool VirtualNetwork::isValidSubPriority(uint32_t priority) {
+bool VirtualNetwork::isValidSubPriority(int32_t priority) {
     // Only supports default subsidiary permissions.
     return priority == UidRanges::DEFAULT_SUB_PRIORITY;
 }
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index 20c9e2c..5e58ab1 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -33,8 +33,8 @@
 public:
     VirtualNetwork(unsigned netId, bool secure);
     virtual ~VirtualNetwork();
-    [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
-    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+    [[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
+    [[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
     bool isVirtual() override { return true; }
     bool canAddUsers() override { return true; }
 
@@ -42,7 +42,7 @@
     std::string getTypeString() const override { return "VIRTUAL"; };
     [[nodiscard]] int addInterface(const std::string& interface) override;
     [[nodiscard]] int removeInterface(const std::string& interface) override;
-    bool isValidSubPriority(uint32_t priority) override;
+    bool isValidSubPriority(int32_t priority) override;
 };
 
 }  // namespace android::net
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 24168a2..da285c8 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -66,10 +66,12 @@
 #include "netdutils/Fd.h"
 #include "netdutils/Slice.h"
 #include "netdutils/Syscalls.h"
+#include "netdutils/Utils.h"
 
 using android::net::INetd;
 using android::netdutils::DumpWriter;
 using android::netdutils::Fd;
+using android::netdutils::getIfaceNames;
 using android::netdutils::ScopedIndent;
 using android::netdutils::Slice;
 using android::netdutils::Status;
@@ -410,7 +412,7 @@
 }
 
 netdutils::Status XfrmController::flushInterfaces() {
-    const auto& ifaces = InterfaceController::getIfaceNames();
+    const auto& ifaces = getIfaceNames();
     RETURN_IF_NOT_OK(ifaces);
     const String8 ifPrefix8 = String8(INetd::IPSEC_INTERFACE_PREFIX().string());
 
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index d51ca45..fdb1e1f 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -76,6 +76,7 @@
 #include "netdutils/InternetAddresses.h"
 #include "netdutils/Stopwatch.h"
 #include "netdutils/Syscalls.h"
+#include "netdutils/Utils.h"
 #include "netid_client.h"  // NETID_UNSET
 #include "test_utils.h"
 #include "tun_interface.h"
@@ -128,6 +129,7 @@
 using android::net::UidRangeParcel;
 using android::net::UidRanges;
 using android::net::netd::aidl::NativeUidRangeConfig;
+using android::netdutils::getIfaceNames;
 using android::netdutils::IPAddress;
 using android::netdutils::ScopedAddrinfo;
 using android::netdutils::sSyscalls;
@@ -618,7 +620,7 @@
 }
 
 NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId, std::vector<UidRangeParcel> uidRanges,
-                                              uint32_t subPriority) {
+                                              int32_t subPriority) {
     NativeUidRangeConfig res;
     res.netId = netId;
     res.uidRanges = move(uidRanges);
@@ -2693,7 +2695,7 @@
 }
 
 bool compareListInterface(const std::vector<std::string>& interfaceList) {
-    const auto& res = InterfaceController::getIfaceNames();
+    const auto& res = getIfaceNames();
     EXPECT_TRUE(isOk(res));
 
     std::vector<std::string> resIfList;
@@ -4045,7 +4047,7 @@
 #define VPN_NETID TEST_NETID3
 
 void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges,
-                       const std::string& iface, uint32_t subPriority) {
+                       const std::string& iface, int32_t subPriority) {
     ASSERT_EQ(expectedResults.size(), uidRanges.size());
     if (iface.size()) {
         std::string action = StringPrintf("lookup %s ", iface.c_str());
@@ -4087,7 +4089,7 @@
     ASSERT_EQ(expectedResults.size(), uidRangeConfig.uidRanges.size());
     std::string action = StringPrintf("lookup %s ", iface.c_str());
 
-    uint32_t priority;
+    int32_t priority;
     if (secure) {
         priority = RULE_PRIORITY_SECURE_VPN;
     } else {
@@ -4565,10 +4567,10 @@
 TEST_F(NetdBinderTest, UidRangeSubPriority_ValidateInputs) {
     createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID,
                                      /*isSecureVPN=*/true);
-    // Invalid priority -1 on a physical network.
+    // Invalid priority -10 on a physical network.
     NativeUidRangeConfig uidRangeConfig =
             makeNativeUidRangeConfig(APP_DEFAULT_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)},
-                                     UidRanges::DEFAULT_SUB_PRIORITY - 1);
+                                     UidRanges::DEFAULT_SUB_PRIORITY - 10);
     binder::Status status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
     EXPECT_FALSE(status.isOk());
     EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());