more correct fix for TCP FIN seq problem: need to predecrement send_nxt
authorMike Karels <karels@ucbvax.Berkeley.EDU>
Mon, 14 Apr 1986 12:43:46 +0000 (04:43 -0800)
committerMike Karels <karels@ucbvax.Berkeley.EDU>
Mon, 14 Apr 1986 12:43:46 +0000 (04:43 -0800)
when resending FIN (for ack, etc.) but not retransmitting

SCCS-vsn: sys/netinet/tcp_output.c 6.18
SCCS-vsn: sys/netinet/tcp_var.h 6.7

usr/src/sys/netinet/tcp_output.c
usr/src/sys/netinet/tcp_var.h

index fb5d8aa..3a725fb 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)tcp_output.c        6.17 (Berkeley) %G%
+ *     @(#)tcp_output.c        6.18 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -70,8 +70,6 @@ again:
         * and go to transmit state.
         */
        if (tp->t_force) {
         * and go to transmit state.
         */
        if (tp->t_force) {
-if (win == 0 && off)
-log(7, "persist offset %d\n", off);
                if (win == 0)
                        win = 1;
                else {
                if (win == 0)
                        win = 1;
                else {
@@ -81,16 +79,6 @@ log(7, "persist offset %d\n", off);
        }
 
        len = MIN(so->so_snd.sb_cc, win) - off;
        }
 
        len = MIN(so->so_snd.sb_cc, win) - off;
-       if (len > tp->t_maxseg) {
-               len = tp->t_maxseg;
-               /*
-                * Don't send more than one segment if retransmitting
-                * (or persisting, but then we shouldn't be here).
-                */
-               if (tp->t_rxtshift == 0)
-                       sendalot = 1;
-       }
-
        flags = tcp_outflags[tp->t_state];
        if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
                flags &= ~TH_FIN;
        flags = tcp_outflags[tp->t_state];
        if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
                flags &= ~TH_FIN;
@@ -99,7 +87,7 @@ log(7, "persist offset %d\n", off);
                /*
                 * If FIN has been sent but not acked,
                 * but we haven't been called to retransmit,
                /*
                 * If FIN has been sent but not acked,
                 * but we haven't been called to retransmit,
-                * len will be -1; no need to transmit now.
+                * len will be -1; transmit if acking, otherwise no need.
                 * Otherwise, window shrank after we sent into it.
                 * If window shrank to 0, cancel pending retransmit
                 * and pull snd_nxt back to (closed) window.
                 * Otherwise, window shrank after we sent into it.
                 * If window shrank to 0, cancel pending retransmit
                 * and pull snd_nxt back to (closed) window.
@@ -107,20 +95,44 @@ log(7, "persist offset %d\n", off);
                 * If the window didn't close completely,
                 * just wait for an ACK.
                 */
                 * If the window didn't close completely,
                 * just wait for an ACK.
                 */
-               if (flags & TH_FIN || win != 0)
+               if (flags & TH_FIN) {
+                       if (tp->t_flags & TF_ACKNOW)
+                               len = 0;
+                       else
+                               return (0);
+               } else if (win == 0) {
+                       tp->t_timer[TCPT_REXMT] = 0;
+                       tp->snd_nxt = tp->snd_una;
+                       len = 0;
+               } else
                        return (0);
                        return (0);
-               tp->t_timer[TCPT_REXMT] = 0;
-               tp->snd_nxt = tp->snd_una;
-               len = 0;
+       }
+       if (len > tp->t_maxseg) {
+               len = tp->t_maxseg;
+               /*
+                * Don't send more than one segment if retransmitting
+                * (or persisting, but then we shouldn't be here).
+                */
+               if (tp->t_rxtshift == 0)
+                       sendalot = 1;
        }
        win = sbspace(&so->so_rcv);
 
        }
        win = sbspace(&so->so_rcv);
 
+
+       /*
+        * If our state indicates that FIN should be sent
+        * and we have not yet done so, or we're retransmitting the FIN,
+        * then we need to send.
+        */
+       if (flags & TH_FIN &&
+           ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
+               goto send;
        /*
         * Send if we owe peer an ACK.
         */
        if (tp->t_flags & TF_ACKNOW)
                goto send;
        /*
         * Send if we owe peer an ACK.
         */
        if (tp->t_flags & TF_ACKNOW)
                goto send;
-       if (flags & (TH_SYN|TH_RST|TH_FIN))
+       if (flags & (TH_SYN|TH_RST))
                goto send;
        if (SEQ_GT(tp->snd_up, tp->snd_una))
                goto send;
                goto send;
        if (SEQ_GT(tp->snd_up, tp->snd_una))
                goto send;
@@ -216,7 +228,11 @@ send:
        /*
         * Fill in fields, remembering maximum advertised
         * window for use in delaying messages about window sizes.
        /*
         * Fill in fields, remembering maximum advertised
         * window for use in delaying messages about window sizes.
+        * If resending a FIN, be sure not to use a new sequence number.
         */
         */
+       if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
+           tp->snd_nxt != tp->snd_una)
+               tp->snd_nxt--;
        ti->ti_seq = htonl(tp->snd_nxt);
        ti->ti_ack = htonl(tp->rcv_nxt);
        /*
        ti->ti_seq = htonl(tp->snd_nxt);
        ti->ti_ack = htonl(tp->rcv_nxt);
        /*
@@ -303,8 +319,12 @@ send:
                /*
                 * Advance snd_nxt over sequence space of this segment.
                 */
                /*
                 * Advance snd_nxt over sequence space of this segment.
                 */
-               if (flags & (TH_SYN|TH_FIN))
+               if (flags & TH_SYN)
+                       tp->snd_nxt++;
+               if (flags & TH_FIN) {
                        tp->snd_nxt++;
                        tp->snd_nxt++;
+                       tp->t_flags |= TF_SENTFIN;
+               }
                tp->snd_nxt += len;
                if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
                        tp->snd_max = tp->snd_nxt;
                tp->snd_nxt += len;
                if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
                        tp->snd_max = tp->snd_nxt;
index df54206..3721df8 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)tcp_var.h   6.6 (Berkeley) %G%
+ *     @(#)tcp_var.h   6.7 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -20,13 +20,14 @@ struct tcpcb {
        short   t_timer[TCPT_NTIMERS];  /* tcp timers */
        short   t_rxtshift;             /* log(2) of rexmt exp. backoff */
        struct  mbuf *t_tcpopt;         /* tcp options */
        short   t_timer[TCPT_NTIMERS];  /* tcp timers */
        short   t_rxtshift;             /* log(2) of rexmt exp. backoff */
        struct  mbuf *t_tcpopt;         /* tcp options */
-       short   t_maxseg;               /* maximum segment size */
+       u_short t_maxseg;               /* maximum segment size */
        char    t_force;                /* 1 if forcing out a byte */
        u_char  t_flags;
 #define        TF_ACKNOW       0x01            /* ack peer immediately */
 #define        TF_DELACK       0x02            /* ack, but try to delay it */
 #define        TF_NODELAY      0x04            /* don't delay packets to coalesce */
 #define        TF_NOOPT        0x08            /* don't use tcp options */
        char    t_force;                /* 1 if forcing out a byte */
        u_char  t_flags;
 #define        TF_ACKNOW       0x01            /* ack peer immediately */
 #define        TF_DELACK       0x02            /* ack, but try to delay it */
 #define        TF_NODELAY      0x04            /* don't delay packets to coalesce */
 #define        TF_NOOPT        0x08            /* don't use tcp options */
+#define        TF_SENTFIN      0x10            /* have sent FIN */
        struct  tcpiphdr *t_template;   /* skeletal packet for transmit */
        struct  inpcb *t_inpcb;         /* back pointer to internet pcb */
 /*
        struct  tcpiphdr *t_template;   /* skeletal packet for transmit */
        struct  inpcb *t_inpcb;         /* back pointer to internet pcb */
 /*