xref: /csrg-svn/sys/netiso/tp_input.c (revision 43334)
136401Ssklower /***********************************************************
236401Ssklower 		Copyright IBM Corporation 1987
336401Ssklower 
436401Ssklower                       All Rights Reserved
536401Ssklower 
636401Ssklower Permission to use, copy, modify, and distribute this software and its
736401Ssklower documentation for any purpose and without fee is hereby granted,
836401Ssklower provided that the above copyright notice appear in all copies and that
936401Ssklower both that copyright notice and this permission notice appear in
1036401Ssklower supporting documentation, and that the name of IBM not be
1136401Ssklower used in advertising or publicity pertaining to distribution of the
1236401Ssklower software without specific, written prior permission.
1336401Ssklower 
1436401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036401Ssklower SOFTWARE.
2136401Ssklower 
2236401Ssklower ******************************************************************/
2336401Ssklower 
2436401Ssklower /*
2536401Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636401Ssklower  */
2736401Ssklower /*
2836401Ssklower  * ARGO TP
2936401Ssklower  *
3036401Ssklower  * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
3136401Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
32*43334Ssklower  *	@(#)tp_input.c	7.11 (Berkeley) 06/20/90 *
3336401Ssklower  *
3436401Ssklower  * tp_input() gets an mbuf chain from ip.  Actually, not directly
3536401Ssklower  * from ip, because ip calls a net-level routine that strips off
3636401Ssklower  * the net header and then calls tp_input(), passing the proper type
3736401Ssklower  * of addresses for the address family in use (how it figures out
3836401Ssklower  * which AF is not yet determined.
3936401Ssklower  *
4036401Ssklower  * Decomposing the tpdu is some of the most laughable code.  The variable-length
4136401Ssklower  * parameters and the problem of non-aligned memory references
4236401Ssklower  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
4336401Ssklower  * to loop through the header and decompose it.
4436401Ssklower  *
4536401Ssklower  * The routine tp_newsocket() is called when a CR comes in for a listening
4636401Ssklower  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
4736401Ssklower  * "child" socket.  Most tpcb values are copied from the parent tpcb into
4836401Ssklower  * the child.
4936401Ssklower  *
5036401Ssklower  * Also in here is tp_headersize() (grot) which tells the expected size
5136401Ssklower  * of a tp header, to be used by other layers.  It's in here because it
5236401Ssklower  * uses the static structure tpdu_info.
5336401Ssklower  */
5436401Ssklower 
5536401Ssklower #ifndef lint
5636401Ssklower static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $";
5736401Ssklower #endif lint
5836401Ssklower 
5936401Ssklower #include "argoxtwentyfive.h"
6036401Ssklower #include "param.h"
6136401Ssklower #include "mbuf.h"
6236401Ssklower #include "socket.h"
6336401Ssklower #include "socketvar.h"
6436401Ssklower #include "domain.h"
6536401Ssklower #include "protosw.h"
6636401Ssklower #include "errno.h"
6736401Ssklower #include "time.h"
6836401Ssklower #include "kernel.h"
6936401Ssklower #include "types.h"
7037469Ssklower #include "iso_errno.h"
7137469Ssklower #include "tp_param.h"
7237469Ssklower #include "tp_timer.h"
7337469Ssklower #include "tp_stat.h"
7437469Ssklower #include "tp_pcb.h"
7537469Ssklower #include "argo_debug.h"
7637469Ssklower #include "tp_trace.h"
7737469Ssklower #include "tp_tpdu.h"
7837469Ssklower #include "iso.h"
7937469Ssklower #include "cons.h"
8036401Ssklower 
8136401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
8236401Ssklower 
8337469Ssklower /*
8437469Ssklower 	#ifdef lint
8537469Ssklower 	#undef ATTR
8637469Ssklower 	#define ATTR(X)ev_number
8737469Ssklower 	#endif lint
8837469Ssklower */
8936401Ssklower 
9036401Ssklower struct mbuf *
9136401Ssklower tp_inputprep(m)
9237469Ssklower 	register struct mbuf *m;
9336401Ssklower {
9437469Ssklower 	int hdrlen;
9536401Ssklower 
9636401Ssklower 	IFDEBUG(D_TPINPUT)
9737469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
9836401Ssklower 	ENDDEBUG
9936401Ssklower 
10036401Ssklower 	while(  m->m_len < 1 ) {
10136401Ssklower 		if( (m = m_free(m)) == MNULL ) {
10236401Ssklower 			return (struct mbuf *)0;
10336401Ssklower 		}
10436401Ssklower 	}
10537469Ssklower 	if(((int)m->m_data) & 0x3) {
10637469Ssklower 		/* If we are not 4-byte aligned, we have to be
10737469Ssklower 		 * above the beginning of the mbuf, and it is ok just
10837469Ssklower 		 * to slide it back.
10937469Ssklower 		 */
11037469Ssklower 		caddr_t ocp = m->m_data;
11136401Ssklower 
11237469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
11337469Ssklower 		ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
11436401Ssklower 	}
11536401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
11636401Ssklower 
11737469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
11837469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
11936401Ssklower 
12037469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
12136401Ssklower 
12236401Ssklower 	/*
12336401Ssklower 	 * now pull up the whole tp header
12436401Ssklower 	 */
12537469Ssklower 	if ( m->m_len < hdrlen) {
12637469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
12736401Ssklower 			IncStat(ts_recv_drop);
12836401Ssklower 			return (struct mbuf *)0;
12936401Ssklower 		}
13036401Ssklower 	}
13136401Ssklower 	IFDEBUG(D_INPUT)
13236401Ssklower 	printf(
13336401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
13437469Ssklower 		hdrlen, m->m_len);
13536401Ssklower 	ENDDEBUG
13636401Ssklower 	return m;
13736401Ssklower }
13836401Ssklower 
13936401Ssklower /* begin groan
14036401Ssklower  * -- this array and the following macros allow you to step through the
14136401Ssklower  * parameters of the variable part of a header
14236401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
14336401Ssklower  * should change, this array has to be rearranged
14436401Ssklower  */
14536401Ssklower 
14636401Ssklower #define TP_LEN_CLASS_0_INDEX	2
14736401Ssklower #define TP_MAX_DATA_INDEX 3
14836401Ssklower 
14936401Ssklower static u_char tpdu_info[][4] =
15036401Ssklower {
15136401Ssklower /*								length						 max data len */
15236401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
15336401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
15436401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
15536401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
15636401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
15736401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
15836401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
15936401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
16036401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
16136401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
16236401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
16336401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
16436401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
16536401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
16636401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
16736401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
16836401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
16936401Ssklower };
17036401Ssklower 
17142944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
172*43334Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
17342944Ssklower 	goto Whattodo; }
17442944Ssklower 
175*43334Ssklower tpibrk() {}
176*43334Ssklower 
17736401Ssklower /*
17836401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
17936401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
18036401Ssklower  */
18136401Ssklower 
18242944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
18342944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
18442944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
18542944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
18642944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
18742944Ssklower 				respond, P - (caddr_t)hdr);\
18842944Ssklower 		if (P == PLIM) break;
18936401Ssklower 
19042944Ssklower #define END_WHILE_OPTIONS(P) } }
19136401Ssklower 
19236401Ssklower /* end groan */
19336401Ssklower 
19436401Ssklower /*
19536401Ssklower  * NAME:  tp_newsocket()
19636401Ssklower  *
19736401Ssklower  * CALLED FROM:
19836401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
19936401Ssklower  * is awaiting a  connection request
20036401Ssklower  *
20136401Ssklower  * FUNCTION and ARGUMENTS:
20236401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
20336401Ssklower  *  using a copy of the net level pcb for the parent socket.
20436401Ssklower  *  (so) is the parent socket.
20536401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
20636401Ssklower  *
20736401Ssklower  * RETURN VALUE:
20836401Ssklower  *  a new socket structure, being this end of the newly formed connection.
20936401Ssklower  *
21036401Ssklower  * SIDE EFFECTS:
21136401Ssklower  *  Sets a few things in the tpcb and net level pcb
21236401Ssklower  *
21336401Ssklower  * NOTES:
21436401Ssklower  */
21536401Ssklower static struct socket *
21636401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
21736401Ssklower 	struct socket				*so;
21836401Ssklower 	struct sockaddr				*fname;
21936401Ssklower 	u_int						cons_channel;
22036401Ssklower 	u_char						class_to_use;
22136401Ssklower 	u_int						netservice;
22236401Ssklower {
22336401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
22436401Ssklower 	struct tp_pcb *			 newtpcb;
22536401Ssklower 
22636401Ssklower 	/*
22736401Ssklower 	 * sonewconn() gets a new socket structure,
22836401Ssklower 	 * a new lower layer pcb and a new tpcb,
22936401Ssklower 	 * but the pcbs are unnamed (not bound)
23036401Ssklower 	 */
23136401Ssklower 	IFTRACE(D_NEWSOCK)
23238841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
23339196Ssklower 			so, tpcb, so->so_head, 0);
23436401Ssklower 	ENDTRACE
23536401Ssklower 
23640636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
23736401Ssklower 		return so;
23836401Ssklower 	IFTRACE(D_NEWSOCK)
23938841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
24038841Ssklower 			so, so->so_head, 0, 0);
24136401Ssklower 	ENDTRACE
24236401Ssklower 
24336401Ssklower 	IFDEBUG(D_NEWSOCK)
24437469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
24537469Ssklower 				cons_channel, so);
24637469Ssklower 		dump_addr(fname);
24736401Ssklower 		{
24836401Ssklower 			struct socket *t, *head ;
24936401Ssklower 
25036401Ssklower 			head = so->so_head;
25136401Ssklower 			t = so;
25236401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
25336401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
25436401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
25536401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
25636401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
25736401Ssklower 		}
25836401Ssklower 	ENDDEBUG
25936401Ssklower 
26036401Ssklower 	/*
26136401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
26236401Ssklower 	 */
26336401Ssklower 	newtpcb = sototpcb(so);
26436401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
26536401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
26636401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
26736401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
26836401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
26936401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
27037469Ssklower 	soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
27136401Ssklower 
27237469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
27336401Ssklower 		/*
27437469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
27536401Ssklower 		 */
27636401Ssklower 		struct mbuf *conndata;
27736401Ssklower 
27837469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
27936401Ssklower 		IFDEBUG(D_CONN)
28036401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
28136401Ssklower 		ENDDEBUG
28237469Ssklower 		newtpcb->tp_ucddata = conndata;
28336401Ssklower 	}
28436401Ssklower 
28536401Ssklower 	tpcb = newtpcb;
28636401Ssklower 	tpcb->tp_state = TP_LISTENING;
28736401Ssklower 	tpcb->tp_class = class_to_use;
28836401Ssklower 	tpcb->tp_netservice = netservice;
28936401Ssklower 
29036401Ssklower 
29136401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
29236401Ssklower 	if ( fname ) {
29336401Ssklower 		/*
29436401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
29536401Ssklower 		 */
29636401Ssklower 		struct mbuf	*m;
29736401Ssklower 		int			err;
29836401Ssklower 
29936401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
30036401Ssklower 		if (m) {
30136401Ssklower 			/*
30236401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
30336401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
30436401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
30536401Ssklower 			 * sigh.
30636401Ssklower 			 */
30737469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
30837469Ssklower 			m->m_len = fname->sa_len;
30936401Ssklower 
31036401Ssklower 			/* grot  : have to say the kernel can override params in
31136401Ssklower 			 * the passive open case
31236401Ssklower 			 */
31336401Ssklower 			tpcb->tp_dont_change_params = 0;
31436401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
31536401Ssklower 			m_free(m);
31636401Ssklower 
31736401Ssklower 			if (!err)
31836401Ssklower 				goto ok;
31936401Ssklower 		}
32036401Ssklower 		IFDEBUG(D_CONN)
32136401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
32236401Ssklower 				tpcb, so);
32336401Ssklower 		ENDDEBUG
32436401Ssklower 		(void) tp_detach(tpcb);
32536401Ssklower 		return 0;
32636401Ssklower 	}
32736401Ssklower ok:
32836401Ssklower 	IFDEBUG(D_TPINPUT)
32936401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
33036401Ssklower 			so, sototpcb(so));
33136401Ssklower 	ENDDEBUG
33236401Ssklower 	return so;
33336401Ssklower }
33436401Ssklower 
33536401Ssklower #ifndef CONS
33636401Ssklower tpcons_output()
33736401Ssklower {
33836401Ssklower 	return(0);
33936401Ssklower }
34036401Ssklower #endif !CONS
34136401Ssklower 
34236401Ssklower /*
34336401Ssklower  * NAME: 	tp_input()
34436401Ssklower  *
34536401Ssklower  * CALLED FROM:
34636401Ssklower  *  net layer input routine
34736401Ssklower  *
34836401Ssklower  * FUNCTION and ARGUMENTS:
34936401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
35036401Ssklower  *  is one. Create the appropriate type of event and call the driver.
35136401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
35236401Ssklower  *
35336401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
35436401Ssklower  * 	has been m_pullup-ed.
35536401Ssklower  *
35636401Ssklower  * RETURN VALUE: Nada
35736401Ssklower  *
35836401Ssklower  * SIDE EFFECTS:
35936401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
36036401Ssklower  *
36136401Ssklower  * NOTE:
36236401Ssklower  *  The initial value of acktime is 2 so that we will never
36336401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
36436401Ssklower  *  computation of the retransmission timer value, and so it
36536401Ssklower  *  mustn't be zero.
36636401Ssklower  *  2 seems like a reasonable minimum.
36736401Ssklower  */
36836401Ssklower ProtoHook
36939929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
37036401Ssklower 	register	struct mbuf 	*m;
37136401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
37236401Ssklower 	u_int 						cons_channel;
37336401Ssklower 	int 						(*dgout_routine)();
37439929Ssklower 	int							ce_bit;
37536401Ssklower 
37636401Ssklower {
37736401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
37836401Ssklower 	register struct tpdu 	*hdr = mtod(m, struct tpdu *);
37936401Ssklower 	struct socket 			*so;
38036401Ssklower 	struct tp_event 		e;
38142944Ssklower 	int 					error = 0;
38236401Ssklower 	unsigned 				dutype;
38342944Ssklower 	u_short 				dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
38442944Ssklower 	u_char 					preferred_class = 0, class_to_use = 0;
38542944Ssklower 	u_char					opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
38636401Ssklower #ifdef TP_PERF_MEAS
38738841Ssklower 	u_char					perf_meas;
38836401Ssklower #endif TP_PERF_MEAS
38942944Ssklower 	u_char					fsufxlen = 0;
39042944Ssklower 	u_char					lsufxlen = 0;
39142944Ssklower 	caddr_t					fsufxloc = 0, lsufxloc = 0;
39242944Ssklower 	int						tpdu_len = 0;
39342944Ssklower 	u_int 					takes_data = FALSE;
39442944Ssklower 	u_int					fcc_present = FALSE;
39542944Ssklower 	int						errlen = 0;
39636401Ssklower 	struct tp_conn_param 	tpp;
39736401Ssklower 	int						tpcons_output();
39836401Ssklower 
39938841Ssklower again:
40036401Ssklower #ifdef TP_PERF_MEAS
40138841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
40236401Ssklower #endif TP_PERF_MEAS
40336401Ssklower 
40436401Ssklower 	IFDEBUG(D_TPINPUT)
40536401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
40636401Ssklower 	ENDDEBUG
40736401Ssklower 
40836401Ssklower 
40936401Ssklower 	/*
41036401Ssklower 	 * get the actual tpdu length - necessary for monitoring
41136401Ssklower 	 * and for checksumming
41236401Ssklower 	 *
41336401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
41436401Ssklower 	 */
41536401Ssklower 
41636401Ssklower 	{ 	register struct mbuf *n=m;
41736401Ssklower #	ifdef ARGO_DEBUG
41836401Ssklower 		int chain_length = 0;
41936401Ssklower #	endif ARGO_DEBUG
42036401Ssklower 
42136401Ssklower 		for(;;) {
42236401Ssklower 			tpdu_len += n->m_len;
42336401Ssklower 			IFDEBUG(D_MBUF_MEAS)
42437469Ssklower 				if( n->m_flags & M_EXT) {
42536401Ssklower 					IncStat(ts_mb_cluster);
42636401Ssklower 				} else {
42736401Ssklower 					IncStat(ts_mb_small);
42836401Ssklower 				}
42936401Ssklower 				chain_length ++;
43036401Ssklower 			ENDDEBUG
43136401Ssklower 			if (n->m_next == MNULL ) {
43236401Ssklower 				break;
43336401Ssklower 			}
43436401Ssklower 			n = n->m_next;
43536401Ssklower 		}
43636401Ssklower 		IFDEBUG(D_MBUF_MEAS)
43736401Ssklower 			if(chain_length > 16)
43836401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
43936401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
44036401Ssklower 		ENDDEBUG
44136401Ssklower 	}
44236401Ssklower 	IFTRACE(D_TPINPUT)
44336401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
44436401Ssklower 			0);
44536401Ssklower 	ENDTRACE
44636401Ssklower 
44736401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
44836401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
44936401Ssklower 	dutype = (int)hdr->tpdu_type;
45036401Ssklower 
45136401Ssklower 	IFDEBUG(D_TPINPUT)
45236401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
45336401Ssklower 			cons_channel, dref);
45436401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
45536401Ssklower 	ENDDEBUG
45636401Ssklower 	IFTRACE(D_TPINPUT)
45736401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
45836401Ssklower 			cons_channel, dutype, dref, 0);
45936401Ssklower 	ENDTRACE
46036401Ssklower 
46136401Ssklower 
46236401Ssklower #ifdef ARGO_DEBUG
46336401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
46436401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
46536401Ssklower 			dutype, cons_channel, dref);
46636401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
46736401Ssklower 
46836401Ssklower 		IncStat(ts_inv_dutype);
46936401Ssklower 		goto discard;
47036401Ssklower 	}
47136401Ssklower #endif ARGO_DEBUG
47236401Ssklower 
47336401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
47436401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
47536401Ssklower 		2 );
47636401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
47736401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
47836401Ssklower 		 */
47936401Ssklower 
48036401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
48136401Ssklower 	 * at the beginning of connection establishment, and by
48236401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
48336401Ssklower 	 */
48436401Ssklower 	if ( dutype == CR_TPDU_type ) {
48536401Ssklower 		u_char alt_classes = 0;
48636401Ssklower 
48737469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
48836401Ssklower 		opt = hdr->tpdu_CRoptions;
48936401Ssklower 
49036401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
49136401Ssklower 
49236401Ssklower 			switch( vbptr(P)->tpv_code ) {
49336401Ssklower 
49436401Ssklower 			case	TPP_tpdu_size:
49536401Ssklower 				vb_getval(P, u_char, dusize);
49636401Ssklower 				IFDEBUG(D_TPINPUT)
49736401Ssklower 					printf("CR dusize 0x%x\n", dusize);
49836401Ssklower 				ENDDEBUG
49942944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
50042944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
50142944Ssklower 						dusize = TP_DFL_TPDUSIZE;
50236401Ssklower 				break;
50336401Ssklower 			case	TPP_addl_opt:
50436401Ssklower 				vb_getval(P, u_char, addlopt);
50536401Ssklower 				break;
50636401Ssklower 			case	TPP_calling_sufx:
50736401Ssklower 				/* could use vb_getval, but we want to save the loc & len
50836401Ssklower 				 * for later use
50936401Ssklower 				 */
51036401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
51136401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
51236401Ssklower 				IFDEBUG(D_TPINPUT)
51336401Ssklower 					printf("CR fsufx:");
51436401Ssklower 					{ register int j;
51536401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
51636401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
51736401Ssklower 						}
51836401Ssklower 						printf("\n");
51936401Ssklower 					}
52036401Ssklower 				ENDDEBUG
52136401Ssklower 				break;
52236401Ssklower 			case	TPP_called_sufx:
52336401Ssklower 				/* could use vb_getval, but we want to save the loc & len
52436401Ssklower 				 * for later use
52536401Ssklower 				 */
52636401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
52736401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
52836401Ssklower 				IFDEBUG(D_TPINPUT)
52936401Ssklower 					printf("CR lsufx:");
53036401Ssklower 					{ register int j;
53136401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
53237469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
53336401Ssklower 						}
53436401Ssklower 						printf("\n");
53536401Ssklower 					}
53636401Ssklower 				ENDDEBUG
53736401Ssklower 				break;
53836401Ssklower 
53936401Ssklower #ifdef TP_PERF_MEAS
54036401Ssklower 			case	TPP_perf_meas:
54136401Ssklower 				vb_getval(P, u_char, perf_meas);
54236401Ssklower 				break;
54336401Ssklower #endif TP_PERF_MEAS
54436401Ssklower 
54536401Ssklower 			case	TPP_vers:
54636401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
54742944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
54836401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
54942491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
55042944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
55142491Ssklower 			setversion:
55242491Ssklower 				version = vbval(P, u_char);
55336401Ssklower 				break;
55436401Ssklower 			case	TPP_acktime:
55536401Ssklower 				vb_getval(P, u_short, acktime);
55636401Ssklower 				acktime = ntohs(acktime);
55736401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
55836401Ssklower 				if((short)acktime <=0 )
55936401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
56036401Ssklower 				IFDEBUG(D_TPINPUT)
56136401Ssklower 					printf("CR acktime 0x%x\n", acktime);
56236401Ssklower 				ENDDEBUG
56336401Ssklower 				break;
56436401Ssklower 
56536401Ssklower 			case	TPP_alt_class:
56636401Ssklower 				{
56736401Ssklower 					u_char *aclass = 0;
56836401Ssklower 					register int i;
56942944Ssklower 					static u_char bad_alt_classes[5] =
57042944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
57136401Ssklower 
57242944Ssklower 					aclass =
57342944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
57436401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
57542944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
57636401Ssklower 					}
57742944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
57842944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
57942944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
58036401Ssklower 					IFDEBUG(D_TPINPUT)
58136401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
58236401Ssklower 					ENDDEBUG
58336401Ssklower 				}
58436401Ssklower 				break;
58536401Ssklower 
58636401Ssklower 			case	TPP_security:
58736401Ssklower 			case	TPP_residER:
58836401Ssklower 			case	TPP_priority:
58936401Ssklower 			case	TPP_transdelay:
59036401Ssklower 			case	TPP_throughput:
59136401Ssklower 			case	TPP_addl_info:
59236401Ssklower 			case	TPP_subseq:
59336401Ssklower 				IFDEBUG(D_TPINPUT)
59436401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
59536401Ssklower 						 vbptr(P)->tpv_code);
59636401Ssklower 				ENDDEBUG
59736401Ssklower 				IncStat(ts_param_ignored);
59836401Ssklower 				break;
59936401Ssklower 
60036401Ssklower 			case	TPP_checksum:
60136401Ssklower 				IFDEBUG(D_TPINPUT)
60236401Ssklower 					printf("CR before cksum\n");
60336401Ssklower 				ENDDEBUG
60436401Ssklower 
60536401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
60636401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
60736401Ssklower 
60836401Ssklower 				IFDEBUG(D_TPINPUT)
60936401Ssklower 					printf("CR before cksum\n");
61036401Ssklower 				ENDDEBUG
61136401Ssklower 				break;
61236401Ssklower 
61336401Ssklower 			default:
61436401Ssklower 				IncStat(ts_inv_pcode);
61536401Ssklower 				error = E_TP_INV_PCODE;
61636401Ssklower 				goto discard;
61736401Ssklower 
61836401Ssklower 			}
61936401Ssklower 
62036401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
62136401Ssklower 
62236401Ssklower 		if( lsufxlen == 0) {
62336401Ssklower 			/* can't look for a tpcb w/o any called sufx */
62436401Ssklower 			error =  E_TP_LENGTH_INVAL;
62536401Ssklower 			IncStat(ts_inv_sufx);
62636401Ssklower 			goto respond;
62736401Ssklower 		} else {
62836401Ssklower 			register	struct tp_ref 	*rp;
62936401Ssklower 			register	int			r;
63036401Ssklower 			extern		int			tp_maxrefopen;
63136401Ssklower 
63236401Ssklower 			rp = &tp_ref[1]; /* zero-th one is never open */
63336401Ssklower 			for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
63436401Ssklower 				if (rp->tpr_state!=REF_OPENING)
63536401Ssklower 					continue;
63636401Ssklower 				if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) {
63736401Ssklower 					tpcb =  rp->tpr_pcb;
63836401Ssklower 					if( laddr->sa_family !=
63936401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family ) {
64036401Ssklower 						IFDEBUG(D_CONN)
64136401Ssklower 						 	printf(
64236401Ssklower 					"MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n",
64336401Ssklower 							laddr->sa_family,
64436401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family );
64536401Ssklower 						ENDDEBUG
64636401Ssklower 						continue;
64736401Ssklower 					}
64836401Ssklower 					IFTRACE(D_TPINPUT)
64936401Ssklower 						tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate",
65036401Ssklower 							r, *lsufxloc, rp->tpr_state, 0);
65136401Ssklower 					ENDTRACE
65236401Ssklower 					/* found it */
65336401Ssklower 					break;
65436401Ssklower 				}
65536401Ssklower 			}
65636401Ssklower 
65736401Ssklower 			CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond,
65836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
65936401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
66036401Ssklower 				 * the fixed part (can't take the address of a bit field)
66136401Ssklower 				 */
66236401Ssklower 		}
66336401Ssklower 
66436401Ssklower 		/*
66536401Ssklower 		 * WE HAVE A TPCB
66636401Ssklower 		 * already know that the classes in the CR match at least
66736401Ssklower 		 * one class implemented, but we don't know yet if they
66836401Ssklower 		 * include any classes permitted by this server.
66936401Ssklower 		 */
67036401Ssklower 
67136401Ssklower 		IFDEBUG(D_TPINPUT)
67236401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
67336401Ssklower 		ENDDEBUG
67436401Ssklower 		IFDEBUG(D_CONN)
67536401Ssklower 			printf(
67636401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
67736401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
67836401Ssklower 		ENDDEBUG
67936401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
68036401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
68136401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
68236401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
68336401Ssklower 
68436401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
68536401Ssklower 
68636401Ssklower 		{
68736401Ssklower 			tpp = tpcb->_tp_param;
68836401Ssklower 			tpp.p_class = class_to_use;
68936401Ssklower 			tpp.p_tpdusize = dusize;
69036401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
69136401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
69236401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
69336401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
69442491Ssklower 			tpp.p_version = version;
69536401Ssklower #ifdef notdef
69636401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
69736401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
69836401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
69936401Ssklower #endif notdef
70036401Ssklower 
70136401Ssklower 		CHECK(
70236401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
70336401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
70436401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
70536401Ssklower 				/* ^ more or less the location of class */
70636401Ssklower 			)
70736401Ssklower 		}
70836401Ssklower 		IFTRACE(D_CONN)
70936401Ssklower 			tptrace(TPPTmisc,
71036401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
71136401Ssklower 				class_to_use,
71236401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
71336401Ssklower 				);
71436401Ssklower 		ENDTRACE
71536401Ssklower 		CHECK(
71636401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
71736401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
71836401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
71936401Ssklower 				/* ^ more or less the location of class */
72036401Ssklower 			)
72136401Ssklower 		IFDEBUG(D_CONN)
72236401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
72336401Ssklower 				tpcb, tpcb->tp_flags);
72436401Ssklower 		ENDDEBUG
72536401Ssklower 		takes_data = TRUE;
72636401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
72736401Ssklower 		e.ev_number = CR_TPDU;
72836401Ssklower 
72936401Ssklower 		so = tpcb->tp_sock;
73036401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
73136401Ssklower 			/*
73236401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
73336401Ssklower 			 * for this newborn connection, and fill in all the values.
73436401Ssklower 			 */
73536401Ssklower 			IFDEBUG(D_CONN)
73636401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
73736401Ssklower 					so, laddr, faddr, cons_channel);
73836401Ssklower 			ENDDEBUG
73936401Ssklower 			if( (so =
74036401Ssklower 				tp_newsocket(so, faddr, cons_channel,
74136401Ssklower 					class_to_use,
74237469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
74337469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
74436401Ssklower 					) == (struct socket *)0 ) {
74536401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
74636401Ssklower 				 * the tp entity is concerned, the only differences
74737469Ssklower 				 * are CO vs CL
74836401Ssklower 				 */
74936401Ssklower 				IFDEBUG(D_CONN)
75036401Ssklower 					printf("tp_newsocket returns 0\n");
75136401Ssklower 				ENDDEBUG
75236401Ssklower 				goto discard;
75336401Ssklower 			}
75436401Ssklower 			tpcb = sototpcb(so);
75536401Ssklower 
75636401Ssklower 			/*
75737469Ssklower 			 * Stash the addresses in the net level pcb
75836401Ssklower 			 * kind of like a pcbconnect() but don't need
75936401Ssklower 			 * or want all those checks.
76036401Ssklower 			 */
76136401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
76236401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
76336401Ssklower 
76437469Ssklower 			/* stash the f suffix in the new tpcb */
76537469Ssklower 			/* l suffix is already there */
76638841Ssklower 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
76736401Ssklower 
76837469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
76937469Ssklower 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
77038841Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
77138841Ssklower 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
77237469Ssklower 
77336401Ssklower #ifdef TP_PERF_MEAS
77436401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
77536401Ssklower 				/* ok, let's create an mbuf for stashing the
77636401Ssklower 				 * statistics if one doesn't already exist
77736401Ssklower 				 */
77836401Ssklower 				(void) tp_setup_perf(tpcb);
77936401Ssklower 			}
78036401Ssklower #endif TP_PERF_MEAS
78136401Ssklower 			tpcb->tp_fref = sref;
78236401Ssklower 
78336401Ssklower 			/* We've already checked for consistency with the options
78436401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
78536401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
78636401Ssklower 			 * Now we set the options in the new socket's tpcb.
78736401Ssklower 			 */
78836401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
78936401Ssklower 
79036401Ssklower 			if(!tpcb->tp_use_checksum)
79136401Ssklower 				IncStat(ts_csum_off);
79236401Ssklower 			if(tpcb->tp_xpd_service)
79336401Ssklower 				IncStat(ts_use_txpd);
79436401Ssklower 			if(tpcb->tp_xtd_format)
79536401Ssklower 				IncStat(ts_xtd_fmt);
79636401Ssklower 
79736401Ssklower 			/*
79836401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
79936401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
80036401Ssklower 			 */
80136401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
80236401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
80336401Ssklower 			tpcb->tp_peer_acktime = acktime;
80436401Ssklower 
80536401Ssklower 			/*
80636401Ssklower 			 * The following kludge is used to test retransmissions and
80736401Ssklower 			 * timeout during connection establishment.
80836401Ssklower 			 */
80936401Ssklower 			IFDEBUG(D_ZDREF)
81036401Ssklower 				IncStat(ts_zdebug);
81137469Ssklower 				/*tpcb->tp_fref = 0;*/
81236401Ssklower 			ENDDEBUG
81336401Ssklower 		}
81436401Ssklower 		IncStat(ts_CR_rcvd);
81539929Ssklower 		if (!tpcb->tp_cebit_off) {
81639929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
81739929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
81839929Ssklower 			LOCAL_CREDIT(tpcb);
81939929Ssklower 			CONG_INIT_SAMPLE(tpcb);
82039929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
82139929Ssklower 		}
82239929Ssklower 		tpcb->tp_ackrcvd = 0;
82336401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
82436401Ssklower 		/*
82536401Ssklower 		 * ER TPDUs have to be recognized separately
82636401Ssklower 		 * because they don't necessarily have a tpcb
82736401Ssklower 		 * with them and we don't want err out looking for such
82836401Ssklower 		 * a beast.
82936401Ssklower 		 * We could put a bunch of little kludges in the
83036401Ssklower 		 * next section of code so it would avoid references to tpcb
83136401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
83236401Ssklower 		 * mess up code for data transfer.
83336401Ssklower 		 */
83436401Ssklower 		IncStat(ts_ER_rcvd);
83536401Ssklower 		e.ev_number = ER_TPDU;
83636401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
83736401Ssklower 		takes_data = 1;
83836401Ssklower 	} else {
83936401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
84036401Ssklower 
84136401Ssklower 		/* In the next 4 checks,
84236401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
84336401Ssklower 		 * the fixed part (can't take the address of a bit field)
84436401Ssklower 		 */
84536401Ssklower 		if(cons_channel) {
84636401Ssklower #if NARGOXTWENTYFIVE > 0
84736401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
84836401Ssklower 
84936401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
85036401Ssklower 			/* Problem:  We may have a legit
85136401Ssklower 			 * error situation yet we may or may not have
85236401Ssklower 			 * a correspondence between the tpcb and the vc,
85336401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
85436401Ssklower 			 *          <---  DR
85536401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
85636401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
85736401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
85836401Ssklower 			 * Sigh.
85936401Ssklower 			 */
86036401Ssklower 
86136401Ssklower 			/* I don't know about this error value */
86236401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
86336401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
86436401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
86536401Ssklower #else
86636401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
86736401Ssklower #endif NARGOXTWENTYFIVE > 0
86836401Ssklower 
86936401Ssklower 		} else {
87036401Ssklower 
87136401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
87242944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
87336401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
87436401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
87542944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
87636401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
87736401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
87842944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
87936401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88036401Ssklower 		}
88136401Ssklower 
88236401Ssklower 		IFDEBUG(D_TPINPUT)
88336401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
88436401Ssklower 		ENDDEBUG
88536401Ssklower 
88636401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
88736401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
88836401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
88936401Ssklower 			ts_inv_dref, respond,
89036401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89136401Ssklower 
89236401Ssklower 		IFDEBUG(D_TPINPUT)
89336401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
89436401Ssklower 		ENDDEBUG
89536401Ssklower 		/*
89636401Ssklower 		 * At this point the state of the dref could be
89736401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
89836401Ssklower 		 *		   for example, DC may arrive after the close() has detached
89936401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
90036401Ssklower 		 * OPENING : a tpcb exists but no timers yet
90136401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
90236401Ssklower 		 */
90336401Ssklower 
90439929Ssklower         if (!tpcb->tp_cebit_off)
90539929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
90639929Ssklower 
90736401Ssklower 		dusize = tpcb->tp_tpdusize;
90836401Ssklower 
90936401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
91036401Ssklower 
91136401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
91236401Ssklower 
91337469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
91436401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
91536401Ssklower 
91636401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
91736401Ssklower 					/* not in class 0; 1 octet */
91836401Ssklower 					vb_getval(P, u_char, addlopt);
91936401Ssklower 					break;
92036401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
92142944Ssklower 				{
92242944Ssklower 					u_char odusize = dusize;
92336401Ssklower 					vb_getval(P, u_char, dusize);
92442944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
92542944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
92642944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
92742944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
92836401Ssklower 					IFDEBUG(D_TPINPUT)
92936401Ssklower 						printf("CC dusize 0x%x\n", dusize);
93036401Ssklower 					ENDDEBUG
93142944Ssklower 				}
93236401Ssklower 					break;
93336401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
93436401Ssklower 					IFDEBUG(D_TPINPUT)
93536401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
93636401Ssklower 					ENDDEBUG
93736401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
93836401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
93936401Ssklower 					break;
94036401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
94136401Ssklower 					/* class 4 only, 2 octets */
94236401Ssklower 					vb_getval(P, u_short, acktime);
94336401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
94436401Ssklower 					if( (short)acktime <=0 )
94536401Ssklower 						acktime = 2;
94636401Ssklower 					break;
94736401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
94836401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
94936401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
95036401Ssklower 					IFDEBUG(D_TPINPUT)
95136401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
95236401Ssklower 					ENDDEBUG
95336401Ssklower 					break;
95436401Ssklower 
95536401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
95636401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
95736401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
95836401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
95936401Ssklower 					if( tpcb->tp_use_checksum )  {
96036401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
96136401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
96236401Ssklower 					}
96336401Ssklower 					break;
96436401Ssklower 
96536401Ssklower 			/*  this is different from the above because in the context
96636401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
96736401Ssklower 			 */
96836401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
96936401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
97036401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
97136401Ssklower 					if( tpcb->tp_use_checksum )  {
97237469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
97336401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
97436401Ssklower 					}
97536401Ssklower 					break;
97636401Ssklower #ifdef notdef
97736401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
97836401Ssklower 				/* ignore - its length and meaning are
97936401Ssklower 				 * user defined and there's no way
98036401Ssklower 				 * to pass this info to the user anyway
98136401Ssklower 				 */
98236401Ssklower 				break;
98336401Ssklower #endif notdef
98436401Ssklower 
98536401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
98636401Ssklower 				/* used after reduction of window */
98736401Ssklower 				vb_getval(P, u_short, subseq);
98836401Ssklower 				subseq = ntohs(subseq);
98936401Ssklower 				IFDEBUG(D_ACKRECV)
99036401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
99136401Ssklower 				ENDDEBUG
99236401Ssklower 				break;
99336401Ssklower 
99436401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
99536401Ssklower 				{
99636401Ssklower 					u_int 	ylwe;
99736401Ssklower 					u_short ysubseq, ycredit;
99836401Ssklower 
99936401Ssklower 					fcc_present = TRUE;
100036401Ssklower 					vb_getval(P, u_int,	 	ylwe);
100136401Ssklower 					vb_getval(P, u_short, 	ysubseq);
100236401Ssklower 					vb_getval(P, u_short, 	ycredit);
100336401Ssklower 					ylwe = ntohl(ylwe);
100436401Ssklower 					ysubseq = ntohs(ysubseq);
100536401Ssklower 					ycredit = ntohs(ycredit);
100636401Ssklower 					IFDEBUG(D_ACKRECV)
100736401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
100836401Ssklower 							ylwe, ysubseq, ycredit);
100936401Ssklower 					ENDDEBUG
101036401Ssklower 				}
101136401Ssklower 				break;
101236401Ssklower 
101336401Ssklower 			default:
101436401Ssklower 				IFDEBUG(D_TPINPUT)
101536401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
101636401Ssklower 						dutype, vbptr(P)->tpv_code);
101736401Ssklower 				ENDDEBUG
101836401Ssklower 				IFTRACE(D_TPINPUT)
101936401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
102036401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
102136401Ssklower 				ENDTRACE
102236401Ssklower 				IncStat(ts_param_ignored);
102336401Ssklower 				break;
102436401Ssklower #undef caseof
102536401Ssklower 		}
102636401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
102736401Ssklower 
102836401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
102936401Ssklower 
103036401Ssklower 		switch( hdr->tpdu_type ) {
103136401Ssklower 		case CC_TPDU_type:
103236401Ssklower 			/* If CC comes back with an unacceptable class
103336401Ssklower 			 * respond with a DR or ER
103436401Ssklower 			 */
103536401Ssklower 
103636401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
103736401Ssklower 
103836401Ssklower 			{
103936401Ssklower 				tpp = tpcb->_tp_param;
104036401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
104136401Ssklower 				tpp.p_tpdusize = dusize;
104236401Ssklower 				tpp.p_dont_change_params = 0;
104336401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
104436401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
104536401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
104636401Ssklower #ifdef notdef
104736401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
104836401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
104936401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
105036401Ssklower #endif notdef
105136401Ssklower 
105236401Ssklower 			CHECK(
105336401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
105436401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
105536401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
105636401Ssklower 					/* ^ more or less the location of class */
105736401Ssklower 				)
105836401Ssklower 			IFTRACE(D_CONN)
105936401Ssklower 				tptrace(TPPTmisc,
106036401Ssklower 					"after 1 consist class, out, tpconsout",
106136401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
106236401Ssklower 					);
106336401Ssklower 			ENDTRACE
106436401Ssklower 			CHECK(
106536401Ssklower 				((class_to_use == TP_CLASS_0)&&
106636401Ssklower 					(dgout_routine != tpcons_output)),
106736401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
106836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
106936401Ssklower 					/* ^ more or less the location of class */
107036401Ssklower 				)
107136401Ssklower 			}
107236401Ssklower 			if( ! tpcb->tp_use_checksum)
107336401Ssklower 				IncStat(ts_csum_off);
107436401Ssklower 			if(tpcb->tp_xpd_service)
107536401Ssklower 				IncStat(ts_use_txpd);
107636401Ssklower 			if(tpcb->tp_xtd_format)
107736401Ssklower 				IncStat(ts_xtd_fmt);
107836401Ssklower 
107936401Ssklower 			IFTRACE(D_CONN)
108036401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
108136401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
108236401Ssklower 					hdr->tpdu_CCclass);
108336401Ssklower 			ENDTRACE
108436401Ssklower 
108536401Ssklower 			/*
108636401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
108736401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
108836401Ssklower 			 * It would be nice if the arguments to this
108936401Ssklower 			 * were more reasonable.
109036401Ssklower 			 */
109136401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
109236401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
109336401Ssklower 
109436401Ssklower #ifdef	CONS
109536401Ssklower 			/* Could be that this CC came in on a NEW vc, in which case
109636401Ssklower 			 * we have to confirm it.
109736401Ssklower 			 */
109836401Ssklower 			if( cons_channel )
109936401Ssklower 				cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
110036401Ssklower 						tpcb->tp_class == TP_CLASS_4);
110136401Ssklower #endif	CONS
110236401Ssklower 
110336401Ssklower 			tpcb->tp_peer_acktime = acktime;
110436401Ssklower 
110536401Ssklower 			/* if called or calling suffices appeared on the CC,
110636401Ssklower 			 * they'd better jive with what's in the pcb
110736401Ssklower 			 */
110836401Ssklower 			if( fsufxlen ) {
110936401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
111036401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
111136401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
111236401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
111336401Ssklower 			}
111436401Ssklower 			if( lsufxlen ) {
111536401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
111636401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
111736401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
111836401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
111936401Ssklower 			}
112036401Ssklower 
112136401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
112236401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
112336401Ssklower 			takes_data = TRUE;
112436401Ssklower 			e.ev_number = CC_TPDU;
112536401Ssklower 			IncStat(ts_CC_rcvd);
112636401Ssklower 			break;
112736401Ssklower 
112836401Ssklower 		case DC_TPDU_type:
112936401Ssklower 			if (sref != tpcb->tp_fref)
113036401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
113136401Ssklower 					sref, tpcb->tp_fref);
113236401Ssklower 
113336401Ssklower 			CHECK( (sref != tpcb->tp_fref),
113442944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
113536401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
113642944Ssklower 
113736401Ssklower 			e.ev_number = DC_TPDU;
113836401Ssklower 			IncStat(ts_DC_rcvd);
113936401Ssklower 			break;
114036401Ssklower 
114136401Ssklower 		case DR_TPDU_type:
114236401Ssklower 			IFTRACE(D_TPINPUT)
114336401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
114436401Ssklower 			ENDTRACE
114542944Ssklower 			if (sref != tpcb->tp_fref) {
114636401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
114736401Ssklower 					sref, tpcb->tp_fref);
114842944Ssklower 			}
114936401Ssklower 
115042944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
115142944Ssklower 					tpcb->tp_state != TP_CRSENT),
115242944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
115336401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
115436401Ssklower 
115536401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
115636401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
115736401Ssklower 			takes_data = TRUE;
115836401Ssklower 			e.ev_number = DR_TPDU;
115936401Ssklower 			IncStat(ts_DR_rcvd);
116036401Ssklower 			break;
116136401Ssklower 
116236401Ssklower 		case ER_TPDU_type:
116336401Ssklower 			IFTRACE(D_TPINPUT)
116436401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
116536401Ssklower 			ENDTRACE
116636401Ssklower 			e.ev_number = ER_TPDU;
116736401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
116836401Ssklower 			IncStat(ts_ER_rcvd);
116936401Ssklower 			break;
117036401Ssklower 
117136401Ssklower 		case AK_TPDU_type:
117236401Ssklower 
117336401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
117436401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
117536401Ssklower 
117636401Ssklower 			if (tpcb->tp_xtd_format) {
117736401Ssklower #ifdef BYTE_ORDER
117836401Ssklower 				union seq_type seqeotX;
117936401Ssklower 
118036401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
118136401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
118236401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
118336401Ssklower #else
118436401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
118536401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
118636401Ssklower #endif BYTE_ORDER
118736401Ssklower 			} else {
118836401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
118936401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
119036401Ssklower 			}
119136401Ssklower 			IFTRACE(D_TPINPUT)
119236401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
119336401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
119436401Ssklower 					subseq, fcc_present);
119536401Ssklower 			ENDTRACE
119636401Ssklower 
119736401Ssklower 			e.ev_number = AK_TPDU;
119836401Ssklower 			IncStat(ts_AK_rcvd);
119936401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
120036401Ssklower 			break;
120136401Ssklower 
120236401Ssklower 		case XAK_TPDU_type:
120336401Ssklower 			if (tpcb->tp_xtd_format) {
120436401Ssklower #ifdef BYTE_ORDER
120536401Ssklower 				union seq_type seqeotX;
120636401Ssklower 
120736401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
120836401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
120936401Ssklower #else
121036401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
121136401Ssklower #endif BYTE_ORDER
121236401Ssklower 			} else {
121336401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
121436401Ssklower 			}
121536401Ssklower 			e.ev_number = XAK_TPDU;
121636401Ssklower 			IncStat(ts_XAK_rcvd);
121736401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
121836401Ssklower 			break;
121936401Ssklower 
122036401Ssklower 		case XPD_TPDU_type:
122136401Ssklower 			if (tpcb->tp_xtd_format) {
122236401Ssklower #ifdef BYTE_ORDER
122336401Ssklower 				union seq_type seqeotX;
122436401Ssklower 
122536401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
122636401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
122736401Ssklower #else
122836401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
122936401Ssklower #endif BYTE_ORDER
123036401Ssklower 			} else {
123136401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
123236401Ssklower 			}
123336401Ssklower 			takes_data = TRUE;
123436401Ssklower 			e.ev_number = XPD_TPDU;
123536401Ssklower 			IncStat(ts_XPD_rcvd);
123636401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
123736401Ssklower 			break;
123836401Ssklower 
123936401Ssklower 		case DT_TPDU_type:
124036401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
124136401Ssklower 			   * A little crude but it works.
124236401Ssklower 			   */
124336401Ssklower 
124436401Ssklower 				IFDEBUG(D_DROP)
124536401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
124636401Ssklower 						IncStat(ts_ydebug);
124736401Ssklower 						goto discard;
124836401Ssklower 					}
124936401Ssklower 				ENDDEBUG
125036401Ssklower 			}
125136401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
125236401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
125336401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
125436401Ssklower 			} else if (tpcb->tp_xtd_format) {
125536401Ssklower #ifdef BYTE_ORDER
125636401Ssklower 				union seq_type seqeotX;
125736401Ssklower 
125836401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
125936401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
126036401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
126136401Ssklower #else
126236401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
126336401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
126436401Ssklower #endif BYTE_ORDER
126536401Ssklower 			} else {
126636401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
126736401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
126836401Ssklower 			}
126936401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
127036401Ssklower 				IncStat(ts_eot_input);
127136401Ssklower 			takes_data = TRUE;
127236401Ssklower 			e.ev_number = DT_TPDU;
127336401Ssklower 			IncStat(ts_DT_rcvd);
127436401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
127536401Ssklower 			break;
127636401Ssklower 
127736401Ssklower 		case GR_TPDU_type:
127836401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
127936401Ssklower 			/* drop through */
128036401Ssklower 		default:
128136401Ssklower 			/* this should NEVER happen because there is a
128236401Ssklower 			 * check for dutype well above here
128336401Ssklower 			 */
128436401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
128536401Ssklower 			IFDEBUG(D_TPINPUT)
128636401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
128736401Ssklower 			ENDDEBUG
128836401Ssklower 			IncStat(ts_inv_dutype);
128936401Ssklower 			goto respond;
129036401Ssklower 		}
129136401Ssklower 	}
129236401Ssklower 	/* peel off the tp header;
129336401Ssklower 	 * remember that the du_li doesn't count itself.
129436401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
129536401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
129636401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
129736401Ssklower 	 */
129836401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
129937469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
130036401Ssklower 
130137469Ssklower 	if (takes_data) {
130237469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
130337469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
130442468Ssklower 		struct cmsghdr c_hdr;
130537469Ssklower 		struct mbuf *n;
130636401Ssklower 
130737469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
130837469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
130936401Ssklower 		switch( hdr->tpdu_type ) {
131037469Ssklower 
131136401Ssklower 		case CR_TPDU_type:
131237469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
131337469Ssklower 			goto make_control_msg;
131437469Ssklower 
131536401Ssklower 		case CC_TPDU_type:
131637469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
131737469Ssklower 			goto make_control_msg;
131837469Ssklower 
131936401Ssklower 		case DR_TPDU_type:
132037469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
132137469Ssklower 		make_control_msg:
132237469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
132337469Ssklower 			mbtype = MT_CONTROL;
1324*43334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
1325*43334Ssklower 			if (n) {
1326*43334Ssklower 				datalen += sizeof(c_hdr);
1327*43334Ssklower 				n->m_len = sizeof(c_hdr);
1328*43334Ssklower 				c_hdr.cmsg_len = datalen;
1329*43334Ssklower 				*mtod(n, struct cmsghdr *) = c_hdr;
1330*43334Ssklower 				n->m_next = m;
1331*43334Ssklower 				m = n;
1332*43334Ssklower 			} else {m_freem(m); m = 0; goto invoke;}
133337469Ssklower 			/* FALLTHROUGH */
133437469Ssklower 
133536401Ssklower 		case XPD_TPDU_type:
133637469Ssklower 			if (mbtype != MT_CONTROL)
133737469Ssklower 				mbtype = MT_OOBDATA;
133837469Ssklower 			m->m_flags |= M_EOR;
133937469Ssklower 			/* FALLTHROUGH */
134037469Ssklower 
134136401Ssklower 		case DT_TPDU_type:
134237469Ssklower 			for (n = m; n; n = n->m_next) {
134337469Ssklower 				MCHTYPE(n, mbtype);
134437469Ssklower 			}
1345*43334Ssklower 		invoke:
134637469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
134736401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
134836401Ssklower 			break;
134936401Ssklower 
135036401Ssklower 		default:
135136401Ssklower 			printf(
135236401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
135336401Ssklower 				hdr->tpdu_type, takes_data, m);
135436401Ssklower 			break;
135536401Ssklower 		}
135636401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
135736401Ssklower 		m = MNULL;
135836401Ssklower 	}
135936401Ssklower 
136036401Ssklower 	IncStat(ts_tpdu_rcvd);
136136401Ssklower 
136236401Ssklower 	IFDEBUG(D_TPINPUT)
136336401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
136436401Ssklower 			tpcb->tp_state, e.ev_number, m );
136536401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
136636401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
136736401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
136836401Ssklower 	ENDDEBUG
136936401Ssklower 
137036401Ssklower 	error = tp_driver(tpcb, &e);
137136401Ssklower 
137236401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
137336401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
137436401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
137536401Ssklower 		tpcb->tp_sock->so_error = error;
137636401Ssklower 
137736401Ssklower 	/* Kludge to keep the state tables under control (adding
137836401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
137936401Ssklower 	 * the data would have exploded the tables and made a big mess ).
138036401Ssklower 	 */
138136401Ssklower 	switch(e.ev_number) {
138236401Ssklower 		case CC_TPDU:
138336401Ssklower 		case DR_TPDU:
138436401Ssklower 		case CR_TPDU:
138536401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
138636401Ssklower 			IFDEBUG(D_TPINPUT)
138736401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
138836401Ssklower 				m, takes_data);
138936401Ssklower 			ENDDEBUG
139036401Ssklower 			break;
139136401Ssklower 		default:
139236401Ssklower 			break;
139336401Ssklower 	}
139436401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
139536401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
139636401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
139736401Ssklower 	 */
139836401Ssklower 
139936401Ssklower separate:
140036401Ssklower 	if ( takes_data == 0 )  {
140136401Ssklower 		ASSERT( m != MNULL );
140236401Ssklower 		/*
140336401Ssklower 		 * we already peeled off the prev. tp header so
140436401Ssklower 		 * we can just pull up some more and repeat
140536401Ssklower 		 */
140636401Ssklower 
140737469Ssklower 		if( m = tp_inputprep(m) ) {
140836401Ssklower 		IFDEBUG(D_TPINPUT)
140936401Ssklower 			hdr = mtod(m, struct tpdu *);
141036401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
141136401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
141236401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
141336401Ssklower 		ENDDEBUG
141436401Ssklower 
141536401Ssklower 			IncStat(ts_concat_rcvd);
141636401Ssklower 			goto again;
141736401Ssklower 		}
141836401Ssklower 	}
141936401Ssklower 	if ( m != MNULL ) {
142036401Ssklower 		IFDEBUG(D_TPINPUT)
142136401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
142236401Ssklower 		ENDDEBUG
142336401Ssklower 		m_freem(m);
142436401Ssklower 		IFDEBUG(D_TPINPUT)
142536401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
142636401Ssklower 		ENDDEBUG
142736401Ssklower 	}
142836401Ssklower 	return (ProtoHook) tpcb;
142936401Ssklower 
143036401Ssklower discard:
143136401Ssklower 	/* class 4: drop the tpdu */
143236401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
143336401Ssklower 	 * to which connection it applies
143436401Ssklower 	 */
143536401Ssklower 	IFDEBUG(D_TPINPUT)
143636401Ssklower 		printf("tp_input DISCARD\n");
143736401Ssklower 	ENDDEBUG
143836401Ssklower 	IFTRACE(D_TPINPUT)
143936401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
144036401Ssklower 	ENDTRACE
144136401Ssklower 	m_freem(m);
144236401Ssklower 	IncStat(ts_recv_drop);
144336401Ssklower 	return (ProtoHook)0;
144436401Ssklower 
144542944Ssklower nonx_dref:
144642944Ssklower 	switch (dutype) {
144742944Ssklower 	default:
144842944Ssklower 		goto discard;
144942944Ssklower 	case CC_TPDU_type:
145042944Ssklower 		/* error = E_TP_MISM_REFS; */
145142944Ssklower 		break;
145242944Ssklower 	case DR_TPDU_type:
145342944Ssklower 		error |= TP_ERROR_SNDC;
145442944Ssklower 	}
145536401Ssklower respond:
1456*43334Ssklower 	IFDEBUG(D_TPINPUT)
145742944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
145836401Ssklower 	ENDDEBUG
145936401Ssklower 	IFTRACE(D_TPINPUT)
146042944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
146136401Ssklower 	ENDTRACE
146242944Ssklower 	if (sref == 0)
146336401Ssklower 		goto discard;
146437469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
146542944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
146637469Ssklower 				(int)cons_channel, dgout_routine);
146736401Ssklower 	IFDEBUG(D_ERROR_EMIT)
146836401Ssklower 		printf("tp_input after error_emit\n");
146936401Ssklower 	ENDDEBUG
147036401Ssklower 
147136401Ssklower #ifdef lint
147236401Ssklower 	printf("",sref,opt);
147336401Ssklower #endif lint
147436401Ssklower 	IncStat(ts_recv_drop);
147536401Ssklower 	return (ProtoHook)0;
147636401Ssklower }
147736401Ssklower 
147836401Ssklower 
147936401Ssklower /*
148036401Ssklower  * NAME: tp_headersize()
148136401Ssklower  *
148236401Ssklower  * CALLED FROM:
148336401Ssklower  *  tp_emit() and tp_sbsend()
148436401Ssklower  *  TP needs to know the header size so it can figure out how
148536401Ssklower  *  much data to put in each tpdu.
148636401Ssklower  *
148736401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
148836401Ssklower  *  For a given connection, represented by (tpcb), and
148936401Ssklower  *  tpdu type (dutype), return the size of a tp header.
149036401Ssklower  *
149136401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
149236401Ssklower  *
149336401Ssklower  * SIDE EFFECTS:
149436401Ssklower  *
149536401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
149636401Ssklower  */
149736401Ssklower int
149836401Ssklower tp_headersize(dutype, tpcb)
149936401Ssklower 	int 			dutype;
150036401Ssklower 	struct tp_pcb 	*tpcb;
150136401Ssklower {
150236401Ssklower 	register int size = 0;
150336401Ssklower 
150436401Ssklower 	IFTRACE(D_CONN)
150536401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
150636401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
150736401Ssklower 	ENDTRACE
150836401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
150936401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
151036401Ssklower 			(dutype == DR_TPDU_type) ||
151136401Ssklower 			(dutype == CR_TPDU_type) )) {
151236401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
151336401Ssklower 			dutype, tpcb->tp_class);
151436401Ssklower 	/* TODO: identify this and GET RID OF IT */
151536401Ssklower 	}
151636401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
151736401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
151836401Ssklower 			(dutype == DR_TPDU_type) ||
151936401Ssklower 			(dutype == CR_TPDU_type) );
152036401Ssklower 
152136401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
152236401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
152336401Ssklower 	} else  {
152436401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
152536401Ssklower 	}
152636401Ssklower 	return size;
152736401Ssklower 	/* caller must get network level header size separately */
152836401Ssklower }
1529