xref: /csrg-svn/sys/netiso/tp_emit.c (revision 37469)
136399Ssklower /***********************************************************
236399Ssklower 		Copyright IBM Corporation 1987
336399Ssklower 
436399Ssklower                       All Rights Reserved
536399Ssklower 
636399Ssklower Permission to use, copy, modify, and distribute this software and its
736399Ssklower documentation for any purpose and without fee is hereby granted,
836399Ssklower provided that the above copyright notice appear in all copies and that
936399Ssklower both that copyright notice and this permission notice appear in
1036399Ssklower supporting documentation, and that the name of IBM not be
1136399Ssklower used in advertising or publicity pertaining to distribution of the
1236399Ssklower software without specific, written prior permission.
1336399Ssklower 
1436399Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536399Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636399Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736399Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836399Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936399Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036399Ssklower SOFTWARE.
2136399Ssklower 
2236399Ssklower ******************************************************************/
2336399Ssklower 
2436399Ssklower /*
2536399Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636399Ssklower  */
2736399Ssklower /*
2836399Ssklower  * ARGO TP
2936399Ssklower  *
3036399Ssklower  * $Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $
3136399Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_emit.c,v $
3236399Ssklower  *
3336399Ssklower  * This file contains tp_emit() and tp_error_emit(), which
3436399Ssklower  * form TPDUs and hand them to ip.
3536399Ssklower  * They take data in the form of mbuf chain, allocate mbufs as
3636399Ssklower  * necessary for headers, and set the fields as appropriate from
3736399Ssklower  * information found in the tpcb and net-level pcb.
3836399Ssklower  *
3936399Ssklower  * The worst thing about this code is adding the variable-length
4036399Ssklower  * options on a machine that requires alignment for any memory access
4136399Ssklower  * that isn't of size 1.  See the macro ADDOPTION() below.
4236399Ssklower  *
4336399Ssklower  * We don't do any concatenation. (There's a kludge to test the
4436399Ssklower  * basic mechanism of separation under the 'w' tpdebug option, that's all.)
4536399Ssklower  */
4636399Ssklower 
4736399Ssklower #ifndef lint
4836399Ssklower static char *rcsid = "$Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $";
4936399Ssklower #endif lint
5036399Ssklower 
5136399Ssklower 
5236399Ssklower #include "argoxtwentyfive.h"
5336399Ssklower #include "param.h"
5436399Ssklower #include "mbuf.h"
5536399Ssklower #include "socket.h"
5636399Ssklower #include "socketvar.h"
5736399Ssklower #include "protosw.h"
5836399Ssklower #include "errno.h"
5936399Ssklower #include "types.h"
6036399Ssklower #include "time.h"
61*37469Ssklower #include "iso.h"
62*37469Ssklower #include "argo_debug.h"
63*37469Ssklower #include "tp_timer.h"
64*37469Ssklower #include "tp_param.h"
65*37469Ssklower #include "tp_stat.h"
66*37469Ssklower #include "tp_pcb.h"
67*37469Ssklower #include "tp_tpdu.h"
68*37469Ssklower #include "tp_trace.h"
69*37469Ssklower #include "tp_meas.h"
70*37469Ssklower #include "tp_seq.h"
71*37469Ssklower #include "iso_errno.h"
7236399Ssklower 
7336399Ssklower void iso_gen_csum();
7436399Ssklower 
7536399Ssklower 
7636399Ssklower /* Here is a mighty kludge.  The token ring misorders packets if you
7736399Ssklower  * fire them at it too fast, and TP sans checksum is "too fast", so
7836399Ssklower  * we have introduced a delay when checksumming isn't used.
7936399Ssklower  */
8036399Ssklower char tp_delay = 0x00; /* delay to keep token ring from blowing it */
8136399Ssklower 
8236399Ssklower /*
8336399Ssklower  * NAME:	tp_emit()
8436399Ssklower  *
8536399Ssklower  * CALLED FROM: tp.trans and from tp_sbsend()
8636399Ssklower  *
8736399Ssklower  * FUNCTION and ARGUMENTS:
8836399Ssklower  * 	Emits one tpdu of the type (dutype), of the format appropriate
8936399Ssklower  * 	to the connection described by the pcb (tpcb), with sequence
9036399Ssklower  * 	number (seq) (where appropriate), end-of-tsdu bit (eot) where
9136399Ssklower  * 	appropriate, and with the data in the mbuf chain (data).
9236399Ssklower  * 	For DR and ER tpdus, the argument (eot) is
9336399Ssklower  * 	the reason for issuing the tpdu rather than an end-of-tsdu indicator.
9436399Ssklower  *
9536399Ssklower  * RETURNS:
9636399Ssklower  * 	0  OK
9736399Ssklower  * 	ENOBUFS
9836399Ssklower  * 	E* returned from net layer output rtn
9936399Ssklower  *
10036399Ssklower  * SIDE EFFECTS:
10136399Ssklower  *
10236399Ssklower  * NOTES:
10336399Ssklower  *
10436399Ssklower  * 	WE ASSUME that the tp header + all options will fit in ONE mbuf.
10536399Ssklower  *	If mbufs are 256 this will most likely be true, but if they are 128 it's
10636399Ssklower  *	possible that they won't.
10736399Ssklower  *	If you used every option on the CR + max. user data you'd overrun
10836399Ssklower  *	112 but unless you used > 115 bytes for the security
10936399Ssklower  *	parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
11036399Ssklower  *	We don't support the security parameter, so this isn't a problem.
11136399Ssklower  *	If security is added, we ought to remove this assumption.
11236399Ssklower  *
11336399Ssklower  *  We do not implement the flow control confirmation "element of procedure".
11436399Ssklower  *  A) it should not affect interoperability,
11536399Ssklower  *  B) it should not be necessary - the protocol will eventually
11636399Ssklower  *   	straighten things out w/o FCC, as long as we don't have severely
11736399Ssklower  *		mismatched keepalive and inactivity timers, and
11836399Ssklower  *	C) it appears not to be REQUIRED, and
11936399Ssklower  *  D) it's incredibly grotesque, and no doubt will lengthen a few
12036399Ssklower  *   	critical paths.
12136399Ssklower  *  HOWEVER, we're thinking about putting it in anyway, for
12236399Ssklower  *  completeness, just like we did with ack subsequencing.
12336399Ssklower  */
12436399Ssklower 
12536399Ssklower int
12636399Ssklower tp_emit(dutype,	tpcb, seq, eot, data)
12736399Ssklower 	int dutype;
12836399Ssklower 	struct tp_pcb *tpcb;
12936399Ssklower 	SeqNum	seq;
13036399Ssklower 	u_int 	eot;
13136399Ssklower 	struct mbuf *data;
13236399Ssklower {
13336399Ssklower 	register struct tpdu *hdr;
13436399Ssklower 	register struct mbuf *m;
13536399Ssklower 	int csum_offset=0;
13636399Ssklower 	int datalen = 0;
13736399Ssklower 	int error = 0;
13836399Ssklower 
13936399Ssklower 	/* NOTE:
14036399Ssklower 	 * here we treat tpdu_li as if it DID include the li field, up until
14136399Ssklower 	 * the end, at which time we subtract 1
14236399Ssklower 	 * THis is because if we subtract 1 right away, we end up adding
14336399Ssklower 	 * one every time we add an option.
14436399Ssklower 	 */
14536399Ssklower 	IFDEBUG(D_EMIT)
14636399Ssklower 		printf(
147*37469Ssklower 	"tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
148*37469Ssklower 		dutype, tpcb, eot, seq, data);
14936399Ssklower 	ENDDEBUG
15036399Ssklower 
151*37469Ssklower 	if (dutype == CR_TPDU || dutype == CC_TPDU) {
152*37469Ssklower 		m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
153*37469Ssklower 		if (m) {
154*37469Ssklower 			m->m_type = TPMT_TPHDR;
155*37469Ssklower 			mbstat.m_mtypes[TPMT_TPHDR]++;
156*37469Ssklower 			m->m_next = MNULL;
157*37469Ssklower 			m->m_data = m->m_dat;
158*37469Ssklower 			m->m_flags = 0;
159*37469Ssklower 		}
160*37469Ssklower 	} else {
161*37469Ssklower 		MGET(m, M_DONTWAIT, TPMT_TPHDR);
162*37469Ssklower 	}
16336399Ssklower 	if (m == NULL) {
16436399Ssklower 		if(data != (struct mbuf *)0)
16536399Ssklower 			m_freem(data);
16636399Ssklower 		error = ENOBUFS;
16736399Ssklower 		goto done;
16836399Ssklower 	}
16936399Ssklower 	m->m_len = sizeof(struct tpdu);
17036399Ssklower 	m->m_act = MNULL;
17136399Ssklower 
17236399Ssklower 	hdr = mtod(m, struct tpdu *);
173*37469Ssklower 	bzero((caddr_t)hdr, sizeof(struct tpdu));
17436399Ssklower 
17536399Ssklower 	{
17636399Ssklower 		int 	tp_headersize();
17736399Ssklower 
17836399Ssklower 		hdr->tpdu_type = dutype;
17936399Ssklower 		hdr->tpdu_li = tp_headersize(dutype, tpcb);
18036399Ssklower 		/*
18136399Ssklower 		 * class 0 doesn't use this for DT
18236399Ssklower 		 * it'll just get overwritten below
18336399Ssklower 		 */
18436399Ssklower 		hdr->tpdu_dref = htons(tpcb->tp_fref);
18536399Ssklower 		if( tpcb->tp_use_checksum ||
18636399Ssklower 			(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
18736399Ssklower 			csum_offset =  hdr->tpdu_li + 2; /* DOESN'T include csum */
18836399Ssklower 			ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */);
18936399Ssklower 			IFDEBUG(D_CHKSUM)
19036399Ssklower 				printf(
19136399Ssklower 					"tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
19236399Ssklower 						csum_offset, hdr->tpdu_li);
19336399Ssklower 			ENDDEBUG
19436399Ssklower 		}
19536399Ssklower 		/*
19636399Ssklower 		 * VARIABLE PARTS...
19736399Ssklower 		 */
19836399Ssklower 		switch( dutype ) {
19936399Ssklower 
20036399Ssklower 		case CR_TPDU_type:
20136399Ssklower 			hdr->tpdu_CRdref_0 = htons(0);	/* must be zero */
20236399Ssklower 
20336399Ssklower 		case CC_TPDU_type:
20436399Ssklower 				{
20536399Ssklower 					u_char x;
20636399Ssklower 
20736399Ssklower 				hdr->tpdu_CCsref =  htons(tpcb->tp_lref); /* same as CRsref */
20836399Ssklower 
20936399Ssklower 				if( tpcb->tp_class > TP_CLASS_1 ) {
21036399Ssklower 					LOCAL_CREDIT( tpcb );
21136399Ssklower 					tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
21236399Ssklower 					tpcb->tp_sent_rcvnxt = 1;
21336399Ssklower 					tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
21436399Ssklower 					hdr->tpdu_cdt = tpcb->tp_lcredit;
21536399Ssklower 				} else {
21636399Ssklower 					hdr->tpdu_cdt = 0;
21736399Ssklower 				}
21836399Ssklower 				hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
21936399Ssklower 				hdr->tpdu_CCoptions =
22036399Ssklower 					(tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
22136399Ssklower 					(tpcb->tp_use_efc? TPO_USE_EFC:0);
22236399Ssklower 
22336399Ssklower 				IFPERF(tpcb)
22436399Ssklower 					u_char perf_meas = tpcb->tp_perf_on;
22536399Ssklower 					ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
22636399Ssklower 				ENDPERF
22736399Ssklower 
22836399Ssklower 				if( dutype == CR_TPDU_type ) {
22936399Ssklower 					IncStat(ts_CR_sent);
23036399Ssklower 
23136399Ssklower 					ASSERT( tpcb->tp_lsuffixlen > 0 );
23236399Ssklower 					ASSERT( tpcb->tp_fsuffixlen > 0 );
23336399Ssklower 
23436399Ssklower 					ADDOPTION(TPP_calling_sufx, hdr,
235*37469Ssklower 						tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
23636399Ssklower 					ADDOPTION(TPP_called_sufx, hdr,
237*37469Ssklower 						tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
23836399Ssklower 				} else {
23936399Ssklower 					IncStat(ts_CC_sent);
24036399Ssklower 				}
24136399Ssklower 
24236399Ssklower 				ADDOPTION(TPP_tpdu_size, hdr,
24336399Ssklower 					sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
24436399Ssklower 
24536399Ssklower 				if (tpcb->tp_class != TP_CLASS_0) {
24636399Ssklower 					short millisec = 500*(tpcb->tp_sendack_ticks);
24736399Ssklower 
24836399Ssklower 					millisec = htons(millisec);
24936399Ssklower 					ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
25036399Ssklower 
25136399Ssklower 					x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
25236399Ssklower 					 |	(tpcb->tp_use_rcc?  TPAO_USE_RCC : 0)
25336399Ssklower 					 |  (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
25436399Ssklower 					 |	(tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
25536399Ssklower 					ADDOPTION(TPP_addl_opt, hdr, 1, x);
25636399Ssklower 
25736399Ssklower 				}
25836399Ssklower 
25936399Ssklower 				if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
26036399Ssklower 
26136399Ssklower 					ASSERT( 1 == sizeof(tpcb->tp_vers) );
26236399Ssklower 					ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
26336399Ssklower 
26436399Ssklower 					/* for each alt protocol class x,
26536399Ssklower 					 * 	x = x<<4;
26636399Ssklower 					 *  option = concat(option, x);
26736399Ssklower 					 * Well, for now we only have TP0 for an
26836399Ssklower 					 * alternative so... this is easy.
26936399Ssklower 					 *
27036399Ssklower 					 * HOWEVER... There should be NO alt protocol
27136399Ssklower 					 * class over CLNS.  Need to see if the route suggests
27236399Ssklower 					 * CONS, and iff so add alt class.
27336399Ssklower 					 */
27436399Ssklower 					x = 0;
27536399Ssklower 					ADDOPTION(TPP_alt_class, hdr, 1, x);
27636399Ssklower 				}
27736399Ssklower 
27836399Ssklower 				if( hdr->tpdu_li > MLEN)
27936399Ssklower 					panic("tp_emit CR/CC");
28036399Ssklower 			}
28136399Ssklower 			break;
28236399Ssklower 
28336399Ssklower 		case DR_TPDU_type:
28436399Ssklower 			if( hdr->tpdu_DRdref == 0 ) {
28536399Ssklower 				/* don't issue the DR */
28636399Ssklower 				goto done;
28736399Ssklower 			}
28836399Ssklower 			hdr->tpdu_cdt = 0;
28936399Ssklower 			hdr->tpdu_DRsref = htons(tpcb->tp_lref);
29036399Ssklower 			hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
29136399Ssklower 
29236399Ssklower 			/* forget the add'l information variable part */
29336399Ssklower 			IncStat(ts_DR_sent);
29436399Ssklower 			break;
29536399Ssklower 
29636399Ssklower 		case DC_TPDU_type: /* not used in class 0 */
29736399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0);
29836399Ssklower 			hdr->tpdu_DCsref =  htons(tpcb->tp_lref);
29936399Ssklower 			hdr->tpdu_cdt = 0;
30036399Ssklower 			data = (struct mbuf *)0;
30136399Ssklower 			IncStat(ts_DC_sent);
30236399Ssklower 			break;
30336399Ssklower 
30436399Ssklower 		case XAK_TPDU_type: /* xak not used in class 0 */
30536399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
30636399Ssklower 			hdr->tpdu_cdt = 0;
30736399Ssklower 
30836399Ssklower 			IFTRACE(D_XPD)
30936399Ssklower 				tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
31036399Ssklower 			ENDTRACE
31136399Ssklower 			data = (struct mbuf *)0;
31236399Ssklower 			if (tpcb->tp_xtd_format) {
31336399Ssklower #ifdef BYTE_ORDER
31436399Ssklower 				hdr->tpdu_XAKseqX = htonl(seq);
31536399Ssklower #else
31636399Ssklower 				hdr->tpdu_XAKseqX = seq;
31736399Ssklower #endif BYTE_ORDER
31836399Ssklower 			} else {
31936399Ssklower 				hdr->tpdu_XAKseq = seq;
32036399Ssklower 			}
32136399Ssklower 			IncStat(ts_XAK_sent);
32236399Ssklower 			IncPStat(tpcb, tps_XAK_sent);
32336399Ssklower 			break;
32436399Ssklower 
32536399Ssklower 		case XPD_TPDU_type: /* xpd not used in class 0 */
32636399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
32736399Ssklower 			hdr->tpdu_cdt = 0;
32836399Ssklower 			if (tpcb->tp_xtd_format) {
32936399Ssklower #ifdef BYTE_ORDER
33036399Ssklower 				union seq_type seqeotX;
33136399Ssklower 
33236399Ssklower 				seqeotX.s_seq = seq;
33336399Ssklower 				seqeotX.s_eot = 1;
33436399Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
33536399Ssklower #else
33636399Ssklower 				hdr->tpdu_XPDseqX = seq;
33736399Ssklower 				hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
33836399Ssklower #endif BYTE_ORDER
33936399Ssklower 			} else {
34036399Ssklower 				hdr->tpdu_XPDseq = seq;
34136399Ssklower 				hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
34236399Ssklower 			}
34336399Ssklower 			IncStat(ts_XPD_sent);
34436399Ssklower 			IncPStat(tpcb, tps_XPD_sent);
34536399Ssklower 
34636399Ssklower 			/* kludge to test the input size checking */
34736399Ssklower 			IFDEBUG(D_SIZE_CHECK)
348*37469Ssklower 				/*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
34936399Ssklower 					printf("Sending too much data on XPD: 18 bytes\n");
35036399Ssklower 					data->m_len = 18;
351*37469Ssklower 				}*/
35236399Ssklower 			ENDDEBUG
35336399Ssklower 			break;
35436399Ssklower 
35536399Ssklower 		case DT_TPDU_type:
35636399Ssklower 			hdr->tpdu_cdt = 0;
35736399Ssklower 			IFTRACE(D_DATA)
35836399Ssklower 				tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
35936399Ssklower 					hdr->tpdu_li, 0);
36036399Ssklower 			ENDTRACE
36136399Ssklower 			if (tpcb->tp_xtd_format) {
36236399Ssklower #ifdef BYTE_ORDER
36336399Ssklower 				union seq_type seqeotX;
36436399Ssklower 
36536399Ssklower 				seqeotX.s_seq = seq;
36636399Ssklower 				seqeotX.s_eot = eot;
36736399Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
36836399Ssklower #else
36936399Ssklower 				hdr->tpdu_DTseqX = seq;
37036399Ssklower 				hdr->tpdu_DTeotX = eot;
37136399Ssklower #endif BYTE_ORDER
37236399Ssklower 			} else if (tpcb->tp_class == TP_CLASS_0) {
37336399Ssklower 				IFDEBUG(D_EMIT)
37436399Ssklower 					printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
37536399Ssklower 					dump_buf( hdr, hdr->tpdu_li + 1 );
37636399Ssklower 				ENDDEBUG
37736399Ssklower 				((struct tp0du *)hdr)->tp0du_eot = eot;
37836399Ssklower 				((struct tp0du *)hdr)->tp0du_mbz = 0;
37936399Ssklower 				IFDEBUG(D_EMIT)
38036399Ssklower 					printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
38136399Ssklower 					dump_buf( hdr, hdr->tpdu_li + 1 );
38236399Ssklower 				ENDDEBUG
38336399Ssklower 			} else {
38436399Ssklower 				hdr->tpdu_DTseq = seq;
38536399Ssklower 				hdr->tpdu_DTeot = eot;
38636399Ssklower 			}
38736399Ssklower 			if(eot) {
38836399Ssklower 				IncStat(ts_EOT_sent);
38936399Ssklower 			}
39036399Ssklower 			IncStat(ts_DT_sent);
39136399Ssklower 			IncPStat(tpcb, tps_DT_sent);
39236399Ssklower 			break;
39336399Ssklower 
39436399Ssklower 		case AK_TPDU_type:/* ak not used in class 0 */
39536399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0);
39636399Ssklower 			data = (struct mbuf *)0;
39736399Ssklower 			{ 	SeqNum olduwe = tpcb->tp_sent_uwe;
39836399Ssklower 
39936399Ssklower 				tpcb->tp_sent_uwe =
40036399Ssklower 					SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
40136399Ssklower 				LOCAL_CREDIT( tpcb );
40236399Ssklower 				tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
40336399Ssklower 
40436399Ssklower 				IFDEBUG(D_RENEG)
40536399Ssklower 					/* occasionally fake a reneging so
40636399Ssklower 						you can test subsequencing */
40736399Ssklower 					if( olduwe & 0x1 ) {
40836399Ssklower 						tpcb->tp_reneged = 1;
40936399Ssklower 						IncStat(ts_ldebug);
41036399Ssklower 					}
41136399Ssklower 				ENDDEBUG
41236399Ssklower 				/* Are we about to reneg on credit?
41336399Ssklower 				 * When might we do so?
41436399Ssklower 				 *	a) when using optimistic credit (which we no longer do).
41536399Ssklower 				 *  b) when drain() gets implemented (not in the plans).
41636399Ssklower 				 *  c) when D_RENEG is on.
417*37469Ssklower 				 *  d) when DEC BIT response is implemented.
41836399Ssklower 				 *	(not- when we do this, we'll need to implement flow control
41936399Ssklower 				 *	confirmation)
42036399Ssklower 				 */
42136399Ssklower 				if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
42236399Ssklower 					tpcb->tp_reneged = 1;
42336399Ssklower 					IncStat(ts_lcdt_reduced);
42436399Ssklower 					IFTRACE(D_CREDIT)
42536399Ssklower 						tptraceTPCB(TPPTmisc,
42636399Ssklower 							"RENEG: olduwe newuwe lcredit rcvnxt",
42736399Ssklower 							olduwe,
42836399Ssklower 							tpcb->tp_sent_uwe, tpcb->tp_lcredit,
42936399Ssklower 							tpcb->tp_rcvnxt);
43036399Ssklower 					ENDTRACE
43136399Ssklower 				}
43236399Ssklower 
43336399Ssklower 				IFPERF(tpcb)
43436399Ssklower 					/* new lwe is less than old uwe means we're
43536399Ssklower 					 * acking before we received a whole window full
43636399Ssklower 					 */
43736399Ssklower 					if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
43836399Ssklower 						/* tmp1 = number of pkts fewer than the full window */
43936399Ssklower 						register int tmp1 =
44036399Ssklower 							(int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
44136399Ssklower 
44236399Ssklower 						if(tmp1 > TP_PM_MAX)
44336399Ssklower 							tmp1 = TP_PM_MAX;
44436399Ssklower 						IncPStat( tpcb,  tps_ack_early[tmp1] );
44536399Ssklower 
44636399Ssklower 						/* tmp1 = amt of new cdt we're advertising */
44736399Ssklower 						tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
44836399Ssklower 						if(tmp1 > TP_PM_MAX )
44936399Ssklower 							tmp1 = TP_PM_MAX;
45036399Ssklower 
45136399Ssklower 						IncPStat( tpcb,
45236399Ssklower 								tps_cdt_acked [ tmp1 ]
45336399Ssklower 								[ ((tpcb->tp_lcredit > TP_PM_MAX)?
45436399Ssklower 									TP_PM_MAX:tpcb->tp_lcredit) ] );
45536399Ssklower 
45636399Ssklower 					}
45736399Ssklower 				ENDPERF
45836399Ssklower 			}
45936399Ssklower 			IFTRACE(D_ACKSEND)
46036399Ssklower 				tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
46136399Ssklower 					tpcb->tp_r_subseq, 0);
46236399Ssklower 			ENDTRACE
46336399Ssklower 			if (tpcb->tp_xtd_format) {
46436399Ssklower #ifdef BYTE_ORDER
46536399Ssklower 				hdr->tpdu_cdt = 0;
46636399Ssklower 				hdr->tpdu_AKseqX = htonl(seq);
46736399Ssklower 				hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
46836399Ssklower #else
46936399Ssklower 				hdr->tpdu_cdt = 0;
47036399Ssklower 				hdr->tpdu_AKseqX = seq;
47136399Ssklower 				hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
47236399Ssklower #endif BYTE_ORDER
47336399Ssklower 			} else {
47436399Ssklower 				hdr->tpdu_AKseq = seq;
47536399Ssklower 				hdr->tpdu_AKcdt = tpcb->tp_lcredit;
47636399Ssklower 			}
47736399Ssklower 			if ((tpcb->tp_class == TP_CLASS_4) && tpcb->tp_reneged ) {
47836399Ssklower 				/*
47936399Ssklower 				 * Ack subsequence parameter req'd if WE reneged on
48036399Ssklower 				 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
48136399Ssklower 				 */
48236399Ssklower 				IFDEBUG(D_RENEG)
48336399Ssklower 					printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
48436399Ssklower 				ENDDEBUG
48536399Ssklower 				tpcb->tp_s_subseq++;
48636399Ssklower 				/*
48736399Ssklower 				 * add tmp subseq and do a htons on it.
48836399Ssklower 				 */
48936399Ssklower 				ADDOPTION(TPP_subseq, hdr,
49036399Ssklower 					sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
49136399Ssklower 			} else
49236399Ssklower 				tpcb->tp_s_subseq = 0;
49336399Ssklower 
49436399Ssklower 			if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
49536399Ssklower 				/*
49636399Ssklower 				 * Rules for sending FCC ("should" send when) :
49736399Ssklower 				 * %a) received an ack from peer with NO NEWS whatsoever,
49836399Ssklower 				 *  	and it did not contain an FCC
49936399Ssklower 				 * 	b) received an ack from peer that opens its closed window.
50036399Ssklower 				 * 	c) received an ack from peer after it reneged on its
50136399Ssklower 				 *		offered credit, AND this ack raises UWE but LWE is same
50236399Ssklower 				 *		and below UWE at time of reneging (reduction)
50336399Ssklower 				 * Now, ISO 8073 12.2.3.8.3 says
50436399Ssklower 				 * that a retransmitted AK shall not contain the FCC
50536399Ssklower 				 * parameter.  Now, how the hell you tell the difference
50636399Ssklower 				 * between a retransmitted ack and an ack that's sent in
50736399Ssklower 				 * response to a received ack, I don't know, because without
50836399Ssklower 				 * any local activity, and w/o any received DTs, they
50936399Ssklower 				 * will contain exactly the same credit/seq# information.
51036399Ssklower 				 * Anyway, given that the "retransmission of acks"
51136399Ssklower 				 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
51236399Ssklower 				 * don't do it (although the peer can't tell that), we
51336399Ssklower 				 * ignore this last rule.
51436399Ssklower 				 *
51536399Ssklower 				 * We send FCC for reasons a) and b) only.
51636399Ssklower 				 * To add reason c) would require a ridiculous amount of state.
51736399Ssklower 				 *
51836399Ssklower 				 */
51936399Ssklower 				u_short 	bogus[4]; /* lwe(32), subseq(16), cdt(16) */
52036399Ssklower 				SeqNum		lwe;
52136399Ssklower 				u_short		subseq, fcredit;
52236399Ssklower 
52336399Ssklower 				tpcb->tp_sendfcc = 0;
52436399Ssklower 
52536399Ssklower 				lwe = (SeqNum) htonl(tpcb->tp_snduna);
52636399Ssklower 				subseq = htons(tpcb->tp_r_subseq);
52736399Ssklower 				fcredit = htons(tpcb->tp_fcredit);
52836399Ssklower 
529*37469Ssklower 				bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
530*37469Ssklower 				bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
531*37469Ssklower 				bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
53236399Ssklower 
53336399Ssklower 				IFTRACE(D_ACKSEND)
53436399Ssklower 					tptraceTPCB(TPPTmisc,
53536399Ssklower 						"emit w/FCC: snduna r_subseq fcredit",
53636399Ssklower 						tpcb->tp_snduna, tpcb->tp_r_subseq,
53736399Ssklower 						tpcb->tp_fcredit, 0);
53836399Ssklower 				ENDTRACE
53936399Ssklower 
54036399Ssklower 				IFDEBUG(D_ACKSEND)
54136399Ssklower 					printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
54236399Ssklower 						TPP_flow_cntl_conf,
54336399Ssklower 						hdr, sizeof(bogus), bogus[0]);
54436399Ssklower 				ENDDEBUG
54536399Ssklower 				ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
54636399Ssklower 				IFDEBUG(D_ACKSEND)
54736399Ssklower 					printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
54836399Ssklower 						hdr, hdr->tpdu_li);
54936399Ssklower 					printf(
55036399Ssklower 					"after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
55136399Ssklower 							csum_offset, hdr->tpdu_li);
55236399Ssklower 				ENDDEBUG
55336399Ssklower 
55436399Ssklower 			}
55536399Ssklower 			tpcb->tp_reneged = 0;
55636399Ssklower 			tpcb->tp_sent_rcvnxt = seq;
55736399Ssklower 			tp_ctimeout(tpcb->tp_refp, TM_sendack,
55836399Ssklower 				(int)tpcb->tp_keepalive_ticks);
55936399Ssklower 			IncStat(ts_AK_sent);
56036399Ssklower 			IncPStat(tpcb, tps_AK_sent);
56136399Ssklower 			IFDEBUG(D_ACKSEND)
56236399Ssklower 				printf(
56336399Ssklower 				"2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
56436399Ssklower 						csum_offset, hdr->tpdu_li);
56536399Ssklower 			ENDDEBUG
56636399Ssklower 			break;
56736399Ssklower 
56836399Ssklower 		case ER_TPDU_type:
56936399Ssklower 			hdr->tpdu_ERreason = eot;
57036399Ssklower 			hdr->tpdu_cdt = 0;
57136399Ssklower 			/* no user data */
57236399Ssklower 			data = (struct mbuf *)0;
57336399Ssklower 			IncStat(ts_ER_sent);
57436399Ssklower 			break;
57536399Ssklower 		}
57636399Ssklower 
57736399Ssklower 	}
57836399Ssklower 	ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
57936399Ssklower 
58036399Ssklower 	m->m_next = data;
58136399Ssklower 
582*37469Ssklower 	ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
58336399Ssklower 	ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
58436399Ssklower 
58536399Ssklower 	m->m_len = hdr->tpdu_li ;
58636399Ssklower 	hdr->tpdu_li --; /* doesn't include the li field */
58736399Ssklower 
58836399Ssklower 	datalen = m_datalen( m ); /* total len */
58936399Ssklower 
59036399Ssklower 	ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
59136399Ssklower 				when CLNP is used; leave in here for the time being */
59236399Ssklower 		IFDEBUG(D_ACKSEND)
59336399Ssklower 			printf(
59436399Ssklower 			"4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
59536399Ssklower 					csum_offset, hdr->tpdu_li);
59636399Ssklower 		ENDDEBUG
59736399Ssklower 	if( datalen > tpcb->tp_l_tpdusize ) {
59836399Ssklower 		printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
59936399Ssklower 			datalen, tpcb->tp_l_tpdusize);
60036399Ssklower 	}
60136399Ssklower 	IFDEBUG(D_EMIT)
60236399Ssklower 		printf(
60336399Ssklower 		"tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
60436399Ssklower 		m->m_len, csum_offset, datalen);
60536399Ssklower 	ENDDEBUG
60636399Ssklower 	if( tpcb->tp_use_checksum ||
60736399Ssklower 		(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
60836399Ssklower 		iso_gen_csum(m, csum_offset, datalen);
60936399Ssklower 	}
61036399Ssklower 
61136399Ssklower 	IFDEBUG(D_EMIT)
61236399Ssklower 	printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
61336399Ssklower 		tpcb, dutype, datalen);
614*37469Ssklower 		dump_buf(mtod(m, caddr_t), datalen);
61536399Ssklower 	ENDDEBUG
61636399Ssklower 
61736399Ssklower 	IFPERF(tpcb)
61836399Ssklower 		if( dutype == DT_TPDU_type ) {
61936399Ssklower 			PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
620*37469Ssklower 			tpmeas( tpcb->tp_lref, TPtime_to_ll,  (struct timeval *)0,
62136399Ssklower 				seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
62236399Ssklower 		}
62336399Ssklower 	ENDPERF
62436399Ssklower 
62536399Ssklower 	IFTRACE(D_EMIT)
62636399Ssklower 		tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
62736399Ssklower 	ENDTRACE
62836399Ssklower 	IFDEBUG(D_EMIT)
62936399Ssklower 		printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
63036399Ssklower 			tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
63136399Ssklower 	ENDDEBUG
63236399Ssklower 
63336399Ssklower 	{ extern char tp_delay;
63436399Ssklower 
63536399Ssklower 		if( tp_delay )
63636399Ssklower 			if( tpcb->tp_use_checksum == 0 ) {
63736399Ssklower 				register u_int i  = tp_delay;
63836399Ssklower 				for (; i!= 0; i--)
63936399Ssklower 					(void) iso_check_csum(m, datalen);
64036399Ssklower 			}
64136399Ssklower 	}
64236399Ssklower 	ASSERT( m->m_len > 0 );
64336399Ssklower 	error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
64436399Ssklower 		!tpcb->tp_use_checksum);
64536399Ssklower 	IFDEBUG(D_EMIT)
64636399Ssklower 		printf("OUTPUT: returned 0x%x\n", error);
64736399Ssklower 	ENDDEBUG
64836399Ssklower 	IFTRACE(D_EMIT)
64936399Ssklower 		tptraceTPCB(TPPTmisc,
65036399Ssklower 			"tp_emit nlproto->output netservice returns datalen",
65136399Ssklower 			tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
65236399Ssklower 	ENDTRACE
65336399Ssklower done:
65436399Ssklower 	if( error == E_CO_QFULL ) {
655*37469Ssklower 		tp_quench(tpcb, PRC_QUENCH);
65636399Ssklower 		return 0;
65736399Ssklower 	}
65836399Ssklower 	return error;
65936399Ssklower }
66036399Ssklower /*
66136399Ssklower  * NAME:		tp_error_emit()
66236399Ssklower  * CALLED FROM:	tp_input() when a DR or ER is to be issued in
66336399Ssklower  * 		response to an input error.
66436399Ssklower  * FUNCTION and ARGUMENTS:
66536399Ssklower  * 		The error type is the first argument.
66636399Ssklower  * 		The argument (sref) is the source reference on the bad incoming tpdu,
66736399Ssklower  * 		and is used for a destination reference on the outgoing packet.
66836399Ssklower  * 		(faddr) and (laddr) are the foreign and local addresses for this
66936399Ssklower  *		connection.
67036399Ssklower  * 		(erdata) is a ptr to the errant incoming tpdu, and is copied into the
67136399Ssklower  * 		outgoing ER, if an ER is to be issued.
67236399Ssklower  * 		(erlen)  is the number of octets of the errant tpdu that we should
67336399Ssklower  * 		try to copy.
67436399Ssklower  * 		(tpcb) is the pcb that describes the connection for which the bad tpdu
67536399Ssklower  * 		arrived.
67636399Ssklower  * RETURN VALUES:
67736399Ssklower  * 		0 OK
67836399Ssklower  *  	ENOBUFS
67936399Ssklower  *  	E* from net layer datagram output routine
68036399Ssklower  * SIDE EFFECTS:
68136399Ssklower  *
68236399Ssklower  * NOTES:
68336399Ssklower  */
68436399Ssklower 
68536399Ssklower int
68636399Ssklower tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
68736399Ssklower 	dgout_routine)
68836399Ssklower 	int				error;
68936399Ssklower 	u_long			sref;
69036399Ssklower 	struct sockaddr_iso *faddr, *laddr;
69136399Ssklower 	struct mbuf 	*erdata;
69236399Ssklower 	int 			erlen;
69336399Ssklower 	struct tp_pcb 	*tpcb;
69436399Ssklower 	int 			cons_channel;
69536399Ssklower 	int				(*dgout_routine)();
69636399Ssklower {
69736399Ssklower 	int						dutype;
69836399Ssklower 	int 					datalen = 0;
69936399Ssklower 	register struct tpdu	*hdr;
70036399Ssklower 	register struct mbuf	*m;
70136399Ssklower 	int						csum_offset;
70236399Ssklower 
70336399Ssklower 	IFTRACE(D_ERROR_EMIT)
70436399Ssklower 		tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
70536399Ssklower 			error, sref, tpcb, erlen);
70636399Ssklower 	ENDTRACE
70736399Ssklower 	IFDEBUG(D_ERROR_EMIT)
70836399Ssklower 		printf(
70936399Ssklower 		"tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
71036399Ssklower 			error, sref, tpcb, erlen, cons_channel);
71136399Ssklower 	ENDDEBUG
71236399Ssklower 
71336399Ssklower 	MGET(m, M_DONTWAIT, TPMT_TPHDR);
71436399Ssklower 	if (m == NULL) {
71536399Ssklower 		return ENOBUFS;
71636399Ssklower 	}
71736399Ssklower 	m->m_len = sizeof(struct tpdu);
71836399Ssklower 	m->m_act = MNULL;
71936399Ssklower 
72036399Ssklower 	hdr = mtod(m, struct tpdu *);
72136399Ssklower 
72236399Ssklower 	IFDEBUG(D_ERROR_EMIT)
72336399Ssklower 		printf("[error 0x%x] [error&0xff  0x%x] [(char)error 0x%x]\n",
72436399Ssklower 			error, error&0xff, (char)error);
72536399Ssklower 	ENDDEBUG
72636399Ssklower 
72736399Ssklower 	error &= 0xff;
72836399Ssklower 
72936399Ssklower 	if( error & 0x40 ) {
73036399Ssklower 		error &= ~0x40;
73136399Ssklower 		dutype = ER_TPDU_type;
73236399Ssklower 	} else
73336399Ssklower 		dutype = DR_TPDU_type;
73436399Ssklower 
73536399Ssklower 	hdr->tpdu_type = dutype;
73636399Ssklower 	hdr->tpdu_cdt = 0;
73736399Ssklower 
73836399Ssklower 	switch( dutype ) {
73936399Ssklower 
74036399Ssklower 	case DR_TPDU_type:
74136399Ssklower 		IncStat(ts_DR_sent);
74236399Ssklower 		hdr->tpdu_li = 7;
74336399Ssklower 		hdr->tpdu_DRdref = htons(sref);
74436399Ssklower 		hdr->tpdu_DRsref = htons(0);
74536399Ssklower 		hdr->tpdu_DRreason = (char)error;
74636399Ssklower 		IFDEBUG(D_ERROR_EMIT)
74736399Ssklower 			printf("DR case:\n");
74836399Ssklower 			dump_buf( hdr, 7);
74936399Ssklower 		ENDDEBUG
75036399Ssklower 		/* forget the add'l information variable part */
75136399Ssklower 		break;
75236399Ssklower 
75336399Ssklower 	case ER_TPDU_type:
75436399Ssklower 		IncStat(ts_ER_sent);
75536399Ssklower 		hdr->tpdu_li = 5;
75636399Ssklower 		hdr->tpdu_ERreason = (char)error;
75736399Ssklower 		break;
75836399Ssklower 
75936399Ssklower 	default:
76036399Ssklower 		ASSERT(0);
76136399Ssklower 		printf("TP PANIC: bad dutype 0x%x\n", dutype);
76236399Ssklower 	}
76336399Ssklower 
76436399Ssklower 	if(tpcb)
76536399Ssklower 		if( tpcb->tp_use_checksum ) {
76636399Ssklower 			ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
76736399Ssklower 			csum_offset =  hdr->tpdu_li - 2;
76836399Ssklower 		}
76936399Ssklower 
770*37469Ssklower 	ASSERT( hdr->tpdu_li < MLEN );
77136399Ssklower 
77236399Ssklower 	if (dutype == ER_TPDU_type) {
77336399Ssklower 		/* copy the errant tpdu into another 'variable part' */
77436399Ssklower 		register caddr_t P;
77536399Ssklower 
77636399Ssklower 		IFTRACE(D_ERROR_EMIT)
77736399Ssklower 			tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
77836399Ssklower 				0,0);
77936399Ssklower 		ENDTRACE
78036399Ssklower 		IFDEBUG(D_ERROR_EMIT)
78136399Ssklower 			printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
78236399Ssklower 		ENDDEBUG
78336399Ssklower 
78436399Ssklower 		/* copy at most as many octets for which you have room */
78536399Ssklower 		if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
78636399Ssklower 			erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
78736399Ssklower 
78836399Ssklower 		/* add the "invalid tpdu" parameter : required in class 0 */
78936399Ssklower 		P = (caddr_t)hdr + (int)(hdr->tpdu_li);
79036399Ssklower 		vbptr(P)->tpv_code =  TPP_invalid_tpdu; /* parameter code */
79136399Ssklower 		vbptr(P)->tpv_len = erlen;	/* parameter length */
79236399Ssklower 		m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
79336399Ssklower 
79436399Ssklower 		/* tp_input very likely handed us an mbuf chain w/ nothing in
79536399Ssklower 		 * the first mbuf and the data following the empty mbuf
79636399Ssklower 		 */
79736399Ssklower 		if(erdata->m_len == 0) {
79836399Ssklower 			erdata = m_free(erdata); /* returns the next mbuf on the chain */
79936399Ssklower 		}
800*37469Ssklower 		/*
801*37469Ssklower 		 * copy only up to the bad octet
802*37469Ssklower 		 * (or max that will fit in a header
803*37469Ssklower 		 */
804*37469Ssklower 		m->m_next = m_copy(erdata, 0, erlen);
80536399Ssklower 		hdr->tpdu_li += erlen + 2;
80636399Ssklower 		m_freem(erdata);
80736399Ssklower 	} else {
80836399Ssklower 		IFDEBUG(D_ERROR_EMIT)
80936399Ssklower 			printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
81036399Ssklower 			dump_buf( (char *)hdr, hdr->tpdu_li );
81136399Ssklower 		ENDDEBUG
81236399Ssklower 		m->m_len = hdr->tpdu_li ;
81336399Ssklower 		m_freem(erdata);
81436399Ssklower 	}
81536399Ssklower 
81636399Ssklower 	hdr->tpdu_li --;
81736399Ssklower 	IFTRACE(D_ERROR_EMIT)
81836399Ssklower 		tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
81936399Ssklower 	ENDTRACE
82036399Ssklower 
82136399Ssklower 	datalen = m_datalen( m);
82236399Ssklower 
82336399Ssklower 	if(tpcb) {
82436399Ssklower 		if( tpcb->tp_use_checksum ) {
82536399Ssklower 			IFTRACE(D_ERROR_EMIT)
82636399Ssklower 				tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
82736399Ssklower 			ENDTRACE
82836399Ssklower 			IFDEBUG(D_ERROR_EMIT)
82936399Ssklower 				printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
83036399Ssklower 					datalen, csum_offset);
83136399Ssklower 			ENDDEBUG
83236399Ssklower 
83336399Ssklower 			iso_gen_csum(m, csum_offset, datalen);
83436399Ssklower 		}
83536399Ssklower 
83636399Ssklower 		IFDEBUG(D_ERROR_EMIT)
83736399Ssklower 			printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
83836399Ssklower 				tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
83936399Ssklower 		ENDDEBUG
84036399Ssklower 		/* Problem: if packet comes in on ISO but sock is listening
84136399Ssklower 		 * in INET, this assertion will fail.
84236399Ssklower 		 * Have to believe the argument, not the nlp_proto.
84336399Ssklower 		ASSERT( tpcb->tp_nlproto->nlp_dgoutput == dgout_routine );
84436399Ssklower 		 */
84536399Ssklower 
84636399Ssklower 		IFDEBUG(D_ERROR_EMIT)
84736399Ssklower 			printf("tp_error_emit 1 sending DG: Laddr\n");
848*37469Ssklower 			dump_addr((struct sockaddr *)laddr);
84936399Ssklower 			printf("Faddr\n");
850*37469Ssklower 			dump_addr((struct sockaddr *)faddr);
85136399Ssklower 		ENDDEBUG
85236399Ssklower 		return (tpcb->tp_nlproto->nlp_dgoutput)(
85336399Ssklower 			&laddr->siso_addr,
85436399Ssklower 			&faddr->siso_addr,
85536399Ssklower 			m, datalen,
85636399Ssklower 					/* no route */	(caddr_t)0, !tpcb->tp_use_checksum);
85736399Ssklower 	} else  {
85836399Ssklower 		if( cons_channel ) {
85936399Ssklower #if NARGOXTWENTYFIVE > 0
860*37469Ssklower #include "cons.h"
86136399Ssklower 			/* This is unfortunate...
86236399Ssklower 				cons_send_on_vc(cons_channel, m, datalen);
86336399Ssklower 			*/
86436399Ssklower 			cons_netcmd( CONN_CLOSE, (struct isopcb *)0,
86536399Ssklower 				cons_channel, CONS_NOT_DGM);
86636399Ssklower 			IFDEBUG(D_ERROR_EMIT)
86736399Ssklower 				printf("OUTPUT: dutype 0x%x channel 0x%x\n",
86836399Ssklower 					dutype, cons_channel);
86936399Ssklower 			ENDDEBUG
87036399Ssklower #else NARGOXTWENTYFIVE
87136399Ssklower 			printf("TP panic! cons channel 0x%x but not cons configured\n",
87236399Ssklower 				cons_channel);
87336399Ssklower #endif NARGOXTWENTYFIVE > 0
87436399Ssklower 		} else {
875*37469Ssklower #ifndef notdef
87636399Ssklower 			IFDEBUG(D_ERROR_EMIT)
87736399Ssklower 				printf("tp_error_emit sending DG: Laddr\n");
878*37469Ssklower 				dump_addr((struct sockaddr *)laddr);
87936399Ssklower 				printf("Faddr\n");
880*37469Ssklower 				dump_addr((struct sockaddr *)faddr);
88136399Ssklower 			ENDDEBUG
88236399Ssklower 			return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
88336399Ssklower 				m, datalen, /* no route */
88436399Ssklower 				(caddr_t)0, /* nochecksum==false */0);
885*37469Ssklower #else notdef
88636399Ssklower 			IFDEBUG(D_ERROR_EMIT)
88736399Ssklower 				printf("tp_error_emit DROPPING \n", m);
88836399Ssklower 			ENDDEBUG
88936399Ssklower 			IncStat(ts_send_drop);
89036399Ssklower 			m_freem(m);
89136399Ssklower 			return 0;
892*37469Ssklower #endif notdef
89336399Ssklower 		}
89436399Ssklower 	}
89536399Ssklower }
896