xref: /csrg-svn/sys/netiso/tp_input.c (revision 42468)
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*42468Ssklower  *	@(#)tp_input.c	7.8 (Berkeley) 05/30/90 *
3336401Ssklower  *
3436401Ssklower  * tp_input() gets an mbuf chain from ip.  Actually, not directly
3536401Ssklower  * from ip, because ip calls a net-level routine that strips off
3636401Ssklower  * the net header and then calls tp_input(), passing the proper type
3736401Ssklower  * of addresses for the address family in use (how it figures out
3836401Ssklower  * which AF is not yet determined.
3936401Ssklower  *
4036401Ssklower  * Decomposing the tpdu is some of the most laughable code.  The variable-length
4136401Ssklower  * parameters and the problem of non-aligned memory references
4236401Ssklower  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
4336401Ssklower  * to loop through the header and decompose it.
4436401Ssklower  *
4536401Ssklower  * The routine tp_newsocket() is called when a CR comes in for a listening
4636401Ssklower  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
4736401Ssklower  * "child" socket.  Most tpcb values are copied from the parent tpcb into
4836401Ssklower  * the child.
4936401Ssklower  *
5036401Ssklower  * Also in here is tp_headersize() (grot) which tells the expected size
5136401Ssklower  * of a tp header, to be used by other layers.  It's in here because it
5236401Ssklower  * uses the static structure tpdu_info.
5336401Ssklower  */
5436401Ssklower 
5536401Ssklower #ifndef lint
5636401Ssklower static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $";
5736401Ssklower #endif lint
5836401Ssklower 
5936401Ssklower #include "argoxtwentyfive.h"
6036401Ssklower #include "param.h"
6136401Ssklower #include "mbuf.h"
6236401Ssklower #include "socket.h"
6336401Ssklower #include "socketvar.h"
6436401Ssklower #include "domain.h"
6536401Ssklower #include "protosw.h"
6636401Ssklower #include "errno.h"
6736401Ssklower #include "time.h"
6836401Ssklower #include "kernel.h"
6936401Ssklower #include "types.h"
7037469Ssklower #include "iso_errno.h"
7137469Ssklower #include "tp_param.h"
7237469Ssklower #include "tp_timer.h"
7337469Ssklower #include "tp_stat.h"
7437469Ssklower #include "tp_pcb.h"
7537469Ssklower #include "argo_debug.h"
7637469Ssklower #include "tp_trace.h"
7737469Ssklower #include "tp_tpdu.h"
7837469Ssklower #include "iso.h"
7937469Ssklower #include "cons.h"
8036401Ssklower 
8136401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
8236401Ssklower 
8337469Ssklower /*
8437469Ssklower 	#ifdef lint
8537469Ssklower 	#undef ATTR
8637469Ssklower 	#define ATTR(X)ev_number
8737469Ssklower 	#endif lint
8837469Ssklower */
8936401Ssklower 
9036401Ssklower struct mbuf *
9136401Ssklower tp_inputprep(m)
9237469Ssklower 	register struct mbuf *m;
9336401Ssklower {
9437469Ssklower 	int hdrlen;
9536401Ssklower 
9636401Ssklower 	IFDEBUG(D_TPINPUT)
9737469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
9836401Ssklower 	ENDDEBUG
9936401Ssklower 
10036401Ssklower 	while(  m->m_len < 1 ) {
10136401Ssklower 		if( (m = m_free(m)) == MNULL ) {
10236401Ssklower 			return (struct mbuf *)0;
10336401Ssklower 		}
10436401Ssklower 	}
10537469Ssklower 	if(((int)m->m_data) & 0x3) {
10637469Ssklower 		/* If we are not 4-byte aligned, we have to be
10737469Ssklower 		 * above the beginning of the mbuf, and it is ok just
10837469Ssklower 		 * to slide it back.
10937469Ssklower 		 */
11037469Ssklower 		caddr_t ocp = m->m_data;
11136401Ssklower 
11237469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
11337469Ssklower 		ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
11436401Ssklower 	}
11536401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
11636401Ssklower 
11737469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
11837469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
11936401Ssklower 
12037469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
12136401Ssklower 
12236401Ssklower 	/*
12336401Ssklower 	 * now pull up the whole tp header
12436401Ssklower 	 */
12537469Ssklower 	if ( m->m_len < hdrlen) {
12637469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
12736401Ssklower 			IncStat(ts_recv_drop);
12836401Ssklower 			return (struct mbuf *)0;
12936401Ssklower 		}
13036401Ssklower 	}
13136401Ssklower 	IFDEBUG(D_INPUT)
13236401Ssklower 	printf(
13336401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
13437469Ssklower 		hdrlen, m->m_len);
13536401Ssklower 	ENDDEBUG
13636401Ssklower 	return m;
13736401Ssklower }
13836401Ssklower 
13936401Ssklower /* begin groan
14036401Ssklower  * -- this array and the following macros allow you to step through the
14136401Ssklower  * parameters of the variable part of a header
14236401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
14336401Ssklower  * should change, this array has to be rearranged
14436401Ssklower  */
14536401Ssklower 
14636401Ssklower #define TP_LEN_CLASS_0_INDEX	2
14736401Ssklower #define TP_MAX_DATA_INDEX 3
14836401Ssklower 
14936401Ssklower static u_char tpdu_info[][4] =
15036401Ssklower {
15136401Ssklower /*								length						 max data len */
15236401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
15336401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
15436401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
15536401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
15636401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
15736401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
15836401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
15936401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
16036401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
16136401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
16236401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
16336401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
16436401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
16536401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
16636401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
16736401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
16836401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
16936401Ssklower };
17036401Ssklower 
17136401Ssklower /*
17236401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
17336401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
17436401Ssklower  */
17536401Ssklower 
17636401Ssklower #define WHILE_OPTIONS(P, hdr,format)\
17736401Ssklower {	register  caddr_t		P;\
17836401Ssklower 	P = (caddr_t)(hdr) +\
17936401Ssklower 	tpdu_info[(hdr)->tpdu_type][(format)];\
18036401Ssklower 	while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) {
18136401Ssklower 
18236401Ssklower #define END_WHILE_OPTIONS(P)\
18336401Ssklower 	P = P  + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\
18436401Ssklower } }
18536401Ssklower 
18636401Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
18736401Ssklower 	if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \
18836401Ssklower 	goto Whattodo; }
18936401Ssklower 
19036401Ssklower /* end groan */
19136401Ssklower 
19236401Ssklower /*
19336401Ssklower  * NAME:  tp_newsocket()
19436401Ssklower  *
19536401Ssklower  * CALLED FROM:
19636401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
19736401Ssklower  * is awaiting a  connection request
19836401Ssklower  *
19936401Ssklower  * FUNCTION and ARGUMENTS:
20036401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
20136401Ssklower  *  using a copy of the net level pcb for the parent socket.
20236401Ssklower  *  (so) is the parent socket.
20336401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
20436401Ssklower  *
20536401Ssklower  * RETURN VALUE:
20636401Ssklower  *  a new socket structure, being this end of the newly formed connection.
20736401Ssklower  *
20836401Ssklower  * SIDE EFFECTS:
20936401Ssklower  *  Sets a few things in the tpcb and net level pcb
21036401Ssklower  *
21136401Ssklower  * NOTES:
21236401Ssklower  */
21336401Ssklower static struct socket *
21436401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
21536401Ssklower 	struct socket				*so;
21636401Ssklower 	struct sockaddr				*fname;
21736401Ssklower 	u_int						cons_channel;
21836401Ssklower 	u_char						class_to_use;
21936401Ssklower 	u_int						netservice;
22036401Ssklower {
22136401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
22236401Ssklower 	struct tp_pcb *			 newtpcb;
22336401Ssklower 
22436401Ssklower 	/*
22536401Ssklower 	 * sonewconn() gets a new socket structure,
22636401Ssklower 	 * a new lower layer pcb and a new tpcb,
22736401Ssklower 	 * but the pcbs are unnamed (not bound)
22836401Ssklower 	 */
22936401Ssklower 	IFTRACE(D_NEWSOCK)
23038841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
23139196Ssklower 			so, tpcb, so->so_head, 0);
23236401Ssklower 	ENDTRACE
23336401Ssklower 
23440636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
23536401Ssklower 		return so;
23636401Ssklower 	IFTRACE(D_NEWSOCK)
23738841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
23838841Ssklower 			so, so->so_head, 0, 0);
23936401Ssklower 	ENDTRACE
24036401Ssklower 
24136401Ssklower 	IFDEBUG(D_NEWSOCK)
24237469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
24337469Ssklower 				cons_channel, so);
24437469Ssklower 		dump_addr(fname);
24536401Ssklower 		{
24636401Ssklower 			struct socket *t, *head ;
24736401Ssklower 
24836401Ssklower 			head = so->so_head;
24936401Ssklower 			t = so;
25036401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
25136401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
25236401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
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 		}
25636401Ssklower 	ENDDEBUG
25736401Ssklower 
25836401Ssklower 	/*
25936401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
26036401Ssklower 	 */
26136401Ssklower 	newtpcb = sototpcb(so);
26236401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
26336401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
26436401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
26536401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
26636401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
26736401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
26837469Ssklower 	soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
26936401Ssklower 
27037469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
27136401Ssklower 		/*
27237469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
27336401Ssklower 		 */
27436401Ssklower 		struct mbuf *conndata;
27536401Ssklower 
27637469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
27736401Ssklower 		IFDEBUG(D_CONN)
27836401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
27936401Ssklower 		ENDDEBUG
28037469Ssklower 		newtpcb->tp_ucddata = conndata;
28136401Ssklower 	}
28236401Ssklower 
28336401Ssklower 	tpcb = newtpcb;
28436401Ssklower 	tpcb->tp_state = TP_LISTENING;
28536401Ssklower 	tpcb->tp_class = class_to_use;
28636401Ssklower 	tpcb->tp_netservice = netservice;
28736401Ssklower 
28836401Ssklower 
28936401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
29036401Ssklower 	if ( fname ) {
29136401Ssklower 		/*
29236401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
29336401Ssklower 		 */
29436401Ssklower 		struct mbuf	*m;
29536401Ssklower 		int			err;
29636401Ssklower 
29736401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
29836401Ssklower 		if (m) {
29936401Ssklower 			/*
30036401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
30136401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
30236401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
30336401Ssklower 			 * sigh.
30436401Ssklower 			 */
30537469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
30637469Ssklower 			m->m_len = fname->sa_len;
30736401Ssklower 
30836401Ssklower 			/* grot  : have to say the kernel can override params in
30936401Ssklower 			 * the passive open case
31036401Ssklower 			 */
31136401Ssklower 			tpcb->tp_dont_change_params = 0;
31236401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
31336401Ssklower 			m_free(m);
31436401Ssklower 
31536401Ssklower 			if (!err)
31636401Ssklower 				goto ok;
31736401Ssklower 		}
31836401Ssklower 		IFDEBUG(D_CONN)
31936401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
32036401Ssklower 				tpcb, so);
32136401Ssklower 		ENDDEBUG
32236401Ssklower 		(void) tp_detach(tpcb);
32336401Ssklower 		return 0;
32436401Ssklower 	}
32536401Ssklower ok:
32636401Ssklower 	IFDEBUG(D_TPINPUT)
32736401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
32836401Ssklower 			so, sototpcb(so));
32936401Ssklower 	ENDDEBUG
33036401Ssklower 	return so;
33136401Ssklower }
33236401Ssklower 
33336401Ssklower #ifndef CONS
33436401Ssklower tpcons_output()
33536401Ssklower {
33636401Ssklower 	return(0);
33736401Ssklower }
33836401Ssklower #endif !CONS
33936401Ssklower 
34036401Ssklower /*
34136401Ssklower  * NAME: 	tp_input()
34236401Ssklower  *
34336401Ssklower  * CALLED FROM:
34436401Ssklower  *  net layer input routine
34536401Ssklower  *
34636401Ssklower  * FUNCTION and ARGUMENTS:
34736401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
34836401Ssklower  *  is one. Create the appropriate type of event and call the driver.
34936401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
35036401Ssklower  *
35136401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
35236401Ssklower  * 	has been m_pullup-ed.
35336401Ssklower  *
35436401Ssklower  * RETURN VALUE: Nada
35536401Ssklower  *
35636401Ssklower  * SIDE EFFECTS:
35736401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
35836401Ssklower  *
35936401Ssklower  * NOTE:
36036401Ssklower  *  The initial value of acktime is 2 so that we will never
36136401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
36236401Ssklower  *  computation of the retransmission timer value, and so it
36336401Ssklower  *  mustn't be zero.
36436401Ssklower  *  2 seems like a reasonable minimum.
36536401Ssklower  */
36636401Ssklower ProtoHook
36739929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
36836401Ssklower 	register	struct mbuf 	*m;
36936401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
37036401Ssklower 	u_int 						cons_channel;
37136401Ssklower 	int 						(*dgout_routine)();
37239929Ssklower 	int							ce_bit;
37336401Ssklower 
37436401Ssklower {
37536401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
37636401Ssklower 	register struct tpdu 	*hdr = mtod(m, struct tpdu *);
37736401Ssklower 	struct socket 			*so;
37836401Ssklower 	struct tp_event 		e;
37938841Ssklower 	int 					error;
38036401Ssklower 	unsigned 				dutype;
38136401Ssklower 	u_short 				dref, sref, acktime, subseq; /*VAX*/
38238841Ssklower 	u_char 					preferred_class, class_to_use;
38336401Ssklower 	u_char					opt, dusize, addlopt;
38436401Ssklower #ifdef TP_PERF_MEAS
38538841Ssklower 	u_char					perf_meas;
38636401Ssklower #endif TP_PERF_MEAS
38736401Ssklower 	u_char					fsufxlen;
38836401Ssklower 	u_char					lsufxlen;
38938841Ssklower 	caddr_t					fsufxloc, lsufxloc;
39036401Ssklower 	int						tpdu_len;
39136401Ssklower 	u_int 					takes_data;
39236401Ssklower 	u_int					fcc_present;
39338841Ssklower 	caddr_t					errloc;
39436401Ssklower 	struct tp_conn_param 	tpp;
39536401Ssklower 	int						tpcons_output();
39636401Ssklower 
39738841Ssklower again:
39836401Ssklower #ifdef TP_PERF_MEAS
39938841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
40036401Ssklower #endif TP_PERF_MEAS
40136401Ssklower 
40236401Ssklower 	IFDEBUG(D_TPINPUT)
40336401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
40436401Ssklower 	ENDDEBUG
40536401Ssklower 
40636401Ssklower 
40736401Ssklower 	tpdu_len = 0;
40836401Ssklower 	tpcb = (struct tp_pcb *)0;
40938841Ssklower 	fsufxlen = 0; fsufxloc = 0;
41038841Ssklower 	lsufxlen = 0; lsufxloc = 0;
41138841Ssklower 	errloc = 0; error = 0;
41236401Ssklower 	addlopt = 0;
41336401Ssklower 	acktime = 2;
41436401Ssklower 	dusize = TP_DFL_TPDUSIZE;
41536401Ssklower 	sref = 0;
41636401Ssklower 	subseq = 0;
41736401Ssklower 	takes_data = FALSE;
41836401Ssklower 	fcc_present = FALSE;
41938841Ssklower 	preferred_class = 0; class_to_use = 0;
42036401Ssklower 
42136401Ssklower 	/*
42236401Ssklower 	 * get the actual tpdu length - necessary for monitoring
42336401Ssklower 	 * and for checksumming
42436401Ssklower 	 *
42536401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
42636401Ssklower 	 */
42736401Ssklower 
42836401Ssklower 	{ 	register struct mbuf *n=m;
42936401Ssklower #	ifdef ARGO_DEBUG
43036401Ssklower 		int chain_length = 0;
43136401Ssklower #	endif ARGO_DEBUG
43236401Ssklower 
43336401Ssklower 		for(;;) {
43436401Ssklower 			tpdu_len += n->m_len;
43536401Ssklower 			IFDEBUG(D_MBUF_MEAS)
43637469Ssklower 				if( n->m_flags & M_EXT) {
43736401Ssklower 					IncStat(ts_mb_cluster);
43836401Ssklower 				} else {
43936401Ssklower 					IncStat(ts_mb_small);
44036401Ssklower 				}
44136401Ssklower 				chain_length ++;
44236401Ssklower 			ENDDEBUG
44336401Ssklower 			if (n->m_next == MNULL ) {
44436401Ssklower 				break;
44536401Ssklower 			}
44636401Ssklower 			n = n->m_next;
44736401Ssklower 		}
44836401Ssklower 		IFDEBUG(D_MBUF_MEAS)
44936401Ssklower 			if(chain_length > 16)
45036401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
45136401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
45236401Ssklower 		ENDDEBUG
45336401Ssklower 	}
45436401Ssklower 	IFTRACE(D_TPINPUT)
45536401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
45636401Ssklower 			0);
45736401Ssklower 	ENDTRACE
45836401Ssklower 
45936401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
46036401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
46136401Ssklower 	dutype = (int)hdr->tpdu_type;
46236401Ssklower 
46336401Ssklower 	IFDEBUG(D_TPINPUT)
46436401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
46536401Ssklower 			cons_channel, dref);
46636401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
46736401Ssklower 	ENDDEBUG
46836401Ssklower 	IFTRACE(D_TPINPUT)
46936401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
47036401Ssklower 			cons_channel, dutype, dref, 0);
47136401Ssklower 	ENDTRACE
47236401Ssklower 
47336401Ssklower 
47436401Ssklower #ifdef ARGO_DEBUG
47536401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
47636401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
47736401Ssklower 			dutype, cons_channel, dref);
47836401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
47936401Ssklower 
48036401Ssklower 		IncStat(ts_inv_dutype);
48136401Ssklower 		goto discard;
48236401Ssklower 	}
48336401Ssklower #endif ARGO_DEBUG
48436401Ssklower 
48536401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
48636401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
48736401Ssklower 		2 );
48836401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
48936401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
49036401Ssklower 		 */
49136401Ssklower 
49236401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
49336401Ssklower 	 * at the beginning of connection establishment, and by
49436401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
49536401Ssklower 	 */
49636401Ssklower 	if ( dutype == CR_TPDU_type ) {
49736401Ssklower 		u_char alt_classes = 0;
49836401Ssklower 
49936401Ssklower #ifdef notdef  /* This is done up above */
50036401Ssklower 		sref = hdr->tpdu_CRsref;
50136401Ssklower #endif notdef
50237469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
50336401Ssklower 		opt = hdr->tpdu_CRoptions;
50436401Ssklower 
50536401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
50636401Ssklower 
50736401Ssklower 			switch( vbptr(P)->tpv_code ) {
50836401Ssklower 
50936401Ssklower 			case	TPP_tpdu_size:
51036401Ssklower 				vb_getval(P, u_char, dusize);
51136401Ssklower 				IFDEBUG(D_TPINPUT)
51236401Ssklower 					printf("CR dusize 0x%x\n", dusize);
51336401Ssklower 				ENDDEBUG
51436401Ssklower 				CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE),
51536401Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
51636401Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
51736401Ssklower 				break;
51836401Ssklower 			case	TPP_addl_opt:
51936401Ssklower 				vb_getval(P, u_char, addlopt);
52036401Ssklower 				break;
52136401Ssklower 			case	TPP_calling_sufx:
52236401Ssklower 				/* could use vb_getval, but we want to save the loc & len
52336401Ssklower 				 * for later use
52436401Ssklower 				 */
52536401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
52636401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
52736401Ssklower 				IFDEBUG(D_TPINPUT)
52836401Ssklower 					printf("CR fsufx:");
52936401Ssklower 					{ register int j;
53036401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
53136401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
53236401Ssklower 						}
53336401Ssklower 						printf("\n");
53436401Ssklower 					}
53536401Ssklower 				ENDDEBUG
53636401Ssklower 				break;
53736401Ssklower 			case	TPP_called_sufx:
53836401Ssklower 				/* could use vb_getval, but we want to save the loc & len
53936401Ssklower 				 * for later use
54036401Ssklower 				 */
54136401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
54236401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
54336401Ssklower 				IFDEBUG(D_TPINPUT)
54436401Ssklower 					printf("CR lsufx:");
54536401Ssklower 					{ register int j;
54636401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
54737469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
54836401Ssklower 						}
54936401Ssklower 						printf("\n");
55036401Ssklower 					}
55136401Ssklower 				ENDDEBUG
55236401Ssklower 				break;
55336401Ssklower 
55436401Ssklower #ifdef TP_PERF_MEAS
55536401Ssklower 			case	TPP_perf_meas:
55636401Ssklower 				vb_getval(P, u_char, perf_meas);
55736401Ssklower 				break;
55836401Ssklower #endif TP_PERF_MEAS
55936401Ssklower 
56036401Ssklower 			case	TPP_vers:
56136401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
56236401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
56336401Ssklower 					E_TP_INV_PVAL, ts_inv_pval, respond,
56436401Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
56536401Ssklower 				break;
56636401Ssklower 			case	TPP_acktime:
56736401Ssklower 				vb_getval(P, u_short, acktime);
56836401Ssklower 				acktime = ntohs(acktime);
56936401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
57036401Ssklower 				if((short)acktime <=0 )
57136401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
57236401Ssklower 				IFDEBUG(D_TPINPUT)
57336401Ssklower 					printf("CR acktime 0x%x\n", acktime);
57436401Ssklower 				ENDDEBUG
57536401Ssklower 				break;
57636401Ssklower 
57736401Ssklower 			case	TPP_alt_class:
57836401Ssklower 				{
57936401Ssklower 					u_char *aclass = 0;
58036401Ssklower 					register int i;
58136401Ssklower 
58236401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
58336401Ssklower 						aclass =
58436401Ssklower 							(u_char *) &(((struct tp_vbp *)P)->tpv_val);
58537469Ssklower 						alt_classes |= (1<<((*aclass)>>4));
58636401Ssklower 					}
58736401Ssklower 					IFDEBUG(D_TPINPUT)
58836401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
58936401Ssklower 					ENDDEBUG
59036401Ssklower 				}
59136401Ssklower 				break;
59236401Ssklower 
59336401Ssklower 			case	TPP_security:
59436401Ssklower 			case	TPP_residER:
59536401Ssklower 			case	TPP_priority:
59636401Ssklower 			case	TPP_transdelay:
59736401Ssklower 			case	TPP_throughput:
59836401Ssklower 			case	TPP_addl_info:
59936401Ssklower 			case	TPP_subseq:
60036401Ssklower 				IFDEBUG(D_TPINPUT)
60136401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
60236401Ssklower 						 vbptr(P)->tpv_code);
60336401Ssklower 				ENDDEBUG
60436401Ssklower 				IncStat(ts_param_ignored);
60536401Ssklower 				break;
60636401Ssklower 
60736401Ssklower 			case	TPP_checksum:
60836401Ssklower 				IFDEBUG(D_TPINPUT)
60936401Ssklower 					printf("CR before cksum\n");
61036401Ssklower 				ENDDEBUG
61136401Ssklower 
61236401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
61336401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
61436401Ssklower 
61536401Ssklower 				IFDEBUG(D_TPINPUT)
61636401Ssklower 					printf("CR before cksum\n");
61736401Ssklower 				ENDDEBUG
61836401Ssklower 				break;
61936401Ssklower 
62036401Ssklower 			default:
62136401Ssklower 				IncStat(ts_inv_pcode);
62236401Ssklower 				error = E_TP_INV_PCODE;
62336401Ssklower 				goto discard;
62436401Ssklower 
62536401Ssklower 			}
62636401Ssklower 
62736401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
62836401Ssklower 
62936401Ssklower 		if( lsufxlen == 0) {
63036401Ssklower 			/* can't look for a tpcb w/o any called sufx */
63136401Ssklower 			error =  E_TP_LENGTH_INVAL;
63236401Ssklower 			IncStat(ts_inv_sufx);
63336401Ssklower 			goto respond;
63436401Ssklower 		} else {
63536401Ssklower 			register	struct tp_ref 	*rp;
63636401Ssklower 			register	int			r;
63736401Ssklower 			extern		int			tp_maxrefopen;
63836401Ssklower 
63936401Ssklower 			rp = &tp_ref[1]; /* zero-th one is never open */
64036401Ssklower 			for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
64136401Ssklower 				if (rp->tpr_state!=REF_OPENING)
64236401Ssklower 					continue;
64336401Ssklower 				if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) {
64436401Ssklower 					tpcb =  rp->tpr_pcb;
64536401Ssklower 					if( laddr->sa_family !=
64636401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family ) {
64736401Ssklower 						IFDEBUG(D_CONN)
64836401Ssklower 						 	printf(
64936401Ssklower 					"MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n",
65036401Ssklower 							laddr->sa_family,
65136401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family );
65236401Ssklower 						ENDDEBUG
65336401Ssklower 						continue;
65436401Ssklower 					}
65536401Ssklower 					IFTRACE(D_TPINPUT)
65636401Ssklower 						tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate",
65736401Ssklower 							r, *lsufxloc, rp->tpr_state, 0);
65836401Ssklower 					ENDTRACE
65936401Ssklower 					/* found it */
66036401Ssklower 					break;
66136401Ssklower 				}
66236401Ssklower 			}
66336401Ssklower 
66436401Ssklower 			CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond,
66536401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
66636401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
66736401Ssklower 				 * the fixed part (can't take the address of a bit field)
66836401Ssklower 				 */
66936401Ssklower 		}
67036401Ssklower 
67136401Ssklower 		/*
67236401Ssklower 		 * WE HAVE A TPCB
67336401Ssklower 		 * already know that the classes in the CR match at least
67436401Ssklower 		 * one class implemented, but we don't know yet if they
67536401Ssklower 		 * include any classes permitted by this server.
67636401Ssklower 		 */
67736401Ssklower 
67836401Ssklower 		IFDEBUG(D_TPINPUT)
67936401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
68036401Ssklower 		ENDDEBUG
68136401Ssklower 		IFDEBUG(D_CONN)
68236401Ssklower 			printf(
68336401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
68436401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
68536401Ssklower 		ENDDEBUG
68636401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
68736401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
68836401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
68936401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
69036401Ssklower 
69136401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
69236401Ssklower 
69336401Ssklower 		{
69436401Ssklower 			tpp = tpcb->_tp_param;
69536401Ssklower 			tpp.p_class = class_to_use;
69636401Ssklower 			tpp.p_tpdusize = dusize;
69736401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
69836401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
69936401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
70036401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
70136401Ssklower #ifdef notdef
70236401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
70336401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
70436401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
70536401Ssklower #endif notdef
70636401Ssklower 
70736401Ssklower 		CHECK(
70836401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
70936401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
71036401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
71136401Ssklower 				/* ^ more or less the location of class */
71236401Ssklower 			)
71336401Ssklower 		}
71436401Ssklower 		IFTRACE(D_CONN)
71536401Ssklower 			tptrace(TPPTmisc,
71636401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
71736401Ssklower 				class_to_use,
71836401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
71936401Ssklower 				);
72036401Ssklower 		ENDTRACE
72136401Ssklower 		CHECK(
72236401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
72336401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
72436401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
72536401Ssklower 				/* ^ more or less the location of class */
72636401Ssklower 			)
72736401Ssklower 		IFDEBUG(D_CONN)
72836401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
72936401Ssklower 				tpcb, tpcb->tp_flags);
73036401Ssklower 		ENDDEBUG
73136401Ssklower 		takes_data = TRUE;
73236401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
73336401Ssklower 		e.ev_number = CR_TPDU;
73436401Ssklower 
73536401Ssklower 		so = tpcb->tp_sock;
73636401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
73736401Ssklower 			/*
73836401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
73936401Ssklower 			 * for this newborn connection, and fill in all the values.
74036401Ssklower 			 */
74136401Ssklower 			IFDEBUG(D_CONN)
74236401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
74336401Ssklower 					so, laddr, faddr, cons_channel);
74436401Ssklower 			ENDDEBUG
74536401Ssklower 			if( (so =
74636401Ssklower 				tp_newsocket(so, faddr, cons_channel,
74736401Ssklower 					class_to_use,
74837469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
74937469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
75036401Ssklower 					) == (struct socket *)0 ) {
75136401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
75236401Ssklower 				 * the tp entity is concerned, the only differences
75337469Ssklower 				 * are CO vs CL
75436401Ssklower 				 */
75536401Ssklower 				IFDEBUG(D_CONN)
75636401Ssklower 					printf("tp_newsocket returns 0\n");
75736401Ssklower 				ENDDEBUG
75836401Ssklower 				goto discard;
75936401Ssklower 			}
76036401Ssklower 			tpcb = sototpcb(so);
76136401Ssklower 
76236401Ssklower 			/*
76337469Ssklower 			 * Stash the addresses in the net level pcb
76436401Ssklower 			 * kind of like a pcbconnect() but don't need
76536401Ssklower 			 * or want all those checks.
76636401Ssklower 			 */
76736401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
76836401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
76936401Ssklower 
77037469Ssklower 			/* stash the f suffix in the new tpcb */
77137469Ssklower 			/* l suffix is already there */
77238841Ssklower 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
77336401Ssklower 
77437469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
77537469Ssklower 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
77638841Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
77738841Ssklower 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
77837469Ssklower 
77936401Ssklower #ifdef TP_PERF_MEAS
78036401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
78136401Ssklower 				/* ok, let's create an mbuf for stashing the
78236401Ssklower 				 * statistics if one doesn't already exist
78336401Ssklower 				 */
78436401Ssklower 				(void) tp_setup_perf(tpcb);
78536401Ssklower 			}
78636401Ssklower #endif TP_PERF_MEAS
78736401Ssklower 			tpcb->tp_fref = sref;
78836401Ssklower 
78936401Ssklower 			/* We've already checked for consistency with the options
79036401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
79136401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
79236401Ssklower 			 * Now we set the options in the new socket's tpcb.
79336401Ssklower 			 */
79436401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
79536401Ssklower 
79636401Ssklower 			if(!tpcb->tp_use_checksum)
79736401Ssklower 				IncStat(ts_csum_off);
79836401Ssklower 			if(tpcb->tp_xpd_service)
79936401Ssklower 				IncStat(ts_use_txpd);
80036401Ssklower 			if(tpcb->tp_xtd_format)
80136401Ssklower 				IncStat(ts_xtd_fmt);
80236401Ssklower 
80336401Ssklower 			/*
80436401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
80536401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
80636401Ssklower 			 */
80736401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
80836401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
80936401Ssklower 			tpcb->tp_peer_acktime = acktime;
81036401Ssklower 
81136401Ssklower 			/*
81236401Ssklower 			 * The following kludge is used to test retransmissions and
81336401Ssklower 			 * timeout during connection establishment.
81436401Ssklower 			 */
81536401Ssklower 			IFDEBUG(D_ZDREF)
81636401Ssklower 				IncStat(ts_zdebug);
81737469Ssklower 				/*tpcb->tp_fref = 0;*/
81836401Ssklower 			ENDDEBUG
81936401Ssklower 		}
82036401Ssklower 		IncStat(ts_CR_rcvd);
82139929Ssklower 		if (!tpcb->tp_cebit_off) {
82239929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
82339929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
82439929Ssklower 			LOCAL_CREDIT(tpcb);
82539929Ssklower 			CONG_INIT_SAMPLE(tpcb);
82639929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
82739929Ssklower 		}
82839929Ssklower 		tpcb->tp_ackrcvd = 0;
82936401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
83036401Ssklower 		/*
83136401Ssklower 		 * ER TPDUs have to be recognized separately
83236401Ssklower 		 * because they don't necessarily have a tpcb
83336401Ssklower 		 * with them and we don't want err out looking for such
83436401Ssklower 		 * a beast.
83536401Ssklower 		 * We could put a bunch of little kludges in the
83636401Ssklower 		 * next section of code so it would avoid references to tpcb
83736401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
83836401Ssklower 		 * mess up code for data transfer.
83936401Ssklower 		 */
84036401Ssklower 		IncStat(ts_ER_rcvd);
84136401Ssklower 		e.ev_number = ER_TPDU;
84236401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
84336401Ssklower 		takes_data = 1;
84436401Ssklower 	} else {
84536401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
84636401Ssklower 
84736401Ssklower 		/* In the next 4 checks,
84836401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
84936401Ssklower 		 * the fixed part (can't take the address of a bit field)
85036401Ssklower 		 */
85136401Ssklower 		if(cons_channel) {
85236401Ssklower #if NARGOXTWENTYFIVE > 0
85336401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
85436401Ssklower 
85536401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
85636401Ssklower 			/* Problem:  We may have a legit
85736401Ssklower 			 * error situation yet we may or may not have
85836401Ssklower 			 * a correspondence between the tpcb and the vc,
85936401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
86036401Ssklower 			 *          <---  DR
86136401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
86236401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
86336401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
86436401Ssklower 			 * Sigh.
86536401Ssklower 			 */
86636401Ssklower 
86736401Ssklower 			/* I don't know about this error value */
86836401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
86936401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
87036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
87136401Ssklower #else
87236401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
87336401Ssklower #endif NARGOXTWENTYFIVE > 0
87436401Ssklower 
87536401Ssklower 		} else {
87636401Ssklower 
87736401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
87836401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
87936401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88036401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
88136401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
88236401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88336401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
88436401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
88536401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88636401Ssklower 		}
88736401Ssklower 
88836401Ssklower 		IFDEBUG(D_TPINPUT)
88936401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
89036401Ssklower 		ENDDEBUG
89136401Ssklower 
89236401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
89336401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
89436401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
89536401Ssklower 			ts_inv_dref, respond,
89636401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89736401Ssklower 
89836401Ssklower 		IFDEBUG(D_TPINPUT)
89936401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
90036401Ssklower 		ENDDEBUG
90136401Ssklower 		/*
90236401Ssklower 		 * At this point the state of the dref could be
90336401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
90436401Ssklower 		 *		   for example, DC may arrive after the close() has detached
90536401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
90636401Ssklower 		 * OPENING : a tpcb exists but no timers yet
90736401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
90836401Ssklower 		 */
90936401Ssklower 
91039929Ssklower         if (!tpcb->tp_cebit_off)
91139929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
91239929Ssklower 
91336401Ssklower 		dusize = tpcb->tp_tpdusize;
91436401Ssklower 
91536401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
91636401Ssklower 
91736401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
91836401Ssklower 
91937469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
92036401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
92136401Ssklower 
92236401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
92336401Ssklower 					/* not in class 0; 1 octet */
92436401Ssklower 					vb_getval(P, u_char, addlopt);
92536401Ssklower 					break;
92636401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
92736401Ssklower 					vb_getval(P, u_char, dusize);
92836401Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE || dusize >
92936401Ssklower 						TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond,
93036401Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
93136401Ssklower 					IFDEBUG(D_TPINPUT)
93236401Ssklower 						printf("CC dusize 0x%x\n", dusize);
93336401Ssklower 					ENDDEBUG
93436401Ssklower 					break;
93536401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
93636401Ssklower 					IFDEBUG(D_TPINPUT)
93736401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
93836401Ssklower 					ENDDEBUG
93936401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
94036401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
94136401Ssklower 					break;
94236401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
94336401Ssklower 					/* class 4 only, 2 octets */
94436401Ssklower 					vb_getval(P, u_short, acktime);
94536401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
94636401Ssklower 					if( (short)acktime <=0 )
94736401Ssklower 						acktime = 2;
94836401Ssklower 					break;
94936401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
95036401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
95136401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
95236401Ssklower 					IFDEBUG(D_TPINPUT)
95336401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
95436401Ssklower 					ENDDEBUG
95536401Ssklower 					break;
95636401Ssklower 
95736401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
95836401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
95936401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
96036401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
96136401Ssklower 					if( tpcb->tp_use_checksum )  {
96236401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
96336401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
96436401Ssklower 					}
96536401Ssklower 					break;
96636401Ssklower 
96736401Ssklower 			/*  this is different from the above because in the context
96836401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
96936401Ssklower 			 */
97036401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
97136401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
97236401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
97336401Ssklower 					if( tpcb->tp_use_checksum )  {
97437469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
97536401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
97636401Ssklower 					}
97736401Ssklower 					break;
97836401Ssklower #ifdef notdef
97936401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
98036401Ssklower 				/* ignore - its length and meaning are
98136401Ssklower 				 * user defined and there's no way
98236401Ssklower 				 * to pass this info to the user anyway
98336401Ssklower 				 */
98436401Ssklower 				break;
98536401Ssklower #endif notdef
98636401Ssklower 
98736401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
98836401Ssklower 				/* used after reduction of window */
98936401Ssklower 				vb_getval(P, u_short, subseq);
99036401Ssklower 				subseq = ntohs(subseq);
99136401Ssklower 				IFDEBUG(D_ACKRECV)
99236401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
99336401Ssklower 				ENDDEBUG
99436401Ssklower 				break;
99536401Ssklower 
99636401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
99736401Ssklower 				{
99836401Ssklower 					u_int 	ylwe;
99936401Ssklower 					u_short ysubseq, ycredit;
100036401Ssklower 
100136401Ssklower 					fcc_present = TRUE;
100236401Ssklower 					vb_getval(P, u_int,	 	ylwe);
100336401Ssklower 					vb_getval(P, u_short, 	ysubseq);
100436401Ssklower 					vb_getval(P, u_short, 	ycredit);
100536401Ssklower 					ylwe = ntohl(ylwe);
100636401Ssklower 					ysubseq = ntohs(ysubseq);
100736401Ssklower 					ycredit = ntohs(ycredit);
100836401Ssklower 					IFDEBUG(D_ACKRECV)
100936401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
101036401Ssklower 							ylwe, ysubseq, ycredit);
101136401Ssklower 					ENDDEBUG
101236401Ssklower 				}
101336401Ssklower 				break;
101436401Ssklower 
101536401Ssklower 			default:
101636401Ssklower 				IFDEBUG(D_TPINPUT)
101736401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
101836401Ssklower 						dutype, vbptr(P)->tpv_code);
101936401Ssklower 				ENDDEBUG
102036401Ssklower 				IFTRACE(D_TPINPUT)
102136401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
102236401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
102336401Ssklower 				ENDTRACE
102436401Ssklower 				IncStat(ts_param_ignored);
102536401Ssklower 				break;
102636401Ssklower #undef caseof
102736401Ssklower 		}
102836401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
102936401Ssklower 
103036401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
103136401Ssklower 
103236401Ssklower 		switch( hdr->tpdu_type ) {
103336401Ssklower 		case CC_TPDU_type:
103436401Ssklower 			/* If CC comes back with an unacceptable class
103536401Ssklower 			 * respond with a DR or ER
103636401Ssklower 			 */
103736401Ssklower 
103836401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
103936401Ssklower 
104036401Ssklower 			{
104136401Ssklower 				tpp = tpcb->_tp_param;
104236401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
104336401Ssklower 				tpp.p_tpdusize = dusize;
104436401Ssklower 				tpp.p_dont_change_params = 0;
104536401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
104636401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
104736401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
104836401Ssklower #ifdef notdef
104936401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
105036401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
105136401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
105236401Ssklower #endif notdef
105336401Ssklower 
105436401Ssklower 			CHECK(
105536401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
105636401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
105736401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
105836401Ssklower 					/* ^ more or less the location of class */
105936401Ssklower 				)
106036401Ssklower 			IFTRACE(D_CONN)
106136401Ssklower 				tptrace(TPPTmisc,
106236401Ssklower 					"after 1 consist class, out, tpconsout",
106336401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
106436401Ssklower 					);
106536401Ssklower 			ENDTRACE
106636401Ssklower 			CHECK(
106736401Ssklower 				((class_to_use == TP_CLASS_0)&&
106836401Ssklower 					(dgout_routine != tpcons_output)),
106936401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
107036401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
107136401Ssklower 					/* ^ more or less the location of class */
107236401Ssklower 				)
107336401Ssklower 			}
107436401Ssklower 			if( ! tpcb->tp_use_checksum)
107536401Ssklower 				IncStat(ts_csum_off);
107636401Ssklower 			if(tpcb->tp_xpd_service)
107736401Ssklower 				IncStat(ts_use_txpd);
107836401Ssklower 			if(tpcb->tp_xtd_format)
107936401Ssklower 				IncStat(ts_xtd_fmt);
108036401Ssklower 
108136401Ssklower 			IFTRACE(D_CONN)
108236401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
108336401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
108436401Ssklower 					hdr->tpdu_CCclass);
108536401Ssklower 			ENDTRACE
108636401Ssklower 
108736401Ssklower 			/*
108836401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
108936401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
109036401Ssklower 			 * It would be nice if the arguments to this
109136401Ssklower 			 * were more reasonable.
109236401Ssklower 			 */
109336401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
109436401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
109536401Ssklower 
109636401Ssklower #ifdef	CONS
109736401Ssklower 			/* Could be that this CC came in on a NEW vc, in which case
109836401Ssklower 			 * we have to confirm it.
109936401Ssklower 			 */
110036401Ssklower 			if( cons_channel )
110136401Ssklower 				cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
110236401Ssklower 						tpcb->tp_class == TP_CLASS_4);
110336401Ssklower #endif	CONS
110436401Ssklower 
110536401Ssklower 			tpcb->tp_peer_acktime = acktime;
110636401Ssklower 
110736401Ssklower 			/* if called or calling suffices appeared on the CC,
110836401Ssklower 			 * they'd better jive with what's in the pcb
110936401Ssklower 			 */
111036401Ssklower 			if( fsufxlen ) {
111136401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
111236401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
111336401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
111436401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
111536401Ssklower 			}
111636401Ssklower 			if( lsufxlen ) {
111736401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
111836401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
111936401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
112036401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
112136401Ssklower 			}
112236401Ssklower 
112336401Ssklower #ifdef notdef
112436401Ssklower 			e.ATTR(CC_TPDU).e_sref =  (u_short)hdr->tpdu_CCsref;
112536401Ssklower #else
112636401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
112736401Ssklower #endif notdef
112836401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
112936401Ssklower 			takes_data = TRUE;
113036401Ssklower 			e.ev_number = CC_TPDU;
113136401Ssklower 			IncStat(ts_CC_rcvd);
113236401Ssklower 			break;
113336401Ssklower 
113436401Ssklower 		case DC_TPDU_type:
113536401Ssklower #ifdef notdef
113636401Ssklower 			if (hdr->tpdu_DCsref != tpcb->tp_fref)
113736401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
113836401Ssklower 					hdr->tpdu_DCsref, tpcb->tp_fref);
113936401Ssklower #else
114036401Ssklower 			if (sref != tpcb->tp_fref)
114136401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
114236401Ssklower 					sref, tpcb->tp_fref);
114336401Ssklower #endif notdef
114436401Ssklower 
114536401Ssklower #ifdef notdef
114636401Ssklower 			CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref),
114736401Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, respond,
114836401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
114936401Ssklower #else
115036401Ssklower 			CHECK( (sref != tpcb->tp_fref),
115136401Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, respond,
115236401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
115336401Ssklower #endif notdef
115436401Ssklower 			e.ev_number = DC_TPDU;
115536401Ssklower 			IncStat(ts_DC_rcvd);
115636401Ssklower 			break;
115736401Ssklower 
115836401Ssklower 		case DR_TPDU_type:
115936401Ssklower 			IFTRACE(D_TPINPUT)
116036401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
116136401Ssklower 			ENDTRACE
116236401Ssklower #ifdef vax
116336401Ssklower 			if(sref != tpcb->tp_fref)
116436401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
116536401Ssklower 					sref, tpcb->tp_fref);
116636401Ssklower 
116736401Ssklower 			CHECK( (sref != tpcb->tp_fref),
116836401Ssklower 				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 #else
117436401Ssklower 			if(hdr->tpdu_DRsref != tpcb->tp_fref)
117536401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
117636401Ssklower 					hdr->tpdu_DRsref, tpcb->tp_fref);
117736401Ssklower 
117836401Ssklower 			CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref),
117936401Ssklower 				E_TP_MISM_REFS,ts_inv_sufx, respond,
118036401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
118136401Ssklower 
118236401Ssklower 			e.ATTR(DR_TPDU).e_reason =
118336401Ssklower 				hdr->tpdu_DRreason;
118436401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)hdr->tpdu_DRsref;
118536401Ssklower #endif vax
118636401Ssklower 			takes_data = TRUE;
118736401Ssklower 			e.ev_number = DR_TPDU;
118836401Ssklower 			IncStat(ts_DR_rcvd);
118936401Ssklower 			break;
119036401Ssklower 
119136401Ssklower 		case ER_TPDU_type:
119236401Ssklower 			IFTRACE(D_TPINPUT)
119336401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
119436401Ssklower 			ENDTRACE
119536401Ssklower 			e.ev_number = ER_TPDU;
119636401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
119736401Ssklower 			IncStat(ts_ER_rcvd);
119836401Ssklower 			break;
119936401Ssklower 
120036401Ssklower 		case AK_TPDU_type:
120136401Ssklower 
120236401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
120336401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
120436401Ssklower 
120536401Ssklower 			if (tpcb->tp_xtd_format) {
120636401Ssklower #ifdef BYTE_ORDER
120736401Ssklower 				union seq_type seqeotX;
120836401Ssklower 
120936401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
121036401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
121136401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
121236401Ssklower #else
121336401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
121436401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
121536401Ssklower #endif BYTE_ORDER
121636401Ssklower 			} else {
121736401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
121836401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
121936401Ssklower 			}
122036401Ssklower 			IFTRACE(D_TPINPUT)
122136401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
122236401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
122336401Ssklower 					subseq, fcc_present);
122436401Ssklower 			ENDTRACE
122536401Ssklower 
122636401Ssklower 			e.ev_number = AK_TPDU;
122736401Ssklower 			IncStat(ts_AK_rcvd);
122836401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
122936401Ssklower 			break;
123036401Ssklower 
123136401Ssklower 		case XAK_TPDU_type:
123236401Ssklower 			if (tpcb->tp_xtd_format) {
123336401Ssklower #ifdef BYTE_ORDER
123436401Ssklower 				union seq_type seqeotX;
123536401Ssklower 
123636401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
123736401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
123836401Ssklower #else
123936401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
124036401Ssklower #endif BYTE_ORDER
124136401Ssklower 			} else {
124236401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
124336401Ssklower 			}
124436401Ssklower 			e.ev_number = XAK_TPDU;
124536401Ssklower 			IncStat(ts_XAK_rcvd);
124636401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
124736401Ssklower 			break;
124836401Ssklower 
124936401Ssklower 		case XPD_TPDU_type:
125036401Ssklower 			if (tpcb->tp_xtd_format) {
125136401Ssklower #ifdef BYTE_ORDER
125236401Ssklower 				union seq_type seqeotX;
125336401Ssklower 
125436401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
125536401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
125636401Ssklower #else
125736401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
125836401Ssklower #endif BYTE_ORDER
125936401Ssklower 			} else {
126036401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
126136401Ssklower 			}
126236401Ssklower 			takes_data = TRUE;
126336401Ssklower 			e.ev_number = XPD_TPDU;
126436401Ssklower 			IncStat(ts_XPD_rcvd);
126536401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
126636401Ssklower 			break;
126736401Ssklower 
126836401Ssklower 		case DT_TPDU_type:
126936401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
127036401Ssklower 			   * A little crude but it works.
127136401Ssklower 			   */
127236401Ssklower 
127336401Ssklower 				IFDEBUG(D_DROP)
127436401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
127536401Ssklower 						IncStat(ts_ydebug);
127636401Ssklower 						goto discard;
127736401Ssklower 					}
127836401Ssklower 				ENDDEBUG
127936401Ssklower 			}
128036401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
128136401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
128236401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
128336401Ssklower 			} else if (tpcb->tp_xtd_format) {
128436401Ssklower #ifdef BYTE_ORDER
128536401Ssklower 				union seq_type seqeotX;
128636401Ssklower 
128736401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
128836401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
128936401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
129036401Ssklower #else
129136401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
129236401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
129336401Ssklower #endif BYTE_ORDER
129436401Ssklower 			} else {
129536401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
129636401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
129736401Ssklower 			}
129836401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
129936401Ssklower 				IncStat(ts_eot_input);
130036401Ssklower 			takes_data = TRUE;
130136401Ssklower 			e.ev_number = DT_TPDU;
130236401Ssklower 			IncStat(ts_DT_rcvd);
130336401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
130436401Ssklower 			break;
130536401Ssklower 
130636401Ssklower 		case GR_TPDU_type:
130736401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
130836401Ssklower 			/* drop through */
130936401Ssklower 		default:
131036401Ssklower 			/* this should NEVER happen because there is a
131136401Ssklower 			 * check for dutype well above here
131236401Ssklower 			 */
131336401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
131436401Ssklower 			IFDEBUG(D_TPINPUT)
131536401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
131636401Ssklower 			ENDDEBUG
131736401Ssklower 			IncStat(ts_inv_dutype);
131836401Ssklower 			goto respond;
131936401Ssklower 		}
132036401Ssklower 	}
132136401Ssklower 
132236401Ssklower 	/* peel off the tp header;
132336401Ssklower 	 * remember that the du_li doesn't count itself.
132436401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
132536401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
132636401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
132736401Ssklower 	 */
132836401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
132937469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
133036401Ssklower 
133137469Ssklower 	if (takes_data) {
133237469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
133337469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
1334*42468Ssklower 		struct cmsghdr c_hdr;
133537469Ssklower 		struct mbuf *n;
133636401Ssklower 
133737469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
133837469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
133936401Ssklower 		switch( hdr->tpdu_type ) {
134037469Ssklower 
134136401Ssklower 		case CR_TPDU_type:
134237469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
134337469Ssklower 			goto make_control_msg;
134437469Ssklower 
134536401Ssklower 		case CC_TPDU_type:
134637469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
134737469Ssklower 			goto make_control_msg;
134837469Ssklower 
134936401Ssklower 		case DR_TPDU_type:
135037469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
135137469Ssklower 		make_control_msg:
135237469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
135337469Ssklower 			mbtype = MT_CONTROL;
135440015Ssklower 			datalen += sizeof(c_hdr);
135540015Ssklower 			m->m_len += sizeof(c_hdr);
135640015Ssklower 			m->m_data -= sizeof(c_hdr);
135740015Ssklower 			c_hdr.cmsg_len = datalen;
135840015Ssklower 			bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr));
135937469Ssklower 			/* FALLTHROUGH */
136037469Ssklower 
136136401Ssklower 		case XPD_TPDU_type:
136237469Ssklower 			if (mbtype != MT_CONTROL)
136337469Ssklower 				mbtype = MT_OOBDATA;
136437469Ssklower 			m->m_flags |= M_EOR;
136537469Ssklower 			/* FALLTHROUGH */
136637469Ssklower 
136736401Ssklower 		case DT_TPDU_type:
136837469Ssklower 			for (n = m; n; n = n->m_next) {
136937469Ssklower 				MCHTYPE(n, mbtype);
137037469Ssklower 			}
137137469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
137236401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
137336401Ssklower 			break;
137436401Ssklower 
137536401Ssklower 		default:
137636401Ssklower 			printf(
137736401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
137836401Ssklower 				hdr->tpdu_type, takes_data, m);
137936401Ssklower 			break;
138036401Ssklower 		}
138136401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
138236401Ssklower 		m = MNULL;
138336401Ssklower 	}
138436401Ssklower 
138536401Ssklower 	IncStat(ts_tpdu_rcvd);
138636401Ssklower 
138736401Ssklower 	IFDEBUG(D_TPINPUT)
138836401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
138936401Ssklower 			tpcb->tp_state, e.ev_number, m );
139036401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
139136401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
139236401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
139336401Ssklower 	ENDDEBUG
139436401Ssklower 
139536401Ssklower 	error = tp_driver(tpcb, &e);
139636401Ssklower 
139736401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
139836401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
139936401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
140036401Ssklower 		tpcb->tp_sock->so_error = error;
140136401Ssklower 
140236401Ssklower 	/* Kludge to keep the state tables under control (adding
140336401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
140436401Ssklower 	 * the data would have exploded the tables and made a big mess ).
140536401Ssklower 	 */
140636401Ssklower 	switch(e.ev_number) {
140736401Ssklower 		case CC_TPDU:
140836401Ssklower 		case DR_TPDU:
140936401Ssklower 		case CR_TPDU:
141036401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
141136401Ssklower 			IFDEBUG(D_TPINPUT)
141236401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
141336401Ssklower 				m, takes_data);
141436401Ssklower 			ENDDEBUG
141536401Ssklower 			break;
141636401Ssklower 		default:
141736401Ssklower 			break;
141836401Ssklower 	}
141936401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
142036401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
142136401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
142236401Ssklower 	 */
142336401Ssklower 
142436401Ssklower separate:
142536401Ssklower 	if ( takes_data == 0 )  {
142636401Ssklower 		ASSERT( m != MNULL );
142736401Ssklower 		/*
142836401Ssklower 		 * we already peeled off the prev. tp header so
142936401Ssklower 		 * we can just pull up some more and repeat
143036401Ssklower 		 */
143136401Ssklower 
143237469Ssklower 		if( m = tp_inputprep(m) ) {
143336401Ssklower 		IFDEBUG(D_TPINPUT)
143436401Ssklower 			hdr = mtod(m, struct tpdu *);
143536401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
143636401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
143736401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
143836401Ssklower 		ENDDEBUG
143936401Ssklower 
144036401Ssklower 			IncStat(ts_concat_rcvd);
144136401Ssklower 			goto again;
144236401Ssklower 		}
144336401Ssklower 	}
144436401Ssklower 	if ( m != MNULL ) {
144536401Ssklower 		IFDEBUG(D_TPINPUT)
144636401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
144736401Ssklower 		ENDDEBUG
144836401Ssklower 		m_freem(m);
144936401Ssklower 		IFDEBUG(D_TPINPUT)
145036401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
145136401Ssklower 		ENDDEBUG
145236401Ssklower 	}
145336401Ssklower 	return (ProtoHook) tpcb;
145436401Ssklower 
145536401Ssklower discard:
145636401Ssklower 	/* class 4: drop the tpdu */
145736401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
145836401Ssklower 	 * to which connection it applies
145936401Ssklower 	 */
146036401Ssklower 	IFDEBUG(D_TPINPUT)
146136401Ssklower 		printf("tp_input DISCARD\n");
146236401Ssklower 	ENDDEBUG
146336401Ssklower 	IFTRACE(D_TPINPUT)
146436401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
146536401Ssklower 	ENDTRACE
146636401Ssklower 	m_freem(m);
146736401Ssklower 	IncStat(ts_recv_drop);
146836401Ssklower 	return (ProtoHook)0;
146936401Ssklower 
147036401Ssklower respond:
147136401Ssklower 	IFDEBUG(D_ERROR_EMIT)
147236401Ssklower 		printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc);
147336401Ssklower 	ENDDEBUG
147436401Ssklower 	IFTRACE(D_TPINPUT)
147536401Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref",  m,error,sref,0);
147636401Ssklower 	ENDTRACE
147736401Ssklower 	if( sref == 0 )
147836401Ssklower 		goto discard;
147937469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
148037469Ssklower 				(struct sockaddr_iso *)laddr, m, (int)errloc, tpcb,
148137469Ssklower 				(int)cons_channel, dgout_routine);
148236401Ssklower 	IFDEBUG(D_ERROR_EMIT)
148336401Ssklower 		printf("tp_input after error_emit\n");
148436401Ssklower 	ENDDEBUG
148536401Ssklower 
148636401Ssklower #ifdef lint
148736401Ssklower 	printf("",sref,opt);
148836401Ssklower #endif lint
148936401Ssklower 	IncStat(ts_recv_drop);
149036401Ssklower 	return (ProtoHook)0;
149136401Ssklower }
149236401Ssklower 
149336401Ssklower 
149436401Ssklower /*
149536401Ssklower  * NAME: tp_headersize()
149636401Ssklower  *
149736401Ssklower  * CALLED FROM:
149836401Ssklower  *  tp_emit() and tp_sbsend()
149936401Ssklower  *  TP needs to know the header size so it can figure out how
150036401Ssklower  *  much data to put in each tpdu.
150136401Ssklower  *
150236401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
150336401Ssklower  *  For a given connection, represented by (tpcb), and
150436401Ssklower  *  tpdu type (dutype), return the size of a tp header.
150536401Ssklower  *
150636401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
150736401Ssklower  *
150836401Ssklower  * SIDE EFFECTS:
150936401Ssklower  *
151036401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
151136401Ssklower  */
151236401Ssklower int
151336401Ssklower tp_headersize(dutype, tpcb)
151436401Ssklower 	int 			dutype;
151536401Ssklower 	struct tp_pcb 	*tpcb;
151636401Ssklower {
151736401Ssklower 	register int size = 0;
151836401Ssklower 
151936401Ssklower 	IFTRACE(D_CONN)
152036401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
152136401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
152236401Ssklower 	ENDTRACE
152336401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
152436401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
152536401Ssklower 			(dutype == DR_TPDU_type) ||
152636401Ssklower 			(dutype == CR_TPDU_type) )) {
152736401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
152836401Ssklower 			dutype, tpcb->tp_class);
152936401Ssklower 	/* TODO: identify this and GET RID OF IT */
153036401Ssklower 	}
153136401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
153236401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
153336401Ssklower 			(dutype == DR_TPDU_type) ||
153436401Ssklower 			(dutype == CR_TPDU_type) );
153536401Ssklower 
153636401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
153736401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
153836401Ssklower 	} else  {
153936401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
154036401Ssklower 	}
154136401Ssklower 	return size;
154236401Ssklower 	/* caller must get network level header size separately */
154336401Ssklower }
1544