home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp_input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  45.1 KB  |  1,593 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_input.c    7.19 (Berkeley) 6/27/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. /* 
  63.  * ARGO TP
  64.  *
  65.  * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
  66.  * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
  67.  *
  68.  * tp_input() gets an mbuf chain from ip.  Actually, not directly
  69.  * from ip, because ip calls a net-level routine that strips off
  70.  * the net header and then calls tp_input(), passing the proper type
  71.  * of addresses for the address family in use (how it figures out
  72.  * which AF is not yet determined.
  73.  *
  74.  * Decomposing the tpdu is some of the most laughable code.  The variable-length
  75.  * parameters and the problem of non-aligned memory references
  76.  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
  77.  * to loop through the header and decompose it.
  78.  *
  79.  * The routine tp_newsocket() is called when a CR comes in for a listening
  80.  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
  81.  * "child" socket.  Most tpcb values are copied from the parent tpcb into
  82.  * the child.
  83.  * 
  84.  * Also in here is tp_headersize() (grot) which tells the expected size
  85.  * of a tp header, to be used by other layers.  It's in here because it
  86.  * uses the static structure tpdu_info.
  87.  */
  88.  
  89. #include "param.h"
  90. #include "systm.h"
  91. #include "mbuf.h"
  92. #include "socket.h"
  93. #include "socketvar.h"
  94. #include "domain.h"
  95. #include "protosw.h"
  96. #include "errno.h"
  97. #include "time.h"
  98. #include "kernel.h"
  99. #include "types.h"
  100. #include "iso.h"
  101. #include "iso_errno.h"
  102. #include "iso_pcb.h"
  103. #include "tp_param.h"
  104. #include "tp_timer.h"
  105. #include "tp_stat.h"
  106. #include "tp_pcb.h"
  107. #include "argo_debug.h"
  108. #include "tp_trace.h"
  109. #include "tp_tpdu.h"
  110.  
  111. #include "../net/if.h"
  112. #ifdef TRUE
  113. #undef FALSE
  114. #undef TRUE
  115. #endif
  116. #include "../netccitt/x25.h"
  117. #include "../netccitt/pk.h"
  118. #include "../netccitt/pk_var.h"
  119.  
  120. int     iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
  121.  
  122. /*
  123.     #ifdef lint
  124.     #undef ATTR
  125.     #define ATTR(X)ev_number
  126.     #endif lint
  127. */
  128.  
  129. struct mbuf *
  130. tp_inputprep(m) 
  131.     register struct mbuf *m;
  132. {
  133.     int hdrlen;
  134.  
  135.     IFDEBUG(D_TPINPUT)
  136.         printf("tp_inputprep: m 0x%x\n", m) ;
  137.     ENDDEBUG
  138.  
  139.     while(  m->m_len < 1 ) {
  140.         if( (m = m_free(m)) == MNULL ) {
  141.             return (struct mbuf *)0;
  142.         }
  143.     }
  144.     if(((int)m->m_data) & 0x3) {
  145.         /* If we are not 4-byte aligned, we have to be
  146.          * above the beginning of the mbuf, and it is ok just
  147.          * to slide it back. 
  148.          */
  149.         caddr_t ocp = m->m_data;
  150.  
  151.         m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
  152.         ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
  153.     }
  154.     CHANGE_MTYPE(m, TPMT_DATA);
  155.  
  156.     /* we KNOW that there is at least 1 byte in this mbuf
  157.        and that it is hdr->tpdu_li XXXXXXX!  */
  158.  
  159.     hdrlen = 1 + *mtod( m, u_char *);
  160.  
  161.     /*
  162.      * now pull up the whole tp header 
  163.      */
  164.     if ( m->m_len < hdrlen) {
  165.         if ((m = m_pullup(m, hdrlen)) == MNULL ) {
  166.             IncStat(ts_recv_drop);
  167.             return (struct mbuf *)0;
  168.         }
  169.     }
  170.     IFDEBUG(D_INPUT)
  171.     printf(
  172.     " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
  173.         hdrlen, m->m_len);
  174.     ENDDEBUG
  175.     return m;
  176. }
  177.  
  178. /* begin groan
  179.  * -- this array and the following macros allow you to step through the
  180.  * parameters of the variable part of a header
  181.  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
  182.  * should change, this array has to be rearranged
  183.  */
  184.  
  185. #define TP_LEN_CLASS_0_INDEX    2
  186. #define TP_MAX_DATA_INDEX 3
  187.  
  188. static u_char tpdu_info[][4] =
  189. {
  190. /*                                length                         max data len */
  191. /*                                reg fmt     xtd fmt  class 0                 */
  192.      /* UNUSED        0x0 */        0x0 ,        0x0,    0x0,        0x0,
  193.      /* XPD_TPDU_type 0x1 */        0x5,        0x8,    0x0,        TP_MAX_XPD_DATA,
  194.      /* XAK_TPDU_type 0x2 */        0x5 ,        0x8,    0x0,        0x0,
  195.      /* GR_TPDU_type    0x3 */        0x0 ,        0x0,    0x0,        0x0,
  196.      /* UNUSED        0x4 */        0x0 ,        0x0,    0x0,        0x0,
  197.      /* UNUSED        0x5 */        0x0 ,        0x0,    0x0,        0x0,
  198.      /* AK_TPDU_type 0x6 */        0x5,        0xa,    0x0,        0x0,
  199.     /* ER_TPDU_type 0x7 */        0x5,        0x5,    0x0,        0x0,
  200.      /* DR_TPDU_type 0x8 */        0x7,        0x7,    0x7,        TP_MAX_DR_DATA,
  201.      /* UNUSED        0x9 */        0x0 ,        0x0,    0x0,        0x0,
  202.      /* UNUSED        0xa */        0x0 ,        0x0,    0x0,        0x0,
  203.      /* UNUSED        0xb */        0x0 ,        0x0,    0x0,        0x0,
  204.      /* DC_TPDU_type 0xc */        0x6,        0x6,    0x0,        0x0,
  205.      /* CC_TPDU_type 0xd */        0x7,        0x7,    0x7,        TP_MAX_CC_DATA,
  206.      /* CR_TPDU_type 0xe */        0x7,        0x7,    0x7,        TP_MAX_CR_DATA,
  207.      /* DT_TPDU_type 0xf */        0x5,        0x8,    0x3,        0x0,
  208. };
  209.  
  210. #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
  211.     if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
  212.     goto Whattodo; }
  213.  
  214. tpibrk() {}
  215.  
  216. /* 
  217.  * WHENEVER YOU USE THE FOLLOWING MACRO,
  218.  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! 
  219.  */
  220.  
  221. #define WHILE_OPTIONS(P, hdr, format)\
  222. {    register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
  223.     caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
  224.     for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
  225.         CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
  226.                 respond, P - (caddr_t)hdr);\
  227.         if (P == PLIM) break;
  228.  
  229. #define END_WHILE_OPTIONS(P) } }
  230.  
  231. /* end groan */
  232.  
  233. /*
  234.  * NAME:  tp_newsocket()
  235.  *
  236.  * CALLED FROM:
  237.  *  tp_input() on incoming CR, when a socket w/ the called suffix
  238.  * is awaiting a  connection request
  239.  *
  240.  * FUNCTION and ARGUMENTS:
  241.  *  Create a new socket structure, attach to it a new transport pcb,
  242.  *  using a copy of the net level pcb for the parent socket.
  243.  *  (so) is the parent socket.
  244.  *  (fname) is the foreign address (all that's used is the nsap portion)
  245.  *
  246.  * RETURN VALUE:
  247.  *  a new socket structure, being this end of the newly formed connection.
  248.  *
  249.  * SIDE EFFECTS:
  250.  *  Sets a few things in the tpcb and net level pcb
  251.  *
  252.  * NOTES:
  253.  */
  254. static struct socket *
  255. tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
  256.     struct socket                *so;
  257.     struct sockaddr                *fname;
  258.     u_int                        cons_channel;
  259.     u_char                        class_to_use;
  260.     u_int                        netservice;
  261. {
  262.     register struct tp_pcb    *tpcb = sototpcb(so); /* old tpcb, needed below */
  263.     register struct tp_pcb    *newtpcb;
  264.  
  265.     /* 
  266.      * sonewconn() gets a new socket structure,
  267.      * a new lower layer pcb and a new tpcb,
  268.      * but the pcbs are unnamed (not bound)
  269.      */
  270.     IFTRACE(D_NEWSOCK)
  271.         tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
  272.             so, tpcb, so->so_head, 0);
  273.     ENDTRACE    
  274.  
  275.     if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
  276.         return so;
  277.     IFTRACE(D_NEWSOCK)
  278.         tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
  279.             so, so->so_head, 0, 0);
  280.     ENDTRACE    
  281.  
  282.     IFDEBUG(D_NEWSOCK)
  283.         printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
  284.                 cons_channel, so);
  285.         dump_addr(fname);
  286.         { 
  287.             struct socket *t, *head ;
  288.  
  289.             head = so->so_head;
  290.             t = so;
  291.             printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
  292.                     t, t->so_head, t->so_q0, t->so_q0len);
  293.             while( (t=t->so_q0)  && t!= so  && t!= head)
  294.                 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
  295.                     t, t->so_head, t->so_q0, t->so_q0len);
  296.         }
  297.     ENDDEBUG
  298.  
  299.     /* 
  300.      * before we clobber the old tpcb ptr, get these items from the parent pcb 
  301.      */
  302.     newtpcb = sototpcb(so);
  303.     newtpcb->_tp_param = tpcb->_tp_param;
  304.     newtpcb->tp_flags = tpcb->tp_flags;
  305.     newtpcb->tp_lcredit = tpcb->tp_lcredit;
  306.     newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
  307.     newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
  308.     bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
  309.     soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
  310.  
  311.     if( /* old */ tpcb->tp_ucddata) {
  312.         /* 
  313.          * These data are the connect- , confirm- or disconnect- data.
  314.          */
  315.         struct mbuf *conndata;
  316.  
  317.         conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
  318.         IFDEBUG(D_CONN)
  319.             dump_mbuf(conndata, "conndata after mcopy");
  320.         ENDDEBUG
  321.         newtpcb->tp_ucddata = conndata;
  322.     }
  323.  
  324.     tpcb = newtpcb;
  325.     tpcb->tp_state = TP_LISTENING;
  326.     tpcb->tp_class = class_to_use;
  327.     tpcb->tp_netservice = netservice;
  328.  
  329.  
  330.     ASSERT( fname != 0 ) ; /* just checking */
  331.     if ( fname ) {
  332.         /*
  333.          *    tp_route_to takes its address argument in the form of an mbuf.
  334.          */
  335.         struct mbuf    *m;
  336.         int            err;
  337.  
  338.         MGET(m, M_DONTWAIT, MT_SONAME);    /* mbuf type used is confusing */
  339.         if (m) {
  340.             /*
  341.              * this seems a bit grotesque, but tp_route_to expects
  342.              * an mbuf * instead of simply a sockaddr; it calls the ll
  343.              * pcb_connect, which expects the name/addr in an mbuf as well.
  344.              * sigh.
  345.              */
  346.             bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
  347.             m->m_len = fname->sa_len;
  348.  
  349.             /* grot  : have to say the kernel can override params in
  350.              * the passive open case
  351.              */
  352.             tpcb->tp_dont_change_params = 0;
  353.             err = tp_route_to( m, tpcb, cons_channel);
  354.             m_free(m);
  355.  
  356.             if (!err)
  357.                 goto ok;
  358.         }
  359.         IFDEBUG(D_CONN)
  360.             printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
  361.                 tpcb, so);
  362.         ENDDEBUG
  363.         (void) tp_detach(tpcb); 
  364.         return 0;
  365.     }
  366. ok:
  367.     IFDEBUG(D_TPINPUT)
  368.         printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
  369.             so, sototpcb(so));
  370.     ENDDEBUG
  371.     return so;
  372. }
  373.  
  374. #ifndef TPCONS
  375. tpcons_output()
  376. {
  377.     return(0);
  378. }
  379. #endif !CONS
  380.  
  381. /* 
  382.  * NAME:     tp_input()
  383.  *
  384.  * CALLED FROM:
  385.  *  net layer input routine
  386.  *
  387.  * FUNCTION and ARGUMENTS:
  388.  *  Process an incoming TPDU (m), finding the associated tpcb if there
  389.  *  is one. Create the appropriate type of event and call the driver.
  390.  *  (faddr) and (laddr) are the foreign and local addresses.
  391.  * 
  392.  *     When tp_input() is called we KNOW that the ENTIRE TP HEADER
  393.  *     has been m_pullup-ed.
  394.  *
  395.  * RETURN VALUE: Nada
  396.  *  
  397.  * SIDE EFFECTS:
  398.  *    When using COSNS it may affect the state of the net-level pcb
  399.  *
  400.  * NOTE:
  401.  *  The initial value of acktime is 2 so that we will never
  402.  *  have a 0 value for tp_peer_acktime.  It gets used in the
  403.  *  computation of the retransmission timer value, and so it
  404.  *  mustn't be zero.
  405.  *  2 seems like a reasonable minimum.
  406.  */
  407. ProtoHook
  408. tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
  409.     register    struct mbuf     *m;
  410.     struct sockaddr             *faddr, *laddr; /* NSAP addresses */
  411.     u_int                         cons_channel;
  412.     int                         (*dgout_routine)();
  413.     int                            ce_bit;
  414.  
  415. {
  416.     register struct tp_pcb     *tpcb = (struct tp_pcb *)0;
  417.     register struct tpdu     *hdr;
  418.     struct socket             *so;
  419.     struct tp_event         e;
  420.     int                     error = 0;
  421.     unsigned                 dutype;
  422.     u_short                 dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
  423.     u_char                     preferred_class = 0, class_to_use = 0;
  424.     u_char                    opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
  425. #ifdef TP_PERF_MEAS
  426.     u_char                    perf_meas;
  427. #endif TP_PERF_MEAS
  428.     u_char                    fsufxlen = 0, lsufxlen = 0, intercepted = 0;
  429.     caddr_t                    fsufxloc = 0, lsufxloc = 0;
  430.     int                        tpdu_len = 0;
  431.     u_int                     takes_data = FALSE;
  432.     u_int                    fcc_present = FALSE; 
  433.     int                        errlen = 0;
  434.     struct tp_conn_param     tpp;
  435.     int                        tpcons_output();
  436.  
  437. again:
  438.     hdr = mtod(m, struct tpdu *);
  439. #ifdef TP_PERF_MEAS
  440.     GET_CUR_TIME( &e.e_time ); perf_meas = 0;
  441. #endif TP_PERF_MEAS
  442.     
  443.     IFDEBUG(D_TPINPUT)
  444.         printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
  445.     ENDDEBUG
  446.  
  447.  
  448.     /* 
  449.      * get the actual tpdu length - necessary for monitoring
  450.      * and for checksumming
  451.      * 
  452.      * Also, maybe measure the mbuf chain lengths and sizes.
  453.      */
  454.  
  455.     {     register struct mbuf *n=m;
  456. #    ifdef ARGO_DEBUG
  457.         int chain_length = 0;
  458. #    endif ARGO_DEBUG
  459.  
  460.         for(;;) {
  461.             tpdu_len += n->m_len;
  462.             IFDEBUG(D_MBUF_MEAS)
  463.                 if( n->m_flags & M_EXT) {
  464.                     IncStat(ts_mb_cluster);
  465.                 } else {
  466.                     IncStat(ts_mb_small);
  467.                 }
  468.                 chain_length ++;
  469.             ENDDEBUG
  470.             if (n->m_next == MNULL ) {
  471.                 break;
  472.             }
  473.             n = n->m_next;
  474.         }
  475.         IFDEBUG(D_MBUF_MEAS)
  476.             if(chain_length > 16)
  477.                 chain_length = 0; /* zero used for anything > 16 */
  478.             tp_stat.ts_mb_len_distr[chain_length] ++;
  479.         ENDDEBUG
  480.     }
  481.     IFTRACE(D_TPINPUT)
  482.         tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, 
  483.             0);
  484.     ENDTRACE
  485.  
  486.     dref = ntohs((short)hdr->tpdu_dref);
  487.     sref = ntohs((short)hdr->tpdu_sref);
  488.     dutype = (int)hdr->tpdu_type;
  489.  
  490.     IFDEBUG(D_TPINPUT)
  491.         printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
  492.             cons_channel, dref);
  493.         printf("input: dref 0x%x sref 0x%x\n", dref, sref);
  494.     ENDDEBUG
  495.     IFTRACE(D_TPINPUT)
  496.         tptrace(TPPTmisc, "channel dutype dref ", 
  497.             cons_channel, dutype, dref, 0);
  498.     ENDTRACE
  499.  
  500.  
  501. #ifdef ARGO_DEBUG
  502.     if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
  503.         printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
  504.             dutype, cons_channel, dref);
  505.         dump_buf (m, sizeof( struct mbuf ));
  506.  
  507.         IncStat(ts_inv_dutype);
  508.         goto discard;
  509.     }
  510. #endif ARGO_DEBUG
  511.  
  512.     CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
  513.         E_TP_INV_TPDU, ts_inv_dutype, respond, 
  514.         2 );
  515.         /* unfortunately we can't take the address of the tpdu_type field,
  516.          * since it's a bit field - so we just use the constant offset 2
  517.          */
  518.  
  519.     /* Now this isn't very neat but since you locate a pcb one way
  520.      * at the beginning of connection establishment, and by
  521.      * the dref for each tpdu after that, we have to treat CRs differently
  522.      */
  523.     if ( dutype == CR_TPDU_type ) {
  524.         u_char alt_classes = 0;
  525.  
  526.         preferred_class = 1 << hdr->tpdu_CRclass;
  527.         opt = hdr->tpdu_CRoptions;
  528.  
  529.         WHILE_OPTIONS(P, hdr, 1 ) /* { */
  530.  
  531.             switch( vbptr(P)->tpv_code ) {
  532.  
  533.             case    TPP_tpdu_size:         
  534.                 vb_getval(P, u_char, dusize);
  535.                 IFDEBUG(D_TPINPUT)
  536.                     printf("CR dusize 0x%x\n", dusize);
  537.                 ENDDEBUG
  538.                 /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
  539.                 if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
  540.                         dusize = TP_DFL_TPDUSIZE;
  541.                 break;
  542.             case    TPP_addl_opt:
  543.                 vb_getval(P, u_char, addlopt);
  544.                 break;
  545.             case    TPP_calling_sufx:
  546.                 /* could use vb_getval, but we want to save the loc & len
  547.                  * for later use
  548.                  */
  549.                 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
  550.                 fsufxlen = vbptr(P)->tpv_len;
  551.                 IFDEBUG(D_TPINPUT)
  552.                     printf("CR fsufx:");
  553.                     { register int j;
  554.                         for(j=0; j<fsufxlen; j++ ) {
  555.                             printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
  556.                         }
  557.                         printf("\n");
  558.                     }
  559.                 ENDDEBUG
  560.                 break;
  561.             case    TPP_called_sufx:
  562.                 /* could use vb_getval, but we want to save the loc & len
  563.                  * for later use
  564.                  */
  565.                 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
  566.                 lsufxlen = vbptr(P)->tpv_len;
  567.                 IFDEBUG(D_TPINPUT)
  568.                     printf("CR lsufx:");
  569.                     { register int j;
  570.                         for(j=0; j<lsufxlen; j++ ) {
  571.                             printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
  572.                         }
  573.                         printf("\n");
  574.                     }
  575.                 ENDDEBUG
  576.                 break;
  577.  
  578. #ifdef TP_PERF_MEAS
  579.             case    TPP_perf_meas:
  580.                 vb_getval(P, u_char, perf_meas);
  581.                 break;
  582. #endif TP_PERF_MEAS
  583.  
  584.             case    TPP_vers:
  585.                 /* not in class 0; 1 octet; in CR_TPDU only */
  586.                 /* COS tests says if version wrong, use default version!?XXX */
  587.                 CHECK( (vbval(P, u_char) != TP_VERSION ), 
  588.                     E_TP_INV_PVAL, ts_inv_pval, setversion,
  589.                     (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
  590.             setversion:
  591.                 version = vbval(P, u_char);
  592.                 break;
  593.             case    TPP_acktime:
  594.                 vb_getval(P, u_short, acktime);
  595.                 acktime = ntohs(acktime);
  596.                 acktime = acktime/500; /* convert to slowtimo ticks */
  597.                 if((short)acktime <=0 )
  598.                     acktime = 2; /* don't allow a bad peer to screw us up */
  599.                 IFDEBUG(D_TPINPUT)
  600.                     printf("CR acktime 0x%x\n", acktime);
  601.                 ENDDEBUG
  602.                 break;
  603.  
  604.             case    TPP_alt_class:
  605.                 {
  606.                     u_char *aclass = 0;
  607.                     register int i;
  608.                     static u_char bad_alt_classes[5] =
  609.                         { ~0, ~3, ~5, ~0xf, ~0x1f};
  610.  
  611.                     aclass = 
  612.                         (u_char *) &(((struct tp_vbp *)P)->tpv_val);
  613.                     for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
  614.                         alt_classes |= (1<<((*aclass++)>>4));
  615.                     }
  616.                     CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
  617.                         E_TP_INV_PVAL, ts_inv_aclass, respond,
  618.                         ((caddr_t)aclass) - (caddr_t)hdr);
  619.                     IFDEBUG(D_TPINPUT)
  620.                         printf("alt_classes 0x%x\n", alt_classes);
  621.                     ENDDEBUG
  622.                 }
  623.                 break;
  624.  
  625.             case    TPP_security:
  626.             case    TPP_residER:
  627.             case    TPP_priority:
  628.             case    TPP_transdelay:
  629.             case    TPP_throughput: 
  630.             case    TPP_addl_info: 
  631.             case    TPP_subseq:
  632.             default:
  633.                 IFDEBUG(D_TPINPUT)
  634.                     printf("param ignored CR_TPDU code= 0x%x\n",
  635.                          vbptr(P)->tpv_code);
  636.                 ENDDEBUG
  637.                 IncStat(ts_param_ignored);
  638.                 break;
  639.  
  640.             case    TPP_checksum:        
  641.                 IFDEBUG(D_TPINPUT)
  642.                     printf("CR before cksum\n");
  643.                 ENDDEBUG
  644.  
  645.                 CHECK( iso_check_csum(m, tpdu_len), 
  646.                     E_TP_INV_PVAL, ts_bad_csum, discard, 0)
  647.  
  648.                 IFDEBUG(D_TPINPUT)
  649.                     printf("CR before cksum\n");
  650.                 ENDDEBUG
  651.                 break;
  652.             }
  653.  
  654.         /* } */ END_WHILE_OPTIONS(P)
  655.  
  656.         if (lsufxlen == 0) {
  657.             /* can't look for a tpcb w/o any called sufx */
  658.             error =  E_TP_LENGTH_INVAL;
  659.             IncStat(ts_inv_sufx);
  660.             goto respond;
  661.         } else {
  662.             register struct tp_pcb *t;
  663.  
  664.             for (t = tp_intercepts; t ; t = t->tp_nextlisten) {
  665.                 if (laddr->sa_family != t->tp_nlproto->nlp_afamily)
  666.                     continue;
  667.                 if ((*t->tp_nlproto->nlp_cmpnetaddr)(
  668.                         t->tp_npcb, laddr, TP_LOCAL)) {
  669.                             intercepted = 1;
  670.                             goto check_duplicate_cr;
  671.                 }
  672.             }
  673.             for (t = tp_listeners; t ; t = t->tp_nextlisten)
  674.                 if (lsufxlen == t->tp_lsuffixlen &&
  675.                     bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 &&
  676.                     laddr->sa_family == t->tp_nlproto->nlp_afamily)
  677.                         break;
  678.             CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
  679.                 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  680.                 /* _tpduf is the fixed part; add 2 to get the dref bits of 
  681.                  * the fixed part (can't take the address of a bit field) 
  682.                  */
  683.             IFDEBUG(D_TPINPUT)
  684.                 printf("checking if dup CR\n");
  685.             ENDDEBUG
  686.         check_duplicate_cr:
  687.             tpcb = t;
  688.             for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
  689.                 if (sref != t->tp_fref)
  690.                     continue;
  691.                 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
  692.                         t->tp_npcb, faddr, TP_FOREIGN)) {
  693.                     IFDEBUG(D_TPINPUT)
  694.                         printf("duplicate CR discarded\n");
  695.                     ENDDEBUG
  696.                     goto discard;
  697.                 }
  698.             }
  699.             IFTRACE(D_TPINPUT)
  700.                 tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", 
  701.                     tpcb, *lsufxloc, tpcb->tp_state, 0);
  702.             ENDTRACE
  703.         }
  704.  
  705.         /* 
  706.          * WE HAVE A TPCB 
  707.          * already know that the classes in the CR match at least
  708.          * one class implemented, but we don't know yet if they
  709.          * include any classes permitted by this server.
  710.          */
  711.  
  712.         IFDEBUG(D_TPINPUT)
  713.             printf("HAVE A TPCB 1: 0x%x\n", tpcb);
  714.         ENDDEBUG
  715.         IFDEBUG(D_CONN)
  716.             printf(
  717. "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", 
  718.                 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
  719.         ENDDEBUG
  720.         /* tpcb->tp_class doesn't include any classes not implemented  */
  721.         class_to_use = (preferred_class & tpcb->tp_class);
  722.         if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
  723.             class_to_use = alt_classes & tpcb->tp_class;
  724.  
  725.         class_to_use = 1 << tp_mask_to_num(class_to_use);
  726.  
  727.         {
  728.             tpp = tpcb->_tp_param;
  729.             tpp.p_class = class_to_use;
  730.             tpp.p_tpdusize = dusize;
  731.             tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
  732.             tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
  733.             tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
  734.                 (addlopt & TPAO_NO_CSUM) == 0;
  735.             tpp.p_version = version;
  736. #ifdef notdef
  737.             tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
  738.             tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
  739.             tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
  740. #endif notdef
  741.  
  742.         CHECK(
  743.             tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, 
  744.             E_TP_NEGOT_FAILED, ts_negotfailed, respond,
  745.             (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 
  746.                 /* ^ more or less the location of class */
  747.             )
  748.         }
  749.         IFTRACE(D_CONN)
  750.             tptrace(TPPTmisc, 
  751.                 "after 1 consist class_to_use class, out, tpconsout",
  752.                 class_to_use, 
  753.                 tpcb->tp_class, dgout_routine, tpcons_output
  754.                 );
  755.         ENDTRACE
  756.         CHECK(
  757.             ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
  758.             E_TP_NEGOT_FAILED, ts_negotfailed, respond,
  759.             (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 
  760.                 /* ^ more or less the location of class */
  761.             )
  762.         IFDEBUG(D_CONN)
  763.             printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", 
  764.                 tpcb, tpcb->tp_flags);
  765.         ENDDEBUG
  766.         takes_data = TRUE;
  767.         e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
  768.         e.ev_number = CR_TPDU;
  769.  
  770.         so = tpcb->tp_sock;
  771.         if (so->so_options & SO_ACCEPTCONN) {
  772.             struct tp_pcb *parent_tpcb = tpcb;
  773.             /* 
  774.              * Create a socket, tpcb, ll pcb, etc. 
  775.              * for this newborn connection, and fill in all the values. 
  776.              */
  777.             IFDEBUG(D_CONN)
  778.                 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
  779.                     so, laddr, faddr, cons_channel);
  780.             ENDDEBUG
  781.             if( (so = 
  782.                 tp_newsocket(so, faddr, cons_channel, 
  783.                     class_to_use, 
  784.                     ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
  785.                     (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
  786.                     ) == (struct socket *)0 ) {
  787.                 /* note - even if netservice is IN_CLNS, as far as
  788.                  * the tp entity is concerned, the only differences
  789.                  * are CO vs CL
  790.                  */
  791.                 IFDEBUG(D_CONN)
  792.                     printf("tp_newsocket returns 0\n");
  793.                 ENDDEBUG
  794.                 goto discard;
  795.             }
  796.             tpcb = sototpcb(so);
  797.             insque(tpcb, parent_tpcb);
  798.  
  799.             /*
  800.              * Stash the addresses in the net level pcb 
  801.              * kind of like a pcbconnect() but don't need
  802.              * or want all those checks.
  803.              */
  804.             (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
  805.             (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
  806.  
  807.             /* stash the f suffix in the new tpcb */
  808.             bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
  809.             /* l suffix is already there, unless this is an intercept case */
  810.             if (intercepted)
  811.                 bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
  812.             (tpcb->tp_nlproto->nlp_putsufx)
  813.                     (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
  814.             (tpcb->tp_nlproto->nlp_putsufx)
  815.                     (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
  816. #ifdef TP_PERF_MEAS
  817.             if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
  818.                 /* ok, let's create an mbuf for stashing the
  819.                  * statistics if one doesn't already exist 
  820.                  */
  821.                 (void) tp_setup_perf(tpcb);
  822.             }
  823. #endif TP_PERF_MEAS
  824.             tpcb->tp_fref = sref;
  825.  
  826.             /* We've already checked for consistency with the options 
  827.              * set in tpp,  but we couldn't set them earlier because 
  828.              * we didn't want to change options in the LISTENING tpcb.
  829.              * Now we set the options in the new socket's tpcb.
  830.              */
  831.             (void) tp_consistency( tpcb, TP_FORCE, &tpp);
  832.  
  833.             if(!tpcb->tp_use_checksum)
  834.                 IncStat(ts_csum_off);
  835.             if(tpcb->tp_xpd_service)
  836.                 IncStat(ts_use_txpd);
  837.             if(tpcb->tp_xtd_format)
  838.                 IncStat(ts_xtd_fmt);
  839.  
  840.             /*
  841.              * Get the maximum transmission unit from the lower layer(s)
  842.              * so we can negotiate a reasonable max TPDU size.
  843.              */
  844.             (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
  845.                         &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
  846.             tpcb->tp_peer_acktime = acktime;
  847.  
  848.             /* 
  849.              * The following kludge is used to test retransmissions and 
  850.              * timeout during connection establishment.
  851.              */
  852.             IFDEBUG(D_ZDREF)
  853.                 IncStat(ts_zdebug);
  854.                 /*tpcb->tp_fref = 0;*/
  855.             ENDDEBUG
  856.         }
  857.         IncStat(ts_CR_rcvd);
  858.         if (!tpcb->tp_cebit_off) {
  859.             tpcb->tp_win_recv = tp_start_win << 8;
  860.             tpcb->tp_cong_sample.cs_size = 0;
  861.             LOCAL_CREDIT(tpcb);
  862.             CONG_INIT_SAMPLE(tpcb);
  863.             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
  864.         }
  865.         tpcb->tp_ackrcvd = 0;
  866.     } else if ( dutype == ER_TPDU_type ) {
  867.         /* 
  868.          * ER TPDUs have to be recognized separately
  869.          * because they don't necessarily have a tpcb
  870.          * with them and we don't want err out looking for such
  871.          * a beast.
  872.          * We could put a bunch of little kludges in the 
  873.          * next section of code so it would avoid references to tpcb
  874.          * if dutype == ER_TPDU_type but we don't want code for ERs to
  875.          * mess up code for data transfer.
  876.          */
  877.         IncStat(ts_ER_rcvd);
  878.         e.ev_number = ER_TPDU;
  879.         e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
  880.         CHECK (((int)dref <= 0 || dref >= N_TPREF || 
  881.             (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ||
  882.             tpcb->tp_refp->tpr_state == REF_FREE ||
  883.             tpcb->tp_refp->tpr_state == REF_FROZEN),
  884.                E_TP_MISM_REFS, ts_inv_dref, discard, 0)
  885.  
  886.     } else {
  887.         /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
  888.  
  889.         /* In the next 4 checks,
  890.          * _tpduf is the fixed part; add 2 to get the dref bits of 
  891.          * the fixed part (can't take the address of a bit field) 
  892.          */
  893. #ifdef old_history
  894.         if(cons_channel) {
  895. #ifdef NARGOXTWENTYFIVE
  896.             extern struct tp_pcb *cons_chan_to_tpcb();
  897.  
  898.             tpcb = cons_chan_to_tpcb( cons_channel );
  899.             /* Problem:  We may have a legit
  900.              * error situation yet we may or may not have 
  901.              * a correspondence between the tpcb and the vc,
  902.              * e.g., TP4cr--> <no dice, respond w/ DR on vc>
  903.              *          <---  DR
  904.              * Now it's up to TP to look at the tpdu and do one of:
  905.              * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
  906.              * nothing, if the circuit is already open (any other tpdu). 
  907.              * Sigh.
  908.              */
  909.  
  910.             /* I don't know about this error value */
  911.             CHECK( (tpcb == (struct tp_pcb *)0) ,
  912.                 E_TP_NO_CR_ON_NC, ts_inv_dref, respond, 
  913.                 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  914. #else
  915.             printf("tp_input(): X25 NOT CONFIGURED!!\n");
  916. #endif
  917.         } else
  918.             /* we've now made the error reporting thing check for
  919.             multiple channels and not close out if more than
  920.             one in use */
  921. #endif old_history
  922.         {
  923.  
  924.             CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
  925.                 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
  926.                 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  927.             CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), 
  928.                 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
  929.                 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  930.             CHECK( (tpcb->tp_refp->tpr_state == REF_FREE), 
  931.                 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
  932.                 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  933.         }
  934.  
  935.         IFDEBUG(D_TPINPUT)
  936.             printf("HAVE A TPCB 2: 0x%x\n", tpcb);
  937.         ENDDEBUG
  938.  
  939.         /* causes a DR to be sent for CC; ER for all else */
  940.         CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
  941.             (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
  942.             ts_inv_dref, respond,
  943.             (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
  944.  
  945.         IFDEBUG(D_TPINPUT)
  946.             printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
  947.         ENDDEBUG
  948.         /* 
  949.          * At this point the state of the dref could be
  950.          * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
  951.          *           for example, DC may arrive after the close() has detached
  952.          *         the tpcb (e.g., if user turned off SO_LISTEN option)
  953.          * OPENING : a tpcb exists but no timers yet
  954.          * OPEN  : tpcb exists & timers are outstanding
  955.          */
  956.  
  957.         if (!tpcb->tp_cebit_off)
  958.             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
  959.  
  960.         dusize = tpcb->tp_tpdusize;
  961.  
  962.         dutype = hdr->tpdu_type << 8; /* for the switch below */ 
  963.  
  964.         WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
  965.  
  966. #define caseof(x,y) case (((x)<<8)+(y))
  967.         switch( dutype | vbptr(P)->tpv_code ) {
  968.  
  969.             caseof( CC_TPDU_type, TPP_addl_opt ): 
  970.                     /* not in class 0; 1 octet */
  971.                     vb_getval(P, u_char, addlopt);
  972.                     break;
  973.             caseof( CC_TPDU_type, TPP_tpdu_size ): 
  974.                 {
  975.                     u_char odusize = dusize;
  976.                     vb_getval(P, u_char, dusize);
  977.                     CHECK( (dusize < TP_MIN_TPDUSIZE ||
  978.                             dusize > TP_MAX_TPDUSIZE || dusize > odusize),
  979.                         E_TP_INV_PVAL, ts_inv_pval, respond,
  980.                         (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
  981.                     IFDEBUG(D_TPINPUT)
  982.                         printf("CC dusize 0x%x\n", dusize);
  983.                     ENDDEBUG
  984.                 }
  985.                     break;
  986.             caseof( CC_TPDU_type, TPP_calling_sufx):
  987.                     IFDEBUG(D_TPINPUT)
  988.                         printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
  989.                     ENDDEBUG
  990.                     lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
  991.                     lsufxlen = vbptr(P)->tpv_len;
  992.                     break;
  993.             caseof(    CC_TPDU_type, TPP_acktime ):
  994.                     /* class 4 only, 2 octets */
  995.                     vb_getval(P, u_short, acktime);
  996.                     acktime = ntohs(acktime);
  997.                     acktime = acktime/500; /* convert to slowtimo ticks */
  998.                     if( (short)acktime <=0 )
  999.                         acktime = 2;
  1000.                     break;
  1001.             caseof(    CC_TPDU_type, TPP_called_sufx):
  1002.                     fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
  1003.                     fsufxlen = vbptr(P)->tpv_len;
  1004.                     IFDEBUG(D_TPINPUT)
  1005.                         printf("CC called (foreign) sufx len %d\n", fsufxlen);
  1006.                     ENDDEBUG
  1007.                     break;
  1008.  
  1009.             caseof( CC_TPDU_type,    TPP_checksum):        
  1010.             caseof( DR_TPDU_type,    TPP_checksum):        
  1011.             caseof( DT_TPDU_type,    TPP_checksum):        
  1012.             caseof( XPD_TPDU_type,    TPP_checksum):        
  1013.                     if( tpcb->tp_use_checksum )  {
  1014.                         CHECK( iso_check_csum(m, tpdu_len), 
  1015.                             E_TP_INV_PVAL, ts_bad_csum, discard, 0)
  1016.                     }
  1017.                     break;
  1018.  
  1019.             /*  this is different from the above because in the context
  1020.              *  of concat/ sep tpdu_len might not be the same as hdr len 
  1021.              */
  1022.             caseof( AK_TPDU_type,    TPP_checksum):        
  1023.             caseof( XAK_TPDU_type,    TPP_checksum):        
  1024.             caseof( DC_TPDU_type,    TPP_checksum):        
  1025.                     if( tpcb->tp_use_checksum )  {
  1026.                         CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), 
  1027.                             E_TP_INV_PVAL, ts_bad_csum, discard, 0)
  1028.                     }
  1029.                     break;
  1030. #ifdef notdef
  1031.             caseof( DR_TPDU_type, TPP_addl_info ):
  1032.                 /* ignore - its length and meaning are
  1033.                  * user defined and there's no way
  1034.                  * to pass this info to the user anyway
  1035.                  */
  1036.                 break;
  1037. #endif notdef
  1038.  
  1039.             caseof( AK_TPDU_type, TPP_subseq ):
  1040.                 /* used after reduction of window */
  1041.                 vb_getval(P, u_short, subseq);
  1042.                 subseq = ntohs(subseq);
  1043.                 IFDEBUG(D_ACKRECV)
  1044.                     printf("AK Subsequence # 0x%x\n", subseq);
  1045.                 ENDDEBUG
  1046.                 break;
  1047.  
  1048.             caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
  1049.                 {
  1050.                     u_int     ylwe;
  1051.                     u_short ysubseq, ycredit;
  1052.  
  1053.                     fcc_present = TRUE;
  1054.                     vb_getval(P, u_int,         ylwe);
  1055.                     vb_getval(P, u_short,     ysubseq);
  1056.                     vb_getval(P, u_short,     ycredit);
  1057.                     ylwe = ntohl(ylwe);
  1058.                     ysubseq = ntohs(ysubseq);
  1059.                     ycredit = ntohs(ycredit);
  1060.                     IFDEBUG(D_ACKRECV)
  1061.                         printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n", 
  1062.                             ylwe, ysubseq, ycredit);
  1063.                     ENDDEBUG
  1064.                 }
  1065.                 break;
  1066.  
  1067.             default: 
  1068.                 IFDEBUG(D_TPINPUT)
  1069.                     printf("param ignored dutype 0x%x, code  0x%x\n",
  1070.                         dutype, vbptr(P)->tpv_code);
  1071.                 ENDDEBUG
  1072.                 IFTRACE(D_TPINPUT)
  1073.                     tptrace(TPPTmisc, "param ignored dutype code ",
  1074.                         dutype, vbptr(P)->tpv_code ,0,0);
  1075.                 ENDTRACE
  1076.                 IncStat(ts_param_ignored);
  1077.                 break;
  1078. #undef caseof
  1079.         }
  1080.         /* } */ END_WHILE_OPTIONS(P)
  1081.  
  1082.         /* NOTE: the variable dutype has been shifted left! */
  1083.  
  1084.         switch( hdr->tpdu_type ) {
  1085.         case CC_TPDU_type: 
  1086.             /* If CC comes back with an unacceptable class
  1087.              * respond with a DR or ER
  1088.              */
  1089.  
  1090.             opt = hdr->tpdu_CCoptions; /* 1 byte */
  1091.  
  1092.             {
  1093.                 tpp = tpcb->_tp_param;
  1094.                 tpp.p_class = (1<<hdr->tpdu_CCclass);
  1095.                 tpp.p_tpdusize = dusize;
  1096.                 tpp.p_dont_change_params = 0;
  1097.                 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
  1098.                 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
  1099.                 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
  1100. #ifdef notdef
  1101.                 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
  1102.                 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
  1103.                 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
  1104. #endif notdef
  1105.  
  1106.             CHECK(
  1107.                 tp_consistency(tpcb, TP_FORCE, &tpp) != 0, 
  1108.                 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
  1109.                 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 
  1110.                     /* ^ more or less the location of class */
  1111.                 )
  1112.             IFTRACE(D_CONN)
  1113.                 tptrace(TPPTmisc, 
  1114.                     "after 1 consist class, out, tpconsout",
  1115.                     tpcb->tp_class, dgout_routine, tpcons_output, 0
  1116.                     );
  1117.             ENDTRACE
  1118.             CHECK(
  1119.                 ((class_to_use == TP_CLASS_0)&&
  1120.                     (dgout_routine != tpcons_output)),
  1121.                 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
  1122.                 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) 
  1123.                     /* ^ more or less the location of class */
  1124.                 )
  1125. #ifdef TPCONS
  1126.                 if (tpcb->tp_netservice == ISO_CONS &&
  1127.                     class_to_use == TP_CLASS_0) {
  1128.                     struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
  1129.                     struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
  1130.                     lcp->lcd_flags &= ~X25_DG_CIRCUIT;
  1131.                 }
  1132. #endif
  1133.             }
  1134.             if( ! tpcb->tp_use_checksum)
  1135.                 IncStat(ts_csum_off);
  1136.             if(tpcb->tp_xpd_service)
  1137.                 IncStat(ts_use_txpd);
  1138.             if(tpcb->tp_xtd_format)
  1139.                 IncStat(ts_xtd_fmt);
  1140.  
  1141.             IFTRACE(D_CONN)
  1142.                 tptrace(TPPTmisc, "after CC class flags dusize CCclass",
  1143.                     tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, 
  1144.                     hdr->tpdu_CCclass);
  1145.             ENDTRACE
  1146.  
  1147.             /* 
  1148.              * Get the maximum transmission unit from the lower layer(s)
  1149.              * so we can decide how large a TPDU size to negotiate.
  1150.              * It would be nice if the arguments to this
  1151.              * were more reasonable.
  1152.              */
  1153.             (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
  1154.                         &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
  1155.  
  1156.  
  1157.             /* if called or calling suffices appeared on the CC, 
  1158.              * they'd better jive with what's in the pcb
  1159.              */
  1160.             if( fsufxlen ) {
  1161.                 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
  1162.                     bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
  1163.                     E_TP_INV_PVAL,ts_inv_sufx, respond, 
  1164.                     (1+fsufxloc - (caddr_t)hdr))
  1165.             }
  1166.             if( lsufxlen ) {
  1167.                 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
  1168.                     bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
  1169.                     E_TP_INV_PVAL,ts_inv_sufx, respond, 
  1170.                     (1+lsufxloc - (caddr_t)hdr))
  1171.             }
  1172.  
  1173.             e.ATTR(CC_TPDU).e_sref =  sref;
  1174.             e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
  1175.             takes_data = TRUE;
  1176.             e.ev_number = CC_TPDU;
  1177.             IncStat(ts_CC_rcvd);
  1178.             break;
  1179.  
  1180.         case DC_TPDU_type:
  1181.             if (sref != tpcb->tp_fref)
  1182.                 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
  1183.                     sref, tpcb->tp_fref);
  1184.                     
  1185.             CHECK( (sref != tpcb->tp_fref), 
  1186.                 E_TP_MISM_REFS, ts_inv_sufx, discard,
  1187.                 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
  1188.         
  1189.             e.ev_number = DC_TPDU;
  1190.             IncStat(ts_DC_rcvd);
  1191.             break;
  1192.  
  1193.         case DR_TPDU_type: 
  1194.             IFTRACE(D_TPINPUT)
  1195.                 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
  1196.             ENDTRACE
  1197.             if (sref != tpcb->tp_fref) {
  1198.                 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
  1199.                     sref, tpcb->tp_fref);
  1200.             }
  1201.                     
  1202.             CHECK( (sref != 0 && sref != tpcb->tp_fref &&
  1203.                     tpcb->tp_state != TP_CRSENT), 
  1204.                 (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
  1205.                 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
  1206.  
  1207.             e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
  1208.             e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
  1209.             takes_data = TRUE;
  1210.             e.ev_number = DR_TPDU;
  1211.             IncStat(ts_DR_rcvd);
  1212.             break;
  1213.  
  1214.         case ER_TPDU_type:
  1215.             IFTRACE(D_TPINPUT)
  1216.                 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
  1217.             ENDTRACE
  1218.             e.ev_number = ER_TPDU;
  1219.             e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
  1220.             IncStat(ts_ER_rcvd);
  1221.             break;
  1222.  
  1223.         case AK_TPDU_type: 
  1224.  
  1225.             e.ATTR(AK_TPDU).e_subseq = subseq;
  1226.             e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
  1227.  
  1228.             if (tpcb->tp_xtd_format) {
  1229. #ifdef BYTE_ORDER
  1230.                 union seq_type seqeotX;
  1231.  
  1232.                 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
  1233.                 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
  1234.                 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
  1235. #else
  1236.                 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
  1237.                 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
  1238. #endif BYTE_ORDER
  1239.             } else {
  1240.                 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
  1241.                 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
  1242.             }
  1243.             IFTRACE(D_TPINPUT)
  1244.                 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", 
  1245.                     e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
  1246.                     subseq, fcc_present);
  1247.             ENDTRACE
  1248.  
  1249.             e.ev_number = AK_TPDU;
  1250.             IncStat(ts_AK_rcvd);
  1251.             IncPStat(tpcb, tps_AK_rcvd);
  1252.             break;
  1253.  
  1254.         case XAK_TPDU_type: 
  1255.             if (tpcb->tp_xtd_format) {
  1256. #ifdef BYTE_ORDER
  1257.                 union seq_type seqeotX;
  1258.  
  1259.                 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
  1260.                 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
  1261. #else
  1262.                 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
  1263. #endif BYTE_ORDER
  1264.             } else {
  1265.                 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
  1266.             }
  1267.             e.ev_number = XAK_TPDU;
  1268.             IncStat(ts_XAK_rcvd);
  1269.             IncPStat(tpcb, tps_XAK_rcvd);
  1270.             break;
  1271.  
  1272.         case XPD_TPDU_type: 
  1273.             if (tpcb->tp_xtd_format) {
  1274. #ifdef BYTE_ORDER
  1275.                 union seq_type seqeotX;
  1276.  
  1277.                 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
  1278.                 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
  1279. #else
  1280.                 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
  1281. #endif BYTE_ORDER
  1282.             } else {
  1283.                 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
  1284.             }
  1285.             takes_data = TRUE;
  1286.             e.ev_number = XPD_TPDU;
  1287.             IncStat(ts_XPD_rcvd);
  1288.             IncPStat(tpcb, tps_XPD_rcvd);
  1289.             break;
  1290.  
  1291.         case DT_TPDU_type:
  1292.             { /* the y option will cause occasional packets to be dropped.
  1293.                * A little crude but it works.
  1294.                */
  1295.  
  1296.                 IFDEBUG(D_DROP)
  1297.                     if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
  1298.                         IncStat(ts_ydebug);
  1299.                         goto discard;
  1300.                     }
  1301.                 ENDDEBUG
  1302.             }
  1303.             if (tpcb->tp_class == TP_CLASS_0) {
  1304.                 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
  1305.                 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
  1306.             } else if (tpcb->tp_xtd_format) {
  1307. #ifdef BYTE_ORDER
  1308.                 union seq_type seqeotX;
  1309.  
  1310.                 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
  1311.                 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
  1312.                 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
  1313. #else
  1314.                 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
  1315.                 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
  1316. #endif BYTE_ORDER
  1317.             } else {
  1318.                 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
  1319.                 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
  1320.             }
  1321.             if(e.ATTR(DT_TPDU).e_eot)
  1322.                 IncStat(ts_eot_input);
  1323.             takes_data = TRUE;
  1324.             e.ev_number = DT_TPDU;
  1325.             IncStat(ts_DT_rcvd);
  1326.             IncPStat(tpcb, tps_DT_rcvd);
  1327.             break;
  1328.  
  1329.         case GR_TPDU_type: 
  1330.             tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
  1331.             /* drop through */
  1332.         default:
  1333.             /* this should NEVER happen because there is a
  1334.              * check for dutype well above here
  1335.              */
  1336.             error = E_TP_INV_TPDU; /* causes an ER  */
  1337.             IFDEBUG(D_TPINPUT)
  1338.                 printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
  1339.             ENDDEBUG
  1340.             IncStat(ts_inv_dutype);
  1341.             goto respond;
  1342.         }
  1343.     }
  1344.     /* peel off the tp header; 
  1345.      * remember that the du_li doesn't count itself.
  1346.      * This may leave us w/ an empty mbuf at the front of a chain.
  1347.      * We can't just throw away the empty mbuf because hdr still points
  1348.      * into the mbuf's data area and we're still using hdr (the tpdu header)
  1349.      */
  1350.     m->m_len -= ((int)hdr->tpdu_li + 1);
  1351.     m->m_data += ((int)hdr->tpdu_li + 1);
  1352.  
  1353.     if (takes_data) {
  1354.         int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
  1355.         int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
  1356.         struct {
  1357.             struct tp_disc_reason dr;
  1358.             struct cmsghdr x_hdr;
  1359.         } x;
  1360. #define c_hdr x.x_hdr
  1361.         register struct mbuf *n;
  1362.  
  1363.         CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
  1364.                 ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
  1365.         switch( hdr->tpdu_type ) {
  1366.  
  1367.         case CR_TPDU_type:
  1368.             c_hdr.cmsg_type = TPOPT_CONN_DATA;
  1369.             goto make_control_msg;
  1370.  
  1371.         case CC_TPDU_type:
  1372.             c_hdr.cmsg_type = TPOPT_CFRM_DATA;
  1373.             goto make_control_msg;
  1374.  
  1375.         case DR_TPDU_type:
  1376.             x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
  1377.             x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
  1378.             x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
  1379.             x.dr.dr_reason = hdr->tpdu_DRreason;
  1380.             c_hdr.cmsg_type = TPOPT_DISC_DATA;
  1381.         make_control_msg:
  1382.             datalen += sizeof(c_hdr);
  1383.             c_hdr.cmsg_len = datalen;
  1384.             c_hdr.cmsg_level = SOL_TRANSPORT;
  1385.             mbtype = MT_CONTROL;
  1386.             MGET(n, M_DONTWAIT, MT_DATA);
  1387.             if (n == 0)
  1388.                 {m_freem(m); m = 0; datalen = 0; goto invoke; }
  1389.             if (hdr->tpdu_type == DR_TPDU_type) {
  1390.                 datalen += sizeof(x) - sizeof(c_hdr);
  1391.                 bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
  1392.             } else
  1393.                 bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
  1394.                       n->m_len = sizeof(c_hdr));
  1395.             n->m_next = m;
  1396.             m = n;
  1397.             /* FALLTHROUGH */
  1398.  
  1399.         case XPD_TPDU_type:
  1400.             if (mbtype != MT_CONTROL)
  1401.                 mbtype = MT_OOBDATA;
  1402.             m->m_flags |= M_EOR;
  1403.             /* FALLTHROUGH */
  1404.  
  1405.         case DT_TPDU_type:
  1406.             for (n = m; n; n = n->m_next) { 
  1407.                 MCHTYPE(n, mbtype);
  1408.             }
  1409.         invoke:
  1410.             e.ATTR(DT_TPDU).e_datalen = datalen;
  1411.             e.ATTR(DT_TPDU).e_data =  m;
  1412.             break;
  1413.  
  1414.         default:
  1415.             printf(
  1416.                 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
  1417.                 hdr->tpdu_type, takes_data, m);
  1418.             break;
  1419.         }
  1420.         /* prevent m_freem() after tp_driver() from throwing it all away */
  1421.         m = MNULL;
  1422.     }
  1423.  
  1424.     IncStat(ts_tpdu_rcvd);
  1425.  
  1426.     IFDEBUG(D_TPINPUT)
  1427.         printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
  1428.             tpcb->tp_state, e.ev_number, m );
  1429.         printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
  1430.         printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
  1431.             takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
  1432.     ENDDEBUG
  1433.  
  1434.     error = tp_driver(tpcb, &e);
  1435.  
  1436.     ASSERT(tpcb != (struct tp_pcb *)0);
  1437.     ASSERT(tpcb->tp_sock != (struct socket *)0);
  1438.     if( tpcb->tp_sock->so_error == 0 )
  1439.         tpcb->tp_sock->so_error = error;
  1440.  
  1441.     /* Kludge to keep the state tables under control (adding
  1442.      * data on connect & disconnect & freeing the mbuf containing
  1443.      * the data would have exploded the tables and made a big mess ).
  1444.      */
  1445.     switch(e.ev_number) {
  1446.         case CC_TPDU:
  1447.         case DR_TPDU:
  1448.         case CR_TPDU:
  1449.             m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
  1450.             IFDEBUG(D_TPINPUT)
  1451.                 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", 
  1452.                 m, takes_data);
  1453.             ENDDEBUG
  1454.             break;
  1455.         default:
  1456.             break;
  1457.     }
  1458.     /* Concatenated sequences are terminated by any tpdu that 
  1459.      * carries data: CR, CC, DT, XPD, DR.
  1460.      * All other tpdu types may be concatenated: AK, XAK, DC, ER.
  1461.      */
  1462.  
  1463. separate:
  1464.     if ( takes_data == 0 )  {
  1465.         ASSERT( m != MNULL );
  1466.         /* 
  1467.          * we already peeled off the prev. tp header so 
  1468.          * we can just pull up some more and repeat
  1469.          */
  1470.  
  1471.         if( m = tp_inputprep(m) ) {
  1472.         IFDEBUG(D_TPINPUT)
  1473.             hdr = mtod(m, struct tpdu *);
  1474.             printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", 
  1475.             hdr, (int) hdr->tpdu_li + 1, m);
  1476.             dump_mbuf(m, "tp_input after driver, at separate");
  1477.         ENDDEBUG
  1478.  
  1479.             IncStat(ts_concat_rcvd);
  1480.             goto again;
  1481.         }
  1482.     }
  1483.     if ( m != MNULL ) {
  1484.         IFDEBUG(D_TPINPUT)
  1485.             printf("tp_input : m_freem(0x%x)\n", m);
  1486.         ENDDEBUG
  1487.         m_freem(m);
  1488.         IFDEBUG(D_TPINPUT)
  1489.             printf("tp_input : after m_freem 0x%x\n", m);
  1490.         ENDDEBUG
  1491.     }
  1492.     return (ProtoHook) tpcb;
  1493.  
  1494. discard:
  1495.     /* class 4: drop the tpdu */
  1496.     /* class 2,0: Should drop the net connection, if you can figure out
  1497.      * to which connection it applies
  1498.      */
  1499.     IFDEBUG(D_TPINPUT)
  1500.         printf("tp_input DISCARD\n");
  1501.     ENDDEBUG
  1502.     IFTRACE(D_TPINPUT)
  1503.         tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
  1504.     ENDTRACE
  1505.     m_freem(m);
  1506.     IncStat(ts_recv_drop);
  1507.     return (ProtoHook)0;
  1508.  
  1509. nonx_dref:
  1510.     switch (dutype) {
  1511.     default:
  1512.         goto discard;
  1513.     case CC_TPDU_type:
  1514.         /* error = E_TP_MISM_REFS; */
  1515.         break;
  1516.     case DR_TPDU_type:
  1517.         error |= TP_ERROR_SNDC;
  1518.     }
  1519. respond:
  1520.     IFDEBUG(D_TPINPUT)
  1521.         printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
  1522.     ENDDEBUG
  1523.     IFTRACE(D_TPINPUT)
  1524.         tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
  1525.     ENDTRACE
  1526.     if (sref == 0)
  1527.         goto discard;
  1528.     (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
  1529.                 (struct sockaddr_iso *)laddr, m, errlen, tpcb,
  1530.                 (int)cons_channel, dgout_routine);
  1531.     IFDEBUG(D_ERROR_EMIT)
  1532.         printf("tp_input after error_emit\n");
  1533.     ENDDEBUG
  1534.  
  1535. #ifdef lint
  1536.     printf("",sref,opt);
  1537. #endif lint
  1538.     IncStat(ts_recv_drop);
  1539.     return (ProtoHook)0;
  1540. }
  1541.  
  1542.  
  1543. /*
  1544.  * NAME: tp_headersize()
  1545.  *
  1546.  * CALLED FROM:
  1547.  *  tp_emit() and tp_sbsend()
  1548.  *  TP needs to know the header size so it can figure out how
  1549.  *  much data to put in each tpdu.
  1550.  *
  1551.  * FUNCTION, ARGUMENTS, and RETURN VALUE:
  1552.  *  For a given connection, represented by (tpcb), and 
  1553.  *  tpdu type (dutype), return the size of a tp header.
  1554.  *
  1555.  * RETURNS:      the expected size of the heade in bytesr
  1556.  *
  1557.  * SIDE EFFECTS:    
  1558.  *
  1559.  * NOTES:     It would be nice if it got the network header size as well.
  1560.  */
  1561. int
  1562. tp_headersize(dutype, tpcb) 
  1563.     int             dutype;
  1564.     struct tp_pcb     *tpcb;
  1565. {
  1566.     register int size = 0;
  1567.  
  1568.     IFTRACE(D_CONN)
  1569.         tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
  1570.             dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
  1571.     ENDTRACE
  1572.     if( !( (tpcb->tp_class == TP_CLASS_0) || 
  1573.             (tpcb->tp_class == TP_CLASS_4) || 
  1574.             (dutype == DR_TPDU_type) || 
  1575.             (dutype == CR_TPDU_type) )) {
  1576.                 printf("tp_headersize:dutype 0x%x, class 0x%x", 
  1577.             dutype, tpcb->tp_class);
  1578.     /* TODO: identify this and GET RID OF IT */
  1579.     }
  1580.     ASSERT( (tpcb->tp_class == TP_CLASS_0) || 
  1581.             (tpcb->tp_class == TP_CLASS_4) || 
  1582.             (dutype == DR_TPDU_type) || 
  1583.             (dutype == CR_TPDU_type) );
  1584.  
  1585.     if( tpcb->tp_class == TP_CLASS_0 ) {
  1586.         size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
  1587.     } else  {
  1588.         size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
  1589.     } 
  1590.     return size;
  1591.     /* caller must get network level header size separately */
  1592. }
  1593.