kernel - Fix improper persist state in tcp
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 9 Jul 2011 06:45:22 +0000 (23:45 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 9 Jul 2011 06:45:22 +0000 (23:45 -0700)
* When TCP is doing a simultanious connect and sitting in the
  TCPS_SYN_RECEIVED state a degenerate 0 window (due to +SYN -ACK packets)
  case occurs where the code improperly tries to switch over from the
  retry timer to the persist timer, which panics.

  The invalid persist state was caught by code placed earlier in the
  year.

* Adjust the code to document the case and stay with the retry timer.

sys/netinet/tcp_output.c

index c1bf20a..715976b 100644 (file)
@@ -278,6 +278,10 @@ again:
         * acks after fast-retransmit because TCP will reset snd_nxt
         * to snd_max after the fast-retransmit.
         *
         * acks after fast-retransmit because TCP will reset snd_nxt
         * to snd_max after the fast-retransmit.
         *
+        * A negative length can also occur when we are in the
+        * TCPS_SYN_RECEIVED state due to a simultanious connect where
+        * our SYN has not been acked yet.
+        *
         * In the normal retransmit-FIN-only case, however, snd_nxt will
         * be set to snd_una, the offset will be 0, and the length may
         * wind up 0.
         * In the normal retransmit-FIN-only case, however, snd_nxt will
         * be set to snd_una, the offset will be 0, and the length may
         * wind up 0.
@@ -309,17 +313,25 @@ again:
 
        if (len < 0) {
                /*
 
        if (len < 0) {
                /*
-                * If FIN has been sent but not acked,
-                * but we haven't been called to retransmit,
-                * len will be < 0.  Otherwise, window shrank
-                * after we sent into it.  If window shrank to 0,
-                * cancel pending retransmit, pull snd_nxt back
-                * to (closed) window, and set the persist timer
-                * if it isn't already going.  If the window didn't
-                * close completely, just wait for an ACK.
+                * A negative len can occur if our FIN has been sent but not
+                * acked, or if we are in a simultanious connect in the
+                * TCPS_SYN_RECEIVED state with our SYN sent but not yet
+                * acked.
+                *
+                * If our window has contracted to 0 in the FIN case
+                * (which can only occur if we have NOT been called to
+                * retransmit as per code a few paragraphs up) then we
+                * want to shift the retransmit timer over to the
+                * persist timer.
+                *
+                * However, if we are in the TCPS_SYN_RECEIVED state
+                * (the SYN case) we will be in a simultanious connect and
+                * the window may be zero degeneratively.  In this case we
+                * do not want to shift to the persist timer after the SYN
+                * or the SYN+ACK transmission.
                 */
                len = 0;
                 */
                len = 0;
-               if (sendwin == 0) {
+               if (sendwin == 0 && tp->t_state != TCPS_SYN_RECEIVED) {
                        tcp_callout_stop(tp, tp->tt_rexmt);
                        tp->t_rxtshift = 0;
                        tp->snd_nxt = tp->snd_una;
                        tcp_callout_stop(tp, tp->tt_rexmt);
                        tp->t_rxtshift = 0;
                        tp->snd_nxt = tp->snd_una;