home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp.trans < prev    next >
Encoding:
Text File  |  1991-05-07  |  36.7 KB  |  1,413 lines

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