Author: tuexen
Date: Mon Jul 30 20:35:50 2018
New Revision: 336934
URL: https://svnweb.freebsd.org/changeset/base/336934

Log:
  Fix some TCP fast open issues.
  
  The following issues are fixed:
  * Whenever a TCP server with TCP fast open enabled, calls accept(),
    recv(), send(), and close() before the TCP-ACK segment has been received,
    the TCP connection is just dropped and the reception of the TCP-ACK
    segment triggers the sending of a TCP-RST segment.
  * Whenever a TCP server with TCP fast open enabled, calls accept(), recv(),
    send(), send(), and close() before the TCP-ACK segment has been received,
    the first byte provided in the second send call is not transferred.
  * Whenever a TCP client with TCP fast open enabled calls sendto() followed
    by close() the TCP connection is just dropped.
  
  Reviewed by:          jtl@, kbowling@, rrs@
  Sponsored by:         Netflix, Inc.
  Differential Revision:        https://reviews.freebsd.org/D16485

Modified:
  head/sys/netinet/tcp_input.c
  head/sys/netinet/tcp_output.c
  head/sys/netinet/tcp_usrreq.c

Modified: head/sys/netinet/tcp_input.c
==============================================================================
--- head/sys/netinet/tcp_input.c        Mon Jul 30 20:25:32 2018        
(r336933)
+++ head/sys/netinet/tcp_input.c        Mon Jul 30 20:35:50 2018        
(r336934)
@@ -2407,6 +2407,16 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, stru
                 *      SYN-RECEIVED* -> FIN-WAIT-1
                 */
                tp->t_starttime = ticks;
+               if (IS_FASTOPEN(tp->t_flags) && tp->t_tfo_pending) {
+                       tcp_fastopen_decrement_counter(tp->t_tfo_pending);
+                       tp->t_tfo_pending = NULL;
+
+                       /*
+                        * Account for the ACK of our SYN prior to
+                        * regular ACK processing below.
+                        */ 
+                       tp->snd_una++;
+               }
                if (tp->t_flags & TF_NEEDFIN) {
                        tcp_state_change(tp, TCPS_FIN_WAIT_1);
                        tp->t_flags &= ~TF_NEEDFIN;
@@ -2414,16 +2424,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, stru
                        tcp_state_change(tp, TCPS_ESTABLISHED);
                        TCP_PROBE5(accept__established, NULL, tp,
                            m, tp, th);
-                       if (IS_FASTOPEN(tp->t_flags) && tp->t_tfo_pending) {
-                               
tcp_fastopen_decrement_counter(tp->t_tfo_pending);
-                               tp->t_tfo_pending = NULL;
-
-                               /*
-                                * Account for the ACK of our SYN prior to
-                                * regular ACK processing below.
-                                */ 
-                               tp->snd_una++;
-                       }
                        /*
                         * TFO connections call cc_conn_init() during SYN
                         * processing.  Calling it again here for such

Modified: head/sys/netinet/tcp_output.c
==============================================================================
--- head/sys/netinet/tcp_output.c       Mon Jul 30 20:25:32 2018        
(r336933)
+++ head/sys/netinet/tcp_output.c       Mon Jul 30 20:35:50 2018        
(r336934)
@@ -228,13 +228,15 @@ tcp_output(struct tcpcb *tp)
 #endif
 
        /*
-        * For TFO connections in SYN_RECEIVED, only allow the initial
-        * SYN|ACK and those sent by the retransmit timer.
+        * For TFO connections in SYN_SENT or SYN_RECEIVED,
+        * only allow the initial SYN or SYN|ACK and those sent
+        * by the retransmit timer.
         */
        if (IS_FASTOPEN(tp->t_flags) &&
-           (tp->t_state == TCPS_SYN_RECEIVED) &&
-           SEQ_GT(tp->snd_max, tp->snd_una) &&    /* initial SYN|ACK sent */
-           (tp->snd_nxt != tp->snd_una))         /* not a retransmit */
+           ((tp->t_state == TCPS_SYN_SENT) ||
+            (tp->t_state == TCPS_SYN_RECEIVED)) &&
+           SEQ_GT(tp->snd_max, tp->snd_una) && /* initial SYN or SYN|ACK sent 
*/
+           (tp->snd_nxt != tp->snd_una))       /* not a retransmit */
                return (0);
 
        /*

Modified: head/sys/netinet/tcp_usrreq.c
==============================================================================
--- head/sys/netinet/tcp_usrreq.c       Mon Jul 30 20:25:32 2018        
(r336933)
+++ head/sys/netinet/tcp_usrreq.c       Mon Jul 30 20:35:50 2018        
(r336934)
@@ -2113,7 +2113,8 @@ tcp_disconnect(struct tcpcb *tp)
         * Neither tcp_close() nor tcp_drop() should return NULL, as the
         * socket is still open.
         */
-       if (tp->t_state < TCPS_ESTABLISHED) {
+       if (tp->t_state < TCPS_ESTABLISHED &&
+           !(tp->t_state > TCPS_LISTEN && IS_FASTOPEN(tp->t_flags))) {
                tp = tcp_close(tp);
                KASSERT(tp != NULL,
                    ("tcp_disconnect: tcp_close() returned NULL"));
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to