V10/630/src/precv.c
/*
** Process receiver buffers
*/
#include "pconfig.h"
#include "proto.h"
#include "packets.h"
#include "pstats.h"
/* extern int crc(); */
void Reply(), Control();
int Retry();
struct Pktstate precvpkt;
/* static */ Pkt_p Pkp;
/* static */ char * pbufp;
/* static */ char * Sbufp;
/* static */ short dcount;
/* static */ short Scount;
#define Pkt precvpkt.pkt
#define State precvpkt.state
#define Timo precvpkt.timo
#define Header Pkt.header
#define Dsize Pkt.dsize
#define Data Pkp->data
#define Ptyp (Pkt.header & P_PTYPE)
#define Cntl (Pkt.header & P_CNTL)
#define Channel P_channel(Pkt.header)
#define Seq P_seq(Pkt.header)
#define Nextseq pconvs[Channel].rseq
void
#ifndef Blit
precv(bufp, count)
register char * bufp;
register int count;
{
int haveheader = 0;
while ( count-- )
#else Blit
precv(c)
char c;
#endif Blit
{
switch ( State )
{
case PR_NULL:
# ifndef Blit
Pkp = (Pkt_p)bufp;
haveheader++;
Header = *bufp++;
# else Blit
Header = c;
# endif Blit
if ( !Ptyp )
{
PSTATS(PS_BADHDR);
ptracepkt(Pkp, pstats[PS_BADHDR].descp);
break;
}
Timo = Prtimeout;
if ( !Ptflag )
{
Ptflag++;
# ifndef Blit
(void)alarm(Pscanrate);
# endif
}
State = PR_SIZE;
# ifndef Blit
continue;
# else
return;
# endif
case PR_SIZE:
# ifndef Blit
Dsize = *bufp++;
# else
Dsize = c;
# endif
Scount = Dsize;
if ( Scount > MAXPKTDSIZE )
{
PSTATS(PS_BADSIZE);
ptracepkt((haveheader?Pkp:&Pkt), pstats[PS_BADSIZE].descp);
break;
}
dcount = Scount + EDSIZE;
# ifndef Blit
if ( dcount <= count && haveheader )
{
/* Don't move data */
Sbufp = bufp;
bufp += dcount;
count -= dcount;
goto check;
}
# endif
Pkp = &Pkt;
Sbufp = (char *)Data;
pbufp = Sbufp;
State = PR_DATA;
# ifndef Blit
continue;
# else
return;
# endif
case PR_DATA:
# ifndef Blit
*pbufp++ = *bufp++;
# else
*pbufp++ = c;
# endif
if ( --dcount > 0 )
# ifndef Blit
continue;
# else
return;
# endif
check:
/** Now at CRC **/
plogpkt(Pkp, PLOGIN);
if ( crc((uchar *)Pkp, (int)(Scount+2)) ) /* if bit fields were independent */
{
PSTATS(PS_BADCRC);
ptracepkt(Pkp, pstats[PS_BADCRC].descp);
}
else
{
if ( Cntl )
Control();
else
{
Pcdata = (uchar)0;
if ( Seq == Nextseq )
{
if ( (*Prfuncp)(Channel, Sbufp, Scount) )
{
PSTATS(PS_BUSY);
/* Better to let this timeout,
** as a following sequence will
** generate a second retransmission
*/
Reply(NAK);
}
else
{
Nextseq = (Nextseq+1) & (SEQMOD-1); /* NB rseq is a byte, not a bit field, for efficiency */
PSTATS(PS_RPKTS);
# ifdef PSTATISTICS
pstats[PS_RBYTES].count += Scount;
# endif
pconvs[Channel].cdata[Seq] = Pcdata;
Reply(ACK);
}
}
else
if ( Retry() )
{
PSTATS(PS_RDUP);
Reply(ACK);
}
else
{
PSTATS(PS_OUTSEQ);
Reply(NAK);
pdumphist(pstats[PS_OUTSEQ].descp);
}
}
}
}
Timo = 0;
State = PR_NULL;
#ifndef Blit
}
#endif
}
/*
** Deal with control packet
*/
void
Control()
{
register Pch_p pcp = &pconvs[Channel];
register Pks_p psp = pcp->nextpkt;
register Pbyte *lastseqp = &pseqtable[Seq+SEQMOD];
register Pbyte *seqp = lastseqp - (NPCBUFS-1);
register int hit = 0;
# ifdef Blit
register int x = spl1();
# endif
if ( Scount == 0 )
goto ack;
switch ( Data[0] )
{
case ACK:
/** This and all lesser sequenced packets ok **/
ack:
do
{
if ( *seqp == P_seq(psp->pkt.header) )
{
if ( psp->state != PX_WAIT )
{
# if PDEBUG == 1 || PSTATISTICS == 1
if ( psp->state != PX_OK )
{
PSTATS(PS_BADXST);
pdumphist(pstats[PS_BADXST].descp);
}
# endif
}
else
{
psp->state = PX_OK;
psp->timo = 0;
hit++;
}
if ( ++psp >= &pcp->pkts[NPCBUFS] )
psp = pcp->pkts;
}
} while
( ++seqp <= lastseqp );
if ( hit )
{
pcp->nextpkt = psp;
pcp->freepkts += hit;
# ifdef PSTATISTICS
pstats[PS_XPKTS].count += hit;
if ( hit > 1 )
PSTATS(PS_LOSTACK);
# endif
break;
}
# if PDEBUG == 1 || PSTATISTICS == 1
PSTATS(PS_BADACK);
pdumphist(pstats[PS_BADACK].descp);
# endif
# ifdef Blit
splx(x);
# endif
return;
case NAK:
/** Retransmit this and all lesser sequenced packets **/
do
{
if ( *seqp == P_seq(psp->pkt.header) )
{
if ( psp->state != PX_WAIT )
{
# if PSTATISTICS == 1 || PDEBUG == 1
if ( psp->state != PX_OK )
{
PSTATS(PS_BADXST);
pdumphist(pstats[PS_BADXST].descp);
}
# endif
}
else
{
psp->timo = Pxtimeout;
(void)Pxfunc(&psp->pkt, psp->size);
PSTATS(PS_NAKPKT);
hit++;
plogpkt(&psp->pkt, PLOGOUT);
}
if ( ++psp >= &pcp->pkts[NPCBUFS] )
psp = pcp->pkts;
}
} while
( ++seqp <= lastseqp );
if ( !hit )
{
PSTATS(PS_BADNAK);
pdumphist(pstats[PS_BADNAK].descp);
# ifdef Blit
splx(x);
# endif
return;
}
break;
case PCDATA:
break;
default:
PSTATS(PS_BADCNTL);
ptracepkt(Pkp, pstats[PS_BADCNTL].descp);
# ifdef Blit
splx(x);
# endif
return;
}
# ifdef Blit
splx(x);
# endif
if ( --Scount > 0 )
{
(*Prcfuncp)(Channel, Sbufp+1, Scount);
# ifdef PSTATISTICS
pstats[PS_RCBYTES].count += Scount;
# endif
}
}
/*
** Reply to good packet
*/
void
Reply(ctl)
Pbyte ctl;
{
register int count;
Pkt.header |= P_CNTL;
if ( Pcdata )
{
PSTATS(PS_XCBYTES);
count = 2;
Pkt.data[1] = Pcdata;
Pkt.data[0] = ctl;
}
else
if ( ctl != ACK )
{
count = 1;
Pkt.data[0] = ctl;
}
else
count = 0;
Dsize = count;
count += 2; /* if bit fields were independent */
(void)crc((Pbyte *)&Pkt, count);
count += EDSIZE;
(void)Pxfunc(&Pkt, count);
plogpkt(&Pkt, PLOGOUT);
}
/*
** Non trivial sequence number validation:
** is this a valid retransmission?
*/
int
Retry()
{
register Pbyte *lastseqp = &pseqtable[Nextseq+SEQMOD-1];
register Pbyte *seqp = lastseqp - (NPCBUFS-1);
do
if ( *seqp == Seq )
{
Pcdata = pconvs[Channel].cdata[Seq];
return 1;
}
while
( ++seqp <= lastseqp );
return 0;
}