[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);