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