compat/linux: map TCP_USER_TIMEOUT sockopt into TCP_MAXUNACKTIME

After reading both manual pages, our TCP_MAXUNACKTIME is fairly
similar to the TCP_USER_TIMEOUT, the only considerable difference
is ours is in seconds and linux's in milliseconds.

Round up linux's in setsockopt(2) to a next whole second and
clamp ours getter to UINT_MAX ms.

Reviewed by:	tuexen, glebius
Differential Revision: https://reviews.freebsd.org/D56168
MFC after:	2 weeks
Sponsored by:	Sippy Software, Inc.
This commit is contained in:
Maxim Sobolev
2026-04-01 14:42:50 -07:00
parent 970e0db1c3
commit 5d4a39d8ed
2 changed files with 62 additions and 0 deletions
+61
View File
@@ -594,10 +594,34 @@ linux_to_bsd_tcp_sockopt(int opt)
return (-2);
case LINUX_TCP_MD5SIG:
return (TCP_MD5SIG);
case LINUX_TCP_USER_TIMEOUT:
return (TCP_MAXUNACKTIME);
}
return (-1);
}
static u_int
linux_to_bsd_tcp_user_timeout(l_uint linux_timeout)
{
/*
* Linux exposes TCP_USER_TIMEOUT in milliseconds while
* TCP_MAXUNACKTIME uses whole seconds. Round up partial
* seconds so a non-zero Linux timeout never becomes zero.
*/
return (howmany(linux_timeout, 1000U));
}
static l_uint
bsd_to_linux_tcp_user_timeout(u_int bsd_timeout)
{
if (bsd_timeout > UINT_MAX / 1000U)
return (UINT_MAX);
return (bsd_timeout * 1000U);
}
static int
linux_to_bsd_msg_flags(int flags)
{
@@ -2057,8 +2081,10 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
struct proc *p = td->td_proc;
struct linux_pemuldata *pem;
l_timeval linux_tv;
l_uint linux_timeout;
struct sockaddr *sa;
struct timeval tv;
u_int bsd_timeout;
socklen_t len;
int error, level, name, val;
@@ -2130,6 +2156,24 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
break;
case IPPROTO_TCP:
name = linux_to_bsd_tcp_sockopt(args->optname);
switch (name) {
case TCP_MAXUNACKTIME:
if (args->optlen < sizeof(linux_timeout))
return (EINVAL);
error = copyin(PTRIN(args->optval), &linux_timeout,
sizeof(linux_timeout));
if (error != 0)
return (error);
bsd_timeout = linux_to_bsd_tcp_user_timeout(
linux_timeout);
return (kern_setsockopt(td, args->s, level, name,
&bsd_timeout, UIO_SYSSPACE,
sizeof(bsd_timeout)));
default:
break;
}
break;
case SOL_NETLINK:
name = args->optname;
@@ -2279,10 +2323,12 @@ linux_getsockopt_so_linger(struct thread *td,
int
linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
{
l_uint linux_timeout;
l_timeval linux_tv;
struct timeval tv;
socklen_t tv_len, xulen, len;
struct sockaddr *sa;
u_int bsd_timeout;
struct xucred xu;
struct l_ucred lxu;
int error, level, name, newval;
@@ -2373,6 +2419,21 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
break;
case IPPROTO_TCP:
name = linux_to_bsd_tcp_sockopt(args->optname);
switch (name) {
case TCP_MAXUNACKTIME:
len = sizeof(bsd_timeout);
error = kern_getsockopt(td, args->s, level, name,
&bsd_timeout, UIO_SYSSPACE, &len);
if (error != 0)
return (error);
linux_timeout = bsd_to_linux_tcp_user_timeout(
bsd_timeout);
return (linux_sockopt_copyout(td, &linux_timeout,
sizeof(linux_timeout), args));
default:
break;
}
break;
default:
name = -1;
+1
View File
@@ -322,6 +322,7 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
#define LINUX_TCP_KEEPCNT 6
#define LINUX_TCP_INFO 11
#define LINUX_TCP_MD5SIG 14
#define LINUX_TCP_USER_TIMEOUT 18
struct l_ifmap {
l_ulong mem_start;