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