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) {
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"