svn commit: r247136 - stable/6/sys/netinet
Mark Johnston
markj at FreeBSD.org
Thu Feb 21 21:48:39 UTC 2013
Author: markj
Date: Thu Feb 21 21:48:38 2013
New Revision: 247136
URL: http://svnweb.freebsd.org/changeset/base/247136
Log:
MFC r239672 (by rrs):
This small change takes care of a race condition
that can occur when both sides close at the same time.
If that occurs, without this fix the connection enters
FIN1 on both sides and they will forever send FIN|ACK at
each other until the connection times out. This is because
we stopped processing the FIN|ACK and thus did not advance
the sequence and so never ACK'd each others FIN. This
fix adjusts it so we *do* process the FIN properly and
the race goes away ;-)
Approved by: emaste (co-mentor)
Modified:
stable/6/sys/netinet/tcp_input.c
Directory Properties:
stable/6/sys/ (props changed)
Modified: stable/6/sys/netinet/tcp_input.c
==============================================================================
--- stable/6/sys/netinet/tcp_input.c Thu Feb 21 21:47:35 2013 (r247135)
+++ stable/6/sys/netinet/tcp_input.c Thu Feb 21 21:48:38 2013 (r247136)
@@ -1908,6 +1908,16 @@ trimthenstep6:
}
} else
tp->snd_cwnd += tp->t_maxseg;
+ if ((thflags & TH_FIN) &&
+ (TCPS_HAVERCVDFIN(tp->t_state) == 0)) {
+ /*
+ * If its a fin we need to process
+ * it to avoid a race where both
+ * sides enter FIN-WAIT and send FIN|ACK
+ * at the same time.
+ */
+ break;
+ }
(void) tcp_output(tp);
goto drop;
} else if (tp->t_dupacks == tcprexmtthresh) {
@@ -1951,6 +1961,16 @@ trimthenstep6:
}
tp->snd_nxt = th->th_ack;
tp->snd_cwnd = tp->t_maxseg;
+ if ((thflags & TH_FIN) &&
+ (TCPS_HAVERCVDFIN(tp->t_state) == 0)) {
+ /*
+ * If its a fin we need to process
+ * it to avoid a race where both
+ * sides enter FIN-WAIT and send FIN|ACK
+ * at the same time.
+ */
+ break;
+ }
(void) tcp_output(tp);
KASSERT(tp->snd_limited <= 2,
("tp->snd_limited too big"));
@@ -1974,6 +1994,16 @@ trimthenstep6:
(tp->snd_nxt - tp->snd_una) +
(tp->t_dupacks - tp->snd_limited) *
tp->t_maxseg;
+ if ((thflags & TH_FIN) &&
+ (TCPS_HAVERCVDFIN(tp->t_state) == 0)) {
+ /*
+ * If its a fin we need to process
+ * it to avoid a race where both
+ * sides enter FIN-WAIT and send FIN|ACK
+ * at the same time.
+ */
+ break;
+ }
(void) tcp_output(tp);
sent = tp->snd_max - oldsndmax;
if (sent > tp->t_maxseg) {
More information about the svn-src-stable
mailing list