home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 April / macformat-049.iso / mac / Shareware Plus / Developers / dropg++ / usr / include / netiso / tp.trans < prev    next >
Encoding:
Text File  |  1997-02-20  |  34.6 KB  |  1,343 lines  |  [TEXT/R*ch]

  1. /* NEW */
  2. /*-
  3.  * Copyright (c) 1991, 1993
  4.  *    The Regents of the University of California.  All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  *    @(#)tp.trans    8.1 (Berkeley) 6/10/93
  35.  */
  36.  
  37. /***********************************************************
  38.         Copyright IBM Corporation 1987
  39.  
  40.                       All Rights Reserved
  41.  
  42. Permission to use, copy, modify, and distribute this software and its 
  43. documentation for any purpose and without fee is hereby granted, 
  44. provided that the above copyright notice appear in all copies and that
  45. both that copyright notice and this permission notice appear in 
  46. supporting documentation, and that the name of IBM not be
  47. used in advertising or publicity pertaining to distribution of the
  48. software without specific, written prior permission.  
  49.  
  50. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  51. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  52. IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  53. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  54. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  55. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  56. SOFTWARE.
  57.  
  58. ******************************************************************/
  59.  
  60. /*
  61.  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
  62.  */
  63. /* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $
  64.  *
  65.  * Transition file for TP.
  66.  *
  67.  * DO NOT:
  68.  * - change the order of any of the events or states.  to do so will
  69.  *   make tppt, netstat, etc. cease working.
  70.  *
  71.  * NOTE:
  72.  * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED***
  73.  * (read: may not work!)
  74.  *
  75.  * I tried to put everything that causes a change of state in here, hence 
  76.  * there are some seemingly trivial events  like T_DETACH and T_LISTEN_req.
  77.  *
  78.  * Almost everything having to do w/ setting & cancelling timers is here
  79.  * but once it was debugged, I moved the setting of the 
  80.  * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent.
  81.  * This is so the code wouldn't be duplicated all over creation in here.
  82.  *
  83.  */
  84. *PROTOCOL tp
  85.  
  86. *INCLUDE
  87. {
  88. /* @(#)tp.trans    8.1 (Berkeley) 6/10/93 */
  89. #include <sys/param.h>
  90. #include <sys/systm.h>
  91. #include <sys/socket.h>
  92. #include <sys/socketvar.h>
  93. #include <sys/protosw.h>
  94. #include <sys/mbuf.h>
  95. #include <sys/time.h>
  96. #include <sys/errno.h>
  97.  
  98. #include <netiso/tp_param.h>
  99. #include <netiso/tp_stat.h>
  100. #include <netiso/tp_pcb.h>
  101. #include <netiso/tp_tpdu.h>
  102. #include <netiso/argo_debug.h>
  103. #include <netiso/tp_trace.h>
  104. #include <netiso/iso_errno.h>
  105. #include <netiso/tp_seq.h>
  106. #include <netiso/cons.h>
  107.  
  108. #define DRIVERTRACE TPPTdriver
  109. #define sbwakeup(sb)    sowakeup(p->tp_sock, sb);
  110. #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
  111.  
  112. static     trick_hc = 1;
  113.  
  114. int     tp_emit(),
  115.         tp_goodack(),                tp_goodXack(),
  116.         tp_stash()
  117. ;
  118. void    tp_indicate(),                tp_getoptions(),    
  119.         tp_soisdisconnecting(),     tp_soisdisconnected(),
  120.         tp_recycle_tsuffix(),        
  121. #ifdef TP_DEBUG_TIMERS
  122.         tp_etimeout(),                tp_euntimeout(),
  123.         tp_ctimeout(),                tp_cuntimeout(),
  124.         tp_ctimeout_MIN(),
  125. #endif
  126.         tp_freeref(),                tp_detach(),
  127.         tp0_stash(),                 tp0_send(),
  128.         tp_netcmd(),                tp_send()
  129. ;
  130.  
  131. typedef  struct tp_pcb tpcb_struct;
  132.  
  133.  
  134. }
  135.  
  136. *PCB    tpcb_struct     SYNONYM  P
  137.  
  138. *STATES
  139.  
  140. TP_CLOSED     
  141. TP_CRSENT
  142. TP_AKWAIT
  143. TP_OPEN
  144. TP_CLOSING 
  145. TP_REFWAIT
  146. TP_LISTENING    /* Local to this implementation */
  147. TP_CONFIRMING    /* Local to this implementation */
  148.  
  149. *EVENTS        { struct timeval e_time; }         SYNONYM  E
  150.  
  151.  /*
  152.   * C (typically cancelled) timers  - 
  153.   *
  154.   * let these be the first ones so for the sake of convenience
  155.   * their values are 0--> n-1
  156.   * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! 
  157.   */
  158.  TM_inact        
  159.  TM_retrans        
  160.                 /* TM_retrans is used for all 
  161.                  * simple retransmissions - CR,CC,XPD,DR 
  162.                  */
  163.  
  164.  TM_sendack        
  165.                 /* TM_sendack does dual duty - keepalive AND closed-window
  166.                  * Probes.
  167.                  * It's set w/ keepalive-ticks every time an ack is sent.
  168.                  * (this is done in (void) tp_emit() ).
  169.                  * Whenever a DT arrives which doesn't require immediate acking,
  170.                  * a separate fast-timeout flag is set ensuring 200ms response.
  171.                  */
  172.  TM_notused    
  173.  
  174.  /* 
  175.   * E (typically expired) timers - these may be in any order. 
  176.   * These cause procedures to be executed directly; may not
  177.   * cause an 'event' as we know them here.
  178.   */
  179.  TM_reference        { SeqNum e_low; SeqNum e_high; int e_retrans; }
  180.  TM_data_retrans    { SeqNum e_low; SeqNum e_high; int e_retrans; }
  181.  
  182. /* NOTE: in tp_input is a minor optimization that assumes that
  183.  * for all tpdu types that can take e_data and e_datalen, these
  184.  * fields fall in the same place in the event structure, that is,
  185.  * e_data is the first field and e_datalen is the 2nd field.
  186.  */
  187.  
  188.  ER_TPDU           {
  189.                   u_char        e_reason;
  190.                 }
  191.  CR_TPDU           { struct mbuf     *e_data;    /* first field */
  192.                   int             e_datalen; /* 2nd field */
  193.                   u_int            e_cdt;
  194.                 }
  195.  DR_TPDU            { struct mbuf     *e_data;    /* first field */
  196.                   int             e_datalen; /* 2nd field */
  197.                   u_short        e_sref;
  198.                   u_char        e_reason;
  199.                 }
  200.  DC_TPDU        
  201.  CC_TPDU            { struct mbuf     *e_data;    /* first field */
  202.                   int             e_datalen; /* 2nd field */
  203.                   u_short        e_sref;
  204.                   u_int            e_cdt;
  205.                 }
  206.  AK_TPDU        { u_int            e_cdt;    
  207.                   SeqNum          e_seq;        
  208.                   SeqNum          e_subseq;        
  209.                   u_char          e_fcc_present;        
  210.                 }
  211.  DT_TPDU        { struct mbuf    *e_data;     /* first field */
  212.                   int             e_datalen; /* 2nd field */
  213.                   u_int         e_eot;
  214.                   SeqNum        e_seq; 
  215.                 }
  216.  XPD_TPDU        { struct mbuf     *e_data;    /* first field */
  217.                   int             e_datalen;     /* 2nd field */
  218.                   SeqNum         e_seq;    
  219.                 }
  220.  XAK_TPDU        { SeqNum         e_seq;        }
  221.  
  222.  T_CONN_req 
  223.  T_DISC_req        { u_char        e_reason;     }
  224.  T_LISTEN_req
  225.  T_DATA_req
  226.  T_XPD_req    
  227.  T_USR_rcvd    
  228.  T_USR_Xrcvd    
  229.  T_DETACH
  230.  T_NETRESET
  231.  T_ACPT_req
  232.  
  233.  
  234. *TRANSITIONS
  235.  
  236.  
  237. /* TP_AKWAIT doesn't exist in TP 0 */
  238. SAME            <==            TP_AKWAIT            [ CC_TPDU, DC_TPDU, XAK_TPDU ]
  239.     DEFAULT
  240.     NULLACTION
  241. ;
  242.  
  243.  
  244. /* applicable in TP4, TP0 */
  245. SAME            <==            TP_REFWAIT                                DR_TPDU
  246.     ( $$.e_sref !=  0 ) 
  247.     {
  248.         (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
  249.     }
  250. ;
  251.     
  252. /* applicable in TP4, TP0 */
  253. SAME            <==            TP_REFWAIT            [ CR_TPDU, CC_TPDU, DT_TPDU, 
  254.                     DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ]
  255.     DEFAULT
  256.     {
  257. #        ifdef TP_DEBUG
  258.         if( $E.ev_number != AK_TPDU )
  259.             printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number);
  260. #        endif TP_DEBUG
  261.     }
  262. ;
  263.  
  264. /* applicable in TP4, TP0 */
  265. SAME            <==            TP_REFWAIT                [ T_DETACH, T_DISC_req ]
  266.     DEFAULT
  267.     NULLACTION
  268. ;
  269.  
  270. /* applicable in TP4, TP0 */
  271. SAME            <==            TP_CRSENT                                 AK_TPDU
  272.     ($P.tp_class == TP_CLASS_0)
  273.     {
  274.         /* oh, man is this grotesque or what? */
  275.         (void) tp_goodack($P, $$.e_cdt, $$.e_seq,  $$.e_subseq);
  276.         /* but it's necessary because this pseudo-ack may happen
  277.          * before the CC arrives, but we HAVE to adjust the
  278.          * snduna as a result of the ack, WHENEVER it arrives
  279.          */
  280.     }
  281. ;
  282.  
  283. /* applicable in TP4, TP0 */
  284. SAME            <==            TP_CRSENT    
  285.                     [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU,  XAK_TPDU ]
  286.     DEFAULT
  287.     NULLACTION
  288. ;
  289.  
  290. /* applicable in TP4, TP0 */
  291. SAME            <==            TP_CLOSED                    [ DT_TPDU, XPD_TPDU,
  292.                                         ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 
  293.     DEFAULT
  294.     NULLACTION
  295. ;
  296.  
  297. /* TP_CLOSING doesn't exist in TP 0 */
  298. SAME             <==         TP_CLOSING
  299.                     [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ]
  300.     DEFAULT
  301.     NULLACTION
  302. ;
  303.  
  304.  
  305. /* DC_TPDU doesn't exist in TP 0 */
  306. SAME            <==            TP_OPEN                          DC_TPDU
  307.     DEFAULT
  308.     NULLACTION
  309. ;
  310.  
  311. /* applicable in TP4, TP0 */
  312. SAME            <==             TP_LISTENING  [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU,
  313.                                          ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] 
  314.     DEFAULT    
  315.     NULLACTION
  316. ;
  317.  
  318. /* applicable in TP4, TP0 */
  319. TP_LISTENING    <==            TP_CLOSED                              T_LISTEN_req 
  320.     DEFAULT
  321.     NULLACTION
  322. ;
  323.  
  324. /* applicable in TP4, TP0 */
  325. TP_CLOSED          <==         [ TP_LISTENING, TP_CLOSED ]             T_DETACH
  326.     DEFAULT
  327.     {
  328.         tp_detach($P);
  329.     }
  330. ;
  331.  
  332. TP_CONFIRMING    <==         TP_LISTENING                                  CR_TPDU 
  333.     ( $P.tp_class == TP_CLASS_0)
  334.     {
  335.         $P.tp_refstate = REF_OPEN; /* has timers ??? */
  336.     }
  337. ;
  338.  
  339. TP_CONFIRMING        <==         TP_LISTENING                              CR_TPDU 
  340.     DEFAULT
  341.     {
  342.         IFTRACE(D_CONN)
  343.             tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0);
  344.         ENDTRACE
  345.         IFDEBUG(D_CONN)
  346.             printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data);
  347.         ENDDEBUG
  348.         $P.tp_refstate = REF_OPEN; /* has timers */
  349.         $P.tp_fcredit = $$.e_cdt;
  350.  
  351.         if ($$.e_datalen > 0) {
  352.             /* n/a for class 0 */
  353.             ASSERT($P.tp_Xrcv.sb_cc == 0); 
  354.             sbappendrecord(&$P.tp_Xrcv, $$.e_data);
  355.             $$.e_data = MNULL; 
  356.         } 
  357.     }
  358. ;
  359.  
  360. TP_OPEN        <==         TP_CONFIRMING                                  T_ACPT_req 
  361.     ( $P.tp_class == TP_CLASS_0 )
  362.     {
  363.         IncStat(ts_tp0_conn);
  364.         IFTRACE(D_CONN)
  365.             tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
  366.         ENDTRACE
  367.         IFDEBUG(D_CONN)
  368.             printf("Confirming connection: $P" );
  369.         ENDDEBUG
  370.         soisconnected($P.tp_sock);
  371.         (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ;
  372.         $P.tp_fcredit = 1;
  373.     }
  374. ;
  375.  
  376. TP_AKWAIT        <==         TP_CONFIRMING                              T_ACPT_req
  377.     (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0)
  378.     {
  379.         IncStat(ts_tp4_conn); /* even though not quite open */
  380.         IFTRACE(D_CONN)
  381.             tptrace(TPPTmisc, "Confiming", $P, 0,0,0);
  382.         ENDTRACE
  383.         IFDEBUG(D_CONN)
  384.             printf("Confirming connection: $P" );
  385.         ENDDEBUG
  386.         tp_getoptions($P);
  387.         soisconnecting($P.tp_sock);
  388.         if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0))
  389.             $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize;
  390.         $P.tp_retrans = $P.tp_Nretrans;
  391.         tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
  392.     }
  393. ;
  394.  
  395. /* TP4 only */
  396. TP_CLOSED        <==         TP_CONFIRMING                                T_ACPT_req
  397.     DEFAULT /* emit failed */
  398.     {
  399.         IFDEBUG(D_CONN)
  400.             printf("event: CR_TPDU emit CC failed done " );
  401.         ENDDEBUG
  402.         soisdisconnected($P.tp_sock);
  403.         tp_recycle_tsuffix($P);
  404.         tp_freeref($P.tp_lref);
  405.         tp_detach($P);
  406.     }
  407. ;
  408.  
  409. /* applicable in TP4, TP0 */
  410. TP_CRSENT        <==        TP_CLOSED                                T_CONN_req 
  411.     DEFAULT
  412.     {
  413.         int error;
  414.         struct mbuf *data = MNULL;
  415.  
  416.         IFTRACE(D_CONN)
  417.             tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags,
  418.             $P.tp_ucddata, 0, 0);
  419.         ENDTRACE
  420.         data =  MCPY($P.tp_ucddata, M_WAIT);
  421.         if (data) {
  422.             IFDEBUG(D_CONN)
  423.                 printf("T_CONN_req.trans m_copy cc 0x%x\n", 
  424.                     $P.tp_ucddata);
  425.                 dump_mbuf(data, "sosnd @ T_CONN_req");
  426.             ENDDEBUG
  427.         }
  428.  
  429.         if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) )
  430.             return error; /* driver WON'T change state; will return error */
  431.         
  432.         $P.tp_refstate = REF_OPEN; /* has timers */
  433.         if($P.tp_class != TP_CLASS_0) {
  434.             $P.tp_retrans = $P.tp_Nretrans;
  435.             tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
  436.         }
  437.     }
  438. ;
  439.  
  440. /* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */
  441. TP_REFWAIT         <==        [ TP_CRSENT, TP_AKWAIT, TP_OPEN ]             DR_TPDU 
  442.     DEFAULT
  443.     {
  444.         sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */
  445.         if ($$.e_datalen > 0) {
  446.             sbappendrecord(&$P.tp_Xrcv, $$.e_data);
  447.             $$.e_data = MNULL;
  448.         } 
  449.         if ($P.tp_state == TP_OPEN)
  450.             tp_indicate(T_DISCONNECT, $P, 0);
  451.         else {
  452.             int so_error = ECONNREFUSED;
  453.             if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
  454.                 $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
  455.                 $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
  456.                 so_error = ECONNABORTED;
  457.             tp_indicate(T_DISCONNECT, $P, so_error);
  458.         }
  459.         tp_soisdisconnected($P);
  460.         if ($P.tp_class != TP_CLASS_0) {
  461.             if ($P.tp_state == TP_OPEN ) {
  462.                 tp_euntimeout($P, TM_data_retrans); /* all */
  463.                 tp_cuntimeout($P, TM_retrans);
  464.                 tp_cuntimeout($P, TM_inact);
  465.                 tp_cuntimeout($P, TM_sendack);
  466.                 $P.tp_flags &= ~TPF_DELACK;
  467.             }
  468.             tp_cuntimeout($P, TM_retrans);
  469.             if( $$.e_sref !=  0 ) 
  470.                 (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL);
  471.         }
  472.     }
  473. ;
  474.  
  475. SAME             <==        TP_CLOSED                                     DR_TPDU 
  476.     DEFAULT
  477.     {
  478.         if( $$.e_sref != 0 )
  479.             (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); 
  480.         /* reference timer already set - reset it to be safe (???) */
  481.         tp_euntimeout($P, TM_reference); /* all */
  482.         tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
  483.     }
  484. ;
  485.  
  486. /* NBS(34) */
  487. TP_REFWAIT         <==      TP_CRSENT                                      ER_TPDU
  488.     DEFAULT
  489.     {    
  490.         tp_cuntimeout($P, TM_retrans);
  491.         tp_indicate(ER_TPDU, $P, $$.e_reason);
  492.         tp_soisdisconnected($P);
  493.     }
  494. ;
  495.  
  496. /* NBS(27) */
  497. TP_REFWAIT        <==        TP_CLOSING                                    DR_TPDU
  498.     DEFAULT
  499.     {     
  500.         tp_cuntimeout($P, TM_retrans);
  501.         tp_soisdisconnected($P);
  502.     }
  503. ;
  504. /* these two transitions are the same but can't be combined because xebec
  505.  * can't handle the use of $$.e_reason if they're combined
  506.  */
  507. /* NBS(27) */
  508. TP_REFWAIT        <==        TP_CLOSING                                    ER_TPDU
  509.     DEFAULT
  510.     {     
  511.         tp_indicate(ER_TPDU, $P, $$.e_reason);
  512.         tp_cuntimeout($P, TM_retrans);
  513.         tp_soisdisconnected($P);
  514.     }
  515. ;
  516. /* NBS(27) */
  517. TP_REFWAIT        <==        TP_CLOSING                                    DC_TPDU 
  518.     DEFAULT
  519.     {     
  520.         tp_cuntimeout($P, TM_retrans);
  521.         tp_soisdisconnected($P);
  522.     }
  523. ;
  524.  
  525. /* NBS(21) */
  526. SAME             <==     TP_CLOSED                         [ CC_TPDU, CR_TPDU ]
  527.     DEFAULT
  528.     {    /* don't ask me why we have to do this - spec says so */
  529.         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL);
  530.         /* don't bother with retransmissions of the DR */
  531.     }
  532. ;
  533.  
  534. /* NBS(34) */
  535. TP_REFWAIT         <==     TP_OPEN                                       ER_TPDU
  536.     ($P.tp_class == TP_CLASS_0)
  537.     {
  538.         tp_soisdisconnecting($P.tp_sock);
  539.         tp_indicate(ER_TPDU, $P, $$.e_reason);
  540.         tp_soisdisconnected($P);
  541.         tp_netcmd( $P, CONN_CLOSE );
  542.     }
  543. ;
  544.  
  545. TP_CLOSING         <==     [ TP_AKWAIT, TP_OPEN ]                      ER_TPDU
  546.     DEFAULT
  547.     {
  548.         if ($P.tp_state == TP_OPEN) {
  549.             tp_euntimeout($P, TM_data_retrans); /* all */
  550.             tp_cuntimeout($P, TM_inact);
  551.             tp_cuntimeout($P, TM_sendack);
  552.         }
  553.         tp_soisdisconnecting($P.tp_sock);
  554.         tp_indicate(ER_TPDU, $P, $$.e_reason);
  555.         $P.tp_retrans = $P.tp_Nretrans;
  556.         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  557.         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL);
  558.     }
  559. ;
  560. /* NBS(6) */
  561. TP_OPEN            <==        TP_CRSENT                                    CC_TPDU 
  562.     ($P.tp_class == TP_CLASS_0) 
  563.     {    
  564.         tp_cuntimeout($P, TM_retrans);
  565.         IncStat(ts_tp0_conn);
  566.         $P.tp_fcredit = 1;
  567.         soisconnected($P.tp_sock);
  568.     }
  569. ;
  570.  
  571. TP_OPEN            <==        TP_CRSENT                                    CC_TPDU 
  572.     DEFAULT
  573.     {    
  574.         IFDEBUG(D_CONN)
  575.             printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 
  576.                 (int)$P.tp_flags);
  577.         ENDDEBUG
  578.         IncStat(ts_tp4_conn);
  579.         $P.tp_fref = $$.e_sref;
  580.         $P.tp_fcredit = $$.e_cdt;
  581.         if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0))
  582.             $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize;
  583.         tp_getoptions($P);
  584.         tp_cuntimeout($P, TM_retrans);
  585.         if ($P.tp_ucddata) {
  586.             IFDEBUG(D_CONN)
  587.                 printf("dropping user connect data cc 0x%x\n",
  588.                     $P.tp_ucddata->m_len);
  589.             ENDDEBUG
  590.             m_freem($P.tp_ucddata);
  591.             $P.tp_ucddata = 0;
  592.         }
  593.         soisconnected($P.tp_sock);
  594.         if ($$.e_datalen > 0) {
  595.             ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */
  596.             sbappendrecord(&$P.tp_Xrcv, $$.e_data);
  597.             $$.e_data = MNULL;
  598.         }
  599.  
  600.         (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
  601.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  602.     }
  603. ;
  604.  
  605. /* TP4 only */
  606. SAME            <==        TP_CRSENT                                    TM_retrans 
  607.     (    $P.tp_retrans > 0 )
  608.     {
  609.         struct mbuf *data = MNULL;
  610.         int error;
  611.  
  612.         IncStat(ts_retrans_cr);
  613.         $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
  614.         data = MCPY($P.tp_ucddata, M_NOWAIT);
  615.         if($P.tp_ucddata) {
  616.             IFDEBUG(D_CONN)
  617.                 printf("TM_retrans.trans m_copy cc 0x%x\n", data);
  618.                 dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans");
  619.             ENDDEBUG
  620.             if( data == MNULL )
  621.                 return ENOBUFS;
  622.         }
  623.  
  624.         $P.tp_retrans --;
  625.         if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) {
  626.             $P.tp_sock->so_error = error;
  627.         }
  628.         tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks);
  629.     }
  630. ;
  631.  
  632. /* TP4 only  */
  633. TP_REFWAIT        <==        TP_CRSENT                                    TM_retrans 
  634.     DEFAULT /* no more CR retransmissions */
  635.     {     
  636.         IncStat(ts_conn_gaveup);
  637.         $P.tp_sock->so_error = ETIMEDOUT;
  638.         tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
  639.         tp_soisdisconnected($P);
  640.     }
  641. ;
  642.  
  643. /* TP4 only */
  644. SAME             <==     TP_AKWAIT                                            CR_TPDU 
  645.     DEFAULT
  646.     /* duplicate CR (which doesn't really exist in the context of
  647.      * a connectionless network layer) 
  648.      * Doesn't occur in class 0.
  649.      */
  650.     {    
  651.         int error;
  652.         struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
  653.  
  654.         if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) {
  655.             $P.tp_sock->so_error = error;
  656.         }
  657.         $P.tp_retrans = $P.tp_Nretrans;
  658.         tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
  659.     }
  660. ;
  661.  
  662. /* TP4 only */
  663. TP_OPEN            <==        TP_AKWAIT                                         DT_TPDU 
  664.     ( IN_RWINDOW( $P, $$.e_seq,
  665.                     $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
  666.     {
  667.         int doack;
  668.  
  669.         /*
  670.          * Get rid of any confirm or connect data, so that if we
  671.          * crash or close, it isn't thought of as disconnect data.
  672.          */
  673.         if ($P.tp_ucddata) {
  674.             m_freem($P.tp_ucddata);
  675.             $P.tp_ucddata = 0;
  676.         }
  677.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  678.         tp_cuntimeout($P, TM_retrans);
  679.         soisconnected($P.tp_sock);
  680.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  681.  
  682.         /* see also next 2 transitions, if you make any changes */
  683.  
  684.         doack = tp_stash($P, $E);
  685.         IFDEBUG(D_DATA)
  686.             printf("tp_stash returns %d\n",doack);
  687.         ENDDEBUG
  688.  
  689.         if (doack) {
  690.             (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
  691.             tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
  692.         } else
  693.             tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks);
  694.         
  695.         IFDEBUG(D_DATA)
  696.             printf("after stash calling sbwakeup\n");
  697.         ENDDEBUG
  698.     }
  699. ;
  700.  
  701. SAME            <==        TP_OPEN                                     DT_TPDU 
  702.     ( $P.tp_class == TP_CLASS_0 )
  703.     {
  704.         tp0_stash($P, $E);
  705.         sbwakeup( &$P.tp_sock->so_rcv );
  706.  
  707.         IFDEBUG(D_DATA)
  708.             printf("after stash calling sbwakeup\n");
  709.         ENDDEBUG
  710.     }
  711. ;
  712.  
  713. /* TP4 only */
  714. SAME            <==        TP_OPEN                                     DT_TPDU 
  715.     ( IN_RWINDOW( $P, $$.e_seq,
  716.                     $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) )
  717.     {
  718.         int doack; /* tells if we must ack immediately */
  719.  
  720.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  721.         sbwakeup( &$P.tp_sock->so_rcv );
  722.  
  723.         doack = tp_stash($P, $E);
  724.         IFDEBUG(D_DATA)
  725.             printf("tp_stash returns %d\n",doack);
  726.         ENDDEBUG
  727.  
  728.         if(doack)
  729.             (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
  730.         else
  731.             tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks);
  732.         
  733.         IFDEBUG(D_DATA)
  734.             printf("after stash calling sbwakeup\n");
  735.         ENDDEBUG
  736.     }
  737. ;
  738.  
  739. /* Not in window  - we must ack under certain circumstances, namely
  740.  * a) if the seq number is below lwe but > lwe - (max credit ever given)
  741.  * (to handle lost acks) Can use max-possible-credit for this ^^^.
  742.  * and 
  743.  * b) seq number is > uwe but < uwe + previously sent & withdrawn credit
  744.  *
  745.  * (see 12.2.3.8.1 of ISO spec, p. 73)
  746.  * We just always ack.
  747.  */
  748. /* TP4 only */
  749. SAME             <==     [ TP_OPEN, TP_AKWAIT ]                            DT_TPDU
  750.     DEFAULT /* Not in window */
  751.     {     
  752.         IFTRACE(D_DATA)
  753.             tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
  754.                 $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0);
  755.         ENDTRACE
  756.         IncStat(ts_dt_niw);
  757.         m_freem($$.e_data);
  758.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  759.         (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); 
  760.     }
  761. ;
  762.  
  763. /* TP4 only */
  764. TP_OPEN            <==        TP_AKWAIT                                        AK_TPDU
  765.     DEFAULT
  766.     {
  767.         if ($P.tp_ucddata) {
  768.             m_freem($P.tp_ucddata);
  769.             $P.tp_ucddata = 0;
  770.         }
  771.         (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq);
  772.         tp_cuntimeout($P, TM_retrans);
  773.  
  774.         soisconnected($P.tp_sock);
  775.         IFTRACE(D_CONN)
  776.             struct socket *so = $P.tp_sock;
  777.             tptrace(TPPTmisc, 
  778.             "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
  779.                 so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
  780.             tptrace(TPPTmisc, 
  781.             "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
  782.                 so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
  783.         ENDTRACE
  784.  
  785.         tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
  786.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  787.     }
  788. ;
  789.  
  790. /* TP4 only */
  791. TP_OPEN         <==     [ TP_OPEN, TP_AKWAIT ]                        XPD_TPDU
  792.     ($P.tp_Xrcvnxt == $$.e_seq)
  793.     {
  794.         if( $P.tp_state == TP_AKWAIT ) {
  795.             if ($P.tp_ucddata) {
  796.                 m_freem($P.tp_ucddata);
  797.                 $P.tp_ucddata = 0;
  798.             }
  799.             tp_cuntimeout($P, TM_retrans);
  800.             soisconnected($P.tp_sock);
  801.             tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks);
  802.             tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  803.         } 
  804.         IFTRACE(D_XPD)
  805.         tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
  806.                 $P.tp_Xrcvnxt,$$.e_seq,  $$.e_datalen, $$.e_data->m_len);
  807.         ENDTRACE
  808.  
  809.         $P.tp_sock->so_state |= SS_RCVATMARK;
  810.         $$.e_data->m_flags |= M_EOR;
  811.         sbinsertoob(&$P.tp_Xrcv, $$.e_data);
  812.         IFDEBUG(D_XPD)
  813.             dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv");
  814.         ENDDEBUG
  815.         tp_indicate(T_XDATA, $P, 0);
  816.         sbwakeup( &$P.tp_Xrcv );
  817.  
  818.         (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
  819.         SEQ_INC($P, $P.tp_Xrcvnxt);
  820.     }
  821. ;
  822.  
  823. /* TP4 only */
  824. SAME            <==        TP_OPEN                                     T_USR_Xrcvd
  825.     DEFAULT
  826.     {
  827.         if( $P.tp_Xrcv.sb_cc == 0 ) {
  828.             /* kludge for select(): */ 
  829.             /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */
  830.         }
  831.     }
  832.     /* OLD WAY:
  833.      * Ack only after the user receives the XPD.  This is better for 
  834.      * users that use one XPD right after another.
  835.      * Acking right away (the NEW WAY, see the prev. transition) is 
  836.      * better for occasional * XPD, when the receiving user doesn't 
  837.      * want to read the XPD immediately (which is session's behavior).
  838.      *
  839.         int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL);
  840.         SEQ_INC($P, $P.tp_Xrcvnxt);
  841.         return error;
  842.     */
  843. ;
  844.  
  845. /* NOTE: presently if the user doesn't read the connection data
  846.  * before and expedited data PDU comes in, the connection data will
  847.  * be dropped. This is a bug.  To avoid it, we need somewhere else
  848.  * to put the connection data.
  849.  * On the other hand, we need not to have it sitting around forever.
  850.  * This is a problem with the idea of trying to accommodate
  851.  * data on connect w/ a passive-open user interface. 
  852.  */
  853. /* TP4 only */
  854.  
  855. SAME             <==     [ TP_AKWAIT, TP_OPEN ]                             XPD_TPDU
  856.     DEFAULT /* not in window or cdt==0 */
  857.     {
  858.         IFTRACE(D_XPD)
  859.             tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
  860.                 $P.tp_Xrcvnxt, $$.e_seq,  $P.tp_Xrcv.sb_cc , 0);
  861.         ENDTRACE
  862.         if( $P.tp_Xrcvnxt != $$.e_seq )
  863.             IncStat(ts_xpd_niw);
  864.         if( $P.tp_Xrcv.sb_cc ) {
  865.             /* might as well kick 'em again */
  866.             tp_indicate(T_XDATA, $P, 0);
  867.             IncStat(ts_xpd_dup);
  868.         }
  869.         m_freem($$.e_data);
  870.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  871.         /* don't send an xack because the xak gives "last one received", not
  872.          * "next one i expect" (dumb)
  873.          */
  874.     }
  875. ;
  876.  
  877. /* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries
  878.  * to detach all its "children"
  879.  * Also (CRSENT) when user kills a job that's doing a connect()
  880.  */
  881. TP_REFWAIT        <==     TP_CRSENT                                         T_DETACH
  882.     ($P.tp_class == TP_CLASS_0)
  883.     {
  884.         struct socket *so = $P.tp_sock;
  885.  
  886.         /* detach from parent socket so it can finish closing */
  887.         if (so->so_head) {
  888.             if (!soqremque(so, 0) && !soqremque(so, 1))
  889.                 panic("tp: T_DETACH");
  890.             so->so_head = 0;
  891.         }
  892.         tp_soisdisconnecting($P.tp_sock);
  893.         tp_netcmd( $P, CONN_CLOSE);
  894.         tp_soisdisconnected($P);
  895.     }
  896. ;
  897.  
  898. /* TP4 only */
  899. TP_CLOSING        <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ]    T_DETACH
  900.     DEFAULT
  901.     {
  902.         struct socket *so = $P.tp_sock;
  903.         struct mbuf *data = MNULL;
  904.  
  905.         /* detach from parent socket so it can finish closing */
  906.         if (so->so_head) {
  907.             if (!soqremque(so, 0) && !soqremque(so, 1))
  908.                 panic("tp: T_DETACH");
  909.             so->so_head = 0;
  910.         }
  911.         if ($P.tp_state != TP_CLOSING) {
  912.             tp_soisdisconnecting($P.tp_sock);
  913.             data = MCPY($P.tp_ucddata, M_NOWAIT);
  914.             (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data);
  915.             $P.tp_retrans = $P.tp_Nretrans;
  916.             tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  917.         }
  918.     }
  919. ;
  920.  
  921. TP_REFWAIT        <==        [ TP_OPEN, TP_CRSENT ]                           T_DISC_req
  922.     ( $P.tp_class == TP_CLASS_0 )
  923.     {
  924.         tp_soisdisconnecting($P.tp_sock);
  925.         tp_netcmd( $P, CONN_CLOSE);
  926.         tp_soisdisconnected($P);
  927.     }
  928. ;
  929.  
  930. /* TP4 only */
  931. TP_CLOSING        <==    [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ]  T_DISC_req
  932.     DEFAULT
  933.     {
  934.         struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
  935.  
  936.         if($P.tp_state == TP_OPEN) {
  937.             tp_euntimeout($P, TM_data_retrans); /* all */
  938.             tp_cuntimeout($P, TM_inact);
  939.             tp_cuntimeout($P, TM_sendack);
  940.             $P.tp_flags &= ~TPF_DELACK;
  941.         }
  942.         if (data) {
  943.             IFDEBUG(D_CONN)
  944.                 printf("T_DISC_req.trans tp_ucddata 0x%x\n", 
  945.                     $P.tp_ucddata);
  946.                 dump_mbuf(data, "ucddata @ T_DISC_req");
  947.             ENDDEBUG
  948.         }
  949.         tp_soisdisconnecting($P.tp_sock);
  950.         $P.tp_retrans = $P.tp_Nretrans;
  951.         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  952.  
  953.         if( trick_hc )
  954.             return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data);
  955.     }
  956. ;
  957.  
  958. /* TP4 only */
  959. SAME            <==        TP_AKWAIT                                    TM_retrans
  960.     ( $P.tp_retrans > 0 )
  961.     {
  962.         int error;
  963.         struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT);
  964.  
  965.         IncStat(ts_retrans_cc);
  966.         $P.tp_retrans --;
  967.         $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
  968.  
  969.         if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) 
  970.             $P.tp_sock->so_error = error;
  971.         tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks);
  972.     }
  973. ;
  974.  
  975. /* TP4 only */
  976. TP_CLOSING        <==        TP_AKWAIT                                    TM_retrans
  977.     DEFAULT  /* out of time */
  978.     {
  979.         IncStat(ts_conn_gaveup);
  980.         tp_soisdisconnecting($P.tp_sock);
  981.         $P.tp_sock->so_error = ETIMEDOUT;
  982.         tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
  983.         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL);
  984.         $P.tp_retrans = $P.tp_Nretrans;
  985.         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  986.     }
  987. ;
  988.  
  989. /* the retrans timers had better go off BEFORE the inactivity timer does,
  990.  * if transmissions are going on.
  991.  * (i.e., TM_inact should be greater than timer for all retrans plus ack
  992.  * turnaround)
  993.  */
  994. /* TP4 only */
  995. TP_CLOSING         <==        TP_OPEN           [ TM_inact, TM_retrans, TM_data_retrans ]
  996.     DEFAULT
  997.     {
  998.         tp_euntimeout($P, TM_data_retrans); /* all */
  999.         tp_cuntimeout($P, TM_inact); 
  1000.         tp_cuntimeout($P, TM_sendack);
  1001.  
  1002.         IncStat(ts_conn_gaveup);
  1003.         tp_soisdisconnecting($P.tp_sock);
  1004.         $P.tp_sock->so_error = ETIMEDOUT;
  1005.         tp_indicate(T_DISCONNECT, $P, ETIMEDOUT);
  1006.         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL);
  1007.         $P.tp_retrans = $P.tp_Nretrans;
  1008.         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  1009.     }
  1010. ;
  1011.  
  1012. /* TP4 only */
  1013. SAME            <==        TP_OPEN                                        TM_retrans
  1014.     ( $P.tp_retrans > 0 )
  1015.     {
  1016.         $P.tp_cong_win = 1 * $P.tp_l_tpdusize;
  1017.         /* resume XPD */
  1018.         if    ( $P.tp_Xsnd.sb_mb )  {
  1019.             struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
  1020.             int shift;
  1021.  
  1022.             IFTRACE(D_XPD)
  1023.                 tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
  1024.                     $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 
  1025.                     $P.tp_snduna); 
  1026.             ENDTRACE
  1027.             IFDEBUG(D_XPD)
  1028.                 dump_mbuf(m, "XPD retrans emitting M");
  1029.             ENDDEBUG
  1030.             IncStat(ts_retrans_xpd);
  1031.             $P.tp_retrans --;
  1032.             shift = max($P.tp_Nretrans - $P.tp_retrans, 6);
  1033.             (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
  1034.             tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift);
  1035.         }
  1036.     }
  1037. ;
  1038.  
  1039. /* TP4 only */
  1040. SAME             <==        TP_OPEN                                    TM_data_retrans
  1041.     ($P.tp_rxtshift < TP_NRETRANS)
  1042.     {    
  1043.         $P.tp_rxtshift++;
  1044.         (void) tp_data_retrans($P);
  1045.     }
  1046. ;
  1047.  
  1048. /* TP4 only */
  1049. SAME             <==        TP_CLOSING                                    TM_retrans
  1050.     (    $P.tp_retrans > 0 )
  1051.     {    
  1052.         $P.tp_retrans --;
  1053.         (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL);
  1054.         IncStat(ts_retrans_dr);
  1055.         tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks);
  1056.     }
  1057. ;
  1058.  
  1059. /* TP4 only */
  1060. TP_REFWAIT         <==        TP_CLOSING                                    TM_retrans
  1061.     DEFAULT    /* no more retrans - gave up */
  1062.     {    
  1063.         $P.tp_sock->so_error = ETIMEDOUT;
  1064.         $P.tp_refstate = REF_FROZEN;
  1065.         tp_recycle_tsuffix( $P );
  1066.         tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks);
  1067.     }
  1068. ;
  1069.  
  1070. /*
  1071.  * The resources are kept around until the ref timer goes off.
  1072.  * The suffices are wiped out sooner so they can be reused right away.
  1073.  */
  1074. /* applicable in TP4, TP0 */
  1075. TP_CLOSED         <==        TP_REFWAIT                                     TM_reference
  1076.     DEFAULT
  1077.     {
  1078.         tp_freeref($P.tp_lref);
  1079.         tp_detach($P);
  1080.     }
  1081. ;
  1082.  
  1083. /* applicable in TP4, TP0 */
  1084. /* A duplicate CR from connectionless network layer can't happen */
  1085. SAME             <==     TP_OPEN                             [ CR_TPDU, CC_TPDU ]
  1086.     DEFAULT
  1087.     {    
  1088.         if( $P.tp_class != TP_CLASS_0) {
  1089.             tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  1090.             if ( $E.ev_number == CC_TPDU )
  1091.                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); 
  1092.         }
  1093.         /* ignore it if class 0 - state tables are blank for this */
  1094.     }
  1095. ;
  1096.  
  1097. /* applicable in TP4, TP0 */
  1098. SAME            <==     TP_OPEN                                    T_DATA_req
  1099.     DEFAULT
  1100.     {
  1101.         IFTRACE(D_DATA)
  1102.             tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
  1103.                 $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P);
  1104.         ENDTRACE
  1105.  
  1106.         tp_send($P);
  1107.     }
  1108. ;
  1109.  
  1110. /* TP4 only */
  1111. SAME            <==        TP_OPEN                                        T_XPD_req
  1112.     DEFAULT
  1113.         /* T_XPD_req was issued by sosend iff xpd socket buf was empty
  1114.          * at time of sosend(), 
  1115.          * AND (which means) there were no unacknowledged XPD tpdus outstanding!
  1116.          */
  1117.     {
  1118.         int error = 0;
  1119.  
  1120.         /* resume XPD */
  1121.         if    ( $P.tp_Xsnd.sb_mb )  {
  1122.             struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc);
  1123.             /* m_copy doesn't preserve the m_xlink field, but at this pt.
  1124.              * that doesn't matter
  1125.              */
  1126.  
  1127.             IFTRACE(D_XPD)
  1128.                 tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
  1129.                     $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, 
  1130.                     $P.tp_snduna); 
  1131.             ENDTRACE
  1132.             IFDEBUG(D_XPD)
  1133.                 printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc);
  1134.                 dump_mbuf(m, "XPD req emitting M");
  1135.             ENDDEBUG
  1136.             error = 
  1137.                 tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
  1138.             $P.tp_retrans = $P.tp_Nretrans;
  1139.  
  1140.             tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur);
  1141.             SEQ_INC($P, $P.tp_Xsndnxt);
  1142.         } 
  1143.         if(trick_hc)
  1144.             return error;
  1145.     }
  1146. ;
  1147.  
  1148. /* TP4, faked ack in TP0 when cons send completes */
  1149. SAME             <==        TP_OPEN                                     AK_TPDU
  1150.     ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq)  )
  1151.  
  1152.     /* tp_goodack == true means 
  1153.      * EITHER it actually acked something heretofore unacknowledged
  1154.      * OR no news but the credit should be processed.
  1155.      */
  1156.     {
  1157.         struct sockbuf *sb = &$P.tp_sock->so_snd;
  1158.  
  1159.         IFDEBUG(D_ACKRECV)
  1160.             printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt);
  1161.         ENDDEBUG
  1162.         if( $P.tp_class != TP_CLASS_0) {
  1163.             tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  1164.         }
  1165.         sbwakeup(sb);
  1166.         IFDEBUG(D_ACKRECV)
  1167.             printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt);
  1168.         ENDDEBUG
  1169.     }
  1170. ;
  1171.  
  1172. /* TP4, and TP0 after sending a CC or possibly a CR */
  1173. SAME            <==        TP_OPEN                                       AK_TPDU
  1174.     DEFAULT
  1175.     {
  1176.         IFTRACE(D_ACKRECV)
  1177.             tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 
  1178.                 $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0);
  1179.         ENDTRACE
  1180.         if( $P.tp_class != TP_CLASS_0 ) {
  1181.  
  1182.             if ( !$$.e_fcc_present ) {
  1183.                 /* send ACK with FCC */
  1184.                 IncStat( ts_ackreason[_ACK_FCC_] );
  1185.                 (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL);
  1186.             }
  1187.             tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  1188.         } 
  1189.     }
  1190. ;
  1191.  
  1192. /* NBS(47) */
  1193.     /* goes in at *** */
  1194.         /* just so happens that this is never true now, because we allow
  1195.          * only 1 packet in the queue at once (this could be changed)
  1196.         if    ( $P.tp_Xsnd.sb_mb )  {
  1197.             struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??);
  1198.  
  1199.             (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m);
  1200.             $P.tp_retrans = $P.tp_Nretrans;
  1201.             tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks);
  1202.             SEQ_INC($P, $P.tp_Xsndnxt);
  1203.         }
  1204.          */
  1205.     /* end of the above hack */
  1206.  
  1207. /* TP4 only */
  1208. SAME            <==     TP_OPEN                                        XAK_TPDU
  1209.     ( tp_goodXack($P, $$.e_seq) )
  1210.     /* tp_goodXack checks for good ack, removes the correct 
  1211.      * tpdu from the queue and  returns 1 if ack was legit, 0 if not.
  1212.      * also updates tp_Xuna
  1213.      */
  1214.     {    
  1215.         tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  1216.         tp_cuntimeout($P, TM_retrans);
  1217.  
  1218.         sbwakeup( &$P.tp_sock->so_snd );
  1219.  
  1220.         /* resume normal data */
  1221.         tp_send($P);
  1222.     }
  1223. ;
  1224.  
  1225. /* TP4, and TP0 after sending a CC or possibly a CR */
  1226. SAME            <==        TP_OPEN                                      XAK_TPDU
  1227.     DEFAULT
  1228.     {
  1229.         IFTRACE(D_ACKRECV)
  1230.             tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0);
  1231.         ENDTRACE
  1232.         if( $P.tp_class != TP_CLASS_0 ) {
  1233.             tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks);
  1234.         } 
  1235.     }
  1236. ;
  1237.  
  1238. /* TP4 only */
  1239. SAME            <==        TP_OPEN                                 TM_sendack 
  1240.     DEFAULT
  1241.     {    
  1242.         int timo;
  1243.         IFTRACE(D_TIMER)
  1244.             tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, 
  1245.             $P.tp_sent_lcdt, 0);
  1246.         ENDTRACE
  1247.         IncPStat($P, tps_n_TMsendack);
  1248.         (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
  1249.         if ($P.tp_fcredit == 0) {
  1250.             if ($P.tp_rxtshift < TP_MAXRXTSHIFT)
  1251.                 $P.tp_rxtshift++;
  1252.             timo = ($P.tp_dt_ticks) << $P.tp_rxtshift;
  1253.         } else
  1254.             timo = $P.tp_sendack_ticks;
  1255.         tp_ctimeout($P, TM_sendack, timo);
  1256.     }
  1257. ;
  1258.  
  1259. /* TP0 only */
  1260. SAME            <==        TP_OPEN                                     T_USR_rcvd
  1261.     ($P.tp_class == TP_CLASS_0)
  1262.     {
  1263.         if (sbspace(&$P.tp_sock->so_rcv) > 0)
  1264.             tp0_openflow($P);
  1265.     }
  1266. ;
  1267.  
  1268. /* TP4 only */
  1269.         /* If old credit was zero, 
  1270.          * we'd better inform other side that we now have space
  1271.          * But this is not enough.  Sender might not yet have
  1272.          * seen an ack with cdt 0 but it might still think the
  1273.          * window is closed, so it's going to wait.
  1274.          * Best to send an ack each time.
  1275.          * Strictly speaking, this ought to be a function of the
  1276.          * general ack strategy.
  1277.          */
  1278. SAME            <==        TP_OPEN                                     T_USR_rcvd
  1279.     DEFAULT
  1280.     {    
  1281.         if( trick_hc ) {
  1282.             SeqNum ack_thresh;
  1283.             /*
  1284.              * If the upper window edge has advanced a reasonable
  1285.              * amount beyond what was known, send an ACK.
  1286.              * A reasonable amount is 2 packets, unless the max window
  1287.              * is only 1 or 2 packets, in which case we
  1288.              * should send an ack for any advance in the upper window edge.
  1289.              */
  1290.             LOCAL_CREDIT($P);
  1291.             ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt,
  1292.                                      ($P.tp_maxlcredit > 2 ? 2 : 1));
  1293.             if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) {
  1294.                 IncStat(ts_ackreason[_ACK_USRRCV_]);
  1295.                 $P.tp_flags &= ~TPF_DELACK;
  1296.                 return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL);
  1297.             }
  1298.         }
  1299.     }
  1300. ;
  1301.  
  1302. /* applicable in TP4, TP0 */
  1303. SAME            <==        TP_REFWAIT                 [ T_USR_rcvd, T_USR_Xrcvd ]
  1304.     DEFAULT
  1305.     /* This happens if other end sent a DR when  the user was waiting 
  1306.      * on a receive.  
  1307.      * Processing the DR includes putting us in REFWAIT state.
  1308.      */
  1309.     {
  1310.         if(trick_hc)
  1311.         return ECONNABORTED;
  1312.     }
  1313. ;
  1314.  
  1315. /* TP0 only */
  1316. TP_REFWAIT        <==        [ TP_OPEN, TP_CRSENT, TP_LISTENING ]     T_NETRESET
  1317.     ( $P.tp_class != TP_CLASS_4 ) 
  1318.         /* 0 or (4 and 0) */
  1319.         /* in OPEN class will be 0 or 4 but not both */
  1320.         /* in CRSENT or LISTENING it could be in negotiation, hence both */
  1321.         /* Actually, this shouldn't ever happen in LISTENING */
  1322.     {
  1323.         ASSERT( $P.tp_state != TP_LISTENING );
  1324.         tp_indicate(T_DISCONNECT, $P, ECONNRESET);
  1325.         tp_soisdisconnected($P);
  1326.     }
  1327. ;
  1328.  
  1329. /* TP4: ignore resets */
  1330. SAME        <==        [ TP_OPEN, TP_CRSENT, TP_AKWAIT,
  1331.                         TP_CLOSING, TP_LISTENING ]                 T_NETRESET
  1332.     DEFAULT
  1333.     NULLACTION
  1334. ;
  1335.  
  1336. /* applicable in TP4, TP0 */
  1337. SAME            <==        [ TP_CLOSED, TP_REFWAIT ]                T_NETRESET
  1338.     DEFAULT
  1339.     NULLACTION
  1340. ;
  1341.  
  1342. /* C'EST TOUT */
  1343.