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