get rid of useless tp_param global structure.
[unix-history] / usr / src / sys / netiso / tp_emit.c
index ea17757..8bee83e 100644 (file)
@@ -1,3 +1,12 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)tp_emit.c   7.12 (Berkeley) %G%
+ */
+
 /***********************************************************
                Copyright IBM Corporation 1987
 
 /***********************************************************
                Copyright IBM Corporation 1987
 
@@ -44,12 +53,6 @@ SOFTWARE.
  * basic mechanism of separation under the 'w' tpdebug option, that's all.)
  */
 
  * basic mechanism of separation under the 'w' tpdebug option, that's all.)
  */
 
-#ifndef lint
-static char *rcsid = "$Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $";
-#endif lint
-
-
-#include "argoxtwentyfive.h"
 #include "param.h"
 #include "mbuf.h"
 #include "socket.h"
 #include "param.h"
 #include "mbuf.h"
 #include "socket.h"
@@ -58,17 +61,27 @@ static char *rcsid = "$Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $";
 #include "errno.h"
 #include "types.h"
 #include "time.h"
 #include "errno.h"
 #include "types.h"
 #include "time.h"
-#include "../netiso/iso.h"
-#include "../netiso/argo_debug.h"
-#include "../netiso/tp_timer.h"
-#include "../netiso/tp_param.h"
-#include "../netiso/tp_stat.h"
-#include "../netiso/tp_pcb.h"
-#include "../netiso/tp_tpdu.h"
-#include "../netiso/tp_trace.h"
-#include "../netiso/tp_meas.h"
-#include "../netiso/tp_seq.h"
-#include "../netiso/iso_errno.h"
+#include "iso.h"
+#include "iso_pcb.h"
+#include "argo_debug.h"
+#include "tp_timer.h"
+#include "tp_param.h"
+#include "tp_stat.h"
+#include "tp_pcb.h"
+#include "tp_tpdu.h"
+#include "tp_trace.h"
+#include "tp_meas.h"
+#include "tp_seq.h"
+#include "iso_errno.h"
+
+#include "../net/if.h"
+#ifdef TRUE
+#undef FALSE
+#undef TRUE
+#endif
+#include "../netccitt/x25.h"
+#include "../netccitt/pk.h"
+#include "../netccitt/pk_var.h"
 
 void iso_gen_csum();
 
 
 void iso_gen_csum();
 
@@ -135,6 +148,8 @@ tp_emit(dutype,     tpcb, seq, eot, data)
        int csum_offset=0;
        int datalen = 0;
        int error = 0;
        int csum_offset=0;
        int datalen = 0;
        int error = 0;
+       SeqNum olduwe;
+       int acking_ooo;
 
        /* NOTE:
         * here we treat tpdu_li as if it DID include the li field, up until
 
        /* NOTE:
         * here we treat tpdu_li as if it DID include the li field, up until
@@ -144,11 +159,24 @@ tp_emit(dutype,   tpcb, seq, eot, data)
         */
        IFDEBUG(D_EMIT)
                printf(
         */
        IFDEBUG(D_EMIT)
                printf(
-       "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x mfree 0x%x",
-               dutype, tpcb, eot, seq, data, mfree);
+       "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
+               dutype, tpcb, eot, seq, data);
        ENDDEBUG
 
        ENDDEBUG
 
-       MGET(m, M_DONTWAIT, TPMT_TPHDR); 
+       if (dutype == CR_TPDU || dutype == CC_TPDU) {
+               m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
+               if (m) {
+                       m->m_type = TPMT_TPHDR;
+                       mbstat.m_mtypes[TPMT_TPHDR]++;
+                       m->m_next = MNULL;
+                       m->m_nextpkt = MNULL;
+                       m->m_data = m->m_pktdat;
+                       m->m_flags = M_PKTHDR;
+               }
+       } else {
+               MGETHDR(m, M_DONTWAIT, TPMT_TPHDR); 
+       }
+       m->m_data += max_hdr;
        if (m == NULL) {
                if(data != (struct mbuf *)0)
                        m_freem(data);
        if (m == NULL) {
                if(data != (struct mbuf *)0)
                        m_freem(data);
@@ -159,7 +187,7 @@ tp_emit(dutype,     tpcb, seq, eot, data)
        m->m_act = MNULL;
 
        hdr = mtod(m, struct tpdu *);
        m->m_act = MNULL;
 
        hdr = mtod(m, struct tpdu *);
-       bzero(hdr, sizeof(struct tpdu));
+       bzero((caddr_t)hdr, sizeof(struct tpdu));
 
        {
                int     tp_headersize();
 
        {
                int     tp_headersize();
@@ -187,7 +215,14 @@ tp_emit(dutype,    tpcb, seq, eot, data)
                switch( dutype ) {
 
                case CR_TPDU_type:
                switch( dutype ) {
 
                case CR_TPDU_type:
-                       hdr->tpdu_CRdref_0 = htons(0);  /* must be zero */
+                       hdr->tpdu_CRdref_0 = 0; /* must be zero */
+                       if (!tpcb->tp_cebit_off) {
+                               tpcb->tp_win_recv = tp_start_win << 8;
+                               LOCAL_CREDIT(tpcb);
+                               CONG_INIT_SAMPLE(tpcb);
+                       } else
+                               LOCAL_CREDIT(tpcb);
+
 
                case CC_TPDU_type: 
                                {
 
                case CC_TPDU_type: 
                                {
@@ -196,12 +231,21 @@ tp_emit(dutype,   tpcb, seq, eot, data)
                                hdr->tpdu_CCsref =  htons(tpcb->tp_lref); /* same as CRsref */
 
                                if( tpcb->tp_class > TP_CLASS_1 ) {
                                hdr->tpdu_CCsref =  htons(tpcb->tp_lref); /* same as CRsref */
 
                                if( tpcb->tp_class > TP_CLASS_1 ) {
-                                       LOCAL_CREDIT( tpcb ); 
+/* ifdef CE_BIT, we did this in tp_input when the CR came in */
+                                       if (tpcb->tp_cebit_off)
+                                               LOCAL_CREDIT( tpcb );
                                        tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
                                        tpcb->tp_sent_rcvnxt = 1;
                                        tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
                                        hdr->tpdu_cdt = tpcb->tp_lcredit;
                                } else {
                                        tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
                                        tpcb->tp_sent_rcvnxt = 1;
                                        tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
                                        hdr->tpdu_cdt = tpcb->tp_lcredit;
                                } else {
+#ifdef TPCONS
+                                       if (tpcb->tp_netservice == ISO_CONS) {
+                                               struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
+                                               struct pklcd *lcp = (struct pklcd *)(isop->isop_chan);
+                                               lcp->lcd_flags &= ~X25_DG_CIRCUIT;
+                                       }
+#endif
                                        hdr->tpdu_cdt = 0;
                                }
                                hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
                                        hdr->tpdu_cdt = 0;
                                }
                                hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
@@ -221,9 +265,9 @@ tp_emit(dutype,     tpcb, seq, eot, data)
                                        ASSERT( tpcb->tp_fsuffixlen > 0 );
 
                                        ADDOPTION(TPP_calling_sufx, hdr,
                                        ASSERT( tpcb->tp_fsuffixlen > 0 );
 
                                        ADDOPTION(TPP_calling_sufx, hdr,
-                                               tpcb->tp_lsuffixlen, tpcb->tp_lsuffix);
+                                               tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
                                        ADDOPTION(TPP_called_sufx, hdr,
                                        ADDOPTION(TPP_called_sufx, hdr,
-                                               tpcb->tp_fsuffixlen, tpcb->tp_fsuffix);
+                                               tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
                                } else {
                                        IncStat(ts_CC_sent);
                                }
                                } else {
                                        IncStat(ts_CC_sent);
                                }
@@ -300,7 +344,11 @@ tp_emit(dutype,    tpcb, seq, eot, data)
                        data = (struct mbuf *)0;
                        if (tpcb->tp_xtd_format) {
 #ifdef BYTE_ORDER
                        data = (struct mbuf *)0;
                        if (tpcb->tp_xtd_format) {
 #ifdef BYTE_ORDER
-                               hdr->tpdu_XAKseqX = htonl(seq);
+                               union seq_type seqeotX;
+
+                               seqeotX.s_seq = seq;
+                               seqeotX.s_eot = 1;
+                               hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
 #else
                                hdr->tpdu_XAKseqX = seq;
 #endif BYTE_ORDER
 #else
                                hdr->tpdu_XAKseqX = seq;
 #endif BYTE_ORDER
@@ -334,10 +382,10 @@ tp_emit(dutype,   tpcb, seq, eot, data)
 
                        /* kludge to test the input size checking */
                        IFDEBUG(D_SIZE_CHECK)
 
                        /* kludge to test the input size checking */
                        IFDEBUG(D_SIZE_CHECK)
-                               if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
+                               /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
                                        printf("Sending too much data on XPD: 18 bytes\n");
                                        data->m_len = 18;
                                        printf("Sending too much data on XPD: 18 bytes\n");
                                        data->m_len = 18;
-                               }
+                               }*/
                        ENDDEBUG
                        break;
 
                        ENDDEBUG
                        break;
 
@@ -383,76 +431,82 @@ tp_emit(dutype,   tpcb, seq, eot, data)
                case AK_TPDU_type:/* ak not used in class 0 */
                        ASSERT( tpcb->tp_class != TP_CLASS_0); 
                        data = (struct mbuf *)0;
                case AK_TPDU_type:/* ak not used in class 0 */
                        ASSERT( tpcb->tp_class != TP_CLASS_0); 
                        data = (struct mbuf *)0;
-                       {       SeqNum olduwe = tpcb->tp_sent_uwe;
+                       olduwe = tpcb->tp_sent_uwe;
 
 
+                       if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
+                               LOCAL_CREDIT( tpcb ); 
                                tpcb->tp_sent_uwe = 
                                        SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
                                tpcb->tp_sent_uwe = 
                                        SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
-                               LOCAL_CREDIT( tpcb ); 
                                tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
                                tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
+                               acking_ooo = 0;
+                       } else
+                               acking_ooo = 1;
 
 
-                               IFDEBUG(D_RENEG)
-                                       /* occasionally fake a reneging so 
-                                               you can test subsequencing */
-                                       if( olduwe & 0x1 ) {
-                                               tpcb->tp_reneged = 1;
-                                               IncStat(ts_ldebug);
-                                       }
-                               ENDDEBUG
-                               /* Are we about to reneg on credit? 
-                                * When might we do so?
-                                *      a) when using optimistic credit (which we no longer do).
-                                *  b) when drain() gets implemented (not in the plans).
-                                *  c) when D_RENEG is on.
-                                *  d) when DEC BIT response (PRC_QUENCH2) is implemented.
-                                *      (not- when we do this, we'll need to implement flow control
-                                *      confirmation)
-                                */
-                               if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
+                       IFDEBUG(D_RENEG)
+                               /* occasionally fake a reneging so 
+                                       you can test subsequencing */
+                               if( olduwe & 0x1 ) {
                                        tpcb->tp_reneged = 1;
                                        tpcb->tp_reneged = 1;
-                                       IncStat(ts_lcdt_reduced);
-                                       IFTRACE(D_CREDIT)
-                                               tptraceTPCB(TPPTmisc, 
-                                                       "RENEG: olduwe newuwe lcredit rcvnxt",
-                                                       olduwe,
-                                                       tpcb->tp_sent_uwe, tpcb->tp_lcredit,
-                                                       tpcb->tp_rcvnxt);
-                                       ENDTRACE
+                                       IncStat(ts_ldebug);
                                }
                                }
+                       ENDDEBUG
+                       /* Are we about to reneg on credit? 
+                        * When might we do so?
+                        *      a) when using optimistic credit (which we no longer do).
+                        *  b) when drain() gets implemented (not in the plans).
+                        *  c) when D_RENEG is on.
+                        *  d) when DEC BIT response is implemented.
+                        *      (not- when we do this, we'll need to implement flow control
+                        *      confirmation)
+                        */
+                       if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
+                               tpcb->tp_reneged = 1;
+                               IncStat(ts_lcdt_reduced);
+                               IFTRACE(D_CREDIT)
+                                       tptraceTPCB(TPPTmisc, 
+                                               "RENEG: olduwe newuwe lcredit rcvnxt",
+                                               olduwe,
+                                               tpcb->tp_sent_uwe, tpcb->tp_lcredit,
+                                               tpcb->tp_rcvnxt);
+                               ENDTRACE
+                       }
+                       IFPERF(tpcb)
+                               /* new lwe is less than old uwe means we're
+                                * acking before we received a whole window full
+                                */
+                               if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
+                                       /* tmp1 = number of pkts fewer than the full window */
+                                       register int tmp1 = 
+                                               (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
 
 
-                               IFPERF(tpcb)
-                                       /* new lwe is less than old uwe means we're
-                                        * acking before we received a whole window full
-                                        */
-                                       if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
-                                               /* tmp1 = number of pkts fewer than the full window */
-                                               register int tmp1 = 
-                                                       (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
+                                       if(tmp1 > TP_PM_MAX)
+                                               tmp1 = TP_PM_MAX;
+                                       IncPStat( tpcb,  tps_ack_early[tmp1] );
 
 
-                                               if(tmp1 > TP_PM_MAX)
-                                                       tmp1 = TP_PM_MAX;
-                                               IncPStat( tpcb,  tps_ack_early[tmp1] );
+                                       /* tmp1 = amt of new cdt we're advertising */
+                                       tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
+                                       if(tmp1 > TP_PM_MAX )
+                                               tmp1 = TP_PM_MAX;
 
 
-                                               /* tmp1 = amt of new cdt we're advertising */
-                                               tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
-                                               if(tmp1 > TP_PM_MAX )
-                                                       tmp1 = TP_PM_MAX;
+                                       IncPStat( tpcb, 
+                                                       tps_cdt_acked [ tmp1 ]
+                                                       [ ((tpcb->tp_lcredit > TP_PM_MAX)?
+                                                               TP_PM_MAX:tpcb->tp_lcredit) ] );
 
 
-                                               IncPStat( tpcb, 
-                                                               tps_cdt_acked [ tmp1 ]
-                                                               [ ((tpcb->tp_lcredit > TP_PM_MAX)?
-                                                                       TP_PM_MAX:tpcb->tp_lcredit) ] );
+                               }
+                       ENDPERF
 
 
-                                       }
-                               ENDPERF
-                       }
                        IFTRACE(D_ACKSEND)
                                tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, 
                                        tpcb->tp_r_subseq, 0);
                        ENDTRACE
                        if (tpcb->tp_xtd_format) {
 #ifdef BYTE_ORDER
                        IFTRACE(D_ACKSEND)
                                tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, 
                                        tpcb->tp_r_subseq, 0);
                        ENDTRACE
                        if (tpcb->tp_xtd_format) {
 #ifdef BYTE_ORDER
-                               hdr->tpdu_cdt = 0; 
-                               hdr->tpdu_AKseqX = htonl(seq);
+                               union seq_type seqeotX;
+
+                               seqeotX.s_seq = seq;
+                               seqeotX.s_eot = 0;
+                               hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
                                hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
 #else
                                hdr->tpdu_cdt = 0; 
                                hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
 #else
                                hdr->tpdu_cdt = 0; 
@@ -463,7 +517,8 @@ tp_emit(dutype,     tpcb, seq, eot, data)
                                hdr->tpdu_AKseq = seq;
                                hdr->tpdu_AKcdt = tpcb->tp_lcredit;
                        }
                                hdr->tpdu_AKseq = seq;
                                hdr->tpdu_AKcdt = tpcb->tp_lcredit;
                        }
-                       if ((tpcb->tp_class == TP_CLASS_4) && tpcb->tp_reneged ) {
+                       if ((tpcb->tp_class == TP_CLASS_4) &&
+                               (tpcb->tp_reneged || acking_ooo)) {
                                /* 
                                 * Ack subsequence parameter req'd if WE reneged on 
                                 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
                                /* 
                                 * Ack subsequence parameter req'd if WE reneged on 
                                 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
@@ -515,9 +570,9 @@ tp_emit(dutype,     tpcb, seq, eot, data)
                                subseq = htons(tpcb->tp_r_subseq);
                                fcredit = htons(tpcb->tp_fcredit);
 
                                subseq = htons(tpcb->tp_r_subseq);
                                fcredit = htons(tpcb->tp_fcredit);
 
-                               bcopy((caddr_t) &lwe, &bogus[0], sizeof(SeqNum));
-                               bcopy((caddr_t) &subseq, &bogus[2], sizeof(u_short));
-                               bcopy((caddr_t) &fcredit, &bogus[3], sizeof(u_short));
+                               bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
+                               bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
+                               bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
 
                                IFTRACE(D_ACKSEND)
                                        tptraceTPCB(TPPTmisc, 
 
                                IFTRACE(D_ACKSEND)
                                        tptraceTPCB(TPPTmisc, 
@@ -543,8 +598,14 @@ tp_emit(dutype,    tpcb, seq, eot, data)
                        }
                        tpcb->tp_reneged = 0;
                        tpcb->tp_sent_rcvnxt = seq;
                        }
                        tpcb->tp_reneged = 0;
                        tpcb->tp_sent_rcvnxt = seq;
-                       tp_ctimeout(tpcb->tp_refp, TM_sendack, 
-                               (int)tpcb->tp_keepalive_ticks);
+                       if (tpcb->tp_fcredit == 0) {
+                               int timo = tpcb->tp_keepalive_ticks;
+                               if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
+                                       tpcb->tp_rxtshift++;
+                               timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
+                               tp_ctimeout(tpcb, TM_sendack, timo);
+                       } else
+                               tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
                        IncStat(ts_AK_sent);
                        IncPStat(tpcb, tps_AK_sent);
                        IFDEBUG(D_ACKSEND)
                        IncStat(ts_AK_sent);
                        IncPStat(tpcb, tps_AK_sent);
                        IFDEBUG(D_ACKSEND)
@@ -568,7 +629,7 @@ tp_emit(dutype,     tpcb, seq, eot, data)
 
        m->m_next = data;
 
 
        m->m_next = data;
 
-       ASSERT( hdr->tpdu_li < MMAXOFF ); /* leave this in */
+       ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
        ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
 
        m->m_len = hdr->tpdu_li ; 
        ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
 
        m->m_len = hdr->tpdu_li ; 
@@ -600,13 +661,13 @@ tp_emit(dutype,   tpcb, seq, eot, data)
        IFDEBUG(D_EMIT)
        printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
                tpcb, dutype, datalen);
        IFDEBUG(D_EMIT)
        printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
                tpcb, dutype, datalen);
-               dump_buf( m, datalen+12);
+               dump_buf(mtod(m, caddr_t), datalen);
        ENDDEBUG
 
        IFPERF(tpcb)
                if( dutype == DT_TPDU_type ) {
                        PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
        ENDDEBUG
 
        IFPERF(tpcb)
                if( dutype == DT_TPDU_type ) {
                        PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
-                       tpmeas( tpcb->tp_lref, TPtime_to_ll,  0,
+                       tpmeas( tpcb->tp_lref, TPtime_to_ll,  (struct timeval *)0,
                                seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
                }
        ENDPERF
                                seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
                }
        ENDPERF
@@ -640,13 +701,16 @@ tp_emit(dutype,   tpcb, seq, eot, data)
                        tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); 
        ENDTRACE
 done:
                        tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); 
        ENDTRACE
 done:
-       if( error == E_CO_QFULL ) {
-               tp_quench( tpcb );
-               return 0;
+       if (error) {
+               if (dutype == AK_TPDU_type)
+                       tp_ctimeout(tpcb, TM_sendack, 1);
+               if (error == E_CO_QFULL) {
+                       tp_quench(tpcb, PRC_QUENCH);
+                       return 0;
+               }
        }
        return error;
 }
        }
        return error;
 }
-
 /*
  * NAME:               tp_error_emit()
  * CALLED FROM:        tp_input() when a DR or ER is to be issued in
 /*
  * NAME:               tp_error_emit()
  * CALLED FROM:        tp_input() when a DR or ER is to be issued in
@@ -681,7 +745,7 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
        struct mbuf     *erdata;
        int                     erlen;
        struct tp_pcb   *tpcb;
        struct mbuf     *erdata;
        int                     erlen;
        struct tp_pcb   *tpcb;
-       int                     cons_channel;
+       caddr_t                 cons_channel;
        int                             (*dgout_routine)();
 {
        int                                             dutype;
        int                             (*dgout_routine)();
 {
        int                                             dutype;
@@ -714,24 +778,38 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
                        error, error&0xff, (char)error);
        ENDDEBUG
 
                        error, error&0xff, (char)error);
        ENDDEBUG
 
-       error &= 0xff;
 
 
-       if( error & 0x40 ) {
+       if (error & TP_ERROR_SNDC)
+               dutype = DC_TPDU_type;
+       else if (error & 0x40) {
                error &= ~0x40;
                dutype = ER_TPDU_type;
        } else
                dutype = DR_TPDU_type;
                error &= ~0x40;
                dutype = ER_TPDU_type;
        } else
                dutype = DR_TPDU_type;
+       error &= 0xff;
 
        hdr->tpdu_type = dutype;
        hdr->tpdu_cdt = 0;
 
        switch( dutype ) {
 
 
        hdr->tpdu_type = dutype;
        hdr->tpdu_cdt = 0;
 
        switch( dutype ) {
 
+       case DC_TPDU_type:
+               IncStat(ts_DC_sent);
+               hdr->tpdu_li = 6;
+               hdr->tpdu_DCdref = htons(sref);
+               hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
+               IFDEBUG(D_ERROR_EMIT)
+                       printf("DC case:\n");
+                       dump_buf( hdr, 6);
+               ENDDEBUG
+               /* forget the add'l information variable part */
+               break;
+
        case DR_TPDU_type:
                IncStat(ts_DR_sent);
                hdr->tpdu_li = 7;
                hdr->tpdu_DRdref = htons(sref);
        case DR_TPDU_type:
                IncStat(ts_DR_sent);
                hdr->tpdu_li = 7;
                hdr->tpdu_DRdref = htons(sref);
-               hdr->tpdu_DRsref = htons(0);
+               hdr->tpdu_DRsref = 0;
                hdr->tpdu_DRreason = (char)error;
                IFDEBUG(D_ERROR_EMIT)
                        printf("DR case:\n");
                hdr->tpdu_DRreason = (char)error;
                IFDEBUG(D_ERROR_EMIT)
                        printf("DR case:\n");
@@ -744,6 +822,7 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
                IncStat(ts_ER_sent);
                hdr->tpdu_li = 5; 
                hdr->tpdu_ERreason = (char)error;
                IncStat(ts_ER_sent);
                hdr->tpdu_li = 5; 
                hdr->tpdu_ERreason = (char)error;
+               hdr->tpdu_ERdref = htons(sref);
                break;
 
        default:
                break;
 
        default:
@@ -757,7 +836,7 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
                        csum_offset =  hdr->tpdu_li - 2;
                }
 
                        csum_offset =  hdr->tpdu_li - 2;
                }
 
-       ASSERT( hdr->tpdu_li < MMAXOFF );
+       ASSERT( hdr->tpdu_li < MLEN ); 
 
        if (dutype == ER_TPDU_type) {
                /* copy the errant tpdu into another 'variable part' */
 
        if (dutype == ER_TPDU_type) {
                /* copy the errant tpdu into another 'variable part' */
@@ -787,8 +866,11 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
                if(erdata->m_len == 0) {
                        erdata = m_free(erdata); /* returns the next mbuf on the chain */
                }
                if(erdata->m_len == 0) {
                        erdata = m_free(erdata); /* returns the next mbuf on the chain */
                }
-               m->m_next = m_copy(erdata, 0, erlen); /* copy only up to the
-                                       bad octet (or max that will fit in a header */
+               /*
+                * copy only up to the bad octet
+                * (or max that will fit in a header
+                */
+               m->m_next = m_copy(erdata, 0, erlen);
                hdr->tpdu_li += erlen + 2; 
                m_freem(erdata);
        } else {
                hdr->tpdu_li += erlen + 2; 
                m_freem(erdata);
        } else {
@@ -806,8 +888,7 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
        ENDTRACE
 
        datalen = m_datalen( m);
        ENDTRACE
 
        datalen = m_datalen( m);
-
-       if(tpcb) {
+       if (tpcb) {
                if( tpcb->tp_use_checksum ) {
                        IFTRACE(D_ERROR_EMIT)
                                tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
                if( tpcb->tp_use_checksum ) {
                        IFTRACE(D_ERROR_EMIT)
                                tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
@@ -824,59 +905,55 @@ tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
                        printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
                                tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
                ENDDEBUG
                        printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
                                tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
                ENDDEBUG
-               /* Problem: if packet comes in on ISO but sock is listening
-                * in INET, this assertion will fail.
-                * Have to believe the argument, not the nlp_proto.
-               ASSERT( tpcb->tp_nlproto->nlp_dgoutput == dgout_routine );
-                */
+       }
+       if (cons_channel) {
+#ifdef TPCONS
+               struct pklcd *lcp = (struct pklcd *)cons_channel;
+               struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
+
+               tpcons_dg_output(cons_channel, m, datalen);
+               /* was if (tpcb == 0) iso_pcbdetach(isop); */
+               /* but other side may want to try again over same VC,
+                  so, we'll depend on him closing it, but in case it gets forgotten
+                  we'll mark it for garbage collection */
+               lcp->lcd_flags |= X25_DG_CIRCUIT;
+               IFDEBUG(D_ERROR_EMIT)
+                       printf("OUTPUT: dutype 0x%x channel 0x%x\n",
+                               dutype, cons_channel);
+               ENDDEBUG
+#else
+               printf("TP panic! cons channel 0x%x but not cons configured\n",
+                       cons_channel);
+#endif
+       } else if (tpcb) {
 
                IFDEBUG(D_ERROR_EMIT)
                        printf("tp_error_emit 1 sending DG: Laddr\n");
 
                IFDEBUG(D_ERROR_EMIT)
                        printf("tp_error_emit 1 sending DG: Laddr\n");
-                       dump_isoaddr( laddr );
+                       dump_addr((struct sockaddr *)laddr);
                        printf("Faddr\n");
                        printf("Faddr\n");
-                       dump_isoaddr( faddr );
+                       dump_addr((struct sockaddr *)faddr);
                ENDDEBUG
                return (tpcb->tp_nlproto->nlp_dgoutput)(
                        &laddr->siso_addr, 
                        &faddr->siso_addr, 
                        m, datalen, 
                                        /* no route */  (caddr_t)0, !tpcb->tp_use_checksum); 
                ENDDEBUG
                return (tpcb->tp_nlproto->nlp_dgoutput)(
                        &laddr->siso_addr, 
                        &faddr->siso_addr, 
                        m, datalen, 
                                        /* no route */  (caddr_t)0, !tpcb->tp_use_checksum); 
-       } else  {
-               if( cons_channel ) {
-#if NARGOXTWENTYFIVE > 0
-#include "../netiso/cons.h"
-                       /* This is unfortunate...
-                               cons_send_on_vc(cons_channel, m, datalen);
-                       */
-                       cons_netcmd( CONN_CLOSE, (struct isopcb *)0, 
-                               cons_channel, CONS_NOT_DGM);
-                       IFDEBUG(D_ERROR_EMIT)
-                               printf("OUTPUT: dutype 0x%x channel 0x%x\n",
-                                       dutype, cons_channel);
-                       ENDDEBUG
-#else NARGOXTWENTYFIVE
-                       printf("TP panic! cons channel 0x%x but not cons configured\n",
-                               cons_channel);
-#endif NARGOXTWENTYFIVE > 0
-               } else {
-#ifndef nodef
+       } else if (dgout_routine) {
                        IFDEBUG(D_ERROR_EMIT)
                                printf("tp_error_emit sending DG: Laddr\n");
                        IFDEBUG(D_ERROR_EMIT)
                                printf("tp_error_emit sending DG: Laddr\n");
-                               dump_isoaddr( laddr );
+                               dump_addr((struct sockaddr *)laddr);
                                printf("Faddr\n");
                                printf("Faddr\n");
-                               dump_isoaddr( laddr );
+                               dump_addr((struct sockaddr *)faddr);
                        ENDDEBUG
                        ENDDEBUG
-                       return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, 
-                               m, datalen, /* no route */ 
-                               (caddr_t)0, /* nochecksum==false */0);
-#else nodef
+                               return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, 
+                                       m, datalen, /* no route */ 
+                                       (caddr_t)0, /* nochecksum==false */0);
+       } else {
                        IFDEBUG(D_ERROR_EMIT)
                                printf("tp_error_emit DROPPING \n", m);
                        ENDDEBUG
                        IncStat(ts_send_drop);
                        m_freem(m);
                        return 0;
                        IFDEBUG(D_ERROR_EMIT)
                                printf("tp_error_emit DROPPING \n", m);
                        ENDDEBUG
                        IncStat(ts_send_drop);
                        m_freem(m);
                        return 0;
-#endif nodef
-               }
        }
 }
        }
 }