1: #if !defined(lint) && defined(DOSCCS) 2: static char sccsid[] = "@(#)pk1.c 5.9.2 (2.11BSD) 1997/10/2"; 3: #endif 4: 5: #include <signal.h> 6: #include "uucp.h" 7: #include "pk.h" 8: #include <setjmp.h> 9: #include <errno.h> 10: #include <string.h> 11: #ifdef BSD4_2 12: #include <sys/time.h> 13: #endif BSD4_2 14: 15: #ifdef VMS 16: #include <eunice/eunice.h> 17: #include <vms/iodef.h> 18: #include <vms/ssdef.h> 19: int iomask[2]; 20: #endif VMS 21: 22: #define PKMAXSTMSG 40 23: #define MAXPKTIME 32 /* was 16 */ 24: #define CONNODATA 10 25: #define MAXTIMEOUT 32 26: 27: extern int Retries; 28: extern jmp_buf Sjbuf; 29: 30: int Connodata = 0; 31: int Ntimeout = 0; 32: int pktimeout = 4; 33: int pktimeskew = 2; 34: /* 35: * packet driver support routines 36: * 37: */ 38: 39: extern struct pack *pklines[]; 40: 41: /* 42: * start initial synchronization. 43: */ 44: 45: struct pack * 46: pkopen(ifn, ofn) 47: int ifn, ofn; 48: { 49: register struct pack *pk; 50: register char **bp; 51: register int i; 52: 53: if ((pk = (struct pack *) malloc(sizeof (struct pack))) == NULL) 54: return NULL; 55: bzero((caddr_t) pk, sizeof (struct pack)); 56: pk->p_ifn = ifn; 57: pk->p_ofn = ofn; 58: pk->p_xsize = pk->p_rsize = PACKSIZE; 59: pk->p_rwindow = pk->p_swindow = WINDOWS; 60: /* allocate input windows */ 61: for (i = 0; i < pk->p_rwindow; i++) { 62: if ((bp = (char **) malloc((unsigned)pk->p_xsize)) == NULL) 63: break; 64: *bp = (char *) pk->p_ipool; 65: pk->p_ipool = bp; 66: } 67: if (i == 0) { 68: DEBUG(1, "pkopen: can't malloc i = 0\n", CNULL); 69: return NULL; 70: } 71: pk->p_rwindow = i; 72: 73: /* start synchronization */ 74: pk->p_msg = pk->p_rmsg = M_INITA; 75: for (i = 0; i < NPLINES; i++) { 76: if (pklines[i] == NULL) { 77: pklines[i] = pk; 78: break; 79: } 80: } 81: if (i >= NPLINES) { 82: DEBUG(1,"pkopen: i>=NPLINES\n", CNULL); 83: return NULL; 84: } 85: pkoutput(pk); 86: 87: for (i = 0; i < PKMAXSTMSG; i++) { 88: pkgetpack(pk); 89: if ((pk->p_state & LIVE) != 0) 90: break; 91: } 92: if (i >= PKMAXSTMSG) { 93: DEBUG(1, "pkopen: i>= PKMAXSTMSG\n", CNULL); 94: return NULL; 95: } 96: 97: pkreset(pk); 98: return pk; 99: } 100: 101: 102: /* 103: * input framing and block checking. 104: * frame layout for most devices is: 105: * 106: * S|K|X|Y|C|Z| ... data ... | 107: * 108: * where S == initial synch byte 109: * K == encoded frame size (indexes pksizes[]) 110: * X, Y == block check bytes 111: * C == control byte 112: * Z == XOR of header (K^X^Y^C) 113: * data == 0 or more data bytes 114: * 115: */ 116: 117: int pksizes[] = { 118: 1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 1 119: }; 120: 121: #define GETRIES 10 122: /* 123: * Pseudo-dma byte collection. 124: */ 125: 126: pkgetpack(pk) 127: register struct pack *pk; 128: { 129: int k, tries, noise; 130: register char *p; 131: register struct header *h; 132: unsigned short sum; 133: int ifn; 134: char **bp; 135: char hdchk; 136: 137: if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > MAXTIMEOUT) 138: pkfail(); 139: ifn = pk->p_ifn; 140: 141: /* find HEADER */ 142: for (tries = 0, noise = 0; tries < GETRIES; ) { 143: p = (caddr_t) &pk->p_ihbuf; 144: if (pkcget(ifn, p, 1) == SUCCESS) { 145: if (*p++ == SYN) { 146: if (pkcget(ifn, p, HDRSIZ-1) == SUCCESS) 147: break; 148: } else { 149: if (noise++ < 10 || noise < (3*pk->p_rsize)) 150: continue; 151: } 152: DEBUG(4, "Noisy line - set up RXMIT\n", CNULL); 153: noise = 0; 154: } 155: /* set up retransmit or REJ */ 156: tries++; 157: Retries++; 158: pk->p_msg |= pk->p_rmsg; 159: if (pk->p_msg == 0) 160: pk->p_msg |= M_RR; 161: if ((pk->p_state & LIVE) == LIVE) 162: pk->p_state |= RXMIT; 163: pkoutput(pk); 164: } 165: if (tries >= GETRIES) { 166: DEBUG(4, "tries = %d\n", tries); 167: pkfail(); 168: } 169: 170: Connodata++; 171: h = (struct header *) &pk->p_ihbuf; 172: p = (caddr_t) h; 173: hdchk = p[1] ^ p[2] ^ p[3] ^ p[4]; 174: p += 2; 175: sum = (unsigned) *p++ & 0377; 176: sum |= (unsigned) *p << 8; 177: h->sum = sum; 178: DEBUG(7, "rec h->cntl 0%o\n", h->cntl&0xff); 179: k = h->ksize; 180: if (hdchk != h->ccntl) { 181: /* bad header */ 182: DEBUG(7, "bad header 0%o,", hdchk&0xff); 183: DEBUG(7, "h->ccntl 0%o\n", h->ccntl&0xff); 184: return; 185: } 186: if (k == 9) { 187: if (((h->sum + h->cntl) & 0xffff) == CHECK) { 188: pkcntl(h->cntl, pk); 189: DEBUG(7, "state - 0%o\n", pk->p_state); 190: } else { 191: /* bad header */ 192: pk->p_state |= BADFRAME; 193: DEBUG(7, "bad header (k==9) 0%o\n", h->cntl&0xff); 194: } 195: return; 196: } 197: if (k && pksizes[k] == pk->p_rsize) { 198: pk->p_rpr = h->cntl & MOD8; 199: DEBUG(7, "end pksack 0%o\n", pk->p_rpr); 200: pksack(pk); 201: bp = pk->p_ipool; 202: if (bp == NULL) { 203: DEBUG(7, "bp NULL %s\n", ""); 204: return; 205: } 206: pk->p_ipool = (char **) *bp; 207: Connodata = 0; 208: } else 209: return; 210: 211: if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) { 212: pkdata(h->cntl, h->sum, pk, (char **) bp); 213: } else { 214: *bp = (char *)pk->p_ipool; 215: pk->p_ipool = bp; 216: } 217: } 218: 219: pkdata(c, sum, pk, bp) 220: char c; 221: unsigned short sum; 222: register struct pack *pk; 223: char **bp; 224: { 225: register x; 226: int t; 227: char m; 228: 229: if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) { 230: pk->p_msg |= pk->p_rmsg; 231: pkoutput(pk); 232: goto drop; 233: } 234: t = next[pk->p_pr]; 235: for(x=pk->p_pr; x!=t; x = (x-1)&7) { 236: if (pk->p_is[x] == 0) 237: goto slot; 238: } 239: drop: 240: *bp = (char *)pk->p_ipool; 241: pk->p_ipool = bp; 242: return; 243: 244: slot: 245: m = mask[x]; 246: pk->p_imap |= m; 247: pk->p_is[x] = c; 248: pk->p_isum[x] = sum; 249: pk->p_ib[x] = (char *)bp; 250: } 251: 252: /* 253: * setup input transfers 254: */ 255: #define PKMAXBUF 128 256: /* 257: * Start transmission on output device associated with pk. 258: * For asynch devices (t_line==1) framing is 259: * imposed. For devices with framing and crc 260: * in the driver (t_line==2) the transfer is 261: * passed on to the driver. 262: */ 263: pkxstart(pk, cntl, x) 264: register struct pack *pk; 265: char cntl; 266: register x; 267: { 268: register char *p; 269: short checkword; 270: char hdchk; 271: 272: p = (caddr_t) &pk->p_ohbuf; 273: *p++ = SYN; 274: if (x < 0) { 275: *p++ = hdchk = 9; 276: checkword = cntl; 277: } else { 278: *p++ = hdchk = pk->p_lpsize; 279: checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377); 280: } 281: checkword = CHECK - checkword; 282: *p = checkword; 283: hdchk ^= *p++; 284: *p = checkword>>8; 285: hdchk ^= *p++; 286: *p = cntl; 287: hdchk ^= *p++; 288: *p = hdchk; 289: /* writes */ 290: DEBUG(7, "send 0%o\n", cntl&0xff); 291: p = (caddr_t) & pk->p_ohbuf; 292: if (x < 0) { 293: if(write(pk->p_ofn, p, HDRSIZ) != HDRSIZ) { 294: alarm(0); 295: logent("PKXSTART write failed", strerror(errno)); 296: longjmp(Sjbuf, 4); 297: } 298: } else { 299: char buf[PKMAXBUF + HDRSIZ + TAILSIZE], *b; 300: int i; 301: for (i = 0, b = buf; i < HDRSIZ; i++) 302: *b++ = *p++; 303: for (i = 0, p = pk->p_ob[x]; i < pk->p_xsize; i++) 304: *b++ = *p++; 305: #if TAILSIZE != 0 306: for (i = 0; i < TAILSIZE; i++) 307: *b++ = '\0'; 308: #endif TAILSIZE 309: if (write(pk->p_ofn, buf, pk->p_xsize + HDRSIZ + TAILSIZE) 310: != (HDRSIZ + TAILSIZE + pk->p_xsize)) { 311: alarm(0); 312: logent("PKXSTART write failed", strerror(errno)); 313: longjmp(Sjbuf, 5); 314: } 315: Connodata = 0; 316: } 317: if (pk->p_msg) 318: pkoutput(pk); 319: } 320: 321: 322: pkmove(p1, p2, count, flag) 323: char *p1, *p2; 324: int count, flag; 325: { 326: register char *s, *d; 327: register int i; 328: 329: if (flag == B_WRITE) { 330: s = p2; 331: d = p1; 332: } else { 333: s = p1; 334: d = p2; 335: } 336: for (i = 0; i < count; i++) 337: *d++ = *s++; 338: } 339: 340: 341: /* 342: * get n characters from input 343: * 344: * return codes: 345: * n - number of characters returned 346: * 0 - end of file 347: */ 348: 349: jmp_buf Getjbuf; 350: cgalarm() 351: { 352: longjmp(Getjbuf, 1); 353: } 354: 355: pkcget(fn, b, n) 356: int fn; 357: register char *b; 358: register int n; 359: { 360: register int ret; 361: extern int linebaudrate; 362: #ifdef BSD4_2 363: long r, itime = 100000L; /* guess it's been 1/10th second since we 364: last read the line */ 365: struct timeval tv; 366: #endif BSD4_2 367: #ifdef VMS 368: short iosb[4]; 369: int SYS$QioW(); /* use this for long reads on vms */ 370: #endif VMS 371: 372: if (setjmp(Getjbuf)) { 373: Ntimeout++; 374: DEBUG(4, "pkcget: alarm %d\n", pktimeout * 1000 + Ntimeout); 375: pktimeout += pktimeskew; 376: if (pktimeout > MAXPKTIME) 377: pktimeout = MAXPKTIME; 378: return FAIL; 379: } 380: signal(SIGALRM, cgalarm); 381: 382: alarm(pktimeout); 383: while (n > 0) { 384: #ifdef BSD4_2 385: if (linebaudrate > 0) { 386: r = n * 100000L; 387: r = r / linebaudrate; 388: r = (r * 100) - itime; 389: itime = 0; 390: /* we predict that more than 1/50th of a 391: second will go by before the read will 392: give back all that we want. */ 393: if (r > 20000) { 394: tv.tv_sec = r / 1000000L; 395: tv.tv_usec = r % 1000000L; 396: DEBUG(11, "PKCGET stall for %d", tv.tv_sec); 397: DEBUG(11, ".%06d sec\n", tv.tv_usec); 398: (void) select (0, (int *)0, (int *)0, (int *)0, &tv); 399: } 400: } 401: #endif BSD4_2 402: #ifndef VMS 403: ret = read(fn, b, n); 404: #else VMS 405: _$Cancel_IO_On_Signal = FD_FAB_Pointer[fn]; 406: ret = SYS$QioW(_$EFN,(FD_FAB_Pointer[fn]->fab).fab$l_stv, 407: IO$_READVBLK|IO$M_NOFILTR|IO$M_NOECHO, 408: iosb,0,0,b,n,0, 409: iomask,0,0); 410: _$Cancel_IO_On_Signal = 0; 411: if (ret == SS$_NORMAL) 412: ret = iosb[1]+iosb[3]; /* get length of transfer */ 413: else 414: ret = 0; 415: #endif VMS 416: if (ret == 0) { 417: alarm(0); 418: return FAIL; 419: } 420: if (ret <= 0) { 421: alarm(0); 422: logent(strerror(errno),"FAILED pkcget Read"); 423: longjmp(Sjbuf, 6); 424: } 425: b += ret; 426: n -= ret; 427: } 428: alarm(0); 429: return SUCCESS; 430: }