home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp_driver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-02  |  27.2 KB  |  1,071 lines

  1. /* $Header$ */
  2. /* $Source$ */
  3. #ifndef lint
  4. static char *rcsid = "$Header/**/$";
  5. #endif lint
  6. #define _XEBEC_PG static
  7.  
  8. #include "tp_states.h"
  9.  
  10. static struct act_ent {
  11.     int a_newstate;
  12.     int a_action;
  13. } statetable[] = { {0,0},
  14. #include "tp_states.init"
  15. };
  16.  
  17. /*    %W% (Berkeley) %G% */
  18. #include "param.h"
  19. #include "socket.h"
  20. #include "socketvar.h"
  21. #include "protosw.h"
  22. #include "mbuf.h"
  23. #include "time.h"
  24. #include "errno.h"
  25. #include "../netiso/tp_param.h"
  26. #include "../netiso/tp_stat.h"
  27. #include "../netiso/tp_pcb.h"
  28. #include "../netiso/tp_tpdu.h"
  29. #include "../netiso/argo_debug.h"
  30. #include "../netiso/tp_trace.h"
  31. #include "../netiso/iso_errno.h"
  32. #include "../netiso/tp_seq.h"
  33. #include "../netiso/cons.h"
  34.  
  35. #define DRIVERTRACE TPPTdriver
  36. #define sbwakeup(sb)    sowakeup(p->tp_sock, sb);
  37. #define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
  38.  
  39. static     trick_hc = 1;
  40.  
  41. int     tp_emit(),
  42.         tp_goodack(),                tp_goodXack(),
  43.         tp_stash()
  44. ;
  45. void    tp_indicate(),                tp_getoptions(),    
  46.         tp_soisdisconnecting(),     tp_soisdisconnected(),
  47.         tp_recycle_tsuffix(),        
  48.         tp_etimeout(),                tp_euntimeout(),
  49.         tp_euntimeout_lss(),        tp_ctimeout(),
  50.         tp_cuntimeout(),            tp_ctimeout_MIN(),
  51.         tp_freeref(),                tp_detach(),
  52.         tp0_stash(),                 tp0_send(),
  53.         tp_netcmd(),                tp_send()
  54. ;
  55.  
  56. typedef  struct tp_pcb tpcb_struct;
  57.  
  58.  
  59.  
  60. typedef tpcb_struct tp_PCB_;
  61.  
  62. #include "tp_events.h"
  63.  
  64. _XEBEC_PG int _Xebec_action(a,e,p)
  65. int a;
  66. struct tp_event *e;
  67. tp_PCB_ *p;
  68. {
  69. switch(a) {
  70. case -1:  return tp_protocol_error(e,p);
  71. case 0x1: 
  72.         {
  73.         (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
  74.     }
  75.          break;
  76. case 0x2: 
  77.         {
  78. #        ifdef TP_DEBUG
  79.         if( e->ev_number != AK_TPDU )
  80.             printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number);
  81. #        endif TP_DEBUG
  82.     }
  83.          break;
  84. case 0x3: 
  85.         {
  86.         /* oh, man is this grotesque or what? */
  87.         (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq,  e->ev_union.EV_AK_TPDU.e_subseq);
  88.         /* but it's necessary because this pseudo-ack may happen
  89.          * before the CC arrives, but we HAVE to adjust the
  90.          * snduna as a result of the ack, WHENEVER it arrives
  91.          */
  92.     }
  93.          break;
  94. case 0x4: 
  95.         {
  96.         tp_detach(p);
  97.     }
  98.          break;
  99. case 0x5: 
  100.         {
  101.         p->tp_refp->tpr_state = REF_OPEN; /* has timers ??? */
  102.     }
  103.          break;
  104. case 0x6: 
  105.         {
  106.         IFTRACE(D_CONN)
  107.             tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0);
  108.         ENDTRACE
  109.         IFDEBUG(D_CONN)
  110.             printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data);
  111.         ENDDEBUG
  112.         p->tp_refp->tpr_state = REF_OPEN; /* has timers */
  113.         p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt;
  114.  
  115.         if (e->ev_union.EV_CR_TPDU.e_datalen > 0) {
  116.             /* n/a for class 0 */
  117.             ASSERT(p->tp_Xrcv.sb_cc == 0); 
  118.             sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data);
  119.             e->ev_union.EV_CR_TPDU.e_data = MNULL; 
  120.         } 
  121.     }
  122.          break;
  123. case 0x7: 
  124.         {
  125.         IncStat(ts_tp0_conn);
  126.         IFTRACE(D_CONN)
  127.             tptrace(TPPTmisc, "Confiming", p, 0,0,0);
  128.         ENDTRACE
  129.         IFDEBUG(D_CONN)
  130.             printf("Confirming connection: p" );
  131.         ENDDEBUG
  132.         soisconnected(p->tp_sock);
  133.         (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ;
  134.         p->tp_fcredit = 1;
  135.     }
  136.          break;
  137. case 0x8: 
  138.         {
  139.         IncStat(ts_tp4_conn); /* even though not quite open */
  140.         IFTRACE(D_CONN)
  141.             tptrace(TPPTmisc, "Confiming", p, 0,0,0);
  142.         ENDTRACE
  143.         IFDEBUG(D_CONN)
  144.             printf("Confirming connection: p" );
  145.         ENDDEBUG
  146.         soisconnecting(p->tp_sock);
  147.         if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0))
  148.             p->tp_cong_win = p->tp_fcredit;
  149.         p->tp_retrans = p->tp_Nretrans;
  150.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_cc_ticks);
  151.     }
  152.          break;
  153. case 0x9: 
  154.         {
  155.         register struct tp_ref *r = p->tp_refp;
  156.  
  157.         IFDEBUG(D_CONN)
  158.             printf("event: CR_TPDU emit CC failed done " );
  159.         ENDDEBUG
  160.         soisdisconnected(p->tp_sock);
  161.         tp_recycle_tsuffix( p );
  162.         tp_freeref(r);
  163.         tp_detach(p);
  164.     }
  165.          break;
  166. case 0xa: 
  167.         {
  168.         int error;
  169.         struct mbuf *data = MNULL;
  170.  
  171.         IFTRACE(D_CONN)
  172.             tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags,
  173.             p->tp_ucddata, 0, 0);
  174.         ENDTRACE
  175.         data =  MCPY(p->tp_ucddata, M_WAIT);
  176.         if (data) {
  177.             IFDEBUG(D_CONN)
  178.                 printf("T_CONN_req.trans m_copy cc 0x%x\n", 
  179.                     p->tp_ucddata);
  180.                 dump_mbuf(data, "sosnd @ T_CONN_req");
  181.             ENDDEBUG
  182.         }
  183.  
  184.         if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) )
  185.             return error; /* driver WON'T change state; will return error */
  186.         
  187.         p->tp_refp->tpr_state = REF_OPEN; /* has timers */
  188.         if(p->tp_class != TP_CLASS_0) {
  189.             p->tp_retrans = p->tp_Nretrans;
  190.             tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_cr_ticks);
  191.         }
  192.     }
  193.          break;
  194. case 0xb: 
  195.         {
  196.         sbflush(&p->tp_Xrcv); /* purge non-delivered data data */
  197.         if (e->ev_union.EV_DR_TPDU.e_datalen > 0) {
  198.             sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data);
  199.             e->ev_union.EV_DR_TPDU.e_data = MNULL;
  200.         } 
  201.         /* must return no error, or disc data and reason can't be read */
  202.         tp_indicate(T_DISCONNECT, p, 0);
  203.         tp_soisdisconnected(p);
  204.         if (p->tp_class != TP_CLASS_0) {
  205.             if (p->tp_state == TP_OPEN ) {
  206.                 tp_euntimeout(p->tp_refp, TM_data_retrans); /* all */
  207.                 tp_cuntimeout(p->tp_refp, TM_retrans);
  208.                 tp_cuntimeout(p->tp_refp, TM_inact);
  209.                 tp_cuntimeout(p->tp_refp, TM_sendack);
  210.             }
  211.             tp_cuntimeout(p->tp_refp, TM_retrans);
  212.             if( e->ev_union.EV_DR_TPDU.e_sref !=  0 ) 
  213.                 (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
  214.         }
  215.     }
  216.          break;
  217. case 0xc: 
  218.         {
  219.         if( e->ev_union.EV_DR_TPDU.e_sref != 0 )
  220.             (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); 
  221.         /* reference timer already set - reset it to be safe (???) */
  222.         tp_euntimeout(p->tp_refp, TM_reference); /* all */
  223.         tp_etimeout(p->tp_refp, TM_reference, 0, 0, 0, (int)p->tp_refer_ticks);
  224.     }
  225.          break;
  226. case 0xd: 
  227.         {    
  228.         tp_cuntimeout(p->tp_refp, TM_retrans);
  229.         tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
  230.         tp_soisdisconnected(p);
  231.     }
  232.          break;
  233. case 0xe: 
  234.         {     
  235.         tp_cuntimeout(p->tp_refp, TM_retrans);
  236.         tp_soisdisconnected(p);
  237.     }
  238.          break;
  239. case 0xf: 
  240.         {     
  241.         tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
  242.         tp_cuntimeout(p->tp_refp, TM_retrans);
  243.         tp_soisdisconnected(p);
  244.     }
  245.          break;
  246. case 0x10: 
  247.         {     
  248.         tp_cuntimeout(p->tp_refp, TM_retrans);
  249.         tp_soisdisconnected(p);
  250.     }
  251.          break;
  252. case 0x11: 
  253.         {    /* don't ask me why we have to do this - spec says so */
  254.         (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL);
  255.         /* don't bother with retransmissions of the DR */
  256.     }
  257.          break;
  258. case 0x12: 
  259.         {
  260.         tp_soisdisconnecting(p->tp_sock);
  261.         tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
  262.         tp_soisdisconnected(p);
  263.         tp_netcmd( p, CONN_CLOSE );
  264.     }
  265.          break;
  266. case 0x13: 
  267.         {
  268.         if (p->tp_state == TP_OPEN) {
  269.             tp_euntimeout(p->tp_refp, TM_data_retrans); /* all */
  270.             tp_cuntimeout(p->tp_refp, TM_inact);
  271.             tp_cuntimeout(p->tp_refp, TM_sendack);
  272.         }
  273.         tp_soisdisconnecting(p->tp_sock);
  274.         tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
  275.         p->tp_retrans = p->tp_Nretrans;
  276.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  277.         (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL);
  278.     }
  279.          break;
  280. case 0x14: 
  281.         {    
  282.         tp_cuntimeout(p->tp_refp, TM_retrans);
  283.         IncStat(ts_tp0_conn);
  284.         p->tp_fcredit = 1;
  285.         soisconnected(p->tp_sock);
  286.     }
  287.          break;
  288. case 0x15: 
  289.         {    
  290.         IFDEBUG(D_CONN)
  291.             printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", 
  292.                 (int)p->tp_flags);
  293.         ENDDEBUG
  294.         IncStat(ts_tp4_conn);
  295.         p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref;
  296.         p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt;
  297.         p->tp_ackrcvd = 0;
  298.         if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0))
  299.             p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt;
  300.         tp_getoptions(p);
  301.         tp_cuntimeout(p->tp_refp, TM_retrans);
  302.         if (p->tp_ucddata) {
  303.             IFDEBUG(D_CONN)
  304.                 printf("dropping user connect data cc 0x%x\n",
  305.                     p->tp_ucddata->m_len);
  306.             ENDDEBUG
  307.             m_freem(p->tp_ucddata);
  308.             p->tp_ucddata = 0;
  309.         }
  310.         soisconnected(p->tp_sock);
  311.         if (e->ev_union.EV_CC_TPDU.e_datalen > 0) {
  312.             ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */
  313.             sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data);
  314.             e->ev_union.EV_CC_TPDU.e_data = MNULL;
  315.         }
  316.  
  317.         (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
  318.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  319.     }
  320.          break;
  321. case 0x16: 
  322.         {
  323.         struct mbuf *data = MNULL;
  324.         int error;
  325.  
  326.         IncStat(ts_retrans_cr);
  327.         p->tp_cong_win = 1;
  328.         p->tp_ackrcvd = 0;
  329.         data = MCPY(p->tp_ucddata, M_NOWAIT);
  330.         if(p->tp_ucddata) {
  331.             IFDEBUG(D_CONN)
  332.                 printf("TM_retrans.trans m_copy cc 0x%x\n", data);
  333.                 dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans");
  334.             ENDDEBUG
  335.             if( data == MNULL )
  336.                 return ENOBUFS;
  337.         }
  338.  
  339.         p->tp_retrans --;
  340.         if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) {
  341.             p->tp_sock->so_error = error;
  342.         }
  343.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_cr_ticks);
  344.     }
  345.          break;
  346. case 0x17: 
  347.         {     
  348.         IncStat(ts_conn_gaveup);
  349.         p->tp_sock->so_error = ETIMEDOUT;
  350.         tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
  351.         tp_soisdisconnected(p);
  352.     }
  353.          break;
  354. case 0x18: 
  355.         {    
  356.         int error;
  357.         struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
  358.  
  359.         if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) {
  360.             p->tp_sock->so_error = error;
  361.         }
  362.         p->tp_retrans = p->tp_Nretrans;
  363.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_cc_ticks);
  364.     }
  365.          break;
  366. case 0x19: 
  367.         {
  368.         int doack;
  369.  
  370.         /*
  371.          * Get rid of any confirm or connect data, so that if we
  372.          * crash or close, it isn't thought of as disconnect data.
  373.          */
  374.         if (p->tp_ucddata) {
  375.             m_freem(p->tp_ucddata);
  376.             p->tp_ucddata = 0;
  377.         }
  378.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  379.         tp_cuntimeout(p->tp_refp, TM_retrans);
  380.         soisconnected(p->tp_sock);
  381.         tp_getoptions(p);
  382.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  383.  
  384.         /* see also next 2 transitions, if you make any changes */
  385.  
  386.         doack = tp_stash(p, e);
  387.         IFDEBUG(D_DATA)
  388.             printf("tp_stash returns %d\n",doack);
  389.         ENDDEBUG
  390.  
  391.         if(doack) {
  392.             (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); 
  393.             tp_ctimeout(p->tp_refp, TM_sendack, (int)p->tp_keepalive_ticks);
  394.         } else
  395.             tp_ctimeout( p->tp_refp, TM_sendack, (int)p->tp_sendack_ticks);
  396.         
  397.         IFDEBUG(D_DATA)
  398.             printf("after stash calling sbwakeup\n");
  399.         ENDDEBUG
  400.     }
  401.          break;
  402. case 0x1a: 
  403.         {
  404.         tp0_stash(p, e);
  405.         sbwakeup( &p->tp_sock->so_rcv );
  406.  
  407.         IFDEBUG(D_DATA)
  408.             printf("after stash calling sbwakeup\n");
  409.         ENDDEBUG
  410.     }
  411.          break;
  412. case 0x1b: 
  413.         {
  414.         int doack; /* tells if we must ack immediately */
  415.  
  416.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  417.         sbwakeup( &p->tp_sock->so_rcv );
  418.  
  419.         doack = tp_stash(p, e);
  420.         IFDEBUG(D_DATA)
  421.             printf("tp_stash returns %d\n",doack);
  422.         ENDDEBUG
  423.  
  424.         if(doack)
  425.             (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); 
  426.         else
  427.             tp_ctimeout_MIN( p->tp_refp, TM_sendack, (int)p->tp_sendack_ticks);
  428.         
  429.         IFDEBUG(D_DATA)
  430.             printf("after stash calling sbwakeup\n");
  431.         ENDDEBUG
  432.     }
  433.          break;
  434. case 0x1c: 
  435.         {     
  436.         IFTRACE(D_DATA)
  437.             tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
  438.                 e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0);
  439.         ENDTRACE
  440.         IncStat(ts_dt_niw);
  441.         m_freem(e->ev_union.EV_DT_TPDU.e_data);
  442.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  443.         (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); 
  444.     }
  445.          break;
  446. case 0x1d: 
  447.         {
  448.         if (p->tp_ucddata) {
  449.             m_freem(p->tp_ucddata);
  450.             p->tp_ucddata = 0;
  451.         }
  452.         (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq);
  453.         tp_cuntimeout(p->tp_refp, TM_retrans);
  454.  
  455.         tp_getoptions(p);
  456.         soisconnected(p->tp_sock);
  457.         IFTRACE(D_CONN)
  458.             struct socket *so = p->tp_sock;
  459.             tptrace(TPPTmisc, 
  460.             "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
  461.                 so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
  462.             tptrace(TPPTmisc, 
  463.             "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
  464.                 so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
  465.         ENDTRACE
  466.  
  467.         tp_ctimeout(p->tp_refp, TM_sendack, (int)p->tp_keepalive_ticks);
  468.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  469.     }
  470.          break;
  471. case 0x1e: 
  472.         {
  473.         if( p->tp_state == TP_AKWAIT ) {
  474.             if (p->tp_ucddata) {
  475.                 m_freem(p->tp_ucddata);
  476.                 p->tp_ucddata = 0;
  477.             }
  478.             tp_cuntimeout(p->tp_refp, TM_retrans);
  479.             tp_getoptions(p);
  480.             soisconnected(p->tp_sock);
  481.             tp_ctimeout(p->tp_refp, TM_sendack, (int)p->tp_keepalive_ticks);
  482.             tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  483.         } 
  484.         IFTRACE(D_XPD)
  485.         tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
  486.                 p->tp_Xrcvnxt,e->ev_union.EV_XPD_TPDU.e_seq,  e->ev_union.EV_XPD_TPDU.e_datalen, e->ev_union.EV_XPD_TPDU.e_data->m_len);
  487.         ENDTRACE
  488.  
  489.         p->tp_sock->so_state |= SS_RCVATMARK;
  490.         e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR;
  491.         sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data);
  492.         IFDEBUG(D_XPD)
  493.             dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv");
  494.         ENDDEBUG
  495.         tp_indicate(T_XDATA, p, 0);
  496.         sbwakeup( &p->tp_Xrcv );
  497.  
  498.         (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL);
  499.         SEQ_INC(p, p->tp_Xrcvnxt);
  500.     }
  501.          break;
  502. case 0x1f: 
  503.         {
  504.         if( p->tp_Xrcv.sb_cc == 0 ) {
  505.             /* kludge for select(): */ 
  506.             /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */
  507.         }
  508.     }
  509.          break;
  510. case 0x20: 
  511.         {
  512.         IFTRACE(D_XPD)
  513.             tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
  514.                 p->tp_Xrcvnxt, e->ev_union.EV_XPD_TPDU.e_seq,  p->tp_Xrcv.sb_cc , 0);
  515.         ENDTRACE
  516.         if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq )
  517.             IncStat(ts_xpd_niw);
  518.         if( p->tp_Xrcv.sb_cc ) {
  519.             /* might as well kick 'em again */
  520.             tp_indicate(T_XDATA, p, 0);
  521.             IncStat(ts_xpd_dup);
  522.         }
  523.         m_freem(e->ev_union.EV_XPD_TPDU.e_data);
  524.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  525.         /* don't send an xack because the xak gives "last one received", not
  526.          * "next one i expect" (dumb)
  527.          */
  528.     }
  529.          break;
  530. case 0x21: 
  531.         {
  532.         struct socket *so = p->tp_sock;
  533.  
  534.         /* detach from parent socket so it can finish closing */
  535.         if (so->so_head) {
  536.             if (!soqremque(so, 0) && !soqremque(so, 1))
  537.                 panic("tp: T_DETACH");
  538.             so->so_head = 0;
  539.         }
  540.         tp_soisdisconnecting(p->tp_sock);
  541.         tp_netcmd( p, CONN_CLOSE);
  542.         tp_soisdisconnected(p);
  543.     }
  544.          break;
  545. case 0x22: 
  546.         {
  547.         struct socket *so = p->tp_sock;
  548.         struct mbuf *data = MNULL;
  549.  
  550.         /* detach from parent socket so it can finish closing */
  551.         if (so->so_head) {
  552.             if (!soqremque(so, 0) && !soqremque(so, 1))
  553.                 panic("tp: T_DETACH");
  554.             so->so_head = 0;
  555.         }
  556.         if (p->tp_state != TP_CLOSING) {
  557.             tp_soisdisconnecting(p->tp_sock);
  558.             data = MCPY(p->tp_ucddata, M_NOWAIT);
  559.             (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NORMAL_DISC, data);
  560.             p->tp_retrans = p->tp_Nretrans;
  561.             tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  562.         }
  563.     }
  564.          break;
  565. case 0x23: 
  566.         {
  567.         tp_soisdisconnecting(p->tp_sock);
  568.         tp_netcmd( p, CONN_CLOSE);
  569.         tp_soisdisconnected(p);
  570.     }
  571.          break;
  572. case 0x24: 
  573.         {
  574.         struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
  575.  
  576.         if(p->tp_state == TP_OPEN) {
  577.             tp_euntimeout(p->tp_refp, TM_data_retrans); /* all */
  578.             tp_cuntimeout(p->tp_refp, TM_inact);
  579.             tp_cuntimeout(p->tp_refp, TM_sendack);
  580.         }
  581.         if (data) {
  582.             IFDEBUG(D_CONN)
  583.                 printf("T_DISC_req.trans tp_ucddata 0x%x\n", 
  584.                     p->tp_ucddata);
  585.                 dump_mbuf(data, "ucddata @ T_DISC_req");
  586.             ENDDEBUG
  587.         }
  588.         tp_soisdisconnecting(p->tp_sock);
  589.         p->tp_retrans = p->tp_Nretrans;
  590.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  591.  
  592.         if( trick_hc )
  593.             return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data);
  594.     }
  595.          break;
  596. case 0x25: 
  597.         {
  598.         int error;
  599.         struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
  600.  
  601.         IncStat(ts_retrans_cc);
  602.         p->tp_retrans --;
  603.         p->tp_cong_win = 1;
  604.         p->tp_ackrcvd = 0;
  605.  
  606.         if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) 
  607.             p->tp_sock->so_error = error;
  608.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_cc_ticks);
  609.     }
  610.          break;
  611. case 0x26: 
  612.         {
  613.         IncStat(ts_conn_gaveup);
  614.         tp_soisdisconnecting(p->tp_sock);
  615.         p->tp_sock->so_error = ETIMEDOUT;
  616.         tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
  617.         (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST, MNULL);
  618.         p->tp_retrans = p->tp_Nretrans;
  619.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  620.     }
  621.          break;
  622. case 0x27: 
  623.         {
  624.         tp_euntimeout(p->tp_refp, TM_data_retrans); /* all */
  625.         tp_cuntimeout(p->tp_refp, TM_inact); 
  626.         tp_cuntimeout(p->tp_refp, TM_sendack);
  627.  
  628.         IncStat(ts_conn_gaveup);
  629.         tp_soisdisconnecting(p->tp_sock);
  630.         p->tp_sock->so_error = ETIMEDOUT;
  631.         tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
  632.         (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST_2, MNULL);
  633.         p->tp_retrans = p->tp_Nretrans;
  634.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  635.     }
  636.          break;
  637. case 0x28: 
  638.         {
  639.         p->tp_cong_win = 1;
  640.         p->tp_ackrcvd = 0;
  641.         /* resume XPD */
  642.         if    ( p->tp_Xsnd.sb_mb )  {
  643.             struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc);
  644.             /* m_copy doesn't preserve the m_xlink field, but at this pt.
  645.              * that doesn't matter
  646.              */
  647.  
  648.             IFTRACE(D_XPD)
  649.                 tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndhiwat snduna",
  650.                     p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndhiwat, 
  651.                     p->tp_snduna); 
  652.             ENDTRACE
  653.             IFDEBUG(D_XPD)
  654.                 dump_mbuf(m, "XPD retrans emitting M");
  655.             ENDDEBUG
  656.             IncStat(ts_retrans_xpd);
  657.             p->tp_retrans --;
  658.             (void) tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m);
  659.             tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_xpd_ticks);
  660.         }
  661.     }
  662.          break;
  663. case 0x29: 
  664.         {    
  665.         register     SeqNum            low, lowsave = 0;
  666.         register    struct tp_rtc     *r = p->tp_snduna_rtc;
  667.         register    struct mbuf     *m;
  668.         register    SeqNum            high = e->ev_union.EV_TM_data_retrans.e_high;
  669.  
  670.         low = p->tp_snduna;
  671.         lowsave = high = low;
  672.  
  673.         tp_euntimeout_lss(p->tp_refp, TM_data_retrans,
  674.             SEQ_ADD(p, p->tp_sndhiwat, 1));
  675.         p->tp_retrans_hiwat = p->tp_sndhiwat;
  676.  
  677.         if ((p->tp_rx_strat & TPRX_EACH) == 0)
  678.             high = (high>low)?low:high;
  679.  
  680.         if( p->tp_rx_strat & TPRX_USE_CW ) {
  681.             register int i;
  682.  
  683.             p->tp_cong_win = 1;
  684.             p->tp_ackrcvd = 0;
  685.             i = SEQ_ADD(p, low, p->tp_cong_win);
  686.  
  687.             high = SEQ_MIN(p, high, p->tp_sndhiwat);
  688.  
  689.         }
  690.  
  691.         while( SEQ_LEQ(p, low, high) ){
  692.             if ( r == (struct tp_rtc *)0 ){
  693.                 IFDEBUG(D_RTC)
  694.                     printf( "tp: retrans rtc list is GONE!\n");
  695.                 ENDDEBUG
  696.                 break;
  697.             }
  698.             if ( r->tprt_seq == low ){
  699.                 if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))== MNULL)
  700.                     break;
  701.                 (void) tp_emit(DT_TPDU_type, p, low, r->tprt_eot, m);
  702.                 IncStat(ts_retrans_dt);
  703.                 SEQ_INC(p, low );
  704.             }
  705.             r = r->tprt_next;
  706.         }
  707. /* CE_BIT
  708.         if ( SEQ_LEQ(p, lowsave, high) ){
  709. */
  710.             e->ev_union.EV_TM_data_retrans.e_retrans --;
  711.             tp_etimeout(p->tp_refp, TM_data_retrans, (caddr_t)lowsave,
  712.                     (caddr_t)high, e->ev_union.EV_TM_data_retrans.e_retrans,
  713.                     (p->tp_Nretrans - e->ev_union.EV_TM_data_retrans.e_retrans) * (int)p->tp_dt_ticks);
  714. /* CE_BIT
  715.         }
  716. */
  717.     }
  718.          break;
  719. case 0x2a: 
  720.         {    
  721.         p->tp_retrans --;
  722.         (void) tp_emit(DR_TPDU_type, p, 0, E_TP_DR_NO_REAS, MNULL);
  723.         IncStat(ts_retrans_dr);
  724.         tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_dr_ticks);
  725.     }
  726.          break;
  727. case 0x2b: 
  728.         {    
  729.         p->tp_sock->so_error = ETIMEDOUT;
  730.         p->tp_refp->tpr_state = REF_FROZEN;
  731.         tp_recycle_tsuffix( p );
  732.         tp_etimeout(p->tp_refp, TM_reference, 0,0,0, (int)p->tp_refer_ticks);
  733.     }
  734.          break;
  735. case 0x2c: 
  736.         {
  737.         tp_freeref(p->tp_refp);
  738.         tp_detach(p);
  739.     }
  740.          break;
  741. case 0x2d: 
  742.         {    
  743.         if( p->tp_class != TP_CLASS_0) {
  744.             tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  745.             if ( e->ev_number == CC_TPDU )
  746.                 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); 
  747.         }
  748.         /* ignore it if class 0 - state tables are blank for this */
  749.     }
  750.          break;
  751. case 0x2e: 
  752.         {
  753.         IFTRACE(D_DATA)
  754.             tptrace(TPPTmisc, "T_DATA_req sndhiwat snduna fcredit, tpcb",
  755.                 p->tp_sndhiwat, p->tp_snduna, p->tp_fcredit, p);
  756.         ENDTRACE
  757.  
  758.         tp_send(p);
  759.     }
  760.          break;
  761. case 0x2f: 
  762.         {
  763.         int error = 0;
  764.  
  765.         /* resume XPD */
  766.         if    ( p->tp_Xsnd.sb_mb )  {
  767.             struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc);
  768.             /* m_copy doesn't preserve the m_xlink field, but at this pt.
  769.              * that doesn't matter
  770.              */
  771.  
  772.             IFTRACE(D_XPD)
  773.                 tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndhiwat snduna",
  774.                     p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndhiwat, 
  775.                     p->tp_snduna); 
  776.             ENDTRACE
  777.             IFDEBUG(D_XPD)
  778.                 printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc);
  779.                 dump_mbuf(m, "XPD req emitting M");
  780.             ENDDEBUG
  781.             error = 
  782.                 tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m);
  783.             p->tp_retrans = p->tp_Nretrans;
  784.             tp_ctimeout(p->tp_refp, TM_retrans, (int)p->tp_xpd_ticks);
  785.             SEQ_INC(p, p->tp_Xsndnxt);
  786.         } 
  787.         if(trick_hc)
  788.             return error;
  789.     }
  790.          break;
  791. case 0x30: 
  792.         {
  793.         IFDEBUG(D_ACKRECV)
  794.             printf("GOOD ACK seq 0x%x cdt 0x%x\n", e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_cdt);
  795.         ENDDEBUG
  796.         if( p->tp_class != TP_CLASS_0) {
  797.             tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  798.             tp_euntimeout_lss(p->tp_refp, TM_data_retrans, e->ev_union.EV_AK_TPDU.e_seq);
  799.         }
  800.         sbwakeup( &p->tp_sock->so_snd );
  801.  
  802.         if (p->tp_sndhiwat <= p->tp_retrans_hiwat &&
  803.             p->tp_snduna <= p->tp_retrans_hiwat) {
  804.  
  805.             register    struct mbuf     *m;
  806.             /* extern      struct mbuf     *m_copy(); */
  807.             register    struct tp_rtc   *r;
  808.             SeqNum      high, retrans, low_save;
  809.  
  810.             high = SEQ_MIN(p, SEQ_ADD(p, p->tp_snduna,
  811.                     MIN(p->tp_cong_win, p->tp_fcredit)) - 1,
  812.                     p->tp_sndhiwat);
  813.             low_save = retrans = SEQ_MAX(p, SEQ_ADD(p, p->tp_last_retrans, 1),
  814.                     p->tp_snduna);
  815.             for (; SEQ_LEQ(p, retrans, high); SEQ_INC(p, retrans)) {
  816.  
  817.                 for (r = p->tp_snduna_rtc; r; r = r->tprt_next){
  818.                     if ( r->tprt_seq == retrans ){
  819.                         if(( m = m_copy(r->tprt_data, 0, r->tprt_octets ))
  820.                                 == MNULL)
  821.                             break;
  822.                         (void) tp_emit(DT_TPDU_type, p, retrans,
  823.                             r->tprt_eot, m);
  824.                         p->tp_last_retrans = retrans;
  825.                         IncStat(ts_retrans_dt);
  826.                         break;
  827.                     }
  828.                 }
  829.                 if ( r == (struct tp_rtc *)0 ){
  830.                     IFDEBUG(D_RTC)
  831.                         printf( "tp: retrans rtc list is GONE!\n");
  832.                     ENDDEBUG
  833.                     break;
  834.                 }
  835.             }
  836.             tp_etimeout(p->tp_refp, TM_data_retrans, (caddr_t)low_save,
  837.                     (caddr_t)high, p->tp_retrans, (int)p->tp_dt_ticks);
  838.             if (SEQ_DEC(p, retrans) == p->tp_retrans_hiwat)
  839.                 tp_send(p);
  840.         }
  841.         else {
  842.             tp_send(p);
  843.         }
  844.         IFDEBUG(D_ACKRECV)
  845.             printf("GOOD ACK new sndhiwat 0x%x\n", p->tp_sndhiwat);
  846.         ENDDEBUG
  847.     }
  848.          break;
  849. case 0x31: 
  850.         {
  851.         IFTRACE(D_ACKRECV)
  852.             tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", 
  853.                 e->ev_union.EV_AK_TPDU.e_fcc_present, p->tp_r_subseq, e->ev_union.EV_AK_TPDU.e_subseq, 0);
  854.         ENDTRACE
  855.         if( p->tp_class != TP_CLASS_0 ) {
  856.  
  857.             if ( !e->ev_union.EV_AK_TPDU.e_fcc_present ) {
  858.                 /* send ACK with FCC */
  859.                 IncStat( ts_ackreason[_ACK_FCC_] );
  860.                 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 1, MNULL);
  861.             }
  862.             tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  863.         } 
  864.     }
  865.          break;
  866. case 0x32: 
  867.         {    
  868.         tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  869.         tp_cuntimeout(p->tp_refp, TM_retrans);
  870.  
  871.         sbwakeup( &p->tp_sock->so_snd );
  872.  
  873.         /* resume normal data */
  874.         tp_send(p);
  875.     }
  876.          break;
  877. case 0x33: 
  878.         {
  879.         IFTRACE(D_ACKRECV)
  880.             tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0);
  881.         ENDTRACE
  882.         if( p->tp_class != TP_CLASS_0 ) {
  883.             tp_ctimeout(p->tp_refp, TM_inact, (int)p->tp_inact_ticks);
  884.         } 
  885.     }
  886.          break;
  887. case 0x34: 
  888.         {    
  889.         IFTRACE(D_TIMER)
  890.             tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe, 
  891.             p->tp_sent_lcdt, 0);
  892.         ENDTRACE
  893.         IncPStat(p, tps_n_TMsendack);
  894.         (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
  895.     }
  896.          break;
  897. case 0x35: 
  898.         {
  899.         if (sbspace(&p->tp_sock->so_rcv) > 0)
  900.             tp0_openflow(p);
  901.     }
  902.          break;
  903. case 0x36: 
  904.         {    
  905.         if( trick_hc ) {
  906.             IncStat(ts_ackreason[_ACK_USRRCV_]);
  907.  
  908.             /* send an ACK only if there's new information */
  909.             LOCAL_CREDIT( p );
  910.             if ((p->tp_rcvnxt != p->tp_sent_rcvnxt) ||
  911.                 (p->tp_lcredit != p->tp_sent_lcdt))
  912.  
  913.                 return tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
  914.         }
  915.     }
  916.          break;
  917. case 0x37: 
  918.         {
  919.         if(trick_hc)
  920.         return ECONNABORTED;
  921.     }
  922.          break;
  923. case 0x38: 
  924.         {
  925.         ASSERT( p->tp_state != TP_LISTENING );
  926.         tp_indicate(T_DISCONNECT, p, ECONNRESET);
  927.         tp_soisdisconnected(p);
  928.     }
  929.          break;
  930.     }
  931. return 0;
  932. }
  933.  
  934. _XEBEC_PG int
  935. _Xebec_index( e,p )
  936.     struct tp_event *e;
  937.     tp_PCB_ *p;
  938. {
  939. switch( (e->ev_number<<4)+(p->tp_state) ) {
  940. case 0x12:
  941.     if (    p->tp_retrans > 0 ) return 0x1e;
  942.      else return 0x1f;
  943. case 0x13:
  944.     if ( p->tp_retrans > 0 ) return 0x2f;
  945.      else return 0x30;
  946. case 0x14:
  947.     if ( p->tp_retrans > 0 ) return 0x32;
  948.      else return 0x31;
  949. case 0x15:
  950.     if (    p->tp_retrans > 0 ) return 0x34;
  951.      else return 0x35;
  952. case 0x54:
  953.     if ( e->ev_union.EV_TM_data_retrans.e_retrans > 0 ) return 0x33;
  954.      else return 0x31;
  955. case 0x64:
  956.     if (p->tp_class == TP_CLASS_0) return 0x1a;
  957.      else return 0x1b;
  958. case 0x77:
  959.     if ( p->tp_class == TP_CLASS_0) return 0xd;
  960.      else return 0xe;
  961. case 0x86:
  962.     if ( e->ev_union.EV_DR_TPDU.e_sref !=  0 ) return 0x2;
  963.      else return 0x3;
  964. case 0xa2:
  965.     if (p->tp_class == TP_CLASS_0) return 0x1c;
  966.      else return 0x1d;
  967. case 0xb2:
  968.     if (p->tp_class == TP_CLASS_0) return 0x5;
  969.      else return 0x0;
  970. case 0xb4:
  971.     if ( tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq)  ) return 0x3a;
  972.      else return 0x3b;
  973. case 0xc3:
  974.     if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq,
  975.                     p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x21;
  976.      else return 0x24;
  977. case 0xc4:
  978.     if ( p->tp_class == TP_CLASS_0 ) return 0x22;
  979.      else if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq,
  980.                     p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x23;
  981.      else return 0x25;
  982. case 0xd3:
  983.     if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
  984.      else return 0x2a;
  985. case 0xd4:
  986.     if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
  987.      else return 0x29;
  988. case 0xe4:
  989.     if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c;
  990.      else return 0x3d;
  991. case 0x102:
  992.     if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
  993.      else return 0x2e;
  994. case 0x104:
  995.     if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
  996.      else return 0x2e;
  997. case 0x144:
  998.     if (p->tp_class == TP_CLASS_0) return 0x3f;
  999.      else return 0x40;
  1000. case 0x162:
  1001.     if (p->tp_class == TP_CLASS_0) return 0x2b;
  1002.      else return 0x2c;
  1003. case 0x172:
  1004.     if ( p->tp_class != TP_CLASS_4 ) return 0x42;
  1005.      else return 0x46;
  1006. case 0x174:
  1007.     if ( p->tp_class != TP_CLASS_4 ) return 0x42;
  1008.      else return 0x47;
  1009. case 0x177:
  1010.     if ( p->tp_class != TP_CLASS_4 ) return 0x42;
  1011.      else return 0x43;
  1012. case 0x188:
  1013.     if ( p->tp_class == TP_CLASS_0 ) return 0xf;
  1014.      else if (tp_emit(CC_TPDU_type, p, 0,0, MCPY(p->tp_ucddata, M_NOWAIT)) == 0) return 0x10;
  1015.      else return 0x11;
  1016. default: return 0;
  1017. } /* end switch */
  1018. } /* _Xebec_index() */
  1019. static int inx[26][9] = { {0,0,0,0,0,0,0,0,0,},
  1020.  {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, },
  1021.  {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, },
  1022.  {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, },
  1023.  {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
  1024.  {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, },
  1025.  {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, },
  1026.  {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, },
  1027.  {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, },
  1028.  {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, },
  1029.  {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, },
  1030.  {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, },
  1031.  {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, },
  1032.  {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
  1033.  {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
  1034.  {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, },
  1035.  {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
  1036.  {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, },
  1037.  {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
  1038.  {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, },
  1039.  {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, },
  1040.  {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, },
  1041.  {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, },
  1042.  {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, },
  1043.  {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, },
  1044.  {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, },
  1045. };
  1046. tp_driver(p, e)
  1047. register tp_PCB_ *p;
  1048. register struct tp_event *e;
  1049. {
  1050.     register int index, error=0;
  1051.     struct act_ent *a;
  1052.     static struct act_ent erroraction = {0,-1};
  1053.  
  1054.     index = inx[1 + e->ev_number][p->tp_state];
  1055.     if(index<0) index=_Xebec_index(e, p);
  1056.     if (index==0) {
  1057.         a = &erroraction;
  1058.     } else
  1059.         a = &statetable[index];
  1060.  
  1061.     if(a->a_action)
  1062.         error = _Xebec_action( a->a_action, e, p );
  1063.     IFTRACE(D_DRIVER)
  1064.     tptrace(DRIVERTRACE,        a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0);
  1065.  
  1066.     ENDTRACE
  1067.     if(error==0)
  1068.     p->tp_state = a->a_newstate;
  1069.     return error;
  1070. }
  1071.