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