linux(4): Handle SO_TIMESTAMPNS socket option

The SO_TIMESTAMPNS enables or disables the receiving of the SCM_TIMESTAMPNS
control message. The cmsg_data field is a struct timespec.
To distinguish between SO_TIMESTAMP and SO_TIMESTAMPNS in the recvmsg()
map the last one to the SO_BINTIME and convert bintime to the timespec.
In the rest, implementation is identical to the SO_TIMESTAMP.

MFC after:		2 weeks
This commit is contained in:
Dmitry Chagin 2022-05-28 23:46:05 +03:00
parent 0e26e54bdf
commit 71bc8bcf66
3 changed files with 67 additions and 0 deletions

View File

@ -77,6 +77,7 @@ struct linux_pemuldata {
uint32_t ptrace_flags; /* used by ptrace(2) */
uint32_t oom_score_adj; /* /proc/self/oom_score_adj */
uint32_t so_timestamp; /* requested timeval */
uint32_t so_timestampns; /* requested timespec */
};
#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx)

View File

@ -551,6 +551,9 @@ linux_to_bsd_so_sockopt(int opt)
case LINUX_SO_TIMESTAMPO:
case LINUX_SO_TIMESTAMPN:
return (SO_TIMESTAMP);
case LINUX_SO_TIMESTAMPNSO:
case LINUX_SO_TIMESTAMPNSN:
return (SO_BINTIME);
case LINUX_SO_ACCEPTCONN:
return (SO_ACCEPTCONN);
case LINUX_SO_PROTOCOL:
@ -661,6 +664,8 @@ bsd_to_linux_cmsg_type(struct proc *p, int cmsg_type)
return (LINUX_SCM_CREDENTIALS);
case SCM_TIMESTAMP:
return (pem->so_timestamp);
case SCM_BINTIME:
return (pem->so_timestampns);
}
return (-1);
}
@ -1554,6 +1559,7 @@ recvmsg_scm_rights(struct thread *td, l_uint flags, socklen_t *datalen,
return (0);
}
static int
recvmsg_scm_creds(socklen_t *datalen, void **data, void **udata)
{
@ -1632,6 +1638,53 @@ _Static_assert(sizeof(struct timeval) == sizeof(l_timeval),
"scm_timestamp sizeof l_timeval");
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
static int
recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data,
void **udata)
{
struct l_timespec64 ts64;
struct l_timespec ts32;
struct timespec ts;
socklen_t len;
void *buf;
if (msg_type == LINUX_SCM_TIMESTAMPNSO)
len = sizeof(ts32);
else
len = sizeof(ts64);
buf = malloc(len, M_LINUX, M_WAITOK);
bintime2timespec(*data, &ts);
if (msg_type == LINUX_SCM_TIMESTAMPNSO) {
ts32.tv_sec = ts.tv_sec;
ts32.tv_nsec = ts.tv_nsec;
memmove(buf, &ts32, len);
} else {
ts64.tv_sec = ts.tv_sec;
ts64.tv_nsec = ts.tv_nsec;
memmove(buf, &ts64, len);
}
*data = *udata = buf;
*datalen = len;
return (0);
}
#else
static int
recvmsg_scm_timestampns(l_int msg_type, socklen_t *datalen, void **data,
void **udata)
{
struct timespec ts;
bintime2timespec(*data, &ts);
memmove(*data, &ts, sizeof(struct timespec));
*datalen = sizeof(struct timespec);
return (0);
}
_Static_assert(sizeof(struct bintime) >= sizeof(struct timespec),
"scm_timestampns sizeof timespec");
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
static int
linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
l_uint flags, struct msghdr *msg)
@ -1755,6 +1808,11 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
&datalen, &data, &udata);
#endif
break;
case SCM_BINTIME:
error = recvmsg_scm_timestampns(linux_cmsg->cmsg_type,
&datalen, &data, &udata);
break;
}
if (error != 0)
goto bad;
@ -1960,6 +2018,10 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
pem = pem_find(p);
pem->so_timestamp = args->optname;
break;
case SO_BINTIME:
pem = pem_find(p);
pem->so_timestampns = args->optname;
break;
default:
break;
}

View File

@ -189,6 +189,8 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
#endif
#define LINUX_SO_TIMESTAMPO 29
#define LINUX_SO_TIMESTAMPN 63
#define LINUX_SO_TIMESTAMPNSO 35
#define LINUX_SO_TIMESTAMPNSN 64
#define LINUX_SO_ACCEPTCONN 30
#define LINUX_SO_PEERSEC 31
#define LINUX_SO_SNDBUFFORCE 32
@ -203,6 +205,8 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
#define LINUX_SCM_CREDENTIALS 0x02
#define LINUX_SCM_TIMESTAMPO LINUX_SO_TIMESTAMPO
#define LINUX_SCM_TIMESTAMPN LINUX_SO_TIMESTAMPN
#define LINUX_SCM_TIMESTAMPNSO LINUX_SO_TIMESTAMPNSO
#define LINUX_SCM_TIMESTAMPNSN LINUX_SO_TIMESTAMPNSN
/* Socket options */
#define LINUX_IP_TOS 1