xref: /csrg-svn/sys/netiso/tp_input.c (revision 36401)
1*36401Ssklower /***********************************************************
2*36401Ssklower 		Copyright IBM Corporation 1987
3*36401Ssklower 
4*36401Ssklower                       All Rights Reserved
5*36401Ssklower 
6*36401Ssklower Permission to use, copy, modify, and distribute this software and its
7*36401Ssklower documentation for any purpose and without fee is hereby granted,
8*36401Ssklower provided that the above copyright notice appear in all copies and that
9*36401Ssklower both that copyright notice and this permission notice appear in
10*36401Ssklower supporting documentation, and that the name of IBM not be
11*36401Ssklower used in advertising or publicity pertaining to distribution of the
12*36401Ssklower software without specific, written prior permission.
13*36401Ssklower 
14*36401Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36401Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36401Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36401Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36401Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36401Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36401Ssklower SOFTWARE.
21*36401Ssklower 
22*36401Ssklower ******************************************************************/
23*36401Ssklower 
24*36401Ssklower /*
25*36401Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36401Ssklower  */
27*36401Ssklower /*
28*36401Ssklower  * ARGO TP
29*36401Ssklower  *
30*36401Ssklower  * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
31*36401Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
32*36401Ssklower  *
33*36401Ssklower  * tp_input() gets an mbuf chain from ip.  Actually, not directly
34*36401Ssklower  * from ip, because ip calls a net-level routine that strips off
35*36401Ssklower  * the net header and then calls tp_input(), passing the proper type
36*36401Ssklower  * of addresses for the address family in use (how it figures out
37*36401Ssklower  * which AF is not yet determined.
38*36401Ssklower  *
39*36401Ssklower  * Decomposing the tpdu is some of the most laughable code.  The variable-length
40*36401Ssklower  * parameters and the problem of non-aligned memory references
41*36401Ssklower  * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
42*36401Ssklower  * to loop through the header and decompose it.
43*36401Ssklower  *
44*36401Ssklower  * The routine tp_newsocket() is called when a CR comes in for a listening
45*36401Ssklower  * socket.  tp_input calls sonewconn() and tp_newsocket() to set up the
46*36401Ssklower  * "child" socket.  Most tpcb values are copied from the parent tpcb into
47*36401Ssklower  * the child.
48*36401Ssklower  *
49*36401Ssklower  * Also in here is tp_headersize() (grot) which tells the expected size
50*36401Ssklower  * of a tp header, to be used by other layers.  It's in here because it
51*36401Ssklower  * uses the static structure tpdu_info.
52*36401Ssklower  */
53*36401Ssklower 
54*36401Ssklower #ifndef lint
55*36401Ssklower static char *rcsid = "$Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $";
56*36401Ssklower #endif lint
57*36401Ssklower 
58*36401Ssklower #include "argoxtwentyfive.h"
59*36401Ssklower #include "param.h"
60*36401Ssklower #include "mbuf.h"
61*36401Ssklower #include "socket.h"
62*36401Ssklower #include "socketvar.h"
63*36401Ssklower #include "domain.h"
64*36401Ssklower #include "protosw.h"
65*36401Ssklower #include "errno.h"
66*36401Ssklower #include "time.h"
67*36401Ssklower #include "kernel.h"
68*36401Ssklower #include "types.h"
69*36401Ssklower #include "../netiso/iso_errno.h"
70*36401Ssklower #include "../netiso/tp_param.h"
71*36401Ssklower #include "../netiso/tp_timer.h"
72*36401Ssklower #include "../netiso/tp_stat.h"
73*36401Ssklower #include "../netiso/tp_pcb.h"
74*36401Ssklower #include "../netiso/argo_debug.h"
75*36401Ssklower #include "../netiso/tp_trace.h"
76*36401Ssklower #include "../netiso/tp_tpdu.h"
77*36401Ssklower #include "../netiso/iso.h"
78*36401Ssklower #include "../netiso/cons.h"
79*36401Ssklower 
80*36401Ssklower int 	iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
81*36401Ssklower 
82*36401Ssklower #ifdef lint
83*36401Ssklower #undef ATTR
84*36401Ssklower #define ATTR(X)ev_number
85*36401Ssklower #endif lint
86*36401Ssklower 
87*36401Ssklower struct mbuf *
88*36401Ssklower tp_inputprep(m)
89*36401Ssklower 	struct mbuf *m;
90*36401Ssklower {
91*36401Ssklower 	struct tpdu *hdr;
92*36401Ssklower 
93*36401Ssklower 	IFDEBUG(D_TPINPUT)
94*36401Ssklower 		printf("tp_inputprep: m 0x%x\n") ;
95*36401Ssklower 	ENDDEBUG
96*36401Ssklower 
97*36401Ssklower 	while(  m->m_len < 1 ) {
98*36401Ssklower 		if( (m = m_free(m)) == MNULL ) {
99*36401Ssklower 			return (struct mbuf *)0;
100*36401Ssklower 		}
101*36401Ssklower 	}
102*36401Ssklower 
103*36401Ssklower 	if(m->m_off & 0x3) {
104*36401Ssklower 		/* align to a 4-byte boundary - sigh */
105*36401Ssklower 		register struct mbuf *n;
106*36401Ssklower 
107*36401Ssklower 		MGET(n, M_DONTWAIT, m->m_type);
108*36401Ssklower 		if( n == MNULL ) {
109*36401Ssklower 			m_freem(m);
110*36401Ssklower 			return (struct mbuf *)0;
111*36401Ssklower 		}
112*36401Ssklower 		n->m_act = MNULL;
113*36401Ssklower 		n->m_len = m->m_len;
114*36401Ssklower 		n->m_next = m->m_next;
115*36401Ssklower 		bcopy( mtod(m, caddr_t), mtod(n, caddr_t), m->m_len );
116*36401Ssklower 		m->m_next = 0;
117*36401Ssklower 		m_free(m);
118*36401Ssklower 		m = n;
119*36401Ssklower 	}
120*36401Ssklower 	CHANGE_MTYPE(m, TPMT_DATA);
121*36401Ssklower 
122*36401Ssklower 	/* we KNOW that there is at least 1 byte in this mbuf */
123*36401Ssklower 
124*36401Ssklower 	hdr = mtod( m, struct tpdu *);
125*36401Ssklower 
126*36401Ssklower 	/*
127*36401Ssklower 	 * now pull up the whole tp header
128*36401Ssklower 	 */
129*36401Ssklower 	if ( m->m_len < hdr->tpdu_li + 1 ) {
130*36401Ssklower 		if ((m = m_pullup(m, (int)(hdr->tpdu_li) + 1)) == MNULL ) {
131*36401Ssklower 			IncStat(ts_recv_drop);
132*36401Ssklower 			return (struct mbuf *)0;
133*36401Ssklower 		}
134*36401Ssklower 	}
135*36401Ssklower 	IFDEBUG(D_INPUT)
136*36401Ssklower 	printf(
137*36401Ssklower 	" at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
138*36401Ssklower 		hdr->tpdu_li,m->m_len);
139*36401Ssklower 	ENDDEBUG
140*36401Ssklower 	return m;
141*36401Ssklower }
142*36401Ssklower 
143*36401Ssklower /* begin groan
144*36401Ssklower  * -- this array and the following macros allow you to step through the
145*36401Ssklower  * parameters of the variable part of a header
146*36401Ssklower  * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
147*36401Ssklower  * should change, this array has to be rearranged
148*36401Ssklower  */
149*36401Ssklower 
150*36401Ssklower #define TP_LEN_CLASS_0_INDEX	2
151*36401Ssklower #define TP_MAX_DATA_INDEX 3
152*36401Ssklower 
153*36401Ssklower static u_char tpdu_info[][4] =
154*36401Ssklower {
155*36401Ssklower /*								length						 max data len */
156*36401Ssklower /*								reg fmt 	xtd fmt  class 0  		 	  */
157*36401Ssklower  	/* UNUSED		0x0 */		0x0 ,		0x0,	0x0,		0x0,
158*36401Ssklower  	/* XPD_TPDU_type 0x1 */		0x5,		0x8,	0x0,		TP_MAX_XPD_DATA,
159*36401Ssklower  	/* XAK_TPDU_type 0x2 */		0x5 ,		0x8,	0x0,		0x0,
160*36401Ssklower  	/* GR_TPDU_type	0x3 */		0x0 ,		0x0,	0x0,		0x0,
161*36401Ssklower  	/* UNUSED		0x4 */		0x0 ,		0x0,	0x0,		0x0,
162*36401Ssklower  	/* UNUSED		0x5 */		0x0 ,		0x0,	0x0,		0x0,
163*36401Ssklower  	/* AK_TPDU_type 0x6 */		0x5,		0xa,	0x0,		0x0,
164*36401Ssklower 	/* ER_TPDU_type 0x7 */		0x5,		0x5,	0x0,		0x0,
165*36401Ssklower  	/* DR_TPDU_type 0x8 */		0x7,		0x7,	0x7,		TP_MAX_DR_DATA,
166*36401Ssklower  	/* UNUSED		0x9 */		0x0 ,		0x0,	0x0,		0x0,
167*36401Ssklower  	/* UNUSED		0xa */		0x0 ,		0x0,	0x0,		0x0,
168*36401Ssklower  	/* UNUSED		0xb */		0x0 ,		0x0,	0x0,		0x0,
169*36401Ssklower  	/* DC_TPDU_type 0xc */		0x6,		0x6,	0x0,		0x0,
170*36401Ssklower  	/* CC_TPDU_type 0xd */		0x7,		0x7,	0x7,		TP_MAX_CC_DATA,
171*36401Ssklower  	/* CR_TPDU_type 0xe */		0x7,		0x7,	0x7,		TP_MAX_CR_DATA,
172*36401Ssklower  	/* DT_TPDU_type 0xf */		0x5,		0x8,	0x3,		0x0,
173*36401Ssklower };
174*36401Ssklower 
175*36401Ssklower /*
176*36401Ssklower  * WHENEVER YOU USE THE FOLLOWING MACRO,
177*36401Ssklower  * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
178*36401Ssklower  */
179*36401Ssklower 
180*36401Ssklower #define WHILE_OPTIONS(P, hdr,format)\
181*36401Ssklower {	register  caddr_t		P;\
182*36401Ssklower 	P = (caddr_t)(hdr) +\
183*36401Ssklower 	tpdu_info[(hdr)->tpdu_type][(format)];\
184*36401Ssklower 	while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) {
185*36401Ssklower 
186*36401Ssklower #define END_WHILE_OPTIONS(P)\
187*36401Ssklower 	P = P  + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\
188*36401Ssklower } }
189*36401Ssklower 
190*36401Ssklower #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
191*36401Ssklower 	if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \
192*36401Ssklower 	goto Whattodo; }
193*36401Ssklower 
194*36401Ssklower /* end groan */
195*36401Ssklower 
196*36401Ssklower /*
197*36401Ssklower  * NAME:  tp_newsocket()
198*36401Ssklower  *
199*36401Ssklower  * CALLED FROM:
200*36401Ssklower  *  tp_input() on incoming CR, when a socket w/ the called suffix
201*36401Ssklower  * is awaiting a  connection request
202*36401Ssklower  *
203*36401Ssklower  * FUNCTION and ARGUMENTS:
204*36401Ssklower  *  Create a new socket structure, attach to it a new transport pcb,
205*36401Ssklower  *  using a copy of the net level pcb for the parent socket.
206*36401Ssklower  *  (so) is the parent socket.
207*36401Ssklower  *  (fname) is the foreign address (all that's used is the nsap portion)
208*36401Ssklower  *
209*36401Ssklower  * RETURN VALUE:
210*36401Ssklower  *  a new socket structure, being this end of the newly formed connection.
211*36401Ssklower  *
212*36401Ssklower  * SIDE EFFECTS:
213*36401Ssklower  *  Sets a few things in the tpcb and net level pcb
214*36401Ssklower  *
215*36401Ssklower  * NOTES:
216*36401Ssklower  */
217*36401Ssklower static struct socket *
218*36401Ssklower tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
219*36401Ssklower 	struct socket				*so;
220*36401Ssklower 	struct sockaddr				*fname;
221*36401Ssklower 	u_int						cons_channel;
222*36401Ssklower 	u_char						class_to_use;
223*36401Ssklower 	u_int						netservice;
224*36401Ssklower {
225*36401Ssklower 	register struct tp_pcb	*tpcb = sototpcb(so); /* old tpcb, needed below */
226*36401Ssklower 	struct tp_pcb *			 newtpcb;
227*36401Ssklower 	struct proc *			selproc = so->so_rcv.sb_sel; /* kludge for select */
228*36401Ssklower 
229*36401Ssklower 	/*
230*36401Ssklower 	 * sonewconn() gets a new socket structure,
231*36401Ssklower 	 * a new lower layer pcb and a new tpcb,
232*36401Ssklower 	 * but the pcbs are unnamed (not bound)
233*36401Ssklower 	 */
234*36401Ssklower 	IFTRACE(D_NEWSOCK)
235*36401Ssklower 		tptraceTPCB(TPPTmisc, "newsock: listg_so,_tpcb selproc, so_head",
236*36401Ssklower 			so, tpcb, selproc, so->so_head);
237*36401Ssklower 	ENDTRACE
238*36401Ssklower 
239*36401Ssklower 	if ((so = sonewconn(so)) == (struct socket *)0)
240*36401Ssklower 		return so;
241*36401Ssklower 	IFTRACE(D_NEWSOCK)
242*36401Ssklower 		tptraceTPCB(TPPTmisc, "newsock: after newconn so, selproc, so_head",
243*36401Ssklower 			so, selproc, so->so_head, 0);
244*36401Ssklower 	ENDTRACE
245*36401Ssklower 
246*36401Ssklower 	so->so_rcv.sb_sel = selproc; /* so that soisconnected() after receipt
247*36401Ssklower 		* of the ack will wake this guy up if he's selecting on the
248*36401Ssklower 		* listening socket
249*36401Ssklower 		*/
250*36401Ssklower 	IFDEBUG(D_NEWSOCK)
251*36401Ssklower 		printf("tp_newsocket(channel 0x%x)  after sonewconn so 0x%x \n", so);
252*36401Ssklower 		dump_isoaddr(fname);
253*36401Ssklower 		{
254*36401Ssklower 			struct socket *t, *head ;
255*36401Ssklower 
256*36401Ssklower 			head = so->so_head;
257*36401Ssklower 			t = so;
258*36401Ssklower 			printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
259*36401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
260*36401Ssklower 			while( (t=t->so_q0)  && t!= so  && t!= head)
261*36401Ssklower 				printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
262*36401Ssklower 					t, t->so_head, t->so_q0, t->so_q0len);
263*36401Ssklower 		}
264*36401Ssklower 	ENDDEBUG
265*36401Ssklower 
266*36401Ssklower 	/*
267*36401Ssklower 	 * before we clobber the old tpcb ptr, get these items from the parent pcb
268*36401Ssklower 	 */
269*36401Ssklower 	newtpcb = sototpcb(so);
270*36401Ssklower 	newtpcb->_tp_param = tpcb->_tp_param;
271*36401Ssklower 	newtpcb->tp_flags = tpcb->tp_flags;
272*36401Ssklower 	newtpcb->tp_lcredit = tpcb->tp_lcredit;
273*36401Ssklower 	newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
274*36401Ssklower 	newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
275*36401Ssklower 	bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
276*36401Ssklower 	soreserve(so, tpcb->tp_winsize, tpcb->tp_winsize);
277*36401Ssklower 
278*36401Ssklower 	if( /* old */ tpcb->tp_flags & (TPF_CONN_DATA_OUT | TPF_DISC_DATA_OUT )) {
279*36401Ssklower 		/*
280*36401Ssklower 		 * Flags has already been copied, now copy the data
281*36401Ssklower 		 * -- these data are the connect- or disconnect- data.
282*36401Ssklower 		 */
283*36401Ssklower 		struct mbuf *conndata;
284*36401Ssklower 
285*36401Ssklower 		ASSERT(tpcb->tp_sock->so_snd.sb_mb != MNULL);
286*36401Ssklower 		ASSERT(tpcb->tp_sock->so_snd.sb_cc != 0);
287*36401Ssklower 		conndata = m_copy( tpcb->tp_sock->so_snd.sb_mb, 0,
288*36401Ssklower 									tpcb->tp_sock->so_snd.sb_cc);
289*36401Ssklower 		IFDEBUG(D_CONN)
290*36401Ssklower 			dump_mbuf(conndata, "conndata after mcopy");
291*36401Ssklower 			dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, "old sosnd after mcopy");
292*36401Ssklower 			dump_mbuf(so->so_snd.sb_mb, "new (so->)sosnd before sbapndrec");
293*36401Ssklower 			dump_mbuf(conndata, "conndata before sbappendrec");
294*36401Ssklower 		ENDDEBUG
295*36401Ssklower 		sbappendrecord( &so->so_snd, conndata );
296*36401Ssklower 	}
297*36401Ssklower 
298*36401Ssklower 	tpcb = newtpcb;
299*36401Ssklower 	tpcb->tp_state = TP_LISTENING;
300*36401Ssklower 	tpcb->tp_class = class_to_use;
301*36401Ssklower 	tpcb->tp_netservice = netservice;
302*36401Ssklower 
303*36401Ssklower 
304*36401Ssklower 	ASSERT( fname != 0 ) ; /* just checking */
305*36401Ssklower 	if ( fname ) {
306*36401Ssklower 		/*
307*36401Ssklower 		 *	tp_route_to takes its address argument in the form of an mbuf.
308*36401Ssklower 		 */
309*36401Ssklower 		struct mbuf	*m;
310*36401Ssklower 		int			err;
311*36401Ssklower 
312*36401Ssklower 		MGET(m, M_DONTWAIT, MT_SONAME);	/* mbuf type used is confusing */
313*36401Ssklower 		if (m) {
314*36401Ssklower 			/*
315*36401Ssklower 			 * this seems a bit grotesque, but tp_route_to expects
316*36401Ssklower 			 * an mbuf * instead of simply a sockaddr; it calls the ll
317*36401Ssklower 			 * pcb_connect, which expects the name/addr in an mbuf as well.
318*36401Ssklower 			 * sigh.
319*36401Ssklower 			 */
320*36401Ssklower 			bcopy((caddr_t)fname, mtod(m, caddr_t), sizeof (struct sockaddr));
321*36401Ssklower 			m->m_act = MNULL;
322*36401Ssklower 			m->m_len = (fname->sa_family == AF_INET) ?
323*36401Ssklower 				sizeof(struct sockaddr_in) : sizeof(struct sockaddr_iso);
324*36401Ssklower 
325*36401Ssklower 			/* grot  : have to say the kernel can override params in
326*36401Ssklower 			 * the passive open case
327*36401Ssklower 			 */
328*36401Ssklower 			tpcb->tp_dont_change_params = 0;
329*36401Ssklower 			err = tp_route_to( m, tpcb, cons_channel);
330*36401Ssklower 			m_free(m);
331*36401Ssklower 
332*36401Ssklower 			if (!err)
333*36401Ssklower 				goto ok;
334*36401Ssklower 		}
335*36401Ssklower 		IFDEBUG(D_CONN)
336*36401Ssklower 			printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
337*36401Ssklower 				tpcb, so);
338*36401Ssklower 		ENDDEBUG
339*36401Ssklower 		(void) tp_detach(tpcb);
340*36401Ssklower 		return 0;
341*36401Ssklower 	}
342*36401Ssklower ok:
343*36401Ssklower 	IFDEBUG(D_TPINPUT)
344*36401Ssklower 		printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
345*36401Ssklower 			so, sototpcb(so));
346*36401Ssklower 	ENDDEBUG
347*36401Ssklower 	return so;
348*36401Ssklower }
349*36401Ssklower 
350*36401Ssklower #ifndef CONS
351*36401Ssklower tpcons_output()
352*36401Ssklower {
353*36401Ssklower 	return(0);
354*36401Ssklower }
355*36401Ssklower #endif !CONS
356*36401Ssklower 
357*36401Ssklower /*
358*36401Ssklower  * NAME: 	tp_input()
359*36401Ssklower  *
360*36401Ssklower  * CALLED FROM:
361*36401Ssklower  *  net layer input routine
362*36401Ssklower  *
363*36401Ssklower  * FUNCTION and ARGUMENTS:
364*36401Ssklower  *  Process an incoming TPDU (m), finding the associated tpcb if there
365*36401Ssklower  *  is one. Create the appropriate type of event and call the driver.
366*36401Ssklower  *  (faddr) and (laddr) are the foreign and local addresses.
367*36401Ssklower  *
368*36401Ssklower  * 	When tp_input() is called we KNOW that the ENTIRE TP HEADER
369*36401Ssklower  * 	has been m_pullup-ed.
370*36401Ssklower  *
371*36401Ssklower  * RETURN VALUE: Nada
372*36401Ssklower  *
373*36401Ssklower  * SIDE EFFECTS:
374*36401Ssklower  *	When using COSNS it may affect the state of the net-level pcb
375*36401Ssklower  *
376*36401Ssklower  * NOTE:
377*36401Ssklower  *  The initial value of acktime is 2 so that we will never
378*36401Ssklower  *  have a 0 value for tp_peer_acktime.  It gets used in the
379*36401Ssklower  *  computation of the retransmission timer value, and so it
380*36401Ssklower  *  mustn't be zero.
381*36401Ssklower  *  2 seems like a reasonable minimum.
382*36401Ssklower  */
383*36401Ssklower ProtoHook
384*36401Ssklower tp_input(m, faddr, laddr, cons_channel, dgout_routine)
385*36401Ssklower 	register	struct mbuf 	*m;
386*36401Ssklower 	struct sockaddr 			*faddr, *laddr; /* NSAP addresses */
387*36401Ssklower 	u_int 						cons_channel;
388*36401Ssklower 	int 						(*dgout_routine)();
389*36401Ssklower 
390*36401Ssklower {
391*36401Ssklower 	register struct tp_pcb 	*tpcb = (struct tp_pcb *)0;
392*36401Ssklower 	register struct tpdu 	*hdr = mtod(m, struct tpdu *);
393*36401Ssklower 	struct socket 			*so;
394*36401Ssklower 	struct tp_event 		e;
395*36401Ssklower 	int 					error = 0;
396*36401Ssklower 	unsigned 				dutype;
397*36401Ssklower 	u_short 				dref, sref, acktime, subseq; /*VAX*/
398*36401Ssklower 	u_char 					preferred_class=0, class_to_use=0;
399*36401Ssklower 	u_char					opt, dusize, addlopt;
400*36401Ssklower #ifdef TP_PERF_MEAS
401*36401Ssklower 	u_char					perf_meas=0;
402*36401Ssklower #endif TP_PERF_MEAS
403*36401Ssklower 	u_char					fsufxlen;
404*36401Ssklower 	u_char					lsufxlen;
405*36401Ssklower 	caddr_t					fsufxloc=0, lsufxloc=0;
406*36401Ssklower 	int						tpdu_len;
407*36401Ssklower 	u_int 					takes_data;
408*36401Ssklower 	u_int					fcc_present;
409*36401Ssklower 	caddr_t					errloc=0;
410*36401Ssklower 	struct tp_conn_param 	tpp;
411*36401Ssklower 	int						tpcons_output();
412*36401Ssklower 
413*36401Ssklower #ifdef TP_PERF_MEAS
414*36401Ssklower 	GET_CUR_TIME( &e.e_time );
415*36401Ssklower #endif TP_PERF_MEAS
416*36401Ssklower 
417*36401Ssklower 	IFDEBUG(D_TPINPUT)
418*36401Ssklower 		printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
419*36401Ssklower 	ENDDEBUG
420*36401Ssklower 
421*36401Ssklower again:
422*36401Ssklower 
423*36401Ssklower 	tpdu_len = 0;
424*36401Ssklower 	tpcb = (struct tp_pcb *)0;
425*36401Ssklower 	fsufxlen = 0;
426*36401Ssklower 	lsufxlen = 0;
427*36401Ssklower 	addlopt = 0;
428*36401Ssklower 	acktime = 2;
429*36401Ssklower 	dusize = TP_DFL_TPDUSIZE;
430*36401Ssklower 	sref = 0;
431*36401Ssklower 	subseq = 0;
432*36401Ssklower 	takes_data = FALSE;
433*36401Ssklower 	fcc_present = FALSE;
434*36401Ssklower 
435*36401Ssklower 	/*
436*36401Ssklower 	 * get the actual tpdu length - necessary for monitoring
437*36401Ssklower 	 * and for checksumming
438*36401Ssklower 	 *
439*36401Ssklower 	 * Also, maybe measure the mbuf chain lengths and sizes.
440*36401Ssklower 	 */
441*36401Ssklower 
442*36401Ssklower 	{ 	register struct mbuf *n=m;
443*36401Ssklower #	ifdef ARGO_DEBUG
444*36401Ssklower 		int chain_length = 0;
445*36401Ssklower #	endif ARGO_DEBUG
446*36401Ssklower 
447*36401Ssklower 		for(;;) {
448*36401Ssklower 			tpdu_len += n->m_len;
449*36401Ssklower 			IFDEBUG(D_MBUF_MEAS)
450*36401Ssklower 				if( n->m_off > MMAXOFF) {
451*36401Ssklower 					IncStat(ts_mb_cluster);
452*36401Ssklower 				} else {
453*36401Ssklower 					IncStat(ts_mb_small);
454*36401Ssklower 				}
455*36401Ssklower 				chain_length ++;
456*36401Ssklower 			ENDDEBUG
457*36401Ssklower 			if (n->m_next == MNULL ) {
458*36401Ssklower 				break;
459*36401Ssklower 			}
460*36401Ssklower 			n = n->m_next;
461*36401Ssklower 		}
462*36401Ssklower 		IFDEBUG(D_MBUF_MEAS)
463*36401Ssklower 			if(chain_length > 16)
464*36401Ssklower 				chain_length = 0; /* zero used for anything > 16 */
465*36401Ssklower 			tp_stat.ts_mb_len_distr[chain_length] ++;
466*36401Ssklower 		ENDDEBUG
467*36401Ssklower 	}
468*36401Ssklower 	IFTRACE(D_TPINPUT)
469*36401Ssklower 		tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
470*36401Ssklower 			0);
471*36401Ssklower 	ENDTRACE
472*36401Ssklower 
473*36401Ssklower 	dref = ntohs((short)hdr->tpdu_dref);
474*36401Ssklower 	sref = ntohs((short)hdr->tpdu_sref);
475*36401Ssklower 	dutype = (int)hdr->tpdu_type;
476*36401Ssklower 
477*36401Ssklower 	IFDEBUG(D_TPINPUT)
478*36401Ssklower 		printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
479*36401Ssklower 			cons_channel, dref);
480*36401Ssklower 		printf("input: dref 0x%x sref 0x%x\n", dref, sref);
481*36401Ssklower 	ENDDEBUG
482*36401Ssklower 	IFTRACE(D_TPINPUT)
483*36401Ssklower 		tptrace(TPPTmisc, "channel dutype dref ",
484*36401Ssklower 			cons_channel, dutype, dref, 0);
485*36401Ssklower 	ENDTRACE
486*36401Ssklower 
487*36401Ssklower 
488*36401Ssklower #ifdef ARGO_DEBUG
489*36401Ssklower 	if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
490*36401Ssklower 		printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
491*36401Ssklower 			dutype, cons_channel, dref);
492*36401Ssklower 		dump_buf (m, sizeof( struct mbuf ));
493*36401Ssklower 
494*36401Ssklower 		IncStat(ts_inv_dutype);
495*36401Ssklower 		goto discard;
496*36401Ssklower 	}
497*36401Ssklower #endif ARGO_DEBUG
498*36401Ssklower 
499*36401Ssklower 	CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
500*36401Ssklower 		E_TP_INV_TPDU, ts_inv_dutype, respond,
501*36401Ssklower 		2 );
502*36401Ssklower 		/* unfortunately we can't take the address of the tpdu_type field,
503*36401Ssklower 		 * since it's a bit field - so we just use the constant offset 2
504*36401Ssklower 		 */
505*36401Ssklower 
506*36401Ssklower 	/* Now this isn't very neat but since you locate a pcb one way
507*36401Ssklower 	 * at the beginning of connection establishment, and by
508*36401Ssklower 	 * the dref for each tpdu after that, we have to treat CRs differently
509*36401Ssklower 	 */
510*36401Ssklower 	if ( dutype == CR_TPDU_type ) {
511*36401Ssklower 		u_char alt_classes = 0;
512*36401Ssklower 
513*36401Ssklower #ifdef notdef  /* This is done up above */
514*36401Ssklower 		sref = hdr->tpdu_CRsref;
515*36401Ssklower #endif notdef
516*36401Ssklower 		preferred_class = (1 << hdr->tpdu_CRclass);
517*36401Ssklower 		opt = hdr->tpdu_CRoptions;
518*36401Ssklower 
519*36401Ssklower 		WHILE_OPTIONS(P, hdr, 1 ) /* { */
520*36401Ssklower 
521*36401Ssklower 			switch( vbptr(P)->tpv_code ) {
522*36401Ssklower 
523*36401Ssklower 			case	TPP_tpdu_size:
524*36401Ssklower 				vb_getval(P, u_char, dusize);
525*36401Ssklower 				IFDEBUG(D_TPINPUT)
526*36401Ssklower 					printf("CR dusize 0x%x\n", dusize);
527*36401Ssklower 				ENDDEBUG
528*36401Ssklower 				CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE),
529*36401Ssklower 						E_TP_INV_PVAL, ts_inv_pval, respond,
530*36401Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
531*36401Ssklower 				break;
532*36401Ssklower 			case	TPP_addl_opt:
533*36401Ssklower 				vb_getval(P, u_char, addlopt);
534*36401Ssklower 				break;
535*36401Ssklower 			case	TPP_calling_sufx:
536*36401Ssklower 				/* could use vb_getval, but we want to save the loc & len
537*36401Ssklower 				 * for later use
538*36401Ssklower 				 */
539*36401Ssklower 				fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
540*36401Ssklower 				fsufxlen = vbptr(P)->tpv_len;
541*36401Ssklower 				IFDEBUG(D_TPINPUT)
542*36401Ssklower 					printf("CR fsufx:");
543*36401Ssklower 					{ register int j;
544*36401Ssklower 						for(j=0; j<fsufxlen; j++ ) {
545*36401Ssklower 							printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
546*36401Ssklower 						}
547*36401Ssklower 						printf("\n");
548*36401Ssklower 					}
549*36401Ssklower 				ENDDEBUG
550*36401Ssklower 				break;
551*36401Ssklower 			case	TPP_called_sufx:
552*36401Ssklower 				/* could use vb_getval, but we want to save the loc & len
553*36401Ssklower 				 * for later use
554*36401Ssklower 				 */
555*36401Ssklower 				lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
556*36401Ssklower 				lsufxlen = vbptr(P)->tpv_len;
557*36401Ssklower 				IFDEBUG(D_TPINPUT)
558*36401Ssklower 					printf("CR lsufx:");
559*36401Ssklower 					{ register int j;
560*36401Ssklower 						for(j=0; j<lsufxlen; j++ ) {
561*36401Ssklower 							printf(" 0x%x. ", *((caddr_t)(lsufxloc+j)) );
562*36401Ssklower 						}
563*36401Ssklower 						printf("\n");
564*36401Ssklower 					}
565*36401Ssklower 				ENDDEBUG
566*36401Ssklower 				break;
567*36401Ssklower 
568*36401Ssklower #ifdef TP_PERF_MEAS
569*36401Ssklower 			case	TPP_perf_meas:
570*36401Ssklower 				vb_getval(P, u_char, perf_meas);
571*36401Ssklower 				break;
572*36401Ssklower #endif TP_PERF_MEAS
573*36401Ssklower 
574*36401Ssklower 			case	TPP_vers:
575*36401Ssklower 				/* not in class 0; 1 octet; in CR_TPDU only */
576*36401Ssklower 				CHECK( (vbval(P, u_char) != TP_VERSION ),
577*36401Ssklower 					E_TP_INV_PVAL, ts_inv_pval, respond,
578*36401Ssklower 					(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
579*36401Ssklower 				break;
580*36401Ssklower 			case	TPP_acktime:
581*36401Ssklower 				vb_getval(P, u_short, acktime);
582*36401Ssklower 				acktime = ntohs(acktime);
583*36401Ssklower 				acktime = acktime/500; /* convert to slowtimo ticks */
584*36401Ssklower 				if((short)acktime <=0 )
585*36401Ssklower 					acktime = 2; /* don't allow a bad peer to screw us up */
586*36401Ssklower 				IFDEBUG(D_TPINPUT)
587*36401Ssklower 					printf("CR acktime 0x%x\n", acktime);
588*36401Ssklower 				ENDDEBUG
589*36401Ssklower 				break;
590*36401Ssklower 
591*36401Ssklower 			case	TPP_alt_class:
592*36401Ssklower 				{
593*36401Ssklower 					u_char *aclass = 0;
594*36401Ssklower 					register int i;
595*36401Ssklower 
596*36401Ssklower 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
597*36401Ssklower 						aclass =
598*36401Ssklower 							(u_char *) &(((struct tp_vbp *)P)->tpv_val);
599*36401Ssklower 						alt_classes |= (1<<(*aclass));
600*36401Ssklower 					}
601*36401Ssklower 					IFDEBUG(D_TPINPUT)
602*36401Ssklower 						printf("alt_classes 0x%x\n", alt_classes);
603*36401Ssklower 					ENDDEBUG
604*36401Ssklower 				}
605*36401Ssklower 				break;
606*36401Ssklower 
607*36401Ssklower 			case	TPP_security:
608*36401Ssklower 			case	TPP_residER:
609*36401Ssklower 			case	TPP_priority:
610*36401Ssklower 			case	TPP_transdelay:
611*36401Ssklower 			case	TPP_throughput:
612*36401Ssklower 			case	TPP_addl_info:
613*36401Ssklower 			case	TPP_subseq:
614*36401Ssklower 				IFDEBUG(D_TPINPUT)
615*36401Ssklower 					printf("param ignored CR_TPDU code= 0x%x\n",
616*36401Ssklower 						 vbptr(P)->tpv_code);
617*36401Ssklower 				ENDDEBUG
618*36401Ssklower 				IncStat(ts_param_ignored);
619*36401Ssklower 				break;
620*36401Ssklower 
621*36401Ssklower 			case	TPP_checksum:
622*36401Ssklower 				IFDEBUG(D_TPINPUT)
623*36401Ssklower 					printf("CR before cksum\n");
624*36401Ssklower 				ENDDEBUG
625*36401Ssklower 
626*36401Ssklower 				CHECK( iso_check_csum(m, tpdu_len),
627*36401Ssklower 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
628*36401Ssklower 
629*36401Ssklower 				IFDEBUG(D_TPINPUT)
630*36401Ssklower 					printf("CR before cksum\n");
631*36401Ssklower 				ENDDEBUG
632*36401Ssklower 				break;
633*36401Ssklower 
634*36401Ssklower 			default:
635*36401Ssklower 				IncStat(ts_inv_pcode);
636*36401Ssklower 				error = E_TP_INV_PCODE;
637*36401Ssklower 				goto discard;
638*36401Ssklower 
639*36401Ssklower 			}
640*36401Ssklower 
641*36401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
642*36401Ssklower 
643*36401Ssklower 		if( lsufxlen == 0) {
644*36401Ssklower 			/* can't look for a tpcb w/o any called sufx */
645*36401Ssklower 			error =  E_TP_LENGTH_INVAL;
646*36401Ssklower 			IncStat(ts_inv_sufx);
647*36401Ssklower 			goto respond;
648*36401Ssklower 		} else {
649*36401Ssklower 			register	struct tp_ref 	*rp;
650*36401Ssklower 			register	int			r;
651*36401Ssklower 			extern		int			tp_maxrefopen;
652*36401Ssklower 
653*36401Ssklower 			rp = &tp_ref[1]; /* zero-th one is never open */
654*36401Ssklower 			for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
655*36401Ssklower 				if (rp->tpr_state!=REF_OPENING)
656*36401Ssklower 					continue;
657*36401Ssklower 				if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) {
658*36401Ssklower 					tpcb =  rp->tpr_pcb;
659*36401Ssklower 					if( laddr->sa_family !=
660*36401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family ) {
661*36401Ssklower 						IFDEBUG(D_CONN)
662*36401Ssklower 						 	printf(
663*36401Ssklower 					"MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n",
664*36401Ssklower 							laddr->sa_family,
665*36401Ssklower 							tpcb->tp_sock->so_proto->pr_domain->dom_family );
666*36401Ssklower 						ENDDEBUG
667*36401Ssklower 						continue;
668*36401Ssklower 					}
669*36401Ssklower 					IFTRACE(D_TPINPUT)
670*36401Ssklower 						tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate",
671*36401Ssklower 							r, *lsufxloc, rp->tpr_state, 0);
672*36401Ssklower 					ENDTRACE
673*36401Ssklower 					/* found it */
674*36401Ssklower 					break;
675*36401Ssklower 				}
676*36401Ssklower 			}
677*36401Ssklower 
678*36401Ssklower 			CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond,
679*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
680*36401Ssklower 				/* _tpduf is the fixed part; add 2 to get the dref bits of
681*36401Ssklower 				 * the fixed part (can't take the address of a bit field)
682*36401Ssklower 				 */
683*36401Ssklower 		}
684*36401Ssklower 
685*36401Ssklower 		/*
686*36401Ssklower 		 * WE HAVE A TPCB
687*36401Ssklower 		 * already know that the classes in the CR match at least
688*36401Ssklower 		 * one class implemented, but we don't know yet if they
689*36401Ssklower 		 * include any classes permitted by this server.
690*36401Ssklower 		 */
691*36401Ssklower 
692*36401Ssklower 		IFDEBUG(D_TPINPUT)
693*36401Ssklower 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
694*36401Ssklower 		ENDDEBUG
695*36401Ssklower 		IFDEBUG(D_CONN)
696*36401Ssklower 			printf(
697*36401Ssklower "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
698*36401Ssklower 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
699*36401Ssklower 		ENDDEBUG
700*36401Ssklower 		/* tpcb->tp_class doesn't include any classes not implemented  */
701*36401Ssklower 		class_to_use = (preferred_class & tpcb->tp_class);
702*36401Ssklower 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
703*36401Ssklower 			class_to_use = alt_classes & tpcb->tp_class;
704*36401Ssklower 
705*36401Ssklower 		class_to_use = 1 << tp_mask_to_num(class_to_use);
706*36401Ssklower 
707*36401Ssklower 		{
708*36401Ssklower 			tpp = tpcb->_tp_param;
709*36401Ssklower 			tpp.p_class = class_to_use;
710*36401Ssklower 			tpp.p_tpdusize = dusize;
711*36401Ssklower 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
712*36401Ssklower 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
713*36401Ssklower 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
714*36401Ssklower 				(addlopt & TPAO_NO_CSUM) == 0;
715*36401Ssklower #ifdef notdef
716*36401Ssklower 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
717*36401Ssklower 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
718*36401Ssklower 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
719*36401Ssklower #endif notdef
720*36401Ssklower 
721*36401Ssklower 		CHECK(
722*36401Ssklower 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
723*36401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
724*36401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
725*36401Ssklower 				/* ^ more or less the location of class */
726*36401Ssklower 			)
727*36401Ssklower 		}
728*36401Ssklower 		IFTRACE(D_CONN)
729*36401Ssklower 			tptrace(TPPTmisc,
730*36401Ssklower 				"after 1 consist class_to_use class, out, tpconsout",
731*36401Ssklower 				class_to_use,
732*36401Ssklower 				tpcb->tp_class, dgout_routine, tpcons_output
733*36401Ssklower 				);
734*36401Ssklower 		ENDTRACE
735*36401Ssklower 		CHECK(
736*36401Ssklower 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
737*36401Ssklower 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
738*36401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
739*36401Ssklower 				/* ^ more or less the location of class */
740*36401Ssklower 			)
741*36401Ssklower 		IFDEBUG(D_CONN)
742*36401Ssklower 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
743*36401Ssklower 				tpcb, tpcb->tp_flags);
744*36401Ssklower 		ENDDEBUG
745*36401Ssklower 		takes_data = TRUE;
746*36401Ssklower 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
747*36401Ssklower 		e.ev_number = CR_TPDU;
748*36401Ssklower 
749*36401Ssklower 		so = tpcb->tp_sock;
750*36401Ssklower 		if (so->so_options & SO_ACCEPTCONN) {
751*36401Ssklower 			/*
752*36401Ssklower 			 * Create a socket, tpcb, ll pcb, etc.
753*36401Ssklower 			 * for this newborn connection, and fill in all the values.
754*36401Ssklower 			 */
755*36401Ssklower 			IFDEBUG(D_CONN)
756*36401Ssklower 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
757*36401Ssklower 					so, laddr, faddr, cons_channel);
758*36401Ssklower 			ENDDEBUG
759*36401Ssklower 			if( (so =
760*36401Ssklower 				tp_newsocket(so, faddr, cons_channel,
761*36401Ssklower 					class_to_use,
762*36401Ssklower 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)
763*36401Ssklower 					) == (struct socket *)0 ) {
764*36401Ssklower 				/* note - even if netservice is IN_CLNS, as far as
765*36401Ssklower 				 * the tp entity is concerned, the only differences
766*36401Ssklower 				 * are CO vs CL
767*36401Ssklower 				 */
768*36401Ssklower 				IFDEBUG(D_CONN)
769*36401Ssklower 					printf("tp_newsocket returns 0\n");
770*36401Ssklower 				ENDDEBUG
771*36401Ssklower 				goto discard;
772*36401Ssklower 			}
773*36401Ssklower 			tpcb = sototpcb(so);
774*36401Ssklower 
775*36401Ssklower 			/* stash the f suffix in the new tpcb */
776*36401Ssklower 			/* l suffix is already there */
777*36401Ssklower 
778*36401Ssklower 			bcopy( fsufxloc, tpcb->tp_fsuffix, fsufxlen);
779*36401Ssklower 			if( (tpcb->tp_fsuffixlen = fsufxlen) == sizeof(short) ) {
780*36401Ssklower 				/* even if it's AF_ISO */
781*36401Ssklower 				bcopy (fsufxloc, &(satosin(faddr)->sin_port), sizeof(short));
782*36401Ssklower 				(tpcb->tp_nlproto->nlp_putsufx)(so->so_pcb, faddr, TP_FOREIGN);
783*36401Ssklower 			}
784*36401Ssklower 
785*36401Ssklower 			/*
786*36401Ssklower 			 * stash the addresses in the net level pcb
787*36401Ssklower 			 * kind of like a pcbconnect() but don't need
788*36401Ssklower 			 * or want all those checks.
789*36401Ssklower 			 */
790*36401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
791*36401Ssklower 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
792*36401Ssklower 
793*36401Ssklower 			/*
794*36401Ssklower 			 * in the AF_INET case, we need the l,f addrs to contain the ports
795*36401Ssklower 			 */
796*36401Ssklower 			if( tpcb->tp_domain == AF_INET) {
797*36401Ssklower 				CHECK((fsufxlen != sizeof(short))||(lsufxlen != sizeof(short)),
798*36401Ssklower 					E_TP_ADDR_UNK, ts_inv_dref, respond,
799*36401Ssklower 					(fsufxloc - (caddr_t)hdr))
800*36401Ssklower 				bcopy (lsufxloc, &(satosin(laddr)->sin_port), sizeof(short));
801*36401Ssklower 				(tpcb->tp_nlproto->nlp_putsufx)(so->so_pcb, laddr, TP_LOCAL);
802*36401Ssklower 				/*
803*36401Ssklower 					this has already been done 'cause the fsufxlen is
804*36401Ssklower 					sizeof(short):
805*36401Ssklower 					bcopy (fsufxloc, &(satosin(faddr)->sin_port),
806*36401Ssklower 						sizeof(short));
807*36401Ssklower 					(tpcb->tp_nlproto->nlp_putsufx)(so->so_pcb, faddr,
808*36401Ssklower 						TP_FOREIGN);
809*36401Ssklower 				*/
810*36401Ssklower 			}
811*36401Ssklower 
812*36401Ssklower #ifdef TP_PERF_MEAS
813*36401Ssklower 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
814*36401Ssklower 				/* ok, let's create an mbuf for stashing the
815*36401Ssklower 				 * statistics if one doesn't already exist
816*36401Ssklower 				 */
817*36401Ssklower 				(void) tp_setup_perf(tpcb);
818*36401Ssklower 			}
819*36401Ssklower #endif TP_PERF_MEAS
820*36401Ssklower 			tpcb->tp_fref = sref;
821*36401Ssklower 
822*36401Ssklower 			/* We've already checked for consistency with the options
823*36401Ssklower 			 * set in tpp,  but we couldn't set them earlier because
824*36401Ssklower 			 * we didn't want to change options in the LISTENING tpcb.
825*36401Ssklower 			 * Now we set the options in the new socket's tpcb.
826*36401Ssklower 			 */
827*36401Ssklower 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
828*36401Ssklower 
829*36401Ssklower 			if(!tpcb->tp_use_checksum)
830*36401Ssklower 				IncStat(ts_csum_off);
831*36401Ssklower 			if(tpcb->tp_xpd_service)
832*36401Ssklower 				IncStat(ts_use_txpd);
833*36401Ssklower 			if(tpcb->tp_xtd_format)
834*36401Ssklower 				IncStat(ts_xtd_fmt);
835*36401Ssklower 
836*36401Ssklower 			/*
837*36401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
838*36401Ssklower 			 * so we can negotiate a reasonable max TPDU size.
839*36401Ssklower 			 */
840*36401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
841*36401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
842*36401Ssklower 			tpcb->tp_peer_acktime = acktime;
843*36401Ssklower 
844*36401Ssklower 			/*
845*36401Ssklower 			 * The following kludge is used to test retransmissions and
846*36401Ssklower 			 * timeout during connection establishment.
847*36401Ssklower 			 */
848*36401Ssklower 			IFDEBUG(D_ZDREF)
849*36401Ssklower 				IncStat(ts_zdebug);
850*36401Ssklower 				tpcb->tp_fref = 0;
851*36401Ssklower 			ENDDEBUG
852*36401Ssklower 		}
853*36401Ssklower 		IncStat(ts_CR_rcvd);
854*36401Ssklower 	} else if ( dutype == ER_TPDU_type ) {
855*36401Ssklower 		/*
856*36401Ssklower 		 * ER TPDUs have to be recognized separately
857*36401Ssklower 		 * because they don't necessarily have a tpcb
858*36401Ssklower 		 * with them and we don't want err out looking for such
859*36401Ssklower 		 * a beast.
860*36401Ssklower 		 * We could put a bunch of little kludges in the
861*36401Ssklower 		 * next section of code so it would avoid references to tpcb
862*36401Ssklower 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
863*36401Ssklower 		 * mess up code for data transfer.
864*36401Ssklower 		 */
865*36401Ssklower 		IncStat(ts_ER_rcvd);
866*36401Ssklower 		e.ev_number = ER_TPDU;
867*36401Ssklower 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
868*36401Ssklower 		takes_data = 1;
869*36401Ssklower 	} else {
870*36401Ssklower 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
871*36401Ssklower 
872*36401Ssklower 		/* In the next 4 checks,
873*36401Ssklower 		 * _tpduf is the fixed part; add 2 to get the dref bits of
874*36401Ssklower 		 * the fixed part (can't take the address of a bit field)
875*36401Ssklower 		 */
876*36401Ssklower 		if(cons_channel) {
877*36401Ssklower #if NARGOXTWENTYFIVE > 0
878*36401Ssklower 			extern struct tp_pcb *cons_chan_to_tpcb();
879*36401Ssklower 
880*36401Ssklower 			tpcb = cons_chan_to_tpcb( cons_channel );
881*36401Ssklower 			/* Problem:  We may have a legit
882*36401Ssklower 			 * error situation yet we may or may not have
883*36401Ssklower 			 * a correspondence between the tpcb and the vc,
884*36401Ssklower 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
885*36401Ssklower 			 *          <---  DR
886*36401Ssklower 			 * Now it's up to TP to look at the tpdu and do one of:
887*36401Ssklower 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
888*36401Ssklower 			 * nothing, if the circuit is already open (any other tpdu).
889*36401Ssklower 			 * Sigh.
890*36401Ssklower 			 */
891*36401Ssklower 
892*36401Ssklower 			/* I don't know about this error value */
893*36401Ssklower 			CHECK( (tpcb == (struct tp_pcb *)0) ,
894*36401Ssklower 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
895*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
896*36401Ssklower #else
897*36401Ssklower 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
898*36401Ssklower #endif NARGOXTWENTYFIVE > 0
899*36401Ssklower 
900*36401Ssklower 		} else {
901*36401Ssklower 
902*36401Ssklower 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
903*36401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
904*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
905*36401Ssklower 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
906*36401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
907*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
908*36401Ssklower 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
909*36401Ssklower 				E_TP_MISM_REFS,ts_inv_dref, respond,
910*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
911*36401Ssklower 		}
912*36401Ssklower 
913*36401Ssklower 		IFDEBUG(D_TPINPUT)
914*36401Ssklower 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
915*36401Ssklower 		ENDDEBUG
916*36401Ssklower 
917*36401Ssklower 		/* causes a DR to be sent for CC; ER for all else */
918*36401Ssklower 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
919*36401Ssklower 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
920*36401Ssklower 			ts_inv_dref, respond,
921*36401Ssklower 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
922*36401Ssklower 
923*36401Ssklower 		IFDEBUG(D_TPINPUT)
924*36401Ssklower 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
925*36401Ssklower 		ENDDEBUG
926*36401Ssklower 		/*
927*36401Ssklower 		 * At this point the state of the dref could be
928*36401Ssklower 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
929*36401Ssklower 		 *		   for example, DC may arrive after the close() has detached
930*36401Ssklower 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
931*36401Ssklower 		 * OPENING : a tpcb exists but no timers yet
932*36401Ssklower 		 * OPEN  : tpcb exists & timers are outstanding
933*36401Ssklower 		 */
934*36401Ssklower 
935*36401Ssklower 		dusize = tpcb->tp_tpdusize;
936*36401Ssklower 
937*36401Ssklower 		dutype = hdr->tpdu_type << 8; /* for the switch below */
938*36401Ssklower 
939*36401Ssklower 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
940*36401Ssklower 
941*36401Ssklower #		define caseof(x,y) case (((x)<<8)+(y))
942*36401Ssklower 		switch( dutype | vbptr(P)->tpv_code ) {
943*36401Ssklower 
944*36401Ssklower 			caseof( CC_TPDU_type, TPP_addl_opt ):
945*36401Ssklower 					/* not in class 0; 1 octet */
946*36401Ssklower 					vb_getval(P, u_char, addlopt);
947*36401Ssklower 					break;
948*36401Ssklower 			caseof( CC_TPDU_type, TPP_tpdu_size ):
949*36401Ssklower 					vb_getval(P, u_char, dusize);
950*36401Ssklower 					CHECK( (dusize < TP_MIN_TPDUSIZE || dusize >
951*36401Ssklower 						TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond,
952*36401Ssklower 						(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
953*36401Ssklower 					IFDEBUG(D_TPINPUT)
954*36401Ssklower 						printf("CC dusize 0x%x\n", dusize);
955*36401Ssklower 					ENDDEBUG
956*36401Ssklower 					break;
957*36401Ssklower 			caseof( CC_TPDU_type, TPP_calling_sufx):
958*36401Ssklower 					IFDEBUG(D_TPINPUT)
959*36401Ssklower 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
960*36401Ssklower 					ENDDEBUG
961*36401Ssklower 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
962*36401Ssklower 					lsufxlen = vbptr(P)->tpv_len;
963*36401Ssklower 					break;
964*36401Ssklower 			caseof(	CC_TPDU_type, TPP_acktime ):
965*36401Ssklower 					/* class 4 only, 2 octets */
966*36401Ssklower 					vb_getval(P, u_short, acktime);
967*36401Ssklower 					acktime = acktime/500; /* convert to slowtimo ticks */
968*36401Ssklower 					if( (short)acktime <=0 )
969*36401Ssklower 						acktime = 2;
970*36401Ssklower 					break;
971*36401Ssklower 			caseof(	CC_TPDU_type, TPP_called_sufx):
972*36401Ssklower 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
973*36401Ssklower 					fsufxlen = vbptr(P)->tpv_len;
974*36401Ssklower 					IFDEBUG(D_TPINPUT)
975*36401Ssklower 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
976*36401Ssklower 					ENDDEBUG
977*36401Ssklower 					break;
978*36401Ssklower 
979*36401Ssklower 			caseof( CC_TPDU_type,	TPP_checksum):
980*36401Ssklower 			caseof( DR_TPDU_type,	TPP_checksum):
981*36401Ssklower 			caseof( DT_TPDU_type,	TPP_checksum):
982*36401Ssklower 			caseof( XPD_TPDU_type,	TPP_checksum):
983*36401Ssklower 					if( tpcb->tp_use_checksum )  {
984*36401Ssklower 						CHECK( iso_check_csum(m, tpdu_len),
985*36401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
986*36401Ssklower 					}
987*36401Ssklower 					break;
988*36401Ssklower 
989*36401Ssklower 			/*  this is different from the above because in the context
990*36401Ssklower 			 *  of concat/ sep tpdu_len might not be the same as hdr len
991*36401Ssklower 			 */
992*36401Ssklower 			caseof( AK_TPDU_type,	TPP_checksum):
993*36401Ssklower 			caseof( XAK_TPDU_type,	TPP_checksum):
994*36401Ssklower 			caseof( DC_TPDU_type,	TPP_checksum):
995*36401Ssklower 					if( tpcb->tp_use_checksum )  {
996*36401Ssklower 						CHECK( iso_check_csum(m, hdr->tpdu_li + 1),
997*36401Ssklower 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
998*36401Ssklower 					}
999*36401Ssklower 					break;
1000*36401Ssklower #ifdef notdef
1001*36401Ssklower 			caseof( DR_TPDU_type, TPP_addl_info ):
1002*36401Ssklower 				/* ignore - its length and meaning are
1003*36401Ssklower 				 * user defined and there's no way
1004*36401Ssklower 				 * to pass this info to the user anyway
1005*36401Ssklower 				 */
1006*36401Ssklower 				break;
1007*36401Ssklower #endif notdef
1008*36401Ssklower 
1009*36401Ssklower 			caseof( AK_TPDU_type, TPP_subseq ):
1010*36401Ssklower 				/* used after reduction of window */
1011*36401Ssklower 				vb_getval(P, u_short, subseq);
1012*36401Ssklower 				subseq = ntohs(subseq);
1013*36401Ssklower 				IFDEBUG(D_ACKRECV)
1014*36401Ssklower 					printf("AK Subsequence # 0x%x\n", subseq);
1015*36401Ssklower 				ENDDEBUG
1016*36401Ssklower 				break;
1017*36401Ssklower 
1018*36401Ssklower 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
1019*36401Ssklower 				{
1020*36401Ssklower 					u_int 	ylwe;
1021*36401Ssklower 					u_short ysubseq, ycredit;
1022*36401Ssklower 
1023*36401Ssklower 					fcc_present = TRUE;
1024*36401Ssklower 					vb_getval(P, u_int,	 	ylwe);
1025*36401Ssklower 					vb_getval(P, u_short, 	ysubseq);
1026*36401Ssklower 					vb_getval(P, u_short, 	ycredit);
1027*36401Ssklower 					ylwe = ntohl(ylwe);
1028*36401Ssklower 					ysubseq = ntohs(ysubseq);
1029*36401Ssklower 					ycredit = ntohs(ycredit);
1030*36401Ssklower 					IFDEBUG(D_ACKRECV)
1031*36401Ssklower 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
1032*36401Ssklower 							ylwe, ysubseq, ycredit);
1033*36401Ssklower 					ENDDEBUG
1034*36401Ssklower 				}
1035*36401Ssklower 				break;
1036*36401Ssklower 
1037*36401Ssklower 			default:
1038*36401Ssklower 				IFDEBUG(D_TPINPUT)
1039*36401Ssklower 					printf("param ignored dutype 0x%x, code  0x%x\n",
1040*36401Ssklower 						dutype, vbptr(P)->tpv_code);
1041*36401Ssklower 				ENDDEBUG
1042*36401Ssklower 				IFTRACE(D_TPINPUT)
1043*36401Ssklower 					tptrace(TPPTmisc, "param ignored dutype code ",
1044*36401Ssklower 						dutype, vbptr(P)->tpv_code ,0,0);
1045*36401Ssklower 				ENDTRACE
1046*36401Ssklower 				IncStat(ts_param_ignored);
1047*36401Ssklower 				break;
1048*36401Ssklower #undef caseof
1049*36401Ssklower 		}
1050*36401Ssklower 		/* } */ END_WHILE_OPTIONS(P)
1051*36401Ssklower 
1052*36401Ssklower 		/* NOTE: the variable dutype has been shifted left! */
1053*36401Ssklower 
1054*36401Ssklower 		switch( hdr->tpdu_type ) {
1055*36401Ssklower 		case CC_TPDU_type:
1056*36401Ssklower 			/* If CC comes back with an unacceptable class
1057*36401Ssklower 			 * respond with a DR or ER
1058*36401Ssklower 			 */
1059*36401Ssklower 
1060*36401Ssklower 			opt = hdr->tpdu_CCoptions; /* 1 byte */
1061*36401Ssklower 
1062*36401Ssklower 			{
1063*36401Ssklower 				tpp = tpcb->_tp_param;
1064*36401Ssklower 				tpp.p_class = (1<<hdr->tpdu_CCclass);
1065*36401Ssklower 				tpp.p_tpdusize = dusize;
1066*36401Ssklower 				tpp.p_dont_change_params = 0;
1067*36401Ssklower 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1068*36401Ssklower 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1069*36401Ssklower 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1070*36401Ssklower #ifdef notdef
1071*36401Ssklower 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1072*36401Ssklower 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1073*36401Ssklower 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
1074*36401Ssklower #endif notdef
1075*36401Ssklower 
1076*36401Ssklower 			CHECK(
1077*36401Ssklower 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1078*36401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1079*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1080*36401Ssklower 					/* ^ more or less the location of class */
1081*36401Ssklower 				)
1082*36401Ssklower 			IFTRACE(D_CONN)
1083*36401Ssklower 				tptrace(TPPTmisc,
1084*36401Ssklower 					"after 1 consist class, out, tpconsout",
1085*36401Ssklower 					tpcb->tp_class, dgout_routine, tpcons_output, 0
1086*36401Ssklower 					);
1087*36401Ssklower 			ENDTRACE
1088*36401Ssklower 			CHECK(
1089*36401Ssklower 				((class_to_use == TP_CLASS_0)&&
1090*36401Ssklower 					(dgout_routine != tpcons_output)),
1091*36401Ssklower 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1092*36401Ssklower 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1093*36401Ssklower 					/* ^ more or less the location of class */
1094*36401Ssklower 				)
1095*36401Ssklower 			}
1096*36401Ssklower 			if( ! tpcb->tp_use_checksum)
1097*36401Ssklower 				IncStat(ts_csum_off);
1098*36401Ssklower 			if(tpcb->tp_xpd_service)
1099*36401Ssklower 				IncStat(ts_use_txpd);
1100*36401Ssklower 			if(tpcb->tp_xtd_format)
1101*36401Ssklower 				IncStat(ts_xtd_fmt);
1102*36401Ssklower 
1103*36401Ssklower 			IFTRACE(D_CONN)
1104*36401Ssklower 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1105*36401Ssklower 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1106*36401Ssklower 					hdr->tpdu_CCclass);
1107*36401Ssklower 			ENDTRACE
1108*36401Ssklower 
1109*36401Ssklower 			/*
1110*36401Ssklower 			 * Get the maximum transmission unit from the lower layer(s)
1111*36401Ssklower 			 * so we can decide how large a TPDU size to negotiate.
1112*36401Ssklower 			 * It would be nice if the arguments to this
1113*36401Ssklower 			 * were more reasonable.
1114*36401Ssklower 			 */
1115*36401Ssklower 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
1116*36401Ssklower 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
1117*36401Ssklower 
1118*36401Ssklower #ifdef	CONS
1119*36401Ssklower 			/* Could be that this CC came in on a NEW vc, in which case
1120*36401Ssklower 			 * we have to confirm it.
1121*36401Ssklower 			 */
1122*36401Ssklower 			if( cons_channel )
1123*36401Ssklower 				cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
1124*36401Ssklower 						tpcb->tp_class == TP_CLASS_4);
1125*36401Ssklower #endif	CONS
1126*36401Ssklower 
1127*36401Ssklower 			tpcb->tp_peer_acktime = acktime;
1128*36401Ssklower 
1129*36401Ssklower 			/* if called or calling suffices appeared on the CC,
1130*36401Ssklower 			 * they'd better jive with what's in the pcb
1131*36401Ssklower 			 */
1132*36401Ssklower 			if( fsufxlen ) {
1133*36401Ssklower 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
1134*36401Ssklower 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1135*36401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
1136*36401Ssklower 					(1+fsufxloc - (caddr_t)hdr))
1137*36401Ssklower 			}
1138*36401Ssklower 			if( lsufxlen ) {
1139*36401Ssklower 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
1140*36401Ssklower 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1141*36401Ssklower 					E_TP_INV_PVAL,ts_inv_sufx, respond,
1142*36401Ssklower 					(1+lsufxloc - (caddr_t)hdr))
1143*36401Ssklower 			}
1144*36401Ssklower 
1145*36401Ssklower #ifdef notdef
1146*36401Ssklower 			e.ATTR(CC_TPDU).e_sref =  (u_short)hdr->tpdu_CCsref;
1147*36401Ssklower #else
1148*36401Ssklower 			e.ATTR(CC_TPDU).e_sref =  sref;
1149*36401Ssklower #endif notdef
1150*36401Ssklower 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
1151*36401Ssklower 			takes_data = TRUE;
1152*36401Ssklower 			e.ev_number = CC_TPDU;
1153*36401Ssklower 			IncStat(ts_CC_rcvd);
1154*36401Ssklower 			break;
1155*36401Ssklower 
1156*36401Ssklower 		case DC_TPDU_type:
1157*36401Ssklower #ifdef notdef
1158*36401Ssklower 			if (hdr->tpdu_DCsref != tpcb->tp_fref)
1159*36401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1160*36401Ssklower 					hdr->tpdu_DCsref, tpcb->tp_fref);
1161*36401Ssklower #else
1162*36401Ssklower 			if (sref != tpcb->tp_fref)
1163*36401Ssklower 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1164*36401Ssklower 					sref, tpcb->tp_fref);
1165*36401Ssklower #endif notdef
1166*36401Ssklower 
1167*36401Ssklower #ifdef notdef
1168*36401Ssklower 			CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref),
1169*36401Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, respond,
1170*36401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1171*36401Ssklower #else
1172*36401Ssklower 			CHECK( (sref != tpcb->tp_fref),
1173*36401Ssklower 				E_TP_MISM_REFS, ts_inv_sufx, respond,
1174*36401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1175*36401Ssklower #endif notdef
1176*36401Ssklower 			e.ev_number = DC_TPDU;
1177*36401Ssklower 			IncStat(ts_DC_rcvd);
1178*36401Ssklower 			break;
1179*36401Ssklower 
1180*36401Ssklower 		case DR_TPDU_type:
1181*36401Ssklower 			IFTRACE(D_TPINPUT)
1182*36401Ssklower 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1183*36401Ssklower 			ENDTRACE
1184*36401Ssklower #ifdef vax
1185*36401Ssklower 			if(sref != tpcb->tp_fref)
1186*36401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1187*36401Ssklower 					sref, tpcb->tp_fref);
1188*36401Ssklower 
1189*36401Ssklower 			CHECK( (sref != tpcb->tp_fref),
1190*36401Ssklower 				E_TP_MISM_REFS,ts_inv_sufx, respond,
1191*36401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1192*36401Ssklower 
1193*36401Ssklower 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
1194*36401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
1195*36401Ssklower #else
1196*36401Ssklower 			if(hdr->tpdu_DRsref != tpcb->tp_fref)
1197*36401Ssklower 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1198*36401Ssklower 					hdr->tpdu_DRsref, tpcb->tp_fref);
1199*36401Ssklower 
1200*36401Ssklower 			CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref),
1201*36401Ssklower 				E_TP_MISM_REFS,ts_inv_sufx, respond,
1202*36401Ssklower 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1203*36401Ssklower 
1204*36401Ssklower 			e.ATTR(DR_TPDU).e_reason =
1205*36401Ssklower 				hdr->tpdu_DRreason;
1206*36401Ssklower 			e.ATTR(DR_TPDU).e_sref =  (u_short)hdr->tpdu_DRsref;
1207*36401Ssklower #endif vax
1208*36401Ssklower 			takes_data = TRUE;
1209*36401Ssklower 			e.ev_number = DR_TPDU;
1210*36401Ssklower 			IncStat(ts_DR_rcvd);
1211*36401Ssklower 			break;
1212*36401Ssklower 
1213*36401Ssklower 		case ER_TPDU_type:
1214*36401Ssklower 			IFTRACE(D_TPINPUT)
1215*36401Ssklower 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
1216*36401Ssklower 			ENDTRACE
1217*36401Ssklower 			e.ev_number = ER_TPDU;
1218*36401Ssklower 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
1219*36401Ssklower 			IncStat(ts_ER_rcvd);
1220*36401Ssklower 			break;
1221*36401Ssklower 
1222*36401Ssklower 		case AK_TPDU_type:
1223*36401Ssklower 
1224*36401Ssklower 			e.ATTR(AK_TPDU).e_subseq = subseq;
1225*36401Ssklower 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
1226*36401Ssklower 
1227*36401Ssklower 			if (tpcb->tp_xtd_format) {
1228*36401Ssklower #ifdef BYTE_ORDER
1229*36401Ssklower 				union seq_type seqeotX;
1230*36401Ssklower 
1231*36401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1232*36401Ssklower 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
1233*36401Ssklower 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1234*36401Ssklower #else
1235*36401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
1236*36401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
1237*36401Ssklower #endif BYTE_ORDER
1238*36401Ssklower 			} else {
1239*36401Ssklower 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
1240*36401Ssklower 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
1241*36401Ssklower 			}
1242*36401Ssklower 			IFTRACE(D_TPINPUT)
1243*36401Ssklower 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1244*36401Ssklower 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
1245*36401Ssklower 					subseq, fcc_present);
1246*36401Ssklower 			ENDTRACE
1247*36401Ssklower 
1248*36401Ssklower 			e.ev_number = AK_TPDU;
1249*36401Ssklower 			IncStat(ts_AK_rcvd);
1250*36401Ssklower 			IncPStat(tpcb, tps_AK_rcvd);
1251*36401Ssklower 			break;
1252*36401Ssklower 
1253*36401Ssklower 		case XAK_TPDU_type:
1254*36401Ssklower 			if (tpcb->tp_xtd_format) {
1255*36401Ssklower #ifdef BYTE_ORDER
1256*36401Ssklower 				union seq_type seqeotX;
1257*36401Ssklower 
1258*36401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1259*36401Ssklower 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
1260*36401Ssklower #else
1261*36401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
1262*36401Ssklower #endif BYTE_ORDER
1263*36401Ssklower 			} else {
1264*36401Ssklower 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
1265*36401Ssklower 			}
1266*36401Ssklower 			e.ev_number = XAK_TPDU;
1267*36401Ssklower 			IncStat(ts_XAK_rcvd);
1268*36401Ssklower 			IncPStat(tpcb, tps_XAK_rcvd);
1269*36401Ssklower 			break;
1270*36401Ssklower 
1271*36401Ssklower 		case XPD_TPDU_type:
1272*36401Ssklower 			if (tpcb->tp_xtd_format) {
1273*36401Ssklower #ifdef BYTE_ORDER
1274*36401Ssklower 				union seq_type seqeotX;
1275*36401Ssklower 
1276*36401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1277*36401Ssklower 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
1278*36401Ssklower #else
1279*36401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
1280*36401Ssklower #endif BYTE_ORDER
1281*36401Ssklower 			} else {
1282*36401Ssklower 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
1283*36401Ssklower 			}
1284*36401Ssklower 			takes_data = TRUE;
1285*36401Ssklower 			e.ev_number = XPD_TPDU;
1286*36401Ssklower 			IncStat(ts_XPD_rcvd);
1287*36401Ssklower 			IncPStat(tpcb, tps_XPD_rcvd);
1288*36401Ssklower 			break;
1289*36401Ssklower 
1290*36401Ssklower 		case DT_TPDU_type:
1291*36401Ssklower 			{ /* the y option will cause occasional packets to be dropped.
1292*36401Ssklower 			   * A little crude but it works.
1293*36401Ssklower 			   */
1294*36401Ssklower 
1295*36401Ssklower 				IFDEBUG(D_DROP)
1296*36401Ssklower 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
1297*36401Ssklower 						IncStat(ts_ydebug);
1298*36401Ssklower 						goto discard;
1299*36401Ssklower 					}
1300*36401Ssklower 				ENDDEBUG
1301*36401Ssklower 			}
1302*36401Ssklower 			if (tpcb->tp_class == TP_CLASS_0) {
1303*36401Ssklower 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
1304*36401Ssklower 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
1305*36401Ssklower 			} else if (tpcb->tp_xtd_format) {
1306*36401Ssklower #ifdef BYTE_ORDER
1307*36401Ssklower 				union seq_type seqeotX;
1308*36401Ssklower 
1309*36401Ssklower 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1310*36401Ssklower 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
1311*36401Ssklower 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
1312*36401Ssklower #else
1313*36401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
1314*36401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
1315*36401Ssklower #endif BYTE_ORDER
1316*36401Ssklower 			} else {
1317*36401Ssklower 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
1318*36401Ssklower 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
1319*36401Ssklower 			}
1320*36401Ssklower 			if(e.ATTR(DT_TPDU).e_eot)
1321*36401Ssklower 				IncStat(ts_eot_input);
1322*36401Ssklower 			takes_data = TRUE;
1323*36401Ssklower 			e.ev_number = DT_TPDU;
1324*36401Ssklower 			IncStat(ts_DT_rcvd);
1325*36401Ssklower 			IncPStat(tpcb, tps_DT_rcvd);
1326*36401Ssklower 			break;
1327*36401Ssklower 
1328*36401Ssklower 		case GR_TPDU_type:
1329*36401Ssklower 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1330*36401Ssklower 			/* drop through */
1331*36401Ssklower 		default:
1332*36401Ssklower 			/* this should NEVER happen because there is a
1333*36401Ssklower 			 * check for dutype well above here
1334*36401Ssklower 			 */
1335*36401Ssklower 			error = E_TP_INV_TPDU; /* causes an ER  */
1336*36401Ssklower 			IFDEBUG(D_TPINPUT)
1337*36401Ssklower 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1338*36401Ssklower 			ENDDEBUG
1339*36401Ssklower 			IncStat(ts_inv_dutype);
1340*36401Ssklower 			goto respond;
1341*36401Ssklower 		}
1342*36401Ssklower 	}
1343*36401Ssklower 
1344*36401Ssklower 	/* peel off the tp header;
1345*36401Ssklower 	 * remember that the du_li doesn't count itself.
1346*36401Ssklower 	 * This may leave us w/ an empty mbuf at the front of a chain.
1347*36401Ssklower 	 * We can't just throw away the empty mbuf because hdr still points
1348*36401Ssklower 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
1349*36401Ssklower 	 */
1350*36401Ssklower 	m->m_len -= ((int)hdr->tpdu_li + 1);
1351*36401Ssklower 	m->m_off += ((int)hdr->tpdu_li + 1);
1352*36401Ssklower 
1353*36401Ssklower 	if(takes_data) {
1354*36401Ssklower 		register int max;
1355*36401Ssklower 
1356*36401Ssklower 		switch( hdr->tpdu_type ) {
1357*36401Ssklower 		case CR_TPDU_type:
1358*36401Ssklower 		case CC_TPDU_type:
1359*36401Ssklower 		case DR_TPDU_type:
1360*36401Ssklower 		case XPD_TPDU_type:
1361*36401Ssklower 		case DT_TPDU_type:
1362*36401Ssklower 			e.ATTR(DT_TPDU).e_datalen = tpdu_len - hdr->tpdu_li - 1;
1363*36401Ssklower 			max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
1364*36401Ssklower 			CHECK( (max && e.ATTR(DT_TPDU).e_datalen > max),
1365*36401Ssklower 				 E_TP_LENGTH_INVAL,ts_inv_length, respond, (max + hdr->tpdu_li + 1))
1366*36401Ssklower 
1367*36401Ssklower 			e.ATTR(DT_TPDU).e_data =  m;
1368*36401Ssklower 			break;
1369*36401Ssklower 
1370*36401Ssklower 		default:
1371*36401Ssklower 			printf(
1372*36401Ssklower 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1373*36401Ssklower 				hdr->tpdu_type, takes_data, m);
1374*36401Ssklower 			break;
1375*36401Ssklower 		}
1376*36401Ssklower 		/* prevent m_freem() after tp_driver() from throwing it all away */
1377*36401Ssklower 		m = MNULL;
1378*36401Ssklower 	}
1379*36401Ssklower 
1380*36401Ssklower 	IncStat(ts_tpdu_rcvd);
1381*36401Ssklower 
1382*36401Ssklower 	IFDEBUG(D_TPINPUT)
1383*36401Ssklower 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1384*36401Ssklower 			tpcb->tp_state, e.ev_number, m );
1385*36401Ssklower 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
1386*36401Ssklower 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1387*36401Ssklower 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
1388*36401Ssklower 	ENDDEBUG
1389*36401Ssklower 
1390*36401Ssklower 	if( tpcb->tp_decbit != 0 ) /* unsigned 4 bits */
1391*36401Ssklower 		tpcb->tp_decbit --;
1392*36401Ssklower 
1393*36401Ssklower 	error = tp_driver(tpcb, &e);
1394*36401Ssklower 
1395*36401Ssklower 	ASSERT(tpcb != (struct tp_pcb *)0);
1396*36401Ssklower 	ASSERT(tpcb->tp_sock != (struct socket *)0);
1397*36401Ssklower 	if( tpcb->tp_sock->so_error == 0 )
1398*36401Ssklower 		tpcb->tp_sock->so_error = error;
1399*36401Ssklower 
1400*36401Ssklower 	/* Kludge to keep the state tables under control (adding
1401*36401Ssklower 	 * data on connect & disconnect & freeing the mbuf containing
1402*36401Ssklower 	 * the data would have exploded the tables and made a big mess ).
1403*36401Ssklower 	 */
1404*36401Ssklower 	switch(e.ev_number) {
1405*36401Ssklower 		case CC_TPDU:
1406*36401Ssklower 		case DR_TPDU:
1407*36401Ssklower 		case CR_TPDU:
1408*36401Ssklower 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
1409*36401Ssklower 			IFDEBUG(D_TPINPUT)
1410*36401Ssklower 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1411*36401Ssklower 				m, takes_data);
1412*36401Ssklower 			ENDDEBUG
1413*36401Ssklower 			break;
1414*36401Ssklower 		default:
1415*36401Ssklower 			break;
1416*36401Ssklower 	}
1417*36401Ssklower 	/* Concatenated sequences are terminated by any tpdu that
1418*36401Ssklower 	 * carries data: CR, CC, DT, XPD, DR.
1419*36401Ssklower 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1420*36401Ssklower 	 */
1421*36401Ssklower 
1422*36401Ssklower separate:
1423*36401Ssklower 	if ( takes_data == 0 )  {
1424*36401Ssklower 		ASSERT( m != MNULL );
1425*36401Ssklower 		/*
1426*36401Ssklower 		 * we already peeled off the prev. tp header so
1427*36401Ssklower 		 * we can just pull up some more and repeat
1428*36401Ssklower 		 */
1429*36401Ssklower 
1430*36401Ssklower 		IFDEBUG(D_TPINPUT)
1431*36401Ssklower 			hdr = mtod(m, struct tpdu *);
1432*36401Ssklower 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1433*36401Ssklower 			hdr, (int) hdr->tpdu_li + 1, m);
1434*36401Ssklower 			dump_mbuf(m, "tp_input after driver, at separate");
1435*36401Ssklower 		ENDDEBUG
1436*36401Ssklower 
1437*36401Ssklower 		if( m = tp_inputprep(m) ) {
1438*36401Ssklower 			IncStat(ts_concat_rcvd);
1439*36401Ssklower 			goto again;
1440*36401Ssklower 		}
1441*36401Ssklower 	}
1442*36401Ssklower 	if ( m != MNULL ) {
1443*36401Ssklower 		IFDEBUG(D_TPINPUT)
1444*36401Ssklower 			printf("tp_input : m_freem(0x%x)\n", m);
1445*36401Ssklower 		ENDDEBUG
1446*36401Ssklower 		m_freem(m);
1447*36401Ssklower 		IFDEBUG(D_TPINPUT)
1448*36401Ssklower 			printf("tp_input : after m_freem 0x%x\n", m);
1449*36401Ssklower 		ENDDEBUG
1450*36401Ssklower 	}
1451*36401Ssklower 	return (ProtoHook) tpcb;
1452*36401Ssklower 
1453*36401Ssklower discard:
1454*36401Ssklower 	/* class 4: drop the tpdu */
1455*36401Ssklower 	/* class 2,0: Should drop the net connection, if you can figure out
1456*36401Ssklower 	 * to which connection it applies
1457*36401Ssklower 	 */
1458*36401Ssklower 	IFDEBUG(D_TPINPUT)
1459*36401Ssklower 		printf("tp_input DISCARD\n");
1460*36401Ssklower 	ENDDEBUG
1461*36401Ssklower 	IFTRACE(D_TPINPUT)
1462*36401Ssklower 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
1463*36401Ssklower 	ENDTRACE
1464*36401Ssklower 	m_freem(m);
1465*36401Ssklower 	IncStat(ts_recv_drop);
1466*36401Ssklower 	return (ProtoHook)0;
1467*36401Ssklower 
1468*36401Ssklower respond:
1469*36401Ssklower 	IFDEBUG(D_ERROR_EMIT)
1470*36401Ssklower 		printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc);
1471*36401Ssklower 	ENDDEBUG
1472*36401Ssklower 	IFTRACE(D_TPINPUT)
1473*36401Ssklower 		tptrace(TPPTmisc, "tp_input RESPOND m error sref",  m,error,sref,0);
1474*36401Ssklower 	ENDTRACE
1475*36401Ssklower 	if( sref == 0 )
1476*36401Ssklower 		goto discard;
1477*36401Ssklower 	(void) tp_error_emit(error, sref, faddr, laddr,
1478*36401Ssklower 		m, errloc, tpcb, cons_channel, dgout_routine
1479*36401Ssklower 		);
1480*36401Ssklower 	IFDEBUG(D_ERROR_EMIT)
1481*36401Ssklower 		printf("tp_input after error_emit\n");
1482*36401Ssklower 	ENDDEBUG
1483*36401Ssklower 
1484*36401Ssklower #ifdef lint
1485*36401Ssklower 	printf("",sref,opt);
1486*36401Ssklower #endif lint
1487*36401Ssklower 	IncStat(ts_recv_drop);
1488*36401Ssklower 	return (ProtoHook)0;
1489*36401Ssklower }
1490*36401Ssklower 
1491*36401Ssklower 
1492*36401Ssklower /*
1493*36401Ssklower  * NAME: tp_headersize()
1494*36401Ssklower  *
1495*36401Ssklower  * CALLED FROM:
1496*36401Ssklower  *  tp_emit() and tp_sbsend()
1497*36401Ssklower  *  TP needs to know the header size so it can figure out how
1498*36401Ssklower  *  much data to put in each tpdu.
1499*36401Ssklower  *
1500*36401Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
1501*36401Ssklower  *  For a given connection, represented by (tpcb), and
1502*36401Ssklower  *  tpdu type (dutype), return the size of a tp header.
1503*36401Ssklower  *
1504*36401Ssklower  * RETURNS:	  the expected size of the heade in bytesr
1505*36401Ssklower  *
1506*36401Ssklower  * SIDE EFFECTS:
1507*36401Ssklower  *
1508*36401Ssklower  * NOTES:	 It would be nice if it got the network header size as well.
1509*36401Ssklower  */
1510*36401Ssklower int
1511*36401Ssklower tp_headersize(dutype, tpcb)
1512*36401Ssklower 	int 			dutype;
1513*36401Ssklower 	struct tp_pcb 	*tpcb;
1514*36401Ssklower {
1515*36401Ssklower 	register int size = 0;
1516*36401Ssklower 
1517*36401Ssklower 	IFTRACE(D_CONN)
1518*36401Ssklower 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1519*36401Ssklower 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1520*36401Ssklower 	ENDTRACE
1521*36401Ssklower 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
1522*36401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
1523*36401Ssklower 			(dutype == DR_TPDU_type) ||
1524*36401Ssklower 			(dutype == CR_TPDU_type) )) {
1525*36401Ssklower 				printf("tp_headersize:dutype 0x%x, class 0x%x",
1526*36401Ssklower 			dutype, tpcb->tp_class);
1527*36401Ssklower 	/* TODO: identify this and GET RID OF IT */
1528*36401Ssklower 	}
1529*36401Ssklower 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
1530*36401Ssklower 			(tpcb->tp_class == TP_CLASS_4) ||
1531*36401Ssklower 			(dutype == DR_TPDU_type) ||
1532*36401Ssklower 			(dutype == CR_TPDU_type) );
1533*36401Ssklower 
1534*36401Ssklower 	if( tpcb->tp_class == TP_CLASS_0 ) {
1535*36401Ssklower 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
1536*36401Ssklower 	} else  {
1537*36401Ssklower 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
1538*36401Ssklower 	}
1539*36401Ssklower 	return size;
1540*36401Ssklower 	/* caller must get network level header size separately */
1541*36401Ssklower }
1542