Index: sys/netinet/tcp_syncache.c =================================================================== --- sys/netinet/tcp_syncache.c +++ sys/netinet/tcp_syncache.c @@ -1181,6 +1181,7 @@ struct ucred *cred; #ifdef TCP_RFC7413 uint64_t tfo_response_cookie; + int *tfo_pending_count; int tfo_cookie_valid = 0; int tfo_response_cookie_valid = 0; #endif @@ -1209,6 +1210,7 @@ ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE)); #ifdef TCP_RFC7413 + tfo_pending_count = NULL; if (V_tcp_fastopen_enabled && (tp->t_flags & TF_FASTOPEN) && (tp->t_tfo_pending != NULL) && (to->to_flags & TOF_FASTOPEN)) { /* @@ -1217,7 +1219,8 @@ * SYN floods from starving the service by filling the * listen queue with bogus TFO connections. */ - if (atomic_fetchadd_int(tp->t_tfo_pending, 1) <= + tfo_pending_count = tp->t_tfo_pending; + if (atomic_fetchadd_int(tfo_pending_count, 1) <= (so->so_qlimit / 2)) { int result; @@ -1226,8 +1229,7 @@ &tfo_response_cookie); tfo_cookie_valid = (result > 0); tfo_response_cookie_valid = (result >= 0); - } else - atomic_subtract_int(tp->t_tfo_pending, 1); + } } #endif @@ -1470,6 +1472,13 @@ syncache_tfo_expand(sc, lsop, m, tfo_response_cookie); /* INP_WUNLOCK(inp) will be performed by the called */ rv = 1; + /* + * If syncache_tfo_expand() runs, either it or the TCP + * input path will decrement the count of pending TFO + * sessions. Therefore, set tfo_pending_count to NULL + * so this function doesn't also decrement the count. + */ + tfo_pending_count = NULL; goto tfo_done; } #endif @@ -1497,6 +1506,12 @@ } #ifdef TCP_RFC7413 tfo_done: + /* + * If the function incremented the pending counter, but the TFO + * session is no longer pending, decrement the counter. + */ + if (tfo_pending_count != NULL) + tcp_fastopen_decrement_counter(tfo_pending_count); #endif if (cred != NULL) crfree(cred);