149268Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449268Sbostic *
549268Sbostic * %sccs.include.redist.c%
649268Sbostic *
7*63222Sbostic * @(#)tp_emit.c 8.1 (Berkeley) 06/10/93
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
5656533Sbostic #include <sys/param.h>
5756533Sbostic #include <sys/systm.h>
5856533Sbostic #include <sys/mbuf.h>
5956533Sbostic #include <sys/socket.h>
6056533Sbostic #include <sys/socketvar.h>
6156533Sbostic #include <sys/protosw.h>
6256533Sbostic #include <sys/errno.h>
6356533Sbostic #include <sys/time.h>
6436399Ssklower
6556533Sbostic #include <netiso/iso.h>
6656533Sbostic #include <netiso/iso_pcb.h>
6756533Sbostic #include <netiso/argo_debug.h>
6856533Sbostic #include <netiso/tp_timer.h>
6956533Sbostic #include <netiso/tp_param.h>
7056533Sbostic #include <netiso/tp_stat.h>
7156533Sbostic #include <netiso/tp_pcb.h>
7256533Sbostic #include <netiso/tp_tpdu.h>
7356533Sbostic #include <netiso/tp_trace.h>
7456533Sbostic #include <netiso/tp_meas.h>
7556533Sbostic #include <netiso/tp_seq.h>
7656533Sbostic #include <netiso/iso_errno.h>
7756533Sbostic
7856533Sbostic #include <net/if.h>
7945900Ssklower #ifdef TRUE
8045900Ssklower #undef FALSE
8145900Ssklower #undef TRUE
8245900Ssklower #endif
8356533Sbostic #include <netccitt/x25.h>
8456533Sbostic #include <netccitt/pk.h>
8556533Sbostic #include <netccitt/pk_var.h>
8645900Ssklower
8736399Ssklower void iso_gen_csum();
8836399Ssklower
8936399Ssklower
9036399Ssklower /* Here is a mighty kludge. The token ring misorders packets if you
9136399Ssklower * fire them at it too fast, and TP sans checksum is "too fast", so
9236399Ssklower * we have introduced a delay when checksumming isn't used.
9336399Ssklower */
9436399Ssklower char tp_delay = 0x00; /* delay to keep token ring from blowing it */
9536399Ssklower
9636399Ssklower /*
9736399Ssklower * NAME: tp_emit()
9836399Ssklower *
9936399Ssklower * CALLED FROM: tp.trans and from tp_sbsend()
10036399Ssklower *
10136399Ssklower * FUNCTION and ARGUMENTS:
10236399Ssklower * Emits one tpdu of the type (dutype), of the format appropriate
10336399Ssklower * to the connection described by the pcb (tpcb), with sequence
10436399Ssklower * number (seq) (where appropriate), end-of-tsdu bit (eot) where
10536399Ssklower * appropriate, and with the data in the mbuf chain (data).
10636399Ssklower * For DR and ER tpdus, the argument (eot) is
10736399Ssklower * the reason for issuing the tpdu rather than an end-of-tsdu indicator.
10836399Ssklower *
10936399Ssklower * RETURNS:
11036399Ssklower * 0 OK
11136399Ssklower * ENOBUFS
11236399Ssklower * E* returned from net layer output rtn
11336399Ssklower *
11436399Ssklower * SIDE EFFECTS:
11536399Ssklower *
11636399Ssklower * NOTES:
11736399Ssklower *
11836399Ssklower * WE ASSUME that the tp header + all options will fit in ONE mbuf.
11936399Ssklower * If mbufs are 256 this will most likely be true, but if they are 128 it's
12036399Ssklower * possible that they won't.
12136399Ssklower * If you used every option on the CR + max. user data you'd overrun
12236399Ssklower * 112 but unless you used > 115 bytes for the security
12336399Ssklower * parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
12436399Ssklower * We don't support the security parameter, so this isn't a problem.
12536399Ssklower * If security is added, we ought to remove this assumption.
12636399Ssklower *
12736399Ssklower * We do not implement the flow control confirmation "element of procedure".
12836399Ssklower * A) it should not affect interoperability,
12936399Ssklower * B) it should not be necessary - the protocol will eventually
13036399Ssklower * straighten things out w/o FCC, as long as we don't have severely
13136399Ssklower * mismatched keepalive and inactivity timers, and
13236399Ssklower * C) it appears not to be REQUIRED, and
13336399Ssklower * D) it's incredibly grotesque, and no doubt will lengthen a few
13436399Ssklower * critical paths.
13536399Ssklower * HOWEVER, we're thinking about putting it in anyway, for
13636399Ssklower * completeness, just like we did with ack subsequencing.
13736399Ssklower */
13836399Ssklower
13936399Ssklower int
tp_emit(dutype,tpcb,seq,eot,data)14036399Ssklower tp_emit(dutype, tpcb, seq, eot, data)
14136399Ssklower int dutype;
14236399Ssklower struct tp_pcb *tpcb;
14336399Ssklower SeqNum seq;
14436399Ssklower u_int eot;
14536399Ssklower struct mbuf *data;
14636399Ssklower {
14736399Ssklower register struct tpdu *hdr;
14836399Ssklower register struct mbuf *m;
14936399Ssklower int csum_offset=0;
15036399Ssklower int datalen = 0;
15136399Ssklower int error = 0;
15251204Ssklower SeqNum olduwe;
15351204Ssklower int acking_ooo;
15436399Ssklower
15536399Ssklower /* NOTE:
15636399Ssklower * here we treat tpdu_li as if it DID include the li field, up until
15736399Ssklower * the end, at which time we subtract 1
15836399Ssklower * THis is because if we subtract 1 right away, we end up adding
15936399Ssklower * one every time we add an option.
16036399Ssklower */
16136399Ssklower IFDEBUG(D_EMIT)
16236399Ssklower printf(
16337469Ssklower "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
16437469Ssklower dutype, tpcb, eot, seq, data);
16536399Ssklower ENDDEBUG
16636399Ssklower
16737469Ssklower if (dutype == CR_TPDU || dutype == CC_TPDU) {
16837469Ssklower m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
16937469Ssklower if (m) {
17037469Ssklower m->m_type = TPMT_TPHDR;
17137469Ssklower mbstat.m_mtypes[TPMT_TPHDR]++;
17237469Ssklower m->m_next = MNULL;
17349583Ssklower m->m_nextpkt = MNULL;
17449583Ssklower m->m_data = m->m_pktdat;
17549583Ssklower m->m_flags = M_PKTHDR;
17637469Ssklower }
17737469Ssklower } else {
17849583Ssklower MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
17937469Ssklower }
18049583Ssklower m->m_data += max_hdr;
18136399Ssklower if (m == NULL) {
18236399Ssklower if(data != (struct mbuf *)0)
18336399Ssklower m_freem(data);
18436399Ssklower error = ENOBUFS;
18536399Ssklower goto done;
18636399Ssklower }
18736399Ssklower m->m_len = sizeof(struct tpdu);
18836399Ssklower m->m_act = MNULL;
18936399Ssklower
19036399Ssklower hdr = mtod(m, struct tpdu *);
19137469Ssklower bzero((caddr_t)hdr, sizeof(struct tpdu));
19236399Ssklower
19336399Ssklower {
19436399Ssklower int tp_headersize();
19536399Ssklower
19636399Ssklower hdr->tpdu_type = dutype;
19736399Ssklower hdr->tpdu_li = tp_headersize(dutype, tpcb);
19836399Ssklower /*
19936399Ssklower * class 0 doesn't use this for DT
20036399Ssklower * it'll just get overwritten below
20136399Ssklower */
20236399Ssklower hdr->tpdu_dref = htons(tpcb->tp_fref);
20336399Ssklower if( tpcb->tp_use_checksum ||
20436399Ssklower (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
20536399Ssklower csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */
20636399Ssklower ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */);
20736399Ssklower IFDEBUG(D_CHKSUM)
20836399Ssklower printf(
20936399Ssklower "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
21036399Ssklower csum_offset, hdr->tpdu_li);
21136399Ssklower ENDDEBUG
21236399Ssklower }
21336399Ssklower /*
21436399Ssklower * VARIABLE PARTS...
21536399Ssklower */
21636399Ssklower switch( dutype ) {
21736399Ssklower
21836399Ssklower case CR_TPDU_type:
21942494Ssklower hdr->tpdu_CRdref_0 = 0; /* must be zero */
22053686Ssklower case CC_TPDU_type:
22139924Ssklower if (!tpcb->tp_cebit_off) {
22239924Ssklower tpcb->tp_win_recv = tp_start_win << 8;
22339924Ssklower LOCAL_CREDIT(tpcb);
22439924Ssklower CONG_INIT_SAMPLE(tpcb);
22551204Ssklower } else
22639924Ssklower LOCAL_CREDIT(tpcb);
22736399Ssklower
22853686Ssklower /* Case CC_TPDU_type used to be here */
22953686Ssklower {
23036399Ssklower u_char x;
23136399Ssklower
23236399Ssklower hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */
23336399Ssklower
23436399Ssklower if( tpcb->tp_class > TP_CLASS_1 ) {
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
28851996Ssklower if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) {
28951996Ssklower u_short size_s = tpcb->tp_l_tpdusize >> 7;
29051996Ssklower u_char size_c = size_s;
29151996Ssklower ASSERT(tpcb->tp_l_tpdusize < 65536 * 128);
29251996Ssklower if (dutype == CR_TPDU_type)
29351996Ssklower tpcb->tp_ptpdusize = size_s;
29451996Ssklower if (size_s < 256) {
29551996Ssklower ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
29651996Ssklower } else {
29751996Ssklower size_s = htons(size_s);
29851996Ssklower ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s);
29951996Ssklower }
30051996Ssklower }
30136399Ssklower }
30236399Ssklower
30336399Ssklower if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
30436399Ssklower
30536399Ssklower ASSERT( 1 == sizeof(tpcb->tp_vers) );
30636399Ssklower ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
30736399Ssklower
30836399Ssklower /* for each alt protocol class x,
30936399Ssklower * x = x<<4;
31036399Ssklower * option = concat(option, x);
31136399Ssklower * Well, for now we only have TP0 for an
31236399Ssklower * alternative so... this is easy.
31336399Ssklower *
31436399Ssklower * HOWEVER... There should be NO alt protocol
31536399Ssklower * class over CLNS. Need to see if the route suggests
31636399Ssklower * CONS, and iff so add alt class.
31736399Ssklower */
31836399Ssklower x = 0;
31936399Ssklower ADDOPTION(TPP_alt_class, hdr, 1, x);
32036399Ssklower }
32136399Ssklower
32236399Ssklower if( hdr->tpdu_li > MLEN)
32336399Ssklower panic("tp_emit CR/CC");
32436399Ssklower }
32536399Ssklower break;
32636399Ssklower
32736399Ssklower case DR_TPDU_type:
32836399Ssklower if( hdr->tpdu_DRdref == 0 ) {
32936399Ssklower /* don't issue the DR */
33036399Ssklower goto done;
33136399Ssklower }
33236399Ssklower hdr->tpdu_cdt = 0;
33336399Ssklower hdr->tpdu_DRsref = htons(tpcb->tp_lref);
33436399Ssklower hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
33536399Ssklower
33636399Ssklower /* forget the add'l information variable part */
33736399Ssklower IncStat(ts_DR_sent);
33836399Ssklower break;
33936399Ssklower
34036399Ssklower case DC_TPDU_type: /* not used in class 0 */
34136399Ssklower ASSERT( tpcb->tp_class != TP_CLASS_0);
34236399Ssklower hdr->tpdu_DCsref = htons(tpcb->tp_lref);
34336399Ssklower hdr->tpdu_cdt = 0;
34436399Ssklower data = (struct mbuf *)0;
34536399Ssklower IncStat(ts_DC_sent);
34636399Ssklower break;
34736399Ssklower
34836399Ssklower case XAK_TPDU_type: /* xak not used in class 0 */
34936399Ssklower ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
35036399Ssklower hdr->tpdu_cdt = 0;
35136399Ssklower
35236399Ssklower IFTRACE(D_XPD)
35336399Ssklower tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
35436399Ssklower ENDTRACE
35536399Ssklower data = (struct mbuf *)0;
35636399Ssklower if (tpcb->tp_xtd_format) {
35736399Ssklower #ifdef BYTE_ORDER
35848747Ssklower union seq_type seqeotX;
35948747Ssklower
36048747Ssklower seqeotX.s_seq = seq;
36148747Ssklower seqeotX.s_eot = 1;
36248747Ssklower hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
36336399Ssklower #else
36436399Ssklower hdr->tpdu_XAKseqX = seq;
36560359Sbostic #endif /* BYTE_ORDER */
36636399Ssklower } else {
36736399Ssklower hdr->tpdu_XAKseq = seq;
36836399Ssklower }
36936399Ssklower IncStat(ts_XAK_sent);
37036399Ssklower IncPStat(tpcb, tps_XAK_sent);
37136399Ssklower break;
37236399Ssklower
37336399Ssklower case XPD_TPDU_type: /* xpd not used in class 0 */
37436399Ssklower ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
37536399Ssklower hdr->tpdu_cdt = 0;
37636399Ssklower if (tpcb->tp_xtd_format) {
37736399Ssklower #ifdef BYTE_ORDER
37836399Ssklower union seq_type seqeotX;
37936399Ssklower
38036399Ssklower seqeotX.s_seq = seq;
38136399Ssklower seqeotX.s_eot = 1;
38236399Ssklower hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
38336399Ssklower #else
38436399Ssklower hdr->tpdu_XPDseqX = seq;
38536399Ssklower hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
38660359Sbostic #endif /* BYTE_ORDER */
38736399Ssklower } else {
38836399Ssklower hdr->tpdu_XPDseq = seq;
38936399Ssklower hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
39036399Ssklower }
39136399Ssklower IncStat(ts_XPD_sent);
39236399Ssklower IncPStat(tpcb, tps_XPD_sent);
39336399Ssklower
39436399Ssklower /* kludge to test the input size checking */
39536399Ssklower IFDEBUG(D_SIZE_CHECK)
39637469Ssklower /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
39736399Ssklower printf("Sending too much data on XPD: 18 bytes\n");
39836399Ssklower data->m_len = 18;
39937469Ssklower }*/
40036399Ssklower ENDDEBUG
40136399Ssklower break;
40236399Ssklower
40336399Ssklower case DT_TPDU_type:
40436399Ssklower hdr->tpdu_cdt = 0;
40536399Ssklower IFTRACE(D_DATA)
40636399Ssklower tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
40736399Ssklower hdr->tpdu_li, 0);
40836399Ssklower ENDTRACE
40936399Ssklower if (tpcb->tp_xtd_format) {
41036399Ssklower #ifdef BYTE_ORDER
41136399Ssklower union seq_type seqeotX;
41236399Ssklower
41336399Ssklower seqeotX.s_seq = seq;
41436399Ssklower seqeotX.s_eot = eot;
41536399Ssklower hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
41636399Ssklower #else
41736399Ssklower hdr->tpdu_DTseqX = seq;
41836399Ssklower hdr->tpdu_DTeotX = eot;
41960359Sbostic #endif /* BYTE_ORDER */
42036399Ssklower } else if (tpcb->tp_class == TP_CLASS_0) {
42136399Ssklower IFDEBUG(D_EMIT)
42236399Ssklower printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
42336399Ssklower dump_buf( hdr, hdr->tpdu_li + 1 );
42436399Ssklower ENDDEBUG
42536399Ssklower ((struct tp0du *)hdr)->tp0du_eot = eot;
42636399Ssklower ((struct tp0du *)hdr)->tp0du_mbz = 0;
42736399Ssklower IFDEBUG(D_EMIT)
42836399Ssklower printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
42936399Ssklower dump_buf( hdr, hdr->tpdu_li + 1 );
43036399Ssklower ENDDEBUG
43136399Ssklower } else {
43236399Ssklower hdr->tpdu_DTseq = seq;
43336399Ssklower hdr->tpdu_DTeot = eot;
43436399Ssklower }
43536399Ssklower if(eot) {
43636399Ssklower IncStat(ts_EOT_sent);
43736399Ssklower }
43836399Ssklower IncStat(ts_DT_sent);
43936399Ssklower IncPStat(tpcb, tps_DT_sent);
44036399Ssklower break;
44136399Ssklower
44236399Ssklower case AK_TPDU_type:/* ak not used in class 0 */
44336399Ssklower ASSERT( tpcb->tp_class != TP_CLASS_0);
44436399Ssklower data = (struct mbuf *)0;
44551204Ssklower olduwe = tpcb->tp_sent_uwe;
44636399Ssklower
44751204Ssklower if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
44851204Ssklower LOCAL_CREDIT( tpcb );
44936399Ssklower tpcb->tp_sent_uwe =
45036399Ssklower SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
45136399Ssklower tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
45251204Ssklower acking_ooo = 0;
45351204Ssklower } else
45451204Ssklower acking_ooo = 1;
45536399Ssklower
45651204Ssklower IFDEBUG(D_RENEG)
45751204Ssklower /* occasionally fake a reneging so
45851204Ssklower you can test subsequencing */
45951204Ssklower if( olduwe & 0x1 ) {
46036399Ssklower tpcb->tp_reneged = 1;
46151204Ssklower IncStat(ts_ldebug);
46236399Ssklower }
46351204Ssklower ENDDEBUG
46451204Ssklower /* Are we about to reneg on credit?
46551204Ssklower * When might we do so?
46651204Ssklower * a) when using optimistic credit (which we no longer do).
46751204Ssklower * b) when drain() gets implemented (not in the plans).
46851204Ssklower * c) when D_RENEG is on.
46951204Ssklower * d) when DEC BIT response is implemented.
47051204Ssklower * (not- when we do this, we'll need to implement flow control
47151204Ssklower * confirmation)
47251204Ssklower */
47351204Ssklower if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
47451204Ssklower tpcb->tp_reneged = 1;
47551204Ssklower IncStat(ts_lcdt_reduced);
47651204Ssklower IFTRACE(D_CREDIT)
47751204Ssklower tptraceTPCB(TPPTmisc,
47851204Ssklower "RENEG: olduwe newuwe lcredit rcvnxt",
47951204Ssklower olduwe,
48051204Ssklower tpcb->tp_sent_uwe, tpcb->tp_lcredit,
48151204Ssklower tpcb->tp_rcvnxt);
48251204Ssklower ENDTRACE
48351204Ssklower }
48451204Ssklower IFPERF(tpcb)
48551204Ssklower /* new lwe is less than old uwe means we're
48651204Ssklower * acking before we received a whole window full
48751204Ssklower */
48851204Ssklower if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
48951204Ssklower /* tmp1 = number of pkts fewer than the full window */
49051204Ssklower register int tmp1 =
49151204Ssklower (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
49236399Ssklower
49351204Ssklower if(tmp1 > TP_PM_MAX)
49451204Ssklower tmp1 = TP_PM_MAX;
49551204Ssklower IncPStat( tpcb, tps_ack_early[tmp1] );
49636399Ssklower
49751204Ssklower /* tmp1 = amt of new cdt we're advertising */
49851204Ssklower tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
49951204Ssklower if(tmp1 > TP_PM_MAX )
50051204Ssklower tmp1 = TP_PM_MAX;
50136399Ssklower
50251204Ssklower IncPStat( tpcb,
50351204Ssklower tps_cdt_acked [ tmp1 ]
50451204Ssklower [ ((tpcb->tp_lcredit > TP_PM_MAX)?
50551204Ssklower TP_PM_MAX:tpcb->tp_lcredit) ] );
50636399Ssklower
50751204Ssklower }
50851204Ssklower ENDPERF
50936399Ssklower
51036399Ssklower IFTRACE(D_ACKSEND)
51136399Ssklower tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
51236399Ssklower tpcb->tp_r_subseq, 0);
51336399Ssklower ENDTRACE
51436399Ssklower if (tpcb->tp_xtd_format) {
51536399Ssklower #ifdef BYTE_ORDER
51648747Ssklower union seq_type seqeotX;
51748747Ssklower
51848747Ssklower seqeotX.s_seq = seq;
51948747Ssklower seqeotX.s_eot = 0;
52048747Ssklower hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
52136399Ssklower hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
52236399Ssklower #else
52336399Ssklower hdr->tpdu_cdt = 0;
52436399Ssklower hdr->tpdu_AKseqX = seq;
52536399Ssklower hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
52660359Sbostic #endif /* BYTE_ORDER */
52736399Ssklower } else {
52836399Ssklower hdr->tpdu_AKseq = seq;
52936399Ssklower hdr->tpdu_AKcdt = tpcb->tp_lcredit;
53036399Ssklower }
53151204Ssklower if ((tpcb->tp_class == TP_CLASS_4) &&
53251204Ssklower (tpcb->tp_reneged || acking_ooo)) {
53336399Ssklower /*
53436399Ssklower * Ack subsequence parameter req'd if WE reneged on
53536399Ssklower * credit offered. (ISO 8073, 12.2.3.8.2, p. 74)
53636399Ssklower */
53736399Ssklower IFDEBUG(D_RENEG)
53836399Ssklower printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
53936399Ssklower ENDDEBUG
54036399Ssklower tpcb->tp_s_subseq++;
54136399Ssklower /*
54236399Ssklower * add tmp subseq and do a htons on it.
54336399Ssklower */
54436399Ssklower ADDOPTION(TPP_subseq, hdr,
54536399Ssklower sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
54636399Ssklower } else
54736399Ssklower tpcb->tp_s_subseq = 0;
54836399Ssklower
54936399Ssklower if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
55036399Ssklower /*
55136399Ssklower * Rules for sending FCC ("should" send when) :
55236399Ssklower * %a) received an ack from peer with NO NEWS whatsoever,
55336399Ssklower * and it did not contain an FCC
55436399Ssklower * b) received an ack from peer that opens its closed window.
55536399Ssklower * c) received an ack from peer after it reneged on its
55636399Ssklower * offered credit, AND this ack raises UWE but LWE is same
55736399Ssklower * and below UWE at time of reneging (reduction)
55836399Ssklower * Now, ISO 8073 12.2.3.8.3 says
55936399Ssklower * that a retransmitted AK shall not contain the FCC
56036399Ssklower * parameter. Now, how the hell you tell the difference
56136399Ssklower * between a retransmitted ack and an ack that's sent in
56236399Ssklower * response to a received ack, I don't know, because without
56336399Ssklower * any local activity, and w/o any received DTs, they
56436399Ssklower * will contain exactly the same credit/seq# information.
56536399Ssklower * Anyway, given that the "retransmission of acks"
56636399Ssklower * procedure (ISO 8073 12.2.3.8.3) is optional, and we
56736399Ssklower * don't do it (although the peer can't tell that), we
56836399Ssklower * ignore this last rule.
56936399Ssklower *
57036399Ssklower * We send FCC for reasons a) and b) only.
57136399Ssklower * To add reason c) would require a ridiculous amount of state.
57236399Ssklower *
57336399Ssklower */
57436399Ssklower u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */
57536399Ssklower SeqNum lwe;
57636399Ssklower u_short subseq, fcredit;
57736399Ssklower
57836399Ssklower tpcb->tp_sendfcc = 0;
57936399Ssklower
58036399Ssklower lwe = (SeqNum) htonl(tpcb->tp_snduna);
58136399Ssklower subseq = htons(tpcb->tp_r_subseq);
58236399Ssklower fcredit = htons(tpcb->tp_fcredit);
58336399Ssklower
58437469Ssklower bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
58537469Ssklower bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
58637469Ssklower bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
58736399Ssklower
58836399Ssklower IFTRACE(D_ACKSEND)
58936399Ssklower tptraceTPCB(TPPTmisc,
59036399Ssklower "emit w/FCC: snduna r_subseq fcredit",
59136399Ssklower tpcb->tp_snduna, tpcb->tp_r_subseq,
59236399Ssklower tpcb->tp_fcredit, 0);
59336399Ssklower ENDTRACE
59436399Ssklower
59536399Ssklower IFDEBUG(D_ACKSEND)
59636399Ssklower printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
59736399Ssklower TPP_flow_cntl_conf,
59836399Ssklower hdr, sizeof(bogus), bogus[0]);
59936399Ssklower ENDDEBUG
60036399Ssklower ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
60136399Ssklower IFDEBUG(D_ACKSEND)
60236399Ssklower printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
60336399Ssklower hdr, hdr->tpdu_li);
60436399Ssklower printf(
60536399Ssklower "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
60636399Ssklower csum_offset, hdr->tpdu_li);
60736399Ssklower ENDDEBUG
60836399Ssklower
60936399Ssklower }
61036399Ssklower tpcb->tp_reneged = 0;
61136399Ssklower tpcb->tp_sent_rcvnxt = seq;
61251204Ssklower if (tpcb->tp_fcredit == 0) {
61351204Ssklower int timo = tpcb->tp_keepalive_ticks;
61451204Ssklower if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
61551204Ssklower tpcb->tp_rxtshift++;
61651204Ssklower timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
61751204Ssklower tp_ctimeout(tpcb, TM_sendack, timo);
61851204Ssklower } else
61951204Ssklower tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
62036399Ssklower IncStat(ts_AK_sent);
62136399Ssklower IncPStat(tpcb, tps_AK_sent);
62236399Ssklower IFDEBUG(D_ACKSEND)
62336399Ssklower printf(
62436399Ssklower "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
62536399Ssklower csum_offset, hdr->tpdu_li);
62636399Ssklower ENDDEBUG
62736399Ssklower break;
62836399Ssklower
62936399Ssklower case ER_TPDU_type:
63036399Ssklower hdr->tpdu_ERreason = eot;
63136399Ssklower hdr->tpdu_cdt = 0;
63236399Ssklower /* no user data */
63336399Ssklower data = (struct mbuf *)0;
63436399Ssklower IncStat(ts_ER_sent);
63536399Ssklower break;
63636399Ssklower }
63736399Ssklower
63836399Ssklower }
63936399Ssklower ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
64036399Ssklower
64136399Ssklower m->m_next = data;
64236399Ssklower
64337469Ssklower ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
64436399Ssklower ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
64536399Ssklower
64636399Ssklower m->m_len = hdr->tpdu_li ;
64736399Ssklower hdr->tpdu_li --; /* doesn't include the li field */
64836399Ssklower
64936399Ssklower datalen = m_datalen( m ); /* total len */
65036399Ssklower
65136399Ssklower ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
65236399Ssklower when CLNP is used; leave in here for the time being */
65336399Ssklower IFDEBUG(D_ACKSEND)
65436399Ssklower printf(
65536399Ssklower "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
65636399Ssklower csum_offset, hdr->tpdu_li);
65736399Ssklower ENDDEBUG
65836399Ssklower if( datalen > tpcb->tp_l_tpdusize ) {
65936399Ssklower printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
66036399Ssklower datalen, tpcb->tp_l_tpdusize);
66136399Ssklower }
66236399Ssklower IFDEBUG(D_EMIT)
66336399Ssklower printf(
66436399Ssklower "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
66536399Ssklower m->m_len, csum_offset, datalen);
66636399Ssklower ENDDEBUG
66736399Ssklower if( tpcb->tp_use_checksum ||
66836399Ssklower (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
66936399Ssklower iso_gen_csum(m, csum_offset, datalen);
67036399Ssklower }
67136399Ssklower
67236399Ssklower IFDEBUG(D_EMIT)
67336399Ssklower printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
67436399Ssklower tpcb, dutype, datalen);
67537469Ssklower dump_buf(mtod(m, caddr_t), datalen);
67636399Ssklower ENDDEBUG
67736399Ssklower
67836399Ssklower IFPERF(tpcb)
67936399Ssklower if( dutype == DT_TPDU_type ) {
68036399Ssklower PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
68137469Ssklower tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0,
68236399Ssklower seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
68336399Ssklower }
68436399Ssklower ENDPERF
68536399Ssklower
68636399Ssklower IFTRACE(D_EMIT)
68736399Ssklower tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
68836399Ssklower ENDTRACE
68936399Ssklower IFDEBUG(D_EMIT)
69036399Ssklower printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
69136399Ssklower tpcb, tpcb->tp_npcb, tpcb->tp_sock);
69236399Ssklower ENDDEBUG
69336399Ssklower
69436399Ssklower { extern char tp_delay;
69536399Ssklower
69636399Ssklower if( tp_delay )
69736399Ssklower if( tpcb->tp_use_checksum == 0 ) {
69836399Ssklower register u_int i = tp_delay;
69936399Ssklower for (; i!= 0; i--)
70036399Ssklower (void) iso_check_csum(m, datalen);
70136399Ssklower }
70236399Ssklower }
70336399Ssklower ASSERT( m->m_len > 0 );
70436399Ssklower error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
70536399Ssklower !tpcb->tp_use_checksum);
70636399Ssklower IFDEBUG(D_EMIT)
70736399Ssklower printf("OUTPUT: returned 0x%x\n", error);
70836399Ssklower ENDDEBUG
70936399Ssklower IFTRACE(D_EMIT)
71036399Ssklower tptraceTPCB(TPPTmisc,
71136399Ssklower "tp_emit nlproto->output netservice returns datalen",
71236399Ssklower tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
71336399Ssklower ENDTRACE
71436399Ssklower done:
71551204Ssklower if (error) {
71651204Ssklower if (dutype == AK_TPDU_type)
71751204Ssklower tp_ctimeout(tpcb, TM_sendack, 1);
71851204Ssklower if (error == E_CO_QFULL) {
71951204Ssklower tp_quench(tpcb, PRC_QUENCH);
72051204Ssklower return 0;
72151204Ssklower }
72236399Ssklower }
72336399Ssklower return error;
72436399Ssklower }
72536399Ssklower /*
72636399Ssklower * NAME: tp_error_emit()
72736399Ssklower * CALLED FROM: tp_input() when a DR or ER is to be issued in
72836399Ssklower * response to an input error.
72936399Ssklower * FUNCTION and ARGUMENTS:
73036399Ssklower * The error type is the first argument.
73136399Ssklower * The argument (sref) is the source reference on the bad incoming tpdu,
73236399Ssklower * and is used for a destination reference on the outgoing packet.
73336399Ssklower * (faddr) and (laddr) are the foreign and local addresses for this
73436399Ssklower * connection.
73536399Ssklower * (erdata) is a ptr to the errant incoming tpdu, and is copied into the
73636399Ssklower * outgoing ER, if an ER is to be issued.
73736399Ssklower * (erlen) is the number of octets of the errant tpdu that we should
73836399Ssklower * try to copy.
73936399Ssklower * (tpcb) is the pcb that describes the connection for which the bad tpdu
74036399Ssklower * arrived.
74136399Ssklower * RETURN VALUES:
74236399Ssklower * 0 OK
74336399Ssklower * ENOBUFS
74436399Ssklower * E* from net layer datagram output routine
74536399Ssklower * SIDE EFFECTS:
74636399Ssklower *
74736399Ssklower * NOTES:
74836399Ssklower */
74936399Ssklower
75036399Ssklower int
tp_error_emit(error,sref,faddr,laddr,erdata,erlen,tpcb,cons_channel,dgout_routine)75136399Ssklower tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
75236399Ssklower dgout_routine)
75336399Ssklower int error;
75436399Ssklower u_long sref;
75536399Ssklower struct sockaddr_iso *faddr, *laddr;
75636399Ssklower struct mbuf *erdata;
75736399Ssklower int erlen;
75836399Ssklower struct tp_pcb *tpcb;
75950535Ssklower caddr_t cons_channel;
76036399Ssklower int (*dgout_routine)();
76136399Ssklower {
76236399Ssklower int dutype;
76336399Ssklower int datalen = 0;
76436399Ssklower register struct tpdu *hdr;
76536399Ssklower register struct mbuf *m;
76636399Ssklower int csum_offset;
76736399Ssklower
76836399Ssklower IFTRACE(D_ERROR_EMIT)
76936399Ssklower tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
77036399Ssklower error, sref, tpcb, erlen);
77136399Ssklower ENDTRACE
77236399Ssklower IFDEBUG(D_ERROR_EMIT)
77336399Ssklower printf(
77436399Ssklower "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
77536399Ssklower error, sref, tpcb, erlen, cons_channel);
77636399Ssklower ENDDEBUG
77736399Ssklower
77836399Ssklower MGET(m, M_DONTWAIT, TPMT_TPHDR);
77936399Ssklower if (m == NULL) {
78036399Ssklower return ENOBUFS;
78136399Ssklower }
78236399Ssklower m->m_len = sizeof(struct tpdu);
78336399Ssklower m->m_act = MNULL;
78436399Ssklower
78536399Ssklower hdr = mtod(m, struct tpdu *);
78636399Ssklower
78736399Ssklower IFDEBUG(D_ERROR_EMIT)
78836399Ssklower printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
78936399Ssklower error, error&0xff, (char)error);
79036399Ssklower ENDDEBUG
79136399Ssklower
79236399Ssklower
79342494Ssklower if (error & TP_ERROR_SNDC)
79442494Ssklower dutype = DC_TPDU_type;
79542494Ssklower else if (error & 0x40) {
79636399Ssklower error &= ~0x40;
79736399Ssklower dutype = ER_TPDU_type;
79836399Ssklower } else
79936399Ssklower dutype = DR_TPDU_type;
80042494Ssklower error &= 0xff;
80136399Ssklower
80236399Ssklower hdr->tpdu_type = dutype;
80336399Ssklower hdr->tpdu_cdt = 0;
80436399Ssklower
80536399Ssklower switch( dutype ) {
80636399Ssklower
80742494Ssklower case DC_TPDU_type:
80842494Ssklower IncStat(ts_DC_sent);
80942494Ssklower hdr->tpdu_li = 6;
81042494Ssklower hdr->tpdu_DCdref = htons(sref);
81142494Ssklower hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
81242494Ssklower IFDEBUG(D_ERROR_EMIT)
81342494Ssklower printf("DC case:\n");
81442494Ssklower dump_buf( hdr, 6);
81542494Ssklower ENDDEBUG
81642494Ssklower /* forget the add'l information variable part */
81742494Ssklower break;
81842494Ssklower
81936399Ssklower case DR_TPDU_type:
82036399Ssklower IncStat(ts_DR_sent);
82136399Ssklower hdr->tpdu_li = 7;
82236399Ssklower hdr->tpdu_DRdref = htons(sref);
82342494Ssklower hdr->tpdu_DRsref = 0;
82436399Ssklower hdr->tpdu_DRreason = (char)error;
82536399Ssklower IFDEBUG(D_ERROR_EMIT)
82636399Ssklower printf("DR case:\n");
82736399Ssklower dump_buf( hdr, 7);
82836399Ssklower ENDDEBUG
82936399Ssklower /* forget the add'l information variable part */
83036399Ssklower break;
83136399Ssklower
83236399Ssklower case ER_TPDU_type:
83336399Ssklower IncStat(ts_ER_sent);
83436399Ssklower hdr->tpdu_li = 5;
83536399Ssklower hdr->tpdu_ERreason = (char)error;
83650535Ssklower hdr->tpdu_ERdref = htons(sref);
83736399Ssklower break;
83836399Ssklower
83936399Ssklower default:
84036399Ssklower ASSERT(0);
84136399Ssklower printf("TP PANIC: bad dutype 0x%x\n", dutype);
84236399Ssklower }
84336399Ssklower
84436399Ssklower if(tpcb)
84536399Ssklower if( tpcb->tp_use_checksum ) {
84636399Ssklower ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
84736399Ssklower csum_offset = hdr->tpdu_li - 2;
84836399Ssklower }
84936399Ssklower
85037469Ssklower ASSERT( hdr->tpdu_li < MLEN );
85136399Ssklower
85236399Ssklower if (dutype == ER_TPDU_type) {
85336399Ssklower /* copy the errant tpdu into another 'variable part' */
85436399Ssklower register caddr_t P;
85536399Ssklower
85636399Ssklower IFTRACE(D_ERROR_EMIT)
85736399Ssklower tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
85836399Ssklower 0,0);
85936399Ssklower ENDTRACE
86036399Ssklower IFDEBUG(D_ERROR_EMIT)
86136399Ssklower printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
86236399Ssklower ENDDEBUG
86336399Ssklower
86436399Ssklower /* copy at most as many octets for which you have room */
86536399Ssklower if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
86636399Ssklower erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
86736399Ssklower
86836399Ssklower /* add the "invalid tpdu" parameter : required in class 0 */
86936399Ssklower P = (caddr_t)hdr + (int)(hdr->tpdu_li);
87036399Ssklower vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */
87136399Ssklower vbptr(P)->tpv_len = erlen; /* parameter length */
87236399Ssklower m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
87336399Ssklower
87436399Ssklower /* tp_input very likely handed us an mbuf chain w/ nothing in
87536399Ssklower * the first mbuf and the data following the empty mbuf
87636399Ssklower */
87736399Ssklower if(erdata->m_len == 0) {
87836399Ssklower erdata = m_free(erdata); /* returns the next mbuf on the chain */
87936399Ssklower }
88037469Ssklower /*
88137469Ssklower * copy only up to the bad octet
88237469Ssklower * (or max that will fit in a header
88337469Ssklower */
88437469Ssklower m->m_next = m_copy(erdata, 0, erlen);
88536399Ssklower hdr->tpdu_li += erlen + 2;
88636399Ssklower m_freem(erdata);
88736399Ssklower } else {
88836399Ssklower IFDEBUG(D_ERROR_EMIT)
88936399Ssklower printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
89036399Ssklower dump_buf( (char *)hdr, hdr->tpdu_li );
89136399Ssklower ENDDEBUG
89236399Ssklower m->m_len = hdr->tpdu_li ;
89336399Ssklower m_freem(erdata);
89436399Ssklower }
89536399Ssklower
89636399Ssklower hdr->tpdu_li --;
89736399Ssklower IFTRACE(D_ERROR_EMIT)
89836399Ssklower tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
89936399Ssklower ENDTRACE
90036399Ssklower
90136399Ssklower datalen = m_datalen( m);
90250648Ssklower if (tpcb) {
90336399Ssklower if( tpcb->tp_use_checksum ) {
90436399Ssklower IFTRACE(D_ERROR_EMIT)
90536399Ssklower tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
90636399Ssklower ENDTRACE
90736399Ssklower IFDEBUG(D_ERROR_EMIT)
90836399Ssklower printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
90936399Ssklower datalen, csum_offset);
91036399Ssklower ENDDEBUG
91136399Ssklower
91236399Ssklower iso_gen_csum(m, csum_offset, datalen);
91336399Ssklower }
91436399Ssklower
91536399Ssklower IFDEBUG(D_ERROR_EMIT)
91636399Ssklower printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
91736399Ssklower tpcb, tpcb->tp_npcb, tpcb->tp_sock);
91836399Ssklower ENDDEBUG
91950648Ssklower }
92050648Ssklower if (cons_channel) {
92150648Ssklower #ifdef TPCONS
92250648Ssklower struct pklcd *lcp = (struct pklcd *)cons_channel;
92350648Ssklower struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
92436399Ssklower
92550648Ssklower tpcons_dg_output(cons_channel, m, datalen);
92650648Ssklower /* was if (tpcb == 0) iso_pcbdetach(isop); */
92750648Ssklower /* but other side may want to try again over same VC,
92850648Ssklower so, we'll depend on him closing it, but in case it gets forgotten
92950648Ssklower we'll mark it for garbage collection */
93050648Ssklower lcp->lcd_flags |= X25_DG_CIRCUIT;
93136399Ssklower IFDEBUG(D_ERROR_EMIT)
93250648Ssklower printf("OUTPUT: dutype 0x%x channel 0x%x\n",
93350648Ssklower dutype, cons_channel);
93450648Ssklower ENDDEBUG
93550648Ssklower #else
93650648Ssklower printf("TP panic! cons channel 0x%x but not cons configured\n",
93750648Ssklower cons_channel);
93850648Ssklower #endif
93950648Ssklower } else if (tpcb) {
94050648Ssklower
94150648Ssklower IFDEBUG(D_ERROR_EMIT)
94236399Ssklower printf("tp_error_emit 1 sending DG: Laddr\n");
94337469Ssklower dump_addr((struct sockaddr *)laddr);
94436399Ssklower printf("Faddr\n");
94537469Ssklower dump_addr((struct sockaddr *)faddr);
94636399Ssklower ENDDEBUG
94736399Ssklower return (tpcb->tp_nlproto->nlp_dgoutput)(
94836399Ssklower &laddr->siso_addr,
94936399Ssklower &faddr->siso_addr,
95036399Ssklower m, datalen,
95136399Ssklower /* no route */ (caddr_t)0, !tpcb->tp_use_checksum);
95250648Ssklower } else if (dgout_routine) {
95336399Ssklower IFDEBUG(D_ERROR_EMIT)
95436399Ssklower printf("tp_error_emit sending DG: Laddr\n");
95537469Ssklower dump_addr((struct sockaddr *)laddr);
95636399Ssklower printf("Faddr\n");
95737469Ssklower dump_addr((struct sockaddr *)faddr);
95836399Ssklower ENDDEBUG
95950648Ssklower return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
96050648Ssklower m, datalen, /* no route */
96150648Ssklower (caddr_t)0, /* nochecksum==false */0);
96250648Ssklower } else {
96336399Ssklower IFDEBUG(D_ERROR_EMIT)
96436399Ssklower printf("tp_error_emit DROPPING \n", m);
96536399Ssklower ENDDEBUG
96636399Ssklower IncStat(ts_send_drop);
96736399Ssklower m_freem(m);
96836399Ssklower return 0;
96936399Ssklower }
97036399Ssklower }
971