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