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