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