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