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