#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/at_pcb.h>
#include <netat/debug.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
#define TX_DLY 2
int adsp_window = 1;
int CalcRecvWdw(sp)
CCBPtr sp;
{
int bytes;
bytes = calcRecvQ(sp);
bytes = sp->rbuflen - bytes;
if (bytes <= 16) {
sp->rbufFull = 1;
return 0;
}
else
return ((bytes+bytes+bytes) >> 2) + 1;
}
calcRecvQ(sp)
CCBPtr sp;
{
int bytes = 0;
#ifdef AT_Socket
register struct mbuf *m, *p;
if (((sp->gref)->so)->so_rcv.sb_mb)
for (p = ((sp->gref)->so)->so_rcv.sb_mb; p; p = p->m_nextpkt)
for (m = p; m; m = m->m_next)
bytes += m->m_len;
#else
register gbuf_t *mb;
if (sp->rData) {
if (mb = sp->rbuf_mb) {
do {
bytes += gbuf_msgsize(mb);
mb = gbuf_next(mb);
} while (mb);
}
if (mb = sp->crbuf_mb)
bytes += gbuf_msgsize(mb);
}
#endif
return bytes;
}
void CheckSend(sp)
register CCBPtr sp;
{
int i;
int attnMsg;
int s;
register gbuf_t *mp;
#ifdef notdef
register gbuf_t *tmp;
u_char current;
#endif
char *dp;
int use_attention_code;
int len;
int datalen;
gbuf_t *mprev, *mlist = 0;
top:
if (sp->state == sClosed)
return;
if ((mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN + 2,
PRI_LO)) == 0) {
if (mlist)
gbuf_freel(mlist);
return;
}
ATDISABLE(s, sp->lock);
sp->callSend = 0;
use_attention_code = 0;
len = 0;
datalen = 0;
gbuf_rinc(mp,AT_WR_OFFSET);
gbuf_wset(mp,DDPL_FRAME_LEN);
if (sp->sendCtl) {
short mask;
i = sp->sendCtl;
attnMsg = 0;
if (i & 0x1E)
{
dp = ((char *) gbuf_wptr(mp)) + ADSP_FRAME_LEN;
UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->firstRtmtSeq));
UAS_ASSIGN(sp->of.version, netw(0x0100));
UAS_ASSIGN(sp->of.dstCID, sp->remCID);
UAL_ASSIGN(sp->of.pktAttnRecvSeq, netdw(sp->attnRecvSeq));
bcopy((caddr_t) &sp->of, (caddr_t) dp, ADSP_OPEN_FRAME_LEN);
len += ADSP_OPEN_FRAME_LEN;
if (i & B_CTL_OREQ) {
UAS_ASSIGN(sp->f.CID, sp->locCID);
mask = B_CTL_OREQ;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQ;
} else if (i & B_CTL_OACK) {
UAS_ASSIGN(sp->f.CID, sp->locCID);
mask = B_CTL_OACK;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OACK;
} else if (i & B_CTL_OREQACK) {
UAS_ASSIGN(sp->f.CID, sp->locCID);
mask = B_CTL_OREQACK;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQACK;
} else
{
UAS_ASSIGN(sp->f.CID, 0);
mask = B_CTL_ODENY;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY;
UAL_ASSIGN(sp->f.pktFirstByteSeq, 0);
}
if (i & (B_CTL_OREQ | B_CTL_OREQACK))
{
RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
sp->openInterval+1);
}
} else {
UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq));
if (i & B_CTL_CLOSE) {
sp->state = sClosed;
mask = B_CTL_CLOSE;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_CLOSE;
} else if (i & B_CTL_PROBE) {
mask = B_CTL_PROBE;
sp->f.descriptor =
ADSP_CONTROL_BIT | ADSP_CTL_PROBE | ADSP_ACK_REQ_BIT;
} else if (i & B_CTL_FRESET) {
mask = B_CTL_FRESET;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET;
InsertTimerElem(&adspGlobal.fastTimers,
&sp->ResetTimer, sp->rtmtInterval+TX_DLY);
} else if (i & B_CTL_FRESETACK) {
mask = B_CTL_FRESETACK;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET_ACK;
}
else if (i & B_CTL_RETRANSMIT) {
mask = B_CTL_RETRANSMIT;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_RETRANSMIT;
}
else {
dPrintf(D_M_ADSP, D_L_ERROR, ("CheckSend: Control bit error\n"));
}
}
sp->sendCtl &= ~mask;
goto sendit;
}
if (sp->sendAttnData)
{
sp->sendAttnData = 0;
if (sp->sapb) {
sp->sendAttnAck = 0;
attnMsg = 1;
sp->f.descriptor = ADSP_ATTENTION_BIT | ADSP_ACK_REQ_BIT;
if (gbuf_cont(sp->sapb->mp)) {
gbuf_cont(mp) = gbuf_dupm(gbuf_cont(sp->sapb->mp));
}
use_attention_code++;
sp->f.data[0] = high(sp->sapb->u.attnParams.attnCode);
sp->f.data[1] = low(sp->sapb->u.attnParams.attnCode);
InsertTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer,
sp->rtmtInterval+TX_DLY);
goto sendit;
}
}
if (sp->sendAttnAck)
{
attnMsg = 1;
sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_ATTENTION_BIT;
sp->sendAttnAck = 0;
goto sendit;
}
if ((sp->state == sOpen || sp->state == sClosing) &&
(!sp->waitingAck) &&
(sp->sData) &&
(GTE(sp->sendWdwSeq,sp->sendSeq)) &&
(sp->pktSendCnt < sp->pktSendMax))
{
attnMsg = 0;
if (datalen = attachData(sp, mp))
goto sendit;
}
if (sp->sendDataAck) {
UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq));
attnMsg = 0;
sp->f.descriptor = ADSP_CONTROL_BIT;
goto sendit;
}
if (mp)
gbuf_freem(mp);
ATENABLE(s, sp->lock);
if (mlist)
adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
return;
sendit:
if (attnMsg) {
UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->attnSendSeq));
UAL_ASSIGN(sp->f.pktNextRecvSeq, netdw(sp->attnRecvSeq));
UAS_ASSIGN(sp->f.pktRecvWdw, 0);
} else {
sp->sendDataAck = 0;
UAL_ASSIGN(sp->f.pktNextRecvSeq, netdw(sp->recvSeq));
UAS_ASSIGN(sp->f.pktRecvWdw, netw(CalcRecvWdw(sp)));
}
if (use_attention_code) {
bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN + 2);
len += ADSP_FRAME_LEN + 2;
} else {
bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN);
len += ADSP_FRAME_LEN;
}
gbuf_winc(mp,len);
if (mlist)
gbuf_next(mprev) = mp;
else
mlist = mp;
mprev = mp;
if (sp->state == sClosed) {
ATENABLE(s, sp->lock);
adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
DoClose(sp, 0, -1);
return;
}
ATENABLE(s, sp->lock);
if (sp->state == sClosing)
CheckOkToClose(sp);
goto top;
}
void completepb(sp, pb)
register CCBPtr sp;
register struct adspcmd *pb;
{
if (sp->gref && (sp->gref->info == (caddr_t)sp->sp_mp)) {
if (gbuf_len(pb->mp) > sizeof(struct adspcmd))
gbuf_wset(pb->mp,sizeof(struct adspcmd));
SndMsgUp(sp->gref, pb->mp);
NotifyUser(sp);
} else
gbuf_freem(pb->mp);
}
attachData(sp, mp)
register CCBPtr sp;
register gbuf_t *mp;
{
int seq;
int cnt;
char eom = 0;
int bsize;
int diff;
char sendAckReq;
int partial = 0;
int tcnt = 0;
register gbuf_t *smp;
register gbuf_t *psmp;
sendAckReq = 0;
if (LT(sp->sendSeq, sp->firstRtmtSeq))
sp->sendSeq = sp->firstRtmtSeq;
UAL_ASSIGN(sp->f.pktFirstByteSeq, netdw(sp->sendSeq));
if (smp = sp->sbuf_mb)
eom = 1;
else if (smp = sp->csbuf_mb)
eom = 0;
if (smp == 0) {
sp->sData = 0;
return 0;
}
seq = sp->firstRtmtSeq;
while ((diff = (sp->sendSeq - seq)) >= ((bsize = gbuf_msgsize(smp)) + eom)) {
seq += bsize + eom;
if (gbuf_next(smp)) {
smp = gbuf_next(smp);
eom = 1;
} else if (smp == sp->csbuf_mb) {
smp = 0;
break;
} else if (sp->csbuf_mb) {
smp = sp->csbuf_mb;
eom = 0;
} else {
smp = 0;
break;
}
}
if (smp) {
if (gbuf_next(smp) == 0)
sendAckReq = 1;
cnt = bsize - diff;
} else
cnt = 0;
if ((cnt < sp->sendBlocking) && !sp->writeFlush) {
InsertTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer,
sp->sendInterval);
return 0;
}
if (cnt > ADSP_MAX_DATA_LEN) {
cnt = ADSP_MAX_DATA_LEN;
eom = 0;
sendAckReq = 0;
partial++;
}
if (smp) {
while (diff) {
if (gbuf_len(smp) > diff)
break;
else
diff -= gbuf_len(smp);
smp = gbuf_cont(smp);
}
if((gbuf_cont(mp) = gbuf_dupm(smp)) == 0)
return 0;
smp = gbuf_cont(mp);
gbuf_rinc(smp,diff);
}
if ((diff = sp->sendWdwSeq + 1 - sp->sendSeq) <= cnt) {
if (diff < cnt) {
eom = 0;
cnt = diff;
partial++;
}
sendAckReq = 1;
sp->noXmitFlow = 1;
}
if (partial && smp) {
psmp = smp;
tcnt = cnt;
while (tcnt && smp) {
if (tcnt >= gbuf_len(smp)) {
tcnt -= gbuf_len(smp);
if (tcnt) {
psmp = smp;
smp = gbuf_cont(smp);
} else {
if (psmp != smp) {
gbuf_cont(psmp) = 0;
gbuf_freem(smp);
smp = psmp;
} else {
gbuf_freem(gbuf_cont(smp));
gbuf_cont(smp) = 0;
}
break;
}
} else {
gbuf_wset(smp,tcnt);
if (gbuf_cont(smp)) {
gbuf_freem(gbuf_cont(smp));
gbuf_cont(smp) = 0;
}
break;
}
}
}
sp->sendSeq += cnt + eom;
if (GT(sp->sendSeq, sp->maxSendSeq))
sp->maxSendSeq = sp->sendSeq;
if (eom)
sp->f.descriptor = ADSP_EOM_BIT;
else
sp->f.descriptor = 0;
if (sendAckReq || (++sp->pktSendCnt >= sp->pktSendMax)) {
sp->f.descriptor |= ADSP_ACK_REQ_BIT;
sp->waitingAck = 1;
sp->sendStamp = SysTicks();
sp->timerSeq = sp->sendSeq;
InsertTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer,
sp->rtmtInterval+TX_DLY);
}
return cnt + eom;
}