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