/* /sccs/src/cmd/uucp/s.pk1.c pk1.c 1.2 8/30/84 17:37:38 */ #include "uucp.h" VERSION(@(#)pk1.c 1.2); #define USER 1 #include "pk.h" #include <sys/buf.h> /* ** Code added to allow translation of states from numbers to ** letters, to be done in such a way as to be meaningful to ** John Q. Public */ 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", }; #define PKMAXSTMSG 40 extern int Errorrate; int Connodata = 0; /* Continuous Non Valid Data Count */ int Ntimeout = 0; #define CONNODATA 20 /* Max Continuous Non Valid Data Count */ #define NTIMEOUT 50 /* This is not currently used, but maybe future */ /* * packet driver support routines * */ extern struct pack *pklines[]; /* * start initial synchronization. */ struct pack * pkopen(ifn, ofn) int ifn, ofn; { register struct pack *pk; register char **bp; register int i; char *malloc(); if (++pkactive >= NPLINES) return(NULL); if ((pk = (struct pack *) malloc(sizeof (struct pack))) == NULL) return(NULL); pkzero((caddr_t) pk, sizeof (struct pack)); pk->p_ifn = ifn; pk->p_ofn = ofn; pk->p_xsize = pk->p_rsize = PACKSIZE; pk->p_rwindow = pk->p_swindow = WINDOWS; /* * allocate input window */ 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; /* * start synchronization */ pk->p_msg = pk->p_rmsg = M_INITA; for (i = 0; i < NPLINES; i++) { if (pklines[i] == NULL) { pklines[i] = pk; break; } } if (i >= NPLINES) return(NULL); 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); } /* * input framing and block checking. * frame layout for most devices is: * * S|K|X|Y|C|Z| ... data ... | * * where S == initial synch byte * K == encoded frame size (indexes pksizes[]) * X, Y == block check bytes * C == control byte * Z == XOR of header (K^X^Y^C) * data == 0 or more data bytes * */ #define GETRIES 10 #define GESYN 4100 /* overkill */ /* * Pseudo-dma byte collection. */ pkgetpack(ipk) register struct pack *ipk; { register char *p; register struct pack *pk; register struct header *h; unsigned short sum; int i, ret, k, tries, ifn, notsyn; char **bp, hdchk, msgline[80], delimc; pk = ipk; if ((pk->p_state & DOWN) || Connodata > CONNODATA /* || Ntimeout > NTIMEOUT */ ) pkfail(); ifn = pk->p_ifn; /*= * find HEADER */ for (tries = 0, notsyn = 0; tries < GETRIES && notsyn < GESYN; ) { p = (caddr_t) &pk->p_ihbuf; if ((ret = pkcget(ifn, p, 1)) < 0) { /* * set up retransmit or REJ */ tries++; 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); continue; } if (*p != SYN) { notsyn++; continue; } p++; ret = pkcget(ifn, p, HDRSIZ - 1); if (ret == -1) continue; break; } if (tries >= GETRIES) { DEBUG(4, "tries = %d\n", tries); pkfail(); } if (notsyn >= GESYN) { DEBUG(4, "notsyn = %d\n", notsyn); pkfail(); } Connodata++; DEBUG(9, "pkgetpack: Connodata=%d\n", Connodata); h = (struct header * ) &pk->p_ihbuf; p = (caddr_t) h; hdchk = p[1] ^ p[2] ^ p[3] ^ p[4]; p += 2; sum = (unsigned) *p++ & 0377; sum |= (unsigned) *p << 8; h->sum = sum; DEBUG(9, "rec h->cntl %o\n", (unsigned) h->cntl); k = h->ksize; if (hdchk != h->ccntl) { /* * bad header */ DEBUG(7, "bad header %o,", hdchk); DEBUG(7, "h->ccntl %o\n", h->ccntl); return; } if (k == 9) { if (h->sum + h->cntl == CHECK) { pkcntl(h->cntl, pk); /* ** New code added to make the state diagnostics ** meaningful to human beings that can't figure ** out bizarre, silly, cryptic numbers. ** ** Exhibit A: DEBUG(7, "state - %o\n", pk->p_state); */ if(Debug >= 7) { sprintf(msgline,"state -"); delimc = ' '; for(i=0;st_trans[i].state!= -1;i++) { if(pk->p_state&st_trans[i].state){ sprintf(msgline,"%s%c[%s]",msgline,delimc, st_trans[i].msg); delimc = '&'; } } sprintf(msgline,"%s (%o)\n",msgline,pk->p_state); DEBUG(7,"%s",msgline); } } else { /* * bad header */ DEBUG(7, "bad header %o\n", h->cntl); pk->p_state |= BADFRAME; } return; } if (k && pksizes[k] == pk->p_rsize) { pk->p_rpr = h->cntl & MOD8; pksack(pk); if ((bp = pk->p_ipool) == NULL) { DEBUG(7, "bp NULL %s\n", ""); return; } pk->p_ipool = (char **) *bp; ret = pkcget(pk->p_ifn, (char *) bp, pk->p_rsize); if (ret == 0) pkdata(h->cntl, h->sum, pk, bp); } } pkdata(c, sum, pk, bp) register struct pack *pk; unsigned short sum; char c; char **bp; { register 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; return; } #define PKMAXBUF 128 /* * Start transmission on output device * device associated with pk. * For asynch devices (t_line==1) framing is * imposed. For devices with framing and crc * in the driver (t_line==2) the transfer is * passed on to the driver. */ pkxstart(pk, cntl, x) register struct pack *pk; int x; char cntl; { register char *p; register short checkword; register char hdchk; int ret; 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; /* * writes */ DEBUG(9, "send %o\n", (unsigned) cntl); p = (caddr_t) & pk->p_ohbuf; if (x < 0) { ret = write(pk->p_ofn, p, HDRSIZ); PKASSERT(ret == HDRSIZ, "PKXSTART ret", "", ret); } else { register char *b, *q; register int i; char buf[PKMAXBUF + HDRSIZ]; /* for (i = 0, b = buf; i < HDRSIZ; i++) *b++ = *p++; for (i = 0, p = pk->p_ob[x]; i < pk->p_xsize; i++) *b++ = *p++; */ i = HDRSIZ; b = buf; q = p; do *b++ = *q++; while(--i); if(i = pk->p_xsize){ q = pk->p_ob[x]; do *b++ = *q++; while(--i); } ret = write(pk->p_ofn, buf, pk->p_xsize + HDRSIZ); PKASSERT(ret == pk->p_xsize + HDRSIZ, "PKXSTART ret", "", ret); } if (pk->p_msg) pkoutput(pk); return; } /* * get n characters from input * b -> buffer for characters * fn -> file descriptor * n -> requested number of characters * return: * n -> number of characters returned * 0 -> end of file */ jmp_buf Getjbuf; cgalarm() { longjmp(Getjbuf, 1); } int npkccall, npkctry, npkcnap, npkcchar; pkcget(fn, b, n) register int n; register char *b; register int fn; { register int ret; register int donap; if (n == 0) return(0); npkccall++; donap = (linebaudrate > 0 && linebaudrate < 4800); if (setjmp(Getjbuf)) { Ntimeout++; DEBUG(4, "alarm %d\n", Ntimeout); return(-1); } (void) signal(SIGALRM, cgalarm); (void) alarm((unsigned) (n < HDRSIZ ? 10 : 20)); while (1) { if ((ret = read(fn, b, n)) == 0) { (void) alarm(0); return(-1); } npkctry++; npkcchar += ret; PKASSERT(ret > 0, "PKCGET READ", "", ret); if ((n -= ret) <= 0) break; #ifdef PKSPEEDUP if (donap) { sleep(1); npkcnap++; } #endif PKSPEEDUP b += ret; } (void) alarm(0); return(0); }