Index: src/sys/netinet/tcp_input.c =================================================================== --- src/sys/netinet/tcp_input.c (revision 177) +++ src/sys/netinet/tcp_input.c (working copy) @@ -158,6 +158,9 @@ SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD, &tcp_reass_overflows, 0, "Global number of TCP Segment Reassembly Queue Overflows"); +int tcp_ts_perconn = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, ts_perconn, CTLFLAG_RW, + &tcp_ts_perconn, 0, "Per connection TCP timestamps"); struct inpcbhead tcb; #define tcb6 tcb /* for KAME src sync over BSD*'s */ @@ -1091,7 +1094,7 @@ if (to.to_flags & TOF_TS) { tp->t_flags |= TF_RCVD_TSTMP; tp->ts_recent = to.to_tsval; - tp->ts_recent_age = ticks; + tp->ts_recent_age = TCP_TIMESTAMP(tp); } if (to.to_flags & TOF_MSS) tcp_mss(tp, to.to_mss); @@ -1142,7 +1145,7 @@ */ if ((to.to_flags & TOF_TS) != 0 && SEQ_LEQ(th->th_seq, tp->last_ack_sent)) { - tp->ts_recent_age = ticks; + tp->ts_recent_age = TCP_TIMESTAMP(tp); tp->ts_recent = to.to_tsval; } @@ -1187,8 +1190,8 @@ */ if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) { - tcp_xmit_timer(tp, - ticks - to.to_tsecr + 1); + tcp_xmit_timer(tp, TCP_TIMESTAMP(tp) - + to.to_tsecr + 1); } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { tcp_xmit_timer(tp, @@ -1575,7 +1578,8 @@ TSTMP_LT(to.to_tsval, tp->ts_recent)) { /* Check to see if ts_recent is over 24 days old. */ - if ((int)(ticks - tp->ts_recent_age) > TCP_PAWS_IDLE) { + if ((int)(TCP_TIMESTAMP(tp) - tp->ts_recent_age) > + TCP_PAWS_IDLE) { /* * Invalidate ts_recent. If this segment updates * ts_recent, the age will be reset later and ts_recent @@ -1735,7 +1739,7 @@ SEQ_LEQ(th->th_seq, tp->last_ack_sent) && SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen + ((thflags & (TH_SYN|TH_FIN)) != 0))) { - tp->ts_recent_age = ticks; + tp->ts_recent_age = TCP_TIMESTAMP(tp); tp->ts_recent = to.to_tsval; } @@ -2071,7 +2075,7 @@ */ if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) { - tcp_xmit_timer(tp, ticks - to.to_tsecr + 1); + tcp_xmit_timer(tp, TCP_TIMESTAMP(tp) - to.to_tsecr + 1); } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { tcp_xmit_timer(tp, ticks - tp->t_rtttime); } @@ -2617,7 +2621,8 @@ * If echoed timestamp is later than the current time, * fall back to non RFC1323 RTT calculation. */ - if ((to->to_tsecr != 0) && TSTMP_GT(to->to_tsecr, ticks)) + if ((to->to_tsecr != 0) && TSTMP_GT(to->to_tsecr, + TCP_TIMESTAMP(tp))) to->to_tsecr = 0; break; #ifdef TCP_SIGNATURE Index: src/sys/netinet/tcp_subr.c =================================================================== --- src/sys/netinet/tcp_subr.c (revision 177) +++ src/sys/netinet/tcp_subr.c (working copy) @@ -622,6 +622,7 @@ tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_rcvtime = ticks; tp->t_bw_rtttime = ticks; + tp->ts_timebase = ticks; /* * IPv4 TTL initialization is necessary for an IPv6 socket as well, * because the socket may be bound to an IPv6 wildcard address, @@ -1693,10 +1694,13 @@ * Set t_recent if timestamps are used on the connection. */ if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) == - (TF_REQ_TSTMP|TF_RCVD_TSTMP)) + (TF_REQ_TSTMP|TF_RCVD_TSTMP)) { tw->t_recent = tp->ts_recent; - else + tw->t_timebase = tp->ts_timebase; + } else { tw->t_recent = 0; + tw->t_timebase = 0; + } tw->snd_nxt = tp->snd_nxt; tw->rcv_nxt = tp->rcv_nxt; @@ -1841,7 +1845,7 @@ /* Form timestamp option as shown in appendix A of RFC 1323. */ *lp++ = htonl(TCPOPT_TSTAMP_HDR); - *lp++ = htonl(ticks); + *lp++ = htonl(ticks - tw->t_timebase); *lp = htonl(tw->t_recent); optp += TCPOLEN_TSTAMP_APPA; } Index: src/sys/netinet/tcp_var.h =================================================================== --- src/sys/netinet/tcp_var.h (revision 177) +++ src/sys/netinet/tcp_var.h (working copy) @@ -50,6 +50,7 @@ LIST_HEAD(tsegqe_head, tseg_qent); extern int tcp_reass_qsize; extern struct uma_zone *tcp_reass_zone; +extern int tcp_ts_perconn; struct sackblk { tcp_seq start; /* start seq no. of sack block */ @@ -175,6 +176,7 @@ u_char request_r_scale; /* pending window scaling */ u_char requested_s_scale; u_long ts_recent; /* timestamp echo data */ + u_long ts_timebase; /* our time base */ u_long ts_recent_age; /* when last updated */ tcp_seq last_ack_sent; @@ -220,6 +222,8 @@ #define TCP_SIG_SPI 0x1000 #endif /* TCP_SIGNATURE */ +#define TCP_TIMESTAMP(tp) (tcp_ts_perconn ? (ticks - (tp)->ts_timebase) : ticks) + /* * Structure to hold TCP options that are only used during segment * processing (in tcp_input), but not held in the tcpcb. @@ -297,6 +301,7 @@ u_short tw_so_options; /* copy of so_options */ struct ucred *tw_cred; /* user credentials */ u_long t_recent; + u_long t_timebase; u_long t_starttime; int tw_time; LIST_ENTRY(tcptw) tw_2msl; Index: src/sys/netinet/tcp_output.c =================================================================== --- src/sys/netinet/tcp_output.c (revision 177) +++ src/sys/netinet/tcp_output.c (working copy) @@ -571,7 +571,7 @@ /* Form timestamp option as shown in appendix A of RFC 1323. */ *lp++ = htonl(TCPOPT_TSTAMP_HDR); - *lp++ = htonl(ticks); + *lp++ = htonl(TCP_TIMESTAMP(tp)); *lp = htonl(tp->ts_recent); optlen += TCPOLEN_TSTAMP_APPA; } Index: src/sys/netinet/tcp_syncache.c =================================================================== --- src/sys/netinet/tcp_syncache.c (revision 177) +++ src/sys/netinet/tcp_syncache.c (working copy) @@ -278,7 +278,7 @@ * The bucket is full, toss the oldest element. */ sc2 = TAILQ_FIRST(&sch->sch_bucket); - sc2->sc_tp->ts_recent = ticks; + sc2->sc_tp->ts_recent = TCP_TIMESTAMP(sc2->sc_tp); syncache_drop(sc2, sch); tcpstat.tcps_sc_bucketoverflow++; } else if (tcp_syncache.cache_count >= tcp_syncache.cache_limit) { @@ -293,7 +293,7 @@ if (sc2 != NULL) break; } - sc2->sc_tp->ts_recent = ticks; + sc2->sc_tp->ts_recent = TCP_TIMESTAMP(sc2->sc_tp); syncache_drop(sc2, NULL); tcpstat.tcps_sc_cacheoverflow++; } @@ -688,7 +688,7 @@ if (sc->sc_flags & SCF_TIMESTAMP) { tp->t_flags |= TF_REQ_TSTMP|TF_RCVD_TSTMP; tp->ts_recent = sc->sc_tsrecent; - tp->ts_recent_age = ticks; + tp->ts_recent_age = TCP_TIMESTAMP(tp); } #ifdef TCP_SIGNATURE if (sc->sc_flags & SCF_SIGNATURE) @@ -892,7 +892,7 @@ if (sc != NULL) break; } - sc->sc_tp->ts_recent = ticks; + sc->sc_tp->ts_recent = TCP_TIMESTAMP(sc->sc_tp); syncache_drop(sc, NULL); tcpstat.tcps_sc_zonefail++; sc = uma_zalloc(tcp_syncache.zone, M_NOWAIT); @@ -1156,9 +1156,12 @@ if (sc->sc_flags & SCF_TIMESTAMP) { u_int32_t *lp = (u_int32_t *)(optp); + /* Reset the time base */ + sc->sc_tp->ts_timebase = ticks; + /* Form timestamp option per appendix A of RFC 1323. */ *lp++ = htonl(TCPOPT_TSTAMP_HDR); - *lp++ = htonl(ticks); + *lp++ = htonl(TCP_TIMESTAMP(sc->sc_tp)); *lp = htonl(sc->sc_tsrecent); optp += TCPOLEN_TSTAMP_APPA; }