expand parameters to functions; READDIR drops eofflag;
[unix-history] / usr / src / sys / netiso / tp.trans
index 4eb4c22..a5a2a83 100644 (file)
@@ -1,3 +1,13 @@
+/* NEW */
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)tp.trans    7.19 (Berkeley) %G%
+ */
+
 /***********************************************************
                Copyright IBM Corporation 1987
 
 /***********************************************************
                Copyright IBM Corporation 1987
 
@@ -48,9 +58,8 @@ SOFTWARE.
 *PROTOCOL tp
 
 *INCLUDE
 *PROTOCOL tp
 
 *INCLUDE
-
 {
 {
-
+/* @(#)tp.trans        7.19 (Berkeley) %G% */
 #include "param.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "param.h"
 #include "socket.h"
 #include "socketvar.h"
@@ -69,6 +78,8 @@ SOFTWARE.
 #include "../netiso/cons.h"
 
 #define DRIVERTRACE TPPTdriver
 #include "../netiso/cons.h"
 
 #define DRIVERTRACE TPPTdriver
+#define sbwakeup(sb)   sowakeup(p->tp_sock, sb);
+#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
 
 static         trick_hc = 1;
 
 
 static         trick_hc = 1;
 
@@ -79,9 +90,11 @@ int  tp_emit(),
 void   tp_indicate(),                          tp_getoptions(),        
                tp_soisdisconnecting(),         tp_soisdisconnected(),
                tp_recycle_tsuffix(),           
 void   tp_indicate(),                          tp_getoptions(),        
                tp_soisdisconnecting(),         tp_soisdisconnected(),
                tp_recycle_tsuffix(),           
+#ifdef TP_DEBUG_TIMERS
                tp_etimeout(),                          tp_euntimeout(),
                tp_etimeout(),                          tp_euntimeout(),
-               tp_euntimeout_lss(),            tp_ctimeout(),
-               tp_cuntimeout(),                        tp_ctimeout_MIN(),
+               tp_ctimeout(),                          tp_cuntimeout(),
+               tp_ctimeout_MIN(),
+#endif
                tp_freeref(),                           tp_detach(),
                tp0_stash(),                            tp0_send(),
                tp_netcmd(),                            tp_send()
                tp_freeref(),                           tp_detach(),
                tp0_stash(),                            tp0_send(),
                tp_netcmd(),                            tp_send()
@@ -103,6 +116,7 @@ TP_OPEN
 TP_CLOSING 
 TP_REFWAIT
 TP_LISTENING   /* Local to this implementation */
 TP_CLOSING 
 TP_REFWAIT
 TP_LISTENING   /* Local to this implementation */
+TP_CONFIRMING  /* Local to this implementation */
 
 *EVENTS                { struct timeval e_time; }              SYNONYM  E
 
 
 *EVENTS                { struct timeval e_time; }              SYNONYM  E
 
@@ -120,14 +134,12 @@ TP_LISTENING      /* Local to this implementation */
                                 */
 
  TM_sendack            
                                 */
 
  TM_sendack            
-                               /* TM_sendack does dual duty - keepalive AND sendack.
+                               /* TM_sendack does dual duty - keepalive AND closed-window
+                                * Probes.
                                 * It's set w/ keepalive-ticks every time an ack is sent.
                                 * (this is done in (void) tp_emit() ).
                                 * It's set w/ keepalive-ticks every time an ack is sent.
                                 * (this is done in (void) tp_emit() ).
-                                * It's cancelled and reset whenever a DT
-                                * arrives and it doesn't require immediate acking.
-                                * Note that in this case it's set w/ the minimum of
-                                * its prev value and the sendack-ticks value so the 
-                                * purpose of the keepalive is preserved.
+                                * Whenever a DT arrives which doesn't require immediate acking,
+                                * a separate fast-timeout flag is set ensuring 200ms response.
                                 */
  TM_notused    
 
                                 */
  TM_notused    
 
@@ -188,6 +200,7 @@ TP_LISTENING        /* Local to this implementation */
  T_USR_Xrcvd   
  T_DETACH
  T_NETRESET
  T_USR_Xrcvd   
  T_DETACH
  T_NETRESET
+ T_ACPT_req
 
 
 *TRANSITIONS
 
 
 *TRANSITIONS
@@ -288,61 +301,79 @@ TP_CLOSED                 <==             [ TP_LISTENING, TP_CLOSED ]                     T_DETACH
        }
 ;
 
        }
 ;
 
-TP_OPEN                <==              TP_LISTENING                                                           CR_TPDU 
-       ( $P.tp_class == TP_CLASS_0 )
+TP_CONFIRMING  <==              TP_LISTENING                                                           CR_TPDU 
+       ( $P.tp_class == TP_CLASS_0)
+       {
+               $P.tp_refstate = REF_OPEN; /* has timers ??? */
+       }
+;
+
+TP_CONFIRMING          <==              TP_LISTENING                                                   CR_TPDU 
+       DEFAULT
        {
        {
-               IncStat(ts_tp0_conn);
                IFTRACE(D_CONN)
                        tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
                ENDTRACE
                IFDEBUG(D_CONN)
                        printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
                ENDDEBUG
                IFTRACE(D_CONN)
                        tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
                ENDTRACE
                IFDEBUG(D_CONN)
                        printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
                ENDDEBUG
+               $P.tp_refstate = REF_OPEN; /* has timers */
+               $P.tp_fcredit = $$.e_cdt;
+
+               if ($$.e_datalen > 0) {
+                       /* n/a for class 0 */
+                       ASSERT($P.tp_Xrcv.sb_cc == 0); 
+                       sbappendrecord(&$P.tp_Xrcv, $$.e_data);
+                       $$.e_data = MNULL; 
+               } 
+       }
+;
+
+TP_OPEN                <==              TP_CONFIRMING                                                                  T_ACPT_req 
+       ( $P.tp_class == TP_CLASS_0 )
+       {
+               IncStat(ts_tp0_conn);
+               IFTRACE(D_CONN)
+                       tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
+               ENDTRACE
+               IFDEBUG(D_CONN)
+                       printf("Confirming connection: $P" );
+               ENDDEBUG
                soisconnected($P.tp_sock);
                soisconnected($P.tp_sock);
-               $P.tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
                (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
                $P.tp_fcredit = 1;
        }
 ;
 
                (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
                $P.tp_fcredit = 1;
        }
 ;
 
-TP_AKWAIT              <==              TP_LISTENING                                                           CR_TPDU 
-       ( tp_emit(CC_TPDU_type, $P, 0,0, MNULL) == 0 )
+TP_AKWAIT              <==              TP_CONFIRMING                                                          T_ACPT_req
+       (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
        {
                IncStat(ts_tp4_conn); /* even though not quite open */
                IFTRACE(D_CONN)
        {
                IncStat(ts_tp4_conn); /* even though not quite open */
                IFTRACE(D_CONN)
-                       tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
+                       tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
                ENDTRACE
                IFDEBUG(D_CONN)
                ENDTRACE
                IFDEBUG(D_CONN)
-                       printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
+                       printf("Confirming connection: $P" );
                ENDDEBUG
                ENDDEBUG
-               $P.tp_refp->tpr_state = REF_OPEN; /* has timers */
-
-               if ($$.e_datalen > 0) {
-                       /* n/a for class 0 */
-                       ASSERT($P.tp_Xrcv.sb_cc == 0); 
-                       sbappendrecord(&$P.tp_Xrcv, $$.e_data);
-                       $P.tp_flags |= TPF_CONN_DATA_IN;
-                       $$.e_data = MNULL; 
-               } 
-               $P.tp_fcredit = $$.e_cdt;
-               if($P.tp_rx_strat & TPRX_FASTSTART)
-                       $P.tp_cong_win = $$.e_cdt;
+               tp_getoptions($P);
+               soisconnecting($P.tp_sock);
+               if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
+                       $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
                $P.tp_retrans = $P.tp_Nretrans;
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
-        }
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
+       }
 ;
 
 /* TP4 only */
 ;
 
 /* TP4 only */
-TP_CLOSED              <==              TP_LISTENING                                                           CR_TPDU 
+TP_CLOSED              <==              TP_CONFIRMING                                                          T_ACPT_req
        DEFAULT /* emit failed */
        {
        DEFAULT /* emit failed */
        {
-               register struct tp_ref *r = $P.tp_refp;
-
                IFDEBUG(D_CONN)
                        printf("event: CR_TPDU emit CC failed done " );
                ENDDEBUG
                IFDEBUG(D_CONN)
                        printf("event: CR_TPDU emit CC failed done " );
                ENDDEBUG
-               tp_recycle_tsuffix( $P );
-               tp_freeref(r);
+               soisdisconnected($P.tp_sock);
+               tp_recycle_tsuffix($P);
+               tp_freeref($P.tp_lref);
                tp_detach($P);
        }
 ;
                tp_detach($P);
        }
 ;
@@ -352,33 +383,28 @@ TP_CRSENT         <==             TP_CLOSED                                                               T_CONN_req
        DEFAULT
        {
                int error;
        DEFAULT
        {
                int error;
-               extern struct mbuf *m_copy();
                struct mbuf *data = MNULL;
 
                IFTRACE(D_CONN)
                struct mbuf *data = MNULL;
 
                IFTRACE(D_CONN)
-                       tptrace(TPPTmisc, "T_CONN_req flags sbcc", (int)$P.tp_flags,
-                       $P.tp_sock->so_snd.sb_cc, 0, 0);
+                       tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
+                       $P.tp_ucddata, 0, 0);
                ENDTRACE
                ENDTRACE
-               if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
+               data =  MCPY($P.tp_ucddata, M_WAIT);
+               if (data) {
                        IFDEBUG(D_CONN)
                                printf("T_CONN_req.trans m_copy cc 0x%x\n", 
                        IFDEBUG(D_CONN)
                                printf("T_CONN_req.trans m_copy cc 0x%x\n", 
-                                       $P.tp_sock->so_snd.sb_cc);
-                               dump_mbuf($P.tp_sock->so_snd.sb_mb, "sosnd @ T_CONN_req");
+                                       $P.tp_ucddata);
+                               dump_mbuf(data, "sosnd @ T_CONN_req");
                        ENDDEBUG
                        ENDDEBUG
-                       data = 
-                               m_copy($P.tp_sock->so_snd.sb_mb, 0, $P.tp_sock->so_snd.sb_cc);
-                       if( data == MNULL ) {
-                               return ENOBUFS;
-                       }
                }
 
                if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
                        return error; /* driver WON'T change state; will return error */
                
                }
 
                if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
                        return error; /* driver WON'T change state; will return error */
                
-               $P.tp_refp->tpr_state = REF_OPEN; /* has timers */
+               $P.tp_refstate = REF_OPEN; /* has timers */
                if($P.tp_class != TP_CLASS_0) {
                        $P.tp_retrans = $P.tp_Nretrans;
                if($P.tp_class != TP_CLASS_0) {
                        $P.tp_retrans = $P.tp_Nretrans;
-                       tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
+                       tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
                }
        }
 ;
                }
        }
 ;
@@ -387,22 +413,31 @@ TP_CRSENT         <==             TP_CLOSED                                                               T_CONN_req
 TP_REFWAIT             <==             [ TP_CRSENT, TP_AKWAIT, TP_OPEN ]                       DR_TPDU 
        DEFAULT
        {
 TP_REFWAIT             <==             [ TP_CRSENT, TP_AKWAIT, TP_OPEN ]                       DR_TPDU 
        DEFAULT
        {
-               if ($$.e_datalen > 0 && $P.tp_class != TP_CLASS_0) {
-                       sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc); /* purge expedited data */
-                       $P.tp_flags |= TPF_DISC_DATA_IN;
+               sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
+               if ($$.e_datalen > 0) {
                        sbappendrecord(&$P.tp_Xrcv, $$.e_data);
                        $$.e_data = MNULL;
                } 
                        sbappendrecord(&$P.tp_Xrcv, $$.e_data);
                        $$.e_data = MNULL;
                } 
-               tp_indicate(T_DISCONNECT, $P, TP_ERROR_MASK | (u_short)$$.e_reason);
+               if ($P.tp_state == TP_OPEN)
+                       tp_indicate(T_DISCONNECT, $P, 0);
+               else {
+                       int so_error = ECONNREFUSED;
+                       if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
+                           $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
+                           $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
+                               so_error = ECONNABORTED;
+                       tp_indicate(T_DISCONNECT, $P, so_error);
+               }
                tp_soisdisconnected($P);
                if ($P.tp_class != TP_CLASS_0) {
                        if ($P.tp_state == TP_OPEN ) {
                tp_soisdisconnected($P);
                if ($P.tp_class != TP_CLASS_0) {
                        if ($P.tp_state == TP_OPEN ) {
-                               tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
-                               tp_cuntimeout($P.tp_refp, TM_retrans);
-                               tp_cuntimeout($P.tp_refp, TM_inact);
-                               tp_cuntimeout($P.tp_refp, TM_sendack);
+                               tp_euntimeout($P, TM_data_retrans); /* all */
+                               tp_cuntimeout($P, TM_retrans);
+                               tp_cuntimeout($P, TM_inact);
+                               tp_cuntimeout($P, TM_sendack);
+                               $P.tp_flags &= ~TPF_DELACK;
                        }
                        }
-                       tp_cuntimeout($P.tp_refp, TM_retrans);
+                       tp_cuntimeout($P, TM_retrans);
                        if( $$.e_sref !=  0 ) 
                                (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
                }
                        if( $$.e_sref !=  0 ) 
                                (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
                }
@@ -415,8 +450,8 @@ SAME                        <==             TP_CLOSED                                                                       DR_TPDU
                if( $$.e_sref != 0 )
                        (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 
                /* reference timer already set - reset it to be safe (???) */
                if( $$.e_sref != 0 )
                        (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 
                /* reference timer already set - reset it to be safe (???) */
-               tp_euntimeout($P.tp_refp, TM_reference); /* all */
-               tp_etimeout($P.tp_refp, TM_reference, 0, 0, 0, (int)$P.tp_refer_ticks);
+               tp_euntimeout($P, TM_reference); /* all */
+               tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
        }
 ;
 
        }
 ;
 
@@ -424,9 +459,8 @@ SAME                        <==             TP_CLOSED                                                                       DR_TPDU
 TP_REFWAIT             <==     TP_CRSENT                                                                       ER_TPDU
        DEFAULT
        {       
 TP_REFWAIT             <==     TP_CRSENT                                                                       ER_TPDU
        DEFAULT
        {       
-               tp_cuntimeout($P.tp_refp, TM_retrans);
-               tp_indicate(T_DISCONNECT, $P, 
-                       TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
+               tp_cuntimeout($P, TM_retrans);
+               tp_indicate(ER_TPDU, $P, $$.e_reason);
                tp_soisdisconnected($P);
        }
 ;
                tp_soisdisconnected($P);
        }
 ;
@@ -435,8 +469,7 @@ TP_REFWAIT          <==     TP_CRSENT                                                                       ER_TPDU
 TP_REFWAIT             <==             TP_CLOSING                                                                      DR_TPDU
        DEFAULT
        {        
 TP_REFWAIT             <==             TP_CLOSING                                                                      DR_TPDU
        DEFAULT
        {        
-               $P.tp_sock->so_error = (u_short)$$.e_reason;
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_cuntimeout($P, TM_retrans);
                tp_soisdisconnected($P);
        }
 ;
                tp_soisdisconnected($P);
        }
 ;
@@ -447,8 +480,8 @@ TP_REFWAIT          <==             TP_CLOSING                                                                      DR_TPDU
 TP_REFWAIT             <==             TP_CLOSING                                                                      ER_TPDU
        DEFAULT
        {        
 TP_REFWAIT             <==             TP_CLOSING                                                                      ER_TPDU
        DEFAULT
        {        
-               $P.tp_sock->so_error = (u_short)$$.e_reason;
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_indicate(ER_TPDU, $P, $$.e_reason);
+               tp_cuntimeout($P, TM_retrans);
                tp_soisdisconnected($P);
        }
 ;
                tp_soisdisconnected($P);
        }
 ;
@@ -456,7 +489,7 @@ TP_REFWAIT          <==             TP_CLOSING                                                                      ER_TPDU
 TP_REFWAIT             <==             TP_CLOSING                                                                      DC_TPDU 
        DEFAULT
        {        
 TP_REFWAIT             <==             TP_CLOSING                                                                      DC_TPDU 
        DEFAULT
        {        
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_cuntimeout($P, TM_retrans);
                tp_soisdisconnected($P);
        }
 ;
                tp_soisdisconnected($P);
        }
 ;
@@ -475,9 +508,7 @@ TP_REFWAIT          <==     TP_OPEN                                                                         ER_TPDU
        ($P.tp_class == TP_CLASS_0)
        {
                tp_soisdisconnecting($P.tp_sock);
        ($P.tp_class == TP_CLASS_0)
        {
                tp_soisdisconnecting($P.tp_sock);
-               tp_indicate(T_DISCONNECT, $P, 
-                       TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
-
+               tp_indicate(ER_TPDU, $P, $$.e_reason);
                tp_soisdisconnected($P);
                tp_netcmd( $P, CONN_CLOSE );
        }
                tp_soisdisconnected($P);
                tp_netcmd( $P, CONN_CLOSE );
        }
@@ -487,15 +518,14 @@ TP_CLOSING                <==     [ TP_AKWAIT, TP_OPEN ]                                          ER_TPDU
        DEFAULT
        {
                if ($P.tp_state == TP_OPEN) {
        DEFAULT
        {
                if ($P.tp_state == TP_OPEN) {
-                       tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
-                       tp_cuntimeout($P.tp_refp, TM_inact);
-                       tp_cuntimeout($P.tp_refp, TM_sendack);
+                       tp_euntimeout($P, TM_data_retrans); /* all */
+                       tp_cuntimeout($P, TM_inact);
+                       tp_cuntimeout($P, TM_sendack);
                }
                tp_soisdisconnecting($P.tp_sock);
                }
                tp_soisdisconnecting($P.tp_sock);
-               tp_indicate(T_DISCONNECT, $P, 
-                       TP_ERROR_MASK |(u_short)($$.e_reason | 0x40));
+               tp_indicate(ER_TPDU, $P, $$.e_reason);
                $P.tp_retrans = $P.tp_Nretrans;
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
        }
 ;
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
        }
 ;
@@ -503,7 +533,7 @@ TP_CLOSING          <==     [ TP_AKWAIT, TP_OPEN ]                                          ER_TPDU
 TP_OPEN                        <==             TP_CRSENT                                                                       CC_TPDU 
        ($P.tp_class == TP_CLASS_0) 
        {       
 TP_OPEN                        <==             TP_CRSENT                                                                       CC_TPDU 
        ($P.tp_class == TP_CLASS_0) 
        {       
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_cuntimeout($P, TM_retrans);
                IncStat(ts_tp0_conn);
                $P.tp_fcredit = 1;
                soisconnected($P.tp_sock);
                IncStat(ts_tp0_conn);
                $P.tp_fcredit = 1;
                soisconnected($P.tp_sock);
@@ -520,29 +550,27 @@ TP_OPEN                   <==             TP_CRSENT                                                                       CC_TPDU
                IncStat(ts_tp4_conn);
                $P.tp_fref = $$.e_sref;
                $P.tp_fcredit = $$.e_cdt;
                IncStat(ts_tp4_conn);
                $P.tp_fref = $$.e_sref;
                $P.tp_fcredit = $$.e_cdt;
-               if($P.tp_rx_strat & TPRX_FASTSTART)
-                       $P.tp_cong_win = $$.e_cdt;
+               if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
+                       $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
                tp_getoptions($P);
                tp_getoptions($P);
-               tp_cuntimeout($P.tp_refp, TM_retrans);
-               if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
+               tp_cuntimeout($P, TM_retrans);
+               if ($P.tp_ucddata) {
                        IFDEBUG(D_CONN)
                        IFDEBUG(D_CONN)
-                               printf("dropping %d octets of connect data cc 0x%x\n",
-                                       $P.tp_sock->so_snd.sb_mb->m_len, 
-                                       $P.tp_sock->so_snd.sb_cc);
+                               printf("dropping user connect data cc 0x%x\n",
+                                       $P.tp_ucddata->m_len);
                        ENDDEBUG
                        ENDDEBUG
-                       sbdrop(&$P.tp_sock->so_snd, $P.tp_sock->so_snd.sb_cc);
-                       $P.tp_flags &= ~TPF_CONN_DATA_OUT;
+                       m_freem($P.tp_ucddata);
+                       $P.tp_ucddata = 0;
                }
                soisconnected($P.tp_sock);
                if ($$.e_datalen > 0) {
                        ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
                        sbappendrecord(&$P.tp_Xrcv, $$.e_data);
                }
                soisconnected($P.tp_sock);
                if ($$.e_datalen > 0) {
                        ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
                        sbappendrecord(&$P.tp_Xrcv, $$.e_data);
-                       $P.tp_flags |= TPF_CONN_DATA_IN;
                        $$.e_data = MNULL;
                }
 
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
                        $$.e_data = MNULL;
                }
 
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
        }
 ;
 
        }
 ;
 
@@ -550,19 +578,17 @@ TP_OPEN                   <==             TP_CRSENT                                                                       CC_TPDU
 SAME                   <==             TP_CRSENT                                                                       TM_retrans 
        (       $P.tp_retrans > 0 )
        {
 SAME                   <==             TP_CRSENT                                                                       TM_retrans 
        (       $P.tp_retrans > 0 )
        {
-               extern struct mbuf *m_copy();
                struct mbuf *data = MNULL;
                int error;
 
                IncStat(ts_retrans_cr);
                struct mbuf *data = MNULL;
                int error;
 
                IncStat(ts_retrans_cr);
-               if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
+               $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
+               data = MCPY($P.tp_ucddata, M_NOWAIT);
+               if($P.tp_ucddata) {
                        IFDEBUG(D_CONN)
                        IFDEBUG(D_CONN)
-                               printf("TM_retrans.trans m_copy cc 0x%x\n", 
-                                       $P.tp_sock->so_snd.sb_cc);
-                               dump_mbuf($P.tp_sock->so_snd.sb_mb, "sosnd @ TM_retrans");
+                               printf("TM_retrans.trans m_copy cc 0x%x\n", data);
+                               dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
                        ENDDEBUG
                        ENDDEBUG
-                       data = 
-                               m_copy($P.tp_sock->so_snd.sb_mb, 0, $P.tp_sock->so_snd.sb_cc);
                        if( data == MNULL )
                                return ENOBUFS;
                }
                        if( data == MNULL )
                                return ENOBUFS;
                }
@@ -571,7 +597,7 @@ SAME                        <==             TP_CRSENT                                                                       TM_retrans
                if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
                        $P.tp_sock->so_error = error;
                }
                if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
                        $P.tp_sock->so_error = error;
                }
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
        }
 ;
 
        }
 ;
 
@@ -595,12 +621,13 @@ SAME                      <==      TP_AKWAIT                                                                                      CR_TPDU
         */
        {       
                int error;
         */
        {       
                int error;
+               struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
 
 
-               if( error = tp_emit(CC_TPDU_type, $P, 0, 0, MNULL) ) {
+               if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
                        $P.tp_sock->so_error = error;
                }
                $P.tp_retrans = $P.tp_Nretrans;
                        $P.tp_sock->so_error = error;
                }
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
        }
 ;
 
        }
 ;
 
@@ -611,16 +638,18 @@ TP_OPEN                   <==             TP_AKWAIT                                                                               DT_TPDU
        {
                int doack;
 
        {
                int doack;
 
-               if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
-                       sbdrop(&$P.tp_sock->so_snd, $P.tp_sock->so_snd.sb_cc);
-                       $P.tp_flags &= ~TPF_CONN_DATA_OUT;
+               /*
+                * Get rid of any confirm or connect data, so that if we
+                * crash or close, it isn't thought of as disconnect data.
+                */
+               if ($P.tp_ucddata) {
+                       m_freem($P.tp_ucddata);
+                       $P.tp_ucddata = 0;
                }
                }
-
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
+               tp_cuntimeout($P, TM_retrans);
                soisconnected($P.tp_sock);
                soisconnected($P.tp_sock);
-               tp_getoptions($P);
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
 
                /* see also next 2 transitions, if you make any changes */
 
 
                /* see also next 2 transitions, if you make any changes */
 
@@ -629,11 +658,11 @@ TP_OPEN                   <==             TP_AKWAIT                                                                               DT_TPDU
                        printf("tp_stash returns %d\n",doack);
                ENDDEBUG
 
                        printf("tp_stash returns %d\n",doack);
                ENDDEBUG
 
-               if(doack) {
+               if (doack) {
                        (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
                        (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
-                       tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
+                       tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
                } else
                } else
-                       tp_ctimeout( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
+                       tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
                
                IFDEBUG(D_DATA)
                        printf("after stash calling sbwakeup\n");
                
                IFDEBUG(D_DATA)
                        printf("after stash calling sbwakeup\n");
@@ -660,7 +689,7 @@ SAME                        <==             TP_OPEN                                                                         DT_TPDU
        {
                int doack; /* tells if we must ack immediately */
 
        {
                int doack; /* tells if we must ack immediately */
 
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                sbwakeup( &$P.tp_sock->so_rcv );
 
                doack = tp_stash($P, $E);
                sbwakeup( &$P.tp_sock->so_rcv );
 
                doack = tp_stash($P, $E);
@@ -671,7 +700,7 @@ SAME                        <==             TP_OPEN                                                                         DT_TPDU
                if(doack)
                        (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
                else
                if(doack)
                        (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
                else
-                       tp_ctimeout_MIN( $P.tp_refp, TM_sendack, (int)$P.tp_sendack_ticks);
+                       tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
                
                IFDEBUG(D_DATA)
                        printf("after stash calling sbwakeup\n");
                
                IFDEBUG(D_DATA)
                        printf("after stash calling sbwakeup\n");
@@ -698,7 +727,7 @@ SAME                        <==     [ TP_OPEN, TP_AKWAIT ]                                                  DT_TPDU
                ENDTRACE
                IncStat(ts_dt_niw);
                m_freem($$.e_data);
                ENDTRACE
                IncStat(ts_dt_niw);
                m_freem($$.e_data);
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
        }
 ;
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
        }
 ;
@@ -707,15 +736,13 @@ SAME                      <==     [ TP_OPEN, TP_AKWAIT ]                                                  DT_TPDU
 TP_OPEN                        <==             TP_AKWAIT                                                                               AK_TPDU
        DEFAULT
        {
 TP_OPEN                        <==             TP_AKWAIT                                                                               AK_TPDU
        DEFAULT
        {
-               if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
-                       sbdrop(&$P.tp_sock->so_snd, $P.tp_sock->so_snd.sb_cc);
-                       $P.tp_flags &= ~TPF_CONN_DATA_OUT;
+               if ($P.tp_ucddata) {
+                       m_freem($P.tp_ucddata);
+                       $P.tp_ucddata = 0;
                }
                }
-
                (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
                (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_cuntimeout($P, TM_retrans);
 
 
-               tp_getoptions($P);
                soisconnected($P.tp_sock);
                IFTRACE(D_CONN)
                        struct socket *so = $P.tp_sock;
                soisconnected($P.tp_sock);
                IFTRACE(D_CONN)
                        struct socket *so = $P.tp_sock;
@@ -727,38 +754,36 @@ TP_OPEN                   <==             TP_AKWAIT                                                                               AK_TPDU
                                so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
                ENDTRACE
 
                                so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
                ENDTRACE
 
-               tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
        }
 ;
 
 /* TP4 only */
 TP_OPEN                <==     [ TP_OPEN, TP_AKWAIT ]                                          XPD_TPDU
        }
 ;
 
 /* TP4 only */
 TP_OPEN                <==     [ TP_OPEN, TP_AKWAIT ]                                          XPD_TPDU
-       ( $P.tp_Xrcvnxt == $$.e_seq  && $P.tp_Xrcv.sb_cc == 0)
+       ($P.tp_Xrcvnxt == $$.e_seq)
        {
                if( $P.tp_state == TP_AKWAIT ) {
        {
                if( $P.tp_state == TP_AKWAIT ) {
-                       if( $P.tp_flags & TPF_CONN_DATA_OUT ) {
-                               sbdrop(&$P.tp_sock->so_snd, $P.tp_sock->so_snd.sb_cc);
-                               $P.tp_flags &= ~TPF_CONN_DATA_OUT;
+                       if ($P.tp_ucddata) {
+                               m_freem($P.tp_ucddata);
+                               $P.tp_ucddata = 0;
                        }
                        }
-                       tp_cuntimeout($P.tp_refp, TM_retrans);
-                       tp_getoptions($P);
+                       tp_cuntimeout($P, TM_retrans);
                        soisconnected($P.tp_sock);
                        soisconnected($P.tp_sock);
-                       tp_ctimeout($P.tp_refp, TM_sendack, (int)$P.tp_keepalive_ticks);
-                       tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+                       tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
+                       tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                } 
                IFTRACE(D_XPD)
                tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
                                $P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
                ENDTRACE
 
                } 
                IFTRACE(D_XPD)
                tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
                                $P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
                ENDTRACE
 
-               sbappendrecord(&$P.tp_Xrcv, $$.e_data);
+               $P.tp_sock->so_state |= SS_RCVATMARK;
+               $$.e_data->m_flags |= M_EOR;
+               sbinsertoob(&$P.tp_Xrcv, $$.e_data);
                IFDEBUG(D_XPD)
                        dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
                ENDDEBUG
                IFDEBUG(D_XPD)
                        dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
                ENDDEBUG
-               $P.tp_flags |= TPF_XPD_PRESENT;
-               /* kludge for select(): */ 
-               $P.tp_sock->so_state |= SS_OOBAVAIL;
                tp_indicate(T_XDATA, $P, 0);
                sbwakeup( &$P.tp_Xrcv );
 
                tp_indicate(T_XDATA, $P, 0);
                sbwakeup( &$P.tp_Xrcv );
 
@@ -772,9 +797,8 @@ SAME                        <==             TP_OPEN                                                                         T_USR_Xrcvd
        DEFAULT
        {
                if( $P.tp_Xrcv.sb_cc == 0 ) {
        DEFAULT
        {
                if( $P.tp_Xrcv.sb_cc == 0 ) {
-                       $P.tp_flags &= ~TPF_XPD_PRESENT;
                        /* kludge for select(): */ 
                        /* kludge for select(): */ 
-                       $P.tp_sock->so_state &= ~SS_OOBAVAIL;
+                       /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
                }
        }
        /* OLD WAY:
                }
        }
        /* OLD WAY:
@@ -810,17 +834,12 @@ SAME                      <==     [ TP_AKWAIT, TP_OPEN ]                                                  XPD_TPDU
                if( $P.tp_Xrcvnxt != $$.e_seq )
                        IncStat(ts_xpd_niw);
                if( $P.tp_Xrcv.sb_cc ) {
                if( $P.tp_Xrcvnxt != $$.e_seq )
                        IncStat(ts_xpd_niw);
                if( $P.tp_Xrcv.sb_cc ) {
-                       if( $P.tp_flags & TPF_CONN_DATA_IN ) {
-                               /* user isn't reading the connection data; see note above */
-                               sbdrop(&$P.tp_Xrcv, $P.tp_Xrcv.sb_cc);
-                               $P.tp_flags &= ~TPF_CONN_DATA_IN;
-                       }
                        /* might as well kick 'em again */
                        tp_indicate(T_XDATA, $P, 0);
                        IncStat(ts_xpd_dup);
                }
                m_freem($$.e_data);
                        /* might as well kick 'em again */
                        tp_indicate(T_XDATA, $P, 0);
                        IncStat(ts_xpd_dup);
                }
                m_freem($$.e_data);
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                /* don't send an xack because the xak gives "last one received", not
                 * "next one i expect" (dumb)
                 */
                /* don't send an xack because the xak gives "last one received", not
                 * "next one i expect" (dumb)
                 */
@@ -849,10 +868,11 @@ TP_REFWAIT                <==     TP_CRSENT                                                                               T_DETACH
 ;
 
 /* TP4 only */
 ;
 
 /* TP4 only */
-TP_CLOSING             <==     [ TP_CLOSING, TP_AKWAIT, TP_CRSENT ]                    T_DETACH
+TP_CLOSING             <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH
        DEFAULT
        {
                struct socket *so = $P.tp_sock;
        DEFAULT
        {
                struct socket *so = $P.tp_sock;
+               struct mbuf *data = MNULL;
 
                /* detach from parent socket so it can finish closing */
                if (so->so_head) {
 
                /* detach from parent socket so it can finish closing */
                if (so->so_head) {
@@ -862,9 +882,10 @@ TP_CLOSING         <==     [ TP_CLOSING, TP_AKWAIT, TP_CRSENT ]                    T_DETACH
                }
                if ($P.tp_state != TP_CLOSING) {
                        tp_soisdisconnecting($P.tp_sock);
                }
                if ($P.tp_state != TP_CLOSING) {
                        tp_soisdisconnecting($P.tp_sock);
-                       (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, MNULL);
+                       data = MCPY($P.tp_ucddata, M_NOWAIT);
+                       (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
                        $P.tp_retrans = $P.tp_Nretrans;
                        $P.tp_retrans = $P.tp_Nretrans;
-                       tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+                       tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
                }
        }
 ;
                }
        }
 ;
@@ -879,30 +900,27 @@ TP_REFWAIT                <==             [ TP_OPEN, TP_CRSENT ]                                          T_DISC_req
 ;
 
 /* TP4 only */
 ;
 
 /* TP4 only */
-TP_CLOSING             <==             [ TP_AKWAIT, TP_OPEN, TP_CRSENT ]                         T_DISC_req
+TP_CLOSING             <==     [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
        DEFAULT
        {
        DEFAULT
        {
-               struct mbuf *data = MNULL;
-               extern struct mbuf *m_copy();
+               struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
 
                if($P.tp_state == TP_OPEN) {
 
                if($P.tp_state == TP_OPEN) {
-                       tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
-                       tp_cuntimeout($P.tp_refp, TM_inact);
-                       tp_cuntimeout($P.tp_refp, TM_sendack);
+                       tp_euntimeout($P, TM_data_retrans); /* all */
+                       tp_cuntimeout($P, TM_inact);
+                       tp_cuntimeout($P, TM_sendack);
+                       $P.tp_flags &= ~TPF_DELACK;
                }
                }
-               if( $P.tp_flags & TPF_DISC_DATA_OUT ) {
+               if (data) {
                        IFDEBUG(D_CONN)
                        IFDEBUG(D_CONN)
-                               printf("T_DISC_req.trans m_copy cc 0x%x\n", 
-                                       $P.tp_sock->so_snd.sb_cc);
-                               dump_mbuf($P.tp_sock->so_snd.sb_mb, "sosnd @ T_DISC_req");
+                               printf("T_DISC_req.trans tp_ucddata 0x%x\n", 
+                                       $P.tp_ucddata);
+                               dump_mbuf(data, "ucddata @ T_DISC_req");
                        ENDDEBUG
                        ENDDEBUG
-                       data = 
-                               m_copy($P.tp_sock->so_snd.sb_mb, 0, $P.tp_sock->so_snd.sb_cc);
                }
                }
-
                tp_soisdisconnecting($P.tp_sock);
                $P.tp_retrans = $P.tp_Nretrans;
                tp_soisdisconnecting($P.tp_sock);
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
 
                if( trick_hc )
                        return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
 
                if( trick_hc )
                        return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
@@ -914,12 +932,15 @@ SAME                      <==             TP_AKWAIT                                                                       TM_retrans
        ( $P.tp_retrans > 0 )
        {
                int error;
        ( $P.tp_retrans > 0 )
        {
                int error;
+               struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
 
                IncStat(ts_retrans_cc);
                $P.tp_retrans --;
 
                IncStat(ts_retrans_cc);
                $P.tp_retrans --;
-               if( error = tp_emit(CC_TPDU_type, $P, 0, 0, MNULL) ) 
+               $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
+
+               if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 
                        $P.tp_sock->so_error = error;
                        $P.tp_sock->so_error = error;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_cc_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
        }
 ;
 
        }
 ;
 
@@ -933,7 +954,7 @@ TP_CLOSING          <==             TP_AKWAIT                                                                       TM_retrans
                tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
                $P.tp_retrans = $P.tp_Nretrans;
                tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
        }
 ;
 
        }
 ;
 
@@ -946,9 +967,9 @@ TP_CLOSING          <==             TP_AKWAIT                                                                       TM_retrans
 TP_CLOSING             <==             TP_OPEN            [ TM_inact, TM_retrans, TM_data_retrans ]
        DEFAULT
        {
 TP_CLOSING             <==             TP_OPEN            [ TM_inact, TM_retrans, TM_data_retrans ]
        DEFAULT
        {
-               tp_euntimeout($P.tp_refp, TM_data_retrans); /* all */
-               tp_cuntimeout($P.tp_refp, TM_inact); 
-               tp_cuntimeout($P.tp_refp, TM_sendack);
+               tp_euntimeout($P, TM_data_retrans); /* all */
+               tp_cuntimeout($P, TM_inact); 
+               tp_cuntimeout($P, TM_sendack);
 
                IncStat(ts_conn_gaveup);
                tp_soisdisconnecting($P.tp_sock);
 
                IncStat(ts_conn_gaveup);
                tp_soisdisconnecting($P.tp_sock);
@@ -956,7 +977,7 @@ TP_CLOSING          <==             TP_OPEN            [ TM_inact, TM_retrans, TM_data_retrans ]
                tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
                $P.tp_retrans = $P.tp_Nretrans;
                tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
                $P.tp_retrans = $P.tp_Nretrans;
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
        }
 ;
 
        }
 ;
 
@@ -964,17 +985,15 @@ TP_CLOSING                <==             TP_OPEN            [ TM_inact, TM_retrans, TM_data_retrans ]
 SAME                   <==             TP_OPEN                                                                         TM_retrans
        ( $P.tp_retrans > 0 )
        {
 SAME                   <==             TP_OPEN                                                                         TM_retrans
        ( $P.tp_retrans > 0 )
        {
+               $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
                /* resume XPD */
                if      ( $P.tp_Xsnd.sb_mb )  {
                /* resume XPD */
                if      ( $P.tp_Xsnd.sb_mb )  {
-                       extern struct mbuf *m_copy();
-                       struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, $P.tp_Xsnd.sb_cc);
-                       /* m_copy doesn't preserve the m_xlink field, but at this pt.
-                        * that doesn't matter
-                        */
+                       struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
+                       int shift;
 
                        IFTRACE(D_XPD)
 
                        IFTRACE(D_XPD)
-                               tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
-                                       $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 
+                               tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
+                                       $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 
                                        $P.tp_snduna); 
                        ENDTRACE
                        IFDEBUG(D_XPD)
                                        $P.tp_snduna); 
                        ENDTRACE
                        IFDEBUG(D_XPD)
@@ -982,60 +1001,19 @@ SAME                     <==             TP_OPEN                                                                         TM_retrans
                        ENDDEBUG
                        IncStat(ts_retrans_xpd);
                        $P.tp_retrans --;
                        ENDDEBUG
                        IncStat(ts_retrans_xpd);
                        $P.tp_retrans --;
+                       shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
                        (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
                        (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
-                       tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
+                       tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
                }
        }
 ;
 
 /* TP4 only */
 SAME                   <==             TP_OPEN                                                                 TM_data_retrans
                }
        }
 ;
 
 /* TP4 only */
 SAME                   <==             TP_OPEN                                                                 TM_data_retrans
-       ( $$.e_retrans > 0 )
+       ($P.tp_rxtshift < TP_NRETRANS)
        {       
        {       
-               register        SeqNum                  low, lowsave = 0;
-               register        struct tp_rtc   *r = $P.tp_snduna_rtc;
-               register        struct mbuf     *m;
-               register        SeqNum                  high = $$.e_high;
-               extern          struct mbuf             *m_copy();
-
-               low =
-                       SEQ_GT($P, $P.tp_snduna, $$.e_low )? $P.tp_snduna: $$.e_low;
-               lowsave = low;
-               if (($P.tp_rx_strat & TPRX_EACH) == 0)
-                       high = (high>low)?low:high;
-
-               if( $P.tp_rx_strat & TPRX_USE_CW ) {
-                       register int i;
-
-                       $P.tp_cong_win = 1;
-
-                       i = SEQ_ADD($P, low, $P.tp_cong_win);
-                       if(SEQ_LT($P, i, high ))
-                               high = i;
-               }
-
-               while( SEQ_LEQ($P, low, high) ){
-                       if ( r == (struct tp_rtc *)0 ){
-                               IFDEBUG(D_RTC)
-                                       printf( "tp: retrans rtc list is GONE!\n");
-                               ENDDEBUG
-                               break;
-                       }
-                       if ( r->tprt_seq == low ){
-                               if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
-                                       break;
-                               (void) tp_emit(DT_TPDU_type, $P, low, r->tprt_eot, m);
-                               IncStat(ts_retrans_dt);
-                               SEQ_INC($P, low );
-                       }
-                       r = r->tprt_next;
-               }
-               if ( SEQ_LEQ($P, lowsave, high) ){
-                       $$.e_retrans --;
-                       tp_etimeout($P.tp_refp, TM_data_retrans, (caddr_t)lowsave,
-                                       (caddr_t)high, $$.e_retrans,
-                                       ($P.tp_Nretrans - $$.e_retrans) * (int)$P.tp_dt_ticks);
-               }
+               $P.tp_rxtshift++;
+               (void) tp_data_retrans($P);
        }
 ;
 
        }
 ;
 
@@ -1046,7 +1024,7 @@ SAME                      <==             TP_CLOSING                                                                      TM_retrans
                $P.tp_retrans --;
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
                IncStat(ts_retrans_dr);
                $P.tp_retrans --;
                (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
                IncStat(ts_retrans_dr);
-               tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_dr_ticks);
+               tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
        }
 ;
 
        }
 ;
 
@@ -1055,9 +1033,9 @@ TP_REFWAIT                <==             TP_CLOSING                                                                      TM_retrans
        DEFAULT /* no more retrans - gave up */
        {       
                $P.tp_sock->so_error = ETIMEDOUT;
        DEFAULT /* no more retrans - gave up */
        {       
                $P.tp_sock->so_error = ETIMEDOUT;
-               $P.tp_refp->tpr_state = REF_FROZEN;
+               $P.tp_refstate = REF_FROZEN;
                tp_recycle_tsuffix( $P );
                tp_recycle_tsuffix( $P );
-               tp_etimeout($P.tp_refp, TM_reference, 0,0,0, (int)$P.tp_refer_ticks);
+               tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
        }
 ;
 
        }
 ;
 
@@ -1069,7 +1047,7 @@ TP_REFWAIT                <==             TP_CLOSING                                                                      TM_retrans
 TP_CLOSED              <==             TP_REFWAIT                                                                      TM_reference
        DEFAULT
        {
 TP_CLOSED              <==             TP_REFWAIT                                                                      TM_reference
        DEFAULT
        {
-               tp_freeref($P.tp_refp);
+               tp_freeref($P.tp_lref);
                tp_detach($P);
        }
 ;
                tp_detach($P);
        }
 ;
@@ -1080,7 +1058,7 @@ SAME                      <==     TP_OPEN                                                         [ CR_TPDU, CC_TPDU ]
        DEFAULT
        {       
                if( $P.tp_class != TP_CLASS_0) {
        DEFAULT
        {       
                if( $P.tp_class != TP_CLASS_0) {
-                       tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+                       tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                        if ( $E.ev_number == CC_TPDU )
                                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 
                }
                        if ( $E.ev_number == CC_TPDU )
                                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 
                }
@@ -1093,8 +1071,8 @@ SAME                      <==     TP_OPEN                                                                 T_DATA_req
        DEFAULT
        {
                IFTRACE(D_DATA)
        DEFAULT
        {
                IFTRACE(D_DATA)
-                       tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
-                               $P.tp_sndhiwat, $P.tp_snduna, $P.tp_fcredit, $P);
+                       tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
+                               $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
                ENDTRACE
 
                tp_send($P);
                ENDTRACE
 
                tp_send($P);
@@ -1113,15 +1091,14 @@ SAME                    <==             TP_OPEN                                                                         T_XPD_req
 
                /* resume XPD */
                if      ( $P.tp_Xsnd.sb_mb )  {
 
                /* resume XPD */
                if      ( $P.tp_Xsnd.sb_mb )  {
-                       extern struct mbuf *m_copy();
-                       struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, $P.tp_Xsnd.sb_cc);
+                       struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
                        /* m_copy doesn't preserve the m_xlink field, but at this pt.
                         * that doesn't matter
                         */
 
                        IFTRACE(D_XPD)
                        /* m_copy doesn't preserve the m_xlink field, but at this pt.
                         * that doesn't matter
                         */
 
                        IFTRACE(D_XPD)
-                               tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
-                                       $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndhiwat, 
+                               tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
+                                       $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 
                                        $P.tp_snduna); 
                        ENDTRACE
                        IFDEBUG(D_XPD)
                                        $P.tp_snduna); 
                        ENDTRACE
                        IFDEBUG(D_XPD)
@@ -1131,7 +1108,8 @@ SAME                      <==             TP_OPEN                                                                         T_XPD_req
                        error = 
                                tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
                        $P.tp_retrans = $P.tp_Nretrans;
                        error = 
                                tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
                        $P.tp_retrans = $P.tp_Nretrans;
-                       tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
+
+                       tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
                        SEQ_INC($P, $P.tp_Xsndnxt);
                } 
                if(trick_hc)
                        SEQ_INC($P, $P.tp_Xsndnxt);
                } 
                if(trick_hc)
@@ -1148,34 +1126,21 @@ SAME                    <==             TP_OPEN                                                                         AK_TPDU
         * OR no news but the credit should be processed.
         */
        {
         * OR no news but the credit should be processed.
         */
        {
+               struct sockbuf *sb = &$P.tp_sock->so_snd;
+
                IFDEBUG(D_ACKRECV)
                        printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
                ENDDEBUG
                if( $P.tp_class != TP_CLASS_0) {
                IFDEBUG(D_ACKRECV)
                        printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
                ENDDEBUG
                if( $P.tp_class != TP_CLASS_0) {
-                       tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
-                       tp_euntimeout_lss($P.tp_refp, TM_data_retrans, $$.e_seq);
+                       tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                }
                }
-               sbwakeup( &$P.tp_sock->so_snd );
-
-               tp_send($P);
+               sbwakeup(sb);
                IFDEBUG(D_ACKRECV)
                IFDEBUG(D_ACKRECV)
-                       printf("GOOD ACK new sndhiwat 0x%x\n", $P.tp_sndhiwat);
+                       printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
                ENDDEBUG
        }
 ;
 
                ENDDEBUG
        }
 ;
 
-/* TP4, and TP0 after sending a CC or possibly a CR */
-SAME                   <==             TP_OPEN                                                                         XAK_TPDU
-       DEFAULT
-       {
-               IFTRACE(D_ACKRECV)
-                       tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
-               ENDTRACE
-               if( $P.tp_class != TP_CLASS_0 ) {
-                       tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
-               } 
-       }
-;
 /* TP4, and TP0 after sending a CC or possibly a CR */
 SAME                   <==             TP_OPEN                                                                          AK_TPDU
        DEFAULT
 /* TP4, and TP0 after sending a CC or possibly a CR */
 SAME                   <==             TP_OPEN                                                                          AK_TPDU
        DEFAULT
@@ -1191,7 +1156,7 @@ SAME                      <==             TP_OPEN                                                                          AK_TPDU
                                IncStat( ts_ackreason[_ACK_FCC_] );
                                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
                        }
                                IncStat( ts_ackreason[_ACK_FCC_] );
                                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
                        }
-                       tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
+                       tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
                } 
        }
 ;
                } 
        }
 ;
@@ -1201,27 +1166,26 @@ SAME                    <==             TP_OPEN                                                                          AK_TPDU
                /* just so happens that this is never true now, because we allow
                 * only 1 packet in the queue at once (this could be changed)
                if      ( $P.tp_Xsnd.sb_mb )  {
                /* just so happens that this is never true now, because we allow
                 * only 1 packet in the queue at once (this could be changed)
                if      ( $P.tp_Xsnd.sb_mb )  {
-                       extern struct mbuf *m_copy();
                        struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
 
                        (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
                        $P.tp_retrans = $P.tp_Nretrans;
                        struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
 
                        (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
                        $P.tp_retrans = $P.tp_Nretrans;
-                       tp_ctimeout($P.tp_refp, TM_retrans, (int)$P.tp_xpd_ticks);
+                       tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
                        SEQ_INC($P, $P.tp_Xsndnxt);
                }
                 */
        /* end of the above hack */
 
 /* TP4 only */
                        SEQ_INC($P, $P.tp_Xsndnxt);
                }
                 */
        /* end of the above hack */
 
 /* TP4 only */
-SAME                   <==     TP_OPEN                                                                                 XAK_TPDU
+SAME                   <==     TP_OPEN                                                                         XAK_TPDU
        ( tp_goodXack($P, $$.e_seq) )
        /* tp_goodXack checks for good ack, removes the correct 
         * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
         * also updates tp_Xuna
         */
        {       
        ( tp_goodXack($P, $$.e_seq) )
        /* tp_goodXack checks for good ack, removes the correct 
         * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
         * also updates tp_Xuna
         */
        {       
-               tp_ctimeout($P.tp_refp, TM_inact, (int)$P.tp_inact_ticks);
-               tp_cuntimeout($P.tp_refp, TM_retrans);
+               tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
+               tp_cuntimeout($P, TM_retrans);
 
                sbwakeup( &$P.tp_sock->so_snd );
 
 
                sbwakeup( &$P.tp_sock->so_snd );
 
@@ -1230,23 +1194,47 @@ SAME                    <==     TP_OPEN                                                                                 XAK_TPDU
        }
 ;
 
        }
 ;
 
+/* TP4, and TP0 after sending a CC or possibly a CR */
+SAME                   <==             TP_OPEN                                                                         XAK_TPDU
+       DEFAULT
+       {
+               IFTRACE(D_ACKRECV)
+                       tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
+               ENDTRACE
+               if( $P.tp_class != TP_CLASS_0 ) {
+                       tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
+               } 
+       }
+;
+
 /* TP4 only */
 SAME                   <==             TP_OPEN                                                                 TM_sendack 
        DEFAULT
        {       
 /* TP4 only */
 SAME                   <==             TP_OPEN                                                                 TM_sendack 
        DEFAULT
        {       
+               int timo;
                IFTRACE(D_TIMER)
                        tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 
                        $P.tp_sent_lcdt, 0);
                ENDTRACE
                IncPStat($P, tps_n_TMsendack);
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
                IFTRACE(D_TIMER)
                        tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 
                        $P.tp_sent_lcdt, 0);
                ENDTRACE
                IncPStat($P, tps_n_TMsendack);
                (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
+               if ($P.tp_fcredit == 0) {
+                       if ($P.tp_rxtshift < TP_MAXRXTSHIFT)
+                               $P.tp_rxtshift++;
+                       timo = ($P.tp_dt_ticks) << $P.tp_rxtshift;
+               } else
+                       timo = $P.tp_sendack_ticks;
+               tp_ctimeout($P, TM_sendack, timo);
        }
 ;
 
 /* TP0 only */
 SAME                   <==             TP_OPEN                                                                         T_USR_rcvd
        ($P.tp_class == TP_CLASS_0)
        }
 ;
 
 /* TP0 only */
 SAME                   <==             TP_OPEN                                                                         T_USR_rcvd
        ($P.tp_class == TP_CLASS_0)
-       NULLACTION
+       {
+               if (sbspace(&$P.tp_sock->so_rcv) > 0)
+                       tp0_openflow($P);
+       }
 ;
 
 /* TP4 only */
 ;
 
 /* TP4 only */
@@ -1263,8 +1251,22 @@ SAME                     <==             TP_OPEN                                                                         T_USR_rcvd
        DEFAULT
        {       
                if( trick_hc ) {
        DEFAULT
        {       
                if( trick_hc ) {
-                       IncStat(ts_ackreason[_ACK_USRRCV_]);
-                       return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
+                       SeqNum ack_thresh;
+                       /*
+                        * If the upper window edge has advanced a reasonable
+                        * amount beyond what was known, send an ACK.
+                        * A reasonable amount is 2 packets, unless the max window
+                        * is only 1 or 2 packets, in which case we
+                        * should send an ack for any advance in the upper window edge.
+                        */
+                       LOCAL_CREDIT($P);
+                       ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
+                                                                        ($P.tp_maxlcredit > 2 ? 2 : 1));
+                       if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
+                               IncStat(ts_ackreason[_ACK_USRRCV_]);
+                               $P.tp_flags &= ~TPF_DELACK;
+                               return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
+                       }
                }
        }
 ;
                }
        }
 ;