Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Feb 2013 16:40:16 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r246998 - stable/8/sys/netinet
Message-ID:  <201302191640.r1JGeGNR076643@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Tue Feb 19 16:40:16 2013
New Revision: 246998
URL: http://svnweb.freebsd.org/changeset/base/246998

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:	rrs
  Approved by:	emaste (co-mentor)

Modified:
  stable/8/sys/netinet/tcp_input.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/netinet/   (props changed)

Modified: stable/8/sys/netinet/tcp_input.c
==============================================================================
--- stable/8/sys/netinet/tcp_input.c	Tue Feb 19 16:39:53 2013	(r246997)
+++ stable/8/sys/netinet/tcp_input.c	Tue Feb 19 16:40:16 2013	(r246998)
@@ -2372,6 +2372,16 @@ tcp_do_segment(struct mbuf *m, struct tc
 						}
 					} 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) {
@@ -2411,6 +2421,16 @@ tcp_do_segment(struct mbuf *m, struct tc
 					}
 					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,
 					    ("%s: tp->snd_limited too big",
@@ -2437,6 +2457,16 @@ tcp_do_segment(struct mbuf *m, struct tc
 					    (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) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302191640.r1JGeGNR076643>