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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 9309fc7bf0e5aeebac47ff889d28fdbd


[ 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.