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