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

Cache object: 0d12567ddba00acbe3905552ecc16a9f


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