git: f801346706ea - stable/14 - ip6: add SO_BINTIME support

From: Jonathan T. Looney <jtl_at_FreeBSD.org>
Date: Mon, 29 Sep 2025 15:13:34 UTC
The branch stable/14 has been updated by jtl:

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

commit f801346706ea75401614df2dba3f85ecea2af03e
Author:     Jonathan T. Looney <jtl@FreeBSD.org>
AuthorDate: 2025-09-12 17:49:17 +0000
Commit:     Jonathan T. Looney <jtl@FreeBSD.org>
CommitDate: 2025-09-29 15:12:49 +0000

    ip6: add SO_BINTIME support
    
    This adds support for obtaining timestamps from IPv6 packets using the
    SO_BINTIME socket option, bringing it in parity with IPv4 behavior.
    
    Enable testing the SO_BINTIME option in the relevant (manual) regression
    test.
    
    PR:             289423
    Reviewed by:    markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D52504
    
    (cherry picked from commit cd02a8a9f8be2085d5242606a79668dc3720e7b0)
---
 sys/netinet6/ip6_input.c                           | 53 +++++++++++++++-------
 .../regression/sockets/udp_pingpong/udp_pingpong.c |  8 ++--
 2 files changed, 39 insertions(+), 22 deletions(-)

diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index b3f10ddc5ea7..2db1b4723edc 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1193,8 +1193,8 @@ ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp,
 {
 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 
-#ifdef SO_TIMESTAMP
-	if ((inp->inp_socket->so_options & SO_TIMESTAMP) != 0) {
+#if defined(SO_TIMESTAMP) && defined(SO_BINTIME)
+	if ((inp->inp_socket->so_options & (SO_TIMESTAMP | SO_BINTIME)) != 0) {
 		union {
 			struct timeval tv;
 			struct bintime bt;
@@ -1202,47 +1202,66 @@ ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp,
 		} t;
 		struct bintime boottimebin, bt1;
 		struct timespec ts1;
+		int ts_clock;
 		bool stamped;
 
+		ts_clock = inp->inp_socket->so_ts_clock;
 		stamped = false;
-		switch (inp->inp_socket->so_ts_clock) {
-		case SO_TS_REALTIME_MICRO:
+
+		/*
+		 * Handle BINTIME first. We create the same output options
+		 * for both SO_BINTIME and the case where SO_TIMESTAMP is
+		 * set with the timestamp clock set to SO_TS_BINTIME.
+		 */
+		if ((inp->inp_socket->so_options & SO_BINTIME) != 0 ||
+		    ts_clock == SO_TS_BINTIME) {
 			if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
 			    M_TSTMP)) {
 				mbuf_tstmp2timespec(m, &ts1);
-				timespec2bintime(&ts1, &bt1);
+				timespec2bintime(&ts1, &t.bt);
 				getboottimebin(&boottimebin);
-				bintime_add(&bt1, &boottimebin);
-				bintime2timeval(&bt1, &t.tv);
+				bintime_add(&t.bt, &boottimebin);
 			} else {
-				microtime(&t.tv);
+				bintime(&t.bt);
 			}
-			*mp = sbcreatecontrol(&t.tv, sizeof(t.tv),
-			    SCM_TIMESTAMP, SOL_SOCKET, M_NOWAIT);
+			*mp = sbcreatecontrol(&t.bt, sizeof(t.bt), SCM_BINTIME,
+			    SOL_SOCKET, M_NOWAIT);
 			if (*mp != NULL) {
 				mp = &(*mp)->m_next;
 				stamped = true;
 			}
-			break;
 
-		case SO_TS_BINTIME:
+			/*
+			 * Suppress other timestamps if SO_TIMESTAMP is not
+			 * set.
+			 */
+			if ((inp->inp_socket->so_options & SO_TIMESTAMP) == 0)
+				ts_clock = SO_TS_BINTIME;
+		}
+
+		switch (ts_clock) {
+		case SO_TS_REALTIME_MICRO:
 			if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
 			    M_TSTMP)) {
 				mbuf_tstmp2timespec(m, &ts1);
-				timespec2bintime(&ts1, &t.bt);
+				timespec2bintime(&ts1, &bt1);
 				getboottimebin(&boottimebin);
-				bintime_add(&t.bt, &boottimebin);
+				bintime_add(&bt1, &boottimebin);
+				bintime2timeval(&bt1, &t.tv);
 			} else {
-				bintime(&t.bt);
+				microtime(&t.tv);
 			}
-			*mp = sbcreatecontrol(&t.bt, sizeof(t.bt), SCM_BINTIME,
-			    SOL_SOCKET, M_NOWAIT);
+			*mp = sbcreatecontrol(&t.tv, sizeof(t.tv),
+			    SCM_TIMESTAMP, SOL_SOCKET, M_NOWAIT);
 			if (*mp != NULL) {
 				mp = &(*mp)->m_next;
 				stamped = true;
 			}
 			break;
 
+		case SO_TS_BINTIME:
+			break;
+
 		case SO_TS_REALTIME:
 			if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR |
 			    M_TSTMP)) {
diff --git a/tools/regression/sockets/udp_pingpong/udp_pingpong.c b/tools/regression/sockets/udp_pingpong/udp_pingpong.c
index 9babe144adcb..23ba8403be6d 100644
--- a/tools/regression/sockets/udp_pingpong/udp_pingpong.c
+++ b/tools/regression/sockets/udp_pingpong/udp_pingpong.c
@@ -602,11 +602,9 @@ main(void)
         test_run(TT_TIMESTAMP, i, 1,
           "send()/recvmsg(), setsockopt(SO_TIMESTAMP, 1)");
         printf("OK\n");
-        if (i == 0) {
-            test_run(TT_BINTIME, i, 1,
-              "send()/recvmsg(), setsockopt(SO_BINTIME, 1)");
-            printf("OK\n");
-        }
+        test_run(TT_BINTIME, i, 1,
+          "send()/recvmsg(), setsockopt(SO_BINTIME, 1)");
+        printf("OK\n");
         test_run(TT_REALTIME_MICRO, i, 1,
           "send()/recvmsg(), setsockopt(SO_TS_CLOCK, SO_TS_REALTIME_MICRO)");
         printf("OK\n");