The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_input.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: e390130be238ca2dfbf5780e7442be95


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.