Index: sys/netinet/tcp_congctl.c =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_congctl.c,v retrieving revision 1.29 diff -p -u -r1.29 tcp_congctl.c --- sys/netinet/tcp_congctl.c 14 May 2024 19:00:44 -0000 1.29 +++ sys/netinet/tcp_congctl.c 16 Feb 2025 16:44:39 -0000 @@ -603,7 +603,7 @@ tcp_reno_newack(struct tcpcb *tp, const int acked = th->th_ack - tp->snd_una; - if (cw >= tp->snd_ssthresh) { + if (cw > tp->snd_ssthresh) { tp->t_bytes_acked += acked; if (tp->t_bytes_acked >= cw) { /* Time to increase the window. */ @@ -624,6 +624,7 @@ tcp_reno_newack(struct tcpcb *tp, const abc_lim = (tcp_abc_aggressive == 0 || tp->snd_nxt != tp->snd_max) ? incr : incr * 2; incr = uimin(acked, abc_lim); + tp->t_bytes_acked = 0; } } else { @@ -632,14 +633,17 @@ tcp_reno_newack(struct tcpcb *tp, const * in flight, open exponentially (segsz per packet). * Otherwise open linearly: segsz per window * (segsz^2 / cwnd per packet). - */ - - if (cw >= tp->snd_ssthresh) { - incr = incr * incr / cw; + * If cwnd > maxseg^2, fix the cwnd increment at 1 byte + * to avoid capping cwnd. + */ + + if (cw > tp->snd_ssthresh) { + incr = uimax(incr * incr / cw, 1); } } - tp->snd_cwnd = uimin(cw + incr, TCP_MAXWIN << tp->snd_scale); + if (incr > 0) + tp->snd_cwnd = uimin(cw + incr, TCP_MAXWIN << tp->snd_scale); } const struct tcp_congctl tcp_reno_ctl = { @@ -726,6 +730,8 @@ tcp_newreno_fast_retransmit_newack(struc tp->snd_cwnd = sack_bytes_rxmt + (tp->snd_nxt - tp->sack_newdata) + sack_num_segs * tp->t_segsz; + // if (tp->snd_cwnd > tp->snd_ssthresh) + // tp->snd_cwnd = tp->snd_ssthresh; tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); } else { @@ -735,6 +741,7 @@ tcp_newreno_fast_retransmit_newack(struc * snd_una is not yet updated when we're called */ tp->snd_cwnd = tp->t_segsz + (th->th_ack - tp->snd_una); + tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); tp->snd_cwnd = ocwnd; if (SEQ_GT(onxt, tp->snd_nxt)) @@ -755,17 +762,23 @@ tcp_newreno_fast_retransmit_newack(struc * snd_ssthresh outstanding data. But in case we * would be inclined to send a burst, better to do * it via the slow start mechanism. + * + * RFC 6582 3.2 + * cwnd = min(sshtresh, max(flightsize, smss) + smss) */ - if (SEQ_SUB(tp->snd_max, th->th_ack) < tp->snd_ssthresh) - tp->snd_cwnd = SEQ_SUB(tp->snd_max, th->th_ack) - + tp->t_segsz; - else - tp->snd_cwnd = tp->snd_ssthresh; + + long flight; + flight = uimax(SEQ_SUB(tp->snd_max, th->th_ack), tp->t_segsz); + tp->snd_cwnd = uimin(flight + tp->t_segsz, tp->snd_ssthresh); + tp->t_partialacks = -1; tp->t_dupacks = 0; tp->t_bytes_acked = 0; if (TCP_SACK_ENABLED(tp) && SEQ_GT(th->th_ack, tp->snd_fack)) tp->snd_fack = th->th_ack; + + if (SEQ_LEQ(th->th_ack, tp->snd_max)) + tp->t_flags |= TF_ACKNOW; } } @@ -868,12 +881,15 @@ tcp_cubic_getW(struct tcpcb *tp, uint32_ long tK3; /* Section 3.1 Eq. 2 */ - K = tcp_cubic_cbrt(tp->snd_cubic_wmax / CUBIC_BETAB * + K = tcp_cubic_cbrt(tp->snd_cubic_wmax / (CUBIC_BETAB - CUBIC_BETAA) / CUBIC_BETAB * CUBIC_CB / CUBIC_CA); /* (t-K)^3 - not clear why is the measure unit mattering */ tK3 = (long)(ms_elapsed + rtt) - (long)K; - tK3 = tK3 * tK3 * tK3; + if (tK3 <= 0) + return tp->snd_cubic_wmax; + + tK3 = tK3 * tK3 * tK3; return CUBIC_CA * tK3 / CUBIC_CB + tp->snd_cubic_wmax; } @@ -896,7 +912,7 @@ tcp_cubic_congestion_exp(struct tcpcb *t tp->snd_cubic_wmax = tp->snd_cwnd; } - tp->snd_cubic_wmax = uimax(tp->t_segsz, tp->snd_cubic_wmax); + tp->snd_cubic_wmax = ulmax(tp->t_segsz, tp->snd_cubic_wmax); /* Shrink CWND */ tcp_common_congestion_exp(tp, CUBIC_BETAA, CUBIC_BETAB); @@ -939,7 +955,7 @@ tcp_cubic_newack(struct tcpcb *tp, const /* Compute W_tcp(t) */ w_tcp = tp->snd_cubic_wmax * CUBIC_BETAA / CUBIC_BETAB + - ms_elapsed / rtt / 3; + ms_elapsed / rtt / ((CUBIC_BETAB + CUBIC_BETAA)/(3*(CUBIC_BETAB - CUBIC_BETAA))); if (tp->snd_cwnd > w_tcp) { /* Not in TCP friendly mode */ @@ -951,8 +967,8 @@ tcp_cubic_newack(struct tcpcb *tp, const } /* Make sure we are within limits */ - tp->snd_cwnd = uimax(tp->snd_cwnd, tp->t_segsz); - tp->snd_cwnd = uimin(tp->snd_cwnd, TCP_MAXWIN << tp->snd_scale); + tp->snd_cwnd = ulmax(tp->snd_cwnd, tp->t_segsz); + tp->snd_cwnd = ulmin(tp->snd_cwnd, TCP_MAXWIN << tp->snd_scale); } else { /* Use New Reno */ tcp_newreno_newack(tp, th); Index: sys/netinet/tcp_input.c =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v retrieving revision 1.441 diff -p -u -r1.441 tcp_input.c --- sys/netinet/tcp_input.c 8 Oct 2024 06:17:14 -0000 1.441 +++ sys/netinet/tcp_input.c 16 Feb 2025 16:44:39 -0000 @@ -1486,7 +1486,7 @@ findpcb: /* Unscale the window into a 32-bit value. */ if ((tiflags & TH_SYN) == 0) - tiwin = th->th_win << tp->snd_scale; + tiwin = (u_long)th->th_win << tp->snd_scale; else tiwin = th->th_win; @@ -1911,7 +1911,7 @@ after_listen: } else if (th->th_ack == tp->snd_una && TAILQ_FIRST(&tp->segq) == NULL && tlen <= sbspace(&so->so_rcv)) { - int newsize = 0; + u_long newsize = 0; /* * this is a pure, in-sequence data packet @@ -1978,8 +1978,8 @@ after_listen: (so->so_rcv.sb_hiwat / 8 * 7) && so->so_rcv.sb_hiwat < tcp_autorcvbuf_max) { - newsize = - uimin(so->so_rcv.sb_hiwat + + newsize = tcp_growbuf( + so->so_rcv.sb_hiwat, tcp_autorcvbuf_inc, tcp_autorcvbuf_max); } Index: sys/netinet/tcp_output.c =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_output.c,v retrieving revision 1.222 diff -p -u -r1.222 tcp_output.c --- sys/netinet/tcp_output.c 8 Sep 2024 09:36:52 -0000 1.222 +++ sys/netinet/tcp_output.c 16 Feb 2025 16:44:39 -0000 @@ -521,7 +521,9 @@ tcp_output(struct tcpcb *tp) unsigned int sack_numblks; int idle, sendalot, txsegsize, rxsegsize; int txsegsize_nosack; +#if 0 int maxburst = TCP_MAXBURST; +#endif int af; /* address family on the wire */ int iphdrlen; int has_tso4, has_tso6; @@ -596,22 +598,27 @@ tcp_output(struct tcpcb *tp) * larger value for the restart window should never increase * the size of cwnd). */ - if (tcp_cwm) { + if (idle && (tcp_now - tp->t_rcvtime) >= tp->t_rxtcur) { /* - * Hughes/Touch/Heidemann Congestion Window Monitoring. - * Count the number of packets currently pending - * acknowledgement, and limit our congestion window - * to a pre-determined allowed burst size plus that count. - * This prevents bursting once all pending packets have - * been acknowledged (i.e. transmission is idle). - * - * XXX Link this to Initial Window? + * RFC2861 Section 2, limit ssthresh to 3/4 of + * the old cwnd to not exit slow-start prematurely. */ - tp->snd_cwnd = uimin(tp->snd_cwnd, - (tcp_cwm_burstsize * txsegsize) + - (tp->snd_nxt - tp->snd_una)); - } else { - if (idle && (tcp_now - tp->t_rcvtime) >= tp->t_rxtcur) { + tp->snd_ssthresh = ulmax(tp->snd_ssthresh, + tp->snd_cwnd * 3 / 4); + + if (tcp_cwm) { + /* + * Hughes/Touch/Heidemann Congestion Window Monitoring. + * Count the number of packets currently pending + * acknowledgement, and limit our congestion window + * to a pre-determined allowed burst size plus that count. + * This prevents bursting once all pending packets have + * been acknowledged (i.e. transmission is idle). + */ + tp->snd_cwnd = uimin(tp->snd_cwnd, + (tcp_cwm_burstsize * txsegsize) + + (tp->snd_nxt - tp->snd_una)); + } else { /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- @@ -770,7 +777,11 @@ again: } if (sack_rxmit == 0) { +#if 0 if (TCP_SACK_ENABLED(tp) && tp->t_partialacks >= 0) { +#else + if (sack_bytes_rxmt > 0) { +#endif long cwin; /* @@ -796,7 +807,7 @@ again: */ if (len > 0) { cwin = tp->snd_cwnd - - (tp->snd_nxt - tp->sack_newdata) - + imax(0, (tp->snd_nxt - tp->sack_newdata)) - sack_bytes_rxmt; if (cwin < 0) cwin = 0; @@ -879,9 +890,11 @@ again: so->so_snd.sb_cc >= (so->so_snd.sb_hiwat / 8 * 7) && so->so_snd.sb_cc < tcp_autosndbuf_max && win >= (so->so_snd.sb_cc - (tp->snd_nxt - tp->snd_una))) { - if (!sbreserve(&so->so_snd, - uimin(so->so_snd.sb_hiwat + tcp_autosndbuf_inc, - tcp_autosndbuf_max), so)) + u_long newsize = tcp_growbuf( + so->so_snd.sb_hiwat, + tcp_autosndbuf_inc, + tcp_autosndbuf_max); + if (!sbreserve(&so->so_snd, newsize, so)) so->so_snd.sb_flags &= ~SB_AUTOSIZE; } } @@ -1648,12 +1661,17 @@ out: tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~TF_ACKNOW; TCP_CLEAR_DELACK(tp); +#if 0 #ifdef DIAGNOSTIC if (maxburst < 0) printf("tcp_output: maxburst exceeded by %d\n", -maxburst); #endif if (sendalot && (tp->t_congctl == &tcp_reno_ctl || --maxburst)) goto again; +#else + if (sendalot) + goto again; +#endif return 0; } Index: sys/netinet/tcp_subr.c =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v retrieving revision 1.297 diff -p -u -r1.297 tcp_subr.c --- sys/netinet/tcp_subr.c 5 Jul 2024 04:31:54 -0000 1.297 +++ sys/netinet/tcp_subr.c 16 Feb 2025 16:44:39 -0000 @@ -862,6 +862,7 @@ tcp_respond(struct tcpcb *tp, struct mbu break; #endif default: + m_freem(m); error = EAFNOSUPPORT; break; } Index: sys/netinet/tcp_var.h =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_var.h,v retrieving revision 1.199 diff -p -u -r1.199 tcp_var.h --- sys/netinet/tcp_var.h 3 Dec 2024 20:02:30 -0000 1.199 +++ sys/netinet/tcp_var.h 16 Feb 2025 16:44:39 -0000 @@ -785,6 +785,21 @@ extern int tcp_do_autosndbuf; extern int tcp_autosndbuf_inc; extern int tcp_autosndbuf_max; +static __inline u_long +tcp_growbuf(u_long current, int increment, int limit) +{ + if (increment < 0) { + uint64_t adj; + + adj = (uint64_t)current * -increment / 65536; + current += adj; + } else { + current += increment; + } + + return uimin(current, limit); +} + struct secasvar; void tcp_canceltimers(struct tcpcb *);