#include "uucp.h"
#include "pk.h"
#include <sys/buf.h>
extern void pkfail(), pkzero(), pkoutput(), pkreset(), pkcntl(), pkgetpack();
extern int pksack();
static void pkdata();
static int pkcget();
static void xlatestate(struct pack *, int);
void xlatecntl(int, int);
struct {
int state;
char *msg;
} st_trans[] = {
DEAD, "Dead!",
INITa, "INIT code a",
INITb, "INIT code b",
LIVE, "O.K.",
RXMIT, "Rcv/Xmit",
RREJ, "RREJ?",
PDEBUG, "PDEBUG?",
DRAINO, "Draino...",
WAITO, "Waiting",
DOWN, "Link down",
RCLOSE, "RCLOSE?",
BADFRAME, "Bad frame",
-1, "End of the line",
};
extern char _Protocol[];
#define PKMAXSTMSG 40
int Connodata = 0;
int Ntimeout = 0;
#define CONNODATA 20
#define NTIMEOUT 50
extern jmp_buf Getjbuf;
struct pack *
pkopen(ifn, ofn)
int ifn, ofn;
{
struct pack *pk;
char **bp;
int i;
int windows = WINDOWS;
extern int xpacksize, packsize;
if ((pk = (struct pack *) calloc(1, sizeof (struct pack))) == NULL)
return(NULL);
pk->p_ifn = ifn;
pk->p_ofn = ofn;
DEBUG(7, "Setting up protocol parameters '%s'\n", _Protocol);
if ( _Protocol[1] == '(' ) {
if (sscanf(_Protocol, "%*c(%d,%d)", &windows, &packsize) == 0)
sscanf(_Protocol, "%*c(,%d)", &packsize);
windows = ( windows < MINWINDOWS ? WINDOWS :
( windows > MAXWINDOWS ? WINDOWS : windows ) );
packsize = ( packsize < MINPACKSIZE ? PACKSIZE :
( packsize > MAXPACKSIZE ? PACKSIZE : packsize ) );
}
if ( (_Protocol[0] == 'g') && (packsize > OLDPACKSIZE) ) {
packsize = OLDPACKSIZE;
}
pk->p_xsize = pk->p_rsize = xpacksize = packsize;
pk->p_rwindow = pk->p_swindow = windows;
for (i = 0; i < pk->p_rwindow; i++) {
if ((bp = (char **) malloc((unsigned) pk->p_xsize)) == NULL)
break;
*bp = (char *) pk->p_ipool;
pk->p_ipool = bp;
}
if (i == 0)
return(NULL);
pk->p_rwindow = i;
pk->p_msg = pk->p_rmsg = M_INITA;
pkoutput(pk);
for (i = 0; i < PKMAXSTMSG; i++) {
pkgetpack(pk);
if ((pk->p_state & LIVE) != 0)
break;
}
if (i >= PKMAXSTMSG)
return(NULL);
pkreset(pk);
return(pk);
}
#define GETRIES 10
void
pkgetpack(ipk)
struct pack *ipk;
{
char *p;
struct pack *pk;
struct header *h;
unsigned short sum;
int k, tries, ifn, noise;
char **bp, hdchk;
pk = ipk;
if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > NTIMEOUT)
pkfail();
ifn = pk->p_ifn;
h = &pk->p_ihbuf;
for (tries = 0; tries < GETRIES; tries++) {
p = (caddr_t) h;
noise = 0;
for ( ; ; ) {
if (pkcget(ifn, p, HDRSIZ) != SUCCESS) {
DEBUG(7,
"Alarm while looking for SYN -- request RXMIT\n%s", "");
goto retransmit;
}
if (*p == SYN)
break;
else {
char *pp, *pend;
DEBUG(7, "first char not SYN (%x)\n", *p&0xff);
if ((pp = memchr(p, SYN, HDRSIZ)) != NULL) {
pend = p + HDRSIZ;
while (pp < pend)
*p++ = *pp++;
if (pkcget(ifn, p, pend - p) !=
SUCCESS) {
DEBUG(7,
"Alarm while looking for header -- request RXMIT\n%s", "");
goto retransmit;
}
p = (caddr_t) h;
break;
}
}
if ((noise += HDRSIZ) > 3 * pk->p_rsize) {
DEBUG(7,
"No SYN in %d characters -- request RXMIT\n", noise);
goto retransmit;
}
}
Connodata++;
hdchk = p[1] ^ p[2] ^ p[3] ^ p[4];
sum = ((unsigned) p[2] & 0377) | ((unsigned) p[3] << 8);
h->sum = sum;
k = h->ksize;
if (hdchk != h->ccntl) {
DEBUG(7, "bad header checksum\n%s", "");
return;
}
if (k == 9) {
if (((h->sum + h->cntl) & 0xffff) == CHECK) {
pkcntl(h->cntl, pk);
xlatestate(pk, 7);
} else {
DEBUG(7, "bad header (k == 9) 0%o\n", h->cntl&0xff);
pk->p_state |= BADFRAME;
}
return;
}
if (k && pksizes[k] != pk->p_rsize)
return;
pk->p_rpr = h->cntl & MOD8;
pksack(pk);
if ((bp = pk->p_ipool) == NULL) {
DEBUG(7, "bp NULL\n%s", "");
return;
}
pk->p_ipool = (char **) *bp;
if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) {
pkdata(h->cntl, h->sum, pk, bp);
Ntimeout = 0;
return;
}
DEBUG(7, "Alarm while reading data -- request RXMIT\n%s", "");
retransmit:
pk->p_msg |= pk->p_rmsg;
if (pk->p_msg == 0)
pk->p_msg |= M_RR;
if ((pk->p_state & LIVE) == LIVE)
pk->p_state |= RXMIT;
pkoutput(pk);
}
DEBUG(7, "pkgetpack failed after %d tries\n", tries);
pkfail();
}
static void
xlatestate(pk, dbglvl)
struct pack *pk;
int dbglvl;
{
int i;
char delimc = ' ', msgline[80], *buf = msgline;
if (Debug < dbglvl)
return;
sprintf(buf, "state -");
buf += strlen(buf);
for(i = 0; st_trans[i].state != -1; i++) {
if (pk->p_state&st_trans[i].state){
sprintf(buf, "%c[%s]", delimc, st_trans[i].msg);
buf += strlen(buf);
delimc = '&';
}
}
sprintf(buf, " (0%o)\n", pk->p_state);
DEBUG(dbglvl, "%s", msgline);
return;
}
static void
pkdata(c, sum, pk, bp)
struct pack *pk;
unsigned short sum;
char c;
char **bp;
{
int x;
int t;
char m;
if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) {
pk->p_msg |= pk->p_rmsg;
pkoutput(pk);
goto drop;
}
t = next[pk->p_pr];
for(x=pk->p_pr; x!=t; x = (x-1)&7) {
if (pk->p_is[x] == 0)
goto slot;
}
drop:
*bp = (char *)pk->p_ipool;
pk->p_ipool = bp;
return;
slot:
m = mask[x];
pk->p_imap |= m;
pk->p_is[x] = c;
pk->p_isum[x] = sum;
pk->p_ib[x] = (char *)bp;
}
void
pkxstart(pk, cntl, x)
struct pack *pk;
int x;
char cntl;
{
char *p;
short checkword;
char hdchk;
p = (caddr_t) &pk->p_ohbuf;
*p++ = SYN;
if (x < 0) {
*p++ = hdchk = 9;
checkword = cntl;
} else {
*p++ = hdchk = pk->p_lpsize;
checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377);
}
checkword = CHECK - checkword;
*p = checkword;
hdchk ^= *p++;
*p = checkword>>8;
hdchk ^= *p++;
*p = cntl;
hdchk ^= *p++;
*p = hdchk;
if (Debug >= 9)
xlatecntl(1, cntl);
p = (caddr_t) & pk->p_ohbuf;
if (x < 0) {
if ((*Write)(pk->p_ofn, p, HDRSIZ) != HDRSIZ) {
DEBUG(4, "pkxstart, write failed, %s\n",
strerror(errno));
logent(strerror(errno), "PKXSTART WRITE");
pkfail();
}
} else {
char buf[MAXPACKSIZE + HDRSIZ];
memcpy(buf, p, HDRSIZ);
memcpy(buf+HDRSIZ, pk->p_ob[x], pk->p_xsize);
if ((*Write)(pk->p_ofn, buf, pk->p_xsize + HDRSIZ) !=
pk->p_xsize + HDRSIZ) {
DEBUG(4, "pkxstart, write failed, %s\n",
strerror(errno));
logent(strerror(errno), "PKXSTART WRITE");
pkfail();
}
Connodata = 0;
}
if (pk->p_msg)
pkoutput(pk);
}
static int
pkcget(fn, b, n)
int n;
char *b;
int fn;
{
int ret;
#ifdef PKSPEEDUP
extern int linebaudrate;
int donap = (linebaudrate > 0 && linebaudrate < 4800);
#endif
if (n == 0)
return(SUCCESS);
if (setjmp(Getjbuf)) {
Ntimeout++;
DEBUG(4, "pkcget: alarm %d\n", Ntimeout);
return(FAIL);
}
(void) alarm( (unsigned) ( 10 + (n >> 7)) );
for (;;) {
ret = (*Read)(fn, b, n);
(void) alarm(0);
if (ret == 0) {
DEBUG(4, "pkcget, read failed, EOF\n", 0);
pkfail();
}
if (ret < 0) {
DEBUG(4, "pkcget, read failed, %s\n",
strerror(errno));
logent(strerror(errno), "PKCGET READ");
pkfail();
}
if ((n -= ret) <= 0)
break;
#ifdef PKSPEEDUP
if (donap) {
#if defined(BSD4_2) || defined(ATTSVR4)
nap((n * HZ * 10) / linebaudrate);
#else
sleep(1);
#endif
}
#endif
b += ret;
(void) alarm( (unsigned) ( 10 + (n >> 7)) );
}
(void) alarm(0);
return(SUCCESS);
}
void
xlatecntl(role, cntl)
int role;
int cntl;
{
static char *cntltype[4] = {"CNTL, ", "ALT, ", "DATA, ", "SHORT, "};
static char *cntlxxx[8] = {"ZERO, ", "CLOSE, ", "RJ, ", "SRJ, ",
"RR, ", "INITC, ", "INITB, ", "INITA, "};
char dbgbuf[128];
char *ptr;
ptr = dbgbuf;
strcpy(ptr, role ? "send " : "recv ");
ptr += strlen(ptr);
strcpy(ptr, cntltype[(cntl&0300)>>6]);
ptr += strlen(ptr);
if (cntl&0300) {
if (role)
sprintf(ptr, "loc %o, rem %o\n", (cntl & 070) >> 3, cntl & 7);
else
sprintf(ptr, "loc %o, rem %o\n", cntl & 7, (cntl & 070) >> 3);
} else {
strcpy(ptr, cntlxxx[(cntl&070)>>3]);
ptr += strlen(ptr);
sprintf(ptr, "val %o\n", cntl & 7);
}
DEBUG(1, dbgbuf, 0);
}