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