xref: /csrg-svn/sys/netiso/tp_input.c (revision 63222)
149268Sbostic /*-
2*63222Sbostic  * Copyright (c) 1991, 1993
3*63222Sbostic  *	The Regents of the University of California.  All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*63222Sbostic  *	@(#)tp_input.c	8.1 (Berkeley) 06/10/93
849268Sbostic  */
949268Sbostic 
1036401Ssklower /***********************************************************
1136401Ssklower 		Copyright IBM Corporation 1987
1236401Ssklower 
1336401Ssklower                       All Rights Reserved
1436401Ssklower 
1536401Ssklower Permission to use, copy, modify, and distribute this software and its
1636401Ssklower documentation for any purpose and without fee is hereby granted,
1736401Ssklower provided that the above copyright notice appear in all copies and that
1836401Ssklower both that copyright notice and this permission notice appear in
1936401Ssklower supporting documentation, and that the name of IBM not be
2036401Ssklower used in advertising or publicity pertaining to distribution of the
2136401Ssklower software without specific, written prior permission.
2236401Ssklower 
2336401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936401Ssklower SOFTWARE.
3036401Ssklower 
3136401Ssklower ******************************************************************/
3236401Ssklower 
3336401Ssklower /*
3436401Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536401Ssklower  */
3636401Ssklower /*
3736401Ssklower  * ARGO TP
3836401Ssklower  *
3936401Ssklower  * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
4036401Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
4136401Ssklower  *
4236401Ssklower  * tp_input() gets an mbuf chain from ip.  Actually, not directly
4336401Ssklower  * from ip, because ip calls a net-level routine that strips off
4436401Ssklower  * the net header and then calls tp_input(), passing the proper type
4536401Ssklower  * of addresses for the address family in use (how it figures out
4650648Ssklower  * which AF is not yet determined.)
4736401Ssklower  *
4836401Ssklower  * Decomposing the tpdu is some of the most laughable code.  The variable-length
4936401Ssklower  * parameters and the problem of non-aligned memory references
5036401Ssklower  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
5136401Ssklower  * to loop through the header and decompose it.
5236401Ssklower  *
5336401Ssklower  * The routine tp_newsocket() is called when a CR comes in for a listening
5436401Ssklower  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
5536401Ssklower  * "child" socket.  Most tpcb values are copied from the parent tpcb into
5636401Ssklower  * the child.
5736401Ssklower  *
5836401Ssklower  * Also in here is tp_headersize() (grot) which tells the expected size
5936401Ssklower  * of a tp header, to be used by other layers.  It's in here because it
6036401Ssklower  * uses the static structure tpdu_info.
6136401Ssklower  */
6236401Ssklower 
6356533Sbostic #include <sys/param.h>
6456533Sbostic #include <sys/systm.h>
6556533Sbostic #include <sys/mbuf.h>
6656533Sbostic #include <sys/socket.h>
6756533Sbostic #include <sys/socketvar.h>
6856533Sbostic #include <sys/domain.h>
6956533Sbostic #include <sys/protosw.h>
7056533Sbostic #include <sys/errno.h>
7156533Sbostic #include <sys/time.h>
7256533Sbostic #include <sys/kernel.h>
7336401Ssklower 
7456533Sbostic #include <netiso/iso.h>
7556533Sbostic #include <netiso/iso_errno.h>
7656533Sbostic #include <netiso/iso_pcb.h>
7756533Sbostic #include <netiso/tp_param.h>
7856533Sbostic #include <netiso/tp_timer.h>
7956533Sbostic #include <netiso/tp_stat.h>
8056533Sbostic #include <netiso/tp_pcb.h>
8156533Sbostic #include <netiso/argo_debug.h>
8256533Sbostic #include <netiso/tp_trace.h>
8356533Sbostic #include <netiso/tp_tpdu.h>
8456533Sbostic 
8556533Sbostic #include <net/if.h>
8645900Ssklower #ifdef TRUE
8745900Ssklower #undef FALSE
8845900Ssklower #undef TRUE
8945900Ssklower #endif
9056533Sbostic #include <netccitt/x25.h>
9156533Sbostic #include <netccitt/pk.h>
9256533Sbostic #include <netccitt/pk_var.h>
9345900Ssklower 
9436401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
9536401Ssklower 
9637469Ssklower /*
9737469Ssklower 	#ifdef lint
9837469Ssklower 	#undef ATTR
9937469Ssklower 	#define ATTR(X)ev_number
10037469Ssklower 	#endif lint
10137469Ssklower */
10236401Ssklower 
10336401Ssklower struct mbuf *
tp_inputprep(m)10436401Ssklower tp_inputprep(m)
10537469Ssklower 	register struct mbuf *m;
10636401Ssklower {
10737469Ssklower 	int hdrlen;
10836401Ssklower 
10936401Ssklower 	IFDEBUG(D_TPINPUT)
11037469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
11136401Ssklower 	ENDDEBUG
11236401Ssklower 
11336401Ssklower 	while(  m->m_len < 1 ) {
11455437Ssklower 	    /* The "m_free" logic
11555437Ssklower 	     * if( (m = m_free(m)) == MNULL )
11655437Ssklower 	     *      return (struct mbuf *)0;
11755437Ssklower 		 * would cause a system crash if ever executed.
11855437Ssklower 		 * This logic will be executed if the first mbuf
11955437Ssklower 	     * in the chain only contains a CLNP header. The m_free routine
12055437Ssklower 	     * will release the mbuf containing the CLNP header from the
12155437Ssklower 	     * chain and the new head of the chain will not have the
12255437Ssklower 	     * M_PKTHDR bit set. This routine, tp_inputprep, will
12355437Ssklower 	     * eventually call the "sbappendaddr" routine. "sbappendaddr"
12455437Ssklower 	     * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap
12555437Ssklower 	     * way of keeping the head of the chain from being freed.
12655437Ssklower 		 */
12755550Ssklower 		if((m = m_pullup(m, 1)) == MNULL)
12855437Ssklower 			return (MNULL);
12936401Ssklower 	}
13037469Ssklower 	if(((int)m->m_data) & 0x3) {
13137469Ssklower 		/* If we are not 4-byte aligned, we have to be
13237469Ssklower 		 * above the beginning of the mbuf, and it is ok just
13337469Ssklower 		 * to slide it back.
13437469Ssklower 		 */
13537469Ssklower 		caddr_t ocp = m->m_data;
13636401Ssklower 
13737469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
13852465Smckusick 		bcopy(ocp, m->m_data, (unsigned)m->m_len);
13936401Ssklower 	}
14036401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
14136401Ssklower 
14237469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
14337469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
14436401Ssklower 
14537469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
14636401Ssklower 
14736401Ssklower 	/*
14836401Ssklower 	 * now pull up the whole tp header
14936401Ssklower 	 */
15037469Ssklower 	if ( m->m_len < hdrlen) {
15137469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
15236401Ssklower 			IncStat(ts_recv_drop);
15336401Ssklower 			return (struct mbuf *)0;
15436401Ssklower 		}
15536401Ssklower 	}
15636401Ssklower 	IFDEBUG(D_INPUT)
15736401Ssklower 	printf(
15836401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
15937469Ssklower 		hdrlen, m->m_len);
16036401Ssklower 	ENDDEBUG
16136401Ssklower 	return m;
16236401Ssklower }
16336401Ssklower 
16436401Ssklower /* begin groan
16536401Ssklower  * -- this array and the following macros allow you to step through the
16636401Ssklower  * parameters of the variable part of a header
16736401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
16836401Ssklower  * should change, this array has to be rearranged
16936401Ssklower  */
17036401Ssklower 
17136401Ssklower #define TP_LEN_CLASS_0_INDEX	2
17236401Ssklower #define TP_MAX_DATA_INDEX 3
17336401Ssklower 
17436401Ssklower static u_char tpdu_info[][4] =
17536401Ssklower {
17636401Ssklower /*								length						 max data len */
17736401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
17836401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
17936401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
18036401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
18136401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
18236401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
18336401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
18436401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
18536401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
18636401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
18736401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
18836401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
18936401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
19036401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
19136401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
19236401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
19336401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
19436401Ssklower };
19536401Ssklower 
19642944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
19755437Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\
19842944Ssklower 	goto Whattodo; }
19942944Ssklower 
20036401Ssklower /*
20136401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
20236401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
20336401Ssklower  */
20436401Ssklower 
20542944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
20642944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
20742944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
20842944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
20942944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
21042944Ssklower 				respond, P - (caddr_t)hdr);\
21142944Ssklower 		if (P == PLIM) break;
21236401Ssklower 
21342944Ssklower #define END_WHILE_OPTIONS(P) } }
21436401Ssklower 
21536401Ssklower /* end groan */
21636401Ssklower 
21736401Ssklower /*
21836401Ssklower  * NAME:  tp_newsocket()
21936401Ssklower  *
22036401Ssklower  * CALLED FROM:
22136401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
22236401Ssklower  * is awaiting a  connection request
22336401Ssklower  *
22436401Ssklower  * FUNCTION and ARGUMENTS:
22536401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
22636401Ssklower  *  using a copy of the net level pcb for the parent socket.
22736401Ssklower  *  (so) is the parent socket.
22836401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
22936401Ssklower  *
23036401Ssklower  * RETURN VALUE:
23136401Ssklower  *  a new socket structure, being this end of the newly formed connection.
23236401Ssklower  *
23336401Ssklower  * SIDE EFFECTS:
23436401Ssklower  *  Sets a few things in the tpcb and net level pcb
23536401Ssklower  *
23636401Ssklower  * NOTES:
23736401Ssklower  */
23836401Ssklower static struct socket *
tp_newsocket(so,fname,cons_channel,class_to_use,netservice)23936401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
24036401Ssklower 	struct socket				*so;
24136401Ssklower 	struct sockaddr				*fname;
24250648Ssklower 	caddr_t						cons_channel;
24336401Ssklower 	u_char						class_to_use;
24436401Ssklower 	u_int						netservice;
24536401Ssklower {
24636401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
24745900Ssklower 	register struct tp_pcb	*newtpcb;
24836401Ssklower 
24936401Ssklower 	/*
25036401Ssklower 	 * sonewconn() gets a new socket structure,
25136401Ssklower 	 * a new lower layer pcb and a new tpcb,
25236401Ssklower 	 * but the pcbs are unnamed (not bound)
25336401Ssklower 	 */
25436401Ssklower 	IFTRACE(D_NEWSOCK)
25538841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
25639196Ssklower 			so, tpcb, so->so_head, 0);
25736401Ssklower 	ENDTRACE
25836401Ssklower 
25940636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
26036401Ssklower 		return so;
26136401Ssklower 	IFTRACE(D_NEWSOCK)
26238841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
26338841Ssklower 			so, so->so_head, 0, 0);
26436401Ssklower 	ENDTRACE
26536401Ssklower 
26636401Ssklower 	IFDEBUG(D_NEWSOCK)
26737469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
26837469Ssklower 				cons_channel, so);
26937469Ssklower 		dump_addr(fname);
27036401Ssklower 		{
27136401Ssklower 			struct socket *t, *head ;
27236401Ssklower 
27336401Ssklower 			head = so->so_head;
27436401Ssklower 			t = so;
27536401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
27636401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
27736401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
27836401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
27936401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
28036401Ssklower 		}
28136401Ssklower 	ENDDEBUG
28236401Ssklower 
28336401Ssklower 	/*
28436401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
28536401Ssklower 	 */
28636401Ssklower 	newtpcb = sototpcb(so);
28736401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
28836401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
28936401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
29036401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
29136401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
29236401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
29336401Ssklower 
29437469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
29536401Ssklower 		/*
29637469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
29736401Ssklower 		 */
29836401Ssklower 		struct mbuf *conndata;
29936401Ssklower 
30037469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
30136401Ssklower 		IFDEBUG(D_CONN)
30236401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
30336401Ssklower 		ENDDEBUG
30437469Ssklower 		newtpcb->tp_ucddata = conndata;
30536401Ssklower 	}
30636401Ssklower 
30736401Ssklower 	tpcb = newtpcb;
30836401Ssklower 	tpcb->tp_state = TP_LISTENING;
30936401Ssklower 	tpcb->tp_class = class_to_use;
31036401Ssklower 	tpcb->tp_netservice = netservice;
31136401Ssklower 
31236401Ssklower 
31336401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
31436401Ssklower 	if ( fname ) {
31536401Ssklower 		/*
31636401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
31736401Ssklower 		 */
31836401Ssklower 		struct mbuf	*m;
31936401Ssklower 		int			err;
32036401Ssklower 
32136401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
32236401Ssklower 		if (m) {
32336401Ssklower 			/*
32436401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
32536401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
32636401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
32736401Ssklower 			 * sigh.
32836401Ssklower 			 */
32937469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
33037469Ssklower 			m->m_len = fname->sa_len;
33136401Ssklower 
33236401Ssklower 			/* grot  : have to say the kernel can override params in
33336401Ssklower 			 * the passive open case
33436401Ssklower 			 */
33536401Ssklower 			tpcb->tp_dont_change_params = 0;
33636401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
33736401Ssklower 			m_free(m);
33836401Ssklower 
33936401Ssklower 			if (!err)
34036401Ssklower 				goto ok;
34136401Ssklower 		}
34236401Ssklower 		IFDEBUG(D_CONN)
34336401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
34436401Ssklower 				tpcb, so);
34536401Ssklower 		ENDDEBUG
34636401Ssklower 		(void) tp_detach(tpcb);
34736401Ssklower 		return 0;
34836401Ssklower 	}
34936401Ssklower ok:
35036401Ssklower 	IFDEBUG(D_TPINPUT)
35136401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
35236401Ssklower 			so, sototpcb(so));
35336401Ssklower 	ENDDEBUG
35436401Ssklower 	return so;
35536401Ssklower }
35636401Ssklower 
35745900Ssklower #ifndef TPCONS
tpcons_output()35836401Ssklower tpcons_output()
35936401Ssklower {
36036401Ssklower 	return(0);
36136401Ssklower }
36260359Sbostic #endif /* !CONS */
36336401Ssklower 
36436401Ssklower /*
36536401Ssklower  * NAME: 	tp_input()
36636401Ssklower  *
36736401Ssklower  * CALLED FROM:
36836401Ssklower  *  net layer input routine
36936401Ssklower  *
37036401Ssklower  * FUNCTION and ARGUMENTS:
37136401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
37236401Ssklower  *  is one. Create the appropriate type of event and call the driver.
37336401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
37436401Ssklower  *
37536401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
37636401Ssklower  * 	has been m_pullup-ed.
37736401Ssklower  *
37836401Ssklower  * RETURN VALUE: Nada
37936401Ssklower  *
38036401Ssklower  * SIDE EFFECTS:
38136401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
38236401Ssklower  *
38336401Ssklower  * NOTE:
38436401Ssklower  *  The initial value of acktime is 2 so that we will never
38536401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
38636401Ssklower  *  computation of the retransmission timer value, and so it
38736401Ssklower  *  mustn't be zero.
38836401Ssklower  *  2 seems like a reasonable minimum.
38936401Ssklower  */
39036401Ssklower ProtoHook
tp_input(m,faddr,laddr,cons_channel,dgout_routine,ce_bit)39139929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
39236401Ssklower 	register	struct mbuf 	*m;
39336401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
39450648Ssklower 	caddr_t						cons_channel;
39536401Ssklower 	int 						(*dgout_routine)();
39639929Ssklower 	int							ce_bit;
39736401Ssklower 
39836401Ssklower {
39955437Ssklower 	register struct tp_pcb 	*tpcb;
40044947Ssklower 	register struct tpdu 	*hdr;
40136401Ssklower 	struct socket 			*so;
40236401Ssklower 	struct tp_event 		e;
40355437Ssklower 	int 					error;
40436401Ssklower 	unsigned 				dutype;
40555437Ssklower 	u_short 				dref, sref, acktime, subseq;
40655437Ssklower 	u_char 					preferred_class, class_to_use, pdusize;
40755437Ssklower 	u_char					opt, dusize, addlopt, version;
40836401Ssklower #ifdef TP_PERF_MEAS
40938841Ssklower 	u_char					perf_meas;
41060359Sbostic #endif /* TP_PERF_MEAS */
41155437Ssklower 	u_char					fsufxlen, lsufxlen;
41255437Ssklower 	caddr_t					fsufxloc, lsufxloc;
41355437Ssklower 	int						tpdu_len;
41455437Ssklower 	u_int 					takes_data;
41555437Ssklower 	u_int					fcc_present;
41655437Ssklower 	int						errlen;
41736401Ssklower 	struct tp_conn_param 	tpp;
41836401Ssklower 	int						tpcons_output();
41936401Ssklower 
42038841Ssklower again:
42144947Ssklower 	hdr = mtod(m, struct tpdu *);
42255437Ssklower 	tpcb = 0;
42355550Ssklower 	error = errlen = tpdu_len = 0;
42455437Ssklower 	takes_data = fcc_present = FALSE;
42555437Ssklower 	acktime = 2; sref = subseq = 0;
42655550Ssklower 	fsufxloc = lsufxloc = NULL;
42755437Ssklower 	fsufxlen = lsufxlen =
42855437Ssklower 		preferred_class = class_to_use = pdusize = addlopt = 0;
42955437Ssklower 	dusize = TP_DFL_TPDUSIZE;
43036401Ssklower #ifdef TP_PERF_MEAS
43138841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
43260359Sbostic #endif /* TP_PERF_MEAS */
43336401Ssklower 
43436401Ssklower 	IFDEBUG(D_TPINPUT)
43536401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
43636401Ssklower 	ENDDEBUG
43736401Ssklower 
43836401Ssklower 
43936401Ssklower 	/*
44036401Ssklower 	 * get the actual tpdu length - necessary for monitoring
44136401Ssklower 	 * and for checksumming
44236401Ssklower 	 *
44336401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
44436401Ssklower 	 */
44536401Ssklower 
44636401Ssklower 	{ 	register struct mbuf *n=m;
44736401Ssklower #	ifdef ARGO_DEBUG
44836401Ssklower 		int chain_length = 0;
44936401Ssklower #	endif ARGO_DEBUG
45036401Ssklower 
45136401Ssklower 		for(;;) {
45236401Ssklower 			tpdu_len += n->m_len;
45336401Ssklower 			IFDEBUG(D_MBUF_MEAS)
45437469Ssklower 				if( n->m_flags & M_EXT) {
45536401Ssklower 					IncStat(ts_mb_cluster);
45636401Ssklower 				} else {
45736401Ssklower 					IncStat(ts_mb_small);
45836401Ssklower 				}
45936401Ssklower 				chain_length ++;
46036401Ssklower 			ENDDEBUG
46136401Ssklower 			if (n->m_next == MNULL ) {
46236401Ssklower 				break;
46336401Ssklower 			}
46436401Ssklower 			n = n->m_next;
46536401Ssklower 		}
46636401Ssklower 		IFDEBUG(D_MBUF_MEAS)
46736401Ssklower 			if(chain_length > 16)
46836401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
46936401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
47036401Ssklower 		ENDDEBUG
47136401Ssklower 	}
47236401Ssklower 	IFTRACE(D_TPINPUT)
47336401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
47436401Ssklower 			0);
47536401Ssklower 	ENDTRACE
47636401Ssklower 
47736401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
47836401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
47936401Ssklower 	dutype = (int)hdr->tpdu_type;
48036401Ssklower 
48136401Ssklower 	IFDEBUG(D_TPINPUT)
48236401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
48336401Ssklower 			cons_channel, dref);
48436401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
48536401Ssklower 	ENDDEBUG
48636401Ssklower 	IFTRACE(D_TPINPUT)
48736401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
48836401Ssklower 			cons_channel, dutype, dref, 0);
48936401Ssklower 	ENDTRACE
49036401Ssklower 
49136401Ssklower 
49236401Ssklower #ifdef ARGO_DEBUG
49336401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
49436401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
49536401Ssklower 			dutype, cons_channel, dref);
49636401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
49736401Ssklower 
49836401Ssklower 		IncStat(ts_inv_dutype);
49936401Ssklower 		goto discard;
50036401Ssklower 	}
50160359Sbostic #endif /* ARGO_DEBUG */
50236401Ssklower 
50336401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
50436401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
50536401Ssklower 		2 );
50636401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
50736401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
50836401Ssklower 		 */
50936401Ssklower 
51036401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
51136401Ssklower 	 * at the beginning of connection establishment, and by
51236401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
51336401Ssklower 	 */
51436401Ssklower 	if ( dutype == CR_TPDU_type ) {
51536401Ssklower 		u_char alt_classes = 0;
51636401Ssklower 
51737469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
51836401Ssklower 		opt = hdr->tpdu_CRoptions;
51936401Ssklower 
52036401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
52136401Ssklower 
52236401Ssklower 			switch( vbptr(P)->tpv_code ) {
52336401Ssklower 
52436401Ssklower 			case	TPP_tpdu_size:
52536401Ssklower 				vb_getval(P, u_char, dusize);
52636401Ssklower 				IFDEBUG(D_TPINPUT)
52736401Ssklower 					printf("CR dusize 0x%x\n", dusize);
52836401Ssklower 				ENDDEBUG
52942944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
53042944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
53142944Ssklower 						dusize = TP_DFL_TPDUSIZE;
53236401Ssklower 				break;
53351996Ssklower 			case	TPP_ptpdu_size:
53451996Ssklower 				switch (vbptr(P)->tpv_len) {
53551996Ssklower 				case 1: pdusize = vbval(P, u_char); break;
53651996Ssklower 				case 2: pdusize = ntohs(vbval(P, u_short)); break;
53751996Ssklower 				default: ;
53851996Ssklower 				IFDEBUG(D_TPINPUT)
53951996Ssklower 					printf("malformed prefered TPDU option\n");
54051996Ssklower 				ENDDEBUG
54151996Ssklower 				}
54251996Ssklower 				break;
54336401Ssklower 			case	TPP_addl_opt:
54436401Ssklower 				vb_getval(P, u_char, addlopt);
54536401Ssklower 				break;
54636401Ssklower 			case	TPP_calling_sufx:
54736401Ssklower 				/* could use vb_getval, but we want to save the loc & len
54836401Ssklower 				 * for later use
54936401Ssklower 				 */
55036401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
55136401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
55236401Ssklower 				IFDEBUG(D_TPINPUT)
55336401Ssklower 					printf("CR fsufx:");
55436401Ssklower 					{ register int j;
55536401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
55636401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
55736401Ssklower 						}
55836401Ssklower 						printf("\n");
55936401Ssklower 					}
56036401Ssklower 				ENDDEBUG
56136401Ssklower 				break;
56236401Ssklower 			case	TPP_called_sufx:
56336401Ssklower 				/* could use vb_getval, but we want to save the loc & len
56436401Ssklower 				 * for later use
56536401Ssklower 				 */
56636401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
56736401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
56836401Ssklower 				IFDEBUG(D_TPINPUT)
56936401Ssklower 					printf("CR lsufx:");
57036401Ssklower 					{ register int j;
57136401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
57237469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
57336401Ssklower 						}
57436401Ssklower 						printf("\n");
57536401Ssklower 					}
57636401Ssklower 				ENDDEBUG
57736401Ssklower 				break;
57836401Ssklower 
57936401Ssklower #ifdef TP_PERF_MEAS
58036401Ssklower 			case	TPP_perf_meas:
58136401Ssklower 				vb_getval(P, u_char, perf_meas);
58236401Ssklower 				break;
58360359Sbostic #endif /* TP_PERF_MEAS */
58436401Ssklower 
58536401Ssklower 			case	TPP_vers:
58636401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
58742944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
58836401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
58942491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
59042944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
59142491Ssklower 			setversion:
59242491Ssklower 				version = vbval(P, u_char);
59336401Ssklower 				break;
59436401Ssklower 			case	TPP_acktime:
59536401Ssklower 				vb_getval(P, u_short, acktime);
59636401Ssklower 				acktime = ntohs(acktime);
59736401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
59836401Ssklower 				if((short)acktime <=0 )
59936401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
60036401Ssklower 				IFDEBUG(D_TPINPUT)
60136401Ssklower 					printf("CR acktime 0x%x\n", acktime);
60236401Ssklower 				ENDDEBUG
60336401Ssklower 				break;
60436401Ssklower 
60536401Ssklower 			case	TPP_alt_class:
60636401Ssklower 				{
60736401Ssklower 					u_char *aclass = 0;
60836401Ssklower 					register int i;
60942944Ssklower 					static u_char bad_alt_classes[5] =
61042944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
61136401Ssklower 
61242944Ssklower 					aclass =
61342944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
61436401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
61542944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
61636401Ssklower 					}
61742944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
61842944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
61942944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
62036401Ssklower 					IFDEBUG(D_TPINPUT)
62136401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
62236401Ssklower 					ENDDEBUG
62336401Ssklower 				}
62436401Ssklower 				break;
62536401Ssklower 
62636401Ssklower 			case	TPP_security:
62736401Ssklower 			case	TPP_residER:
62836401Ssklower 			case	TPP_priority:
62936401Ssklower 			case	TPP_transdelay:
63036401Ssklower 			case	TPP_throughput:
63136401Ssklower 			case	TPP_addl_info:
63236401Ssklower 			case	TPP_subseq:
63344947Ssklower 			default:
63436401Ssklower 				IFDEBUG(D_TPINPUT)
63536401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
63636401Ssklower 						 vbptr(P)->tpv_code);
63736401Ssklower 				ENDDEBUG
63836401Ssklower 				IncStat(ts_param_ignored);
63936401Ssklower 				break;
64036401Ssklower 
64136401Ssklower 			case	TPP_checksum:
64236401Ssklower 				IFDEBUG(D_TPINPUT)
64336401Ssklower 					printf("CR before cksum\n");
64436401Ssklower 				ENDDEBUG
64536401Ssklower 
64636401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
64736401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
64836401Ssklower 
64936401Ssklower 				IFDEBUG(D_TPINPUT)
65036401Ssklower 					printf("CR before cksum\n");
65136401Ssklower 				ENDDEBUG
65236401Ssklower 				break;
65336401Ssklower 			}
65436401Ssklower 
65536401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
65636401Ssklower 
65744422Ssklower 		if (lsufxlen == 0) {
65836401Ssklower 			/* can't look for a tpcb w/o any called sufx */
65936401Ssklower 			error =  E_TP_LENGTH_INVAL;
66036401Ssklower 			IncStat(ts_inv_sufx);
66136401Ssklower 			goto respond;
66236401Ssklower 		} else {
66344422Ssklower 			register struct tp_pcb *t;
66450648Ssklower 			/*
66550648Ssklower 			 * The intention here is to trap all CR requests
66650648Ssklower 			 * to a given nsap, for constructing transport
66750648Ssklower 			 * service bridges at user level; so these
66850648Ssklower 			 * intercepts should precede the normal listens.
66950648Ssklower 			 * Phrasing the logic in this way also allows for
67050648Ssklower 			 * mop-up listeners, which we don't currently implement.
67150648Ssklower 			 * We also wish to have a single socket be able to
67250648Ssklower 			 * listen over any network service provider,
67350648Ssklower 			 * (cons or clns or ip).
67450648Ssklower 			 */
67550648Ssklower 			for (t = tp_listeners; t ; t = t->tp_nextlisten)
67650648Ssklower 				if ((t->tp_lsuffixlen == 0 ||
67750648Ssklower 					 (lsufxlen == t->tp_lsuffixlen &&
67850648Ssklower 					  bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) &&
67950648Ssklower 					((t->tp_flags & TPF_GENERAL_ADDR) ||
68050648Ssklower 					 (laddr->sa_family == t->tp_domain &&
68150648Ssklower 					  (*t->tp_nlproto->nlp_cmpnetaddr)
68250648Ssklower 								(t->tp_npcb, laddr, TP_LOCAL))))
68350648Ssklower 					break;
68436401Ssklower 
68544422Ssklower 			CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
68636401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
68736401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
68836401Ssklower 				 * the fixed part (can't take the address of a bit field)
68936401Ssklower 				 */
69044601Ssklower 			IFDEBUG(D_TPINPUT)
69144601Ssklower 				printf("checking if dup CR\n");
69244601Ssklower 			ENDDEBUG
69344422Ssklower 			tpcb = t;
69444422Ssklower 			for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
69544422Ssklower 				if (sref != t->tp_fref)
69644422Ssklower 					continue;
69744422Ssklower 				if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
69844422Ssklower 						t->tp_npcb, faddr, TP_FOREIGN)) {
69944422Ssklower 					IFDEBUG(D_TPINPUT)
70044422Ssklower 						printf("duplicate CR discarded\n");
70144422Ssklower 					ENDDEBUG
70244422Ssklower 					goto discard;
70344422Ssklower 				}
70444422Ssklower 			}
70544422Ssklower 			IFTRACE(D_TPINPUT)
70644422Ssklower 				tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
70744422Ssklower 					tpcb, *lsufxloc, tpcb->tp_state, 0);
70844422Ssklower 			ENDTRACE
70936401Ssklower 		}
71036401Ssklower 
71136401Ssklower 		/*
71236401Ssklower 		 * WE HAVE A TPCB
71336401Ssklower 		 * already know that the classes in the CR match at least
71436401Ssklower 		 * one class implemented, but we don't know yet if they
71536401Ssklower 		 * include any classes permitted by this server.
71636401Ssklower 		 */
71736401Ssklower 
71836401Ssklower 		IFDEBUG(D_TPINPUT)
71936401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
72036401Ssklower 		ENDDEBUG
72136401Ssklower 		IFDEBUG(D_CONN)
72236401Ssklower 			printf(
72336401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
72436401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
72536401Ssklower 		ENDDEBUG
72636401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
72736401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
72836401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
72936401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
73036401Ssklower 
73136401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
73236401Ssklower 
73336401Ssklower 		{
73436401Ssklower 			tpp = tpcb->_tp_param;
73536401Ssklower 			tpp.p_class = class_to_use;
73636401Ssklower 			tpp.p_tpdusize = dusize;
73751996Ssklower 			tpp.p_ptpdusize = pdusize;
73836401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
73936401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
74036401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
74136401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
74242491Ssklower 			tpp.p_version = version;
74336401Ssklower #ifdef notdef
74436401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
74536401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
74636401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
74760359Sbostic #endif /* notdef */
74836401Ssklower 
74936401Ssklower 		CHECK(
75036401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
75150648Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
75236401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
75336401Ssklower 				/* ^ more or less the location of class */
75436401Ssklower 			)
75536401Ssklower 		}
75636401Ssklower 		IFTRACE(D_CONN)
75736401Ssklower 			tptrace(TPPTmisc,
75836401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
75936401Ssklower 				class_to_use,
76036401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
76136401Ssklower 				);
76236401Ssklower 		ENDTRACE
76336401Ssklower 		CHECK(
76436401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
76550648Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
76636401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
76736401Ssklower 				/* ^ more or less the location of class */
76836401Ssklower 			)
76936401Ssklower 		IFDEBUG(D_CONN)
77036401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
77136401Ssklower 				tpcb, tpcb->tp_flags);
77236401Ssklower 		ENDDEBUG
77336401Ssklower 		takes_data = TRUE;
77436401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
77536401Ssklower 		e.ev_number = CR_TPDU;
77636401Ssklower 
77736401Ssklower 		so = tpcb->tp_sock;
77836401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
77944422Ssklower 			struct tp_pcb *parent_tpcb = tpcb;
78036401Ssklower 			/*
78136401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
78236401Ssklower 			 * for this newborn connection, and fill in all the values.
78336401Ssklower 			 */
78436401Ssklower 			IFDEBUG(D_CONN)
78536401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
78636401Ssklower 					so, laddr, faddr, cons_channel);
78736401Ssklower 			ENDDEBUG
78836401Ssklower 			if( (so =
78936401Ssklower 				tp_newsocket(so, faddr, cons_channel,
79036401Ssklower 					class_to_use,
79137469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
79237469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
79336401Ssklower 					) == (struct socket *)0 ) {
79436401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
79536401Ssklower 				 * the tp entity is concerned, the only differences
79637469Ssklower 				 * are CO vs CL
79736401Ssklower 				 */
79836401Ssklower 				IFDEBUG(D_CONN)
79936401Ssklower 					printf("tp_newsocket returns 0\n");
80036401Ssklower 				ENDDEBUG
80136401Ssklower 				goto discard;
80250648Ssklower 			clear_parent_tcb:
80350648Ssklower 				tpcb = 0;
80450648Ssklower 				goto respond;
80536401Ssklower 			}
80636401Ssklower 			tpcb = sototpcb(so);
80744601Ssklower 			insque(tpcb, parent_tpcb);
80836401Ssklower 
80936401Ssklower 			/*
81037469Ssklower 			 * Stash the addresses in the net level pcb
81136401Ssklower 			 * kind of like a pcbconnect() but don't need
81236401Ssklower 			 * or want all those checks.
81336401Ssklower 			 */
81450435Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN);
81550435Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL);
81636401Ssklower 
81737469Ssklower 			/* stash the f suffix in the new tpcb */
81850648Ssklower 			if (tpcb->tp_fsuffixlen = fsufxlen) {
81950648Ssklower 				bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
82050648Ssklower 				(tpcb->tp_nlproto->nlp_putsufx)
82150648Ssklower 						(tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN);
82250648Ssklower 			}
82350648Ssklower 			/* stash the l suffix in the new tpcb */
82450648Ssklower 			tpcb->tp_lsuffixlen = lsufxlen;
82550648Ssklower 			bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
82637469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
82750435Ssklower 					(tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL);
82836401Ssklower #ifdef TP_PERF_MEAS
82936401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
83036401Ssklower 				/* ok, let's create an mbuf for stashing the
83136401Ssklower 				 * statistics if one doesn't already exist
83236401Ssklower 				 */
83336401Ssklower 				(void) tp_setup_perf(tpcb);
83436401Ssklower 			}
83560359Sbostic #endif /* TP_PERF_MEAS */
83636401Ssklower 			tpcb->tp_fref = sref;
83736401Ssklower 
83836401Ssklower 			/* We've already checked for consistency with the options
83936401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
84036401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
84136401Ssklower 			 * Now we set the options in the new socket's tpcb.
84236401Ssklower 			 */
84336401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
84436401Ssklower 
84536401Ssklower 			if(!tpcb->tp_use_checksum)
84636401Ssklower 				IncStat(ts_csum_off);
84736401Ssklower 			if(tpcb->tp_xpd_service)
84836401Ssklower 				IncStat(ts_use_txpd);
84936401Ssklower 			if(tpcb->tp_xtd_format)
85036401Ssklower 				IncStat(ts_xtd_fmt);
85136401Ssklower 
85236401Ssklower 			tpcb->tp_peer_acktime = acktime;
85336401Ssklower 
85436401Ssklower 			/*
85536401Ssklower 			 * The following kludge is used to test retransmissions and
85636401Ssklower 			 * timeout during connection establishment.
85736401Ssklower 			 */
85836401Ssklower 			IFDEBUG(D_ZDREF)
85936401Ssklower 				IncStat(ts_zdebug);
86037469Ssklower 				/*tpcb->tp_fref = 0;*/
86136401Ssklower 			ENDDEBUG
86236401Ssklower 		}
86353682Ssklower 		LOCAL_CREDIT(tpcb);
86436401Ssklower 		IncStat(ts_CR_rcvd);
86539929Ssklower 		if (!tpcb->tp_cebit_off) {
86639929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
86739929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
86839929Ssklower 			CONG_INIT_SAMPLE(tpcb);
86939929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
87039929Ssklower 		}
87136401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
87236401Ssklower 		/*
87336401Ssklower 		 * ER TPDUs have to be recognized separately
87436401Ssklower 		 * because they don't necessarily have a tpcb
87536401Ssklower 		 * with them and we don't want err out looking for such
87636401Ssklower 		 * a beast.
87736401Ssklower 		 * We could put a bunch of little kludges in the
87836401Ssklower 		 * next section of code so it would avoid references to tpcb
87936401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
88036401Ssklower 		 * mess up code for data transfer.
88136401Ssklower 		 */
88236401Ssklower 		IncStat(ts_ER_rcvd);
88336401Ssklower 		e.ev_number = ER_TPDU;
88436401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
88551007Ssklower 		CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size ||
88650176Ssklower 			(tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ||
88751204Ssklower 			tpcb->tp_refstate == REF_FREE ||
88851204Ssklower 			tpcb->tp_refstate == REF_FROZEN),
88950176Ssklower 		       E_TP_MISM_REFS, ts_inv_dref, discard, 0)
89050176Ssklower 
89136401Ssklower 	} else {
89236401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
89336401Ssklower 
89436401Ssklower 		/* In the next 4 checks,
89536401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
89636401Ssklower 		 * the fixed part (can't take the address of a bit field)
89736401Ssklower 		 */
89850648Ssklower #ifdef TPCONS
89950648Ssklower 		if (cons_channel && dutype == DT_TPDU_type) {
90050648Ssklower 			struct isopcb *isop = ((struct isopcb *)
90150648Ssklower 				((struct pklcd *)cons_channel)->lcd_upnext);
90250648Ssklower 			if (isop && isop->isop_refcnt == 1 && isop->isop_socket &&
90350648Ssklower 				(tpcb = sototpcb(isop->isop_socket)) &&
90450648Ssklower 				 (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) {
90550648Ssklower 				IFDEBUG(D_TPINPUT)
90650648Ssklower 					printf("tpinput_dt: class 0 short circuit\n");
90750648Ssklower 				ENDDEBUG
90850648Ssklower 				dref = tpcb->tp_lref;
90950648Ssklower 				sref = tpcb->tp_fref;
91051204Ssklower 				CHECK( (tpcb->tp_refstate == REF_FREE),
91150648Ssklower 					E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
91250648Ssklower 					(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
91350648Ssklower 				goto tp0_data;
91450648Ssklower 			}
91536401Ssklower 
91650648Ssklower 		}
91745900Ssklower #endif
91845900Ssklower 		{
91936401Ssklower 
92051007Ssklower 			CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) ,
92142944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
92236401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
92336401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
92442944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
92536401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
92651204Ssklower 			CHECK( (tpcb->tp_refstate == REF_FREE),
92742944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
92836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
92936401Ssklower 		}
93036401Ssklower 
93136401Ssklower 		IFDEBUG(D_TPINPUT)
93236401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
93336401Ssklower 		ENDDEBUG
93436401Ssklower 
93536401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
93651204Ssklower 		CHECK( (tpcb->tp_refstate == REF_FROZEN),
93736401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
93836401Ssklower 			ts_inv_dref, respond,
93936401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
94036401Ssklower 
94136401Ssklower 		IFDEBUG(D_TPINPUT)
94236401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
94336401Ssklower 		ENDDEBUG
94436401Ssklower 		/*
94536401Ssklower 		 * At this point the state of the dref could be
94636401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
94736401Ssklower 		 *		   for example, DC may arrive after the close() has detached
94836401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
94936401Ssklower 		 * OPENING : a tpcb exists but no timers yet
95036401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
95136401Ssklower 		 */
95236401Ssklower 
95339929Ssklower         if (!tpcb->tp_cebit_off)
95439929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
95539929Ssklower 
95636401Ssklower 		dusize = tpcb->tp_tpdusize;
95751996Ssklower 		pdusize = tpcb->tp_ptpdusize;
95836401Ssklower 
95936401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
96036401Ssklower 
96136401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
96236401Ssklower 
96337469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
96436401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
96536401Ssklower 
96636401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
96736401Ssklower 					/* not in class 0; 1 octet */
96836401Ssklower 					vb_getval(P, u_char, addlopt);
96936401Ssklower 					break;
97036401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
97142944Ssklower 				{
97242944Ssklower 					u_char odusize = dusize;
97336401Ssklower 					vb_getval(P, u_char, dusize);
97442944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
97542944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
97642944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
97742944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
97836401Ssklower 					IFDEBUG(D_TPINPUT)
97936401Ssklower 						printf("CC dusize 0x%x\n", dusize);
98036401Ssklower 					ENDDEBUG
98142944Ssklower 				}
98236401Ssklower 					break;
98351996Ssklower 			caseof( CC_TPDU_type, TPP_ptpdu_size ):
98451996Ssklower 				{
98551996Ssklower 					u_short opdusize = pdusize;
98651996Ssklower 					switch (vbptr(P)->tpv_len) {
98751996Ssklower 					case 1: pdusize = vbval(P, u_char); break;
98851996Ssklower 					case 2: pdusize = ntohs(vbval(P, u_short)); break;
98951996Ssklower 					default: ;
99051996Ssklower 					IFDEBUG(D_TPINPUT)
99151996Ssklower 						printf("malformed prefered TPDU option\n");
99251996Ssklower 					ENDDEBUG
99351996Ssklower 					}
99451996Ssklower 					CHECK( (pdusize == 0 ||
99551996Ssklower 							(opdusize && (pdusize > opdusize))),
99651996Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
99751996Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
99851996Ssklower 				}
99951996Ssklower 					break;
100036401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
100136401Ssklower 					IFDEBUG(D_TPINPUT)
100236401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
100336401Ssklower 					ENDDEBUG
100436401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
100536401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
100636401Ssklower 					break;
100736401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
100836401Ssklower 					/* class 4 only, 2 octets */
100936401Ssklower 					vb_getval(P, u_short, acktime);
101044947Ssklower 					acktime = ntohs(acktime);
101136401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
101236401Ssklower 					if( (short)acktime <=0 )
101336401Ssklower 						acktime = 2;
101436401Ssklower 					break;
101536401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
101636401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
101736401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
101836401Ssklower 					IFDEBUG(D_TPINPUT)
101936401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
102036401Ssklower 					ENDDEBUG
102136401Ssklower 					break;
102236401Ssklower 
102336401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
102436401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
102536401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
102636401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
102736401Ssklower 					if( tpcb->tp_use_checksum )  {
102836401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
102936401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
103036401Ssklower 					}
103136401Ssklower 					break;
103236401Ssklower 
103336401Ssklower 			/*  this is different from the above because in the context
103436401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
103536401Ssklower 			 */
103636401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
103736401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
103836401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
103936401Ssklower 					if( tpcb->tp_use_checksum )  {
104037469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
104136401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
104236401Ssklower 					}
104336401Ssklower 					break;
104436401Ssklower #ifdef notdef
104536401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
104636401Ssklower 				/* ignore - its length and meaning are
104736401Ssklower 				 * user defined and there's no way
104836401Ssklower 				 * to pass this info to the user anyway
104936401Ssklower 				 */
105036401Ssklower 				break;
105160359Sbostic #endif /* notdef */
105236401Ssklower 
105336401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
105436401Ssklower 				/* used after reduction of window */
105536401Ssklower 				vb_getval(P, u_short, subseq);
105636401Ssklower 				subseq = ntohs(subseq);
105736401Ssklower 				IFDEBUG(D_ACKRECV)
105851204Ssklower 					printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq);
105936401Ssklower 				ENDDEBUG
106036401Ssklower 				break;
106136401Ssklower 
106236401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
106336401Ssklower 				{
106436401Ssklower 					u_int 	ylwe;
106536401Ssklower 					u_short ysubseq, ycredit;
106636401Ssklower 
106736401Ssklower 					fcc_present = TRUE;
106836401Ssklower 					vb_getval(P, u_int,	 	ylwe);
106936401Ssklower 					vb_getval(P, u_short, 	ysubseq);
107036401Ssklower 					vb_getval(P, u_short, 	ycredit);
107136401Ssklower 					ylwe = ntohl(ylwe);
107236401Ssklower 					ysubseq = ntohs(ysubseq);
107336401Ssklower 					ycredit = ntohs(ycredit);
107436401Ssklower 					IFDEBUG(D_ACKRECV)
107551204Ssklower 						printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n",
107651204Ssklower 							"AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref);
107736401Ssklower 					ENDDEBUG
107836401Ssklower 				}
107936401Ssklower 				break;
108036401Ssklower 
108136401Ssklower 			default:
108236401Ssklower 				IFDEBUG(D_TPINPUT)
108336401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
108436401Ssklower 						dutype, vbptr(P)->tpv_code);
108536401Ssklower 				ENDDEBUG
108636401Ssklower 				IFTRACE(D_TPINPUT)
108736401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
108836401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
108936401Ssklower 				ENDTRACE
109036401Ssklower 				IncStat(ts_param_ignored);
109136401Ssklower 				break;
109236401Ssklower #undef caseof
109336401Ssklower 		}
109436401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
109536401Ssklower 
109636401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
109736401Ssklower 
109836401Ssklower 		switch( hdr->tpdu_type ) {
109936401Ssklower 		case CC_TPDU_type:
110036401Ssklower 			/* If CC comes back with an unacceptable class
110136401Ssklower 			 * respond with a DR or ER
110236401Ssklower 			 */
110336401Ssklower 
110436401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
110536401Ssklower 
110636401Ssklower 			{
110736401Ssklower 				tpp = tpcb->_tp_param;
110836401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
110936401Ssklower 				tpp.p_tpdusize = dusize;
111051996Ssklower 				tpp.p_ptpdusize = pdusize;
111136401Ssklower 				tpp.p_dont_change_params = 0;
111236401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
111336401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
111436401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
111536401Ssklower #ifdef notdef
111636401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
111736401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
111836401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
111960359Sbostic #endif /* notdef */
112036401Ssklower 
112136401Ssklower 			CHECK(
112236401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
112336401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
112436401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
112536401Ssklower 					/* ^ more or less the location of class */
112636401Ssklower 				)
112736401Ssklower 			IFTRACE(D_CONN)
112836401Ssklower 				tptrace(TPPTmisc,
112936401Ssklower 					"after 1 consist class, out, tpconsout",
113036401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
113136401Ssklower 					);
113236401Ssklower 			ENDTRACE
113336401Ssklower 			CHECK(
113436401Ssklower 				((class_to_use == TP_CLASS_0)&&
113536401Ssklower 					(dgout_routine != tpcons_output)),
113636401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
113736401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
113836401Ssklower 					/* ^ more or less the location of class */
113936401Ssklower 				)
114045900Ssklower #ifdef TPCONS
114145900Ssklower 				if (tpcb->tp_netservice == ISO_CONS &&
114245900Ssklower 					class_to_use == TP_CLASS_0) {
114345900Ssklower 					struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
114445900Ssklower 					struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
114545900Ssklower 					lcp->lcd_flags &= ~X25_DG_CIRCUIT;
114645900Ssklower 				}
114745900Ssklower #endif
114836401Ssklower 			}
114936401Ssklower 			if( ! tpcb->tp_use_checksum)
115036401Ssklower 				IncStat(ts_csum_off);
115136401Ssklower 			if(tpcb->tp_xpd_service)
115236401Ssklower 				IncStat(ts_use_txpd);
115336401Ssklower 			if(tpcb->tp_xtd_format)
115436401Ssklower 				IncStat(ts_xtd_fmt);
115536401Ssklower 
115636401Ssklower 			IFTRACE(D_CONN)
115736401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
115836401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
115936401Ssklower 					hdr->tpdu_CCclass);
116036401Ssklower 			ENDTRACE
116136401Ssklower 
116236401Ssklower 			/* if called or calling suffices appeared on the CC,
116336401Ssklower 			 * they'd better jive with what's in the pcb
116436401Ssklower 			 */
116536401Ssklower 			if( fsufxlen ) {
116636401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
116736401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
116836401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
116936401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
117036401Ssklower 			}
117136401Ssklower 			if( lsufxlen ) {
117236401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
117336401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
117436401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
117536401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
117636401Ssklower 			}
117736401Ssklower 
117836401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
117936401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
118036401Ssklower 			takes_data = TRUE;
118136401Ssklower 			e.ev_number = CC_TPDU;
118236401Ssklower 			IncStat(ts_CC_rcvd);
118336401Ssklower 			break;
118436401Ssklower 
118536401Ssklower 		case DC_TPDU_type:
118636401Ssklower 			if (sref != tpcb->tp_fref)
118736401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
118836401Ssklower 					sref, tpcb->tp_fref);
118936401Ssklower 
119036401Ssklower 			CHECK( (sref != tpcb->tp_fref),
119142944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
119236401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
119342944Ssklower 
119436401Ssklower 			e.ev_number = DC_TPDU;
119536401Ssklower 			IncStat(ts_DC_rcvd);
119636401Ssklower 			break;
119736401Ssklower 
119836401Ssklower 		case DR_TPDU_type:
119936401Ssklower 			IFTRACE(D_TPINPUT)
120036401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
120136401Ssklower 			ENDTRACE
120242944Ssklower 			if (sref != tpcb->tp_fref) {
120336401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
120436401Ssklower 					sref, tpcb->tp_fref);
120542944Ssklower 			}
120636401Ssklower 
120742944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
120842944Ssklower 					tpcb->tp_state != TP_CRSENT),
120942944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
121036401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
121136401Ssklower 
121236401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
121336401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
121436401Ssklower 			takes_data = TRUE;
121536401Ssklower 			e.ev_number = DR_TPDU;
121636401Ssklower 			IncStat(ts_DR_rcvd);
121736401Ssklower 			break;
121836401Ssklower 
121936401Ssklower 		case ER_TPDU_type:
122036401Ssklower 			IFTRACE(D_TPINPUT)
122136401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
122236401Ssklower 			ENDTRACE
122336401Ssklower 			e.ev_number = ER_TPDU;
122436401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
122536401Ssklower 			IncStat(ts_ER_rcvd);
122636401Ssklower 			break;
122736401Ssklower 
122836401Ssklower 		case AK_TPDU_type:
122936401Ssklower 
123036401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
123136401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
123236401Ssklower 
123336401Ssklower 			if (tpcb->tp_xtd_format) {
123436401Ssklower #ifdef BYTE_ORDER
123536401Ssklower 				union seq_type seqeotX;
123636401Ssklower 
123736401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
123836401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
123936401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
124036401Ssklower #else
124136401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
124236401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
124360359Sbostic #endif /* BYTE_ORDER */
124436401Ssklower 			} else {
124536401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
124636401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
124736401Ssklower 			}
124836401Ssklower 			IFTRACE(D_TPINPUT)
124936401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
125036401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
125136401Ssklower 					subseq, fcc_present);
125236401Ssklower 			ENDTRACE
125336401Ssklower 
125436401Ssklower 			e.ev_number = AK_TPDU;
125536401Ssklower 			IncStat(ts_AK_rcvd);
125636401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
125736401Ssklower 			break;
125836401Ssklower 
125936401Ssklower 		case XAK_TPDU_type:
126036401Ssklower 			if (tpcb->tp_xtd_format) {
126136401Ssklower #ifdef BYTE_ORDER
126236401Ssklower 				union seq_type seqeotX;
126336401Ssklower 
126436401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
126536401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
126636401Ssklower #else
126736401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
126860359Sbostic #endif /* BYTE_ORDER */
126936401Ssklower 			} else {
127036401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
127136401Ssklower 			}
127236401Ssklower 			e.ev_number = XAK_TPDU;
127336401Ssklower 			IncStat(ts_XAK_rcvd);
127436401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
127536401Ssklower 			break;
127636401Ssklower 
127736401Ssklower 		case XPD_TPDU_type:
127836401Ssklower 			if (tpcb->tp_xtd_format) {
127936401Ssklower #ifdef BYTE_ORDER
128036401Ssklower 				union seq_type seqeotX;
128136401Ssklower 
128236401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
128336401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
128436401Ssklower #else
128536401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
128660359Sbostic #endif /* BYTE_ORDER */
128736401Ssklower 			} else {
128836401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
128936401Ssklower 			}
129036401Ssklower 			takes_data = TRUE;
129136401Ssklower 			e.ev_number = XPD_TPDU;
129236401Ssklower 			IncStat(ts_XPD_rcvd);
129336401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
129436401Ssklower 			break;
129536401Ssklower 
129636401Ssklower 		case DT_TPDU_type:
129736401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
129836401Ssklower 			   * A little crude but it works.
129936401Ssklower 			   */
130036401Ssklower 
130136401Ssklower 				IFDEBUG(D_DROP)
130236401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
130336401Ssklower 						IncStat(ts_ydebug);
130436401Ssklower 						goto discard;
130536401Ssklower 					}
130636401Ssklower 				ENDDEBUG
130736401Ssklower 			}
130836401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
130950648Ssklower 			tp0_data:
131036401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
131136401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
131236401Ssklower 			} else if (tpcb->tp_xtd_format) {
131336401Ssklower #ifdef BYTE_ORDER
131436401Ssklower 				union seq_type seqeotX;
131536401Ssklower 
131636401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
131736401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
131836401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
131936401Ssklower #else
132036401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
132136401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
132260359Sbostic #endif /* BYTE_ORDER */
132336401Ssklower 			} else {
132436401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
132536401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
132636401Ssklower 			}
132736401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
132836401Ssklower 				IncStat(ts_eot_input);
132936401Ssklower 			takes_data = TRUE;
133036401Ssklower 			e.ev_number = DT_TPDU;
133136401Ssklower 			IncStat(ts_DT_rcvd);
133236401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
133336401Ssklower 			break;
133436401Ssklower 
133536401Ssklower 		case GR_TPDU_type:
133636401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
133736401Ssklower 			/* drop through */
133836401Ssklower 		default:
133936401Ssklower 			/* this should NEVER happen because there is a
134036401Ssklower 			 * check for dutype well above here
134136401Ssklower 			 */
134236401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
134336401Ssklower 			IFDEBUG(D_TPINPUT)
134436401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
134536401Ssklower 			ENDDEBUG
134636401Ssklower 			IncStat(ts_inv_dutype);
134736401Ssklower 			goto respond;
134836401Ssklower 		}
134936401Ssklower 	}
135036401Ssklower 	/* peel off the tp header;
135136401Ssklower 	 * remember that the du_li doesn't count itself.
135236401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
135336401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
135436401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
135536401Ssklower 	 */
135636401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
135737469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
135836401Ssklower 
135937469Ssklower 	if (takes_data) {
136037469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
136137469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
136248749Ssklower 		struct {
136348749Ssklower 			struct tp_disc_reason dr;
136448749Ssklower 			struct cmsghdr x_hdr;
136548749Ssklower 		} x;
136648749Ssklower #define c_hdr x.x_hdr
136748749Ssklower 		register struct mbuf *n;
136836401Ssklower 
136937469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
137037469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
137136401Ssklower 		switch( hdr->tpdu_type ) {
137237469Ssklower 
137336401Ssklower 		case CR_TPDU_type:
137437469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
137537469Ssklower 			goto make_control_msg;
137637469Ssklower 
137736401Ssklower 		case CC_TPDU_type:
137837469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
137937469Ssklower 			goto make_control_msg;
138037469Ssklower 
138136401Ssklower 		case DR_TPDU_type:
138248749Ssklower 			x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
138348749Ssklower 			x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
138448749Ssklower 			x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
138548749Ssklower 			x.dr.dr_reason = hdr->tpdu_DRreason;
138637469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
138737469Ssklower 		make_control_msg:
138848749Ssklower 			datalen += sizeof(c_hdr);
138948749Ssklower 			c_hdr.cmsg_len = datalen;
139037469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
139137469Ssklower 			mbtype = MT_CONTROL;
139243334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
139348749Ssklower 			if (n == 0)
139448749Ssklower 				{m_freem(m); m = 0; datalen = 0; goto invoke; }
139548749Ssklower 			if (hdr->tpdu_type == DR_TPDU_type) {
139648749Ssklower 				datalen += sizeof(x) - sizeof(c_hdr);
139748749Ssklower 				bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
139848749Ssklower 			} else
139948749Ssklower 				bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
140048749Ssklower 					  n->m_len = sizeof(c_hdr));
140148749Ssklower 			n->m_next = m;
140248749Ssklower 			m = n;
140337469Ssklower 			/* FALLTHROUGH */
140437469Ssklower 
140536401Ssklower 		case XPD_TPDU_type:
140637469Ssklower 			if (mbtype != MT_CONTROL)
140737469Ssklower 				mbtype = MT_OOBDATA;
140837469Ssklower 			m->m_flags |= M_EOR;
140937469Ssklower 			/* FALLTHROUGH */
141037469Ssklower 
141136401Ssklower 		case DT_TPDU_type:
141237469Ssklower 			for (n = m; n; n = n->m_next) {
141337469Ssklower 				MCHTYPE(n, mbtype);
141437469Ssklower 			}
141543334Ssklower 		invoke:
141637469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
141736401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
141836401Ssklower 			break;
141936401Ssklower 
142036401Ssklower 		default:
142136401Ssklower 			printf(
142236401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
142336401Ssklower 				hdr->tpdu_type, takes_data, m);
142436401Ssklower 			break;
142536401Ssklower 		}
142636401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
142736401Ssklower 		m = MNULL;
142836401Ssklower 	}
142936401Ssklower 
143036401Ssklower 	IncStat(ts_tpdu_rcvd);
143136401Ssklower 
143236401Ssklower 	IFDEBUG(D_TPINPUT)
143336401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
143436401Ssklower 			tpcb->tp_state, e.ev_number, m );
143536401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
143636401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
143736401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
143836401Ssklower 	ENDDEBUG
143936401Ssklower 
144036401Ssklower 	error = tp_driver(tpcb, &e);
144136401Ssklower 
144236401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
144336401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
144436401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
144536401Ssklower 		tpcb->tp_sock->so_error = error;
144636401Ssklower 
144736401Ssklower 	/* Kludge to keep the state tables under control (adding
144836401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
144936401Ssklower 	 * the data would have exploded the tables and made a big mess ).
145036401Ssklower 	 */
145136401Ssklower 	switch(e.ev_number) {
145236401Ssklower 		case CC_TPDU:
145336401Ssklower 		case DR_TPDU:
145436401Ssklower 		case CR_TPDU:
145536401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
145636401Ssklower 			IFDEBUG(D_TPINPUT)
145736401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
145836401Ssklower 				m, takes_data);
145936401Ssklower 			ENDDEBUG
146036401Ssklower 			break;
146136401Ssklower 		default:
146236401Ssklower 			break;
146336401Ssklower 	}
146436401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
146536401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
146636401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
146736401Ssklower 	 */
146836401Ssklower 
146936401Ssklower separate:
147036401Ssklower 	if ( takes_data == 0 )  {
147136401Ssklower 		ASSERT( m != MNULL );
147236401Ssklower 		/*
147336401Ssklower 		 * we already peeled off the prev. tp header so
147436401Ssklower 		 * we can just pull up some more and repeat
147536401Ssklower 		 */
147636401Ssklower 
147737469Ssklower 		if( m = tp_inputprep(m) ) {
147836401Ssklower 		IFDEBUG(D_TPINPUT)
147936401Ssklower 			hdr = mtod(m, struct tpdu *);
148036401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
148136401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
148236401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
148336401Ssklower 		ENDDEBUG
148436401Ssklower 
148536401Ssklower 			IncStat(ts_concat_rcvd);
148636401Ssklower 			goto again;
148736401Ssklower 		}
148836401Ssklower 	}
148936401Ssklower 	if ( m != MNULL ) {
149036401Ssklower 		IFDEBUG(D_TPINPUT)
149136401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
149236401Ssklower 		ENDDEBUG
149336401Ssklower 		m_freem(m);
149436401Ssklower 		IFDEBUG(D_TPINPUT)
149536401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
149636401Ssklower 		ENDDEBUG
149736401Ssklower 	}
149836401Ssklower 	return (ProtoHook) tpcb;
149936401Ssklower 
150036401Ssklower discard:
150136401Ssklower 	/* class 4: drop the tpdu */
150236401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
150336401Ssklower 	 * to which connection it applies
150436401Ssklower 	 */
150536401Ssklower 	IFDEBUG(D_TPINPUT)
150636401Ssklower 		printf("tp_input DISCARD\n");
150736401Ssklower 	ENDDEBUG
150836401Ssklower 	IFTRACE(D_TPINPUT)
150936401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
151036401Ssklower 	ENDTRACE
151136401Ssklower 	m_freem(m);
151236401Ssklower 	IncStat(ts_recv_drop);
151336401Ssklower 	return (ProtoHook)0;
151436401Ssklower 
151542944Ssklower nonx_dref:
151642944Ssklower 	switch (dutype) {
151742944Ssklower 	default:
151842944Ssklower 		goto discard;
151942944Ssklower 	case CC_TPDU_type:
152042944Ssklower 		/* error = E_TP_MISM_REFS; */
152142944Ssklower 		break;
152242944Ssklower 	case DR_TPDU_type:
152342944Ssklower 		error |= TP_ERROR_SNDC;
152442944Ssklower 	}
152536401Ssklower respond:
152643334Ssklower 	IFDEBUG(D_TPINPUT)
152742944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
152836401Ssklower 	ENDDEBUG
152936401Ssklower 	IFTRACE(D_TPINPUT)
153042944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
153136401Ssklower 	ENDTRACE
153242944Ssklower 	if (sref == 0)
153336401Ssklower 		goto discard;
153437469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
153542944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
153650648Ssklower 				cons_channel, dgout_routine);
153736401Ssklower 	IFDEBUG(D_ERROR_EMIT)
153836401Ssklower 		printf("tp_input after error_emit\n");
153936401Ssklower 	ENDDEBUG
154036401Ssklower 
154136401Ssklower #ifdef lint
154236401Ssklower 	printf("",sref,opt);
154360359Sbostic #endif /* lint */
154436401Ssklower 	IncStat(ts_recv_drop);
154536401Ssklower 	return (ProtoHook)0;
154636401Ssklower }
154736401Ssklower 
154836401Ssklower 
154936401Ssklower /*
155036401Ssklower  * NAME: tp_headersize()
155136401Ssklower  *
155236401Ssklower  * CALLED FROM:
155336401Ssklower  *  tp_emit() and tp_sbsend()
155436401Ssklower  *  TP needs to know the header size so it can figure out how
155536401Ssklower  *  much data to put in each tpdu.
155636401Ssklower  *
155736401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
155836401Ssklower  *  For a given connection, represented by (tpcb), and
155936401Ssklower  *  tpdu type (dutype), return the size of a tp header.
156036401Ssklower  *
156136401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
156236401Ssklower  *
156336401Ssklower  * SIDE EFFECTS:
156436401Ssklower  *
156536401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
156636401Ssklower  */
156736401Ssklower int
tp_headersize(dutype,tpcb)156836401Ssklower tp_headersize(dutype, tpcb)
156936401Ssklower 	int 			dutype;
157036401Ssklower 	struct tp_pcb 	*tpcb;
157136401Ssklower {
157236401Ssklower 	register int size = 0;
157336401Ssklower 
157436401Ssklower 	IFTRACE(D_CONN)
157536401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
157636401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
157736401Ssklower 	ENDTRACE
157836401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
157936401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
158036401Ssklower 			(dutype == DR_TPDU_type) ||
158136401Ssklower 			(dutype == CR_TPDU_type) )) {
158236401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
158336401Ssklower 			dutype, tpcb->tp_class);
158436401Ssklower 	/* TODO: identify this and GET RID OF IT */
158536401Ssklower 	}
158636401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
158736401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
158836401Ssklower 			(dutype == DR_TPDU_type) ||
158936401Ssklower 			(dutype == CR_TPDU_type) );
159036401Ssklower 
159136401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
159236401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
159336401Ssklower 	} else  {
159436401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
159536401Ssklower 	}
159636401Ssklower 	return size;
159736401Ssklower 	/* caller must get network level header size separately */
159836401Ssklower }
1599