xref: /csrg-svn/sys/netiso/tp_emit.c (revision 51996)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51996Ssklower  *	@(#)tp_emit.c	7.13 (Berkeley) 12/17/91
849268Sbostic  */
949268Sbostic 
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;
15151204Ssklower  	SeqNum olduwe;
15251204Ssklower 	int acking_ooo;
15336399Ssklower 
15436399Ssklower 	/* NOTE:
15536399Ssklower 	 * here we treat tpdu_li as if it DID include the li field, up until
15636399Ssklower 	 * the end, at which time we subtract 1
15736399Ssklower 	 * THis is because if we subtract 1 right away, we end up adding
15836399Ssklower 	 * one every time we add an option.
15936399Ssklower 	 */
16036399Ssklower 	IFDEBUG(D_EMIT)
16136399Ssklower 		printf(
16237469Ssklower 	"tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
16337469Ssklower 		dutype, tpcb, eot, seq, data);
16436399Ssklower 	ENDDEBUG
16536399Ssklower 
16637469Ssklower 	if (dutype == CR_TPDU || dutype == CC_TPDU) {
16737469Ssklower 		m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
16837469Ssklower 		if (m) {
16937469Ssklower 			m->m_type = TPMT_TPHDR;
17037469Ssklower 			mbstat.m_mtypes[TPMT_TPHDR]++;
17137469Ssklower 			m->m_next = MNULL;
17249583Ssklower 			m->m_nextpkt = MNULL;
17349583Ssklower 			m->m_data = m->m_pktdat;
17449583Ssklower 			m->m_flags = M_PKTHDR;
17537469Ssklower 		}
17637469Ssklower 	} else {
17749583Ssklower 		MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
17837469Ssklower 	}
17949583Ssklower 	m->m_data += max_hdr;
18036399Ssklower 	if (m == NULL) {
18136399Ssklower 		if(data != (struct mbuf *)0)
18236399Ssklower 			m_freem(data);
18336399Ssklower 		error = ENOBUFS;
18436399Ssklower 		goto done;
18536399Ssklower 	}
18636399Ssklower 	m->m_len = sizeof(struct tpdu);
18736399Ssklower 	m->m_act = MNULL;
18836399Ssklower 
18936399Ssklower 	hdr = mtod(m, struct tpdu *);
19037469Ssklower 	bzero((caddr_t)hdr, sizeof(struct tpdu));
19136399Ssklower 
19236399Ssklower 	{
19336399Ssklower 		int 	tp_headersize();
19436399Ssklower 
19536399Ssklower 		hdr->tpdu_type = dutype;
19636399Ssklower 		hdr->tpdu_li = tp_headersize(dutype, tpcb);
19736399Ssklower 		/*
19836399Ssklower 		 * class 0 doesn't use this for DT
19936399Ssklower 		 * it'll just get overwritten below
20036399Ssklower 		 */
20136399Ssklower 		hdr->tpdu_dref = htons(tpcb->tp_fref);
20236399Ssklower 		if( tpcb->tp_use_checksum ||
20336399Ssklower 			(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
20436399Ssklower 			csum_offset =  hdr->tpdu_li + 2; /* DOESN'T include csum */
20536399Ssklower 			ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */);
20636399Ssklower 			IFDEBUG(D_CHKSUM)
20736399Ssklower 				printf(
20836399Ssklower 					"tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
20936399Ssklower 						csum_offset, hdr->tpdu_li);
21036399Ssklower 			ENDDEBUG
21136399Ssklower 		}
21236399Ssklower 		/*
21336399Ssklower 		 * VARIABLE PARTS...
21436399Ssklower 		 */
21536399Ssklower 		switch( dutype ) {
21636399Ssklower 
21736399Ssklower 		case CR_TPDU_type:
21842494Ssklower 			hdr->tpdu_CRdref_0 = 0;	/* must be zero */
21939924Ssklower 			if (!tpcb->tp_cebit_off) {
22039924Ssklower 				tpcb->tp_win_recv = tp_start_win << 8;
22139924Ssklower 				LOCAL_CREDIT(tpcb);
22239924Ssklower 				CONG_INIT_SAMPLE(tpcb);
22351204Ssklower 			} else
22439924Ssklower 				LOCAL_CREDIT(tpcb);
22536399Ssklower 
22639924Ssklower 
22736399Ssklower 		case CC_TPDU_type:
22836399Ssklower 				{
22936399Ssklower 					u_char x;
23036399Ssklower 
23136399Ssklower 				hdr->tpdu_CCsref =  htons(tpcb->tp_lref); /* same as CRsref */
23236399Ssklower 
23336399Ssklower 				if( tpcb->tp_class > TP_CLASS_1 ) {
23439924Ssklower /* ifdef CE_BIT, we did this in tp_input when the CR came in */
23539924Ssklower 					if (tpcb->tp_cebit_off)
23639924Ssklower 						LOCAL_CREDIT( tpcb );
23736399Ssklower 					tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
23836399Ssklower 					tpcb->tp_sent_rcvnxt = 1;
23936399Ssklower 					tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
24036399Ssklower 					hdr->tpdu_cdt = tpcb->tp_lcredit;
24136399Ssklower 				} else {
24245900Ssklower #ifdef TPCONS
24345900Ssklower 					if (tpcb->tp_netservice == ISO_CONS) {
24445900Ssklower 						struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
24545900Ssklower 						struct pklcd *lcp = (struct pklcd *)(isop->isop_chan);
24645900Ssklower 						lcp->lcd_flags &= ~X25_DG_CIRCUIT;
24745900Ssklower 					}
24845900Ssklower #endif
24936399Ssklower 					hdr->tpdu_cdt = 0;
25036399Ssklower 				}
25136399Ssklower 				hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
25236399Ssklower 				hdr->tpdu_CCoptions =
25336399Ssklower 					(tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
25436399Ssklower 					(tpcb->tp_use_efc? TPO_USE_EFC:0);
25536399Ssklower 
25636399Ssklower 				IFPERF(tpcb)
25736399Ssklower 					u_char perf_meas = tpcb->tp_perf_on;
25836399Ssklower 					ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
25936399Ssklower 				ENDPERF
26036399Ssklower 
26136399Ssklower 				if( dutype == CR_TPDU_type ) {
26236399Ssklower 					IncStat(ts_CR_sent);
26336399Ssklower 
26436399Ssklower 					ASSERT( tpcb->tp_lsuffixlen > 0 );
26536399Ssklower 					ASSERT( tpcb->tp_fsuffixlen > 0 );
26636399Ssklower 
26736399Ssklower 					ADDOPTION(TPP_calling_sufx, hdr,
26837469Ssklower 						tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
26936399Ssklower 					ADDOPTION(TPP_called_sufx, hdr,
27037469Ssklower 						tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
27136399Ssklower 				} else {
27236399Ssklower 					IncStat(ts_CC_sent);
27336399Ssklower 				}
27436399Ssklower 
27536399Ssklower 				ADDOPTION(TPP_tpdu_size, hdr,
27636399Ssklower 					sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
27736399Ssklower 
27836399Ssklower 				if (tpcb->tp_class != TP_CLASS_0) {
27936399Ssklower 					short millisec = 500*(tpcb->tp_sendack_ticks);
28036399Ssklower 
28136399Ssklower 					millisec = htons(millisec);
28236399Ssklower 					ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
28336399Ssklower 
28436399Ssklower 					x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
28536399Ssklower 					 |	(tpcb->tp_use_rcc?  TPAO_USE_RCC : 0)
28636399Ssklower 					 |  (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
28736399Ssklower 					 |	(tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
28836399Ssklower 					ADDOPTION(TPP_addl_opt, hdr, 1, x);
28936399Ssklower 
290*51996Ssklower 					if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) {
291*51996Ssklower 						u_short size_s = tpcb->tp_l_tpdusize >> 7;
292*51996Ssklower 						u_char size_c = size_s;
293*51996Ssklower 						ASSERT(tpcb->tp_l_tpdusize < 65536 * 128);
294*51996Ssklower 						if (dutype == CR_TPDU_type)
295*51996Ssklower 							tpcb->tp_ptpdusize = size_s;
296*51996Ssklower 						if (size_s < 256) {
297*51996Ssklower 							ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
298*51996Ssklower 						} else {
299*51996Ssklower 							size_s = htons(size_s);
300*51996Ssklower 							ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s);
301*51996Ssklower 						}
302*51996Ssklower 					}
30336399Ssklower 				}
30436399Ssklower 
30536399Ssklower 				if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
30636399Ssklower 
30736399Ssklower 					ASSERT( 1 == sizeof(tpcb->tp_vers) );
30836399Ssklower 					ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
30936399Ssklower 
31036399Ssklower 					/* for each alt protocol class x,
31136399Ssklower 					 * 	x = x<<4;
31236399Ssklower 					 *  option = concat(option, x);
31336399Ssklower 					 * Well, for now we only have TP0 for an
31436399Ssklower 					 * alternative so... this is easy.
31536399Ssklower 					 *
31636399Ssklower 					 * HOWEVER... There should be NO alt protocol
31736399Ssklower 					 * class over CLNS.  Need to see if the route suggests
31836399Ssklower 					 * CONS, and iff so add alt class.
31936399Ssklower 					 */
32036399Ssklower 					x = 0;
32136399Ssklower 					ADDOPTION(TPP_alt_class, hdr, 1, x);
32236399Ssklower 				}
32336399Ssklower 
32436399Ssklower 				if( hdr->tpdu_li > MLEN)
32536399Ssklower 					panic("tp_emit CR/CC");
32636399Ssklower 			}
32736399Ssklower 			break;
32836399Ssklower 
32936399Ssklower 		case DR_TPDU_type:
33036399Ssklower 			if( hdr->tpdu_DRdref == 0 ) {
33136399Ssklower 				/* don't issue the DR */
33236399Ssklower 				goto done;
33336399Ssklower 			}
33436399Ssklower 			hdr->tpdu_cdt = 0;
33536399Ssklower 			hdr->tpdu_DRsref = htons(tpcb->tp_lref);
33636399Ssklower 			hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
33736399Ssklower 
33836399Ssklower 			/* forget the add'l information variable part */
33936399Ssklower 			IncStat(ts_DR_sent);
34036399Ssklower 			break;
34136399Ssklower 
34236399Ssklower 		case DC_TPDU_type: /* not used in class 0 */
34336399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0);
34436399Ssklower 			hdr->tpdu_DCsref =  htons(tpcb->tp_lref);
34536399Ssklower 			hdr->tpdu_cdt = 0;
34636399Ssklower 			data = (struct mbuf *)0;
34736399Ssklower 			IncStat(ts_DC_sent);
34836399Ssklower 			break;
34936399Ssklower 
35036399Ssklower 		case XAK_TPDU_type: /* xak not used in class 0 */
35136399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
35236399Ssklower 			hdr->tpdu_cdt = 0;
35336399Ssklower 
35436399Ssklower 			IFTRACE(D_XPD)
35536399Ssklower 				tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
35636399Ssklower 			ENDTRACE
35736399Ssklower 			data = (struct mbuf *)0;
35836399Ssklower 			if (tpcb->tp_xtd_format) {
35936399Ssklower #ifdef BYTE_ORDER
36048747Ssklower 				union seq_type seqeotX;
36148747Ssklower 
36248747Ssklower 				seqeotX.s_seq = seq;
36348747Ssklower 				seqeotX.s_eot = 1;
36448747Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
36536399Ssklower #else
36636399Ssklower 				hdr->tpdu_XAKseqX = seq;
36736399Ssklower #endif BYTE_ORDER
36836399Ssklower 			} else {
36936399Ssklower 				hdr->tpdu_XAKseq = seq;
37036399Ssklower 			}
37136399Ssklower 			IncStat(ts_XAK_sent);
37236399Ssklower 			IncPStat(tpcb, tps_XAK_sent);
37336399Ssklower 			break;
37436399Ssklower 
37536399Ssklower 		case XPD_TPDU_type: /* xpd not used in class 0 */
37636399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
37736399Ssklower 			hdr->tpdu_cdt = 0;
37836399Ssklower 			if (tpcb->tp_xtd_format) {
37936399Ssklower #ifdef BYTE_ORDER
38036399Ssklower 				union seq_type seqeotX;
38136399Ssklower 
38236399Ssklower 				seqeotX.s_seq = seq;
38336399Ssklower 				seqeotX.s_eot = 1;
38436399Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
38536399Ssklower #else
38636399Ssklower 				hdr->tpdu_XPDseqX = seq;
38736399Ssklower 				hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
38836399Ssklower #endif BYTE_ORDER
38936399Ssklower 			} else {
39036399Ssklower 				hdr->tpdu_XPDseq = seq;
39136399Ssklower 				hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
39236399Ssklower 			}
39336399Ssklower 			IncStat(ts_XPD_sent);
39436399Ssklower 			IncPStat(tpcb, tps_XPD_sent);
39536399Ssklower 
39636399Ssklower 			/* kludge to test the input size checking */
39736399Ssklower 			IFDEBUG(D_SIZE_CHECK)
39837469Ssklower 				/*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
39936399Ssklower 					printf("Sending too much data on XPD: 18 bytes\n");
40036399Ssklower 					data->m_len = 18;
40137469Ssklower 				}*/
40236399Ssklower 			ENDDEBUG
40336399Ssklower 			break;
40436399Ssklower 
40536399Ssklower 		case DT_TPDU_type:
40636399Ssklower 			hdr->tpdu_cdt = 0;
40736399Ssklower 			IFTRACE(D_DATA)
40836399Ssklower 				tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
40936399Ssklower 					hdr->tpdu_li, 0);
41036399Ssklower 			ENDTRACE
41136399Ssklower 			if (tpcb->tp_xtd_format) {
41236399Ssklower #ifdef BYTE_ORDER
41336399Ssklower 				union seq_type seqeotX;
41436399Ssklower 
41536399Ssklower 				seqeotX.s_seq = seq;
41636399Ssklower 				seqeotX.s_eot = eot;
41736399Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
41836399Ssklower #else
41936399Ssklower 				hdr->tpdu_DTseqX = seq;
42036399Ssklower 				hdr->tpdu_DTeotX = eot;
42136399Ssklower #endif BYTE_ORDER
42236399Ssklower 			} else if (tpcb->tp_class == TP_CLASS_0) {
42336399Ssklower 				IFDEBUG(D_EMIT)
42436399Ssklower 					printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
42536399Ssklower 					dump_buf( hdr, hdr->tpdu_li + 1 );
42636399Ssklower 				ENDDEBUG
42736399Ssklower 				((struct tp0du *)hdr)->tp0du_eot = eot;
42836399Ssklower 				((struct tp0du *)hdr)->tp0du_mbz = 0;
42936399Ssklower 				IFDEBUG(D_EMIT)
43036399Ssklower 					printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
43136399Ssklower 					dump_buf( hdr, hdr->tpdu_li + 1 );
43236399Ssklower 				ENDDEBUG
43336399Ssklower 			} else {
43436399Ssklower 				hdr->tpdu_DTseq = seq;
43536399Ssklower 				hdr->tpdu_DTeot = eot;
43636399Ssklower 			}
43736399Ssklower 			if(eot) {
43836399Ssklower 				IncStat(ts_EOT_sent);
43936399Ssklower 			}
44036399Ssklower 			IncStat(ts_DT_sent);
44136399Ssklower 			IncPStat(tpcb, tps_DT_sent);
44236399Ssklower 			break;
44336399Ssklower 
44436399Ssklower 		case AK_TPDU_type:/* ak not used in class 0 */
44536399Ssklower 			ASSERT( tpcb->tp_class != TP_CLASS_0);
44636399Ssklower 			data = (struct mbuf *)0;
44751204Ssklower 			olduwe = tpcb->tp_sent_uwe;
44836399Ssklower 
44951204Ssklower 			if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
45051204Ssklower 				LOCAL_CREDIT( tpcb );
45136399Ssklower 				tpcb->tp_sent_uwe =
45236399Ssklower 					SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
45336399Ssklower 				tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
45451204Ssklower 				acking_ooo = 0;
45551204Ssklower 			} else
45651204Ssklower 				acking_ooo = 1;
45736399Ssklower 
45851204Ssklower 			IFDEBUG(D_RENEG)
45951204Ssklower 				/* occasionally fake a reneging so
46051204Ssklower 					you can test subsequencing */
46151204Ssklower 				if( olduwe & 0x1 ) {
46236399Ssklower 					tpcb->tp_reneged = 1;
46351204Ssklower 					IncStat(ts_ldebug);
46436399Ssklower 				}
46551204Ssklower 			ENDDEBUG
46651204Ssklower 			/* Are we about to reneg on credit?
46751204Ssklower 			 * When might we do so?
46851204Ssklower 			 *	a) when using optimistic credit (which we no longer do).
46951204Ssklower 			 *  b) when drain() gets implemented (not in the plans).
47051204Ssklower 			 *  c) when D_RENEG is on.
47151204Ssklower 			 *  d) when DEC BIT response is implemented.
47251204Ssklower 			 *	(not- when we do this, we'll need to implement flow control
47351204Ssklower 			 *	confirmation)
47451204Ssklower 			 */
47551204Ssklower 			if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
47651204Ssklower 				tpcb->tp_reneged = 1;
47751204Ssklower 				IncStat(ts_lcdt_reduced);
47851204Ssklower 				IFTRACE(D_CREDIT)
47951204Ssklower 					tptraceTPCB(TPPTmisc,
48051204Ssklower 						"RENEG: olduwe newuwe lcredit rcvnxt",
48151204Ssklower 						olduwe,
48251204Ssklower 						tpcb->tp_sent_uwe, tpcb->tp_lcredit,
48351204Ssklower 						tpcb->tp_rcvnxt);
48451204Ssklower 				ENDTRACE
48551204Ssklower 			}
48651204Ssklower 			IFPERF(tpcb)
48751204Ssklower 				/* new lwe is less than old uwe means we're
48851204Ssklower 				 * acking before we received a whole window full
48951204Ssklower 				 */
49051204Ssklower 				if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
49151204Ssklower 					/* tmp1 = number of pkts fewer than the full window */
49251204Ssklower 					register int tmp1 =
49351204Ssklower 						(int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
49436399Ssklower 
49551204Ssklower 					if(tmp1 > TP_PM_MAX)
49651204Ssklower 						tmp1 = TP_PM_MAX;
49751204Ssklower 					IncPStat( tpcb,  tps_ack_early[tmp1] );
49836399Ssklower 
49951204Ssklower 					/* tmp1 = amt of new cdt we're advertising */
50051204Ssklower 					tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
50151204Ssklower 					if(tmp1 > TP_PM_MAX )
50251204Ssklower 						tmp1 = TP_PM_MAX;
50336399Ssklower 
50451204Ssklower 					IncPStat( tpcb,
50551204Ssklower 							tps_cdt_acked [ tmp1 ]
50651204Ssklower 							[ ((tpcb->tp_lcredit > TP_PM_MAX)?
50751204Ssklower 								TP_PM_MAX:tpcb->tp_lcredit) ] );
50836399Ssklower 
50951204Ssklower 				}
51051204Ssklower 			ENDPERF
51136399Ssklower 
51236399Ssklower 			IFTRACE(D_ACKSEND)
51336399Ssklower 				tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
51436399Ssklower 					tpcb->tp_r_subseq, 0);
51536399Ssklower 			ENDTRACE
51636399Ssklower 			if (tpcb->tp_xtd_format) {
51736399Ssklower #ifdef BYTE_ORDER
51848747Ssklower 				union seq_type seqeotX;
51948747Ssklower 
52048747Ssklower 				seqeotX.s_seq = seq;
52148747Ssklower 				seqeotX.s_eot = 0;
52248747Ssklower 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
52336399Ssklower 				hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
52436399Ssklower #else
52536399Ssklower 				hdr->tpdu_cdt = 0;
52636399Ssklower 				hdr->tpdu_AKseqX = seq;
52736399Ssklower 				hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
52836399Ssklower #endif BYTE_ORDER
52936399Ssklower 			} else {
53036399Ssklower 				hdr->tpdu_AKseq = seq;
53136399Ssklower 				hdr->tpdu_AKcdt = tpcb->tp_lcredit;
53236399Ssklower 			}
53351204Ssklower 			if ((tpcb->tp_class == TP_CLASS_4) &&
53451204Ssklower 				(tpcb->tp_reneged || acking_ooo)) {
53536399Ssklower 				/*
53636399Ssklower 				 * Ack subsequence parameter req'd if WE reneged on
53736399Ssklower 				 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
53836399Ssklower 				 */
53936399Ssklower 				IFDEBUG(D_RENEG)
54036399Ssklower 					printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
54136399Ssklower 				ENDDEBUG
54236399Ssklower 				tpcb->tp_s_subseq++;
54336399Ssklower 				/*
54436399Ssklower 				 * add tmp subseq and do a htons on it.
54536399Ssklower 				 */
54636399Ssklower 				ADDOPTION(TPP_subseq, hdr,
54736399Ssklower 					sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
54836399Ssklower 			} else
54936399Ssklower 				tpcb->tp_s_subseq = 0;
55036399Ssklower 
55136399Ssklower 			if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
55236399Ssklower 				/*
55336399Ssklower 				 * Rules for sending FCC ("should" send when) :
55436399Ssklower 				 * %a) received an ack from peer with NO NEWS whatsoever,
55536399Ssklower 				 *  	and it did not contain an FCC
55636399Ssklower 				 * 	b) received an ack from peer that opens its closed window.
55736399Ssklower 				 * 	c) received an ack from peer after it reneged on its
55836399Ssklower 				 *		offered credit, AND this ack raises UWE but LWE is same
55936399Ssklower 				 *		and below UWE at time of reneging (reduction)
56036399Ssklower 				 * Now, ISO 8073 12.2.3.8.3 says
56136399Ssklower 				 * that a retransmitted AK shall not contain the FCC
56236399Ssklower 				 * parameter.  Now, how the hell you tell the difference
56336399Ssklower 				 * between a retransmitted ack and an ack that's sent in
56436399Ssklower 				 * response to a received ack, I don't know, because without
56536399Ssklower 				 * any local activity, and w/o any received DTs, they
56636399Ssklower 				 * will contain exactly the same credit/seq# information.
56736399Ssklower 				 * Anyway, given that the "retransmission of acks"
56836399Ssklower 				 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
56936399Ssklower 				 * don't do it (although the peer can't tell that), we
57036399Ssklower 				 * ignore this last rule.
57136399Ssklower 				 *
57236399Ssklower 				 * We send FCC for reasons a) and b) only.
57336399Ssklower 				 * To add reason c) would require a ridiculous amount of state.
57436399Ssklower 				 *
57536399Ssklower 				 */
57636399Ssklower 				u_short 	bogus[4]; /* lwe(32), subseq(16), cdt(16) */
57736399Ssklower 				SeqNum		lwe;
57836399Ssklower 				u_short		subseq, fcredit;
57936399Ssklower 
58036399Ssklower 				tpcb->tp_sendfcc = 0;
58136399Ssklower 
58236399Ssklower 				lwe = (SeqNum) htonl(tpcb->tp_snduna);
58336399Ssklower 				subseq = htons(tpcb->tp_r_subseq);
58436399Ssklower 				fcredit = htons(tpcb->tp_fcredit);
58536399Ssklower 
58637469Ssklower 				bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
58737469Ssklower 				bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
58837469Ssklower 				bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
58936399Ssklower 
59036399Ssklower 				IFTRACE(D_ACKSEND)
59136399Ssklower 					tptraceTPCB(TPPTmisc,
59236399Ssklower 						"emit w/FCC: snduna r_subseq fcredit",
59336399Ssklower 						tpcb->tp_snduna, tpcb->tp_r_subseq,
59436399Ssklower 						tpcb->tp_fcredit, 0);
59536399Ssklower 				ENDTRACE
59636399Ssklower 
59736399Ssklower 				IFDEBUG(D_ACKSEND)
59836399Ssklower 					printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
59936399Ssklower 						TPP_flow_cntl_conf,
60036399Ssklower 						hdr, sizeof(bogus), bogus[0]);
60136399Ssklower 				ENDDEBUG
60236399Ssklower 				ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
60336399Ssklower 				IFDEBUG(D_ACKSEND)
60436399Ssklower 					printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
60536399Ssklower 						hdr, hdr->tpdu_li);
60636399Ssklower 					printf(
60736399Ssklower 					"after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
60836399Ssklower 							csum_offset, hdr->tpdu_li);
60936399Ssklower 				ENDDEBUG
61036399Ssklower 
61136399Ssklower 			}
61236399Ssklower 			tpcb->tp_reneged = 0;
61336399Ssklower 			tpcb->tp_sent_rcvnxt = seq;
61451204Ssklower 			if (tpcb->tp_fcredit == 0) {
61551204Ssklower 				int timo = tpcb->tp_keepalive_ticks;
61651204Ssklower 				if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
61751204Ssklower 					tpcb->tp_rxtshift++;
61851204Ssklower 				timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
61951204Ssklower 				tp_ctimeout(tpcb, TM_sendack, timo);
62051204Ssklower 			} else
62151204Ssklower 				tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
62236399Ssklower 			IncStat(ts_AK_sent);
62336399Ssklower 			IncPStat(tpcb, tps_AK_sent);
62436399Ssklower 			IFDEBUG(D_ACKSEND)
62536399Ssklower 				printf(
62636399Ssklower 				"2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
62736399Ssklower 						csum_offset, hdr->tpdu_li);
62836399Ssklower 			ENDDEBUG
62936399Ssklower 			break;
63036399Ssklower 
63136399Ssklower 		case ER_TPDU_type:
63236399Ssklower 			hdr->tpdu_ERreason = eot;
63336399Ssklower 			hdr->tpdu_cdt = 0;
63436399Ssklower 			/* no user data */
63536399Ssklower 			data = (struct mbuf *)0;
63636399Ssklower 			IncStat(ts_ER_sent);
63736399Ssklower 			break;
63836399Ssklower 		}
63936399Ssklower 
64036399Ssklower 	}
64136399Ssklower 	ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
64236399Ssklower 
64336399Ssklower 	m->m_next = data;
64436399Ssklower 
64537469Ssklower 	ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
64636399Ssklower 	ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
64736399Ssklower 
64836399Ssklower 	m->m_len = hdr->tpdu_li ;
64936399Ssklower 	hdr->tpdu_li --; /* doesn't include the li field */
65036399Ssklower 
65136399Ssklower 	datalen = m_datalen( m ); /* total len */
65236399Ssklower 
65336399Ssklower 	ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
65436399Ssklower 				when CLNP is used; leave in here for the time being */
65536399Ssklower 		IFDEBUG(D_ACKSEND)
65636399Ssklower 			printf(
65736399Ssklower 			"4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
65836399Ssklower 					csum_offset, hdr->tpdu_li);
65936399Ssklower 		ENDDEBUG
66036399Ssklower 	if( datalen > tpcb->tp_l_tpdusize ) {
66136399Ssklower 		printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
66236399Ssklower 			datalen, tpcb->tp_l_tpdusize);
66336399Ssklower 	}
66436399Ssklower 	IFDEBUG(D_EMIT)
66536399Ssklower 		printf(
66636399Ssklower 		"tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
66736399Ssklower 		m->m_len, csum_offset, datalen);
66836399Ssklower 	ENDDEBUG
66936399Ssklower 	if( tpcb->tp_use_checksum ||
67036399Ssklower 		(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
67136399Ssklower 		iso_gen_csum(m, csum_offset, datalen);
67236399Ssklower 	}
67336399Ssklower 
67436399Ssklower 	IFDEBUG(D_EMIT)
67536399Ssklower 	printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
67636399Ssklower 		tpcb, dutype, datalen);
67737469Ssklower 		dump_buf(mtod(m, caddr_t), datalen);
67836399Ssklower 	ENDDEBUG
67936399Ssklower 
68036399Ssklower 	IFPERF(tpcb)
68136399Ssklower 		if( dutype == DT_TPDU_type ) {
68236399Ssklower 			PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
68337469Ssklower 			tpmeas( tpcb->tp_lref, TPtime_to_ll,  (struct timeval *)0,
68436399Ssklower 				seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
68536399Ssklower 		}
68636399Ssklower 	ENDPERF
68736399Ssklower 
68836399Ssklower 	IFTRACE(D_EMIT)
68936399Ssklower 		tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
69036399Ssklower 	ENDTRACE
69136399Ssklower 	IFDEBUG(D_EMIT)
69236399Ssklower 		printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
69336399Ssklower 			tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
69436399Ssklower 	ENDDEBUG
69536399Ssklower 
69636399Ssklower 	{ extern char tp_delay;
69736399Ssklower 
69836399Ssklower 		if( tp_delay )
69936399Ssklower 			if( tpcb->tp_use_checksum == 0 ) {
70036399Ssklower 				register u_int i  = tp_delay;
70136399Ssklower 				for (; i!= 0; i--)
70236399Ssklower 					(void) iso_check_csum(m, datalen);
70336399Ssklower 			}
70436399Ssklower 	}
70536399Ssklower 	ASSERT( m->m_len > 0 );
70636399Ssklower 	error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
70736399Ssklower 		!tpcb->tp_use_checksum);
70836399Ssklower 	IFDEBUG(D_EMIT)
70936399Ssklower 		printf("OUTPUT: returned 0x%x\n", error);
71036399Ssklower 	ENDDEBUG
71136399Ssklower 	IFTRACE(D_EMIT)
71236399Ssklower 		tptraceTPCB(TPPTmisc,
71336399Ssklower 			"tp_emit nlproto->output netservice returns datalen",
71436399Ssklower 			tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
71536399Ssklower 	ENDTRACE
71636399Ssklower done:
71751204Ssklower 	if (error) {
71851204Ssklower 		if (dutype == AK_TPDU_type)
71951204Ssklower 			tp_ctimeout(tpcb, TM_sendack, 1);
72051204Ssklower 		if (error == E_CO_QFULL) {
72151204Ssklower 			tp_quench(tpcb, PRC_QUENCH);
72251204Ssklower 			return 0;
72351204Ssklower 		}
72436399Ssklower 	}
72536399Ssklower 	return error;
72636399Ssklower }
72736399Ssklower /*
72836399Ssklower  * NAME:		tp_error_emit()
72936399Ssklower  * CALLED FROM:	tp_input() when a DR or ER is to be issued in
73036399Ssklower  * 		response to an input error.
73136399Ssklower  * FUNCTION and ARGUMENTS:
73236399Ssklower  * 		The error type is the first argument.
73336399Ssklower  * 		The argument (sref) is the source reference on the bad incoming tpdu,
73436399Ssklower  * 		and is used for a destination reference on the outgoing packet.
73536399Ssklower  * 		(faddr) and (laddr) are the foreign and local addresses for this
73636399Ssklower  *		connection.
73736399Ssklower  * 		(erdata) is a ptr to the errant incoming tpdu, and is copied into the
73836399Ssklower  * 		outgoing ER, if an ER is to be issued.
73936399Ssklower  * 		(erlen)  is the number of octets of the errant tpdu that we should
74036399Ssklower  * 		try to copy.
74136399Ssklower  * 		(tpcb) is the pcb that describes the connection for which the bad tpdu
74236399Ssklower  * 		arrived.
74336399Ssklower  * RETURN VALUES:
74436399Ssklower  * 		0 OK
74536399Ssklower  *  	ENOBUFS
74636399Ssklower  *  	E* from net layer datagram output routine
74736399Ssklower  * SIDE EFFECTS:
74836399Ssklower  *
74936399Ssklower  * NOTES:
75036399Ssklower  */
75136399Ssklower 
75236399Ssklower int
75336399Ssklower tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
75436399Ssklower 	dgout_routine)
75536399Ssklower 	int				error;
75636399Ssklower 	u_long			sref;
75736399Ssklower 	struct sockaddr_iso *faddr, *laddr;
75836399Ssklower 	struct mbuf 	*erdata;
75936399Ssklower 	int 			erlen;
76036399Ssklower 	struct tp_pcb 	*tpcb;
76150535Ssklower 	caddr_t			cons_channel;
76236399Ssklower 	int				(*dgout_routine)();
76336399Ssklower {
76436399Ssklower 	int						dutype;
76536399Ssklower 	int 					datalen = 0;
76636399Ssklower 	register struct tpdu	*hdr;
76736399Ssklower 	register struct mbuf	*m;
76836399Ssklower 	int						csum_offset;
76936399Ssklower 
77036399Ssklower 	IFTRACE(D_ERROR_EMIT)
77136399Ssklower 		tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
77236399Ssklower 			error, sref, tpcb, erlen);
77336399Ssklower 	ENDTRACE
77436399Ssklower 	IFDEBUG(D_ERROR_EMIT)
77536399Ssklower 		printf(
77636399Ssklower 		"tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
77736399Ssklower 			error, sref, tpcb, erlen, cons_channel);
77836399Ssklower 	ENDDEBUG
77936399Ssklower 
78036399Ssklower 	MGET(m, M_DONTWAIT, TPMT_TPHDR);
78136399Ssklower 	if (m == NULL) {
78236399Ssklower 		return ENOBUFS;
78336399Ssklower 	}
78436399Ssklower 	m->m_len = sizeof(struct tpdu);
78536399Ssklower 	m->m_act = MNULL;
78636399Ssklower 
78736399Ssklower 	hdr = mtod(m, struct tpdu *);
78836399Ssklower 
78936399Ssklower 	IFDEBUG(D_ERROR_EMIT)
79036399Ssklower 		printf("[error 0x%x] [error&0xff  0x%x] [(char)error 0x%x]\n",
79136399Ssklower 			error, error&0xff, (char)error);
79236399Ssklower 	ENDDEBUG
79336399Ssklower 
79436399Ssklower 
79542494Ssklower 	if (error & TP_ERROR_SNDC)
79642494Ssklower 		dutype = DC_TPDU_type;
79742494Ssklower 	else if (error & 0x40) {
79836399Ssklower 		error &= ~0x40;
79936399Ssklower 		dutype = ER_TPDU_type;
80036399Ssklower 	} else
80136399Ssklower 		dutype = DR_TPDU_type;
80242494Ssklower 	error &= 0xff;
80336399Ssklower 
80436399Ssklower 	hdr->tpdu_type = dutype;
80536399Ssklower 	hdr->tpdu_cdt = 0;
80636399Ssklower 
80736399Ssklower 	switch( dutype ) {
80836399Ssklower 
80942494Ssklower 	case DC_TPDU_type:
81042494Ssklower 		IncStat(ts_DC_sent);
81142494Ssklower 		hdr->tpdu_li = 6;
81242494Ssklower 		hdr->tpdu_DCdref = htons(sref);
81342494Ssklower 		hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
81442494Ssklower 		IFDEBUG(D_ERROR_EMIT)
81542494Ssklower 			printf("DC case:\n");
81642494Ssklower 			dump_buf( hdr, 6);
81742494Ssklower 		ENDDEBUG
81842494Ssklower 		/* forget the add'l information variable part */
81942494Ssklower 		break;
82042494Ssklower 
82136399Ssklower 	case DR_TPDU_type:
82236399Ssklower 		IncStat(ts_DR_sent);
82336399Ssklower 		hdr->tpdu_li = 7;
82436399Ssklower 		hdr->tpdu_DRdref = htons(sref);
82542494Ssklower 		hdr->tpdu_DRsref = 0;
82636399Ssklower 		hdr->tpdu_DRreason = (char)error;
82736399Ssklower 		IFDEBUG(D_ERROR_EMIT)
82836399Ssklower 			printf("DR case:\n");
82936399Ssklower 			dump_buf( hdr, 7);
83036399Ssklower 		ENDDEBUG
83136399Ssklower 		/* forget the add'l information variable part */
83236399Ssklower 		break;
83336399Ssklower 
83436399Ssklower 	case ER_TPDU_type:
83536399Ssklower 		IncStat(ts_ER_sent);
83636399Ssklower 		hdr->tpdu_li = 5;
83736399Ssklower 		hdr->tpdu_ERreason = (char)error;
83850535Ssklower 		hdr->tpdu_ERdref = htons(sref);
83936399Ssklower 		break;
84036399Ssklower 
84136399Ssklower 	default:
84236399Ssklower 		ASSERT(0);
84336399Ssklower 		printf("TP PANIC: bad dutype 0x%x\n", dutype);
84436399Ssklower 	}
84536399Ssklower 
84636399Ssklower 	if(tpcb)
84736399Ssklower 		if( tpcb->tp_use_checksum ) {
84836399Ssklower 			ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
84936399Ssklower 			csum_offset =  hdr->tpdu_li - 2;
85036399Ssklower 		}
85136399Ssklower 
85237469Ssklower 	ASSERT( hdr->tpdu_li < MLEN );
85336399Ssklower 
85436399Ssklower 	if (dutype == ER_TPDU_type) {
85536399Ssklower 		/* copy the errant tpdu into another 'variable part' */
85636399Ssklower 		register caddr_t P;
85736399Ssklower 
85836399Ssklower 		IFTRACE(D_ERROR_EMIT)
85936399Ssklower 			tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
86036399Ssklower 				0,0);
86136399Ssklower 		ENDTRACE
86236399Ssklower 		IFDEBUG(D_ERROR_EMIT)
86336399Ssklower 			printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
86436399Ssklower 		ENDDEBUG
86536399Ssklower 
86636399Ssklower 		/* copy at most as many octets for which you have room */
86736399Ssklower 		if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
86836399Ssklower 			erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
86936399Ssklower 
87036399Ssklower 		/* add the "invalid tpdu" parameter : required in class 0 */
87136399Ssklower 		P = (caddr_t)hdr + (int)(hdr->tpdu_li);
87236399Ssklower 		vbptr(P)->tpv_code =  TPP_invalid_tpdu; /* parameter code */
87336399Ssklower 		vbptr(P)->tpv_len = erlen;	/* parameter length */
87436399Ssklower 		m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
87536399Ssklower 
87636399Ssklower 		/* tp_input very likely handed us an mbuf chain w/ nothing in
87736399Ssklower 		 * the first mbuf and the data following the empty mbuf
87836399Ssklower 		 */
87936399Ssklower 		if(erdata->m_len == 0) {
88036399Ssklower 			erdata = m_free(erdata); /* returns the next mbuf on the chain */
88136399Ssklower 		}
88237469Ssklower 		/*
88337469Ssklower 		 * copy only up to the bad octet
88437469Ssklower 		 * (or max that will fit in a header
88537469Ssklower 		 */
88637469Ssklower 		m->m_next = m_copy(erdata, 0, erlen);
88736399Ssklower 		hdr->tpdu_li += erlen + 2;
88836399Ssklower 		m_freem(erdata);
88936399Ssklower 	} else {
89036399Ssklower 		IFDEBUG(D_ERROR_EMIT)
89136399Ssklower 			printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
89236399Ssklower 			dump_buf( (char *)hdr, hdr->tpdu_li );
89336399Ssklower 		ENDDEBUG
89436399Ssklower 		m->m_len = hdr->tpdu_li ;
89536399Ssklower 		m_freem(erdata);
89636399Ssklower 	}
89736399Ssklower 
89836399Ssklower 	hdr->tpdu_li --;
89936399Ssklower 	IFTRACE(D_ERROR_EMIT)
90036399Ssklower 		tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
90136399Ssklower 	ENDTRACE
90236399Ssklower 
90336399Ssklower 	datalen = m_datalen( m);
90450648Ssklower 	if (tpcb) {
90536399Ssklower 		if( tpcb->tp_use_checksum ) {
90636399Ssklower 			IFTRACE(D_ERROR_EMIT)
90736399Ssklower 				tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
90836399Ssklower 			ENDTRACE
90936399Ssklower 			IFDEBUG(D_ERROR_EMIT)
91036399Ssklower 				printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
91136399Ssklower 					datalen, csum_offset);
91236399Ssklower 			ENDDEBUG
91336399Ssklower 
91436399Ssklower 			iso_gen_csum(m, csum_offset, datalen);
91536399Ssklower 		}
91636399Ssklower 
91736399Ssklower 		IFDEBUG(D_ERROR_EMIT)
91836399Ssklower 			printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
91936399Ssklower 				tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
92036399Ssklower 		ENDDEBUG
92150648Ssklower 	}
92250648Ssklower 	if (cons_channel) {
92350648Ssklower #ifdef TPCONS
92450648Ssklower 		struct pklcd *lcp = (struct pklcd *)cons_channel;
92550648Ssklower 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
92636399Ssklower 
92750648Ssklower 		tpcons_dg_output(cons_channel, m, datalen);
92850648Ssklower 		/* was if (tpcb == 0) iso_pcbdetach(isop); */
92950648Ssklower 		/* but other side may want to try again over same VC,
93050648Ssklower 		   so, we'll depend on him closing it, but in case it gets forgotten
93150648Ssklower 		   we'll mark it for garbage collection */
93250648Ssklower 		lcp->lcd_flags |= X25_DG_CIRCUIT;
93336399Ssklower 		IFDEBUG(D_ERROR_EMIT)
93450648Ssklower 			printf("OUTPUT: dutype 0x%x channel 0x%x\n",
93550648Ssklower 				dutype, cons_channel);
93650648Ssklower 		ENDDEBUG
93750648Ssklower #else
93850648Ssklower 		printf("TP panic! cons channel 0x%x but not cons configured\n",
93950648Ssklower 			cons_channel);
94050648Ssklower #endif
94150648Ssklower 	} else if (tpcb) {
94250648Ssklower 
94350648Ssklower 		IFDEBUG(D_ERROR_EMIT)
94436399Ssklower 			printf("tp_error_emit 1 sending DG: Laddr\n");
94537469Ssklower 			dump_addr((struct sockaddr *)laddr);
94636399Ssklower 			printf("Faddr\n");
94737469Ssklower 			dump_addr((struct sockaddr *)faddr);
94836399Ssklower 		ENDDEBUG
94936399Ssklower 		return (tpcb->tp_nlproto->nlp_dgoutput)(
95036399Ssklower 			&laddr->siso_addr,
95136399Ssklower 			&faddr->siso_addr,
95236399Ssklower 			m, datalen,
95336399Ssklower 					/* no route */	(caddr_t)0, !tpcb->tp_use_checksum);
95450648Ssklower 	} else if (dgout_routine) {
95536399Ssklower 			IFDEBUG(D_ERROR_EMIT)
95636399Ssklower 				printf("tp_error_emit sending DG: Laddr\n");
95737469Ssklower 				dump_addr((struct sockaddr *)laddr);
95836399Ssklower 				printf("Faddr\n");
95937469Ssklower 				dump_addr((struct sockaddr *)faddr);
96036399Ssklower 			ENDDEBUG
96150648Ssklower 				return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
96250648Ssklower 					m, datalen, /* no route */
96350648Ssklower 					(caddr_t)0, /* nochecksum==false */0);
96450648Ssklower 	} else {
96536399Ssklower 			IFDEBUG(D_ERROR_EMIT)
96636399Ssklower 				printf("tp_error_emit DROPPING \n", m);
96736399Ssklower 			ENDDEBUG
96836399Ssklower 			IncStat(ts_send_drop);
96936399Ssklower 			m_freem(m);
97036399Ssklower 			return 0;
97136399Ssklower 	}
97236399Ssklower }
973