git: 71bc8bcf660b - main - linux(4): Handle SO_TIMESTAMPNS socket option

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Sat, 28 May 2022 20:53:25 UTC
The branch main has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=71bc8bcf660b437b99af1e3d382f7bfdaea5fa9c

commit 71bc8bcf660b437b99af1e3d382f7bfdaea5fa9c
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2022-05-28 20:46:05 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-05-28 20:46:05 +0000

    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
---
 sys/compat/linux/linux_emul.h   |  1 +
 sys/compat/linux/linux_socket.c | 62 +++++++++++++++++++++++++++++++++++++++++
 sys/compat/linux/linux_socket.h |  4 +++
 3 files changed, 67 insertions(+)

diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
index e801bf09ba72..9b552ab9c720 100644
--- a/sys/compat/linux/linux_emul.h
+++ b/sys/compat/linux/linux_emul.h
@@ -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)
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 3360cf48cb16..14f034eb8037 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -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;
 		}
diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h
index 77537afad6ee..ef0c1f24f10a 100644
--- a/sys/compat/linux/linux_socket.h
+++ b/sys/compat/linux/linux_socket.h
@@ -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