diff options
-rw-r--r-- | sys/netinet/tcp_input.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 1840b08..015b1ff 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -2414,6 +2414,16 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, } } 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 tcphdr *th, struct socket *so, } 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 tcphdr *th, struct socket *so, (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) { |