diff --git a/sys/netinet/tcp_ecn.h b/sys/netinet/tcp_ecn.h --- a/sys/netinet/tcp_ecn.h +++ b/sys/netinet/tcp_ecn.h @@ -43,7 +43,7 @@ void tcp_ecn_input_syn_sent(struct tcpcb *, uint16_t, int); void tcp_ecn_input_parallel_syn(struct tcpcb *, uint16_t, int); -int tcp_ecn_input_segment(struct tcpcb *, uint16_t, int); +int tcp_ecn_input_segment(struct tcpcb *, uint16_t, int, int, int); uint16_t tcp_ecn_output_syn_sent(struct tcpcb *); int tcp_ecn_output_established(struct tcpcb *, uint16_t *, int, bool); void tcp_ecn_syncache_socket(struct tcpcb *, struct syncache *); diff --git a/sys/netinet/tcp_ecn.c b/sys/netinet/tcp_ecn.c --- a/sys/netinet/tcp_ecn.c +++ b/sys/netinet/tcp_ecn.c @@ -271,9 +271,9 @@ * TCP ECN processing. */ int -tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int iptos) +tcp_ecn_input_segment(struct tcpcb *tp, uint16_t thflags, int tlen, int pkts, int iptos) { - int delta_ace = 0; + int delta_cep = 0; if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT)) { switch (iptos & IPTOS_ECN_MASK) { @@ -292,9 +292,12 @@ if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) tp->t_rcep += 1; if (tp->t_flags2 & TF2_ECN_PERMIT) { - delta_ace = (tcp_ecn_get_ace(thflags) + 8 - - (tp->t_scep & 0x07)) & 0x07; - tp->t_scep += delta_ace; + delta_cep = (tcp_ecn_get_ace(thflags) + 8 - + (tp->t_scep & 7)) & 7; + if (delta_cep < pkts) + delta_cep = pkts - + ((pkts - delta_cep) & 7); + tp->t_scep += delta_cep; } else { /* * process the final ACK of the 3WHS @@ -326,7 +329,7 @@ } else { /* RFC3168 ECN handling */ if ((thflags & (TH_SYN | TH_ECE)) == TH_ECE) { - delta_ace = 1; + delta_cep = 1; tp->t_scep++; } if (thflags & TH_CWR) { @@ -341,7 +344,7 @@ cc_ecnpkt_handler_flags(tp, thflags, iptos); } - return delta_ace; + return delta_cep; } /* diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1627,7 +1627,9 @@ /* * TCP ECN processing. */ - if (tcp_ecn_input_segment(tp, thflags, iptos)) + if (tcp_ecn_input_segment(tp, thflags, tlen, + tcp_packets_this_ack(tp, th->th_ack), + iptos)) cc_cong_signal(tp, th, CC_ECN); /* diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c --- a/sys/netinet/tcp_stacks/rack.c +++ b/sys/netinet/tcp_stacks/rack.c @@ -13528,8 +13528,10 @@ rack_cc_after_idle(rack, tp); } tp->t_rcvtime = ticks; - /* Now what about ECN? */ - if (tcp_ecn_input_segment(tp, ae->flags, ae->codepoint)) + /* Now what about ECN of a chain of pure ACKs? */ + if (tcp_ecn_input_segment(tp, ae->flags, 0, + tcp_packets_this_ack(tp, ae->ack), + ae->codepoint)) rack_cong_signal(tp, CC_ECN, ae->ack, __LINE__); #ifdef TCP_ACCOUNTING /* Count for the specific type of ack in */ @@ -14320,7 +14322,9 @@ * TCP ECN processing. XXXJTL: If we ever use ECN, we need to move * this to occur after we've validated the segment. */ - if (tcp_ecn_input_segment(tp, thflags, iptos)) + if (tcp_ecn_input_segment(tp, thflags, tlen, + tcp_packets_this_ack(tp, th->th_ack), + iptos)) rack_cong_signal(tp, CC_ECN, th->th_ack, __LINE__); /* diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -551,6 +551,12 @@ #endif #define BYTES_THIS_ACK(tp, th) (th->th_ack - tp->snd_una) +static int inline +tcp_packets_this_ack(struct tcpcb *tp, tcp_seq ack) +{ + return ((ack - tp->snd_una) / tp->t_maxseg + + ((((ack - tp->snd_una) % tp->t_maxseg) != 0) ? 1 : 0)); +} /* * Flags for the t_oobflags field.