Index: sys/netinet/tcp_output.c =================================================================== --- sys/netinet/tcp_output.c +++ sys/netinet/tcp_output.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -200,6 +201,7 @@ { struct socket *so = tp->t_inpcb->inp_socket; int32_t len; + tcp_seq top; uint32_t recwin, sendwin; uint16_t flags; int off, error = 0; /* Keep compiler happy */ @@ -1569,6 +1571,14 @@ tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; + top = tp->snd_una + sbused(&so->so_snd); + KASSERT(SEQ_LEQ(tp->snd_max, top + 1), + ("%s: snd_max beyond so_snd", __func__)); + if (SEQ_GT(tp->snd_max, top + 1)) { + log(LOG_CRIT, "%s#%d: snd_max %u > so_snd+1 %u adjusting.\n", + __func__, __LINE__, tp->snd_max, top + 1); + tp->snd_max = top + 1; + } /* * Time this transmission if not a retransmission and * not currently timing anything. @@ -1644,8 +1654,17 @@ ++xlen; tp->t_flags |= TF_SENTFIN; } - if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max)) + if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max)) { tp->snd_max = tp->snd_nxt + xlen; + top = tp->snd_una + sbused(&so->so_snd); + KASSERT(SEQ_LEQ(tp->snd_max, top + 1), + ("%s: snd_max beyond so_snd", __func__)); + if (SEQ_GT(tp->snd_max, top + 1)) { + log(LOG_CRIT, "%s#%d: snd_max %u > so_snd+1 %u adjusting.\n", + __func__, __LINE__, tp->snd_max, top + 1); + tp->snd_max = top + 1; + } + } } if ((error == 0) && (TCPS_HAVEESTABLISHED(tp->t_state) && @@ -1681,8 +1700,11 @@ tp->sackhint.sack_bytes_rexmit -= len; KASSERT(tp->sackhint.sack_bytes_rexmit >= 0, ("sackhint bytes rtx >= 0")); - } else + } else { tp->snd_nxt -= len; + if (flags & TH_FIN) + tp->snd_nxt--; + } } SOCKBUF_UNLOCK_ASSERT(&so->so_snd); /* Check gotos. */ switch (error) { Index: sys/netinet/tcp_sack.c =================================================================== --- sys/netinet/tcp_sack.c +++ sys/netinet/tcp_sack.c @@ -853,7 +853,9 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) { int num_segs = 1; + tcp_seq top; u_int maxseg = tcp_maxseg(tp); + struct socket *so = tp->t_inpcb->inp_socket; INP_WLOCK_ASSERT(tp->t_inpcb); tcp_timer_activate(tp, TT_REXMT, 0); @@ -898,8 +900,19 @@ highdata--; if (th->th_ack != highdata) { tp->snd_fack = th->th_ack; - (void)tcp_sackhole_insert(tp, SEQ_MAX(th->th_ack, - highdata - maxseg), highdata, NULL); + top = tp->snd_una + sbused(&so->so_snd); + KASSERT(SEQ_LEQ(highdata, top), + ("%s: rescue.end > so_snd, NEEDFIN:%d SENTFIN:%d\n", + __func__, (tp->t_flags & TF_NEEDFIN) != 0, + (tp->t_flags & TF_SENTFIN) != 0)); + if (SEQ_GT(highdata, top)) { + log(LOG_CRIT,"%s#%d: rescue (%u-%u) > so_snd %u skipping.\n", + __func__, __LINE__, + SEQ_MAX(th->th_ack, highdata - maxseg), + highdata, top); + } else + (void)tcp_sackhole_insert(tp, SEQ_MAX(th->th_ack, + highdata - maxseg), highdata, NULL); } } (void) tcp_output(tp); @@ -952,6 +965,8 @@ tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt) { struct sackhole *hole = NULL; + struct socket *so = tp->t_inpcb->inp_socket; + tcp_seq top = tp->snd_una + sbused(&so->so_snd); INP_WLOCK_ASSERT(tp->t_inpcb); *sack_bytes_rexmt = tp->sackhint.sack_bytes_rexmit; @@ -970,18 +985,16 @@ } } KASSERT(SEQ_LT(hole->start, hole->end), ("%s: hole.start >= hole.end", __func__)); - if (!(V_tcp_do_newsack)) { - KASSERT(SEQ_LT(hole->start, tp->snd_fack), ("%s: hole.start >= snd.fack", __func__)); - KASSERT(SEQ_LT(hole->end, tp->snd_fack), ("%s: hole.end >= snd.fack", __func__)); - KASSERT(SEQ_LT(hole->rxmit, tp->snd_fack), ("%s: hole.rxmit >= snd.fack", __func__)); - if (SEQ_GEQ(hole->start, hole->end) || - SEQ_GEQ(hole->start, tp->snd_fack) || - SEQ_GEQ(hole->end, tp->snd_fack) || - SEQ_GEQ(hole->rxmit, tp->snd_fack)) { - log(LOG_CRIT,"tcp: invalid SACK hole (%u-%u,%u) vs fwd ack %u, ignoring.\n", - hole->start, hole->end, hole->rxmit, tp->snd_fack); - return (NULL); - } + KASSERT(SEQ_LEQ(hole->start, top), ("%s: hole.start >= so_snd", __func__)); + KASSERT(SEQ_LEQ(hole->end, top), ("%s: hole.end >= so_snd", __func__)); + KASSERT(SEQ_LEQ(hole->rxmit, top), ("%s: hole.rxmit >= so_snd", __func__)); + if (SEQ_GEQ(hole->start, hole->end) || + SEQ_GT(hole->start, top) || + SEQ_GT(hole->end, top) || + SEQ_GT(hole->rxmit, top)) { + log(LOG_CRIT, "%s#%d: invalid SACK hole (%u-%u,%u) vs so_snd %u ignoring.\n", + __func__, __LINE__, hole->start, hole->end, hole->rxmit, top); + return (NULL); } return (hole); }