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