diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 17bc1a5a01..30ac297e17 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -67,6 +67,14 @@ struct sockaddr_vm { #define IPV6_FREEBIND 78 #endif +#ifndef IP_RECVFRAGSIZE +#define IP_RECVFRAGSIZE 25 +#endif + +#ifndef IPV6_RECVFRAGSIZE +#define IPV6_RECVFRAGSIZE 77 +#endif + /* linux/sockios.h */ #ifndef SIOCGSKNS #define SIOCGSKNS 0x894C diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 1e53ac4e86..59039bea4f 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1314,3 +1314,35 @@ int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) { return -EAFNOSUPPORT; } } + +int socket_get_mtu(int fd, int af, size_t *ret) { + int mtu, r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu); + break; + + case AF_INET6: + r = getsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, &mtu); + break; + + default: + return -EAFNOSUPPORT; + } + + if (r < 0) + return r; + if (mtu <= 0) + return -EINVAL; + + *ret = (size_t) mtu; + return 0; +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index e353f82a42..240d209c14 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -258,6 +258,19 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) { return 0; } +static inline int getsockopt_int(int fd, int level, int optname, int *ret) { + int v; + socklen_t sl = sizeof(v); + + if (getsockopt(fd, level, optname, &v, &sl) < 0) + return -errno; + if (sl != sizeof(v)) + return -EIO; + + *ret = v; + return 0; +} + int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); @@ -266,6 +279,7 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); int socket_get_family(int fd, int *ret); int socket_set_recvpktinfo(int fd, int af, bool b); int socket_set_unicast_if(int fd, int af, int ifi); + int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val); static inline int socket_set_recverr(int fd, int af, bool b) { return socket_set_option(fd, af, IP_RECVERR, IPV6_RECVERR, b); @@ -282,3 +296,8 @@ static inline int socket_set_freebind(int fd, int af, bool b) { static inline int socket_set_transparent(int fd, int af, bool b) { return socket_set_option(fd, af, IP_TRANSPARENT, IPV6_TRANSPARENT, b); } +static inline int socket_set_recvfragsize(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVFRAGSIZE, IPV6_RECVFRAGSIZE, b); +} + +int socket_get_mtu(int fd, int af, size_t *ret);