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