xref: /csrg-svn/sys/netiso/tp_input.c (revision 49268)
1*49268Sbostic /*-
2*49268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*49268Sbostic  * All rights reserved.
4*49268Sbostic  *
5*49268Sbostic  * %sccs.include.redist.c%
6*49268Sbostic  *
7*49268Sbostic  *	@(#)tp_input.c	7.18 (Berkeley) 05/06/91
8*49268Sbostic  */
9*49268Sbostic 
1036401Ssklower /***********************************************************
1136401Ssklower 		Copyright IBM Corporation 1987
1236401Ssklower 
1336401Ssklower                       All Rights Reserved
1436401Ssklower 
1536401Ssklower Permission to use, copy, modify, and distribute this software and its
1636401Ssklower documentation for any purpose and without fee is hereby granted,
1736401Ssklower provided that the above copyright notice appear in all copies and that
1836401Ssklower both that copyright notice and this permission notice appear in
1936401Ssklower supporting documentation, and that the name of IBM not be
2036401Ssklower used in advertising or publicity pertaining to distribution of the
2136401Ssklower software without specific, written prior permission.
2236401Ssklower 
2336401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936401Ssklower SOFTWARE.
3036401Ssklower 
3136401Ssklower ******************************************************************/
3236401Ssklower 
3336401Ssklower /*
3436401Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536401Ssklower  */
3636401Ssklower /*
3736401Ssklower  * ARGO TP
3836401Ssklower  *
3936401Ssklower  * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
4036401Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
4136401Ssklower  *
4236401Ssklower  * tp_input() gets an mbuf chain from ip.  Actually, not directly
4336401Ssklower  * from ip, because ip calls a net-level routine that strips off
4436401Ssklower  * the net header and then calls tp_input(), passing the proper type
4536401Ssklower  * of addresses for the address family in use (how it figures out
4636401Ssklower  * which AF is not yet determined.
4736401Ssklower  *
4836401Ssklower  * Decomposing the tpdu is some of the most laughable code.  The variable-length
4936401Ssklower  * parameters and the problem of non-aligned memory references
5036401Ssklower  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
5136401Ssklower  * to loop through the header and decompose it.
5236401Ssklower  *
5336401Ssklower  * The routine tp_newsocket() is called when a CR comes in for a listening
5436401Ssklower  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
5536401Ssklower  * "child" socket.  Most tpcb values are copied from the parent tpcb into
5636401Ssklower  * the child.
5736401Ssklower  *
5836401Ssklower  * Also in here is tp_headersize() (grot) which tells the expected size
5936401Ssklower  * of a tp header, to be used by other layers.  It's in here because it
6036401Ssklower  * uses the static structure tpdu_info.
6136401Ssklower  */
6236401Ssklower 
6336401Ssklower #include "param.h"
6444422Ssklower #include "systm.h"
6536401Ssklower #include "mbuf.h"
6636401Ssklower #include "socket.h"
6736401Ssklower #include "socketvar.h"
6836401Ssklower #include "domain.h"
6936401Ssklower #include "protosw.h"
7036401Ssklower #include "errno.h"
7136401Ssklower #include "time.h"
7236401Ssklower #include "kernel.h"
7336401Ssklower #include "types.h"
7445900Ssklower #include "iso.h"
7537469Ssklower #include "iso_errno.h"
7645900Ssklower #include "iso_pcb.h"
7737469Ssklower #include "tp_param.h"
7837469Ssklower #include "tp_timer.h"
7937469Ssklower #include "tp_stat.h"
8037469Ssklower #include "tp_pcb.h"
8137469Ssklower #include "argo_debug.h"
8237469Ssklower #include "tp_trace.h"
8337469Ssklower #include "tp_tpdu.h"
8436401Ssklower 
8545900Ssklower #include "../net/if.h"
8645900Ssklower #ifdef TRUE
8745900Ssklower #undef FALSE
8845900Ssklower #undef TRUE
8945900Ssklower #endif
9045900Ssklower #include "../netccitt/x25.h"
9145900Ssklower #include "../netccitt/pk.h"
9245900Ssklower #include "../netccitt/pk_var.h"
9345900Ssklower 
9436401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
9536401Ssklower 
9637469Ssklower /*
9737469Ssklower 	#ifdef lint
9837469Ssklower 	#undef ATTR
9937469Ssklower 	#define ATTR(X)ev_number
10037469Ssklower 	#endif lint
10137469Ssklower */
10236401Ssklower 
10336401Ssklower struct mbuf *
10436401Ssklower tp_inputprep(m)
10537469Ssklower 	register struct mbuf *m;
10636401Ssklower {
10737469Ssklower 	int hdrlen;
10836401Ssklower 
10936401Ssklower 	IFDEBUG(D_TPINPUT)
11037469Ssklower 		printf("tp_inputprep: m 0x%x\n", m) ;
11136401Ssklower 	ENDDEBUG
11236401Ssklower 
11336401Ssklower 	while(  m->m_len < 1 ) {
11436401Ssklower 		if( (m = m_free(m)) == MNULL ) {
11536401Ssklower 			return (struct mbuf *)0;
11636401Ssklower 		}
11736401Ssklower 	}
11837469Ssklower 	if(((int)m->m_data) & 0x3) {
11937469Ssklower 		/* If we are not 4-byte aligned, we have to be
12037469Ssklower 		 * above the beginning of the mbuf, and it is ok just
12137469Ssklower 		 * to slide it back.
12237469Ssklower 		 */
12337469Ssklower 		caddr_t ocp = m->m_data;
12436401Ssklower 
12537469Ssklower 		m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
12637469Ssklower 		ovbcopy(ocp, m->m_data, (unsigned)m->m_len);
12736401Ssklower 	}
12836401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
12936401Ssklower 
13037469Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf
13137469Ssklower 	   and that it is hdr->tpdu_li XXXXXXX!  */
13236401Ssklower 
13337469Ssklower 	hdrlen = 1 + *mtod( m, u_char *);
13436401Ssklower 
13536401Ssklower 	/*
13636401Ssklower 	 * now pull up the whole tp header
13736401Ssklower 	 */
13837469Ssklower 	if ( m->m_len < hdrlen) {
13937469Ssklower 		if ((m = m_pullup(m, hdrlen)) == MNULL ) {
14036401Ssklower 			IncStat(ts_recv_drop);
14136401Ssklower 			return (struct mbuf *)0;
14236401Ssklower 		}
14336401Ssklower 	}
14436401Ssklower 	IFDEBUG(D_INPUT)
14536401Ssklower 	printf(
14636401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
14737469Ssklower 		hdrlen, m->m_len);
14836401Ssklower 	ENDDEBUG
14936401Ssklower 	return m;
15036401Ssklower }
15136401Ssklower 
15236401Ssklower /* begin groan
15336401Ssklower  * -- this array and the following macros allow you to step through the
15436401Ssklower  * parameters of the variable part of a header
15536401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
15636401Ssklower  * should change, this array has to be rearranged
15736401Ssklower  */
15836401Ssklower 
15936401Ssklower #define TP_LEN_CLASS_0_INDEX	2
16036401Ssklower #define TP_MAX_DATA_INDEX 3
16136401Ssklower 
16236401Ssklower static u_char tpdu_info[][4] =
16336401Ssklower {
16436401Ssklower /*								length						 max data len */
16536401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
16636401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
16736401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
16836401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
16936401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
17036401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
17136401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
17236401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
17336401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
17436401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
17536401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
17636401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
17736401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
17836401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
17936401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
18036401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
18136401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
18236401Ssklower };
18336401Ssklower 
18442944Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
18543334Ssklower 	if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat); tpibrk();\
18642944Ssklower 	goto Whattodo; }
18742944Ssklower 
18843334Ssklower tpibrk() {}
18943334Ssklower 
19036401Ssklower /*
19136401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
19236401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
19336401Ssklower  */
19436401Ssklower 
19542944Ssklower #define WHILE_OPTIONS(P, hdr, format)\
19642944Ssklower {	register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
19742944Ssklower 	caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
19842944Ssklower 	for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
19942944Ssklower 		CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
20042944Ssklower 				respond, P - (caddr_t)hdr);\
20142944Ssklower 		if (P == PLIM) break;
20236401Ssklower 
20342944Ssklower #define END_WHILE_OPTIONS(P) } }
20436401Ssklower 
20536401Ssklower /* end groan */
20636401Ssklower 
20736401Ssklower /*
20836401Ssklower  * NAME:  tp_newsocket()
20936401Ssklower  *
21036401Ssklower  * CALLED FROM:
21136401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
21236401Ssklower  * is awaiting a  connection request
21336401Ssklower  *
21436401Ssklower  * FUNCTION and ARGUMENTS:
21536401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
21636401Ssklower  *  using a copy of the net level pcb for the parent socket.
21736401Ssklower  *  (so) is the parent socket.
21836401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
21936401Ssklower  *
22036401Ssklower  * RETURN VALUE:
22136401Ssklower  *  a new socket structure, being this end of the newly formed connection.
22236401Ssklower  *
22336401Ssklower  * SIDE EFFECTS:
22436401Ssklower  *  Sets a few things in the tpcb and net level pcb
22536401Ssklower  *
22636401Ssklower  * NOTES:
22736401Ssklower  */
22836401Ssklower static struct socket *
22936401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
23036401Ssklower 	struct socket				*so;
23136401Ssklower 	struct sockaddr				*fname;
23236401Ssklower 	u_int						cons_channel;
23336401Ssklower 	u_char						class_to_use;
23436401Ssklower 	u_int						netservice;
23536401Ssklower {
23636401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
23745900Ssklower 	register struct tp_pcb	*newtpcb;
23836401Ssklower 
23936401Ssklower 	/*
24036401Ssklower 	 * sonewconn() gets a new socket structure,
24136401Ssklower 	 * a new lower layer pcb and a new tpcb,
24236401Ssklower 	 * but the pcbs are unnamed (not bound)
24336401Ssklower 	 */
24436401Ssklower 	IFTRACE(D_NEWSOCK)
24538841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
24639196Ssklower 			so, tpcb, so->so_head, 0);
24736401Ssklower 	ENDTRACE
24836401Ssklower 
24940636Skarels 	if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
25036401Ssklower 		return so;
25136401Ssklower 	IFTRACE(D_NEWSOCK)
25238841Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
25338841Ssklower 			so, so->so_head, 0, 0);
25436401Ssklower 	ENDTRACE
25536401Ssklower 
25636401Ssklower 	IFDEBUG(D_NEWSOCK)
25737469Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n",
25837469Ssklower 				cons_channel, so);
25937469Ssklower 		dump_addr(fname);
26036401Ssklower 		{
26136401Ssklower 			struct socket *t, *head ;
26236401Ssklower 
26336401Ssklower 			head = so->so_head;
26436401Ssklower 			t = so;
26536401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26636401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
26736401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
26836401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
26936401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
27036401Ssklower 		}
27136401Ssklower 	ENDDEBUG
27236401Ssklower 
27336401Ssklower 	/*
27436401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
27536401Ssklower 	 */
27636401Ssklower 	newtpcb = sototpcb(so);
27736401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
27836401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
27936401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
28036401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
28136401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
28236401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
28337469Ssklower 	soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
28436401Ssklower 
28537469Ssklower 	if( /* old */ tpcb->tp_ucddata) {
28636401Ssklower 		/*
28737469Ssklower 		 * These data are the connect- , confirm- or disconnect- data.
28836401Ssklower 		 */
28936401Ssklower 		struct mbuf *conndata;
29036401Ssklower 
29137469Ssklower 		conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
29236401Ssklower 		IFDEBUG(D_CONN)
29336401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
29436401Ssklower 		ENDDEBUG
29537469Ssklower 		newtpcb->tp_ucddata = conndata;
29636401Ssklower 	}
29736401Ssklower 
29836401Ssklower 	tpcb = newtpcb;
29936401Ssklower 	tpcb->tp_state = TP_LISTENING;
30036401Ssklower 	tpcb->tp_class = class_to_use;
30136401Ssklower 	tpcb->tp_netservice = netservice;
30236401Ssklower 
30336401Ssklower 
30436401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
30536401Ssklower 	if ( fname ) {
30636401Ssklower 		/*
30736401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
30836401Ssklower 		 */
30936401Ssklower 		struct mbuf	*m;
31036401Ssklower 		int			err;
31136401Ssklower 
31236401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
31336401Ssklower 		if (m) {
31436401Ssklower 			/*
31536401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
31636401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
31736401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
31836401Ssklower 			 * sigh.
31936401Ssklower 			 */
32037469Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
32137469Ssklower 			m->m_len = fname->sa_len;
32236401Ssklower 
32336401Ssklower 			/* grot  : have to say the kernel can override params in
32436401Ssklower 			 * the passive open case
32536401Ssklower 			 */
32636401Ssklower 			tpcb->tp_dont_change_params = 0;
32736401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
32836401Ssklower 			m_free(m);
32936401Ssklower 
33036401Ssklower 			if (!err)
33136401Ssklower 				goto ok;
33236401Ssklower 		}
33336401Ssklower 		IFDEBUG(D_CONN)
33436401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
33536401Ssklower 				tpcb, so);
33636401Ssklower 		ENDDEBUG
33736401Ssklower 		(void) tp_detach(tpcb);
33836401Ssklower 		return 0;
33936401Ssklower 	}
34036401Ssklower ok:
34136401Ssklower 	IFDEBUG(D_TPINPUT)
34236401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
34336401Ssklower 			so, sototpcb(so));
34436401Ssklower 	ENDDEBUG
34536401Ssklower 	return so;
34636401Ssklower }
34736401Ssklower 
34845900Ssklower #ifndef TPCONS
34936401Ssklower tpcons_output()
35036401Ssklower {
35136401Ssklower 	return(0);
35236401Ssklower }
35336401Ssklower #endif !CONS
35436401Ssklower 
35536401Ssklower /*
35636401Ssklower  * NAME: 	tp_input()
35736401Ssklower  *
35836401Ssklower  * CALLED FROM:
35936401Ssklower  *  net layer input routine
36036401Ssklower  *
36136401Ssklower  * FUNCTION and ARGUMENTS:
36236401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
36336401Ssklower  *  is one. Create the appropriate type of event and call the driver.
36436401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
36536401Ssklower  *
36636401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
36736401Ssklower  * 	has been m_pullup-ed.
36836401Ssklower  *
36936401Ssklower  * RETURN VALUE: Nada
37036401Ssklower  *
37136401Ssklower  * SIDE EFFECTS:
37236401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
37336401Ssklower  *
37436401Ssklower  * NOTE:
37536401Ssklower  *  The initial value of acktime is 2 so that we will never
37636401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
37736401Ssklower  *  computation of the retransmission timer value, and so it
37836401Ssklower  *  mustn't be zero.
37936401Ssklower  *  2 seems like a reasonable minimum.
38036401Ssklower  */
38136401Ssklower ProtoHook
38239929Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
38336401Ssklower 	register	struct mbuf 	*m;
38436401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
38536401Ssklower 	u_int 						cons_channel;
38636401Ssklower 	int 						(*dgout_routine)();
38739929Ssklower 	int							ce_bit;
38836401Ssklower 
38936401Ssklower {
39036401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
39144947Ssklower 	register struct tpdu 	*hdr;
39236401Ssklower 	struct socket 			*so;
39336401Ssklower 	struct tp_event 		e;
39442944Ssklower 	int 					error = 0;
39536401Ssklower 	unsigned 				dutype;
39642944Ssklower 	u_short 				dref, sref = 0, acktime = 2, subseq = 0; /*VAX*/
39742944Ssklower 	u_char 					preferred_class = 0, class_to_use = 0;
39842944Ssklower 	u_char					opt, dusize = TP_DFL_TPDUSIZE, addlopt = 0, version;
39936401Ssklower #ifdef TP_PERF_MEAS
40038841Ssklower 	u_char					perf_meas;
40136401Ssklower #endif TP_PERF_MEAS
40244422Ssklower 	u_char					fsufxlen = 0, lsufxlen = 0, intercepted = 0;
40342944Ssklower 	caddr_t					fsufxloc = 0, lsufxloc = 0;
40442944Ssklower 	int						tpdu_len = 0;
40542944Ssklower 	u_int 					takes_data = FALSE;
40642944Ssklower 	u_int					fcc_present = FALSE;
40742944Ssklower 	int						errlen = 0;
40836401Ssklower 	struct tp_conn_param 	tpp;
40936401Ssklower 	int						tpcons_output();
41036401Ssklower 
41138841Ssklower again:
41244947Ssklower 	hdr = mtod(m, struct tpdu *);
41336401Ssklower #ifdef TP_PERF_MEAS
41438841Ssklower 	GET_CUR_TIME( &e.e_time ); perf_meas = 0;
41536401Ssklower #endif TP_PERF_MEAS
41636401Ssklower 
41736401Ssklower 	IFDEBUG(D_TPINPUT)
41836401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
41936401Ssklower 	ENDDEBUG
42036401Ssklower 
42136401Ssklower 
42236401Ssklower 	/*
42336401Ssklower 	 * get the actual tpdu length - necessary for monitoring
42436401Ssklower 	 * and for checksumming
42536401Ssklower 	 *
42636401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
42736401Ssklower 	 */
42836401Ssklower 
42936401Ssklower 	{ 	register struct mbuf *n=m;
43036401Ssklower #	ifdef ARGO_DEBUG
43136401Ssklower 		int chain_length = 0;
43236401Ssklower #	endif ARGO_DEBUG
43336401Ssklower 
43436401Ssklower 		for(;;) {
43536401Ssklower 			tpdu_len += n->m_len;
43636401Ssklower 			IFDEBUG(D_MBUF_MEAS)
43737469Ssklower 				if( n->m_flags & M_EXT) {
43836401Ssklower 					IncStat(ts_mb_cluster);
43936401Ssklower 				} else {
44036401Ssklower 					IncStat(ts_mb_small);
44136401Ssklower 				}
44236401Ssklower 				chain_length ++;
44336401Ssklower 			ENDDEBUG
44436401Ssklower 			if (n->m_next == MNULL ) {
44536401Ssklower 				break;
44636401Ssklower 			}
44736401Ssklower 			n = n->m_next;
44836401Ssklower 		}
44936401Ssklower 		IFDEBUG(D_MBUF_MEAS)
45036401Ssklower 			if(chain_length > 16)
45136401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
45236401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
45336401Ssklower 		ENDDEBUG
45436401Ssklower 	}
45536401Ssklower 	IFTRACE(D_TPINPUT)
45636401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
45736401Ssklower 			0);
45836401Ssklower 	ENDTRACE
45936401Ssklower 
46036401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
46136401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
46236401Ssklower 	dutype = (int)hdr->tpdu_type;
46336401Ssklower 
46436401Ssklower 	IFDEBUG(D_TPINPUT)
46536401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
46636401Ssklower 			cons_channel, dref);
46736401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
46836401Ssklower 	ENDDEBUG
46936401Ssklower 	IFTRACE(D_TPINPUT)
47036401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
47136401Ssklower 			cons_channel, dutype, dref, 0);
47236401Ssklower 	ENDTRACE
47336401Ssklower 
47436401Ssklower 
47536401Ssklower #ifdef ARGO_DEBUG
47636401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
47736401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
47836401Ssklower 			dutype, cons_channel, dref);
47936401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
48036401Ssklower 
48136401Ssklower 		IncStat(ts_inv_dutype);
48236401Ssklower 		goto discard;
48336401Ssklower 	}
48436401Ssklower #endif ARGO_DEBUG
48536401Ssklower 
48636401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
48736401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
48836401Ssklower 		2 );
48936401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
49036401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
49136401Ssklower 		 */
49236401Ssklower 
49336401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
49436401Ssklower 	 * at the beginning of connection establishment, and by
49536401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
49636401Ssklower 	 */
49736401Ssklower 	if ( dutype == CR_TPDU_type ) {
49836401Ssklower 		u_char alt_classes = 0;
49936401Ssklower 
50037469Ssklower 		preferred_class = 1 << hdr->tpdu_CRclass;
50136401Ssklower 		opt = hdr->tpdu_CRoptions;
50236401Ssklower 
50336401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
50436401Ssklower 
50536401Ssklower 			switch( vbptr(P)->tpv_code ) {
50636401Ssklower 
50736401Ssklower 			case	TPP_tpdu_size:
50836401Ssklower 				vb_getval(P, u_char, dusize);
50936401Ssklower 				IFDEBUG(D_TPINPUT)
51036401Ssklower 					printf("CR dusize 0x%x\n", dusize);
51136401Ssklower 				ENDDEBUG
51242944Ssklower 				/* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
51342944Ssklower 				if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
51442944Ssklower 						dusize = TP_DFL_TPDUSIZE;
51536401Ssklower 				break;
51636401Ssklower 			case	TPP_addl_opt:
51736401Ssklower 				vb_getval(P, u_char, addlopt);
51836401Ssklower 				break;
51936401Ssklower 			case	TPP_calling_sufx:
52036401Ssklower 				/* could use vb_getval, but we want to save the loc & len
52136401Ssklower 				 * for later use
52236401Ssklower 				 */
52336401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
52436401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
52536401Ssklower 				IFDEBUG(D_TPINPUT)
52636401Ssklower 					printf("CR fsufx:");
52736401Ssklower 					{ register int j;
52836401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
52936401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
53036401Ssklower 						}
53136401Ssklower 						printf("\n");
53236401Ssklower 					}
53336401Ssklower 				ENDDEBUG
53436401Ssklower 				break;
53536401Ssklower 			case	TPP_called_sufx:
53636401Ssklower 				/* could use vb_getval, but we want to save the loc & len
53736401Ssklower 				 * for later use
53836401Ssklower 				 */
53936401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
54036401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
54136401Ssklower 				IFDEBUG(D_TPINPUT)
54236401Ssklower 					printf("CR lsufx:");
54336401Ssklower 					{ register int j;
54436401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
54537469Ssklower 							printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
54636401Ssklower 						}
54736401Ssklower 						printf("\n");
54836401Ssklower 					}
54936401Ssklower 				ENDDEBUG
55036401Ssklower 				break;
55136401Ssklower 
55236401Ssklower #ifdef TP_PERF_MEAS
55336401Ssklower 			case	TPP_perf_meas:
55436401Ssklower 				vb_getval(P, u_char, perf_meas);
55536401Ssklower 				break;
55636401Ssklower #endif TP_PERF_MEAS
55736401Ssklower 
55836401Ssklower 			case	TPP_vers:
55936401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
56042944Ssklower 				/* COS tests says if version wrong, use default version!?XXX */
56136401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
56242491Ssklower 					E_TP_INV_PVAL, ts_inv_pval, setversion,
56342944Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
56442491Ssklower 			setversion:
56542491Ssklower 				version = vbval(P, u_char);
56636401Ssklower 				break;
56736401Ssklower 			case	TPP_acktime:
56836401Ssklower 				vb_getval(P, u_short, acktime);
56936401Ssklower 				acktime = ntohs(acktime);
57036401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
57136401Ssklower 				if((short)acktime <=0 )
57236401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
57336401Ssklower 				IFDEBUG(D_TPINPUT)
57436401Ssklower 					printf("CR acktime 0x%x\n", acktime);
57536401Ssklower 				ENDDEBUG
57636401Ssklower 				break;
57736401Ssklower 
57836401Ssklower 			case	TPP_alt_class:
57936401Ssklower 				{
58036401Ssklower 					u_char *aclass = 0;
58136401Ssklower 					register int i;
58242944Ssklower 					static u_char bad_alt_classes[5] =
58342944Ssklower 						{ ~0, ~3, ~5, ~0xf, ~0x1f};
58436401Ssklower 
58542944Ssklower 					aclass =
58642944Ssklower 						(u_char *) &(((struct tp_vbp *)P)->tpv_val);
58736401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
58842944Ssklower 						alt_classes |= (1<<((*aclass++)>>4));
58936401Ssklower 					}
59042944Ssklower 					CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
59142944Ssklower 						E_TP_INV_PVAL, ts_inv_aclass, respond,
59242944Ssklower 						((caddr_t)aclass) - (caddr_t)hdr);
59336401Ssklower 					IFDEBUG(D_TPINPUT)
59436401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
59536401Ssklower 					ENDDEBUG
59636401Ssklower 				}
59736401Ssklower 				break;
59836401Ssklower 
59936401Ssklower 			case	TPP_security:
60036401Ssklower 			case	TPP_residER:
60136401Ssklower 			case	TPP_priority:
60236401Ssklower 			case	TPP_transdelay:
60336401Ssklower 			case	TPP_throughput:
60436401Ssklower 			case	TPP_addl_info:
60536401Ssklower 			case	TPP_subseq:
60644947Ssklower 			default:
60736401Ssklower 				IFDEBUG(D_TPINPUT)
60836401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
60936401Ssklower 						 vbptr(P)->tpv_code);
61036401Ssklower 				ENDDEBUG
61136401Ssklower 				IncStat(ts_param_ignored);
61236401Ssklower 				break;
61336401Ssklower 
61436401Ssklower 			case	TPP_checksum:
61536401Ssklower 				IFDEBUG(D_TPINPUT)
61636401Ssklower 					printf("CR before cksum\n");
61736401Ssklower 				ENDDEBUG
61836401Ssklower 
61936401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
62036401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
62136401Ssklower 
62236401Ssklower 				IFDEBUG(D_TPINPUT)
62336401Ssklower 					printf("CR before cksum\n");
62436401Ssklower 				ENDDEBUG
62536401Ssklower 				break;
62636401Ssklower 			}
62736401Ssklower 
62836401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
62936401Ssklower 
63044422Ssklower 		if (lsufxlen == 0) {
63136401Ssklower 			/* can't look for a tpcb w/o any called sufx */
63236401Ssklower 			error =  E_TP_LENGTH_INVAL;
63336401Ssklower 			IncStat(ts_inv_sufx);
63436401Ssklower 			goto respond;
63536401Ssklower 		} else {
63644422Ssklower 			register struct tp_pcb *t;
63736401Ssklower 
63844601Ssklower 			for (t = tp_intercepts; t ; t = t->tp_nextlisten) {
63944422Ssklower 				if (laddr->sa_family != t->tp_nlproto->nlp_afamily)
64036401Ssklower 					continue;
64144601Ssklower 				if ((*t->tp_nlproto->nlp_cmpnetaddr)(
64244422Ssklower 						t->tp_npcb, laddr, TP_LOCAL)) {
64344422Ssklower 							intercepted = 1;
64444422Ssklower 							goto check_duplicate_cr;
64536401Ssklower 				}
64636401Ssklower 			}
64744601Ssklower 			for (t = tp_listeners; t ; t = t->tp_nextlisten)
64848872Ssklower 				if (lsufxlen == t->tp_lsuffixlen &&
64948872Ssklower 					bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0 &&
65044601Ssklower 					laddr->sa_family == t->tp_nlproto->nlp_afamily)
65144601Ssklower 						break;
65244422Ssklower 			CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
65336401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
65436401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
65536401Ssklower 				 * the fixed part (can't take the address of a bit field)
65636401Ssklower 				 */
65744601Ssklower 			IFDEBUG(D_TPINPUT)
65844601Ssklower 				printf("checking if dup CR\n");
65944601Ssklower 			ENDDEBUG
66044422Ssklower 		check_duplicate_cr:
66144422Ssklower 			tpcb = t;
66244422Ssklower 			for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
66344422Ssklower 				if (sref != t->tp_fref)
66444422Ssklower 					continue;
66544422Ssklower 				if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
66644422Ssklower 						t->tp_npcb, faddr, TP_FOREIGN)) {
66744422Ssklower 					IFDEBUG(D_TPINPUT)
66844422Ssklower 						printf("duplicate CR discarded\n");
66944422Ssklower 					ENDDEBUG
67044422Ssklower 					goto discard;
67144422Ssklower 				}
67244422Ssklower 			}
67344422Ssklower 			IFTRACE(D_TPINPUT)
67444422Ssklower 				tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
67544422Ssklower 					tpcb, *lsufxloc, tpcb->tp_state, 0);
67644422Ssklower 			ENDTRACE
67736401Ssklower 		}
67836401Ssklower 
67936401Ssklower 		/*
68036401Ssklower 		 * WE HAVE A TPCB
68136401Ssklower 		 * already know that the classes in the CR match at least
68236401Ssklower 		 * one class implemented, but we don't know yet if they
68336401Ssklower 		 * include any classes permitted by this server.
68436401Ssklower 		 */
68536401Ssklower 
68636401Ssklower 		IFDEBUG(D_TPINPUT)
68736401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
68836401Ssklower 		ENDDEBUG
68936401Ssklower 		IFDEBUG(D_CONN)
69036401Ssklower 			printf(
69136401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
69236401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
69336401Ssklower 		ENDDEBUG
69436401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
69536401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
69636401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
69736401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
69836401Ssklower 
69936401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
70036401Ssklower 
70136401Ssklower 		{
70236401Ssklower 			tpp = tpcb->_tp_param;
70336401Ssklower 			tpp.p_class = class_to_use;
70436401Ssklower 			tpp.p_tpdusize = dusize;
70536401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
70636401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
70736401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
70836401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
70942491Ssklower 			tpp.p_version = version;
71036401Ssklower #ifdef notdef
71136401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
71236401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
71336401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
71436401Ssklower #endif notdef
71536401Ssklower 
71636401Ssklower 		CHECK(
71736401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
71836401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
71936401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
72036401Ssklower 				/* ^ more or less the location of class */
72136401Ssklower 			)
72236401Ssklower 		}
72336401Ssklower 		IFTRACE(D_CONN)
72436401Ssklower 			tptrace(TPPTmisc,
72536401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
72636401Ssklower 				class_to_use,
72736401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
72836401Ssklower 				);
72936401Ssklower 		ENDTRACE
73036401Ssklower 		CHECK(
73136401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
73236401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
73336401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
73436401Ssklower 				/* ^ more or less the location of class */
73536401Ssklower 			)
73636401Ssklower 		IFDEBUG(D_CONN)
73736401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
73836401Ssklower 				tpcb, tpcb->tp_flags);
73936401Ssklower 		ENDDEBUG
74036401Ssklower 		takes_data = TRUE;
74136401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
74236401Ssklower 		e.ev_number = CR_TPDU;
74336401Ssklower 
74436401Ssklower 		so = tpcb->tp_sock;
74536401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
74644422Ssklower 			struct tp_pcb *parent_tpcb = tpcb;
74736401Ssklower 			/*
74836401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
74936401Ssklower 			 * for this newborn connection, and fill in all the values.
75036401Ssklower 			 */
75136401Ssklower 			IFDEBUG(D_CONN)
75236401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
75336401Ssklower 					so, laddr, faddr, cons_channel);
75436401Ssklower 			ENDDEBUG
75536401Ssklower 			if( (so =
75636401Ssklower 				tp_newsocket(so, faddr, cons_channel,
75736401Ssklower 					class_to_use,
75837469Ssklower 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
75937469Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
76036401Ssklower 					) == (struct socket *)0 ) {
76136401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
76236401Ssklower 				 * the tp entity is concerned, the only differences
76337469Ssklower 				 * are CO vs CL
76436401Ssklower 				 */
76536401Ssklower 				IFDEBUG(D_CONN)
76636401Ssklower 					printf("tp_newsocket returns 0\n");
76736401Ssklower 				ENDDEBUG
76836401Ssklower 				goto discard;
76936401Ssklower 			}
77036401Ssklower 			tpcb = sototpcb(so);
77144601Ssklower 			insque(tpcb, parent_tpcb);
77236401Ssklower 
77336401Ssklower 			/*
77437469Ssklower 			 * Stash the addresses in the net level pcb
77536401Ssklower 			 * kind of like a pcbconnect() but don't need
77636401Ssklower 			 * or want all those checks.
77736401Ssklower 			 */
77836401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
77936401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
78036401Ssklower 
78137469Ssklower 			/* stash the f suffix in the new tpcb */
78238841Ssklower 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
78344422Ssklower 			/* l suffix is already there, unless this is an intercept case */
78444422Ssklower 			if (intercepted)
78544422Ssklower 				bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
78637469Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
78737469Ssklower 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
78838841Ssklower 			(tpcb->tp_nlproto->nlp_putsufx)
78938841Ssklower 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
79036401Ssklower #ifdef TP_PERF_MEAS
79136401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
79236401Ssklower 				/* ok, let's create an mbuf for stashing the
79336401Ssklower 				 * statistics if one doesn't already exist
79436401Ssklower 				 */
79536401Ssklower 				(void) tp_setup_perf(tpcb);
79636401Ssklower 			}
79736401Ssklower #endif TP_PERF_MEAS
79836401Ssklower 			tpcb->tp_fref = sref;
79936401Ssklower 
80036401Ssklower 			/* We've already checked for consistency with the options
80136401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
80236401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
80336401Ssklower 			 * Now we set the options in the new socket's tpcb.
80436401Ssklower 			 */
80536401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
80636401Ssklower 
80736401Ssklower 			if(!tpcb->tp_use_checksum)
80836401Ssklower 				IncStat(ts_csum_off);
80936401Ssklower 			if(tpcb->tp_xpd_service)
81036401Ssklower 				IncStat(ts_use_txpd);
81136401Ssklower 			if(tpcb->tp_xtd_format)
81236401Ssklower 				IncStat(ts_xtd_fmt);
81336401Ssklower 
81436401Ssklower 			/*
81536401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
81636401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
81736401Ssklower 			 */
81836401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
81936401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
82036401Ssklower 			tpcb->tp_peer_acktime = acktime;
82136401Ssklower 
82236401Ssklower 			/*
82336401Ssklower 			 * The following kludge is used to test retransmissions and
82436401Ssklower 			 * timeout during connection establishment.
82536401Ssklower 			 */
82636401Ssklower 			IFDEBUG(D_ZDREF)
82736401Ssklower 				IncStat(ts_zdebug);
82837469Ssklower 				/*tpcb->tp_fref = 0;*/
82936401Ssklower 			ENDDEBUG
83036401Ssklower 		}
83136401Ssklower 		IncStat(ts_CR_rcvd);
83239929Ssklower 		if (!tpcb->tp_cebit_off) {
83339929Ssklower 			tpcb->tp_win_recv = tp_start_win << 8;
83439929Ssklower 			tpcb->tp_cong_sample.cs_size = 0;
83539929Ssklower 			LOCAL_CREDIT(tpcb);
83639929Ssklower 			CONG_INIT_SAMPLE(tpcb);
83739929Ssklower 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
83839929Ssklower 		}
83939929Ssklower 		tpcb->tp_ackrcvd = 0;
84036401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
84136401Ssklower 		/*
84236401Ssklower 		 * ER TPDUs have to be recognized separately
84336401Ssklower 		 * because they don't necessarily have a tpcb
84436401Ssklower 		 * with them and we don't want err out looking for such
84536401Ssklower 		 * a beast.
84636401Ssklower 		 * We could put a bunch of little kludges in the
84736401Ssklower 		 * next section of code so it would avoid references to tpcb
84836401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
84936401Ssklower 		 * mess up code for data transfer.
85036401Ssklower 		 */
85136401Ssklower 		IncStat(ts_ER_rcvd);
85236401Ssklower 		e.ev_number = ER_TPDU;
85336401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
85448749Ssklower 		takes_data = FALSE;
85536401Ssklower 	} else {
85636401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
85736401Ssklower 
85836401Ssklower 		/* In the next 4 checks,
85936401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
86036401Ssklower 		 * the fixed part (can't take the address of a bit field)
86136401Ssklower 		 */
86245900Ssklower #ifdef old_history
86336401Ssklower 		if(cons_channel) {
86445900Ssklower #ifdef NARGOXTWENTYFIVE
86536401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
86636401Ssklower 
86736401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
86836401Ssklower 			/* Problem:  We may have a legit
86936401Ssklower 			 * error situation yet we may or may not have
87036401Ssklower 			 * a correspondence between the tpcb and the vc,
87136401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
87236401Ssklower 			 *          <---  DR
87336401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
87436401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
87536401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
87636401Ssklower 			 * Sigh.
87736401Ssklower 			 */
87836401Ssklower 
87936401Ssklower 			/* I don't know about this error value */
88036401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
88136401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
88236401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
88336401Ssklower #else
88436401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
88545900Ssklower #endif
88645900Ssklower 		} else
88745900Ssklower 			/* we've now made the error reporting thing check for
88845900Ssklower 			multiple channels and not close out if more than
88945900Ssklower 			one in use */
89045900Ssklower #endif old_history
89145900Ssklower 		{
89236401Ssklower 
89336401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
89442944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89536401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89636401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
89742944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
89836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
89936401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
90042944Ssklower 				E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
90136401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
90236401Ssklower 		}
90336401Ssklower 
90436401Ssklower 		IFDEBUG(D_TPINPUT)
90536401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
90636401Ssklower 		ENDDEBUG
90736401Ssklower 
90836401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
90936401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
91036401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
91136401Ssklower 			ts_inv_dref, respond,
91236401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
91336401Ssklower 
91436401Ssklower 		IFDEBUG(D_TPINPUT)
91536401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
91636401Ssklower 		ENDDEBUG
91736401Ssklower 		/*
91836401Ssklower 		 * At this point the state of the dref could be
91936401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
92036401Ssklower 		 *		   for example, DC may arrive after the close() has detached
92136401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
92236401Ssklower 		 * OPENING : a tpcb exists but no timers yet
92336401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
92436401Ssklower 		 */
92536401Ssklower 
92639929Ssklower         if (!tpcb->tp_cebit_off)
92739929Ssklower             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
92839929Ssklower 
92936401Ssklower 		dusize = tpcb->tp_tpdusize;
93036401Ssklower 
93136401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
93236401Ssklower 
93336401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
93436401Ssklower 
93537469Ssklower #define caseof(x,y) case (((x)<<8)+(y))
93636401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
93736401Ssklower 
93836401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
93936401Ssklower 					/* not in class 0; 1 octet */
94036401Ssklower 					vb_getval(P, u_char, addlopt);
94136401Ssklower 					break;
94236401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
94342944Ssklower 				{
94442944Ssklower 					u_char odusize = dusize;
94536401Ssklower 					vb_getval(P, u_char, dusize);
94642944Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE ||
94742944Ssklower 							dusize > TP_MAX_TPDUSIZE || dusize > odusize),
94842944Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
94942944Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
95036401Ssklower 					IFDEBUG(D_TPINPUT)
95136401Ssklower 						printf("CC dusize 0x%x\n", dusize);
95236401Ssklower 					ENDDEBUG
95342944Ssklower 				}
95436401Ssklower 					break;
95536401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
95636401Ssklower 					IFDEBUG(D_TPINPUT)
95736401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
95836401Ssklower 					ENDDEBUG
95936401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
96036401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
96136401Ssklower 					break;
96236401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
96336401Ssklower 					/* class 4 only, 2 octets */
96436401Ssklower 					vb_getval(P, u_short, acktime);
96544947Ssklower 					acktime = ntohs(acktime);
96636401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
96736401Ssklower 					if( (short)acktime <=0 )
96836401Ssklower 						acktime = 2;
96936401Ssklower 					break;
97036401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
97136401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
97236401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
97336401Ssklower 					IFDEBUG(D_TPINPUT)
97436401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
97536401Ssklower 					ENDDEBUG
97636401Ssklower 					break;
97736401Ssklower 
97836401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
97936401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
98036401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
98136401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
98236401Ssklower 					if( tpcb->tp_use_checksum )  {
98336401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
98436401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
98536401Ssklower 					}
98636401Ssklower 					break;
98736401Ssklower 
98836401Ssklower 			/*  this is different from the above because in the context
98936401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
99036401Ssklower 			 */
99136401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
99236401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
99336401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
99436401Ssklower 					if( tpcb->tp_use_checksum )  {
99537469Ssklower 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
99636401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
99736401Ssklower 					}
99836401Ssklower 					break;
99936401Ssklower #ifdef notdef
100036401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
100136401Ssklower 				/* ignore - its length and meaning are
100236401Ssklower 				 * user defined and there's no way
100336401Ssklower 				 * to pass this info to the user anyway
100436401Ssklower 				 */
100536401Ssklower 				break;
100636401Ssklower #endif notdef
100736401Ssklower 
100836401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
100936401Ssklower 				/* used after reduction of window */
101036401Ssklower 				vb_getval(P, u_short, subseq);
101136401Ssklower 				subseq = ntohs(subseq);
101236401Ssklower 				IFDEBUG(D_ACKRECV)
101336401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
101436401Ssklower 				ENDDEBUG
101536401Ssklower 				break;
101636401Ssklower 
101736401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
101836401Ssklower 				{
101936401Ssklower 					u_int 	ylwe;
102036401Ssklower 					u_short ysubseq, ycredit;
102136401Ssklower 
102236401Ssklower 					fcc_present = TRUE;
102336401Ssklower 					vb_getval(P, u_int,	 	ylwe);
102436401Ssklower 					vb_getval(P, u_short, 	ysubseq);
102536401Ssklower 					vb_getval(P, u_short, 	ycredit);
102636401Ssklower 					ylwe = ntohl(ylwe);
102736401Ssklower 					ysubseq = ntohs(ysubseq);
102836401Ssklower 					ycredit = ntohs(ycredit);
102936401Ssklower 					IFDEBUG(D_ACKRECV)
103036401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
103136401Ssklower 							ylwe, ysubseq, ycredit);
103236401Ssklower 					ENDDEBUG
103336401Ssklower 				}
103436401Ssklower 				break;
103536401Ssklower 
103636401Ssklower 			default:
103736401Ssklower 				IFDEBUG(D_TPINPUT)
103836401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
103936401Ssklower 						dutype, vbptr(P)->tpv_code);
104036401Ssklower 				ENDDEBUG
104136401Ssklower 				IFTRACE(D_TPINPUT)
104236401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
104336401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
104436401Ssklower 				ENDTRACE
104536401Ssklower 				IncStat(ts_param_ignored);
104636401Ssklower 				break;
104736401Ssklower #undef caseof
104836401Ssklower 		}
104936401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
105036401Ssklower 
105136401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
105236401Ssklower 
105336401Ssklower 		switch( hdr->tpdu_type ) {
105436401Ssklower 		case CC_TPDU_type:
105536401Ssklower 			/* If CC comes back with an unacceptable class
105636401Ssklower 			 * respond with a DR or ER
105736401Ssklower 			 */
105836401Ssklower 
105936401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
106036401Ssklower 
106136401Ssklower 			{
106236401Ssklower 				tpp = tpcb->_tp_param;
106336401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
106436401Ssklower 				tpp.p_tpdusize = dusize;
106536401Ssklower 				tpp.p_dont_change_params = 0;
106636401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
106736401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
106836401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
106936401Ssklower #ifdef notdef
107036401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
107136401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
107236401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
107336401Ssklower #endif notdef
107436401Ssklower 
107536401Ssklower 			CHECK(
107636401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
107736401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
107836401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
107936401Ssklower 					/* ^ more or less the location of class */
108036401Ssklower 				)
108136401Ssklower 			IFTRACE(D_CONN)
108236401Ssklower 				tptrace(TPPTmisc,
108336401Ssklower 					"after 1 consist class, out, tpconsout",
108436401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
108536401Ssklower 					);
108636401Ssklower 			ENDTRACE
108736401Ssklower 			CHECK(
108836401Ssklower 				((class_to_use == TP_CLASS_0)&&
108936401Ssklower 					(dgout_routine != tpcons_output)),
109036401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
109136401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
109236401Ssklower 					/* ^ more or less the location of class */
109336401Ssklower 				)
109445900Ssklower #ifdef TPCONS
109545900Ssklower 				if (tpcb->tp_netservice == ISO_CONS &&
109645900Ssklower 					class_to_use == TP_CLASS_0) {
109745900Ssklower 					struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
109845900Ssklower 					struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
109945900Ssklower 					lcp->lcd_flags &= ~X25_DG_CIRCUIT;
110045900Ssklower 				}
110145900Ssklower #endif
110236401Ssklower 			}
110336401Ssklower 			if( ! tpcb->tp_use_checksum)
110436401Ssklower 				IncStat(ts_csum_off);
110536401Ssklower 			if(tpcb->tp_xpd_service)
110636401Ssklower 				IncStat(ts_use_txpd);
110736401Ssklower 			if(tpcb->tp_xtd_format)
110836401Ssklower 				IncStat(ts_xtd_fmt);
110936401Ssklower 
111036401Ssklower 			IFTRACE(D_CONN)
111136401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
111236401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
111336401Ssklower 					hdr->tpdu_CCclass);
111436401Ssklower 			ENDTRACE
111536401Ssklower 
111636401Ssklower 			/*
111736401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
111836401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
111936401Ssklower 			 * It would be nice if the arguments to this
112036401Ssklower 			 * were more reasonable.
112136401Ssklower 			 */
112236401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
112336401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
112436401Ssklower 
112536401Ssklower 
112636401Ssklower 			/* if called or calling suffices appeared on the CC,
112736401Ssklower 			 * they'd better jive with what's in the pcb
112836401Ssklower 			 */
112936401Ssklower 			if( fsufxlen ) {
113036401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
113136401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
113236401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
113336401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
113436401Ssklower 			}
113536401Ssklower 			if( lsufxlen ) {
113636401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
113736401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
113836401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
113936401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
114036401Ssklower 			}
114136401Ssklower 
114236401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
114336401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
114436401Ssklower 			takes_data = TRUE;
114536401Ssklower 			e.ev_number = CC_TPDU;
114636401Ssklower 			IncStat(ts_CC_rcvd);
114736401Ssklower 			break;
114836401Ssklower 
114936401Ssklower 		case DC_TPDU_type:
115036401Ssklower 			if (sref != tpcb->tp_fref)
115136401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
115236401Ssklower 					sref, tpcb->tp_fref);
115336401Ssklower 
115436401Ssklower 			CHECK( (sref != tpcb->tp_fref),
115542944Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, discard,
115636401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
115742944Ssklower 
115836401Ssklower 			e.ev_number = DC_TPDU;
115936401Ssklower 			IncStat(ts_DC_rcvd);
116036401Ssklower 			break;
116136401Ssklower 
116236401Ssklower 		case DR_TPDU_type:
116336401Ssklower 			IFTRACE(D_TPINPUT)
116436401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
116536401Ssklower 			ENDTRACE
116642944Ssklower 			if (sref != tpcb->tp_fref) {
116736401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
116836401Ssklower 					sref, tpcb->tp_fref);
116942944Ssklower 			}
117036401Ssklower 
117142944Ssklower 			CHECK( (sref != 0 && sref != tpcb->tp_fref &&
117242944Ssklower 					tpcb->tp_state != TP_CRSENT),
117342944Ssklower 				(TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
117436401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
117536401Ssklower 
117636401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
117736401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
117836401Ssklower 			takes_data = TRUE;
117936401Ssklower 			e.ev_number = DR_TPDU;
118036401Ssklower 			IncStat(ts_DR_rcvd);
118136401Ssklower 			break;
118236401Ssklower 
118336401Ssklower 		case ER_TPDU_type:
118436401Ssklower 			IFTRACE(D_TPINPUT)
118536401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
118636401Ssklower 			ENDTRACE
118736401Ssklower 			e.ev_number = ER_TPDU;
118836401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
118936401Ssklower 			IncStat(ts_ER_rcvd);
119036401Ssklower 			break;
119136401Ssklower 
119236401Ssklower 		case AK_TPDU_type:
119336401Ssklower 
119436401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
119536401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
119636401Ssklower 
119736401Ssklower 			if (tpcb->tp_xtd_format) {
119836401Ssklower #ifdef BYTE_ORDER
119936401Ssklower 				union seq_type seqeotX;
120036401Ssklower 
120136401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
120236401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
120336401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
120436401Ssklower #else
120536401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
120636401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
120736401Ssklower #endif BYTE_ORDER
120836401Ssklower 			} else {
120936401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
121036401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
121136401Ssklower 			}
121236401Ssklower 			IFTRACE(D_TPINPUT)
121336401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
121436401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
121536401Ssklower 					subseq, fcc_present);
121636401Ssklower 			ENDTRACE
121736401Ssklower 
121836401Ssklower 			e.ev_number = AK_TPDU;
121936401Ssklower 			IncStat(ts_AK_rcvd);
122036401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
122136401Ssklower 			break;
122236401Ssklower 
122336401Ssklower 		case XAK_TPDU_type:
122436401Ssklower 			if (tpcb->tp_xtd_format) {
122536401Ssklower #ifdef BYTE_ORDER
122636401Ssklower 				union seq_type seqeotX;
122736401Ssklower 
122836401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
122936401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
123036401Ssklower #else
123136401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
123236401Ssklower #endif BYTE_ORDER
123336401Ssklower 			} else {
123436401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
123536401Ssklower 			}
123636401Ssklower 			e.ev_number = XAK_TPDU;
123736401Ssklower 			IncStat(ts_XAK_rcvd);
123836401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
123936401Ssklower 			break;
124036401Ssklower 
124136401Ssklower 		case XPD_TPDU_type:
124236401Ssklower 			if (tpcb->tp_xtd_format) {
124336401Ssklower #ifdef BYTE_ORDER
124436401Ssklower 				union seq_type seqeotX;
124536401Ssklower 
124636401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
124736401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
124836401Ssklower #else
124936401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
125036401Ssklower #endif BYTE_ORDER
125136401Ssklower 			} else {
125236401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
125336401Ssklower 			}
125436401Ssklower 			takes_data = TRUE;
125536401Ssklower 			e.ev_number = XPD_TPDU;
125636401Ssklower 			IncStat(ts_XPD_rcvd);
125736401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
125836401Ssklower 			break;
125936401Ssklower 
126036401Ssklower 		case DT_TPDU_type:
126136401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
126236401Ssklower 			   * A little crude but it works.
126336401Ssklower 			   */
126436401Ssklower 
126536401Ssklower 				IFDEBUG(D_DROP)
126636401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
126736401Ssklower 						IncStat(ts_ydebug);
126836401Ssklower 						goto discard;
126936401Ssklower 					}
127036401Ssklower 				ENDDEBUG
127136401Ssklower 			}
127236401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
127336401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
127436401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
127536401Ssklower 			} else if (tpcb->tp_xtd_format) {
127636401Ssklower #ifdef BYTE_ORDER
127736401Ssklower 				union seq_type seqeotX;
127836401Ssklower 
127936401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
128036401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
128136401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
128236401Ssklower #else
128336401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
128436401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
128536401Ssklower #endif BYTE_ORDER
128636401Ssklower 			} else {
128736401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
128836401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
128936401Ssklower 			}
129036401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
129136401Ssklower 				IncStat(ts_eot_input);
129236401Ssklower 			takes_data = TRUE;
129336401Ssklower 			e.ev_number = DT_TPDU;
129436401Ssklower 			IncStat(ts_DT_rcvd);
129536401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
129636401Ssklower 			break;
129736401Ssklower 
129836401Ssklower 		case GR_TPDU_type:
129936401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
130036401Ssklower 			/* drop through */
130136401Ssklower 		default:
130236401Ssklower 			/* this should NEVER happen because there is a
130336401Ssklower 			 * check for dutype well above here
130436401Ssklower 			 */
130536401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
130636401Ssklower 			IFDEBUG(D_TPINPUT)
130736401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
130836401Ssklower 			ENDDEBUG
130936401Ssklower 			IncStat(ts_inv_dutype);
131036401Ssklower 			goto respond;
131136401Ssklower 		}
131236401Ssklower 	}
131336401Ssklower 	/* peel off the tp header;
131436401Ssklower 	 * remember that the du_li doesn't count itself.
131536401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
131636401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
131736401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
131836401Ssklower 	 */
131936401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
132037469Ssklower 	m->m_data += ((int)hdr->tpdu_li + 1);
132136401Ssklower 
132237469Ssklower 	if (takes_data) {
132337469Ssklower 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
132437469Ssklower 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
132548749Ssklower 		struct {
132648749Ssklower 			struct tp_disc_reason dr;
132748749Ssklower 			struct cmsghdr x_hdr;
132848749Ssklower 		} x;
132948749Ssklower #define c_hdr x.x_hdr
133048749Ssklower 		register struct mbuf *n;
133136401Ssklower 
133237469Ssklower 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
133337469Ssklower 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
133436401Ssklower 		switch( hdr->tpdu_type ) {
133537469Ssklower 
133636401Ssklower 		case CR_TPDU_type:
133737469Ssklower 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
133837469Ssklower 			goto make_control_msg;
133937469Ssklower 
134036401Ssklower 		case CC_TPDU_type:
134137469Ssklower 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
134237469Ssklower 			goto make_control_msg;
134337469Ssklower 
134436401Ssklower 		case DR_TPDU_type:
134548749Ssklower 			x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
134648749Ssklower 			x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
134748749Ssklower 			x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
134848749Ssklower 			x.dr.dr_reason = hdr->tpdu_DRreason;
134937469Ssklower 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
135037469Ssklower 		make_control_msg:
135148749Ssklower 			datalen += sizeof(c_hdr);
135248749Ssklower 			c_hdr.cmsg_len = datalen;
135337469Ssklower 			c_hdr.cmsg_level = SOL_TRANSPORT;
135437469Ssklower 			mbtype = MT_CONTROL;
135543334Ssklower 			MGET(n, M_DONTWAIT, MT_DATA);
135648749Ssklower 			if (n == 0)
135748749Ssklower 				{m_freem(m); m = 0; datalen = 0; goto invoke; }
135848749Ssklower 			if (hdr->tpdu_type == DR_TPDU_type) {
135948749Ssklower 				datalen += sizeof(x) - sizeof(c_hdr);
136048749Ssklower 				bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
136148749Ssklower 			} else
136248749Ssklower 				bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
136348749Ssklower 					  n->m_len = sizeof(c_hdr));
136448749Ssklower 			n->m_next = m;
136548749Ssklower 			m = n;
136637469Ssklower 			/* FALLTHROUGH */
136737469Ssklower 
136836401Ssklower 		case XPD_TPDU_type:
136937469Ssklower 			if (mbtype != MT_CONTROL)
137037469Ssklower 				mbtype = MT_OOBDATA;
137137469Ssklower 			m->m_flags |= M_EOR;
137237469Ssklower 			/* FALLTHROUGH */
137337469Ssklower 
137436401Ssklower 		case DT_TPDU_type:
137537469Ssklower 			for (n = m; n; n = n->m_next) {
137637469Ssklower 				MCHTYPE(n, mbtype);
137737469Ssklower 			}
137843334Ssklower 		invoke:
137937469Ssklower 			e.ATTR(DT_TPDU).e_datalen = datalen;
138036401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
138136401Ssklower 			break;
138236401Ssklower 
138336401Ssklower 		default:
138436401Ssklower 			printf(
138536401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
138636401Ssklower 				hdr->tpdu_type, takes_data, m);
138736401Ssklower 			break;
138836401Ssklower 		}
138936401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
139036401Ssklower 		m = MNULL;
139136401Ssklower 	}
139236401Ssklower 
139336401Ssklower 	IncStat(ts_tpdu_rcvd);
139436401Ssklower 
139536401Ssklower 	IFDEBUG(D_TPINPUT)
139636401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
139736401Ssklower 			tpcb->tp_state, e.ev_number, m );
139836401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
139936401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
140036401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
140136401Ssklower 	ENDDEBUG
140236401Ssklower 
140336401Ssklower 	error = tp_driver(tpcb, &e);
140436401Ssklower 
140536401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
140636401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
140736401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
140836401Ssklower 		tpcb->tp_sock->so_error = error;
140936401Ssklower 
141036401Ssklower 	/* Kludge to keep the state tables under control (adding
141136401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
141236401Ssklower 	 * the data would have exploded the tables and made a big mess ).
141336401Ssklower 	 */
141436401Ssklower 	switch(e.ev_number) {
141536401Ssklower 		case CC_TPDU:
141636401Ssklower 		case DR_TPDU:
141736401Ssklower 		case CR_TPDU:
141836401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
141936401Ssklower 			IFDEBUG(D_TPINPUT)
142036401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
142136401Ssklower 				m, takes_data);
142236401Ssklower 			ENDDEBUG
142336401Ssklower 			break;
142436401Ssklower 		default:
142536401Ssklower 			break;
142636401Ssklower 	}
142736401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
142836401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
142936401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
143036401Ssklower 	 */
143136401Ssklower 
143236401Ssklower separate:
143336401Ssklower 	if ( takes_data == 0 )  {
143436401Ssklower 		ASSERT( m != MNULL );
143536401Ssklower 		/*
143636401Ssklower 		 * we already peeled off the prev. tp header so
143736401Ssklower 		 * we can just pull up some more and repeat
143836401Ssklower 		 */
143936401Ssklower 
144037469Ssklower 		if( m = tp_inputprep(m) ) {
144136401Ssklower 		IFDEBUG(D_TPINPUT)
144236401Ssklower 			hdr = mtod(m, struct tpdu *);
144336401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
144436401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
144536401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
144636401Ssklower 		ENDDEBUG
144736401Ssklower 
144836401Ssklower 			IncStat(ts_concat_rcvd);
144936401Ssklower 			goto again;
145036401Ssklower 		}
145136401Ssklower 	}
145236401Ssklower 	if ( m != MNULL ) {
145336401Ssklower 		IFDEBUG(D_TPINPUT)
145436401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
145536401Ssklower 		ENDDEBUG
145636401Ssklower 		m_freem(m);
145736401Ssklower 		IFDEBUG(D_TPINPUT)
145836401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
145936401Ssklower 		ENDDEBUG
146036401Ssklower 	}
146136401Ssklower 	return (ProtoHook) tpcb;
146236401Ssklower 
146336401Ssklower discard:
146436401Ssklower 	/* class 4: drop the tpdu */
146536401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
146636401Ssklower 	 * to which connection it applies
146736401Ssklower 	 */
146836401Ssklower 	IFDEBUG(D_TPINPUT)
146936401Ssklower 		printf("tp_input DISCARD\n");
147036401Ssklower 	ENDDEBUG
147136401Ssklower 	IFTRACE(D_TPINPUT)
147236401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
147336401Ssklower 	ENDTRACE
147436401Ssklower 	m_freem(m);
147536401Ssklower 	IncStat(ts_recv_drop);
147636401Ssklower 	return (ProtoHook)0;
147736401Ssklower 
147842944Ssklower nonx_dref:
147942944Ssklower 	switch (dutype) {
148042944Ssklower 	default:
148142944Ssklower 		goto discard;
148242944Ssklower 	case CC_TPDU_type:
148342944Ssklower 		/* error = E_TP_MISM_REFS; */
148442944Ssklower 		break;
148542944Ssklower 	case DR_TPDU_type:
148642944Ssklower 		error |= TP_ERROR_SNDC;
148742944Ssklower 	}
148836401Ssklower respond:
148943334Ssklower 	IFDEBUG(D_TPINPUT)
149042944Ssklower 		printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
149136401Ssklower 	ENDDEBUG
149236401Ssklower 	IFTRACE(D_TPINPUT)
149342944Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
149436401Ssklower 	ENDTRACE
149542944Ssklower 	if (sref == 0)
149636401Ssklower 		goto discard;
149737469Ssklower 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
149842944Ssklower 				(struct sockaddr_iso *)laddr, m, errlen, tpcb,
149937469Ssklower 				(int)cons_channel, dgout_routine);
150036401Ssklower 	IFDEBUG(D_ERROR_EMIT)
150136401Ssklower 		printf("tp_input after error_emit\n");
150236401Ssklower 	ENDDEBUG
150336401Ssklower 
150436401Ssklower #ifdef lint
150536401Ssklower 	printf("",sref,opt);
150636401Ssklower #endif lint
150736401Ssklower 	IncStat(ts_recv_drop);
150836401Ssklower 	return (ProtoHook)0;
150936401Ssklower }
151036401Ssklower 
151136401Ssklower 
151236401Ssklower /*
151336401Ssklower  * NAME: tp_headersize()
151436401Ssklower  *
151536401Ssklower  * CALLED FROM:
151636401Ssklower  *  tp_emit() and tp_sbsend()
151736401Ssklower  *  TP needs to know the header size so it can figure out how
151836401Ssklower  *  much data to put in each tpdu.
151936401Ssklower  *
152036401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
152136401Ssklower  *  For a given connection, represented by (tpcb), and
152236401Ssklower  *  tpdu type (dutype), return the size of a tp header.
152336401Ssklower  *
152436401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
152536401Ssklower  *
152636401Ssklower  * SIDE EFFECTS:
152736401Ssklower  *
152836401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
152936401Ssklower  */
153036401Ssklower int
153136401Ssklower tp_headersize(dutype, tpcb)
153236401Ssklower 	int 			dutype;
153336401Ssklower 	struct tp_pcb 	*tpcb;
153436401Ssklower {
153536401Ssklower 	register int size = 0;
153636401Ssklower 
153736401Ssklower 	IFTRACE(D_CONN)
153836401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
153936401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
154036401Ssklower 	ENDTRACE
154136401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
154236401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
154336401Ssklower 			(dutype == DR_TPDU_type) ||
154436401Ssklower 			(dutype == CR_TPDU_type) )) {
154536401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
154636401Ssklower 			dutype, tpcb->tp_class);
154736401Ssklower 	/* TODO: identify this and GET RID OF IT */
154836401Ssklower 	}
154936401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
155036401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
155136401Ssklower 			(dutype == DR_TPDU_type) ||
155236401Ssklower 			(dutype == CR_TPDU_type) );
155336401Ssklower 
155436401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
155536401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
155636401Ssklower 	} else  {
155736401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
155836401Ssklower 	}
155936401Ssklower 	return size;
156036401Ssklower 	/* caller must get network level header size separately */
156136401Ssklower }
1562