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