xref: /csrg-svn/sys/netiso/tp_input.c (revision 48749)
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*48749Ssklower  *	@(#)tp_input.c	7.16 (Berkeley) 04/26/91 *
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 "param.h"
6044422Ssklower #include "systm.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"
7045900Ssklower #include "iso.h"
7137469Ssklower #include "iso_errno.h"
7245900Ssklower #include "iso_pcb.h"
7337469Ssklower #include "tp_param.h"
7437469Ssklower #include "tp_timer.h"
7537469Ssklower #include "tp_stat.h"
7637469Ssklower #include "tp_pcb.h"
7737469Ssklower #include "argo_debug.h"
7837469Ssklower #include "tp_trace.h"
7937469Ssklower #include "tp_tpdu.h"
8036401Ssklower 
8145900Ssklower #include "../net/if.h"
8245900Ssklower #ifdef TRUE
8345900Ssklower #undef FALSE
8445900Ssklower #undef TRUE
8545900Ssklower #endif
8645900Ssklower #include "../netccitt/x25.h"
8745900Ssklower #include "../netccitt/pk.h"
8845900Ssklower #include "../netccitt/pk_var.h"
8945900Ssklower 
9036401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
9136401Ssklower 
9237469Ssklower /*
9337469Ssklower 	#ifdef lint
9437469Ssklower 	#undef ATTR
9537469Ssklower 	#define ATTR(X)ev_number
9637469Ssklower 	#endif lint
9737469Ssklower */
9836401Ssklower 
9936401Ssklower struct mbuf *
10036401Ssklower tp_inputprep(m)
10137469Ssklower 	register struct mbuf *m;
10236401Ssklower {
10337469Ssklower 	int hdrlen;
10436401Ssklower 
10536401Ssklower 	IFDEBUG(D_TPINPUT)
10637469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
10736401Ssklower 	ENDDEBUG
10836401Ssklower 
10936401Ssklower 	while(  m->m_len < 1 ) {
11036401Ssklower 		if( (m = m_free(m)) == MNULL ) {
11136401Ssklower 			return (struct mbuf *)0;
11236401Ssklower 		}
11336401Ssklower 	}
11437469Ssklower 	if(((int)m->m_data) & 0x3) {
11537469Ssklower 		/* If we are not 4-byte aligned, we have to be
11637469Ssklower 		 * above the beginning of the mbuf, and it is ok just
11737469Ssklower 		 * to slide it back.
11837469Ssklower 		 */
11937469Ssklower 		caddr_t ocp = m->m_data;
12036401Ssklower 
12137469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
12237469Ssklower 		ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
12336401Ssklower 	}
12436401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
12536401Ssklower 
12637469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
12737469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
12836401Ssklower 
12937469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
13036401Ssklower 
13136401Ssklower 	/*
13236401Ssklower 	 * now pull up the whole tp header
13336401Ssklower 	 */
13437469Ssklower 	if ( m->m_len < hdrlen) {
13537469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
13636401Ssklower 			IncStat(ts_recv_drop);
13736401Ssklower 			return (struct mbuf *)0;
13836401Ssklower 		}
13936401Ssklower 	}
14036401Ssklower 	IFDEBUG(D_INPUT)
14136401Ssklower 	printf(
14236401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
14337469Ssklower 		hdrlen, m->m_len);
14436401Ssklower 	ENDDEBUG
14536401Ssklower 	return m;
14636401Ssklower }
14736401Ssklower 
14836401Ssklower /* begin groan
14936401Ssklower  * -- this array and the following macros allow you to step through the
15036401Ssklower  * parameters of the variable part of a header
15136401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
15236401Ssklower  * should change, this array has to be rearranged
15336401Ssklower  */
15436401Ssklower 
15536401Ssklower #define TP_LEN_CLASS_0_INDEX	2
15636401Ssklower #define TP_MAX_DATA_INDEX 3
15736401Ssklower 
15836401Ssklower static u_char tpdu_info[][4] =
15936401Ssklower {
16036401Ssklower /*								length						 max data len */
16136401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
16236401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
16336401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
16436401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
16536401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
16636401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
16736401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
16836401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
16936401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
17036401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
17136401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
17236401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
17336401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
17436401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
17536401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
17636401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
17736401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
17836401Ssklower };
17936401Ssklower 
18042944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
18143334Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
18242944Ssklower 	goto Whattodo; }
18342944Ssklower 
18443334Ssklower tpibrk() {}
18543334Ssklower 
18636401Ssklower /*
18736401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
18836401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
18936401Ssklower  */
19036401Ssklower 
19142944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
19242944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
19342944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
19442944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
19542944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
19642944Ssklower 				respond, P - (caddr_t)hdr);\
19742944Ssklower 		if (P == PLIM) break;
19836401Ssklower 
19942944Ssklower #define END_WHILE_OPTIONS(P) } }
20036401Ssklower 
20136401Ssklower /* end groan */
20236401Ssklower 
20336401Ssklower /*
20436401Ssklower  * NAME:  tp_newsocket()
20536401Ssklower  *
20636401Ssklower  * CALLED FROM:
20736401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
20836401Ssklower  * is awaiting a  connection request
20936401Ssklower  *
21036401Ssklower  * FUNCTION and ARGUMENTS:
21136401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
21236401Ssklower  *  using a copy of the net level pcb for the parent socket.
21336401Ssklower  *  (so) is the parent socket.
21436401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
21536401Ssklower  *
21636401Ssklower  * RETURN VALUE:
21736401Ssklower  *  a new socket structure, being this end of the newly formed connection.
21836401Ssklower  *
21936401Ssklower  * SIDE EFFECTS:
22036401Ssklower  *  Sets a few things in the tpcb and net level pcb
22136401Ssklower  *
22236401Ssklower  * NOTES:
22336401Ssklower  */
22436401Ssklower static struct socket *
22536401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
22636401Ssklower 	struct socket				*so;
22736401Ssklower 	struct sockaddr				*fname;
22836401Ssklower 	u_int						cons_channel;
22936401Ssklower 	u_char						class_to_use;
23036401Ssklower 	u_int						netservice;
23136401Ssklower {
23236401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
23345900Ssklower 	register struct tp_pcb	*newtpcb;
23436401Ssklower 
23536401Ssklower 	/*
23636401Ssklower 	 * sonewconn() gets a new socket structure,
23736401Ssklower 	 * a new lower layer pcb and a new tpcb,
23836401Ssklower 	 * but the pcbs are unnamed (not bound)
23936401Ssklower 	 */
24036401Ssklower 	IFTRACE(D_NEWSOCK)
24138841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
24239196Ssklower 			so, tpcb, so->so_head, 0);
24336401Ssklower 	ENDTRACE
24436401Ssklower 
24540636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
24636401Ssklower 		return so;
24736401Ssklower 	IFTRACE(D_NEWSOCK)
24838841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
24938841Ssklower 			so, so->so_head, 0, 0);
25036401Ssklower 	ENDTRACE
25136401Ssklower 
25236401Ssklower 	IFDEBUG(D_NEWSOCK)
25337469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
25437469Ssklower 				cons_channel, so);
25537469Ssklower 		dump_addr(fname);
25636401Ssklower 		{
25736401Ssklower 			struct socket *t, *head ;
25836401Ssklower 
25936401Ssklower 			head = so->so_head;
26036401Ssklower 			t = so;
26136401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26236401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
26336401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
26436401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26536401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
26636401Ssklower 		}
26736401Ssklower 	ENDDEBUG
26836401Ssklower 
26936401Ssklower 	/*
27036401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
27136401Ssklower 	 */
27236401Ssklower 	newtpcb = sototpcb(so);
27336401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
27436401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
27536401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
27636401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
27736401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
27836401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
27937469Ssklower 	soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
28036401Ssklower 
28137469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
28236401Ssklower 		/*
28337469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
28436401Ssklower 		 */
28536401Ssklower 		struct mbuf *conndata;
28636401Ssklower 
28737469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
28836401Ssklower 		IFDEBUG(D_CONN)
28936401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
29036401Ssklower 		ENDDEBUG
29137469Ssklower 		newtpcb->tp_ucddata = conndata;
29236401Ssklower 	}
29336401Ssklower 
29436401Ssklower 	tpcb = newtpcb;
29536401Ssklower 	tpcb->tp_state = TP_LISTENING;
29636401Ssklower 	tpcb->tp_class = class_to_use;
29736401Ssklower 	tpcb->tp_netservice = netservice;
29836401Ssklower 
29936401Ssklower 
30036401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
30136401Ssklower 	if ( fname ) {
30236401Ssklower 		/*
30336401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
30436401Ssklower 		 */
30536401Ssklower 		struct mbuf	*m;
30636401Ssklower 		int			err;
30736401Ssklower 
30836401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
30936401Ssklower 		if (m) {
31036401Ssklower 			/*
31136401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
31236401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
31336401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
31436401Ssklower 			 * sigh.
31536401Ssklower 			 */
31637469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
31737469Ssklower 			m->m_len = fname->sa_len;
31836401Ssklower 
31936401Ssklower 			/* grot  : have to say the kernel can override params in
32036401Ssklower 			 * the passive open case
32136401Ssklower 			 */
32236401Ssklower 			tpcb->tp_dont_change_params = 0;
32336401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
32436401Ssklower 			m_free(m);
32536401Ssklower 
32636401Ssklower 			if (!err)
32736401Ssklower 				goto ok;
32836401Ssklower 		}
32936401Ssklower 		IFDEBUG(D_CONN)
33036401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
33136401Ssklower 				tpcb, so);
33236401Ssklower 		ENDDEBUG
33336401Ssklower 		(void) tp_detach(tpcb);
33436401Ssklower 		return 0;
33536401Ssklower 	}
33636401Ssklower ok:
33736401Ssklower 	IFDEBUG(D_TPINPUT)
33836401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
33936401Ssklower 			so, sototpcb(so));
34036401Ssklower 	ENDDEBUG
34136401Ssklower 	return so;
34236401Ssklower }
34336401Ssklower 
34445900Ssklower #ifndef TPCONS
34536401Ssklower tpcons_output()
34636401Ssklower {
34736401Ssklower 	return(0);
34836401Ssklower }
34936401Ssklower #endif !CONS
35036401Ssklower 
35136401Ssklower /*
35236401Ssklower  * NAME: 	tp_input()
35336401Ssklower  *
35436401Ssklower  * CALLED FROM:
35536401Ssklower  *  net layer input routine
35636401Ssklower  *
35736401Ssklower  * FUNCTION and ARGUMENTS:
35836401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
35936401Ssklower  *  is one. Create the appropriate type of event and call the driver.
36036401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
36136401Ssklower  *
36236401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
36336401Ssklower  * 	has been m_pullup-ed.
36436401Ssklower  *
36536401Ssklower  * RETURN VALUE: Nada
36636401Ssklower  *
36736401Ssklower  * SIDE EFFECTS:
36836401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
36936401Ssklower  *
37036401Ssklower  * NOTE:
37136401Ssklower  *  The initial value of acktime is 2 so that we will never
37236401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
37336401Ssklower  *  computation of the retransmission timer value, and so it
37436401Ssklower  *  mustn't be zero.
37536401Ssklower  *  2 seems like a reasonable minimum.
37636401Ssklower  */
37736401Ssklower ProtoHook
37839929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
37936401Ssklower 	register	struct mbuf 	*m;
38036401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
38136401Ssklower 	u_int 						cons_channel;
38236401Ssklower 	int 						(*dgout_routine)();
38339929Ssklower 	int							ce_bit;
38436401Ssklower 
38536401Ssklower {
38636401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
38744947Ssklower 	register struct tpdu 	*hdr;
38836401Ssklower 	struct socket 			*so;
38936401Ssklower 	struct tp_event 		e;
39042944Ssklower 	int 					error = 0;
39136401Ssklower 	unsigned 				dutype;
39242944Ssklower 	u_short 				dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
39342944Ssklower 	u_char 					preferred_class = 0, class_to_use = 0;
39442944Ssklower 	u_char					opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
39536401Ssklower #ifdef TP_PERF_MEAS
39638841Ssklower 	u_char					perf_meas;
39736401Ssklower #endif TP_PERF_MEAS
39844422Ssklower 	u_char					fsufxlen = 0, lsufxlen = 0, intercepted = 0;
39942944Ssklower 	caddr_t					fsufxloc = 0, lsufxloc = 0;
40042944Ssklower 	int						tpdu_len = 0;
40142944Ssklower 	u_int 					takes_data = FALSE;
40242944Ssklower 	u_int					fcc_present = FALSE;
40342944Ssklower 	int						errlen = 0;
40436401Ssklower 	struct tp_conn_param 	tpp;
40536401Ssklower 	int						tpcons_output();
40636401Ssklower 
40738841Ssklower again:
40844947Ssklower 	hdr = mtod(m, struct tpdu *);
40936401Ssklower #ifdef TP_PERF_MEAS
41038841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
41136401Ssklower #endif TP_PERF_MEAS
41236401Ssklower 
41336401Ssklower 	IFDEBUG(D_TPINPUT)
41436401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
41536401Ssklower 	ENDDEBUG
41636401Ssklower 
41736401Ssklower 
41836401Ssklower 	/*
41936401Ssklower 	 * get the actual tpdu length - necessary for monitoring
42036401Ssklower 	 * and for checksumming
42136401Ssklower 	 *
42236401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
42336401Ssklower 	 */
42436401Ssklower 
42536401Ssklower 	{ 	register struct mbuf *n=m;
42636401Ssklower #	ifdef ARGO_DEBUG
42736401Ssklower 		int chain_length = 0;
42836401Ssklower #	endif ARGO_DEBUG
42936401Ssklower 
43036401Ssklower 		for(;;) {
43136401Ssklower 			tpdu_len += n->m_len;
43236401Ssklower 			IFDEBUG(D_MBUF_MEAS)
43337469Ssklower 				if( n->m_flags & M_EXT) {
43436401Ssklower 					IncStat(ts_mb_cluster);
43536401Ssklower 				} else {
43636401Ssklower 					IncStat(ts_mb_small);
43736401Ssklower 				}
43836401Ssklower 				chain_length ++;
43936401Ssklower 			ENDDEBUG
44036401Ssklower 			if (n->m_next == MNULL ) {
44136401Ssklower 				break;
44236401Ssklower 			}
44336401Ssklower 			n = n->m_next;
44436401Ssklower 		}
44536401Ssklower 		IFDEBUG(D_MBUF_MEAS)
44636401Ssklower 			if(chain_length > 16)
44736401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
44836401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
44936401Ssklower 		ENDDEBUG
45036401Ssklower 	}
45136401Ssklower 	IFTRACE(D_TPINPUT)
45236401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
45336401Ssklower 			0);
45436401Ssklower 	ENDTRACE
45536401Ssklower 
45636401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
45736401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
45836401Ssklower 	dutype = (int)hdr->tpdu_type;
45936401Ssklower 
46036401Ssklower 	IFDEBUG(D_TPINPUT)
46136401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
46236401Ssklower 			cons_channel, dref);
46336401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
46436401Ssklower 	ENDDEBUG
46536401Ssklower 	IFTRACE(D_TPINPUT)
46636401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
46736401Ssklower 			cons_channel, dutype, dref, 0);
46836401Ssklower 	ENDTRACE
46936401Ssklower 
47036401Ssklower 
47136401Ssklower #ifdef ARGO_DEBUG
47236401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
47336401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
47436401Ssklower 			dutype, cons_channel, dref);
47536401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
47636401Ssklower 
47736401Ssklower 		IncStat(ts_inv_dutype);
47836401Ssklower 		goto discard;
47936401Ssklower 	}
48036401Ssklower #endif ARGO_DEBUG
48136401Ssklower 
48236401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
48336401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
48436401Ssklower 		2 );
48536401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
48636401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
48736401Ssklower 		 */
48836401Ssklower 
48936401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
49036401Ssklower 	 * at the beginning of connection establishment, and by
49136401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
49236401Ssklower 	 */
49336401Ssklower 	if ( dutype == CR_TPDU_type ) {
49436401Ssklower 		u_char alt_classes = 0;
49536401Ssklower 
49637469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
49736401Ssklower 		opt = hdr->tpdu_CRoptions;
49836401Ssklower 
49936401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
50036401Ssklower 
50136401Ssklower 			switch( vbptr(P)->tpv_code ) {
50236401Ssklower 
50336401Ssklower 			case	TPP_tpdu_size:
50436401Ssklower 				vb_getval(P, u_char, dusize);
50536401Ssklower 				IFDEBUG(D_TPINPUT)
50636401Ssklower 					printf("CR dusize 0x%x\n", dusize);
50736401Ssklower 				ENDDEBUG
50842944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
50942944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
51042944Ssklower 						dusize = TP_DFL_TPDUSIZE;
51136401Ssklower 				break;
51236401Ssklower 			case	TPP_addl_opt:
51336401Ssklower 				vb_getval(P, u_char, addlopt);
51436401Ssklower 				break;
51536401Ssklower 			case	TPP_calling_sufx:
51636401Ssklower 				/* could use vb_getval, but we want to save the loc & len
51736401Ssklower 				 * for later use
51836401Ssklower 				 */
51936401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
52036401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
52136401Ssklower 				IFDEBUG(D_TPINPUT)
52236401Ssklower 					printf("CR fsufx:");
52336401Ssklower 					{ register int j;
52436401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
52536401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
52636401Ssklower 						}
52736401Ssklower 						printf("\n");
52836401Ssklower 					}
52936401Ssklower 				ENDDEBUG
53036401Ssklower 				break;
53136401Ssklower 			case	TPP_called_sufx:
53236401Ssklower 				/* could use vb_getval, but we want to save the loc & len
53336401Ssklower 				 * for later use
53436401Ssklower 				 */
53536401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
53636401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
53736401Ssklower 				IFDEBUG(D_TPINPUT)
53836401Ssklower 					printf("CR lsufx:");
53936401Ssklower 					{ register int j;
54036401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
54137469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
54236401Ssklower 						}
54336401Ssklower 						printf("\n");
54436401Ssklower 					}
54536401Ssklower 				ENDDEBUG
54636401Ssklower 				break;
54736401Ssklower 
54836401Ssklower #ifdef TP_PERF_MEAS
54936401Ssklower 			case	TPP_perf_meas:
55036401Ssklower 				vb_getval(P, u_char, perf_meas);
55136401Ssklower 				break;
55236401Ssklower #endif TP_PERF_MEAS
55336401Ssklower 
55436401Ssklower 			case	TPP_vers:
55536401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
55642944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
55736401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
55842491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
55942944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
56042491Ssklower 			setversion:
56142491Ssklower 				version = vbval(P, u_char);
56236401Ssklower 				break;
56336401Ssklower 			case	TPP_acktime:
56436401Ssklower 				vb_getval(P, u_short, acktime);
56536401Ssklower 				acktime = ntohs(acktime);
56636401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
56736401Ssklower 				if((short)acktime <=0 )
56836401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
56936401Ssklower 				IFDEBUG(D_TPINPUT)
57036401Ssklower 					printf("CR acktime 0x%x\n", acktime);
57136401Ssklower 				ENDDEBUG
57236401Ssklower 				break;
57336401Ssklower 
57436401Ssklower 			case	TPP_alt_class:
57536401Ssklower 				{
57636401Ssklower 					u_char *aclass = 0;
57736401Ssklower 					register int i;
57842944Ssklower 					static u_char bad_alt_classes[5] =
57942944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
58036401Ssklower 
58142944Ssklower 					aclass =
58242944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
58336401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
58442944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
58536401Ssklower 					}
58642944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
58742944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
58842944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
58936401Ssklower 					IFDEBUG(D_TPINPUT)
59036401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
59136401Ssklower 					ENDDEBUG
59236401Ssklower 				}
59336401Ssklower 				break;
59436401Ssklower 
59536401Ssklower 			case	TPP_security:
59636401Ssklower 			case	TPP_residER:
59736401Ssklower 			case	TPP_priority:
59836401Ssklower 			case	TPP_transdelay:
59936401Ssklower 			case	TPP_throughput:
60036401Ssklower 			case	TPP_addl_info:
60136401Ssklower 			case	TPP_subseq:
60244947Ssklower 			default:
60336401Ssklower 				IFDEBUG(D_TPINPUT)
60436401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
60536401Ssklower 						 vbptr(P)->tpv_code);
60636401Ssklower 				ENDDEBUG
60736401Ssklower 				IncStat(ts_param_ignored);
60836401Ssklower 				break;
60936401Ssklower 
61036401Ssklower 			case	TPP_checksum:
61136401Ssklower 				IFDEBUG(D_TPINPUT)
61236401Ssklower 					printf("CR before cksum\n");
61336401Ssklower 				ENDDEBUG
61436401Ssklower 
61536401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
61636401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
61736401Ssklower 
61836401Ssklower 				IFDEBUG(D_TPINPUT)
61936401Ssklower 					printf("CR before cksum\n");
62036401Ssklower 				ENDDEBUG
62136401Ssklower 				break;
62236401Ssklower 			}
62336401Ssklower 
62436401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
62536401Ssklower 
62644422Ssklower 		if (lsufxlen == 0) {
62736401Ssklower 			/* can't look for a tpcb w/o any called sufx */
62836401Ssklower 			error =  E_TP_LENGTH_INVAL;
62936401Ssklower 			IncStat(ts_inv_sufx);
63036401Ssklower 			goto respond;
63136401Ssklower 		} else {
63244422Ssklower 			register struct tp_pcb *t;
63336401Ssklower 
63444601Ssklower 			for (t = tp_intercepts; t ; t = t->tp_nextlisten) {
63544422Ssklower 				if (laddr->sa_family != t->tp_nlproto->nlp_afamily)
63636401Ssklower 					continue;
63744601Ssklower 				if ((*t->tp_nlproto->nlp_cmpnetaddr)(
63844422Ssklower 						t->tp_npcb, laddr, TP_LOCAL)) {
63944422Ssklower 							intercepted = 1;
64044422Ssklower 							goto check_duplicate_cr;
64136401Ssklower 				}
64236401Ssklower 			}
64344601Ssklower 			for (t = tp_listeners; t ; t = t->tp_nextlisten)
64444601Ssklower 				if (bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 &&
64544601Ssklower 					laddr->sa_family == t->tp_nlproto->nlp_afamily)
64644601Ssklower 						break;
64744422Ssklower 			CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
64836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
64936401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
65036401Ssklower 				 * the fixed part (can't take the address of a bit field)
65136401Ssklower 				 */
65244601Ssklower 			IFDEBUG(D_TPINPUT)
65344601Ssklower 				printf("checking if dup CR\n");
65444601Ssklower 			ENDDEBUG
65544422Ssklower 		check_duplicate_cr:
65644422Ssklower 			tpcb = t;
65744422Ssklower 			for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
65844422Ssklower 				if (sref != t->tp_fref)
65944422Ssklower 					continue;
66044422Ssklower 				if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
66144422Ssklower 						t->tp_npcb, faddr, TP_FOREIGN)) {
66244422Ssklower 					IFDEBUG(D_TPINPUT)
66344422Ssklower 						printf("duplicate CR discarded\n");
66444422Ssklower 					ENDDEBUG
66544422Ssklower 					goto discard;
66644422Ssklower 				}
66744422Ssklower 			}
66844422Ssklower 			IFTRACE(D_TPINPUT)
66944422Ssklower 				tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
67044422Ssklower 					tpcb, *lsufxloc, tpcb->tp_state, 0);
67144422Ssklower 			ENDTRACE
67236401Ssklower 		}
67336401Ssklower 
67436401Ssklower 		/*
67536401Ssklower 		 * WE HAVE A TPCB
67636401Ssklower 		 * already know that the classes in the CR match at least
67736401Ssklower 		 * one class implemented, but we don't know yet if they
67836401Ssklower 		 * include any classes permitted by this server.
67936401Ssklower 		 */
68036401Ssklower 
68136401Ssklower 		IFDEBUG(D_TPINPUT)
68236401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
68336401Ssklower 		ENDDEBUG
68436401Ssklower 		IFDEBUG(D_CONN)
68536401Ssklower 			printf(
68636401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
68736401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
68836401Ssklower 		ENDDEBUG
68936401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
69036401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
69136401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
69236401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
69336401Ssklower 
69436401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
69536401Ssklower 
69636401Ssklower 		{
69736401Ssklower 			tpp = tpcb->_tp_param;
69836401Ssklower 			tpp.p_class = class_to_use;
69936401Ssklower 			tpp.p_tpdusize = dusize;
70036401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
70136401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
70236401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
70336401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
70442491Ssklower 			tpp.p_version = version;
70536401Ssklower #ifdef notdef
70636401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
70736401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
70836401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
70936401Ssklower #endif notdef
71036401Ssklower 
71136401Ssklower 		CHECK(
71236401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
71336401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
71436401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
71536401Ssklower 				/* ^ more or less the location of class */
71636401Ssklower 			)
71736401Ssklower 		}
71836401Ssklower 		IFTRACE(D_CONN)
71936401Ssklower 			tptrace(TPPTmisc,
72036401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
72136401Ssklower 				class_to_use,
72236401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
72336401Ssklower 				);
72436401Ssklower 		ENDTRACE
72536401Ssklower 		CHECK(
72636401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
72736401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
72836401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
72936401Ssklower 				/* ^ more or less the location of class */
73036401Ssklower 			)
73136401Ssklower 		IFDEBUG(D_CONN)
73236401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
73336401Ssklower 				tpcb, tpcb->tp_flags);
73436401Ssklower 		ENDDEBUG
73536401Ssklower 		takes_data = TRUE;
73636401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
73736401Ssklower 		e.ev_number = CR_TPDU;
73836401Ssklower 
73936401Ssklower 		so = tpcb->tp_sock;
74036401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
74144422Ssklower 			struct tp_pcb *parent_tpcb = tpcb;
74236401Ssklower 			/*
74336401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
74436401Ssklower 			 * for this newborn connection, and fill in all the values.
74536401Ssklower 			 */
74636401Ssklower 			IFDEBUG(D_CONN)
74736401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
74836401Ssklower 					so, laddr, faddr, cons_channel);
74936401Ssklower 			ENDDEBUG
75036401Ssklower 			if( (so =
75136401Ssklower 				tp_newsocket(so, faddr, cons_channel,
75236401Ssklower 					class_to_use,
75337469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
75437469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
75536401Ssklower 					) == (struct socket *)0 ) {
75636401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
75736401Ssklower 				 * the tp entity is concerned, the only differences
75837469Ssklower 				 * are CO vs CL
75936401Ssklower 				 */
76036401Ssklower 				IFDEBUG(D_CONN)
76136401Ssklower 					printf("tp_newsocket returns 0\n");
76236401Ssklower 				ENDDEBUG
76336401Ssklower 				goto discard;
76436401Ssklower 			}
76536401Ssklower 			tpcb = sototpcb(so);
76644601Ssklower 			insque(tpcb, parent_tpcb);
76736401Ssklower 
76836401Ssklower 			/*
76937469Ssklower 			 * Stash the addresses in the net level pcb
77036401Ssklower 			 * kind of like a pcbconnect() but don't need
77136401Ssklower 			 * or want all those checks.
77236401Ssklower 			 */
77336401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
77436401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
77536401Ssklower 
77637469Ssklower 			/* stash the f suffix in the new tpcb */
77738841Ssklower 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
77844422Ssklower 			/* l suffix is already there, unless this is an intercept case */
77944422Ssklower 			if (intercepted)
78044422Ssklower 				bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
78137469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
78237469Ssklower 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
78338841Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
78438841Ssklower 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
78536401Ssklower #ifdef TP_PERF_MEAS
78636401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
78736401Ssklower 				/* ok, let's create an mbuf for stashing the
78836401Ssklower 				 * statistics if one doesn't already exist
78936401Ssklower 				 */
79036401Ssklower 				(void) tp_setup_perf(tpcb);
79136401Ssklower 			}
79236401Ssklower #endif TP_PERF_MEAS
79336401Ssklower 			tpcb->tp_fref = sref;
79436401Ssklower 
79536401Ssklower 			/* We've already checked for consistency with the options
79636401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
79736401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
79836401Ssklower 			 * Now we set the options in the new socket's tpcb.
79936401Ssklower 			 */
80036401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
80136401Ssklower 
80236401Ssklower 			if(!tpcb->tp_use_checksum)
80336401Ssklower 				IncStat(ts_csum_off);
80436401Ssklower 			if(tpcb->tp_xpd_service)
80536401Ssklower 				IncStat(ts_use_txpd);
80636401Ssklower 			if(tpcb->tp_xtd_format)
80736401Ssklower 				IncStat(ts_xtd_fmt);
80836401Ssklower 
80936401Ssklower 			/*
81036401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
81136401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
81236401Ssklower 			 */
81336401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
81436401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
81536401Ssklower 			tpcb->tp_peer_acktime = acktime;
81636401Ssklower 
81736401Ssklower 			/*
81836401Ssklower 			 * The following kludge is used to test retransmissions and
81936401Ssklower 			 * timeout during connection establishment.
82036401Ssklower 			 */
82136401Ssklower 			IFDEBUG(D_ZDREF)
82236401Ssklower 				IncStat(ts_zdebug);
82337469Ssklower 				/*tpcb->tp_fref = 0;*/
82436401Ssklower 			ENDDEBUG
82536401Ssklower 		}
82636401Ssklower 		IncStat(ts_CR_rcvd);
82739929Ssklower 		if (!tpcb->tp_cebit_off) {
82839929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
82939929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
83039929Ssklower 			LOCAL_CREDIT(tpcb);
83139929Ssklower 			CONG_INIT_SAMPLE(tpcb);
83239929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
83339929Ssklower 		}
83439929Ssklower 		tpcb->tp_ackrcvd = 0;
83536401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
83636401Ssklower 		/*
83736401Ssklower 		 * ER TPDUs have to be recognized separately
83836401Ssklower 		 * because they don't necessarily have a tpcb
83936401Ssklower 		 * with them and we don't want err out looking for such
84036401Ssklower 		 * a beast.
84136401Ssklower 		 * We could put a bunch of little kludges in the
84236401Ssklower 		 * next section of code so it would avoid references to tpcb
84336401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
84436401Ssklower 		 * mess up code for data transfer.
84536401Ssklower 		 */
84636401Ssklower 		IncStat(ts_ER_rcvd);
84736401Ssklower 		e.ev_number = ER_TPDU;
84836401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
849*48749Ssklower 		takes_data = FALSE;
85036401Ssklower 	} else {
85136401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
85236401Ssklower 
85336401Ssklower 		/* In the next 4 checks,
85436401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
85536401Ssklower 		 * the fixed part (can't take the address of a bit field)
85636401Ssklower 		 */
85745900Ssklower #ifdef old_history
85836401Ssklower 		if(cons_channel) {
85945900Ssklower #ifdef NARGOXTWENTYFIVE
86036401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
86136401Ssklower 
86236401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
86336401Ssklower 			/* Problem:  We may have a legit
86436401Ssklower 			 * error situation yet we may or may not have
86536401Ssklower 			 * a correspondence between the tpcb and the vc,
86636401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
86736401Ssklower 			 *          <---  DR
86836401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
86936401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
87036401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
87136401Ssklower 			 * Sigh.
87236401Ssklower 			 */
87336401Ssklower 
87436401Ssklower 			/* I don't know about this error value */
87536401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
87636401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
87736401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
87836401Ssklower #else
87936401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
88045900Ssklower #endif
88145900Ssklower 		} else
88245900Ssklower 			/* we've now made the error reporting thing check for
88345900Ssklower 			multiple channels and not close out if more than
88445900Ssklower 			one in use */
88545900Ssklower #endif old_history
88645900Ssklower 		{
88736401Ssklower 
88836401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
88942944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89136401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
89242944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89336401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89436401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
89542944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89636401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89736401Ssklower 		}
89836401Ssklower 
89936401Ssklower 		IFDEBUG(D_TPINPUT)
90036401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
90136401Ssklower 		ENDDEBUG
90236401Ssklower 
90336401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
90436401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
90536401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
90636401Ssklower 			ts_inv_dref, respond,
90736401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
90836401Ssklower 
90936401Ssklower 		IFDEBUG(D_TPINPUT)
91036401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
91136401Ssklower 		ENDDEBUG
91236401Ssklower 		/*
91336401Ssklower 		 * At this point the state of the dref could be
91436401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
91536401Ssklower 		 *		   for example, DC may arrive after the close() has detached
91636401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
91736401Ssklower 		 * OPENING : a tpcb exists but no timers yet
91836401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
91936401Ssklower 		 */
92036401Ssklower 
92139929Ssklower         if (!tpcb->tp_cebit_off)
92239929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
92339929Ssklower 
92436401Ssklower 		dusize = tpcb->tp_tpdusize;
92536401Ssklower 
92636401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
92736401Ssklower 
92836401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
92936401Ssklower 
93037469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
93136401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
93236401Ssklower 
93336401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
93436401Ssklower 					/* not in class 0; 1 octet */
93536401Ssklower 					vb_getval(P, u_char, addlopt);
93636401Ssklower 					break;
93736401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
93842944Ssklower 				{
93942944Ssklower 					u_char odusize = dusize;
94036401Ssklower 					vb_getval(P, u_char, dusize);
94142944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
94242944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
94342944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
94442944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
94536401Ssklower 					IFDEBUG(D_TPINPUT)
94636401Ssklower 						printf("CC dusize 0x%x\n", dusize);
94736401Ssklower 					ENDDEBUG
94842944Ssklower 				}
94936401Ssklower 					break;
95036401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
95136401Ssklower 					IFDEBUG(D_TPINPUT)
95236401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
95336401Ssklower 					ENDDEBUG
95436401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
95536401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
95636401Ssklower 					break;
95736401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
95836401Ssklower 					/* class 4 only, 2 octets */
95936401Ssklower 					vb_getval(P, u_short, acktime);
96044947Ssklower 					acktime = ntohs(acktime);
96136401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
96236401Ssklower 					if( (short)acktime <=0 )
96336401Ssklower 						acktime = 2;
96436401Ssklower 					break;
96536401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
96636401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
96736401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
96836401Ssklower 					IFDEBUG(D_TPINPUT)
96936401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
97036401Ssklower 					ENDDEBUG
97136401Ssklower 					break;
97236401Ssklower 
97336401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
97436401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
97536401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
97636401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
97736401Ssklower 					if( tpcb->tp_use_checksum )  {
97836401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
97936401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
98036401Ssklower 					}
98136401Ssklower 					break;
98236401Ssklower 
98336401Ssklower 			/*  this is different from the above because in the context
98436401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
98536401Ssklower 			 */
98636401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
98736401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
98836401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
98936401Ssklower 					if( tpcb->tp_use_checksum )  {
99037469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
99136401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
99236401Ssklower 					}
99336401Ssklower 					break;
99436401Ssklower #ifdef notdef
99536401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
99636401Ssklower 				/* ignore - its length and meaning are
99736401Ssklower 				 * user defined and there's no way
99836401Ssklower 				 * to pass this info to the user anyway
99936401Ssklower 				 */
100036401Ssklower 				break;
100136401Ssklower #endif notdef
100236401Ssklower 
100336401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
100436401Ssklower 				/* used after reduction of window */
100536401Ssklower 				vb_getval(P, u_short, subseq);
100636401Ssklower 				subseq = ntohs(subseq);
100736401Ssklower 				IFDEBUG(D_ACKRECV)
100836401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
100936401Ssklower 				ENDDEBUG
101036401Ssklower 				break;
101136401Ssklower 
101236401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
101336401Ssklower 				{
101436401Ssklower 					u_int 	ylwe;
101536401Ssklower 					u_short ysubseq, ycredit;
101636401Ssklower 
101736401Ssklower 					fcc_present = TRUE;
101836401Ssklower 					vb_getval(P, u_int,	 	ylwe);
101936401Ssklower 					vb_getval(P, u_short, 	ysubseq);
102036401Ssklower 					vb_getval(P, u_short, 	ycredit);
102136401Ssklower 					ylwe = ntohl(ylwe);
102236401Ssklower 					ysubseq = ntohs(ysubseq);
102336401Ssklower 					ycredit = ntohs(ycredit);
102436401Ssklower 					IFDEBUG(D_ACKRECV)
102536401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
102636401Ssklower 							ylwe, ysubseq, ycredit);
102736401Ssklower 					ENDDEBUG
102836401Ssklower 				}
102936401Ssklower 				break;
103036401Ssklower 
103136401Ssklower 			default:
103236401Ssklower 				IFDEBUG(D_TPINPUT)
103336401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
103436401Ssklower 						dutype, vbptr(P)->tpv_code);
103536401Ssklower 				ENDDEBUG
103636401Ssklower 				IFTRACE(D_TPINPUT)
103736401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
103836401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
103936401Ssklower 				ENDTRACE
104036401Ssklower 				IncStat(ts_param_ignored);
104136401Ssklower 				break;
104236401Ssklower #undef caseof
104336401Ssklower 		}
104436401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
104536401Ssklower 
104636401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
104736401Ssklower 
104836401Ssklower 		switch( hdr->tpdu_type ) {
104936401Ssklower 		case CC_TPDU_type:
105036401Ssklower 			/* If CC comes back with an unacceptable class
105136401Ssklower 			 * respond with a DR or ER
105236401Ssklower 			 */
105336401Ssklower 
105436401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
105536401Ssklower 
105636401Ssklower 			{
105736401Ssklower 				tpp = tpcb->_tp_param;
105836401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
105936401Ssklower 				tpp.p_tpdusize = dusize;
106036401Ssklower 				tpp.p_dont_change_params = 0;
106136401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
106236401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
106336401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
106436401Ssklower #ifdef notdef
106536401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
106636401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
106736401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
106836401Ssklower #endif notdef
106936401Ssklower 
107036401Ssklower 			CHECK(
107136401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
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 			IFTRACE(D_CONN)
107736401Ssklower 				tptrace(TPPTmisc,
107836401Ssklower 					"after 1 consist class, out, tpconsout",
107936401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
108036401Ssklower 					);
108136401Ssklower 			ENDTRACE
108236401Ssklower 			CHECK(
108336401Ssklower 				((class_to_use == TP_CLASS_0)&&
108436401Ssklower 					(dgout_routine != tpcons_output)),
108536401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
108636401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
108736401Ssklower 					/* ^ more or less the location of class */
108836401Ssklower 				)
108945900Ssklower #ifdef TPCONS
109045900Ssklower 				if (tpcb->tp_netservice == ISO_CONS &&
109145900Ssklower 					class_to_use == TP_CLASS_0) {
109245900Ssklower 					struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
109345900Ssklower 					struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
109445900Ssklower 					lcp->lcd_flags &= ~X25_DG_CIRCUIT;
109545900Ssklower 				}
109645900Ssklower #endif
109736401Ssklower 			}
109836401Ssklower 			if( ! tpcb->tp_use_checksum)
109936401Ssklower 				IncStat(ts_csum_off);
110036401Ssklower 			if(tpcb->tp_xpd_service)
110136401Ssklower 				IncStat(ts_use_txpd);
110236401Ssklower 			if(tpcb->tp_xtd_format)
110336401Ssklower 				IncStat(ts_xtd_fmt);
110436401Ssklower 
110536401Ssklower 			IFTRACE(D_CONN)
110636401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
110736401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
110836401Ssklower 					hdr->tpdu_CCclass);
110936401Ssklower 			ENDTRACE
111036401Ssklower 
111136401Ssklower 			/*
111236401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
111336401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
111436401Ssklower 			 * It would be nice if the arguments to this
111536401Ssklower 			 * were more reasonable.
111636401Ssklower 			 */
111736401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
111836401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
111936401Ssklower 
112036401Ssklower 
112136401Ssklower 			/* if called or calling suffices appeared on the CC,
112236401Ssklower 			 * they'd better jive with what's in the pcb
112336401Ssklower 			 */
112436401Ssklower 			if( fsufxlen ) {
112536401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
112636401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
112736401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
112836401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
112936401Ssklower 			}
113036401Ssklower 			if( lsufxlen ) {
113136401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
113236401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
113336401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
113436401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
113536401Ssklower 			}
113636401Ssklower 
113736401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
113836401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
113936401Ssklower 			takes_data = TRUE;
114036401Ssklower 			e.ev_number = CC_TPDU;
114136401Ssklower 			IncStat(ts_CC_rcvd);
114236401Ssklower 			break;
114336401Ssklower 
114436401Ssklower 		case DC_TPDU_type:
114536401Ssklower 			if (sref != tpcb->tp_fref)
114636401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
114736401Ssklower 					sref, tpcb->tp_fref);
114836401Ssklower 
114936401Ssklower 			CHECK( (sref != tpcb->tp_fref),
115042944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
115136401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
115242944Ssklower 
115336401Ssklower 			e.ev_number = DC_TPDU;
115436401Ssklower 			IncStat(ts_DC_rcvd);
115536401Ssklower 			break;
115636401Ssklower 
115736401Ssklower 		case DR_TPDU_type:
115836401Ssklower 			IFTRACE(D_TPINPUT)
115936401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
116036401Ssklower 			ENDTRACE
116142944Ssklower 			if (sref != tpcb->tp_fref) {
116236401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
116336401Ssklower 					sref, tpcb->tp_fref);
116442944Ssklower 			}
116536401Ssklower 
116642944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
116742944Ssklower 					tpcb->tp_state != TP_CRSENT),
116842944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
116936401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
117036401Ssklower 
117136401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
117236401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
117336401Ssklower 			takes_data = TRUE;
117436401Ssklower 			e.ev_number = DR_TPDU;
117536401Ssklower 			IncStat(ts_DR_rcvd);
117636401Ssklower 			break;
117736401Ssklower 
117836401Ssklower 		case ER_TPDU_type:
117936401Ssklower 			IFTRACE(D_TPINPUT)
118036401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
118136401Ssklower 			ENDTRACE
118236401Ssklower 			e.ev_number = ER_TPDU;
118336401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
118436401Ssklower 			IncStat(ts_ER_rcvd);
118536401Ssklower 			break;
118636401Ssklower 
118736401Ssklower 		case AK_TPDU_type:
118836401Ssklower 
118936401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
119036401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
119136401Ssklower 
119236401Ssklower 			if (tpcb->tp_xtd_format) {
119336401Ssklower #ifdef BYTE_ORDER
119436401Ssklower 				union seq_type seqeotX;
119536401Ssklower 
119636401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
119736401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
119836401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
119936401Ssklower #else
120036401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
120136401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
120236401Ssklower #endif BYTE_ORDER
120336401Ssklower 			} else {
120436401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
120536401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
120636401Ssklower 			}
120736401Ssklower 			IFTRACE(D_TPINPUT)
120836401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
120936401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
121036401Ssklower 					subseq, fcc_present);
121136401Ssklower 			ENDTRACE
121236401Ssklower 
121336401Ssklower 			e.ev_number = AK_TPDU;
121436401Ssklower 			IncStat(ts_AK_rcvd);
121536401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
121636401Ssklower 			break;
121736401Ssklower 
121836401Ssklower 		case XAK_TPDU_type:
121936401Ssklower 			if (tpcb->tp_xtd_format) {
122036401Ssklower #ifdef BYTE_ORDER
122136401Ssklower 				union seq_type seqeotX;
122236401Ssklower 
122336401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
122436401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
122536401Ssklower #else
122636401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
122736401Ssklower #endif BYTE_ORDER
122836401Ssklower 			} else {
122936401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
123036401Ssklower 			}
123136401Ssklower 			e.ev_number = XAK_TPDU;
123236401Ssklower 			IncStat(ts_XAK_rcvd);
123336401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
123436401Ssklower 			break;
123536401Ssklower 
123636401Ssklower 		case XPD_TPDU_type:
123736401Ssklower 			if (tpcb->tp_xtd_format) {
123836401Ssklower #ifdef BYTE_ORDER
123936401Ssklower 				union seq_type seqeotX;
124036401Ssklower 
124136401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
124236401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
124336401Ssklower #else
124436401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
124536401Ssklower #endif BYTE_ORDER
124636401Ssklower 			} else {
124736401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
124836401Ssklower 			}
124936401Ssklower 			takes_data = TRUE;
125036401Ssklower 			e.ev_number = XPD_TPDU;
125136401Ssklower 			IncStat(ts_XPD_rcvd);
125236401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
125336401Ssklower 			break;
125436401Ssklower 
125536401Ssklower 		case DT_TPDU_type:
125636401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
125736401Ssklower 			   * A little crude but it works.
125836401Ssklower 			   */
125936401Ssklower 
126036401Ssklower 				IFDEBUG(D_DROP)
126136401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
126236401Ssklower 						IncStat(ts_ydebug);
126336401Ssklower 						goto discard;
126436401Ssklower 					}
126536401Ssklower 				ENDDEBUG
126636401Ssklower 			}
126736401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
126836401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
126936401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
127036401Ssklower 			} else if (tpcb->tp_xtd_format) {
127136401Ssklower #ifdef BYTE_ORDER
127236401Ssklower 				union seq_type seqeotX;
127336401Ssklower 
127436401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
127536401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
127636401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
127736401Ssklower #else
127836401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
127936401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
128036401Ssklower #endif BYTE_ORDER
128136401Ssklower 			} else {
128236401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
128336401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
128436401Ssklower 			}
128536401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
128636401Ssklower 				IncStat(ts_eot_input);
128736401Ssklower 			takes_data = TRUE;
128836401Ssklower 			e.ev_number = DT_TPDU;
128936401Ssklower 			IncStat(ts_DT_rcvd);
129036401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
129136401Ssklower 			break;
129236401Ssklower 
129336401Ssklower 		case GR_TPDU_type:
129436401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
129536401Ssklower 			/* drop through */
129636401Ssklower 		default:
129736401Ssklower 			/* this should NEVER happen because there is a
129836401Ssklower 			 * check for dutype well above here
129936401Ssklower 			 */
130036401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
130136401Ssklower 			IFDEBUG(D_TPINPUT)
130236401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
130336401Ssklower 			ENDDEBUG
130436401Ssklower 			IncStat(ts_inv_dutype);
130536401Ssklower 			goto respond;
130636401Ssklower 		}
130736401Ssklower 	}
130836401Ssklower 	/* peel off the tp header;
130936401Ssklower 	 * remember that the du_li doesn't count itself.
131036401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
131136401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
131236401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
131336401Ssklower 	 */
131436401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
131537469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
131636401Ssklower 
131737469Ssklower 	if (takes_data) {
131837469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
131937469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
1320*48749Ssklower 		struct {
1321*48749Ssklower 			struct tp_disc_reason dr;
1322*48749Ssklower 			struct cmsghdr x_hdr;
1323*48749Ssklower 		} x;
1324*48749Ssklower #define c_hdr x.x_hdr
1325*48749Ssklower 		register struct mbuf *n;
132636401Ssklower 
132737469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
132837469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
132936401Ssklower 		switch( hdr->tpdu_type ) {
133037469Ssklower 
133136401Ssklower 		case CR_TPDU_type:
133237469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
133337469Ssklower 			goto make_control_msg;
133437469Ssklower 
133536401Ssklower 		case CC_TPDU_type:
133637469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
133737469Ssklower 			goto make_control_msg;
133837469Ssklower 
133936401Ssklower 		case DR_TPDU_type:
1340*48749Ssklower 			x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
1341*48749Ssklower 			x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
1342*48749Ssklower 			x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
1343*48749Ssklower 			x.dr.dr_reason = hdr->tpdu_DRreason;
134437469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
134537469Ssklower 		make_control_msg:
1346*48749Ssklower 			datalen += sizeof(c_hdr);
1347*48749Ssklower 			c_hdr.cmsg_len = datalen;
134837469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
134937469Ssklower 			mbtype = MT_CONTROL;
135043334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
1351*48749Ssklower 			if (n == 0)
1352*48749Ssklower 				{m_freem(m); m = 0; datalen = 0; goto invoke; }
1353*48749Ssklower 			if (hdr->tpdu_type == DR_TPDU_type) {
1354*48749Ssklower 				datalen += sizeof(x) - sizeof(c_hdr);
1355*48749Ssklower 				bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
1356*48749Ssklower 			} else
1357*48749Ssklower 				bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
1358*48749Ssklower 					  n->m_len = sizeof(c_hdr));
1359*48749Ssklower 			n->m_next = m;
1360*48749Ssklower 			m = n;
136137469Ssklower 			/* FALLTHROUGH */
136237469Ssklower 
136336401Ssklower 		case XPD_TPDU_type:
136437469Ssklower 			if (mbtype != MT_CONTROL)
136537469Ssklower 				mbtype = MT_OOBDATA;
136637469Ssklower 			m->m_flags |= M_EOR;
136737469Ssklower 			/* FALLTHROUGH */
136837469Ssklower 
136936401Ssklower 		case DT_TPDU_type:
137037469Ssklower 			for (n = m; n; n = n->m_next) {
137137469Ssklower 				MCHTYPE(n, mbtype);
137237469Ssklower 			}
137343334Ssklower 		invoke:
137437469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
137536401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
137636401Ssklower 			break;
137736401Ssklower 
137836401Ssklower 		default:
137936401Ssklower 			printf(
138036401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
138136401Ssklower 				hdr->tpdu_type, takes_data, m);
138236401Ssklower 			break;
138336401Ssklower 		}
138436401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
138536401Ssklower 		m = MNULL;
138636401Ssklower 	}
138736401Ssklower 
138836401Ssklower 	IncStat(ts_tpdu_rcvd);
138936401Ssklower 
139036401Ssklower 	IFDEBUG(D_TPINPUT)
139136401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
139236401Ssklower 			tpcb->tp_state, e.ev_number, m );
139336401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
139436401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
139536401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
139636401Ssklower 	ENDDEBUG
139736401Ssklower 
139836401Ssklower 	error = tp_driver(tpcb, &e);
139936401Ssklower 
140036401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
140136401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
140236401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
140336401Ssklower 		tpcb->tp_sock->so_error = error;
140436401Ssklower 
140536401Ssklower 	/* Kludge to keep the state tables under control (adding
140636401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
140736401Ssklower 	 * the data would have exploded the tables and made a big mess ).
140836401Ssklower 	 */
140936401Ssklower 	switch(e.ev_number) {
141036401Ssklower 		case CC_TPDU:
141136401Ssklower 		case DR_TPDU:
141236401Ssklower 		case CR_TPDU:
141336401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
141436401Ssklower 			IFDEBUG(D_TPINPUT)
141536401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
141636401Ssklower 				m, takes_data);
141736401Ssklower 			ENDDEBUG
141836401Ssklower 			break;
141936401Ssklower 		default:
142036401Ssklower 			break;
142136401Ssklower 	}
142236401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
142336401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
142436401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
142536401Ssklower 	 */
142636401Ssklower 
142736401Ssklower separate:
142836401Ssklower 	if ( takes_data == 0 )  {
142936401Ssklower 		ASSERT( m != MNULL );
143036401Ssklower 		/*
143136401Ssklower 		 * we already peeled off the prev. tp header so
143236401Ssklower 		 * we can just pull up some more and repeat
143336401Ssklower 		 */
143436401Ssklower 
143537469Ssklower 		if( m = tp_inputprep(m) ) {
143636401Ssklower 		IFDEBUG(D_TPINPUT)
143736401Ssklower 			hdr = mtod(m, struct tpdu *);
143836401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
143936401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
144036401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
144136401Ssklower 		ENDDEBUG
144236401Ssklower 
144336401Ssklower 			IncStat(ts_concat_rcvd);
144436401Ssklower 			goto again;
144536401Ssklower 		}
144636401Ssklower 	}
144736401Ssklower 	if ( m != MNULL ) {
144836401Ssklower 		IFDEBUG(D_TPINPUT)
144936401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
145036401Ssklower 		ENDDEBUG
145136401Ssklower 		m_freem(m);
145236401Ssklower 		IFDEBUG(D_TPINPUT)
145336401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
145436401Ssklower 		ENDDEBUG
145536401Ssklower 	}
145636401Ssklower 	return (ProtoHook) tpcb;
145736401Ssklower 
145836401Ssklower discard:
145936401Ssklower 	/* class 4: drop the tpdu */
146036401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
146136401Ssklower 	 * to which connection it applies
146236401Ssklower 	 */
146336401Ssklower 	IFDEBUG(D_TPINPUT)
146436401Ssklower 		printf("tp_input DISCARD\n");
146536401Ssklower 	ENDDEBUG
146636401Ssklower 	IFTRACE(D_TPINPUT)
146736401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
146836401Ssklower 	ENDTRACE
146936401Ssklower 	m_freem(m);
147036401Ssklower 	IncStat(ts_recv_drop);
147136401Ssklower 	return (ProtoHook)0;
147236401Ssklower 
147342944Ssklower nonx_dref:
147442944Ssklower 	switch (dutype) {
147542944Ssklower 	default:
147642944Ssklower 		goto discard;
147742944Ssklower 	case CC_TPDU_type:
147842944Ssklower 		/* error = E_TP_MISM_REFS; */
147942944Ssklower 		break;
148042944Ssklower 	case DR_TPDU_type:
148142944Ssklower 		error |= TP_ERROR_SNDC;
148242944Ssklower 	}
148336401Ssklower respond:
148443334Ssklower 	IFDEBUG(D_TPINPUT)
148542944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
148636401Ssklower 	ENDDEBUG
148736401Ssklower 	IFTRACE(D_TPINPUT)
148842944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
148936401Ssklower 	ENDTRACE
149042944Ssklower 	if (sref == 0)
149136401Ssklower 		goto discard;
149237469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
149342944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
149437469Ssklower 				(int)cons_channel, dgout_routine);
149536401Ssklower 	IFDEBUG(D_ERROR_EMIT)
149636401Ssklower 		printf("tp_input after error_emit\n");
149736401Ssklower 	ENDDEBUG
149836401Ssklower 
149936401Ssklower #ifdef lint
150036401Ssklower 	printf("",sref,opt);
150136401Ssklower #endif lint
150236401Ssklower 	IncStat(ts_recv_drop);
150336401Ssklower 	return (ProtoHook)0;
150436401Ssklower }
150536401Ssklower 
150636401Ssklower 
150736401Ssklower /*
150836401Ssklower  * NAME: tp_headersize()
150936401Ssklower  *
151036401Ssklower  * CALLED FROM:
151136401Ssklower  *  tp_emit() and tp_sbsend()
151236401Ssklower  *  TP needs to know the header size so it can figure out how
151336401Ssklower  *  much data to put in each tpdu.
151436401Ssklower  *
151536401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
151636401Ssklower  *  For a given connection, represented by (tpcb), and
151736401Ssklower  *  tpdu type (dutype), return the size of a tp header.
151836401Ssklower  *
151936401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
152036401Ssklower  *
152136401Ssklower  * SIDE EFFECTS:
152236401Ssklower  *
152336401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
152436401Ssklower  */
152536401Ssklower int
152636401Ssklower tp_headersize(dutype, tpcb)
152736401Ssklower 	int 			dutype;
152836401Ssklower 	struct tp_pcb 	*tpcb;
152936401Ssklower {
153036401Ssklower 	register int size = 0;
153136401Ssklower 
153236401Ssklower 	IFTRACE(D_CONN)
153336401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
153436401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
153536401Ssklower 	ENDTRACE
153636401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
153736401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
153836401Ssklower 			(dutype == DR_TPDU_type) ||
153936401Ssklower 			(dutype == CR_TPDU_type) )) {
154036401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
154136401Ssklower 			dutype, tpcb->tp_class);
154236401Ssklower 	/* TODO: identify this and GET RID OF IT */
154336401Ssklower 	}
154436401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
154536401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
154636401Ssklower 			(dutype == DR_TPDU_type) ||
154736401Ssklower 			(dutype == CR_TPDU_type) );
154836401Ssklower 
154936401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
155036401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
155136401Ssklower 	} else  {
155236401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
155336401Ssklower 	}
155436401Ssklower 	return size;
155536401Ssklower 	/* caller must get network level header size separately */
155636401Ssklower }
1557