#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <netiso/iso.h>
#include <netiso/iso_pcb.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 <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();
char tp_delay = 0x00;
int
tp_emit(dutype, tpcb, seq, eot, data)
int dutype;
struct tp_pcb *tpcb;
SeqNum seq;
u_int eot;
struct mbuf *data;
{
register struct tpdu *hdr;
register struct mbuf *m;
int csum_offset=0;
int datalen = 0;
int error = 0;
SeqNum olduwe;
int acking_ooo;
IFDEBUG(D_EMIT)
printf(
"tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
dutype, tpcb, eot, seq, data);
ENDDEBUG
if (dutype == CR_TPDU || dutype == CC_TPDU) {
MALLOC(m, struct mbuf *, 256, M_MBUF, M_NOWAIT);
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);
error = ENOBUFS;
goto done;
}
m->m_len = sizeof(struct tpdu);
m->m_act = MNULL;
hdr = mtod(m, struct tpdu *);
bzero((caddr_t)hdr, sizeof(struct tpdu));
{
int tp_headersize();
hdr->tpdu_type = dutype;
hdr->tpdu_li = tp_headersize(dutype, tpcb);
hdr->tpdu_dref = htons(tpcb->tp_fref);
if( tpcb->tp_use_checksum ||
(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
csum_offset = hdr->tpdu_li + 2;
ADDOPTION(TPP_checksum, hdr, 2, eot );
IFDEBUG(D_CHKSUM)
printf(
"tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
csum_offset, hdr->tpdu_li);
ENDDEBUG
}
switch( dutype ) {
case CR_TPDU_type:
hdr->tpdu_CRdref_0 = 0;
case CC_TPDU_type:
if (!tpcb->tp_cebit_off) {
tpcb->tp_win_recv = tp_start_win << 8;
LOCAL_CREDIT(tpcb);
CONG_INIT_SAMPLE(tpcb);
} else
LOCAL_CREDIT(tpcb);
{
u_char x;
hdr->tpdu_CCsref = htons(tpcb->tp_lref);
if( tpcb->tp_class > TP_CLASS_1 ) {
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 {
#if 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_CCoptions =
(tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
(tpcb->tp_use_efc? TPO_USE_EFC:0);
IFPERF(tpcb)
u_char perf_meas = tpcb->tp_perf_on;
ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
ENDPERF
if( dutype == CR_TPDU_type ) {
IncStat(ts_CR_sent);
ASSERT( tpcb->tp_lsuffixlen > 0 );
ASSERT( tpcb->tp_fsuffixlen > 0 );
ADDOPTION(TPP_calling_sufx, hdr,
tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
ADDOPTION(TPP_called_sufx, hdr,
tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
} else {
IncStat(ts_CC_sent);
}
ADDOPTION(TPP_tpdu_size, hdr,
sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
if (tpcb->tp_class != TP_CLASS_0) {
short millisec = 500*(tpcb->tp_sendack_ticks);
millisec = htons(millisec);
ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
| (tpcb->tp_use_rcc? TPAO_USE_RCC : 0)
| (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
| (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
ADDOPTION(TPP_addl_opt, hdr, 1, x);
if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) {
u_short size_s = tpcb->tp_l_tpdusize >> 7;
u_char size_c = size_s;
ASSERT(tpcb->tp_l_tpdusize < 65536 * 128);
if (dutype == CR_TPDU_type)
tpcb->tp_ptpdusize = size_s;
if (size_s < 256) {
ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
} else {
size_s = htons(size_s);
ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s);
}
}
}
if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
ASSERT( 1 == sizeof(tpcb->tp_vers) );
ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
x = 0;
ADDOPTION(TPP_alt_class, hdr, 1, x);
}
if( hdr->tpdu_li > MLEN)
panic("tp_emit CR/CC");
}
break;
case DR_TPDU_type:
if( hdr->tpdu_DRdref == 0 ) {
goto done;
}
hdr->tpdu_cdt = 0;
hdr->tpdu_DRsref = htons(tpcb->tp_lref);
hdr->tpdu_DRreason = (u_char)eot;
IncStat(ts_DR_sent);
break;
case DC_TPDU_type:
ASSERT( tpcb->tp_class != TP_CLASS_0);
hdr->tpdu_DCsref = htons(tpcb->tp_lref);
hdr->tpdu_cdt = 0;
data = (struct mbuf *)0;
IncStat(ts_DC_sent);
break;
case XAK_TPDU_type:
ASSERT( tpcb->tp_class != TP_CLASS_0);
hdr->tpdu_cdt = 0;
IFTRACE(D_XPD)
tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
ENDTRACE
data = (struct mbuf *)0;
if (tpcb->tp_xtd_format) {
#ifdef BYTE_ORDER
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
} else {
hdr->tpdu_XAKseq = seq;
}
IncStat(ts_XAK_sent);
IncPStat(tpcb, tps_XAK_sent);
break;
case XPD_TPDU_type:
ASSERT( tpcb->tp_class != TP_CLASS_0);
hdr->tpdu_cdt = 0;
if (tpcb->tp_xtd_format) {
#ifdef BYTE_ORDER
union seq_type seqeotX;
seqeotX.s_seq = seq;
seqeotX.s_eot = 1;
hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
#else
hdr->tpdu_XPDseqX = seq;
hdr->tpdu_XPDeotX = 1;
#endif
} else {
hdr->tpdu_XPDseq = seq;
hdr->tpdu_XPDeot = 1;
}
IncStat(ts_XPD_sent);
IncPStat(tpcb, tps_XPD_sent);
IFDEBUG(D_SIZE_CHECK)
ENDDEBUG
break;
case DT_TPDU_type:
hdr->tpdu_cdt = 0;
IFTRACE(D_DATA)
tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
hdr->tpdu_li, 0);
ENDTRACE
if (tpcb->tp_xtd_format) {
#ifdef BYTE_ORDER
union seq_type seqeotX;
seqeotX.s_seq = seq;
seqeotX.s_eot = eot;
hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
#else
hdr->tpdu_DTseqX = seq;
hdr->tpdu_DTeotX = eot;
#endif
} else if (tpcb->tp_class == TP_CLASS_0) {
IFDEBUG(D_EMIT)
printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
dump_buf( hdr, hdr->tpdu_li + 1 );
ENDDEBUG
((struct tp0du *)hdr)->tp0du_eot = eot;
((struct tp0du *)hdr)->tp0du_mbz = 0;
IFDEBUG(D_EMIT)
printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
dump_buf( hdr, hdr->tpdu_li + 1 );
ENDDEBUG
} else {
hdr->tpdu_DTseq = seq;
hdr->tpdu_DTeot = eot;
}
if(eot) {
IncStat(ts_EOT_sent);
}
IncStat(ts_DT_sent);
IncPStat(tpcb, tps_DT_sent);
break;
case AK_TPDU_type:
ASSERT( tpcb->tp_class != TP_CLASS_0);
data = (struct mbuf *)0;
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_lcdt = tpcb->tp_lcredit;
acking_ooo = 0;
} else
acking_ooo = 1;
IFDEBUG(D_RENEG)
if( olduwe & 0x1 ) {
tpcb->tp_reneged = 1;
IncStat(ts_ldebug);
}
ENDDEBUG
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)
if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
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] );
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) ] );
}
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
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_AKseqX = seq;
hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
#endif
} else {
hdr->tpdu_AKseq = seq;
hdr->tpdu_AKcdt = tpcb->tp_lcredit;
}
if ((tpcb->tp_class == TP_CLASS_4) &&
(tpcb->tp_reneged || acking_ooo)) {
IFDEBUG(D_RENEG)
printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
ENDDEBUG
tpcb->tp_s_subseq++;
ADDOPTION(TPP_subseq, hdr,
sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
} else
tpcb->tp_s_subseq = 0;
if ( tpcb->tp_sendfcc || eot ) {
u_short bogus[4];
SeqNum lwe;
u_short subseq, fcredit;
tpcb->tp_sendfcc = 0;
lwe = (SeqNum) htonl(tpcb->tp_snduna);
subseq = htons(tpcb->tp_r_subseq);
fcredit = htons(tpcb->tp_fcredit);
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,
"emit w/FCC: snduna r_subseq fcredit",
tpcb->tp_snduna, tpcb->tp_r_subseq,
tpcb->tp_fcredit, 0);
ENDTRACE
IFDEBUG(D_ACKSEND)
printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
TPP_flow_cntl_conf,
hdr, sizeof(bogus), bogus[0]);
ENDDEBUG
ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
IFDEBUG(D_ACKSEND)
printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
hdr, hdr->tpdu_li);
printf(
"after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
csum_offset, hdr->tpdu_li);
ENDDEBUG
}
tpcb->tp_reneged = 0;
tpcb->tp_sent_rcvnxt = seq;
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)
printf(
"2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
csum_offset, hdr->tpdu_li);
ENDDEBUG
break;
case ER_TPDU_type:
hdr->tpdu_ERreason = eot;
hdr->tpdu_cdt = 0;
data = (struct mbuf *)0;
IncStat(ts_ER_sent);
break;
}
}
ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
m->m_next = data;
ASSERT( hdr->tpdu_li < MLEN );
ASSERT( hdr->tpdu_li != 0 );
m->m_len = hdr->tpdu_li ;
hdr->tpdu_li --;
datalen = m_datalen( m );
ASSERT( datalen <= tpcb->tp_l_tpdusize );
IFDEBUG(D_ACKSEND)
printf(
"4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
csum_offset, hdr->tpdu_li);
ENDDEBUG
if( datalen > tpcb->tp_l_tpdusize ) {
printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
datalen, tpcb->tp_l_tpdusize);
}
IFDEBUG(D_EMIT)
printf(
"tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
m->m_len, csum_offset, datalen);
ENDDEBUG
if( tpcb->tp_use_checksum ||
(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
iso_gen_csum(m, csum_offset, 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(mtod(m, caddr_t), datalen);
ENDDEBUG
IFPERF(tpcb)
if( dutype == DT_TPDU_type ) {
PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0,
seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
}
ENDPERF
IFTRACE(D_EMIT)
tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
ENDTRACE
IFDEBUG(D_EMIT)
printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
tpcb, tpcb->tp_npcb, tpcb->tp_sock);
ENDDEBUG
{ extern char tp_delay;
if( tp_delay )
if( tpcb->tp_use_checksum == 0 ) {
register u_int i = tp_delay;
for (; i!= 0; i--)
(void) iso_check_csum(m, datalen);
}
}
ASSERT( m->m_len > 0 );
error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
!tpcb->tp_use_checksum);
IFDEBUG(D_EMIT)
printf("OUTPUT: returned 0x%x\n", error);
ENDDEBUG
IFTRACE(D_EMIT)
tptraceTPCB(TPPTmisc,
"tp_emit nlproto->output netservice returns datalen",
tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
ENDTRACE
done:
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;
}
int
tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
dgout_routine)
int error;
u_long sref;
struct sockaddr_iso *faddr, *laddr;
struct mbuf *erdata;
int erlen;
struct tp_pcb *tpcb;
caddr_t cons_channel;
int (*dgout_routine)();
{
int dutype;
int datalen = 0;
register struct tpdu *hdr;
register struct mbuf *m;
int csum_offset;
IFTRACE(D_ERROR_EMIT)
tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
error, sref, tpcb, erlen);
ENDTRACE
IFDEBUG(D_ERROR_EMIT)
printf(
"tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
error, sref, tpcb, erlen, cons_channel);
ENDDEBUG
MGET(m, M_DONTWAIT, TPMT_TPHDR);
if (m == NULL) {
return ENOBUFS;
}
m->m_len = sizeof(struct tpdu);
m->m_act = MNULL;
hdr = mtod(m, struct tpdu *);
IFDEBUG(D_ERROR_EMIT)
printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
error, error&0xff, (char)error);
ENDDEBUG
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 &= 0xff;
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
break;
case DR_TPDU_type:
IncStat(ts_DR_sent);
hdr->tpdu_li = 7;
hdr->tpdu_DRdref = htons(sref);
hdr->tpdu_DRsref = 0;
hdr->tpdu_DRreason = (char)error;
IFDEBUG(D_ERROR_EMIT)
printf("DR case:\n");
dump_buf( hdr, 7);
ENDDEBUG
break;
case ER_TPDU_type:
IncStat(ts_ER_sent);
hdr->tpdu_li = 5;
hdr->tpdu_ERreason = (char)error;
hdr->tpdu_ERdref = htons(sref);
break;
default:
ASSERT(0);
printf("TP PANIC: bad dutype 0x%x\n", dutype);
}
if(tpcb)
if( tpcb->tp_use_checksum ) {
ADDOPTION(TPP_checksum, hdr, 2, csum_offset );
csum_offset = hdr->tpdu_li - 2;
}
ASSERT( hdr->tpdu_li < MLEN );
if (dutype == ER_TPDU_type) {
register caddr_t P;
IFTRACE(D_ERROR_EMIT)
tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
0,0);
ENDTRACE
IFDEBUG(D_ERROR_EMIT)
printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
ENDDEBUG
if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
P = (caddr_t)hdr + (int)(hdr->tpdu_li);
vbptr(P)->tpv_code = TPP_invalid_tpdu;
vbptr(P)->tpv_len = erlen;
m->m_len = hdr->tpdu_li + 2;
if(erdata->m_len == 0) {
erdata = m_free(erdata);
}
m->m_next = m_copy(erdata, 0, erlen);
hdr->tpdu_li += erlen + 2;
m_freem(erdata);
} else {
IFDEBUG(D_ERROR_EMIT)
printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
dump_buf( (char *)hdr, hdr->tpdu_li );
ENDDEBUG
m->m_len = hdr->tpdu_li ;
m_freem(erdata);
}
hdr->tpdu_li --;
IFTRACE(D_ERROR_EMIT)
tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
ENDTRACE
datalen = m_datalen( m);
if (tpcb) {
if( tpcb->tp_use_checksum ) {
IFTRACE(D_ERROR_EMIT)
tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
ENDTRACE
IFDEBUG(D_ERROR_EMIT)
printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
datalen, csum_offset);
ENDDEBUG
iso_gen_csum(m, csum_offset, datalen);
}
IFDEBUG(D_ERROR_EMIT)
printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
tpcb, tpcb->tp_npcb, tpcb->tp_sock);
ENDDEBUG
}
if (cons_channel) {
#if TPCONS
struct pklcd *lcp = (struct pklcd *)cons_channel;
struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
tpcons_dg_output(cons_channel, m, datalen);
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");
dump_addr((struct sockaddr *)laddr);
printf("Faddr\n");
dump_addr((struct sockaddr *)faddr);
ENDDEBUG
return (tpcb->tp_nlproto->nlp_dgoutput)(
&laddr->siso_addr,
&faddr->siso_addr,
m, datalen,
(caddr_t)0, !tpcb->tp_use_checksum);
} else if (dgout_routine) {
IFDEBUG(D_ERROR_EMIT)
printf("tp_error_emit sending DG: Laddr\n");
dump_addr((struct sockaddr *)laddr);
printf("Faddr\n");
dump_addr((struct sockaddr *)faddr);
ENDDEBUG
return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
m, datalen,
(caddr_t)0, 0);
} else {
IFDEBUG(D_ERROR_EMIT)
printf("tp_error_emit DROPPING \n", m);
ENDDEBUG
IncStat(ts_send_drop);
m_freem(m);
return 0;
}
}