xref: /csrg-svn/sys/netiso/tp_input.c (revision 44947)
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*44947Ssklower  *	@(#)tp_input.c	7.14 (Berkeley) 07/24/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"
6144422Ssklower #include "systm.h"
6236401Ssklower #include "mbuf.h"
6336401Ssklower #include "socket.h"
6436401Ssklower #include "socketvar.h"
6536401Ssklower #include "domain.h"
6636401Ssklower #include "protosw.h"
6736401Ssklower #include "errno.h"
6836401Ssklower #include "time.h"
6936401Ssklower #include "kernel.h"
7036401Ssklower #include "types.h"
7137469Ssklower #include "iso_errno.h"
7237469Ssklower #include "tp_param.h"
7337469Ssklower #include "tp_timer.h"
7437469Ssklower #include "tp_stat.h"
7537469Ssklower #include "tp_pcb.h"
7637469Ssklower #include "argo_debug.h"
7737469Ssklower #include "tp_trace.h"
7837469Ssklower #include "tp_tpdu.h"
7937469Ssklower #include "iso.h"
8037469Ssklower #include "cons.h"
8136401Ssklower 
8236401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
8336401Ssklower 
8437469Ssklower /*
8537469Ssklower 	#ifdef lint
8637469Ssklower 	#undef ATTR
8737469Ssklower 	#define ATTR(X)ev_number
8837469Ssklower 	#endif lint
8937469Ssklower */
9036401Ssklower 
9136401Ssklower struct mbuf *
9236401Ssklower tp_inputprep(m)
9337469Ssklower 	register struct mbuf *m;
9436401Ssklower {
9537469Ssklower 	int hdrlen;
9636401Ssklower 
9736401Ssklower 	IFDEBUG(D_TPINPUT)
9837469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
9936401Ssklower 	ENDDEBUG
10036401Ssklower 
10136401Ssklower 	while(  m->m_len < 1 ) {
10236401Ssklower 		if( (m = m_free(m)) == MNULL ) {
10336401Ssklower 			return (struct mbuf *)0;
10436401Ssklower 		}
10536401Ssklower 	}
10637469Ssklower 	if(((int)m->m_data) & 0x3) {
10737469Ssklower 		/* If we are not 4-byte aligned, we have to be
10837469Ssklower 		 * above the beginning of the mbuf, and it is ok just
10937469Ssklower 		 * to slide it back.
11037469Ssklower 		 */
11137469Ssklower 		caddr_t ocp = m->m_data;
11236401Ssklower 
11337469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
11437469Ssklower 		ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
11536401Ssklower 	}
11636401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
11736401Ssklower 
11837469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
11937469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
12036401Ssklower 
12137469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
12236401Ssklower 
12336401Ssklower 	/*
12436401Ssklower 	 * now pull up the whole tp header
12536401Ssklower 	 */
12637469Ssklower 	if ( m->m_len < hdrlen) {
12737469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
12836401Ssklower 			IncStat(ts_recv_drop);
12936401Ssklower 			return (struct mbuf *)0;
13036401Ssklower 		}
13136401Ssklower 	}
13236401Ssklower 	IFDEBUG(D_INPUT)
13336401Ssklower 	printf(
13436401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
13537469Ssklower 		hdrlen, m->m_len);
13636401Ssklower 	ENDDEBUG
13736401Ssklower 	return m;
13836401Ssklower }
13936401Ssklower 
14036401Ssklower /* begin groan
14136401Ssklower  * -- this array and the following macros allow you to step through the
14236401Ssklower  * parameters of the variable part of a header
14336401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
14436401Ssklower  * should change, this array has to be rearranged
14536401Ssklower  */
14636401Ssklower 
14736401Ssklower #define TP_LEN_CLASS_0_INDEX	2
14836401Ssklower #define TP_MAX_DATA_INDEX 3
14936401Ssklower 
15036401Ssklower static u_char tpdu_info[][4] =
15136401Ssklower {
15236401Ssklower /*								length						 max data len */
15336401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
15436401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
15536401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
15636401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
15736401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
15836401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
15936401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
16036401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
16136401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
16236401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
16336401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
16436401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
16536401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
16636401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
16736401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
16836401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
16936401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
17036401Ssklower };
17136401Ssklower 
17242944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
17343334Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
17442944Ssklower 	goto Whattodo; }
17542944Ssklower 
17643334Ssklower tpibrk() {}
17743334Ssklower 
17836401Ssklower /*
17936401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
18036401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
18136401Ssklower  */
18236401Ssklower 
18342944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
18442944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
18542944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
18642944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
18742944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
18842944Ssklower 				respond, P - (caddr_t)hdr);\
18942944Ssklower 		if (P == PLIM) break;
19036401Ssklower 
19142944Ssklower #define END_WHILE_OPTIONS(P) } }
19236401Ssklower 
19336401Ssklower /* end groan */
19436401Ssklower 
19536401Ssklower /*
19636401Ssklower  * NAME:  tp_newsocket()
19736401Ssklower  *
19836401Ssklower  * CALLED FROM:
19936401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
20036401Ssklower  * is awaiting a  connection request
20136401Ssklower  *
20236401Ssklower  * FUNCTION and ARGUMENTS:
20336401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
20436401Ssklower  *  using a copy of the net level pcb for the parent socket.
20536401Ssklower  *  (so) is the parent socket.
20636401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
20736401Ssklower  *
20836401Ssklower  * RETURN VALUE:
20936401Ssklower  *  a new socket structure, being this end of the newly formed connection.
21036401Ssklower  *
21136401Ssklower  * SIDE EFFECTS:
21236401Ssklower  *  Sets a few things in the tpcb and net level pcb
21336401Ssklower  *
21436401Ssklower  * NOTES:
21536401Ssklower  */
21636401Ssklower static struct socket *
21736401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
21836401Ssklower 	struct socket				*so;
21936401Ssklower 	struct sockaddr				*fname;
22036401Ssklower 	u_int						cons_channel;
22136401Ssklower 	u_char						class_to_use;
22236401Ssklower 	u_int						netservice;
22336401Ssklower {
22436401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
22536401Ssklower 	struct tp_pcb *			 newtpcb;
22636401Ssklower 
22736401Ssklower 	/*
22836401Ssklower 	 * sonewconn() gets a new socket structure,
22936401Ssklower 	 * a new lower layer pcb and a new tpcb,
23036401Ssklower 	 * but the pcbs are unnamed (not bound)
23136401Ssklower 	 */
23236401Ssklower 	IFTRACE(D_NEWSOCK)
23338841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
23439196Ssklower 			so, tpcb, so->so_head, 0);
23536401Ssklower 	ENDTRACE
23636401Ssklower 
23740636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
23836401Ssklower 		return so;
23936401Ssklower 	IFTRACE(D_NEWSOCK)
24038841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
24138841Ssklower 			so, so->so_head, 0, 0);
24236401Ssklower 	ENDTRACE
24336401Ssklower 
24436401Ssklower 	IFDEBUG(D_NEWSOCK)
24537469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
24637469Ssklower 				cons_channel, so);
24737469Ssklower 		dump_addr(fname);
24836401Ssklower 		{
24936401Ssklower 			struct socket *t, *head ;
25036401Ssklower 
25136401Ssklower 			head = so->so_head;
25236401Ssklower 			t = so;
25336401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
25436401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
25536401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
25636401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
25736401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
25836401Ssklower 		}
25936401Ssklower 	ENDDEBUG
26036401Ssklower 
26136401Ssklower 	/*
26236401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
26336401Ssklower 	 */
26436401Ssklower 	newtpcb = sototpcb(so);
26536401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
26636401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
26736401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
26836401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
26936401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
27036401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
27137469Ssklower 	soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
27236401Ssklower 
27337469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
27436401Ssklower 		/*
27537469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
27636401Ssklower 		 */
27736401Ssklower 		struct mbuf *conndata;
27836401Ssklower 
27937469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
28036401Ssklower 		IFDEBUG(D_CONN)
28136401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
28236401Ssklower 		ENDDEBUG
28337469Ssklower 		newtpcb->tp_ucddata = conndata;
28436401Ssklower 	}
28536401Ssklower 
28636401Ssklower 	tpcb = newtpcb;
28736401Ssklower 	tpcb->tp_state = TP_LISTENING;
28836401Ssklower 	tpcb->tp_class = class_to_use;
28936401Ssklower 	tpcb->tp_netservice = netservice;
29036401Ssklower 
29136401Ssklower 
29236401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
29336401Ssklower 	if ( fname ) {
29436401Ssklower 		/*
29536401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
29636401Ssklower 		 */
29736401Ssklower 		struct mbuf	*m;
29836401Ssklower 		int			err;
29936401Ssklower 
30036401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
30136401Ssklower 		if (m) {
30236401Ssklower 			/*
30336401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
30436401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
30536401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
30636401Ssklower 			 * sigh.
30736401Ssklower 			 */
30837469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
30937469Ssklower 			m->m_len = fname->sa_len;
31036401Ssklower 
31136401Ssklower 			/* grot  : have to say the kernel can override params in
31236401Ssklower 			 * the passive open case
31336401Ssklower 			 */
31436401Ssklower 			tpcb->tp_dont_change_params = 0;
31536401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
31636401Ssklower 			m_free(m);
31736401Ssklower 
31836401Ssklower 			if (!err)
31936401Ssklower 				goto ok;
32036401Ssklower 		}
32136401Ssklower 		IFDEBUG(D_CONN)
32236401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
32336401Ssklower 				tpcb, so);
32436401Ssklower 		ENDDEBUG
32536401Ssklower 		(void) tp_detach(tpcb);
32636401Ssklower 		return 0;
32736401Ssklower 	}
32836401Ssklower ok:
32936401Ssklower 	IFDEBUG(D_TPINPUT)
33036401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
33136401Ssklower 			so, sototpcb(so));
33236401Ssklower 	ENDDEBUG
33336401Ssklower 	return so;
33436401Ssklower }
33536401Ssklower 
33636401Ssklower #ifndef CONS
33736401Ssklower tpcons_output()
33836401Ssklower {
33936401Ssklower 	return(0);
34036401Ssklower }
34136401Ssklower #endif !CONS
34236401Ssklower 
34336401Ssklower /*
34436401Ssklower  * NAME: 	tp_input()
34536401Ssklower  *
34636401Ssklower  * CALLED FROM:
34736401Ssklower  *  net layer input routine
34836401Ssklower  *
34936401Ssklower  * FUNCTION and ARGUMENTS:
35036401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
35136401Ssklower  *  is one. Create the appropriate type of event and call the driver.
35236401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
35336401Ssklower  *
35436401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
35536401Ssklower  * 	has been m_pullup-ed.
35636401Ssklower  *
35736401Ssklower  * RETURN VALUE: Nada
35836401Ssklower  *
35936401Ssklower  * SIDE EFFECTS:
36036401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
36136401Ssklower  *
36236401Ssklower  * NOTE:
36336401Ssklower  *  The initial value of acktime is 2 so that we will never
36436401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
36536401Ssklower  *  computation of the retransmission timer value, and so it
36636401Ssklower  *  mustn't be zero.
36736401Ssklower  *  2 seems like a reasonable minimum.
36836401Ssklower  */
36936401Ssklower ProtoHook
37039929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
37136401Ssklower 	register	struct mbuf 	*m;
37236401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
37336401Ssklower 	u_int 						cons_channel;
37436401Ssklower 	int 						(*dgout_routine)();
37539929Ssklower 	int							ce_bit;
37636401Ssklower 
37736401Ssklower {
37836401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
379*44947Ssklower 	register struct tpdu 	*hdr;
38036401Ssklower 	struct socket 			*so;
38136401Ssklower 	struct tp_event 		e;
38242944Ssklower 	int 					error = 0;
38336401Ssklower 	unsigned 				dutype;
38442944Ssklower 	u_short 				dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
38542944Ssklower 	u_char 					preferred_class = 0, class_to_use = 0;
38642944Ssklower 	u_char					opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
38736401Ssklower #ifdef TP_PERF_MEAS
38838841Ssklower 	u_char					perf_meas;
38936401Ssklower #endif TP_PERF_MEAS
39044422Ssklower 	u_char					fsufxlen = 0, lsufxlen = 0, intercepted = 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:
400*44947Ssklower 	hdr = mtod(m, struct tpdu *);
40136401Ssklower #ifdef TP_PERF_MEAS
40238841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
40336401Ssklower #endif TP_PERF_MEAS
40436401Ssklower 
40536401Ssklower 	IFDEBUG(D_TPINPUT)
40636401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
40736401Ssklower 	ENDDEBUG
40836401Ssklower 
40936401Ssklower 
41036401Ssklower 	/*
41136401Ssklower 	 * get the actual tpdu length - necessary for monitoring
41236401Ssklower 	 * and for checksumming
41336401Ssklower 	 *
41436401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
41536401Ssklower 	 */
41636401Ssklower 
41736401Ssklower 	{ 	register struct mbuf *n=m;
41836401Ssklower #	ifdef ARGO_DEBUG
41936401Ssklower 		int chain_length = 0;
42036401Ssklower #	endif ARGO_DEBUG
42136401Ssklower 
42236401Ssklower 		for(;;) {
42336401Ssklower 			tpdu_len += n->m_len;
42436401Ssklower 			IFDEBUG(D_MBUF_MEAS)
42537469Ssklower 				if( n->m_flags & M_EXT) {
42636401Ssklower 					IncStat(ts_mb_cluster);
42736401Ssklower 				} else {
42836401Ssklower 					IncStat(ts_mb_small);
42936401Ssklower 				}
43036401Ssklower 				chain_length ++;
43136401Ssklower 			ENDDEBUG
43236401Ssklower 			if (n->m_next == MNULL ) {
43336401Ssklower 				break;
43436401Ssklower 			}
43536401Ssklower 			n = n->m_next;
43636401Ssklower 		}
43736401Ssklower 		IFDEBUG(D_MBUF_MEAS)
43836401Ssklower 			if(chain_length > 16)
43936401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
44036401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
44136401Ssklower 		ENDDEBUG
44236401Ssklower 	}
44336401Ssklower 	IFTRACE(D_TPINPUT)
44436401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
44536401Ssklower 			0);
44636401Ssklower 	ENDTRACE
44736401Ssklower 
44836401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
44936401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
45036401Ssklower 	dutype = (int)hdr->tpdu_type;
45136401Ssklower 
45236401Ssklower 	IFDEBUG(D_TPINPUT)
45336401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
45436401Ssklower 			cons_channel, dref);
45536401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
45636401Ssklower 	ENDDEBUG
45736401Ssklower 	IFTRACE(D_TPINPUT)
45836401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
45936401Ssklower 			cons_channel, dutype, dref, 0);
46036401Ssklower 	ENDTRACE
46136401Ssklower 
46236401Ssklower 
46336401Ssklower #ifdef ARGO_DEBUG
46436401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
46536401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
46636401Ssklower 			dutype, cons_channel, dref);
46736401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
46836401Ssklower 
46936401Ssklower 		IncStat(ts_inv_dutype);
47036401Ssklower 		goto discard;
47136401Ssklower 	}
47236401Ssklower #endif ARGO_DEBUG
47336401Ssklower 
47436401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
47536401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
47636401Ssklower 		2 );
47736401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
47836401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
47936401Ssklower 		 */
48036401Ssklower 
48136401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
48236401Ssklower 	 * at the beginning of connection establishment, and by
48336401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
48436401Ssklower 	 */
48536401Ssklower 	if ( dutype == CR_TPDU_type ) {
48636401Ssklower 		u_char alt_classes = 0;
48736401Ssklower 
48837469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
48936401Ssklower 		opt = hdr->tpdu_CRoptions;
49036401Ssklower 
49136401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
49236401Ssklower 
49336401Ssklower 			switch( vbptr(P)->tpv_code ) {
49436401Ssklower 
49536401Ssklower 			case	TPP_tpdu_size:
49636401Ssklower 				vb_getval(P, u_char, dusize);
49736401Ssklower 				IFDEBUG(D_TPINPUT)
49836401Ssklower 					printf("CR dusize 0x%x\n", dusize);
49936401Ssklower 				ENDDEBUG
50042944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
50142944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
50242944Ssklower 						dusize = TP_DFL_TPDUSIZE;
50336401Ssklower 				break;
50436401Ssklower 			case	TPP_addl_opt:
50536401Ssklower 				vb_getval(P, u_char, addlopt);
50636401Ssklower 				break;
50736401Ssklower 			case	TPP_calling_sufx:
50836401Ssklower 				/* could use vb_getval, but we want to save the loc & len
50936401Ssklower 				 * for later use
51036401Ssklower 				 */
51136401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
51236401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
51336401Ssklower 				IFDEBUG(D_TPINPUT)
51436401Ssklower 					printf("CR fsufx:");
51536401Ssklower 					{ register int j;
51636401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
51736401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
51836401Ssklower 						}
51936401Ssklower 						printf("\n");
52036401Ssklower 					}
52136401Ssklower 				ENDDEBUG
52236401Ssklower 				break;
52336401Ssklower 			case	TPP_called_sufx:
52436401Ssklower 				/* could use vb_getval, but we want to save the loc & len
52536401Ssklower 				 * for later use
52636401Ssklower 				 */
52736401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
52836401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
52936401Ssklower 				IFDEBUG(D_TPINPUT)
53036401Ssklower 					printf("CR lsufx:");
53136401Ssklower 					{ register int j;
53236401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
53337469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
53436401Ssklower 						}
53536401Ssklower 						printf("\n");
53636401Ssklower 					}
53736401Ssklower 				ENDDEBUG
53836401Ssklower 				break;
53936401Ssklower 
54036401Ssklower #ifdef TP_PERF_MEAS
54136401Ssklower 			case	TPP_perf_meas:
54236401Ssklower 				vb_getval(P, u_char, perf_meas);
54336401Ssklower 				break;
54436401Ssklower #endif TP_PERF_MEAS
54536401Ssklower 
54636401Ssklower 			case	TPP_vers:
54736401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
54842944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
54936401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
55042491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
55142944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
55242491Ssklower 			setversion:
55342491Ssklower 				version = vbval(P, u_char);
55436401Ssklower 				break;
55536401Ssklower 			case	TPP_acktime:
55636401Ssklower 				vb_getval(P, u_short, acktime);
55736401Ssklower 				acktime = ntohs(acktime);
55836401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
55936401Ssklower 				if((short)acktime <=0 )
56036401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
56136401Ssklower 				IFDEBUG(D_TPINPUT)
56236401Ssklower 					printf("CR acktime 0x%x\n", acktime);
56336401Ssklower 				ENDDEBUG
56436401Ssklower 				break;
56536401Ssklower 
56636401Ssklower 			case	TPP_alt_class:
56736401Ssklower 				{
56836401Ssklower 					u_char *aclass = 0;
56936401Ssklower 					register int i;
57042944Ssklower 					static u_char bad_alt_classes[5] =
57142944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
57236401Ssklower 
57342944Ssklower 					aclass =
57442944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
57536401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
57642944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
57736401Ssklower 					}
57842944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
57942944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
58042944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
58136401Ssklower 					IFDEBUG(D_TPINPUT)
58236401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
58336401Ssklower 					ENDDEBUG
58436401Ssklower 				}
58536401Ssklower 				break;
58636401Ssklower 
58736401Ssklower 			case	TPP_security:
58836401Ssklower 			case	TPP_residER:
58936401Ssklower 			case	TPP_priority:
59036401Ssklower 			case	TPP_transdelay:
59136401Ssklower 			case	TPP_throughput:
59236401Ssklower 			case	TPP_addl_info:
59336401Ssklower 			case	TPP_subseq:
594*44947Ssklower 			default:
59536401Ssklower 				IFDEBUG(D_TPINPUT)
59636401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
59736401Ssklower 						 vbptr(P)->tpv_code);
59836401Ssklower 				ENDDEBUG
59936401Ssklower 				IncStat(ts_param_ignored);
60036401Ssklower 				break;
60136401Ssklower 
60236401Ssklower 			case	TPP_checksum:
60336401Ssklower 				IFDEBUG(D_TPINPUT)
60436401Ssklower 					printf("CR before cksum\n");
60536401Ssklower 				ENDDEBUG
60636401Ssklower 
60736401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
60836401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
60936401Ssklower 
61036401Ssklower 				IFDEBUG(D_TPINPUT)
61136401Ssklower 					printf("CR before cksum\n");
61236401Ssklower 				ENDDEBUG
61336401Ssklower 				break;
61436401Ssklower 			}
61536401Ssklower 
61636401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
61736401Ssklower 
61844422Ssklower 		if (lsufxlen == 0) {
61936401Ssklower 			/* can't look for a tpcb w/o any called sufx */
62036401Ssklower 			error =  E_TP_LENGTH_INVAL;
62136401Ssklower 			IncStat(ts_inv_sufx);
62236401Ssklower 			goto respond;
62336401Ssklower 		} else {
62444422Ssklower 			register struct tp_pcb *t;
62536401Ssklower 
62644601Ssklower 			for (t = tp_intercepts; t ; t = t->tp_nextlisten) {
62744422Ssklower 				if (laddr->sa_family != t->tp_nlproto->nlp_afamily)
62836401Ssklower 					continue;
62944601Ssklower 				if ((*t->tp_nlproto->nlp_cmpnetaddr)(
63044422Ssklower 						t->tp_npcb, laddr, TP_LOCAL)) {
63144422Ssklower 							intercepted = 1;
63244422Ssklower 							goto check_duplicate_cr;
63336401Ssklower 				}
63436401Ssklower 			}
63544601Ssklower 			for (t = tp_listeners; t ; t = t->tp_nextlisten)
63644601Ssklower 				if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 &&
63744601Ssklower 					laddr->sa_family == t->tp_nlproto->nlp_afamily)
63844601Ssklower 						break;
63944422Ssklower 			CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
64036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
64136401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
64236401Ssklower 				 * the fixed part (can't take the address of a bit field)
64336401Ssklower 				 */
64444601Ssklower 			IFDEBUG(D_TPINPUT)
64544601Ssklower 				printf("checking if dup CR\n");
64644601Ssklower 			ENDDEBUG
64744422Ssklower 		check_duplicate_cr:
64844422Ssklower 			tpcb = t;
64944422Ssklower 			for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
65044422Ssklower 				if (sref != t->tp_fref)
65144422Ssklower 					continue;
65244422Ssklower 				if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
65344422Ssklower 						t->tp_npcb, faddr, TP_FOREIGN)) {
65444422Ssklower 					IFDEBUG(D_TPINPUT)
65544422Ssklower 						printf("duplicate CR discarded\n");
65644422Ssklower 					ENDDEBUG
65744422Ssklower 					goto discard;
65844422Ssklower 				}
65944422Ssklower 			}
66044422Ssklower 			IFTRACE(D_TPINPUT)
66144422Ssklower 				tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
66244422Ssklower 					tpcb, *lsufxloc, tpcb->tp_state, 0);
66344422Ssklower 			ENDTRACE
66436401Ssklower 		}
66536401Ssklower 
66636401Ssklower 		/*
66736401Ssklower 		 * WE HAVE A TPCB
66836401Ssklower 		 * already know that the classes in the CR match at least
66936401Ssklower 		 * one class implemented, but we don't know yet if they
67036401Ssklower 		 * include any classes permitted by this server.
67136401Ssklower 		 */
67236401Ssklower 
67336401Ssklower 		IFDEBUG(D_TPINPUT)
67436401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
67536401Ssklower 		ENDDEBUG
67636401Ssklower 		IFDEBUG(D_CONN)
67736401Ssklower 			printf(
67836401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
67936401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
68036401Ssklower 		ENDDEBUG
68136401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
68236401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
68336401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
68436401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
68536401Ssklower 
68636401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
68736401Ssklower 
68836401Ssklower 		{
68936401Ssklower 			tpp = tpcb->_tp_param;
69036401Ssklower 			tpp.p_class = class_to_use;
69136401Ssklower 			tpp.p_tpdusize = dusize;
69236401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
69336401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
69436401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
69536401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
69642491Ssklower 			tpp.p_version = version;
69736401Ssklower #ifdef notdef
69836401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
69936401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
70036401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
70136401Ssklower #endif notdef
70236401Ssklower 
70336401Ssklower 		CHECK(
70436401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
70536401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
70636401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
70736401Ssklower 				/* ^ more or less the location of class */
70836401Ssklower 			)
70936401Ssklower 		}
71036401Ssklower 		IFTRACE(D_CONN)
71136401Ssklower 			tptrace(TPPTmisc,
71236401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
71336401Ssklower 				class_to_use,
71436401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
71536401Ssklower 				);
71636401Ssklower 		ENDTRACE
71736401Ssklower 		CHECK(
71836401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
71936401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
72036401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
72136401Ssklower 				/* ^ more or less the location of class */
72236401Ssklower 			)
72336401Ssklower 		IFDEBUG(D_CONN)
72436401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
72536401Ssklower 				tpcb, tpcb->tp_flags);
72636401Ssklower 		ENDDEBUG
72736401Ssklower 		takes_data = TRUE;
72836401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
72936401Ssklower 		e.ev_number = CR_TPDU;
73036401Ssklower 
73136401Ssklower 		so = tpcb->tp_sock;
73236401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
73344422Ssklower 			struct tp_pcb *parent_tpcb = tpcb;
73436401Ssklower 			/*
73536401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
73636401Ssklower 			 * for this newborn connection, and fill in all the values.
73736401Ssklower 			 */
73836401Ssklower 			IFDEBUG(D_CONN)
73936401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
74036401Ssklower 					so, laddr, faddr, cons_channel);
74136401Ssklower 			ENDDEBUG
74236401Ssklower 			if( (so =
74336401Ssklower 				tp_newsocket(so, faddr, cons_channel,
74436401Ssklower 					class_to_use,
74537469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
74637469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
74736401Ssklower 					) == (struct socket *)0 ) {
74836401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
74936401Ssklower 				 * the tp entity is concerned, the only differences
75037469Ssklower 				 * are CO vs CL
75136401Ssklower 				 */
75236401Ssklower 				IFDEBUG(D_CONN)
75336401Ssklower 					printf("tp_newsocket returns 0\n");
75436401Ssklower 				ENDDEBUG
75536401Ssklower 				goto discard;
75636401Ssklower 			}
75736401Ssklower 			tpcb = sototpcb(so);
75844601Ssklower 			insque(tpcb, parent_tpcb);
75936401Ssklower 
76036401Ssklower 			/*
76137469Ssklower 			 * Stash the addresses in the net level pcb
76236401Ssklower 			 * kind of like a pcbconnect() but don't need
76336401Ssklower 			 * or want all those checks.
76436401Ssklower 			 */
76536401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
76636401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
76736401Ssklower 
76837469Ssklower 			/* stash the f suffix in the new tpcb */
76938841Ssklower 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
77044422Ssklower 			/* l suffix is already there, unless this is an intercept case */
77144422Ssklower 			if (intercepted)
77244422Ssklower 				bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
77337469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
77437469Ssklower 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
77538841Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
77638841Ssklower 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
77736401Ssklower #ifdef TP_PERF_MEAS
77836401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
77936401Ssklower 				/* ok, let's create an mbuf for stashing the
78036401Ssklower 				 * statistics if one doesn't already exist
78136401Ssklower 				 */
78236401Ssklower 				(void) tp_setup_perf(tpcb);
78336401Ssklower 			}
78436401Ssklower #endif TP_PERF_MEAS
78536401Ssklower 			tpcb->tp_fref = sref;
78636401Ssklower 
78736401Ssklower 			/* We've already checked for consistency with the options
78836401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
78936401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
79036401Ssklower 			 * Now we set the options in the new socket's tpcb.
79136401Ssklower 			 */
79236401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
79336401Ssklower 
79436401Ssklower 			if(!tpcb->tp_use_checksum)
79536401Ssklower 				IncStat(ts_csum_off);
79636401Ssklower 			if(tpcb->tp_xpd_service)
79736401Ssklower 				IncStat(ts_use_txpd);
79836401Ssklower 			if(tpcb->tp_xtd_format)
79936401Ssklower 				IncStat(ts_xtd_fmt);
80036401Ssklower 
80136401Ssklower 			/*
80236401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
80336401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
80436401Ssklower 			 */
80536401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
80636401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
80736401Ssklower 			tpcb->tp_peer_acktime = acktime;
80836401Ssklower 
80936401Ssklower 			/*
81036401Ssklower 			 * The following kludge is used to test retransmissions and
81136401Ssklower 			 * timeout during connection establishment.
81236401Ssklower 			 */
81336401Ssklower 			IFDEBUG(D_ZDREF)
81436401Ssklower 				IncStat(ts_zdebug);
81537469Ssklower 				/*tpcb->tp_fref = 0;*/
81636401Ssklower 			ENDDEBUG
81736401Ssklower 		}
81836401Ssklower 		IncStat(ts_CR_rcvd);
81939929Ssklower 		if (!tpcb->tp_cebit_off) {
82039929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
82139929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
82239929Ssklower 			LOCAL_CREDIT(tpcb);
82339929Ssklower 			CONG_INIT_SAMPLE(tpcb);
82439929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
82539929Ssklower 		}
82639929Ssklower 		tpcb->tp_ackrcvd = 0;
82736401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
82836401Ssklower 		/*
82936401Ssklower 		 * ER TPDUs have to be recognized separately
83036401Ssklower 		 * because they don't necessarily have a tpcb
83136401Ssklower 		 * with them and we don't want err out looking for such
83236401Ssklower 		 * a beast.
83336401Ssklower 		 * We could put a bunch of little kludges in the
83436401Ssklower 		 * next section of code so it would avoid references to tpcb
83536401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
83636401Ssklower 		 * mess up code for data transfer.
83736401Ssklower 		 */
83836401Ssklower 		IncStat(ts_ER_rcvd);
83936401Ssklower 		e.ev_number = ER_TPDU;
84036401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
84136401Ssklower 		takes_data = 1;
84236401Ssklower 	} else {
84336401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
84436401Ssklower 
84536401Ssklower 		/* In the next 4 checks,
84636401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
84736401Ssklower 		 * the fixed part (can't take the address of a bit field)
84836401Ssklower 		 */
84936401Ssklower 		if(cons_channel) {
85036401Ssklower #if NARGOXTWENTYFIVE > 0
85136401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
85236401Ssklower 
85336401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
85436401Ssklower 			/* Problem:  We may have a legit
85536401Ssklower 			 * error situation yet we may or may not have
85636401Ssklower 			 * a correspondence between the tpcb and the vc,
85736401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
85836401Ssklower 			 *          <---  DR
85936401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
86036401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
86136401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
86236401Ssklower 			 * Sigh.
86336401Ssklower 			 */
86436401Ssklower 
86536401Ssklower 			/* I don't know about this error value */
86636401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
86736401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
86836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
86936401Ssklower #else
87036401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
87136401Ssklower #endif NARGOXTWENTYFIVE > 0
87236401Ssklower 
87336401Ssklower 		} else {
87436401Ssklower 
87536401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
87642944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
87736401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
87836401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
87942944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
88036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88136401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
88242944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
88336401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88436401Ssklower 		}
88536401Ssklower 
88636401Ssklower 		IFDEBUG(D_TPINPUT)
88736401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
88836401Ssklower 		ENDDEBUG
88936401Ssklower 
89036401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
89136401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
89236401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
89336401Ssklower 			ts_inv_dref, respond,
89436401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89536401Ssklower 
89636401Ssklower 		IFDEBUG(D_TPINPUT)
89736401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
89836401Ssklower 		ENDDEBUG
89936401Ssklower 		/*
90036401Ssklower 		 * At this point the state of the dref could be
90136401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
90236401Ssklower 		 *		   for example, DC may arrive after the close() has detached
90336401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
90436401Ssklower 		 * OPENING : a tpcb exists but no timers yet
90536401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
90636401Ssklower 		 */
90736401Ssklower 
90839929Ssklower         if (!tpcb->tp_cebit_off)
90939929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
91039929Ssklower 
91136401Ssklower 		dusize = tpcb->tp_tpdusize;
91236401Ssklower 
91336401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
91436401Ssklower 
91536401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
91636401Ssklower 
91737469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
91836401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
91936401Ssklower 
92036401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
92136401Ssklower 					/* not in class 0; 1 octet */
92236401Ssklower 					vb_getval(P, u_char, addlopt);
92336401Ssklower 					break;
92436401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
92542944Ssklower 				{
92642944Ssklower 					u_char odusize = dusize;
92736401Ssklower 					vb_getval(P, u_char, dusize);
92842944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
92942944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
93042944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
93142944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
93236401Ssklower 					IFDEBUG(D_TPINPUT)
93336401Ssklower 						printf("CC dusize 0x%x\n", dusize);
93436401Ssklower 					ENDDEBUG
93542944Ssklower 				}
93636401Ssklower 					break;
93736401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
93836401Ssklower 					IFDEBUG(D_TPINPUT)
93936401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
94036401Ssklower 					ENDDEBUG
94136401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
94236401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
94336401Ssklower 					break;
94436401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
94536401Ssklower 					/* class 4 only, 2 octets */
94636401Ssklower 					vb_getval(P, u_short, acktime);
947*44947Ssklower 					acktime = ntohs(acktime);
94836401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
94936401Ssklower 					if( (short)acktime <=0 )
95036401Ssklower 						acktime = 2;
95136401Ssklower 					break;
95236401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
95336401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
95436401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
95536401Ssklower 					IFDEBUG(D_TPINPUT)
95636401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
95736401Ssklower 					ENDDEBUG
95836401Ssklower 					break;
95936401Ssklower 
96036401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
96136401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
96236401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
96336401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
96436401Ssklower 					if( tpcb->tp_use_checksum )  {
96536401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
96636401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
96736401Ssklower 					}
96836401Ssklower 					break;
96936401Ssklower 
97036401Ssklower 			/*  this is different from the above because in the context
97136401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
97236401Ssklower 			 */
97336401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
97436401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
97536401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
97636401Ssklower 					if( tpcb->tp_use_checksum )  {
97737469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
97836401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
97936401Ssklower 					}
98036401Ssklower 					break;
98136401Ssklower #ifdef notdef
98236401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
98336401Ssklower 				/* ignore - its length and meaning are
98436401Ssklower 				 * user defined and there's no way
98536401Ssklower 				 * to pass this info to the user anyway
98636401Ssklower 				 */
98736401Ssklower 				break;
98836401Ssklower #endif notdef
98936401Ssklower 
99036401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
99136401Ssklower 				/* used after reduction of window */
99236401Ssklower 				vb_getval(P, u_short, subseq);
99336401Ssklower 				subseq = ntohs(subseq);
99436401Ssklower 				IFDEBUG(D_ACKRECV)
99536401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
99636401Ssklower 				ENDDEBUG
99736401Ssklower 				break;
99836401Ssklower 
99936401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
100036401Ssklower 				{
100136401Ssklower 					u_int 	ylwe;
100236401Ssklower 					u_short ysubseq, ycredit;
100336401Ssklower 
100436401Ssklower 					fcc_present = TRUE;
100536401Ssklower 					vb_getval(P, u_int,	 	ylwe);
100636401Ssklower 					vb_getval(P, u_short, 	ysubseq);
100736401Ssklower 					vb_getval(P, u_short, 	ycredit);
100836401Ssklower 					ylwe = ntohl(ylwe);
100936401Ssklower 					ysubseq = ntohs(ysubseq);
101036401Ssklower 					ycredit = ntohs(ycredit);
101136401Ssklower 					IFDEBUG(D_ACKRECV)
101236401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
101336401Ssklower 							ylwe, ysubseq, ycredit);
101436401Ssklower 					ENDDEBUG
101536401Ssklower 				}
101636401Ssklower 				break;
101736401Ssklower 
101836401Ssklower 			default:
101936401Ssklower 				IFDEBUG(D_TPINPUT)
102036401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
102136401Ssklower 						dutype, vbptr(P)->tpv_code);
102236401Ssklower 				ENDDEBUG
102336401Ssklower 				IFTRACE(D_TPINPUT)
102436401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
102536401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
102636401Ssklower 				ENDTRACE
102736401Ssklower 				IncStat(ts_param_ignored);
102836401Ssklower 				break;
102936401Ssklower #undef caseof
103036401Ssklower 		}
103136401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
103236401Ssklower 
103336401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
103436401Ssklower 
103536401Ssklower 		switch( hdr->tpdu_type ) {
103636401Ssklower 		case CC_TPDU_type:
103736401Ssklower 			/* If CC comes back with an unacceptable class
103836401Ssklower 			 * respond with a DR or ER
103936401Ssklower 			 */
104036401Ssklower 
104136401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
104236401Ssklower 
104336401Ssklower 			{
104436401Ssklower 				tpp = tpcb->_tp_param;
104536401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
104636401Ssklower 				tpp.p_tpdusize = dusize;
104736401Ssklower 				tpp.p_dont_change_params = 0;
104836401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
104936401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
105036401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
105136401Ssklower #ifdef notdef
105236401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
105336401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
105436401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
105536401Ssklower #endif notdef
105636401Ssklower 
105736401Ssklower 			CHECK(
105836401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
105936401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
106036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
106136401Ssklower 					/* ^ more or less the location of class */
106236401Ssklower 				)
106336401Ssklower 			IFTRACE(D_CONN)
106436401Ssklower 				tptrace(TPPTmisc,
106536401Ssklower 					"after 1 consist class, out, tpconsout",
106636401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
106736401Ssklower 					);
106836401Ssklower 			ENDTRACE
106936401Ssklower 			CHECK(
107036401Ssklower 				((class_to_use == TP_CLASS_0)&&
107136401Ssklower 					(dgout_routine != tpcons_output)),
107236401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
107336401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
107436401Ssklower 					/* ^ more or less the location of class */
107536401Ssklower 				)
107636401Ssklower 			}
107736401Ssklower 			if( ! tpcb->tp_use_checksum)
107836401Ssklower 				IncStat(ts_csum_off);
107936401Ssklower 			if(tpcb->tp_xpd_service)
108036401Ssklower 				IncStat(ts_use_txpd);
108136401Ssklower 			if(tpcb->tp_xtd_format)
108236401Ssklower 				IncStat(ts_xtd_fmt);
108336401Ssklower 
108436401Ssklower 			IFTRACE(D_CONN)
108536401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
108636401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
108736401Ssklower 					hdr->tpdu_CCclass);
108836401Ssklower 			ENDTRACE
108936401Ssklower 
109036401Ssklower 			/*
109136401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
109236401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
109336401Ssklower 			 * It would be nice if the arguments to this
109436401Ssklower 			 * were more reasonable.
109536401Ssklower 			 */
109636401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
109736401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
109836401Ssklower 
109936401Ssklower #ifdef	CONS
110036401Ssklower 			/* Could be that this CC came in on a NEW vc, in which case
110136401Ssklower 			 * we have to confirm it.
110236401Ssklower 			 */
110336401Ssklower 			if( cons_channel )
110436401Ssklower 				cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
110536401Ssklower 						tpcb->tp_class == TP_CLASS_4);
110636401Ssklower #endif	CONS
110736401Ssklower 
110836401Ssklower 			tpcb->tp_peer_acktime = acktime;
110936401Ssklower 
111036401Ssklower 			/* if called or calling suffices appeared on the CC,
111136401Ssklower 			 * they'd better jive with what's in the pcb
111236401Ssklower 			 */
111336401Ssklower 			if( fsufxlen ) {
111436401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
111536401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
111636401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
111736401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
111836401Ssklower 			}
111936401Ssklower 			if( lsufxlen ) {
112036401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
112136401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
112236401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
112336401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
112436401Ssklower 			}
112536401Ssklower 
112636401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
112736401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
112836401Ssklower 			takes_data = TRUE;
112936401Ssklower 			e.ev_number = CC_TPDU;
113036401Ssklower 			IncStat(ts_CC_rcvd);
113136401Ssklower 			break;
113236401Ssklower 
113336401Ssklower 		case DC_TPDU_type:
113436401Ssklower 			if (sref != tpcb->tp_fref)
113536401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
113636401Ssklower 					sref, tpcb->tp_fref);
113736401Ssklower 
113836401Ssklower 			CHECK( (sref != tpcb->tp_fref),
113942944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
114036401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
114142944Ssklower 
114236401Ssklower 			e.ev_number = DC_TPDU;
114336401Ssklower 			IncStat(ts_DC_rcvd);
114436401Ssklower 			break;
114536401Ssklower 
114636401Ssklower 		case DR_TPDU_type:
114736401Ssklower 			IFTRACE(D_TPINPUT)
114836401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
114936401Ssklower 			ENDTRACE
115042944Ssklower 			if (sref != tpcb->tp_fref) {
115136401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
115236401Ssklower 					sref, tpcb->tp_fref);
115342944Ssklower 			}
115436401Ssklower 
115542944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
115642944Ssklower 					tpcb->tp_state != TP_CRSENT),
115742944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
115836401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
115936401Ssklower 
116036401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
116136401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
116236401Ssklower 			takes_data = TRUE;
116336401Ssklower 			e.ev_number = DR_TPDU;
116436401Ssklower 			IncStat(ts_DR_rcvd);
116536401Ssklower 			break;
116636401Ssklower 
116736401Ssklower 		case ER_TPDU_type:
116836401Ssklower 			IFTRACE(D_TPINPUT)
116936401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
117036401Ssklower 			ENDTRACE
117136401Ssklower 			e.ev_number = ER_TPDU;
117236401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
117336401Ssklower 			IncStat(ts_ER_rcvd);
117436401Ssklower 			break;
117536401Ssklower 
117636401Ssklower 		case AK_TPDU_type:
117736401Ssklower 
117836401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
117936401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
118036401Ssklower 
118136401Ssklower 			if (tpcb->tp_xtd_format) {
118236401Ssklower #ifdef BYTE_ORDER
118336401Ssklower 				union seq_type seqeotX;
118436401Ssklower 
118536401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
118636401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
118736401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
118836401Ssklower #else
118936401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
119036401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
119136401Ssklower #endif BYTE_ORDER
119236401Ssklower 			} else {
119336401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
119436401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
119536401Ssklower 			}
119636401Ssklower 			IFTRACE(D_TPINPUT)
119736401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
119836401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
119936401Ssklower 					subseq, fcc_present);
120036401Ssklower 			ENDTRACE
120136401Ssklower 
120236401Ssklower 			e.ev_number = AK_TPDU;
120336401Ssklower 			IncStat(ts_AK_rcvd);
120436401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
120536401Ssklower 			break;
120636401Ssklower 
120736401Ssklower 		case XAK_TPDU_type:
120836401Ssklower 			if (tpcb->tp_xtd_format) {
120936401Ssklower #ifdef BYTE_ORDER
121036401Ssklower 				union seq_type seqeotX;
121136401Ssklower 
121236401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
121336401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
121436401Ssklower #else
121536401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
121636401Ssklower #endif BYTE_ORDER
121736401Ssklower 			} else {
121836401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
121936401Ssklower 			}
122036401Ssklower 			e.ev_number = XAK_TPDU;
122136401Ssklower 			IncStat(ts_XAK_rcvd);
122236401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
122336401Ssklower 			break;
122436401Ssklower 
122536401Ssklower 		case XPD_TPDU_type:
122636401Ssklower 			if (tpcb->tp_xtd_format) {
122736401Ssklower #ifdef BYTE_ORDER
122836401Ssklower 				union seq_type seqeotX;
122936401Ssklower 
123036401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
123136401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
123236401Ssklower #else
123336401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
123436401Ssklower #endif BYTE_ORDER
123536401Ssklower 			} else {
123636401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
123736401Ssklower 			}
123836401Ssklower 			takes_data = TRUE;
123936401Ssklower 			e.ev_number = XPD_TPDU;
124036401Ssklower 			IncStat(ts_XPD_rcvd);
124136401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
124236401Ssklower 			break;
124336401Ssklower 
124436401Ssklower 		case DT_TPDU_type:
124536401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
124636401Ssklower 			   * A little crude but it works.
124736401Ssklower 			   */
124836401Ssklower 
124936401Ssklower 				IFDEBUG(D_DROP)
125036401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
125136401Ssklower 						IncStat(ts_ydebug);
125236401Ssklower 						goto discard;
125336401Ssklower 					}
125436401Ssklower 				ENDDEBUG
125536401Ssklower 			}
125636401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
125736401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
125836401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
125936401Ssklower 			} else if (tpcb->tp_xtd_format) {
126036401Ssklower #ifdef BYTE_ORDER
126136401Ssklower 				union seq_type seqeotX;
126236401Ssklower 
126336401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
126436401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
126536401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
126636401Ssklower #else
126736401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
126836401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
126936401Ssklower #endif BYTE_ORDER
127036401Ssklower 			} else {
127136401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
127236401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
127336401Ssklower 			}
127436401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
127536401Ssklower 				IncStat(ts_eot_input);
127636401Ssklower 			takes_data = TRUE;
127736401Ssklower 			e.ev_number = DT_TPDU;
127836401Ssklower 			IncStat(ts_DT_rcvd);
127936401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
128036401Ssklower 			break;
128136401Ssklower 
128236401Ssklower 		case GR_TPDU_type:
128336401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
128436401Ssklower 			/* drop through */
128536401Ssklower 		default:
128636401Ssklower 			/* this should NEVER happen because there is a
128736401Ssklower 			 * check for dutype well above here
128836401Ssklower 			 */
128936401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
129036401Ssklower 			IFDEBUG(D_TPINPUT)
129136401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
129236401Ssklower 			ENDDEBUG
129336401Ssklower 			IncStat(ts_inv_dutype);
129436401Ssklower 			goto respond;
129536401Ssklower 		}
129636401Ssklower 	}
129736401Ssklower 	/* peel off the tp header;
129836401Ssklower 	 * remember that the du_li doesn't count itself.
129936401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
130036401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
130136401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
130236401Ssklower 	 */
130336401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
130437469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
130536401Ssklower 
130637469Ssklower 	if (takes_data) {
130737469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
130837469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
130942468Ssklower 		struct cmsghdr c_hdr;
131037469Ssklower 		struct mbuf *n;
131136401Ssklower 
131237469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
131337469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
131436401Ssklower 		switch( hdr->tpdu_type ) {
131537469Ssklower 
131636401Ssklower 		case CR_TPDU_type:
131737469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
131837469Ssklower 			goto make_control_msg;
131937469Ssklower 
132036401Ssklower 		case CC_TPDU_type:
132137469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
132237469Ssklower 			goto make_control_msg;
132337469Ssklower 
132436401Ssklower 		case DR_TPDU_type:
132537469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
132637469Ssklower 		make_control_msg:
132737469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
132837469Ssklower 			mbtype = MT_CONTROL;
132943334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
133043334Ssklower 			if (n) {
133143334Ssklower 				datalen += sizeof(c_hdr);
133243334Ssklower 				n->m_len = sizeof(c_hdr);
133343334Ssklower 				c_hdr.cmsg_len = datalen;
133443334Ssklower 				*mtod(n, struct cmsghdr *) = c_hdr;
133543334Ssklower 				n->m_next = m;
133643334Ssklower 				m = n;
133743334Ssklower 			} else {m_freem(m); m = 0; goto invoke;}
133837469Ssklower 			/* FALLTHROUGH */
133937469Ssklower 
134036401Ssklower 		case XPD_TPDU_type:
134137469Ssklower 			if (mbtype != MT_CONTROL)
134237469Ssklower 				mbtype = MT_OOBDATA;
134337469Ssklower 			m->m_flags |= M_EOR;
134437469Ssklower 			/* FALLTHROUGH */
134537469Ssklower 
134636401Ssklower 		case DT_TPDU_type:
134737469Ssklower 			for (n = m; n; n = n->m_next) {
134837469Ssklower 				MCHTYPE(n, mbtype);
134937469Ssklower 			}
135043334Ssklower 		invoke:
135137469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
135236401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
135336401Ssklower 			break;
135436401Ssklower 
135536401Ssklower 		default:
135636401Ssklower 			printf(
135736401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
135836401Ssklower 				hdr->tpdu_type, takes_data, m);
135936401Ssklower 			break;
136036401Ssklower 		}
136136401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
136236401Ssklower 		m = MNULL;
136336401Ssklower 	}
136436401Ssklower 
136536401Ssklower 	IncStat(ts_tpdu_rcvd);
136636401Ssklower 
136736401Ssklower 	IFDEBUG(D_TPINPUT)
136836401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
136936401Ssklower 			tpcb->tp_state, e.ev_number, m );
137036401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
137136401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
137236401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
137336401Ssklower 	ENDDEBUG
137436401Ssklower 
137536401Ssklower 	error = tp_driver(tpcb, &e);
137636401Ssklower 
137736401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
137836401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
137936401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
138036401Ssklower 		tpcb->tp_sock->so_error = error;
138136401Ssklower 
138236401Ssklower 	/* Kludge to keep the state tables under control (adding
138336401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
138436401Ssklower 	 * the data would have exploded the tables and made a big mess ).
138536401Ssklower 	 */
138636401Ssklower 	switch(e.ev_number) {
138736401Ssklower 		case CC_TPDU:
138836401Ssklower 		case DR_TPDU:
138936401Ssklower 		case CR_TPDU:
139036401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
139136401Ssklower 			IFDEBUG(D_TPINPUT)
139236401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
139336401Ssklower 				m, takes_data);
139436401Ssklower 			ENDDEBUG
139536401Ssklower 			break;
139636401Ssklower 		default:
139736401Ssklower 			break;
139836401Ssklower 	}
139936401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
140036401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
140136401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
140236401Ssklower 	 */
140336401Ssklower 
140436401Ssklower separate:
140536401Ssklower 	if ( takes_data == 0 )  {
140636401Ssklower 		ASSERT( m != MNULL );
140736401Ssklower 		/*
140836401Ssklower 		 * we already peeled off the prev. tp header so
140936401Ssklower 		 * we can just pull up some more and repeat
141036401Ssklower 		 */
141136401Ssklower 
141237469Ssklower 		if( m = tp_inputprep(m) ) {
141336401Ssklower 		IFDEBUG(D_TPINPUT)
141436401Ssklower 			hdr = mtod(m, struct tpdu *);
141536401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
141636401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
141736401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
141836401Ssklower 		ENDDEBUG
141936401Ssklower 
142036401Ssklower 			IncStat(ts_concat_rcvd);
142136401Ssklower 			goto again;
142236401Ssklower 		}
142336401Ssklower 	}
142436401Ssklower 	if ( m != MNULL ) {
142536401Ssklower 		IFDEBUG(D_TPINPUT)
142636401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
142736401Ssklower 		ENDDEBUG
142836401Ssklower 		m_freem(m);
142936401Ssklower 		IFDEBUG(D_TPINPUT)
143036401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
143136401Ssklower 		ENDDEBUG
143236401Ssklower 	}
143336401Ssklower 	return (ProtoHook) tpcb;
143436401Ssklower 
143536401Ssklower discard:
143636401Ssklower 	/* class 4: drop the tpdu */
143736401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
143836401Ssklower 	 * to which connection it applies
143936401Ssklower 	 */
144036401Ssklower 	IFDEBUG(D_TPINPUT)
144136401Ssklower 		printf("tp_input DISCARD\n");
144236401Ssklower 	ENDDEBUG
144336401Ssklower 	IFTRACE(D_TPINPUT)
144436401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
144536401Ssklower 	ENDTRACE
144636401Ssklower 	m_freem(m);
144736401Ssklower 	IncStat(ts_recv_drop);
144836401Ssklower 	return (ProtoHook)0;
144936401Ssklower 
145042944Ssklower nonx_dref:
145142944Ssklower 	switch (dutype) {
145242944Ssklower 	default:
145342944Ssklower 		goto discard;
145442944Ssklower 	case CC_TPDU_type:
145542944Ssklower 		/* error = E_TP_MISM_REFS; */
145642944Ssklower 		break;
145742944Ssklower 	case DR_TPDU_type:
145842944Ssklower 		error |= TP_ERROR_SNDC;
145942944Ssklower 	}
146036401Ssklower respond:
146143334Ssklower 	IFDEBUG(D_TPINPUT)
146242944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
146336401Ssklower 	ENDDEBUG
146436401Ssklower 	IFTRACE(D_TPINPUT)
146542944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
146636401Ssklower 	ENDTRACE
146742944Ssklower 	if (sref == 0)
146836401Ssklower 		goto discard;
146937469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
147042944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
147137469Ssklower 				(int)cons_channel, dgout_routine);
147236401Ssklower 	IFDEBUG(D_ERROR_EMIT)
147336401Ssklower 		printf("tp_input after error_emit\n");
147436401Ssklower 	ENDDEBUG
147536401Ssklower 
147636401Ssklower #ifdef lint
147736401Ssklower 	printf("",sref,opt);
147836401Ssklower #endif lint
147936401Ssklower 	IncStat(ts_recv_drop);
148036401Ssklower 	return (ProtoHook)0;
148136401Ssklower }
148236401Ssklower 
148336401Ssklower 
148436401Ssklower /*
148536401Ssklower  * NAME: tp_headersize()
148636401Ssklower  *
148736401Ssklower  * CALLED FROM:
148836401Ssklower  *  tp_emit() and tp_sbsend()
148936401Ssklower  *  TP needs to know the header size so it can figure out how
149036401Ssklower  *  much data to put in each tpdu.
149136401Ssklower  *
149236401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
149336401Ssklower  *  For a given connection, represented by (tpcb), and
149436401Ssklower  *  tpdu type (dutype), return the size of a tp header.
149536401Ssklower  *
149636401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
149736401Ssklower  *
149836401Ssklower  * SIDE EFFECTS:
149936401Ssklower  *
150036401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
150136401Ssklower  */
150236401Ssklower int
150336401Ssklower tp_headersize(dutype, tpcb)
150436401Ssklower 	int 			dutype;
150536401Ssklower 	struct tp_pcb 	*tpcb;
150636401Ssklower {
150736401Ssklower 	register int size = 0;
150836401Ssklower 
150936401Ssklower 	IFTRACE(D_CONN)
151036401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
151136401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
151236401Ssklower 	ENDTRACE
151336401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
151436401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
151536401Ssklower 			(dutype == DR_TPDU_type) ||
151636401Ssklower 			(dutype == CR_TPDU_type) )) {
151736401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
151836401Ssklower 			dutype, tpcb->tp_class);
151936401Ssklower 	/* TODO: identify this and GET RID OF IT */
152036401Ssklower 	}
152136401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
152236401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
152336401Ssklower 			(dutype == DR_TPDU_type) ||
152436401Ssklower 			(dutype == CR_TPDU_type) );
152536401Ssklower 
152636401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
152736401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
152836401Ssklower 	} else  {
152936401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
153036401Ssklower 	}
153136401Ssklower 	return size;
153236401Ssklower 	/* caller must get network level header size separately */
153336401Ssklower }
1534