xref: /original-bsd/sys/netiso/tp_input.c (revision 23c6a147)
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.7 (Berkeley) 03/26/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;
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 				CHECK( (vbval(P, u_char) != TP_VERSION ),
563 					E_TP_INV_PVAL, ts_inv_pval, respond,
564 					(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
565 				break;
566 			case	TPP_acktime:
567 				vb_getval(P, u_short, acktime);
568 				acktime = ntohs(acktime);
569 				acktime = acktime/500; /* convert to slowtimo ticks */
570 				if((short)acktime <=0 )
571 					acktime = 2; /* don't allow a bad peer to screw us up */
572 				IFDEBUG(D_TPINPUT)
573 					printf("CR acktime 0x%x\n", acktime);
574 				ENDDEBUG
575 				break;
576 
577 			case	TPP_alt_class:
578 				{
579 					u_char *aclass = 0;
580 					register int i;
581 
582 					for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
583 						aclass =
584 							(u_char *) &(((struct tp_vbp *)P)->tpv_val);
585 						alt_classes |= (1<<((*aclass)>>4));
586 					}
587 					IFDEBUG(D_TPINPUT)
588 						printf("alt_classes 0x%x\n", alt_classes);
589 					ENDDEBUG
590 				}
591 				break;
592 
593 			case	TPP_security:
594 			case	TPP_residER:
595 			case	TPP_priority:
596 			case	TPP_transdelay:
597 			case	TPP_throughput:
598 			case	TPP_addl_info:
599 			case	TPP_subseq:
600 				IFDEBUG(D_TPINPUT)
601 					printf("param ignored CR_TPDU code= 0x%x\n",
602 						 vbptr(P)->tpv_code);
603 				ENDDEBUG
604 				IncStat(ts_param_ignored);
605 				break;
606 
607 			case	TPP_checksum:
608 				IFDEBUG(D_TPINPUT)
609 					printf("CR before cksum\n");
610 				ENDDEBUG
611 
612 				CHECK( iso_check_csum(m, tpdu_len),
613 					E_TP_INV_PVAL, ts_bad_csum, discard, 0)
614 
615 				IFDEBUG(D_TPINPUT)
616 					printf("CR before cksum\n");
617 				ENDDEBUG
618 				break;
619 
620 			default:
621 				IncStat(ts_inv_pcode);
622 				error = E_TP_INV_PCODE;
623 				goto discard;
624 
625 			}
626 
627 		/* } */ END_WHILE_OPTIONS(P)
628 
629 		if( lsufxlen == 0) {
630 			/* can't look for a tpcb w/o any called sufx */
631 			error =  E_TP_LENGTH_INVAL;
632 			IncStat(ts_inv_sufx);
633 			goto respond;
634 		} else {
635 			register	struct tp_ref 	*rp;
636 			register	int			r;
637 			extern		int			tp_maxrefopen;
638 
639 			rp = &tp_ref[1]; /* zero-th one is never open */
640 			for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
641 				if (rp->tpr_state!=REF_OPENING)
642 					continue;
643 				if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) {
644 					tpcb =  rp->tpr_pcb;
645 					if( laddr->sa_family !=
646 							tpcb->tp_sock->so_proto->pr_domain->dom_family ) {
647 						IFDEBUG(D_CONN)
648 						 	printf(
649 					"MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n",
650 							laddr->sa_family,
651 							tpcb->tp_sock->so_proto->pr_domain->dom_family );
652 						ENDDEBUG
653 						continue;
654 					}
655 					IFTRACE(D_TPINPUT)
656 						tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate",
657 							r, *lsufxloc, rp->tpr_state, 0);
658 					ENDTRACE
659 					/* found it */
660 					break;
661 				}
662 			}
663 
664 			CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond,
665 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
666 				/* _tpduf is the fixed part; add 2 to get the dref bits of
667 				 * the fixed part (can't take the address of a bit field)
668 				 */
669 		}
670 
671 		/*
672 		 * WE HAVE A TPCB
673 		 * already know that the classes in the CR match at least
674 		 * one class implemented, but we don't know yet if they
675 		 * include any classes permitted by this server.
676 		 */
677 
678 		IFDEBUG(D_TPINPUT)
679 			printf("HAVE A TPCB 1: 0x%x\n", tpcb);
680 		ENDDEBUG
681 		IFDEBUG(D_CONN)
682 			printf(
683 "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
684 				tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
685 		ENDDEBUG
686 		/* tpcb->tp_class doesn't include any classes not implemented  */
687 		class_to_use = (preferred_class & tpcb->tp_class);
688 		if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
689 			class_to_use = alt_classes & tpcb->tp_class;
690 
691 		class_to_use = 1 << tp_mask_to_num(class_to_use);
692 
693 		{
694 			tpp = tpcb->_tp_param;
695 			tpp.p_class = class_to_use;
696 			tpp.p_tpdusize = dusize;
697 			tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
698 			tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
699 			tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
700 				(addlopt & TPAO_NO_CSUM) == 0;
701 #ifdef notdef
702 			tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
703 			tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
704 			tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
705 #endif notdef
706 
707 		CHECK(
708 			tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
709 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
710 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
711 				/* ^ more or less the location of class */
712 			)
713 		}
714 		IFTRACE(D_CONN)
715 			tptrace(TPPTmisc,
716 				"after 1 consist class_to_use class, out, tpconsout",
717 				class_to_use,
718 				tpcb->tp_class, dgout_routine, tpcons_output
719 				);
720 		ENDTRACE
721 		CHECK(
722 			((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
723 			E_TP_NEGOT_FAILED, ts_negotfailed, respond,
724 			(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
725 				/* ^ more or less the location of class */
726 			)
727 		IFDEBUG(D_CONN)
728 			printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
729 				tpcb, tpcb->tp_flags);
730 		ENDDEBUG
731 		takes_data = TRUE;
732 		e.ATTR(CR_TPDU).e_cdt  =  hdr->tpdu_CRcdt;
733 		e.ev_number = CR_TPDU;
734 
735 		so = tpcb->tp_sock;
736 		if (so->so_options & SO_ACCEPTCONN) {
737 			/*
738 			 * Create a socket, tpcb, ll pcb, etc.
739 			 * for this newborn connection, and fill in all the values.
740 			 */
741 			IFDEBUG(D_CONN)
742 				printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
743 					so, laddr, faddr, cons_channel);
744 			ENDDEBUG
745 			if( (so =
746 				tp_newsocket(so, faddr, cons_channel,
747 					class_to_use,
748 					((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
749 					(dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
750 					) == (struct socket *)0 ) {
751 				/* note - even if netservice is IN_CLNS, as far as
752 				 * the tp entity is concerned, the only differences
753 				 * are CO vs CL
754 				 */
755 				IFDEBUG(D_CONN)
756 					printf("tp_newsocket returns 0\n");
757 				ENDDEBUG
758 				goto discard;
759 			}
760 			tpcb = sototpcb(so);
761 
762 			/*
763 			 * Stash the addresses in the net level pcb
764 			 * kind of like a pcbconnect() but don't need
765 			 * or want all those checks.
766 			 */
767 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
768 			(tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
769 
770 			/* stash the f suffix in the new tpcb */
771 			/* l suffix is already there */
772 			bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
773 
774 			(tpcb->tp_nlproto->nlp_putsufx)
775 					(so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
776 			(tpcb->tp_nlproto->nlp_putsufx)
777 					(so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
778 
779 #ifdef TP_PERF_MEAS
780 			if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
781 				/* ok, let's create an mbuf for stashing the
782 				 * statistics if one doesn't already exist
783 				 */
784 				(void) tp_setup_perf(tpcb);
785 			}
786 #endif TP_PERF_MEAS
787 			tpcb->tp_fref = sref;
788 
789 			/* We've already checked for consistency with the options
790 			 * set in tpp,  but we couldn't set them earlier because
791 			 * we didn't want to change options in the LISTENING tpcb.
792 			 * Now we set the options in the new socket's tpcb.
793 			 */
794 			(void) tp_consistency( tpcb, TP_FORCE, &tpp);
795 
796 			if(!tpcb->tp_use_checksum)
797 				IncStat(ts_csum_off);
798 			if(tpcb->tp_xpd_service)
799 				IncStat(ts_use_txpd);
800 			if(tpcb->tp_xtd_format)
801 				IncStat(ts_xtd_fmt);
802 
803 			/*
804 			 * Get the maximum transmission unit from the lower layer(s)
805 			 * so we can negotiate a reasonable max TPDU size.
806 			 */
807 			(tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
808 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
809 			tpcb->tp_peer_acktime = acktime;
810 
811 			/*
812 			 * The following kludge is used to test retransmissions and
813 			 * timeout during connection establishment.
814 			 */
815 			IFDEBUG(D_ZDREF)
816 				IncStat(ts_zdebug);
817 				/*tpcb->tp_fref = 0;*/
818 			ENDDEBUG
819 		}
820 		IncStat(ts_CR_rcvd);
821 		if (!tpcb->tp_cebit_off) {
822 			tpcb->tp_win_recv = tp_start_win << 8;
823 			tpcb->tp_cong_sample.cs_size = 0;
824 			LOCAL_CREDIT(tpcb);
825 			CONG_INIT_SAMPLE(tpcb);
826 			CONG_UPDATE_SAMPLE(tpcb, ce_bit);
827 		}
828 		tpcb->tp_ackrcvd = 0;
829 	} else if ( dutype == ER_TPDU_type ) {
830 		/*
831 		 * ER TPDUs have to be recognized separately
832 		 * because they don't necessarily have a tpcb
833 		 * with them and we don't want err out looking for such
834 		 * a beast.
835 		 * We could put a bunch of little kludges in the
836 		 * next section of code so it would avoid references to tpcb
837 		 * if dutype == ER_TPDU_type but we don't want code for ERs to
838 		 * mess up code for data transfer.
839 		 */
840 		IncStat(ts_ER_rcvd);
841 		e.ev_number = ER_TPDU;
842 		e.ATTR(ER_TPDU).e_reason =  (u_char)hdr->tpdu_ERreason;
843 		takes_data = 1;
844 	} else {
845 		/* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
846 
847 		/* In the next 4 checks,
848 		 * _tpduf is the fixed part; add 2 to get the dref bits of
849 		 * the fixed part (can't take the address of a bit field)
850 		 */
851 		if(cons_channel) {
852 #if NARGOXTWENTYFIVE > 0
853 			extern struct tp_pcb *cons_chan_to_tpcb();
854 
855 			tpcb = cons_chan_to_tpcb( cons_channel );
856 			/* Problem:  We may have a legit
857 			 * error situation yet we may or may not have
858 			 * a correspondence between the tpcb and the vc,
859 			 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
860 			 *          <---  DR
861 			 * Now it's up to TP to look at the tpdu and do one of:
862 			 * confirm(dgm)(cr),  confirm(circuit)(cr), reject(cr), or
863 			 * nothing, if the circuit is already open (any other tpdu).
864 			 * Sigh.
865 			 */
866 
867 			/* I don't know about this error value */
868 			CHECK( (tpcb == (struct tp_pcb *)0) ,
869 				E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
870 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
871 #else
872 			printf("tp_input(): X25 NOT CONFIGURED!!\n");
873 #endif NARGOXTWENTYFIVE > 0
874 
875 		} else {
876 
877 			CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
878 				E_TP_MISM_REFS,ts_inv_dref, respond,
879 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
880 			CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
881 				E_TP_MISM_REFS,ts_inv_dref, respond,
882 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
883 			CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
884 				E_TP_MISM_REFS,ts_inv_dref, respond,
885 				(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
886 		}
887 
888 		IFDEBUG(D_TPINPUT)
889 			printf("HAVE A TPCB 2: 0x%x\n", tpcb);
890 		ENDDEBUG
891 
892 		/* causes a DR to be sent for CC; ER for all else */
893 		CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
894 			(dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
895 			ts_inv_dref, respond,
896 			(1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
897 
898 		IFDEBUG(D_TPINPUT)
899 			printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
900 		ENDDEBUG
901 		/*
902 		 * At this point the state of the dref could be
903 		 * FROZEN: tpr_pcb == NULL,  has ( reference only) timers
904 		 *		   for example, DC may arrive after the close() has detached
905 		 *         the tpcb (e.g., if user turned off SO_LISTEN option)
906 		 * OPENING : a tpcb exists but no timers yet
907 		 * OPEN  : tpcb exists & timers are outstanding
908 		 */
909 
910         if (!tpcb->tp_cebit_off)
911             CONG_UPDATE_SAMPLE(tpcb, ce_bit);
912 
913 		dusize = tpcb->tp_tpdusize;
914 
915 		dutype = hdr->tpdu_type << 8; /* for the switch below */
916 
917 		WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
918 
919 #define caseof(x,y) case (((x)<<8)+(y))
920 		switch( dutype | vbptr(P)->tpv_code ) {
921 
922 			caseof( CC_TPDU_type, TPP_addl_opt ):
923 					/* not in class 0; 1 octet */
924 					vb_getval(P, u_char, addlopt);
925 					break;
926 			caseof( CC_TPDU_type, TPP_tpdu_size ):
927 					vb_getval(P, u_char, dusize);
928 					CHECK( (dusize < TP_MIN_TPDUSIZE || dusize >
929 						TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond,
930 						(1 + (caddr_t)&vbptr(P)->tpv_val - P) )
931 					IFDEBUG(D_TPINPUT)
932 						printf("CC dusize 0x%x\n", dusize);
933 					ENDDEBUG
934 					break;
935 			caseof( CC_TPDU_type, TPP_calling_sufx):
936 					IFDEBUG(D_TPINPUT)
937 						printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
938 					ENDDEBUG
939 					lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
940 					lsufxlen = vbptr(P)->tpv_len;
941 					break;
942 			caseof(	CC_TPDU_type, TPP_acktime ):
943 					/* class 4 only, 2 octets */
944 					vb_getval(P, u_short, acktime);
945 					acktime = acktime/500; /* convert to slowtimo ticks */
946 					if( (short)acktime <=0 )
947 						acktime = 2;
948 					break;
949 			caseof(	CC_TPDU_type, TPP_called_sufx):
950 					fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
951 					fsufxlen = vbptr(P)->tpv_len;
952 					IFDEBUG(D_TPINPUT)
953 						printf("CC called (foreign) sufx len %d\n", fsufxlen);
954 					ENDDEBUG
955 					break;
956 
957 			caseof( CC_TPDU_type,	TPP_checksum):
958 			caseof( DR_TPDU_type,	TPP_checksum):
959 			caseof( DT_TPDU_type,	TPP_checksum):
960 			caseof( XPD_TPDU_type,	TPP_checksum):
961 					if( tpcb->tp_use_checksum )  {
962 						CHECK( iso_check_csum(m, tpdu_len),
963 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
964 					}
965 					break;
966 
967 			/*  this is different from the above because in the context
968 			 *  of concat/ sep tpdu_len might not be the same as hdr len
969 			 */
970 			caseof( AK_TPDU_type,	TPP_checksum):
971 			caseof( XAK_TPDU_type,	TPP_checksum):
972 			caseof( DC_TPDU_type,	TPP_checksum):
973 					if( tpcb->tp_use_checksum )  {
974 						CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
975 							E_TP_INV_PVAL, ts_bad_csum, discard, 0)
976 					}
977 					break;
978 #ifdef notdef
979 			caseof( DR_TPDU_type, TPP_addl_info ):
980 				/* ignore - its length and meaning are
981 				 * user defined and there's no way
982 				 * to pass this info to the user anyway
983 				 */
984 				break;
985 #endif notdef
986 
987 			caseof( AK_TPDU_type, TPP_subseq ):
988 				/* used after reduction of window */
989 				vb_getval(P, u_short, subseq);
990 				subseq = ntohs(subseq);
991 				IFDEBUG(D_ACKRECV)
992 					printf("AK Subsequence # 0x%x\n", subseq);
993 				ENDDEBUG
994 				break;
995 
996 			caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
997 				{
998 					u_int 	ylwe;
999 					u_short ysubseq, ycredit;
1000 
1001 					fcc_present = TRUE;
1002 					vb_getval(P, u_int,	 	ylwe);
1003 					vb_getval(P, u_short, 	ysubseq);
1004 					vb_getval(P, u_short, 	ycredit);
1005 					ylwe = ntohl(ylwe);
1006 					ysubseq = ntohs(ysubseq);
1007 					ycredit = ntohs(ycredit);
1008 					IFDEBUG(D_ACKRECV)
1009 						printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
1010 							ylwe, ysubseq, ycredit);
1011 					ENDDEBUG
1012 				}
1013 				break;
1014 
1015 			default:
1016 				IFDEBUG(D_TPINPUT)
1017 					printf("param ignored dutype 0x%x, code  0x%x\n",
1018 						dutype, vbptr(P)->tpv_code);
1019 				ENDDEBUG
1020 				IFTRACE(D_TPINPUT)
1021 					tptrace(TPPTmisc, "param ignored dutype code ",
1022 						dutype, vbptr(P)->tpv_code ,0,0);
1023 				ENDTRACE
1024 				IncStat(ts_param_ignored);
1025 				break;
1026 #undef caseof
1027 		}
1028 		/* } */ END_WHILE_OPTIONS(P)
1029 
1030 		/* NOTE: the variable dutype has been shifted left! */
1031 
1032 		switch( hdr->tpdu_type ) {
1033 		case CC_TPDU_type:
1034 			/* If CC comes back with an unacceptable class
1035 			 * respond with a DR or ER
1036 			 */
1037 
1038 			opt = hdr->tpdu_CCoptions; /* 1 byte */
1039 
1040 			{
1041 				tpp = tpcb->_tp_param;
1042 				tpp.p_class = (1<<hdr->tpdu_CCclass);
1043 				tpp.p_tpdusize = dusize;
1044 				tpp.p_dont_change_params = 0;
1045 				tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1046 				tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1047 				tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1048 #ifdef notdef
1049 				tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1050 				tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1051 				tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
1052 #endif notdef
1053 
1054 			CHECK(
1055 				tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1056 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1057 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1058 					/* ^ more or less the location of class */
1059 				)
1060 			IFTRACE(D_CONN)
1061 				tptrace(TPPTmisc,
1062 					"after 1 consist class, out, tpconsout",
1063 					tpcb->tp_class, dgout_routine, tpcons_output, 0
1064 					);
1065 			ENDTRACE
1066 			CHECK(
1067 				((class_to_use == TP_CLASS_0)&&
1068 					(dgout_routine != tpcons_output)),
1069 				E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1070 				(1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1071 					/* ^ more or less the location of class */
1072 				)
1073 			}
1074 			if( ! tpcb->tp_use_checksum)
1075 				IncStat(ts_csum_off);
1076 			if(tpcb->tp_xpd_service)
1077 				IncStat(ts_use_txpd);
1078 			if(tpcb->tp_xtd_format)
1079 				IncStat(ts_xtd_fmt);
1080 
1081 			IFTRACE(D_CONN)
1082 				tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1083 					tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1084 					hdr->tpdu_CCclass);
1085 			ENDTRACE
1086 
1087 			/*
1088 			 * Get the maximum transmission unit from the lower layer(s)
1089 			 * so we can decide how large a TPDU size to negotiate.
1090 			 * It would be nice if the arguments to this
1091 			 * were more reasonable.
1092 			 */
1093 			(tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
1094 						&tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
1095 
1096 #ifdef	CONS
1097 			/* Could be that this CC came in on a NEW vc, in which case
1098 			 * we have to confirm it.
1099 			 */
1100 			if( cons_channel )
1101 				cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
1102 						tpcb->tp_class == TP_CLASS_4);
1103 #endif	CONS
1104 
1105 			tpcb->tp_peer_acktime = acktime;
1106 
1107 			/* if called or calling suffices appeared on the CC,
1108 			 * they'd better jive with what's in the pcb
1109 			 */
1110 			if( fsufxlen ) {
1111 				CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
1112 					bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1113 					E_TP_INV_PVAL,ts_inv_sufx, respond,
1114 					(1+fsufxloc - (caddr_t)hdr))
1115 			}
1116 			if( lsufxlen ) {
1117 				CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
1118 					bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1119 					E_TP_INV_PVAL,ts_inv_sufx, respond,
1120 					(1+lsufxloc - (caddr_t)hdr))
1121 			}
1122 
1123 #ifdef notdef
1124 			e.ATTR(CC_TPDU).e_sref =  (u_short)hdr->tpdu_CCsref;
1125 #else
1126 			e.ATTR(CC_TPDU).e_sref =  sref;
1127 #endif notdef
1128 			e.ATTR(CC_TPDU).e_cdt  =  hdr->tpdu_CCcdt;
1129 			takes_data = TRUE;
1130 			e.ev_number = CC_TPDU;
1131 			IncStat(ts_CC_rcvd);
1132 			break;
1133 
1134 		case DC_TPDU_type:
1135 #ifdef notdef
1136 			if (hdr->tpdu_DCsref != tpcb->tp_fref)
1137 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1138 					hdr->tpdu_DCsref, tpcb->tp_fref);
1139 #else
1140 			if (sref != tpcb->tp_fref)
1141 				printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1142 					sref, tpcb->tp_fref);
1143 #endif notdef
1144 
1145 #ifdef notdef
1146 			CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref),
1147 				E_TP_MISM_REFS, ts_inv_sufx, respond,
1148 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1149 #else
1150 			CHECK( (sref != tpcb->tp_fref),
1151 				E_TP_MISM_REFS, ts_inv_sufx, respond,
1152 				(1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1153 #endif notdef
1154 			e.ev_number = DC_TPDU;
1155 			IncStat(ts_DC_rcvd);
1156 			break;
1157 
1158 		case DR_TPDU_type:
1159 			IFTRACE(D_TPINPUT)
1160 				tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1161 			ENDTRACE
1162 #ifdef vax
1163 			if(sref != tpcb->tp_fref)
1164 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1165 					sref, tpcb->tp_fref);
1166 
1167 			CHECK( (sref != tpcb->tp_fref),
1168 				E_TP_MISM_REFS,ts_inv_sufx, respond,
1169 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1170 
1171 			e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
1172 			e.ATTR(DR_TPDU).e_sref =  (u_short)sref;
1173 #else
1174 			if(hdr->tpdu_DRsref != tpcb->tp_fref)
1175 				printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1176 					hdr->tpdu_DRsref, tpcb->tp_fref);
1177 
1178 			CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref),
1179 				E_TP_MISM_REFS,ts_inv_sufx, respond,
1180 				(1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1181 
1182 			e.ATTR(DR_TPDU).e_reason =
1183 				hdr->tpdu_DRreason;
1184 			e.ATTR(DR_TPDU).e_sref =  (u_short)hdr->tpdu_DRsref;
1185 #endif vax
1186 			takes_data = TRUE;
1187 			e.ev_number = DR_TPDU;
1188 			IncStat(ts_DR_rcvd);
1189 			break;
1190 
1191 		case ER_TPDU_type:
1192 			IFTRACE(D_TPINPUT)
1193 				tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
1194 			ENDTRACE
1195 			e.ev_number = ER_TPDU;
1196 			e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
1197 			IncStat(ts_ER_rcvd);
1198 			break;
1199 
1200 		case AK_TPDU_type:
1201 
1202 			e.ATTR(AK_TPDU).e_subseq = subseq;
1203 			e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
1204 
1205 			if (tpcb->tp_xtd_format) {
1206 #ifdef BYTE_ORDER
1207 				union seq_type seqeotX;
1208 
1209 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1210 				e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
1211 				e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1212 #else
1213 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
1214 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
1215 #endif BYTE_ORDER
1216 			} else {
1217 				e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
1218 				e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
1219 			}
1220 			IFTRACE(D_TPINPUT)
1221 				tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1222 					e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
1223 					subseq, fcc_present);
1224 			ENDTRACE
1225 
1226 			e.ev_number = AK_TPDU;
1227 			IncStat(ts_AK_rcvd);
1228 			IncPStat(tpcb, tps_AK_rcvd);
1229 			break;
1230 
1231 		case XAK_TPDU_type:
1232 			if (tpcb->tp_xtd_format) {
1233 #ifdef BYTE_ORDER
1234 				union seq_type seqeotX;
1235 
1236 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1237 				e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
1238 #else
1239 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
1240 #endif BYTE_ORDER
1241 			} else {
1242 				e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
1243 			}
1244 			e.ev_number = XAK_TPDU;
1245 			IncStat(ts_XAK_rcvd);
1246 			IncPStat(tpcb, tps_XAK_rcvd);
1247 			break;
1248 
1249 		case XPD_TPDU_type:
1250 			if (tpcb->tp_xtd_format) {
1251 #ifdef BYTE_ORDER
1252 				union seq_type seqeotX;
1253 
1254 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1255 				e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
1256 #else
1257 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
1258 #endif BYTE_ORDER
1259 			} else {
1260 				e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
1261 			}
1262 			takes_data = TRUE;
1263 			e.ev_number = XPD_TPDU;
1264 			IncStat(ts_XPD_rcvd);
1265 			IncPStat(tpcb, tps_XPD_rcvd);
1266 			break;
1267 
1268 		case DT_TPDU_type:
1269 			{ /* the y option will cause occasional packets to be dropped.
1270 			   * A little crude but it works.
1271 			   */
1272 
1273 				IFDEBUG(D_DROP)
1274 					if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
1275 						IncStat(ts_ydebug);
1276 						goto discard;
1277 					}
1278 				ENDDEBUG
1279 			}
1280 			if (tpcb->tp_class == TP_CLASS_0) {
1281 				e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
1282 				e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
1283 			} else if (tpcb->tp_xtd_format) {
1284 #ifdef BYTE_ORDER
1285 				union seq_type seqeotX;
1286 
1287 				seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1288 				e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
1289 				e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
1290 #else
1291 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
1292 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
1293 #endif BYTE_ORDER
1294 			} else {
1295 				e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
1296 				e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
1297 			}
1298 			if(e.ATTR(DT_TPDU).e_eot)
1299 				IncStat(ts_eot_input);
1300 			takes_data = TRUE;
1301 			e.ev_number = DT_TPDU;
1302 			IncStat(ts_DT_rcvd);
1303 			IncPStat(tpcb, tps_DT_rcvd);
1304 			break;
1305 
1306 		case GR_TPDU_type:
1307 			tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1308 			/* drop through */
1309 		default:
1310 			/* this should NEVER happen because there is a
1311 			 * check for dutype well above here
1312 			 */
1313 			error = E_TP_INV_TPDU; /* causes an ER  */
1314 			IFDEBUG(D_TPINPUT)
1315 				printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1316 			ENDDEBUG
1317 			IncStat(ts_inv_dutype);
1318 			goto respond;
1319 		}
1320 	}
1321 
1322 	/* peel off the tp header;
1323 	 * remember that the du_li doesn't count itself.
1324 	 * This may leave us w/ an empty mbuf at the front of a chain.
1325 	 * We can't just throw away the empty mbuf because hdr still points
1326 	 * into the mbuf's data area and we're still using hdr (the tpdu header)
1327 	 */
1328 	m->m_len -= ((int)hdr->tpdu_li + 1);
1329 	m->m_data += ((int)hdr->tpdu_li + 1);
1330 
1331 	if (takes_data) {
1332 		int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
1333 		int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
1334 		struct tp_control_hdr c_hdr;
1335 		struct mbuf *n;
1336 
1337 		CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
1338 		        ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
1339 		switch( hdr->tpdu_type ) {
1340 
1341 		case CR_TPDU_type:
1342 			c_hdr.cmsg_type = TPOPT_CONN_DATA;
1343 			goto make_control_msg;
1344 
1345 		case CC_TPDU_type:
1346 			c_hdr.cmsg_type = TPOPT_CFRM_DATA;
1347 			goto make_control_msg;
1348 
1349 		case DR_TPDU_type:
1350 			c_hdr.cmsg_type = TPOPT_DISC_DATA;
1351 		make_control_msg:
1352 			c_hdr.cmsg_level = SOL_TRANSPORT;
1353 			mbtype = MT_CONTROL;
1354 			datalen += sizeof(c_hdr);
1355 			m->m_len += sizeof(c_hdr);
1356 			m->m_data -= sizeof(c_hdr);
1357 			c_hdr.cmsg_len = datalen;
1358 			bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr));
1359 			/* FALLTHROUGH */
1360 
1361 		case XPD_TPDU_type:
1362 			if (mbtype != MT_CONTROL)
1363 				mbtype = MT_OOBDATA;
1364 			m->m_flags |= M_EOR;
1365 			/* FALLTHROUGH */
1366 
1367 		case DT_TPDU_type:
1368 			for (n = m; n; n = n->m_next) {
1369 				MCHTYPE(n, mbtype);
1370 			}
1371 			e.ATTR(DT_TPDU).e_datalen = datalen;
1372 			e.ATTR(DT_TPDU).e_data =  m;
1373 			break;
1374 
1375 		default:
1376 			printf(
1377 				"ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1378 				hdr->tpdu_type, takes_data, m);
1379 			break;
1380 		}
1381 		/* prevent m_freem() after tp_driver() from throwing it all away */
1382 		m = MNULL;
1383 	}
1384 
1385 	IncStat(ts_tpdu_rcvd);
1386 
1387 	IFDEBUG(D_TPINPUT)
1388 		printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1389 			tpcb->tp_state, e.ev_number, m );
1390 		printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
1391 		printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1392 			takes_data, (m==MNULL)?0:m->m_len,  tpdu_len);
1393 	ENDDEBUG
1394 
1395 	error = tp_driver(tpcb, &e);
1396 
1397 	ASSERT(tpcb != (struct tp_pcb *)0);
1398 	ASSERT(tpcb->tp_sock != (struct socket *)0);
1399 	if( tpcb->tp_sock->so_error == 0 )
1400 		tpcb->tp_sock->so_error = error;
1401 
1402 	/* Kludge to keep the state tables under control (adding
1403 	 * data on connect & disconnect & freeing the mbuf containing
1404 	 * the data would have exploded the tables and made a big mess ).
1405 	 */
1406 	switch(e.ev_number) {
1407 		case CC_TPDU:
1408 		case DR_TPDU:
1409 		case CR_TPDU:
1410 			m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
1411 			IFDEBUG(D_TPINPUT)
1412 				printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1413 				m, takes_data);
1414 			ENDDEBUG
1415 			break;
1416 		default:
1417 			break;
1418 	}
1419 	/* Concatenated sequences are terminated by any tpdu that
1420 	 * carries data: CR, CC, DT, XPD, DR.
1421 	 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1422 	 */
1423 
1424 separate:
1425 	if ( takes_data == 0 )  {
1426 		ASSERT( m != MNULL );
1427 		/*
1428 		 * we already peeled off the prev. tp header so
1429 		 * we can just pull up some more and repeat
1430 		 */
1431 
1432 		if( m = tp_inputprep(m) ) {
1433 		IFDEBUG(D_TPINPUT)
1434 			hdr = mtod(m, struct tpdu *);
1435 			printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1436 			hdr, (int) hdr->tpdu_li + 1, m);
1437 			dump_mbuf(m, "tp_input after driver, at separate");
1438 		ENDDEBUG
1439 
1440 			IncStat(ts_concat_rcvd);
1441 			goto again;
1442 		}
1443 	}
1444 	if ( m != MNULL ) {
1445 		IFDEBUG(D_TPINPUT)
1446 			printf("tp_input : m_freem(0x%x)\n", m);
1447 		ENDDEBUG
1448 		m_freem(m);
1449 		IFDEBUG(D_TPINPUT)
1450 			printf("tp_input : after m_freem 0x%x\n", m);
1451 		ENDDEBUG
1452 	}
1453 	return (ProtoHook) tpcb;
1454 
1455 discard:
1456 	/* class 4: drop the tpdu */
1457 	/* class 2,0: Should drop the net connection, if you can figure out
1458 	 * to which connection it applies
1459 	 */
1460 	IFDEBUG(D_TPINPUT)
1461 		printf("tp_input DISCARD\n");
1462 	ENDDEBUG
1463 	IFTRACE(D_TPINPUT)
1464 		tptrace(TPPTmisc, "tp_input DISCARD m",  m,0,0,0);
1465 	ENDTRACE
1466 	m_freem(m);
1467 	IncStat(ts_recv_drop);
1468 	return (ProtoHook)0;
1469 
1470 respond:
1471 	IFDEBUG(D_ERROR_EMIT)
1472 		printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc);
1473 	ENDDEBUG
1474 	IFTRACE(D_TPINPUT)
1475 		tptrace(TPPTmisc, "tp_input RESPOND m error sref",  m,error,sref,0);
1476 	ENDTRACE
1477 	if( sref == 0 )
1478 		goto discard;
1479 	(void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
1480 				(struct sockaddr_iso *)laddr, m, (int)errloc, tpcb,
1481 				(int)cons_channel, dgout_routine);
1482 	IFDEBUG(D_ERROR_EMIT)
1483 		printf("tp_input after error_emit\n");
1484 	ENDDEBUG
1485 
1486 #ifdef lint
1487 	printf("",sref,opt);
1488 #endif lint
1489 	IncStat(ts_recv_drop);
1490 	return (ProtoHook)0;
1491 }
1492 
1493 
1494 /*
1495  * NAME: tp_headersize()
1496  *
1497  * CALLED FROM:
1498  *  tp_emit() and tp_sbsend()
1499  *  TP needs to know the header size so it can figure out how
1500  *  much data to put in each tpdu.
1501  *
1502  * FUNCTION, ARGUMENTS, and RETURN VALUE:
1503  *  For a given connection, represented by (tpcb), and
1504  *  tpdu type (dutype), return the size of a tp header.
1505  *
1506  * RETURNS:	  the expected size of the heade in bytesr
1507  *
1508  * SIDE EFFECTS:
1509  *
1510  * NOTES:	 It would be nice if it got the network header size as well.
1511  */
1512 int
1513 tp_headersize(dutype, tpcb)
1514 	int 			dutype;
1515 	struct tp_pcb 	*tpcb;
1516 {
1517 	register int size = 0;
1518 
1519 	IFTRACE(D_CONN)
1520 		tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1521 			dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1522 	ENDTRACE
1523 	if( !( (tpcb->tp_class == TP_CLASS_0) ||
1524 			(tpcb->tp_class == TP_CLASS_4) ||
1525 			(dutype == DR_TPDU_type) ||
1526 			(dutype == CR_TPDU_type) )) {
1527 				printf("tp_headersize:dutype 0x%x, class 0x%x",
1528 			dutype, tpcb->tp_class);
1529 	/* TODO: identify this and GET RID OF IT */
1530 	}
1531 	ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
1532 			(tpcb->tp_class == TP_CLASS_4) ||
1533 			(dutype == DR_TPDU_type) ||
1534 			(dutype == CR_TPDU_type) );
1535 
1536 	if( tpcb->tp_class == TP_CLASS_0 ) {
1537 		size =  tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
1538 	} else  {
1539 		size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
1540 	}
1541 	return size;
1542 	/* caller must get network level header size separately */
1543 }
1544