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