[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/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