[CLATJ#5] libclat: move detect_mtu() from netd to apex

detect_mtu() is moved from ClatdController without behavior
change. The unique_fd for socket fd is replaced by primitive int
because libbase is not supported in mainline.

Bug: 212345928
Test: build and boot
      atest libclat_test
Change-Id: Ib9c1a9d4b9e1c141d88164e8489c5044fdf70685
diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp
index a45ffa6..9fe441a 100644
--- a/service/native/libs/libclat/Android.bp
+++ b/service/native/libs/libclat/Android.bp
@@ -22,6 +22,7 @@
     srcs: ["clatutils.cpp"],
     stl: "libc++_static",
     static_libs: ["libip_checksum"],
+    shared_libs: ["liblog"],
     export_include_dirs: ["include"],
     min_sdk_version: "30",
     apex_available: ["com.android.tethering"],
@@ -39,4 +40,5 @@
         "libclat",
         "libip_checksum",
     ],
+    shared_libs: ["liblog"],
 }
\ No newline at end of file
diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp
index 9ceed75..8f037ad 100644
--- a/service/native/libs/libclat/clatutils.cpp
+++ b/service/native/libs/libclat/clatutils.cpp
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#define LOG_TAG "clatutils"
+
 #include "libclat/clatutils.h"
 
 #include <errno.h>
+#include <log/log.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -23,6 +26,9 @@
 #include "checksum.h"
 }
 
+// Sync from system/netd/include/netid_client.h.
+#define MARK_UNSET 0u
+
 namespace android {
 namespace net {
 namespace clat {
@@ -148,6 +154,55 @@
     return 0;
 }
 
+int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark) {
+    // Create an IPv6 UDP socket.
+    int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (s < 0) {
+        int ret = errno;
+        ALOGE("socket(AF_INET6, SOCK_DGRAM, 0) failed: %s", strerror(errno));
+        return -ret;
+    }
+
+    // Socket's mark affects routing decisions (network selection)
+    if ((mark != MARK_UNSET) && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) {
+        int ret = errno;
+        ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno));
+        close(s);
+        return -ret;
+    }
+
+    // Try to connect udp socket to plat_subnet(96 bits):plat_suffix(32 bits)
+    struct sockaddr_in6 dst = {
+            .sin6_family = AF_INET6,
+            .sin6_addr = *plat_subnet,
+    };
+    dst.sin6_addr.s6_addr32[3] = plat_suffix;
+    if (connect(s, (struct sockaddr*)&dst, sizeof(dst))) {
+        int ret = errno;
+        ALOGE("connect() failed: %s", strerror(errno));
+        close(s);
+        return -ret;
+    }
+
+    // Fetch the socket's IPv6 mtu - this is effectively fetching mtu from routing table
+    int mtu;
+    socklen_t sz_mtu = sizeof(mtu);
+    if (getsockopt(s, SOL_IPV6, IPV6_MTU, &mtu, &sz_mtu)) {
+        int ret = errno;
+        ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(errno));
+        close(s);
+        return -ret;
+    }
+    if (sz_mtu != sizeof(mtu)) {
+        ALOGE("getsockopt(SOL_IPV6, IPV6_MTU) returned unexpected size: %d", sz_mtu);
+        close(s);
+        return -EFAULT;
+    }
+    close(s);
+
+    return mtu;
+}
+
 }  // namespace clat
 }  // namespace net
 }  // namespace android
diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp
index 0b38bce..bb9678d 100644
--- a/service/native/libs/libclat/clatutils_test.cpp
+++ b/service/native/libs/libclat/clatutils_test.cpp
@@ -150,6 +150,11 @@
     EXPECT_GE(3210000, onebits);
 }
 
+TEST_F(ClatUtils, DetectMtu) {
+    // ::1 with bottom 32 bits set to 1 is still ::1 which routes via lo with mtu of 64KiB
+    ASSERT_EQ(detect_mtu(&in6addr_loopback, htonl(1), 0 /*MARK_UNSET*/), 65536);
+}
+
 }  // namespace clat
 }  // namespace net
 }  // namespace android
diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h
index d1e2277..c8f83f1 100644
--- a/service/native/libs/libclat/include/libclat/clatutils.h
+++ b/service/native/libs/libclat/include/libclat/clatutils.h
@@ -25,6 +25,7 @@
 void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
 int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix,
                         in6_addr* v6);
+int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark);
 
 // For testing
 typedef bool (*isIpv4AddrFreeFn)(in_addr_t);