aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2026-02-25 12:59:04 +0000
committerRandall Stewart <rrs@FreeBSD.org>2026-02-25 13:03:33 +0000
commit4e28874a6048f3c5a72a42b5bcfcfc7e71cad8a6 (patch)
tree64142b5a8925eb57019e7138e60e5fa56fcbf188
parent454212b9718b55b43781f81bef252658e20e0fd3 (diff)
When TCP ECN decides it wants to assure an ACK is sent it needs to do it correctly and with some limits.
So in testing I have found two interesting cases where ECN is going to make it so that an ack will be sent right away. These cases need to be limited to being in the ESTABLISHED state. You don't want ECN sending ACK's when we are transitioning in front or end states. Also we don't start a delayed ack timer <and> at the same time set the ACKNOW flag, thats just plain wrong. Reviewed by: tuexen, rscheff Differential Revision:<https://reviews.freebsd.org/D55460>
-rw-r--r--sys/netinet/tcp_ecn.c5
-rw-r--r--sys/netinet/tcp_input.c7
-rw-r--r--sys/netinet/tcp_stacks/rack.c5
3 files changed, 13 insertions, 4 deletions
diff --git a/sys/netinet/tcp_ecn.c b/sys/netinet/tcp_ecn.c
index 31b9418c5fc2..fb650831289e 100644
--- a/sys/netinet/tcp_ecn.c
+++ b/sys/netinet/tcp_ecn.c
@@ -353,7 +353,10 @@ tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int tlen, int pkts, in
}
if (thflags & TH_CWR) {
tp->t_flags2 &= ~TF2_ECN_SND_ECE;
- tp->t_flags |= TF_ACKNOW;
+ if ((tp->t_state == TCPS_ESTABLISHED) ||
+ (tp->t_state == TCPS_FIN_WAIT_1) ||
+ (tp->t_state == TCPS_FIN_WAIT_2))
+ tp->t_flags |= TF_ACKNOW;
}
if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE)
tp->t_flags2 |= TF2_ECN_SND_ECE;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index c015995ffc7a..35a9d7633fa7 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -539,9 +539,12 @@ cc_ecnpkt_handler_flags(struct tcpcb *tp, uint16_t flags, uint8_t iptos)
CC_ALGO(tp)->ecnpkt_handler(&tp->t_ccv);
- if (tp->t_ccv.flags & CCF_ACKNOW) {
- tcp_timer_activate(tp, TT_DELACK, tcp_delacktime);
+ if (((tp->t_state == TCPS_ESTABLISHED) ||
+ (tp->t_state == TCPS_FIN_WAIT_1) ||
+ (tp->t_state == TCPS_FIN_WAIT_2)) &&
+ (tp->t_ccv.flags & CCF_ACKNOW)) {
tp->t_flags |= TF_ACKNOW;
+ tp->t_ccv.flags &= ~CCF_ACKNOW;
}
}
}
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 42c6757b4b2a..78b0026a8c5d 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -15709,6 +15709,8 @@ rack_do_compressed_ack_processing(struct tcpcb *tp, struct socket *so, struct mb
tcp_packets_this_ack(tp, ae->ack),
ae->codepoint))
rack_cong_signal(tp, CC_ECN, ae->ack, __LINE__);
+ if (tp->t_flags & TF_ACKNOW)
+ rack->r_wanted_output = 1;
#ifdef TCP_ACCOUNTING
/* Count for the specific type of ack in */
if (tp->t_flags2 & TF2_TCP_ACCOUNTING) {
@@ -16566,7 +16568,8 @@ rack_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
tcp_packets_this_ack(tp, th->th_ack),
iptos))
rack_cong_signal(tp, CC_ECN, th->th_ack, __LINE__);
-
+ if (tp->t_flags & TF_ACKNOW)
+ rack->r_wanted_output = 1;
/*
* If echoed timestamp is later than the current time, fall back to
* non RFC1323 RTT calculation. Normalize timestamp if syncookies