The branch stable/15 has been updated by chuck:

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

commit 61c64a84d42f0e43dbfb4a10f5a7213e1761142a
Author:     Chuck Tuffli <[email protected]>
AuthorDate: 2026-06-10 00:22:49 +0000
Commit:     Chuck Tuffli <[email protected]>
CommitDate: 2026-07-10 15:29:29 +0000

    linux: Add TCP_INFO support
    
    Implement the getsockopt for TCP_INFO by mapping FreeBSD's version to
    what Linux expects.
    
    (cherry picked from commit 925ca9b8355d10a0dc85175dc865095c9b3370c4)
---
 sys/compat/linux/linux_socket.c | 47 +++++++++++++++++++--
 sys/compat/linux/linux_socket.h | 92 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 615ef12ec201..56c44039420e 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -589,9 +589,7 @@ linux_to_bsd_tcp_sockopt(int opt)
        case LINUX_TCP_KEEPCNT:
                return (TCP_KEEPCNT);
        case LINUX_TCP_INFO:
-               LINUX_RATELIMIT_MSG_OPT1(
-                   "unsupported TCP socket option TCP_INFO (%d)", opt);
-               return (-2);
+               return (TCP_INFO);
        case LINUX_TCP_MD5SIG:
                return (TCP_MD5SIG);
        }
@@ -2259,6 +2257,42 @@ linux_getsockopt_so_linger(struct thread *td,
        return (linux_sockopt_copyout(td, &ling, len, args));
 }
 
+static int
+linux_getsockopt_tcp_info(struct thread *td,
+    struct linux_getsockopt_args *args)
+{
+       struct tcp_info tinfo;
+       struct l_tcp_info l_tinfo;
+       socklen_t len;
+       int error;
+
+       len = sizeof(tinfo);
+       error = kern_getsockopt(td, args->s, IPPROTO_TCP, TCP_INFO, &tinfo,
+           UIO_SYSSPACE, &len);
+       if (error != 0)
+               return (error);
+       memset(&l_tinfo, 0, sizeof(l_tinfo));
+       l_tinfo.tcpi_state         = tinfo.tcpi_state;
+       l_tinfo.tcpi_options       = tinfo.tcpi_options;
+       l_tinfo.tcpi_snd_wscale    = tinfo.tcpi_snd_wscale;
+       l_tinfo.tcpi_rcv_wscale    = tinfo.tcpi_rcv_wscale;
+       l_tinfo.tcpi_rto           = tinfo.tcpi_rto;
+       l_tinfo.tcpi_snd_mss       = tinfo.tcpi_snd_mss;
+       l_tinfo.tcpi_rcv_mss       = tinfo.tcpi_rcv_mss;
+       l_tinfo.tcpi_last_data_recv = tinfo.tcpi_last_data_recv;
+       l_tinfo.tcpi_rtt           = tinfo.tcpi_rtt;
+       l_tinfo.tcpi_rttvar        = tinfo.tcpi_rttvar;
+       l_tinfo.tcpi_snd_ssthresh  = tinfo.tcpi_snd_ssthresh;
+       l_tinfo.tcpi_snd_cwnd      = tinfo.tcpi_snd_cwnd;
+       l_tinfo.tcpi_rcv_space     = tinfo.tcpi_rcv_space;
+       l_tinfo.tcpi_snd_wnd       = tinfo.tcpi_snd_wnd;
+       l_tinfo.tcpi_rcv_ooopack   = tinfo.tcpi_rcv_ooopack;
+       /* Eqivalent */
+       l_tinfo.tcpi_total_retrans = tinfo.tcpi_snd_rexmitpack;
+
+       return (linux_sockopt_copyout(td, &l_tinfo, len, args));
+}
+
 int
 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
 {
@@ -2355,6 +2389,13 @@ linux_getsockopt(struct thread *td, struct 
linux_getsockopt_args *args)
                name = linux_to_bsd_ip6_sockopt(args->optname);
                break;
        case IPPROTO_TCP:
+               switch (args->optname) {
+               case LINUX_TCP_INFO:
+                       return (linux_getsockopt_tcp_info(td, args));
+                       /* NOTREACHED */
+               default:
+                       break;
+               }
                name = linux_to_bsd_tcp_sockopt(args->optname);
                break;
        default:
diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h
index 68176c3cc401..f69ed90bd584 100644
--- a/sys/compat/linux/linux_socket.h
+++ b/sys/compat/linux/linux_socket.h
@@ -356,6 +356,98 @@ struct l_ifreq {
        } ifr_ifru;
 };
 
+/*
+ * Linux TCP_INFO structure as of v6.19.8
+ *
+ * Comments indicate last field for the given kernel version
+ */
+struct l_tcp_info {
+       uint8_t tcpi_state;
+       uint8_t tcpi_ca_state;
+       uint8_t tcpi_retransmits;
+       uint8_t tcpi_probes;
+       uint8_t tcpi_backoff;
+       uint8_t tcpi_options;
+       uint8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+       uint8_t tcpi_delivery_rate_app_limited:1, tcpi_fastopen_client_fail:2;
+
+       uint32_t        tcpi_rto;
+       uint32_t        tcpi_ato;
+       uint32_t        tcpi_snd_mss;
+       uint32_t        tcpi_rcv_mss;
+
+       uint32_t        tcpi_unacked;
+       uint32_t        tcpi_sacked;
+       uint32_t        tcpi_lost;
+       uint32_t        tcpi_retrans;
+       uint32_t        tcpi_fackets;
+
+       uint32_t        tcpi_last_data_sent;
+       uint32_t        tcpi_last_ack_sent;
+       uint32_t        tcpi_last_data_recv;
+       uint32_t        tcpi_last_ack_recv;
+
+       uint32_t        tcpi_pmtu;
+       uint32_t        tcpi_rcv_ssthresh;
+       uint32_t        tcpi_rtt;
+       uint32_t        tcpi_rttvar;
+       uint32_t        tcpi_snd_ssthresh;
+       uint32_t        tcpi_snd_cwnd;
+       uint32_t        tcpi_advmss;
+       uint32_t        tcpi_reordering;
+
+       uint32_t        tcpi_rcv_rtt;
+       uint32_t        tcpi_rcv_space;
+
+       uint32_t        tcpi_total_retrans;             /* v3.6 */
+
+       uint64_t        tcpi_pacing_rate;
+       uint64_t        tcpi_max_pacing_rate;   /* v3.14 */
+       uint64_t        tcpi_bytes_acked;
+       uint64_t        tcpi_bytes_received;
+       uint32_t        tcpi_segs_out;
+       uint32_t        tcpi_segs_in;                                   /* v4.1 
*/
+
+       uint32_t        tcpi_notsent_bytes;
+       uint32_t        tcpi_min_rtt;
+       uint32_t        tcpi_data_segs_in;
+       uint32_t        tcpi_data_segs_out;             /* v4.5 */
+
+       uint64_t   tcpi_delivery_rate;  /* v4.8 */
+
+       uint64_t        tcpi_busy_time;
+       uint64_t        tcpi_rwnd_limited;
+       uint64_t        tcpi_sndbuf_limited;    /* v4.9 */
+
+       uint32_t        tcpi_delivered;
+       uint32_t        tcpi_delivered_ce;              /* v4.16 */
+
+       uint64_t        tcpi_bytes_sent;
+       uint64_t        tcpi_bytes_retrans;
+       uint32_t        tcpi_dsack_dups;
+       uint32_t        tcpi_reord_seen;                        /* v4.18 */
+
+       uint32_t        tcpi_rcv_ooopack;
+
+       uint32_t        tcpi_snd_wnd;                                   /* v5.3 
*/
+       uint32_t        tcpi_rcv_wnd;
+
+       uint32_t  tcpi_rehash;                                  /* v6.1 */
+
+       uint16_t        tcpi_total_rto;
+       uint16_t        tcpi_total_rto_recoveries;
+       uint32_t        tcpi_total_rto_time;    /* v6.6 */
+       uint32_t        tcpi_received_ce;
+       uint32_t        tcpi_delivered_e1_bytes;
+       uint32_t        tcpi_delivered_e0_bytes;
+       uint32_t        tcpi_delivered_ce_bytes;
+       uint32_t        tcpi_received_e1_bytes;
+       uint32_t        tcpi_received_e0_bytes;
+       uint32_t        tcpi_received_ce_bytes;
+       uint16_t        tcpi_accecn_fail_mode;
+       uint16_t        tcpi_accecn_opt_seen;   /* v6.17 */
+};
+
 /*
  * Define here members which are not exists in the FreeBSD struct ifreq.
  */

Reply via email to