Date: Sat, 25 Aug 2012 09:26:37 +0000 (UTC) From: Randall Stewart <rrs@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r239672 - head/sys/netinet Message-ID: <201208250926.q7P9QbcQ014751@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rrs Date: Sat Aug 25 09:26:37 2012 New Revision: 239672 URL: http://svn.freebsd.org/changeset/base/239672 Log: 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 ;-) MFC after: 1 month Modified: head/sys/netinet/tcp_input.c Modified: head/sys/netinet/tcp_input.c ============================================================================== --- head/sys/netinet/tcp_input.c Sat Aug 25 08:31:21 2012 (r239671) +++ head/sys/netinet/tcp_input.c Sat Aug 25 09:26:37 2012 (r239672) @@ -2414,6 +2414,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) { @@ -2453,6 +2463,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", @@ -2479,6 +2499,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?201208250926.q7P9QbcQ014751>