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