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 @@ -40,6 +40,9 @@ #include #include +#define TH_ACE_SHIFT 6 +#define MAX_ACE_DELTA 3 + 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, int); @@ -48,7 +51,6 @@ void tcp_ecn_syncache_socket(struct tcpcb *, struct syncache *); int tcp_ecn_syncache_add(uint16_t, int); uint16_t tcp_ecn_syncache_respond(uint16_t, struct syncache *); -int tcp_ecn_get_ace(uint16_t); #endif /* _KERNEL */ 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 @@ -98,6 +98,12 @@ #include #include + +static inline +int tcp_ecn_get_ace(uint16_t); +static inline +void tcp_ecn_set_ace(uint16_t *, uint32_t); + static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, ecn, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "TCP ECN"); @@ -299,8 +305,14 @@ if (tp->t_flags2 & (TF2_ECN_PERMIT | TF2_ACE_PERMIT)) { if (tp->t_flags2 & TF2_ACE_PERMIT) { - if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) + if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) { tp->t_rcep += 1; + if (tp->t_rcepdelta < UCHAR_MAX) { + tp->t_rcepdelta++; + } + if (tp->t_rcepdelta >= MAX_ACE_DELTA) + tp->t_flags |= TF_ACKNOW; + } if (tp->t_flags2 & TF2_ECN_PERMIT) { delta_cep = (tcp_ecn_get_ace(thflags) + 8 - (tp->t_scep & 7)) & 7; @@ -420,13 +432,8 @@ * Reply with proper ECN notifications. */ if (tp->t_flags2 & TF2_ACE_PERMIT) { - *thflags &= ~(TH_AE|TH_CWR|TH_ECE); - if (tp->t_rcep & 0x01) - *thflags |= TH_ECE; - if (tp->t_rcep & 0x02) - *thflags |= TH_CWR; - if (tp->t_rcep & 0x04) - *thflags |= TH_AE; + tcp_ecn_set_ace(thflags, tp->t_rcep); + tp->t_rcepdelta = 0; if (!(tp->t_flags2 & TF2_ECN_PERMIT)) { /* * here we process the final @@ -601,16 +608,15 @@ return thflags; } -int +static inline int tcp_ecn_get_ace(uint16_t thflags) { - int ace = 0; - - if (thflags & TH_ECE) - ace += 1; - if (thflags & TH_CWR) - ace += 2; - if (thflags & TH_AE) - ace += 4; - return ace; + return ((thflags & (TH_AE|TH_CWR|TH_ECE)) >> TH_ACE_SHIFT); } + +static inline void +tcp_ecn_set_ace(uint16_t *thflags, uint32_t t_rcep) +{ + *thflags &= ~(TH_AE|TH_CWR|TH_ECE); + *thflags |= ((t_rcep & 0x07) << TH_ACE_SHIFT); +} \ No newline at end of file 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 @@ -458,6 +458,7 @@ uint32_t t_dsack_pack; /* dsack packets we have eceived */ uint8_t t_tmr_granularity; /* Granularity of all timers srtt etc */ uint8_t t_rttupdated; /* number of times rtt sampled */ + uint8_t t_rcepdelta; /* Number of received CE marks not sent */ /* TCP Fast Open */ uint8_t t_tfo_client_cookie_len; /* TFO client cookie length */ uint32_t t_end_info_status; /* Status flag of end info */