diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 71c34117f4e1..6abf8db2b9e8 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1831,6 +1831,9 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, win = sbspace(&so->so_rcv); if (win < 0) win = 0; + KASSERT(SEQ_GEQ(tp->rcv_adv, tp->rcv_nxt), + ("tcp_input negative window: tp %p rcv_nxt %u rcv_adv %u", tp, + tp->rcv_adv, tp->rcv_nxt)); tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt)); /* Reset receive buffer auto scaling when not in bulk receive mode. */ @@ -2868,7 +2871,10 @@ dodata: /* XXX */ * buffer size. * XXX: Unused. */ - len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); + if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) + len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); + else + len = so->so_rcv.sb_hiwat; #endif } else { m_freem(m); diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 3ccb61a22332..4b5fa101d1f0 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -561,15 +561,21 @@ after_sack_rexmit: * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ - long adv = min(recwin, (long)TCP_MAXWIN << tp->rcv_scale) - - (tp->rcv_adv - tp->rcv_nxt); + long adv; + int oldwin; + + adv = min(recwin, (long)TCP_MAXWIN << tp->rcv_scale); + if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) { + oldwin = (tp->rcv_adv - tp->rcv_nxt); + adv -= oldwin; + } else + oldwin = 0; /* * If the new window size ends up being the same as the old * size when it is scaled, then don't force a window update. */ - if ((tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale == - (adv + tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale) + if (oldwin >> tp->rcv_scale == (adv + oldwin) >> tp->rcv_scale) goto dontupdate; if (adv >= (long) (2 * tp->t_maxseg)) goto send; @@ -1008,7 +1014,8 @@ send: if (recwin < (long)(so->so_rcv.sb_hiwat / 4) && recwin < (long)tp->t_maxseg) recwin = 0; - if (recwin < (long)(tp->rcv_adv - tp->rcv_nxt)) + if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt) && + recwin < (long)(tp->rcv_adv - tp->rcv_nxt)) recwin = (long)(tp->rcv_adv - tp->rcv_nxt); if (recwin > (long)TCP_MAXWIN << tp->rcv_scale) recwin = (long)TCP_MAXWIN << tp->rcv_scale; diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index d283eb166da8..4427e1c005cf 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -242,6 +242,9 @@ tcp_twstart(struct tcpcb *tp) /* * Recover last window size sent. */ + KASSERT(SEQ_GEQ(tp->rcv_adv, tp->rcv_nxt), + ("tcp_twstart negative window: tp %p rcv_nxt %u rcv_adv %u", tp, + tp->rcv_adv, tp->rcv_nxt)); tw->last_win = (tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale; /*