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