1 /*- 2 * Copyright (c) 1985 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)pk1.c 5.13 (Berkeley) 04/24/91"; 10 #endif /* not lint */ 11 12 #include <signal.h> 13 #include "uucp.h" 14 #include "pk.h" 15 #include <setjmp.h> 16 #ifdef BSD4_2 17 #include <sys/time.h> 18 #include <sys/uio.h> 19 #else /* !BSD4_2 */ 20 struct iovec { 21 caddr_t iov_base; 22 int iov_len; 23 } 24 #endif /* !BSD4_2 */ 25 26 #ifdef VMS 27 #include <eunice/eunice.h> 28 #include <vms/iodef.h> 29 #include <vms/ssdef.h> 30 int iomask[2]; 31 #endif VMS 32 33 #define PKMAXSTMSG 40 34 #define MAXPKTIME 32 /* was 16 */ 35 #define CONNODATA 10 36 #define MAXTIMEOUT 32 37 38 extern int errno; 39 extern int Retries; 40 extern char *sys_errlist[]; 41 extern jmp_buf Sjbuf; 42 extern char *malloc(); 43 44 int Connodata = 0; 45 int Ntimeout = 0; 46 int pktimeout = 4; 47 int pktimeskew = 2; 48 /* 49 * packet driver support routines 50 * 51 */ 52 53 extern struct pack *pklines[]; 54 55 /* 56 * start initial synchronization. 57 */ 58 59 struct pack * 60 pkopen(ifn, ofn) 61 int ifn, ofn; 62 { 63 register struct pack *pk; 64 register char **bp; 65 register int i; 66 67 if ((pk = (struct pack *) malloc(sizeof (struct pack))) == NULL) 68 return NULL; 69 bzero((caddr_t) pk, sizeof (struct pack)); 70 pk->p_ifn = ifn; 71 pk->p_ofn = ofn; 72 pk->p_xsize = pk->p_rsize = PACKSIZE; 73 pk->p_rwindow = pk->p_swindow = WINDOWS; 74 /* allocate input windows */ 75 for (i = 0; i < pk->p_rwindow; i++) { 76 if ((bp = (char **) malloc((unsigned)pk->p_xsize)) == NULL) 77 break; 78 *bp = (char *) pk->p_ipool; 79 pk->p_ipool = bp; 80 } 81 if (i == 0) { 82 DEBUG(1, "pkopen: can't malloc i = 0\n", CNULL); 83 return NULL; 84 } 85 pk->p_rwindow = i; 86 87 /* start synchronization */ 88 pk->p_msg = pk->p_rmsg = M_INITA; 89 for (i = 0; i < NPLINES; i++) { 90 if (pklines[i] == NULL) { 91 pklines[i] = pk; 92 break; 93 } 94 } 95 if (i >= NPLINES) { 96 DEBUG(1,"pkopen: i>=NPLINES\n", CNULL); 97 return NULL; 98 } 99 pkoutput(pk); 100 101 for (i = 0; i < PKMAXSTMSG; i++) { 102 pkgetpack(pk); 103 if ((pk->p_state & LIVE) != 0) 104 break; 105 } 106 if (i >= PKMAXSTMSG) { 107 DEBUG(1, "pkopen: i>= PKMAXSTMSG\n", CNULL); 108 return NULL; 109 } 110 111 pkreset(pk); 112 return pk; 113 } 114 115 116 /* 117 * input framing and block checking. 118 * frame layout for most devices is: 119 * 120 * S|K|X|Y|C|Z| ... data ... | 121 * 122 * where S == initial synch byte 123 * K == encoded frame size (indexes pksizes[]) 124 * X, Y == block check bytes 125 * C == control byte 126 * Z == XOR of header (K^X^Y^C) 127 * data == 0 or more data bytes 128 * 129 */ 130 131 int pksizes[] = { 132 1, 32, 64, 128, 256, 512, 1024, 2048, 4096, 1 133 }; 134 135 #define GETRIES 10 136 /* 137 * Pseudo-dma byte collection. 138 */ 139 140 pkgetpack(pk) 141 register struct pack *pk; 142 { 143 int k, tries, noise; 144 register char *p; 145 register struct header *h; 146 unsigned short sum; 147 int ifn; 148 char **bp; 149 char hdchk; 150 151 if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > MAXTIMEOUT) 152 pkfail(); 153 ifn = pk->p_ifn; 154 155 /* find HEADER */ 156 for (tries = 0, noise = 0; tries < GETRIES; ) { 157 p = (caddr_t) &pk->p_ihbuf; 158 if (pkcget(ifn, p, 1) == SUCCESS) { 159 if (*p++ == SYN) { 160 if (pkcget(ifn, p, HDRSIZ-1) == SUCCESS) 161 break; 162 } else { 163 if (noise++ < 10 || noise < (3*pk->p_rsize)) 164 continue; 165 } 166 DEBUG(4, "Noisy line - set up RXMIT\n", CNULL); 167 noise = 0; 168 } 169 /* set up retransmit or REJ */ 170 tries++; 171 Retries++; 172 pk->p_msg |= pk->p_rmsg; 173 if (pk->p_msg == 0) 174 pk->p_msg |= M_RR; 175 if ((pk->p_state & LIVE) == LIVE) 176 pk->p_state |= RXMIT; 177 pkoutput(pk); 178 } 179 if (tries >= GETRIES) { 180 DEBUG(4, "tries = %d\n", tries); 181 pkfail(); 182 } 183 184 Connodata++; 185 h = (struct header *) &pk->p_ihbuf; 186 p = (caddr_t) h; 187 hdchk = p[1] ^ p[2] ^ p[3] ^ p[4]; 188 p += 2; 189 sum = (unsigned) *p++ & 0377; 190 sum |= (unsigned) *p << 8; 191 h->sum = sum; 192 DEBUG(7, "rec h->cntl 0%o\n", h->cntl&0xff); 193 k = h->ksize; 194 if (hdchk != h->ccntl) { 195 /* bad header */ 196 DEBUG(7, "bad header 0%o,", hdchk&0xff); 197 DEBUG(7, "h->ccntl 0%o\n", h->ccntl&0xff); 198 return; 199 } 200 if (k == 9) { 201 if (((h->sum + h->cntl) & 0xffff) == CHECK) { 202 pkcntl(h->cntl, pk); 203 DEBUG(7, "state - 0%o\n", pk->p_state); 204 } else { 205 /* bad header */ 206 pk->p_state |= BADFRAME; 207 DEBUG(7, "bad header (k==9) 0%o\n", h->cntl&0xff); 208 } 209 return; 210 } 211 if (k && pksizes[k] == pk->p_rsize) { 212 pk->p_rpr = h->cntl & MOD8; 213 DEBUG(7, "end pksack 0%o\n", pk->p_rpr); 214 pksack(pk); 215 bp = pk->p_ipool; 216 if (bp == NULL) { 217 DEBUG(7, "bp NULL %s\n", ""); 218 return; 219 } 220 pk->p_ipool = (char **) *bp; 221 Connodata = 0; 222 } else 223 return; 224 225 if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) { 226 pkdata(h->cntl, h->sum, pk, (char **) bp); 227 } else { 228 *bp = (char *)pk->p_ipool; 229 pk->p_ipool = bp; 230 } 231 } 232 233 pkdata(c, sum, pk, bp) 234 char c; 235 unsigned short sum; 236 register struct pack *pk; 237 char **bp; 238 { 239 register x; 240 register int t; 241 242 if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) { 243 pk->p_msg |= pk->p_rmsg; 244 pkoutput(pk); 245 goto drop; 246 } 247 t = next[pk->p_pr]; 248 for(x = pk->p_pr; x != t; x = (x-1)&7) { 249 if (pk->p_is[x] == 0) { 250 pk->p_imap |= mask[x]; 251 pk->p_is[x] = c; 252 pk->p_isum[x] = sum; 253 pk->p_ib[x] = (char *)bp; 254 return; 255 } 256 } 257 drop: 258 *bp = (char *)pk->p_ipool; 259 pk->p_ipool = bp; 260 } 261 262 /* 263 * setup input transfers 264 * 265 * Start transmission on output device associated with pk. 266 * For asynch devices (t_line==1) framing is 267 * imposed. For devices with framing and crc 268 * in the driver (t_line==2) the transfer is 269 * passed on to the driver. 270 */ 271 pkxstart(pk, cntl, x) 272 register struct pack *pk; 273 char cntl; 274 register x; 275 { 276 register char *p; 277 short checkword; 278 char hdchk; 279 280 p = (caddr_t) &pk->p_ohbuf; 281 *p++ = SYN; 282 if (x < 0) { 283 *p++ = hdchk = 9; 284 checkword = cntl; 285 } else { 286 *p++ = hdchk = pk->p_lpsize; 287 checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377); 288 } 289 checkword = CHECK - checkword; 290 *p = checkword; 291 hdchk ^= *p++; 292 *p = checkword>>8; 293 hdchk ^= *p++; 294 *p = cntl; 295 hdchk ^= *p++; 296 *p = hdchk; 297 /* writes */ 298 DEBUG(7, "send 0%o\n", cntl&0xff); 299 p = (caddr_t) & pk->p_ohbuf; 300 if (x < 0) { 301 if(write(pk->p_ofn, p, HDRSIZ) != HDRSIZ) { 302 alarm(0); 303 logent("PKXSTART write failed", sys_errlist[errno]); 304 longjmp(Sjbuf, 4); 305 } 306 } else { 307 struct iovec iov[2]; 308 309 iov[0].iov_base = p; 310 iov[0].iov_len = HDRSIZ; 311 iov[1].iov_base = pk->p_ob[x]; 312 iov[1].iov_len = pk->p_xsize; 313 314 if (writev(pk->p_ofn, iov, 2) < 0) { 315 alarm(0); 316 logent("PKXSTART write failed", sys_errlist[errno]); 317 longjmp(Sjbuf, 5); 318 } 319 #ifdef 0 320 char buf[PKMAXBUF + HDRSIZ], *b; 321 int i; 322 for (i = 0, b = buf; i < HDRSIZ; i++) 323 *b++ = *p++; 324 for (i = 0, p = pk->p_ob[x]; i < pk->p_xsize; i++) 325 *b++ = *p++; 326 327 if (write(pk->p_ofn, buf, pk->p_xsize + HDRSIZ) 328 != (HDRSIZ + pk->p_xsize)) { 329 alarm(0); 330 logent("PKXSTART write failed", sys_errlist[errno]); 331 longjmp(Sjbuf, 5); 332 } 333 #endif 0 334 Connodata = 0; 335 } 336 if (pk->p_msg) 337 pkoutput(pk); 338 } 339 340 /* 341 * get n characters from input 342 * 343 * return codes: 344 * n - number of characters returned 345 * 0 - end of file 346 */ 347 348 jmp_buf Getjbuf; 349 void 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(sys_errlist[errno],"FAILED pkcget Read"); 423 longjmp(Sjbuf, 6); 424 } 425 b += ret; 426 n -= ret; 427 } 428 alarm(0); 429 return SUCCESS; 430 } 431