xref: /csrg-svn/sys/netiso/tp_input.c (revision 52465)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*52465Smckusick  *	@(#)tp_input.c	7.27 (Berkeley) 02/11/92
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 
6336401Ssklower #include "param.h"
6444422Ssklower #include "systm.h"
6536401Ssklower #include "mbuf.h"
6636401Ssklower #include "socket.h"
6736401Ssklower #include "socketvar.h"
6836401Ssklower #include "domain.h"
6936401Ssklower #include "protosw.h"
7036401Ssklower #include "errno.h"
7136401Ssklower #include "time.h"
7236401Ssklower #include "kernel.h"
7336401Ssklower #include "types.h"
7445900Ssklower #include "iso.h"
7537469Ssklower #include "iso_errno.h"
7645900Ssklower #include "iso_pcb.h"
7737469Ssklower #include "tp_param.h"
7837469Ssklower #include "tp_timer.h"
7937469Ssklower #include "tp_stat.h"
8037469Ssklower #include "tp_pcb.h"
8137469Ssklower #include "argo_debug.h"
8237469Ssklower #include "tp_trace.h"
8337469Ssklower #include "tp_tpdu.h"
8436401Ssklower 
8545900Ssklower #include "../net/if.h"
8645900Ssklower #ifdef TRUE
8745900Ssklower #undef FALSE
8845900Ssklower #undef TRUE
8945900Ssklower #endif
9045900Ssklower #include "../netccitt/x25.h"
9145900Ssklower #include "../netccitt/pk.h"
9245900Ssklower #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 *
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 ) {
11436401Ssklower 		if( (m = m_free(m)) == MNULL ) {
11536401Ssklower 			return (struct mbuf *)0;
11636401Ssklower 		}
11736401Ssklower 	}
11837469Ssklower 	if(((int)m->m_data) & 0x3) {
11937469Ssklower 		/* If we are not 4-byte aligned, we have to be
12037469Ssklower 		 * above the beginning of the mbuf, and it is ok just
12137469Ssklower 		 * to slide it back.
12237469Ssklower 		 */
12337469Ssklower 		caddr_t ocp = m->m_data;
12436401Ssklower 
12537469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
126*52465Smckusick 		bcopy(ocp, m->m_data, (unsigned)m->m_len);
12736401Ssklower 	}
12836401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
12936401Ssklower 
13037469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
13137469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
13236401Ssklower 
13337469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
13436401Ssklower 
13536401Ssklower 	/*
13636401Ssklower 	 * now pull up the whole tp header
13736401Ssklower 	 */
13837469Ssklower 	if ( m->m_len < hdrlen) {
13937469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
14036401Ssklower 			IncStat(ts_recv_drop);
14136401Ssklower 			return (struct mbuf *)0;
14236401Ssklower 		}
14336401Ssklower 	}
14436401Ssklower 	IFDEBUG(D_INPUT)
14536401Ssklower 	printf(
14636401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
14737469Ssklower 		hdrlen, m->m_len);
14836401Ssklower 	ENDDEBUG
14936401Ssklower 	return m;
15036401Ssklower }
15136401Ssklower 
15236401Ssklower /* begin groan
15336401Ssklower  * -- this array and the following macros allow you to step through the
15436401Ssklower  * parameters of the variable part of a header
15536401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
15636401Ssklower  * should change, this array has to be rearranged
15736401Ssklower  */
15836401Ssklower 
15936401Ssklower #define TP_LEN_CLASS_0_INDEX	2
16036401Ssklower #define TP_MAX_DATA_INDEX 3
16136401Ssklower 
16236401Ssklower static u_char tpdu_info[][4] =
16336401Ssklower {
16436401Ssklower /*								length						 max data len */
16536401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
16636401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
16736401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
16836401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
16936401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
17036401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
17136401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
17236401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
17336401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
17436401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
17536401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
17636401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
17736401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
17836401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
17936401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
18036401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
18136401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
18236401Ssklower };
18336401Ssklower 
18442944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
18543334Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
18642944Ssklower 	goto Whattodo; }
18742944Ssklower 
18843334Ssklower tpibrk() {}
18943334Ssklower 
19036401Ssklower /*
19136401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
19236401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
19336401Ssklower  */
19436401Ssklower 
19542944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
19642944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
19742944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
19842944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
19942944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
20042944Ssklower 				respond, P - (caddr_t)hdr);\
20142944Ssklower 		if (P == PLIM) break;
20236401Ssklower 
20342944Ssklower #define END_WHILE_OPTIONS(P) } }
20436401Ssklower 
20536401Ssklower /* end groan */
20636401Ssklower 
20736401Ssklower /*
20836401Ssklower  * NAME:  tp_newsocket()
20936401Ssklower  *
21036401Ssklower  * CALLED FROM:
21136401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
21236401Ssklower  * is awaiting a  connection request
21336401Ssklower  *
21436401Ssklower  * FUNCTION and ARGUMENTS:
21536401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
21636401Ssklower  *  using a copy of the net level pcb for the parent socket.
21736401Ssklower  *  (so) is the parent socket.
21836401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
21936401Ssklower  *
22036401Ssklower  * RETURN VALUE:
22136401Ssklower  *  a new socket structure, being this end of the newly formed connection.
22236401Ssklower  *
22336401Ssklower  * SIDE EFFECTS:
22436401Ssklower  *  Sets a few things in the tpcb and net level pcb
22536401Ssklower  *
22636401Ssklower  * NOTES:
22736401Ssklower  */
22836401Ssklower static struct socket *
22936401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
23036401Ssklower 	struct socket				*so;
23136401Ssklower 	struct sockaddr				*fname;
23250648Ssklower 	caddr_t						cons_channel;
23336401Ssklower 	u_char						class_to_use;
23436401Ssklower 	u_int						netservice;
23536401Ssklower {
23636401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
23745900Ssklower 	register struct tp_pcb	*newtpcb;
23836401Ssklower 
23936401Ssklower 	/*
24036401Ssklower 	 * sonewconn() gets a new socket structure,
24136401Ssklower 	 * a new lower layer pcb and a new tpcb,
24236401Ssklower 	 * but the pcbs are unnamed (not bound)
24336401Ssklower 	 */
24436401Ssklower 	IFTRACE(D_NEWSOCK)
24538841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
24639196Ssklower 			so, tpcb, so->so_head, 0);
24736401Ssklower 	ENDTRACE
24836401Ssklower 
24940636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
25036401Ssklower 		return so;
25136401Ssklower 	IFTRACE(D_NEWSOCK)
25238841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
25338841Ssklower 			so, so->so_head, 0, 0);
25436401Ssklower 	ENDTRACE
25536401Ssklower 
25636401Ssklower 	IFDEBUG(D_NEWSOCK)
25737469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
25837469Ssklower 				cons_channel, so);
25937469Ssklower 		dump_addr(fname);
26036401Ssklower 		{
26136401Ssklower 			struct socket *t, *head ;
26236401Ssklower 
26336401Ssklower 			head = so->so_head;
26436401Ssklower 			t = so;
26536401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26636401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
26736401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
26836401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26936401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
27036401Ssklower 		}
27136401Ssklower 	ENDDEBUG
27236401Ssklower 
27336401Ssklower 	/*
27436401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
27536401Ssklower 	 */
27636401Ssklower 	newtpcb = sototpcb(so);
27736401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
27836401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
27936401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
28036401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
28136401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
28236401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
28336401Ssklower 
28437469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
28536401Ssklower 		/*
28637469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
28736401Ssklower 		 */
28836401Ssklower 		struct mbuf *conndata;
28936401Ssklower 
29037469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
29136401Ssklower 		IFDEBUG(D_CONN)
29236401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
29336401Ssklower 		ENDDEBUG
29437469Ssklower 		newtpcb->tp_ucddata = conndata;
29536401Ssklower 	}
29636401Ssklower 
29736401Ssklower 	tpcb = newtpcb;
29836401Ssklower 	tpcb->tp_state = TP_LISTENING;
29936401Ssklower 	tpcb->tp_class = class_to_use;
30036401Ssklower 	tpcb->tp_netservice = netservice;
30136401Ssklower 
30236401Ssklower 
30336401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
30436401Ssklower 	if ( fname ) {
30536401Ssklower 		/*
30636401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
30736401Ssklower 		 */
30836401Ssklower 		struct mbuf	*m;
30936401Ssklower 		int			err;
31036401Ssklower 
31136401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
31236401Ssklower 		if (m) {
31336401Ssklower 			/*
31436401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
31536401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
31636401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
31736401Ssklower 			 * sigh.
31836401Ssklower 			 */
31937469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
32037469Ssklower 			m->m_len = fname->sa_len;
32136401Ssklower 
32236401Ssklower 			/* grot  : have to say the kernel can override params in
32336401Ssklower 			 * the passive open case
32436401Ssklower 			 */
32536401Ssklower 			tpcb->tp_dont_change_params = 0;
32636401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
32736401Ssklower 			m_free(m);
32836401Ssklower 
32936401Ssklower 			if (!err)
33036401Ssklower 				goto ok;
33136401Ssklower 		}
33236401Ssklower 		IFDEBUG(D_CONN)
33336401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
33436401Ssklower 				tpcb, so);
33536401Ssklower 		ENDDEBUG
33636401Ssklower 		(void) tp_detach(tpcb);
33736401Ssklower 		return 0;
33836401Ssklower 	}
33936401Ssklower ok:
34036401Ssklower 	IFDEBUG(D_TPINPUT)
34136401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
34236401Ssklower 			so, sototpcb(so));
34336401Ssklower 	ENDDEBUG
34436401Ssklower 	return so;
34536401Ssklower }
34636401Ssklower 
34745900Ssklower #ifndef TPCONS
34836401Ssklower tpcons_output()
34936401Ssklower {
35036401Ssklower 	return(0);
35136401Ssklower }
35236401Ssklower #endif !CONS
35336401Ssklower 
35436401Ssklower /*
35536401Ssklower  * NAME: 	tp_input()
35636401Ssklower  *
35736401Ssklower  * CALLED FROM:
35836401Ssklower  *  net layer input routine
35936401Ssklower  *
36036401Ssklower  * FUNCTION and ARGUMENTS:
36136401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
36236401Ssklower  *  is one. Create the appropriate type of event and call the driver.
36336401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
36436401Ssklower  *
36536401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
36636401Ssklower  * 	has been m_pullup-ed.
36736401Ssklower  *
36836401Ssklower  * RETURN VALUE: Nada
36936401Ssklower  *
37036401Ssklower  * SIDE EFFECTS:
37136401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
37236401Ssklower  *
37336401Ssklower  * NOTE:
37436401Ssklower  *  The initial value of acktime is 2 so that we will never
37536401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
37636401Ssklower  *  computation of the retransmission timer value, and so it
37736401Ssklower  *  mustn't be zero.
37836401Ssklower  *  2 seems like a reasonable minimum.
37936401Ssklower  */
38036401Ssklower ProtoHook
38139929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
38236401Ssklower 	register	struct mbuf 	*m;
38336401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
38450648Ssklower 	caddr_t						cons_channel;
38536401Ssklower 	int 						(*dgout_routine)();
38639929Ssklower 	int							ce_bit;
38736401Ssklower 
38836401Ssklower {
38936401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
39044947Ssklower 	register struct tpdu 	*hdr;
39136401Ssklower 	struct socket 			*so;
39236401Ssklower 	struct tp_event 		e;
39342944Ssklower 	int 					error = 0;
39436401Ssklower 	unsigned 				dutype;
39542944Ssklower 	u_short 				dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
39651996Ssklower 	u_char 					preferred_class = 0, class_to_use = 0, pdusize = 0;
39742944Ssklower 	u_char					opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
39836401Ssklower #ifdef TP_PERF_MEAS
39938841Ssklower 	u_char					perf_meas;
40036401Ssklower #endif TP_PERF_MEAS
40150648Ssklower 	u_char					fsufxlen = 0, lsufxlen = 0;
40242944Ssklower 	caddr_t					fsufxloc = 0, lsufxloc = 0;
40342944Ssklower 	int						tpdu_len = 0;
40442944Ssklower 	u_int 					takes_data = FALSE;
40542944Ssklower 	u_int					fcc_present = FALSE;
40642944Ssklower 	int						errlen = 0;
40736401Ssklower 	struct tp_conn_param 	tpp;
40836401Ssklower 	int						tpcons_output();
40936401Ssklower 
41038841Ssklower again:
41144947Ssklower 	hdr = mtod(m, struct tpdu *);
41236401Ssklower #ifdef TP_PERF_MEAS
41338841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
41436401Ssklower #endif TP_PERF_MEAS
41536401Ssklower 
41636401Ssklower 	IFDEBUG(D_TPINPUT)
41736401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
41836401Ssklower 	ENDDEBUG
41936401Ssklower 
42036401Ssklower 
42136401Ssklower 	/*
42236401Ssklower 	 * get the actual tpdu length - necessary for monitoring
42336401Ssklower 	 * and for checksumming
42436401Ssklower 	 *
42536401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
42636401Ssklower 	 */
42736401Ssklower 
42836401Ssklower 	{ 	register struct mbuf *n=m;
42936401Ssklower #	ifdef ARGO_DEBUG
43036401Ssklower 		int chain_length = 0;
43136401Ssklower #	endif ARGO_DEBUG
43236401Ssklower 
43336401Ssklower 		for(;;) {
43436401Ssklower 			tpdu_len += n->m_len;
43536401Ssklower 			IFDEBUG(D_MBUF_MEAS)
43637469Ssklower 				if( n->m_flags & M_EXT) {
43736401Ssklower 					IncStat(ts_mb_cluster);
43836401Ssklower 				} else {
43936401Ssklower 					IncStat(ts_mb_small);
44036401Ssklower 				}
44136401Ssklower 				chain_length ++;
44236401Ssklower 			ENDDEBUG
44336401Ssklower 			if (n->m_next == MNULL ) {
44436401Ssklower 				break;
44536401Ssklower 			}
44636401Ssklower 			n = n->m_next;
44736401Ssklower 		}
44836401Ssklower 		IFDEBUG(D_MBUF_MEAS)
44936401Ssklower 			if(chain_length > 16)
45036401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
45136401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
45236401Ssklower 		ENDDEBUG
45336401Ssklower 	}
45436401Ssklower 	IFTRACE(D_TPINPUT)
45536401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
45636401Ssklower 			0);
45736401Ssklower 	ENDTRACE
45836401Ssklower 
45936401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
46036401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
46136401Ssklower 	dutype = (int)hdr->tpdu_type;
46236401Ssklower 
46336401Ssklower 	IFDEBUG(D_TPINPUT)
46436401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
46536401Ssklower 			cons_channel, dref);
46636401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
46736401Ssklower 	ENDDEBUG
46836401Ssklower 	IFTRACE(D_TPINPUT)
46936401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
47036401Ssklower 			cons_channel, dutype, dref, 0);
47136401Ssklower 	ENDTRACE
47236401Ssklower 
47336401Ssklower 
47436401Ssklower #ifdef ARGO_DEBUG
47536401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
47636401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
47736401Ssklower 			dutype, cons_channel, dref);
47836401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
47936401Ssklower 
48036401Ssklower 		IncStat(ts_inv_dutype);
48136401Ssklower 		goto discard;
48236401Ssklower 	}
48336401Ssklower #endif ARGO_DEBUG
48436401Ssklower 
48536401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
48636401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
48736401Ssklower 		2 );
48836401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
48936401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
49036401Ssklower 		 */
49136401Ssklower 
49236401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
49336401Ssklower 	 * at the beginning of connection establishment, and by
49436401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
49536401Ssklower 	 */
49636401Ssklower 	if ( dutype == CR_TPDU_type ) {
49736401Ssklower 		u_char alt_classes = 0;
49836401Ssklower 
49937469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
50036401Ssklower 		opt = hdr->tpdu_CRoptions;
50136401Ssklower 
50236401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
50336401Ssklower 
50436401Ssklower 			switch( vbptr(P)->tpv_code ) {
50536401Ssklower 
50636401Ssklower 			case	TPP_tpdu_size:
50736401Ssklower 				vb_getval(P, u_char, dusize);
50836401Ssklower 				IFDEBUG(D_TPINPUT)
50936401Ssklower 					printf("CR dusize 0x%x\n", dusize);
51036401Ssklower 				ENDDEBUG
51142944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
51242944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
51342944Ssklower 						dusize = TP_DFL_TPDUSIZE;
51436401Ssklower 				break;
51551996Ssklower 			case	TPP_ptpdu_size:
51651996Ssklower 				switch (vbptr(P)->tpv_len) {
51751996Ssklower 				case 1: pdusize = vbval(P, u_char); break;
51851996Ssklower 				case 2: pdusize = ntohs(vbval(P, u_short)); break;
51951996Ssklower 				default: ;
52051996Ssklower 				IFDEBUG(D_TPINPUT)
52151996Ssklower 					printf("malformed prefered TPDU option\n");
52251996Ssklower 				ENDDEBUG
52351996Ssklower 				}
52451996Ssklower 				break;
52536401Ssklower 			case	TPP_addl_opt:
52636401Ssklower 				vb_getval(P, u_char, addlopt);
52736401Ssklower 				break;
52836401Ssklower 			case	TPP_calling_sufx:
52936401Ssklower 				/* could use vb_getval, but we want to save the loc & len
53036401Ssklower 				 * for later use
53136401Ssklower 				 */
53236401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
53336401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
53436401Ssklower 				IFDEBUG(D_TPINPUT)
53536401Ssklower 					printf("CR fsufx:");
53636401Ssklower 					{ register int j;
53736401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
53836401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
53936401Ssklower 						}
54036401Ssklower 						printf("\n");
54136401Ssklower 					}
54236401Ssklower 				ENDDEBUG
54336401Ssklower 				break;
54436401Ssklower 			case	TPP_called_sufx:
54536401Ssklower 				/* could use vb_getval, but we want to save the loc & len
54636401Ssklower 				 * for later use
54736401Ssklower 				 */
54836401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
54936401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
55036401Ssklower 				IFDEBUG(D_TPINPUT)
55136401Ssklower 					printf("CR lsufx:");
55236401Ssklower 					{ register int j;
55336401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
55437469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
55536401Ssklower 						}
55636401Ssklower 						printf("\n");
55736401Ssklower 					}
55836401Ssklower 				ENDDEBUG
55936401Ssklower 				break;
56036401Ssklower 
56136401Ssklower #ifdef TP_PERF_MEAS
56236401Ssklower 			case	TPP_perf_meas:
56336401Ssklower 				vb_getval(P, u_char, perf_meas);
56436401Ssklower 				break;
56536401Ssklower #endif TP_PERF_MEAS
56636401Ssklower 
56736401Ssklower 			case	TPP_vers:
56836401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
56942944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
57036401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
57142491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
57242944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
57342491Ssklower 			setversion:
57442491Ssklower 				version = vbval(P, u_char);
57536401Ssklower 				break;
57636401Ssklower 			case	TPP_acktime:
57736401Ssklower 				vb_getval(P, u_short, acktime);
57836401Ssklower 				acktime = ntohs(acktime);
57936401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
58036401Ssklower 				if((short)acktime <=0 )
58136401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
58236401Ssklower 				IFDEBUG(D_TPINPUT)
58336401Ssklower 					printf("CR acktime 0x%x\n", acktime);
58436401Ssklower 				ENDDEBUG
58536401Ssklower 				break;
58636401Ssklower 
58736401Ssklower 			case	TPP_alt_class:
58836401Ssklower 				{
58936401Ssklower 					u_char *aclass = 0;
59036401Ssklower 					register int i;
59142944Ssklower 					static u_char bad_alt_classes[5] =
59242944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
59336401Ssklower 
59442944Ssklower 					aclass =
59542944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
59636401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
59742944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
59836401Ssklower 					}
59942944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
60042944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
60142944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
60236401Ssklower 					IFDEBUG(D_TPINPUT)
60336401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
60436401Ssklower 					ENDDEBUG
60536401Ssklower 				}
60636401Ssklower 				break;
60736401Ssklower 
60836401Ssklower 			case	TPP_security:
60936401Ssklower 			case	TPP_residER:
61036401Ssklower 			case	TPP_priority:
61136401Ssklower 			case	TPP_transdelay:
61236401Ssklower 			case	TPP_throughput:
61336401Ssklower 			case	TPP_addl_info:
61436401Ssklower 			case	TPP_subseq:
61544947Ssklower 			default:
61636401Ssklower 				IFDEBUG(D_TPINPUT)
61736401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
61836401Ssklower 						 vbptr(P)->tpv_code);
61936401Ssklower 				ENDDEBUG
62036401Ssklower 				IncStat(ts_param_ignored);
62136401Ssklower 				break;
62236401Ssklower 
62336401Ssklower 			case	TPP_checksum:
62436401Ssklower 				IFDEBUG(D_TPINPUT)
62536401Ssklower 					printf("CR before cksum\n");
62636401Ssklower 				ENDDEBUG
62736401Ssklower 
62836401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
62936401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
63036401Ssklower 
63136401Ssklower 				IFDEBUG(D_TPINPUT)
63236401Ssklower 					printf("CR before cksum\n");
63336401Ssklower 				ENDDEBUG
63436401Ssklower 				break;
63536401Ssklower 			}
63636401Ssklower 
63736401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
63836401Ssklower 
63944422Ssklower 		if (lsufxlen == 0) {
64036401Ssklower 			/* can't look for a tpcb w/o any called sufx */
64136401Ssklower 			error =  E_TP_LENGTH_INVAL;
64236401Ssklower 			IncStat(ts_inv_sufx);
64336401Ssklower 			goto respond;
64436401Ssklower 		} else {
64544422Ssklower 			register struct tp_pcb *t;
64650648Ssklower 			/*
64750648Ssklower 			 * The intention here is to trap all CR requests
64850648Ssklower 			 * to a given nsap, for constructing transport
64950648Ssklower 			 * service bridges at user level; so these
65050648Ssklower 			 * intercepts should precede the normal listens.
65150648Ssklower 			 * Phrasing the logic in this way also allows for
65250648Ssklower 			 * mop-up listeners, which we don't currently implement.
65350648Ssklower 			 * We also wish to have a single socket be able to
65450648Ssklower 			 * listen over any network service provider,
65550648Ssklower 			 * (cons or clns or ip).
65650648Ssklower 			 */
65750648Ssklower 			for (t = tp_listeners; t ; t = t->tp_nextlisten)
65850648Ssklower 				if ((t->tp_lsuffixlen == 0 ||
65950648Ssklower 					 (lsufxlen == t->tp_lsuffixlen &&
66050648Ssklower 					  bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) &&
66150648Ssklower 					((t->tp_flags & TPF_GENERAL_ADDR) ||
66250648Ssklower 					 (laddr->sa_family == t->tp_domain &&
66350648Ssklower 					  (*t->tp_nlproto->nlp_cmpnetaddr)
66450648Ssklower 								(t->tp_npcb, laddr, TP_LOCAL))))
66550648Ssklower 					break;
66636401Ssklower 
66744422Ssklower 			CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
66836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
66936401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
67036401Ssklower 				 * the fixed part (can't take the address of a bit field)
67136401Ssklower 				 */
67244601Ssklower 			IFDEBUG(D_TPINPUT)
67344601Ssklower 				printf("checking if dup CR\n");
67444601Ssklower 			ENDDEBUG
67544422Ssklower 			tpcb = t;
67644422Ssklower 			for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
67744422Ssklower 				if (sref != t->tp_fref)
67844422Ssklower 					continue;
67944422Ssklower 				if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
68044422Ssklower 						t->tp_npcb, faddr, TP_FOREIGN)) {
68144422Ssklower 					IFDEBUG(D_TPINPUT)
68244422Ssklower 						printf("duplicate CR discarded\n");
68344422Ssklower 					ENDDEBUG
68444422Ssklower 					goto discard;
68544422Ssklower 				}
68644422Ssklower 			}
68744422Ssklower 			IFTRACE(D_TPINPUT)
68844422Ssklower 				tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
68944422Ssklower 					tpcb, *lsufxloc, tpcb->tp_state, 0);
69044422Ssklower 			ENDTRACE
69136401Ssklower 		}
69236401Ssklower 
69336401Ssklower 		/*
69436401Ssklower 		 * WE HAVE A TPCB
69536401Ssklower 		 * already know that the classes in the CR match at least
69636401Ssklower 		 * one class implemented, but we don't know yet if they
69736401Ssklower 		 * include any classes permitted by this server.
69836401Ssklower 		 */
69936401Ssklower 
70036401Ssklower 		IFDEBUG(D_TPINPUT)
70136401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
70236401Ssklower 		ENDDEBUG
70336401Ssklower 		IFDEBUG(D_CONN)
70436401Ssklower 			printf(
70536401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
70636401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
70736401Ssklower 		ENDDEBUG
70836401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
70936401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
71036401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
71136401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
71236401Ssklower 
71336401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
71436401Ssklower 
71536401Ssklower 		{
71636401Ssklower 			tpp = tpcb->_tp_param;
71736401Ssklower 			tpp.p_class = class_to_use;
71836401Ssklower 			tpp.p_tpdusize = dusize;
71951996Ssklower 			tpp.p_ptpdusize = pdusize;
72036401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
72136401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
72236401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
72336401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
72442491Ssklower 			tpp.p_version = version;
72536401Ssklower #ifdef notdef
72636401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
72736401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
72836401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
72936401Ssklower #endif notdef
73036401Ssklower 
73136401Ssklower 		CHECK(
73236401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
73350648Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
73436401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
73536401Ssklower 				/* ^ more or less the location of class */
73636401Ssklower 			)
73736401Ssklower 		}
73836401Ssklower 		IFTRACE(D_CONN)
73936401Ssklower 			tptrace(TPPTmisc,
74036401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
74136401Ssklower 				class_to_use,
74236401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
74336401Ssklower 				);
74436401Ssklower 		ENDTRACE
74536401Ssklower 		CHECK(
74636401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
74750648Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
74836401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
74936401Ssklower 				/* ^ more or less the location of class */
75036401Ssklower 			)
75136401Ssklower 		IFDEBUG(D_CONN)
75236401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
75336401Ssklower 				tpcb, tpcb->tp_flags);
75436401Ssklower 		ENDDEBUG
75536401Ssklower 		takes_data = TRUE;
75636401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
75736401Ssklower 		e.ev_number = CR_TPDU;
75836401Ssklower 
75936401Ssklower 		so = tpcb->tp_sock;
76036401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
76144422Ssklower 			struct tp_pcb *parent_tpcb = tpcb;
76236401Ssklower 			/*
76336401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
76436401Ssklower 			 * for this newborn connection, and fill in all the values.
76536401Ssklower 			 */
76636401Ssklower 			IFDEBUG(D_CONN)
76736401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
76836401Ssklower 					so, laddr, faddr, cons_channel);
76936401Ssklower 			ENDDEBUG
77036401Ssklower 			if( (so =
77136401Ssklower 				tp_newsocket(so, faddr, cons_channel,
77236401Ssklower 					class_to_use,
77337469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
77437469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
77536401Ssklower 					) == (struct socket *)0 ) {
77636401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
77736401Ssklower 				 * the tp entity is concerned, the only differences
77837469Ssklower 				 * are CO vs CL
77936401Ssklower 				 */
78036401Ssklower 				IFDEBUG(D_CONN)
78136401Ssklower 					printf("tp_newsocket returns 0\n");
78236401Ssklower 				ENDDEBUG
78336401Ssklower 				goto discard;
78450648Ssklower 			clear_parent_tcb:
78550648Ssklower 				tpcb = 0;
78650648Ssklower 				goto respond;
78736401Ssklower 			}
78836401Ssklower 			tpcb = sototpcb(so);
78944601Ssklower 			insque(tpcb, parent_tpcb);
79036401Ssklower 
79136401Ssklower 			/*
79237469Ssklower 			 * Stash the addresses in the net level pcb
79336401Ssklower 			 * kind of like a pcbconnect() but don't need
79436401Ssklower 			 * or want all those checks.
79536401Ssklower 			 */
79650435Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN);
79750435Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL);
79836401Ssklower 
79937469Ssklower 			/* stash the f suffix in the new tpcb */
80050648Ssklower 			if (tpcb->tp_fsuffixlen = fsufxlen) {
80150648Ssklower 				bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
80250648Ssklower 				(tpcb->tp_nlproto->nlp_putsufx)
80350648Ssklower 						(tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN);
80450648Ssklower 			}
80550648Ssklower 			/* stash the l suffix in the new tpcb */
80650648Ssklower 			tpcb->tp_lsuffixlen = lsufxlen;
80750648Ssklower 			bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
80837469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
80950435Ssklower 					(tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL);
81036401Ssklower #ifdef TP_PERF_MEAS
81136401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
81236401Ssklower 				/* ok, let's create an mbuf for stashing the
81336401Ssklower 				 * statistics if one doesn't already exist
81436401Ssklower 				 */
81536401Ssklower 				(void) tp_setup_perf(tpcb);
81636401Ssklower 			}
81736401Ssklower #endif TP_PERF_MEAS
81836401Ssklower 			tpcb->tp_fref = sref;
81936401Ssklower 
82036401Ssklower 			/* We've already checked for consistency with the options
82136401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
82236401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
82336401Ssklower 			 * Now we set the options in the new socket's tpcb.
82436401Ssklower 			 */
82536401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
82636401Ssklower 
82736401Ssklower 			if(!tpcb->tp_use_checksum)
82836401Ssklower 				IncStat(ts_csum_off);
82936401Ssklower 			if(tpcb->tp_xpd_service)
83036401Ssklower 				IncStat(ts_use_txpd);
83136401Ssklower 			if(tpcb->tp_xtd_format)
83236401Ssklower 				IncStat(ts_xtd_fmt);
83336401Ssklower 
83436401Ssklower 			tpcb->tp_peer_acktime = acktime;
83536401Ssklower 
83636401Ssklower 			/*
83736401Ssklower 			 * The following kludge is used to test retransmissions and
83836401Ssklower 			 * timeout during connection establishment.
83936401Ssklower 			 */
84036401Ssklower 			IFDEBUG(D_ZDREF)
84136401Ssklower 				IncStat(ts_zdebug);
84237469Ssklower 				/*tpcb->tp_fref = 0;*/
84336401Ssklower 			ENDDEBUG
84436401Ssklower 		}
84536401Ssklower 		IncStat(ts_CR_rcvd);
84639929Ssklower 		if (!tpcb->tp_cebit_off) {
84739929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
84839929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
84939929Ssklower 			LOCAL_CREDIT(tpcb);
85039929Ssklower 			CONG_INIT_SAMPLE(tpcb);
85139929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
85239929Ssklower 		}
85336401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
85436401Ssklower 		/*
85536401Ssklower 		 * ER TPDUs have to be recognized separately
85636401Ssklower 		 * because they don't necessarily have a tpcb
85736401Ssklower 		 * with them and we don't want err out looking for such
85836401Ssklower 		 * a beast.
85936401Ssklower 		 * We could put a bunch of little kludges in the
86036401Ssklower 		 * next section of code so it would avoid references to tpcb
86136401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
86236401Ssklower 		 * mess up code for data transfer.
86336401Ssklower 		 */
86436401Ssklower 		IncStat(ts_ER_rcvd);
86536401Ssklower 		e.ev_number = ER_TPDU;
86636401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
86751007Ssklower 		CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size ||
86850176Ssklower 			(tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ||
86951204Ssklower 			tpcb->tp_refstate == REF_FREE ||
87051204Ssklower 			tpcb->tp_refstate == REF_FROZEN),
87150176Ssklower 		       E_TP_MISM_REFS, ts_inv_dref, discard, 0)
87250176Ssklower 
87336401Ssklower 	} else {
87436401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
87536401Ssklower 
87636401Ssklower 		/* In the next 4 checks,
87736401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
87836401Ssklower 		 * the fixed part (can't take the address of a bit field)
87936401Ssklower 		 */
88050648Ssklower #ifdef TPCONS
88150648Ssklower 		if (cons_channel && dutype == DT_TPDU_type) {
88250648Ssklower 			struct isopcb *isop = ((struct isopcb *)
88350648Ssklower 				((struct pklcd *)cons_channel)->lcd_upnext);
88450648Ssklower 			if (isop && isop->isop_refcnt == 1 && isop->isop_socket &&
88550648Ssklower 				(tpcb = sototpcb(isop->isop_socket)) &&
88650648Ssklower 				 (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) {
88750648Ssklower 				IFDEBUG(D_TPINPUT)
88850648Ssklower 					printf("tpinput_dt: class 0 short circuit\n");
88950648Ssklower 				ENDDEBUG
89050648Ssklower 				dref = tpcb->tp_lref;
89150648Ssklower 				sref = tpcb->tp_fref;
89251204Ssklower 				CHECK( (tpcb->tp_refstate == REF_FREE),
89350648Ssklower 					E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89450648Ssklower 					(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89550648Ssklower 				goto tp0_data;
89650648Ssklower 			}
89736401Ssklower 
89850648Ssklower 		}
89945900Ssklower #endif
90045900Ssklower 		{
90136401Ssklower 
90251007Ssklower 			CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) ,
90342944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
90436401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
90536401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
90642944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
90736401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
90851204Ssklower 			CHECK( (tpcb->tp_refstate == REF_FREE),
90942944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
91036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
91136401Ssklower 		}
91236401Ssklower 
91336401Ssklower 		IFDEBUG(D_TPINPUT)
91436401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
91536401Ssklower 		ENDDEBUG
91636401Ssklower 
91736401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
91851204Ssklower 		CHECK( (tpcb->tp_refstate == REF_FROZEN),
91936401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
92036401Ssklower 			ts_inv_dref, respond,
92136401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
92236401Ssklower 
92336401Ssklower 		IFDEBUG(D_TPINPUT)
92436401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
92536401Ssklower 		ENDDEBUG
92636401Ssklower 		/*
92736401Ssklower 		 * At this point the state of the dref could be
92836401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
92936401Ssklower 		 *		   for example, DC may arrive after the close() has detached
93036401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
93136401Ssklower 		 * OPENING : a tpcb exists but no timers yet
93236401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
93336401Ssklower 		 */
93436401Ssklower 
93539929Ssklower         if (!tpcb->tp_cebit_off)
93639929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
93739929Ssklower 
93836401Ssklower 		dusize = tpcb->tp_tpdusize;
93951996Ssklower 		pdusize = tpcb->tp_ptpdusize;
94036401Ssklower 
94136401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
94236401Ssklower 
94336401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
94436401Ssklower 
94537469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
94636401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
94736401Ssklower 
94836401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
94936401Ssklower 					/* not in class 0; 1 octet */
95036401Ssklower 					vb_getval(P, u_char, addlopt);
95136401Ssklower 					break;
95236401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
95342944Ssklower 				{
95442944Ssklower 					u_char odusize = dusize;
95536401Ssklower 					vb_getval(P, u_char, dusize);
95642944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
95742944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
95842944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
95942944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
96036401Ssklower 					IFDEBUG(D_TPINPUT)
96136401Ssklower 						printf("CC dusize 0x%x\n", dusize);
96236401Ssklower 					ENDDEBUG
96342944Ssklower 				}
96436401Ssklower 					break;
96551996Ssklower 			caseof( CC_TPDU_type, TPP_ptpdu_size ):
96651996Ssklower 				{
96751996Ssklower 					u_short opdusize = pdusize;
96851996Ssklower 					switch (vbptr(P)->tpv_len) {
96951996Ssklower 					case 1: pdusize = vbval(P, u_char); break;
97051996Ssklower 					case 2: pdusize = ntohs(vbval(P, u_short)); break;
97151996Ssklower 					default: ;
97251996Ssklower 					IFDEBUG(D_TPINPUT)
97351996Ssklower 						printf("malformed prefered TPDU option\n");
97451996Ssklower 					ENDDEBUG
97551996Ssklower 					}
97651996Ssklower 					CHECK( (pdusize == 0 ||
97751996Ssklower 							(opdusize && (pdusize > opdusize))),
97851996Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
97951996Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
98051996Ssklower 				}
98151996Ssklower 					break;
98236401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
98336401Ssklower 					IFDEBUG(D_TPINPUT)
98436401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
98536401Ssklower 					ENDDEBUG
98636401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
98736401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
98836401Ssklower 					break;
98936401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
99036401Ssklower 					/* class 4 only, 2 octets */
99136401Ssklower 					vb_getval(P, u_short, acktime);
99244947Ssklower 					acktime = ntohs(acktime);
99336401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
99436401Ssklower 					if( (short)acktime <=0 )
99536401Ssklower 						acktime = 2;
99636401Ssklower 					break;
99736401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
99836401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
99936401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
100036401Ssklower 					IFDEBUG(D_TPINPUT)
100136401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
100236401Ssklower 					ENDDEBUG
100336401Ssklower 					break;
100436401Ssklower 
100536401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
100636401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
100736401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
100836401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
100936401Ssklower 					if( tpcb->tp_use_checksum )  {
101036401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
101136401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
101236401Ssklower 					}
101336401Ssklower 					break;
101436401Ssklower 
101536401Ssklower 			/*  this is different from the above because in the context
101636401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
101736401Ssklower 			 */
101836401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
101936401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
102036401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
102136401Ssklower 					if( tpcb->tp_use_checksum )  {
102237469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
102336401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
102436401Ssklower 					}
102536401Ssklower 					break;
102636401Ssklower #ifdef notdef
102736401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
102836401Ssklower 				/* ignore - its length and meaning are
102936401Ssklower 				 * user defined and there's no way
103036401Ssklower 				 * to pass this info to the user anyway
103136401Ssklower 				 */
103236401Ssklower 				break;
103336401Ssklower #endif notdef
103436401Ssklower 
103536401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
103636401Ssklower 				/* used after reduction of window */
103736401Ssklower 				vb_getval(P, u_short, subseq);
103836401Ssklower 				subseq = ntohs(subseq);
103936401Ssklower 				IFDEBUG(D_ACKRECV)
104051204Ssklower 					printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq);
104136401Ssklower 				ENDDEBUG
104236401Ssklower 				break;
104336401Ssklower 
104436401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
104536401Ssklower 				{
104636401Ssklower 					u_int 	ylwe;
104736401Ssklower 					u_short ysubseq, ycredit;
104836401Ssklower 
104936401Ssklower 					fcc_present = TRUE;
105036401Ssklower 					vb_getval(P, u_int,	 	ylwe);
105136401Ssklower 					vb_getval(P, u_short, 	ysubseq);
105236401Ssklower 					vb_getval(P, u_short, 	ycredit);
105336401Ssklower 					ylwe = ntohl(ylwe);
105436401Ssklower 					ysubseq = ntohs(ysubseq);
105536401Ssklower 					ycredit = ntohs(ycredit);
105636401Ssklower 					IFDEBUG(D_ACKRECV)
105751204Ssklower 						printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n",
105851204Ssklower 							"AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref);
105936401Ssklower 					ENDDEBUG
106036401Ssklower 				}
106136401Ssklower 				break;
106236401Ssklower 
106336401Ssklower 			default:
106436401Ssklower 				IFDEBUG(D_TPINPUT)
106536401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
106636401Ssklower 						dutype, vbptr(P)->tpv_code);
106736401Ssklower 				ENDDEBUG
106836401Ssklower 				IFTRACE(D_TPINPUT)
106936401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
107036401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
107136401Ssklower 				ENDTRACE
107236401Ssklower 				IncStat(ts_param_ignored);
107336401Ssklower 				break;
107436401Ssklower #undef caseof
107536401Ssklower 		}
107636401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
107736401Ssklower 
107836401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
107936401Ssklower 
108036401Ssklower 		switch( hdr->tpdu_type ) {
108136401Ssklower 		case CC_TPDU_type:
108236401Ssklower 			/* If CC comes back with an unacceptable class
108336401Ssklower 			 * respond with a DR or ER
108436401Ssklower 			 */
108536401Ssklower 
108636401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
108736401Ssklower 
108836401Ssklower 			{
108936401Ssklower 				tpp = tpcb->_tp_param;
109036401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
109136401Ssklower 				tpp.p_tpdusize = dusize;
109251996Ssklower 				tpp.p_ptpdusize = pdusize;
109336401Ssklower 				tpp.p_dont_change_params = 0;
109436401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
109536401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
109636401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
109736401Ssklower #ifdef notdef
109836401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
109936401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
110036401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
110136401Ssklower #endif notdef
110236401Ssklower 
110336401Ssklower 			CHECK(
110436401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
110536401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
110636401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
110736401Ssklower 					/* ^ more or less the location of class */
110836401Ssklower 				)
110936401Ssklower 			IFTRACE(D_CONN)
111036401Ssklower 				tptrace(TPPTmisc,
111136401Ssklower 					"after 1 consist class, out, tpconsout",
111236401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
111336401Ssklower 					);
111436401Ssklower 			ENDTRACE
111536401Ssklower 			CHECK(
111636401Ssklower 				((class_to_use == TP_CLASS_0)&&
111736401Ssklower 					(dgout_routine != tpcons_output)),
111836401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
111936401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
112036401Ssklower 					/* ^ more or less the location of class */
112136401Ssklower 				)
112245900Ssklower #ifdef TPCONS
112345900Ssklower 				if (tpcb->tp_netservice == ISO_CONS &&
112445900Ssklower 					class_to_use == TP_CLASS_0) {
112545900Ssklower 					struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
112645900Ssklower 					struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
112745900Ssklower 					lcp->lcd_flags &= ~X25_DG_CIRCUIT;
112845900Ssklower 				}
112945900Ssklower #endif
113036401Ssklower 			}
113136401Ssklower 			if( ! tpcb->tp_use_checksum)
113236401Ssklower 				IncStat(ts_csum_off);
113336401Ssklower 			if(tpcb->tp_xpd_service)
113436401Ssklower 				IncStat(ts_use_txpd);
113536401Ssklower 			if(tpcb->tp_xtd_format)
113636401Ssklower 				IncStat(ts_xtd_fmt);
113736401Ssklower 
113836401Ssklower 			IFTRACE(D_CONN)
113936401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
114036401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
114136401Ssklower 					hdr->tpdu_CCclass);
114236401Ssklower 			ENDTRACE
114336401Ssklower 
114436401Ssklower 			/* if called or calling suffices appeared on the CC,
114536401Ssklower 			 * they'd better jive with what's in the pcb
114636401Ssklower 			 */
114736401Ssklower 			if( fsufxlen ) {
114836401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
114936401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
115036401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
115136401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
115236401Ssklower 			}
115336401Ssklower 			if( lsufxlen ) {
115436401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
115536401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
115636401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
115736401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
115836401Ssklower 			}
115936401Ssklower 
116036401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
116136401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
116236401Ssklower 			takes_data = TRUE;
116336401Ssklower 			e.ev_number = CC_TPDU;
116436401Ssklower 			IncStat(ts_CC_rcvd);
116536401Ssklower 			break;
116636401Ssklower 
116736401Ssklower 		case DC_TPDU_type:
116836401Ssklower 			if (sref != tpcb->tp_fref)
116936401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
117036401Ssklower 					sref, tpcb->tp_fref);
117136401Ssklower 
117236401Ssklower 			CHECK( (sref != tpcb->tp_fref),
117342944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
117436401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
117542944Ssklower 
117636401Ssklower 			e.ev_number = DC_TPDU;
117736401Ssklower 			IncStat(ts_DC_rcvd);
117836401Ssklower 			break;
117936401Ssklower 
118036401Ssklower 		case DR_TPDU_type:
118136401Ssklower 			IFTRACE(D_TPINPUT)
118236401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
118336401Ssklower 			ENDTRACE
118442944Ssklower 			if (sref != tpcb->tp_fref) {
118536401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
118636401Ssklower 					sref, tpcb->tp_fref);
118742944Ssklower 			}
118836401Ssklower 
118942944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
119042944Ssklower 					tpcb->tp_state != TP_CRSENT),
119142944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
119236401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
119336401Ssklower 
119436401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
119536401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
119636401Ssklower 			takes_data = TRUE;
119736401Ssklower 			e.ev_number = DR_TPDU;
119836401Ssklower 			IncStat(ts_DR_rcvd);
119936401Ssklower 			break;
120036401Ssklower 
120136401Ssklower 		case ER_TPDU_type:
120236401Ssklower 			IFTRACE(D_TPINPUT)
120336401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
120436401Ssklower 			ENDTRACE
120536401Ssklower 			e.ev_number = ER_TPDU;
120636401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
120736401Ssklower 			IncStat(ts_ER_rcvd);
120836401Ssklower 			break;
120936401Ssklower 
121036401Ssklower 		case AK_TPDU_type:
121136401Ssklower 
121236401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
121336401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
121436401Ssklower 
121536401Ssklower 			if (tpcb->tp_xtd_format) {
121636401Ssklower #ifdef BYTE_ORDER
121736401Ssklower 				union seq_type seqeotX;
121836401Ssklower 
121936401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
122036401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
122136401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
122236401Ssklower #else
122336401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
122436401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
122536401Ssklower #endif BYTE_ORDER
122636401Ssklower 			} else {
122736401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
122836401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
122936401Ssklower 			}
123036401Ssklower 			IFTRACE(D_TPINPUT)
123136401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
123236401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
123336401Ssklower 					subseq, fcc_present);
123436401Ssklower 			ENDTRACE
123536401Ssklower 
123636401Ssklower 			e.ev_number = AK_TPDU;
123736401Ssklower 			IncStat(ts_AK_rcvd);
123836401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
123936401Ssklower 			break;
124036401Ssklower 
124136401Ssklower 		case XAK_TPDU_type:
124236401Ssklower 			if (tpcb->tp_xtd_format) {
124336401Ssklower #ifdef BYTE_ORDER
124436401Ssklower 				union seq_type seqeotX;
124536401Ssklower 
124636401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
124736401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
124836401Ssklower #else
124936401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
125036401Ssklower #endif BYTE_ORDER
125136401Ssklower 			} else {
125236401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
125336401Ssklower 			}
125436401Ssklower 			e.ev_number = XAK_TPDU;
125536401Ssklower 			IncStat(ts_XAK_rcvd);
125636401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
125736401Ssklower 			break;
125836401Ssklower 
125936401Ssklower 		case XPD_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(XPD_TPDU).e_seq = seqeotX.s_seq;
126636401Ssklower #else
126736401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
126836401Ssklower #endif BYTE_ORDER
126936401Ssklower 			} else {
127036401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
127136401Ssklower 			}
127236401Ssklower 			takes_data = TRUE;
127336401Ssklower 			e.ev_number = XPD_TPDU;
127436401Ssklower 			IncStat(ts_XPD_rcvd);
127536401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
127636401Ssklower 			break;
127736401Ssklower 
127836401Ssklower 		case DT_TPDU_type:
127936401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
128036401Ssklower 			   * A little crude but it works.
128136401Ssklower 			   */
128236401Ssklower 
128336401Ssklower 				IFDEBUG(D_DROP)
128436401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
128536401Ssklower 						IncStat(ts_ydebug);
128636401Ssklower 						goto discard;
128736401Ssklower 					}
128836401Ssklower 				ENDDEBUG
128936401Ssklower 			}
129036401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
129150648Ssklower 			tp0_data:
129236401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
129336401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
129436401Ssklower 			} else if (tpcb->tp_xtd_format) {
129536401Ssklower #ifdef BYTE_ORDER
129636401Ssklower 				union seq_type seqeotX;
129736401Ssklower 
129836401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
129936401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
130036401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
130136401Ssklower #else
130236401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
130336401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
130436401Ssklower #endif BYTE_ORDER
130536401Ssklower 			} else {
130636401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
130736401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
130836401Ssklower 			}
130936401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
131036401Ssklower 				IncStat(ts_eot_input);
131136401Ssklower 			takes_data = TRUE;
131236401Ssklower 			e.ev_number = DT_TPDU;
131336401Ssklower 			IncStat(ts_DT_rcvd);
131436401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
131536401Ssklower 			break;
131636401Ssklower 
131736401Ssklower 		case GR_TPDU_type:
131836401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
131936401Ssklower 			/* drop through */
132036401Ssklower 		default:
132136401Ssklower 			/* this should NEVER happen because there is a
132236401Ssklower 			 * check for dutype well above here
132336401Ssklower 			 */
132436401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
132536401Ssklower 			IFDEBUG(D_TPINPUT)
132636401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
132736401Ssklower 			ENDDEBUG
132836401Ssklower 			IncStat(ts_inv_dutype);
132936401Ssklower 			goto respond;
133036401Ssklower 		}
133136401Ssklower 	}
133236401Ssklower 	/* peel off the tp header;
133336401Ssklower 	 * remember that the du_li doesn't count itself.
133436401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
133536401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
133636401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
133736401Ssklower 	 */
133836401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
133937469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
134036401Ssklower 
134137469Ssklower 	if (takes_data) {
134237469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
134337469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
134448749Ssklower 		struct {
134548749Ssklower 			struct tp_disc_reason dr;
134648749Ssklower 			struct cmsghdr x_hdr;
134748749Ssklower 		} x;
134848749Ssklower #define c_hdr x.x_hdr
134948749Ssklower 		register struct mbuf *n;
135036401Ssklower 
135137469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
135237469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
135336401Ssklower 		switch( hdr->tpdu_type ) {
135437469Ssklower 
135536401Ssklower 		case CR_TPDU_type:
135637469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
135737469Ssklower 			goto make_control_msg;
135837469Ssklower 
135936401Ssklower 		case CC_TPDU_type:
136037469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
136137469Ssklower 			goto make_control_msg;
136237469Ssklower 
136336401Ssklower 		case DR_TPDU_type:
136448749Ssklower 			x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
136548749Ssklower 			x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
136648749Ssklower 			x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
136748749Ssklower 			x.dr.dr_reason = hdr->tpdu_DRreason;
136837469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
136937469Ssklower 		make_control_msg:
137048749Ssklower 			datalen += sizeof(c_hdr);
137148749Ssklower 			c_hdr.cmsg_len = datalen;
137237469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
137337469Ssklower 			mbtype = MT_CONTROL;
137443334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
137548749Ssklower 			if (n == 0)
137648749Ssklower 				{m_freem(m); m = 0; datalen = 0; goto invoke; }
137748749Ssklower 			if (hdr->tpdu_type == DR_TPDU_type) {
137848749Ssklower 				datalen += sizeof(x) - sizeof(c_hdr);
137948749Ssklower 				bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
138048749Ssklower 			} else
138148749Ssklower 				bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
138248749Ssklower 					  n->m_len = sizeof(c_hdr));
138348749Ssklower 			n->m_next = m;
138448749Ssklower 			m = n;
138537469Ssklower 			/* FALLTHROUGH */
138637469Ssklower 
138736401Ssklower 		case XPD_TPDU_type:
138837469Ssklower 			if (mbtype != MT_CONTROL)
138937469Ssklower 				mbtype = MT_OOBDATA;
139037469Ssklower 			m->m_flags |= M_EOR;
139137469Ssklower 			/* FALLTHROUGH */
139237469Ssklower 
139336401Ssklower 		case DT_TPDU_type:
139437469Ssklower 			for (n = m; n; n = n->m_next) {
139537469Ssklower 				MCHTYPE(n, mbtype);
139637469Ssklower 			}
139743334Ssklower 		invoke:
139837469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
139936401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
140036401Ssklower 			break;
140136401Ssklower 
140236401Ssklower 		default:
140336401Ssklower 			printf(
140436401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
140536401Ssklower 				hdr->tpdu_type, takes_data, m);
140636401Ssklower 			break;
140736401Ssklower 		}
140836401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
140936401Ssklower 		m = MNULL;
141036401Ssklower 	}
141136401Ssklower 
141236401Ssklower 	IncStat(ts_tpdu_rcvd);
141336401Ssklower 
141436401Ssklower 	IFDEBUG(D_TPINPUT)
141536401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
141636401Ssklower 			tpcb->tp_state, e.ev_number, m );
141736401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
141836401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
141936401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
142036401Ssklower 	ENDDEBUG
142136401Ssklower 
142236401Ssklower 	error = tp_driver(tpcb, &e);
142336401Ssklower 
142436401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
142536401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
142636401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
142736401Ssklower 		tpcb->tp_sock->so_error = error;
142836401Ssklower 
142936401Ssklower 	/* Kludge to keep the state tables under control (adding
143036401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
143136401Ssklower 	 * the data would have exploded the tables and made a big mess ).
143236401Ssklower 	 */
143336401Ssklower 	switch(e.ev_number) {
143436401Ssklower 		case CC_TPDU:
143536401Ssklower 		case DR_TPDU:
143636401Ssklower 		case CR_TPDU:
143736401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
143836401Ssklower 			IFDEBUG(D_TPINPUT)
143936401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
144036401Ssklower 				m, takes_data);
144136401Ssklower 			ENDDEBUG
144236401Ssklower 			break;
144336401Ssklower 		default:
144436401Ssklower 			break;
144536401Ssklower 	}
144636401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
144736401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
144836401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
144936401Ssklower 	 */
145036401Ssklower 
145136401Ssklower separate:
145236401Ssklower 	if ( takes_data == 0 )  {
145336401Ssklower 		ASSERT( m != MNULL );
145436401Ssklower 		/*
145536401Ssklower 		 * we already peeled off the prev. tp header so
145636401Ssklower 		 * we can just pull up some more and repeat
145736401Ssklower 		 */
145836401Ssklower 
145937469Ssklower 		if( m = tp_inputprep(m) ) {
146036401Ssklower 		IFDEBUG(D_TPINPUT)
146136401Ssklower 			hdr = mtod(m, struct tpdu *);
146236401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
146336401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
146436401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
146536401Ssklower 		ENDDEBUG
146636401Ssklower 
146736401Ssklower 			IncStat(ts_concat_rcvd);
146836401Ssklower 			goto again;
146936401Ssklower 		}
147036401Ssklower 	}
147136401Ssklower 	if ( m != MNULL ) {
147236401Ssklower 		IFDEBUG(D_TPINPUT)
147336401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
147436401Ssklower 		ENDDEBUG
147536401Ssklower 		m_freem(m);
147636401Ssklower 		IFDEBUG(D_TPINPUT)
147736401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
147836401Ssklower 		ENDDEBUG
147936401Ssklower 	}
148036401Ssklower 	return (ProtoHook) tpcb;
148136401Ssklower 
148236401Ssklower discard:
148336401Ssklower 	/* class 4: drop the tpdu */
148436401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
148536401Ssklower 	 * to which connection it applies
148636401Ssklower 	 */
148736401Ssklower 	IFDEBUG(D_TPINPUT)
148836401Ssklower 		printf("tp_input DISCARD\n");
148936401Ssklower 	ENDDEBUG
149036401Ssklower 	IFTRACE(D_TPINPUT)
149136401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
149236401Ssklower 	ENDTRACE
149336401Ssklower 	m_freem(m);
149436401Ssklower 	IncStat(ts_recv_drop);
149536401Ssklower 	return (ProtoHook)0;
149636401Ssklower 
149742944Ssklower nonx_dref:
149842944Ssklower 	switch (dutype) {
149942944Ssklower 	default:
150042944Ssklower 		goto discard;
150142944Ssklower 	case CC_TPDU_type:
150242944Ssklower 		/* error = E_TP_MISM_REFS; */
150342944Ssklower 		break;
150442944Ssklower 	case DR_TPDU_type:
150542944Ssklower 		error |= TP_ERROR_SNDC;
150642944Ssklower 	}
150736401Ssklower respond:
150843334Ssklower 	IFDEBUG(D_TPINPUT)
150942944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
151036401Ssklower 	ENDDEBUG
151136401Ssklower 	IFTRACE(D_TPINPUT)
151242944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
151336401Ssklower 	ENDTRACE
151442944Ssklower 	if (sref == 0)
151536401Ssklower 		goto discard;
151637469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
151742944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
151850648Ssklower 				cons_channel, dgout_routine);
151936401Ssklower 	IFDEBUG(D_ERROR_EMIT)
152036401Ssklower 		printf("tp_input after error_emit\n");
152136401Ssklower 	ENDDEBUG
152236401Ssklower 
152336401Ssklower #ifdef lint
152436401Ssklower 	printf("",sref,opt);
152536401Ssklower #endif lint
152636401Ssklower 	IncStat(ts_recv_drop);
152736401Ssklower 	return (ProtoHook)0;
152836401Ssklower }
152936401Ssklower 
153036401Ssklower 
153136401Ssklower /*
153236401Ssklower  * NAME: tp_headersize()
153336401Ssklower  *
153436401Ssklower  * CALLED FROM:
153536401Ssklower  *  tp_emit() and tp_sbsend()
153636401Ssklower  *  TP needs to know the header size so it can figure out how
153736401Ssklower  *  much data to put in each tpdu.
153836401Ssklower  *
153936401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
154036401Ssklower  *  For a given connection, represented by (tpcb), and
154136401Ssklower  *  tpdu type (dutype), return the size of a tp header.
154236401Ssklower  *
154336401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
154436401Ssklower  *
154536401Ssklower  * SIDE EFFECTS:
154636401Ssklower  *
154736401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
154836401Ssklower  */
154936401Ssklower int
155036401Ssklower tp_headersize(dutype, tpcb)
155136401Ssklower 	int 			dutype;
155236401Ssklower 	struct tp_pcb 	*tpcb;
155336401Ssklower {
155436401Ssklower 	register int size = 0;
155536401Ssklower 
155636401Ssklower 	IFTRACE(D_CONN)
155736401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
155836401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
155936401Ssklower 	ENDTRACE
156036401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
156136401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
156236401Ssklower 			(dutype == DR_TPDU_type) ||
156336401Ssklower 			(dutype == CR_TPDU_type) )) {
156436401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
156536401Ssklower 			dutype, tpcb->tp_class);
156636401Ssklower 	/* TODO: identify this and GET RID OF IT */
156736401Ssklower 	}
156836401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
156936401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
157036401Ssklower 			(dutype == DR_TPDU_type) ||
157136401Ssklower 			(dutype == CR_TPDU_type) );
157236401Ssklower 
157336401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
157436401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
157536401Ssklower 	} else  {
157636401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
157736401Ssklower 	}
157836401Ssklower 	return size;
157936401Ssklower 	/* caller must get network level header size separately */
158036401Ssklower }
1581