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