diff options
author | bz <bz@FreeBSD.org> | 2012-02-15 16:09:56 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2012-02-15 16:09:56 +0000 |
commit | e7eef5c8119b66a2a14b9e339e440f80c327182a (patch) | |
tree | b0aa46ec2c710c27495fdbd3425f1e1e7f502603 /sys/netinet/tcp_input.c | |
parent | d93961fe9edf9c6624e6d6c918343387bf79d54e (diff) | |
download | FreeBSD-src-e7eef5c8119b66a2a14b9e339e440f80c327182a.zip FreeBSD-src-e7eef5c8119b66a2a14b9e339e440f80c327182a.tar.gz |
Fix PAWS (Protect Against Wrapped Sequence numbers) in cases when
hz >> 1000 and thus getting outside the timestamp clock frequenceny of
1ms < x < 1s per tick as mandated by RFC1323, leading to connection
resets on idle connections.
Always use a granularity of 1ms using getmicrouptime() making all but
relevant callouts independent of hz.
Use getmicrouptime(), not getmicrotime() as the latter may make a jump
possibly breaking TCP nfsroot mounts having our timestamps move forward
for more than 24.8 days in a second without having been idle for that
long.
PR: kern/61404
Reviewed by: jhb, mav, rrs
Discussed with: silby, lstewart
Sponsored by: Sandvine Incorporated (originally in 2011)
MFC after: 6 weeks
Diffstat (limited to 'sys/netinet/tcp_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 0fadf87..1a31c5e 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1493,7 +1493,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, */ if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0)) { to.to_tsecr -= tp->ts_offset; - if (TSTMP_GT(to.to_tsecr, ticks)) + if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks())) to.to_tsecr = 0; } @@ -1518,7 +1518,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, 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_ts_getticks(); } if (to.to_flags & TOF_MSS) tcp_mss(tp, to.to_mss); @@ -1562,7 +1562,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, */ 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_ts_getticks(); tp->ts_recent = to.to_tsval; } @@ -1600,11 +1600,13 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, */ if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) { - if (!tp->t_rttlow || - tp->t_rttlow > ticks - to.to_tsecr) - tp->t_rttlow = ticks - to.to_tsecr; + u_int t; + + t = tcp_ts_getticks() - to.to_tsecr; + if (!tp->t_rttlow || tp->t_rttlow > t) + tp->t_rttlow = t; tcp_xmit_timer(tp, - ticks - to.to_tsecr + 1); + TCP_TS_TO_TICKS(t) + 1); } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { if (!tp->t_rttlow || @@ -2070,7 +2072,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, TSTMP_LT(to.to_tsval, tp->ts_recent)) { /* Check to see if ts_recent is over 24 days old. */ - if (ticks - tp->ts_recent_age > TCP_PAWS_IDLE) { + if (tcp_ts_getticks() - 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 @@ -2229,7 +2231,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, 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_ts_getticks(); tp->ts_recent = to.to_tsval; } @@ -2543,11 +2545,13 @@ process_ACK: * timestamps of 0 or we could calculate a * huge RTT and blow up the retransmit timer. */ - if ((to.to_flags & TOF_TS) != 0 && - to.to_tsecr) { - if (!tp->t_rttlow || tp->t_rttlow > ticks - to.to_tsecr) - tp->t_rttlow = ticks - to.to_tsecr; - tcp_xmit_timer(tp, ticks - to.to_tsecr + 1); + if ((to.to_flags & TOF_TS) != 0 && to.to_tsecr) { + u_int t; + + t = tcp_ts_getticks() - to.to_tsecr; + if (!tp->t_rttlow || tp->t_rttlow > t) + tp->t_rttlow = t; + tcp_xmit_timer(tp, TCP_TS_TO_TICKS(t) + 1); } else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq)) { if (!tp->t_rttlow || tp->t_rttlow > ticks - tp->t_rtttime) tp->t_rttlow = ticks - tp->t_rtttime; |