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[] = "@(#)pk0.c 5.10 (Berkeley) 04/24/91"; 10 #endif /* not lint */ 11 12 #include "uucp.h" 13 #include "pk.h" 14 15 /* 16 * packet driver 17 */ 18 19 char next[8] = { 1, 2, 3, 4, 5, 6, 7, 0}; /* packet sequence numbers */ 20 char mask[8] = { 1, 2, 4, 010, 020, 040, 0100, 0200 }; 21 22 struct pack *pklines[NPLINES]; 23 24 int Reacks; 25 26 #define PKRTIME 4 27 #define PKWTIME 4 28 #define PKRSKEW 3 29 #define PKWSKEW 2 30 extern int pktimeout, pktimeskew, Ntimeout; 31 32 /* 33 * receive control messages 34 */ 35 pkcntl(c, pk) 36 register struct pack *pk; 37 { 38 register cntl, val; 39 40 val = c & MOD8; 41 cntl = (c>>3) & MOD8; 42 43 if (!ISCNTL(c)) { 44 logent("PK0", "not cntl"); 45 return; 46 } 47 48 switch(cntl) { 49 case INITB: 50 val++; 51 pk->p_xsize = pksizes[val]; 52 pk->p_lpsize = val; 53 pk->p_bits = 1; 54 if (pk->p_state & LIVE) { 55 pk->p_msg |= M_INITC; 56 break; 57 } 58 pk->p_state |= INITb; 59 if ((pk->p_state & INITa)==0) { 60 break; 61 } 62 pk->p_rmsg &= ~M_INITA; 63 pk->p_msg |= M_INITC; 64 break; 65 66 case INITC: 67 if ((pk->p_state&INITab)==INITab) { 68 pk->p_state = LIVE; 69 pk->p_rmsg &= ~M_INITB; 70 } else 71 pk->p_msg |= M_INITB; 72 if (val) 73 pk->p_swindow = val; 74 break; 75 case INITA: 76 if (val == 0 && pk->p_state&LIVE) { 77 logent("PK0", "alloc change not implemented"); 78 break; 79 } 80 if (val) { 81 pk->p_state |= INITa; 82 pk->p_msg |= M_INITB; 83 pk->p_rmsg |= M_INITB; 84 pk->p_swindow = val; 85 } 86 break; 87 case RJ: 88 pk->p_state |= RXMIT; 89 pk->p_msg |= M_RR; 90 pk->p_rpr = val; 91 (void) pksack(pk); 92 break; 93 case RR: 94 pk->p_rpr = val; 95 if (pk->p_rpr == pk->p_ps) { 96 DEBUG(9, "Reack count is %d\n", ++Reacks); 97 if (Reacks >= 4) { 98 DEBUG(6, "Reack overflow on %d\n", val); 99 pk->p_state |= RXMIT; 100 pk->p_msg |= M_RR; 101 Reacks = 0; 102 } 103 } else { 104 Reacks = 0; 105 (void) pksack(pk); 106 } 107 break; 108 case SRJ: 109 logent("PK0", "srj not implemented"); 110 break; 111 case CLOSE: 112 pk->p_state = DOWN+RCLOSE; 113 return; 114 } 115 if (pk->p_msg) 116 pkoutput(pk); 117 } 118 119 pkaccept(pk) 120 register struct pack *pk; 121 { 122 register x, seq; 123 char m, cntl, *p, imask, **bp; 124 int bad, accept, skip, t, cc; 125 unsigned short sum; 126 127 bad = accept = skip = 0; 128 /* 129 * wait for input 130 */ 131 x = next[pk->p_pr]; 132 while ((imask=pk->p_imap) == 0 && pk->p_rcount == 0) { 133 pkgetpack(pk); 134 } 135 pk->p_imap = 0; 136 137 /* 138 * determine input window in m. 139 */ 140 t = (~(-1<<(int)(pk->p_rwindow))) <<x; 141 m = t; 142 m |= t>>8; 143 144 /* 145 * mark newly accepted input buffers 146 */ 147 for(x=0; x<8; x++) { 148 if ((imask & mask[x]) == 0) 149 continue; 150 151 if (((cntl=pk->p_is[x])&0200) == 0) { 152 bad++; 153 free: 154 bp = (char **)pk->p_ib[x]; 155 *bp = (char *)pk->p_ipool; 156 pk->p_ipool = bp; 157 pk->p_is[x] = 0; 158 continue; 159 } 160 161 pk->p_is[x] = ~(B_COPY+B_MARK); 162 sum = (unsigned)chksum(pk->p_ib[x], pk->p_rsize) ^ (unsigned)(cntl&0377); 163 sum += pk->p_isum[x]; 164 if (sum == CHECK) { 165 seq = (cntl>>3) & MOD8; 166 if (m & mask[seq]) { 167 if (pk->p_is[seq] & (B_COPY | B_MARK)) { 168 dup: 169 pk->p_msg |= M_RR; 170 skip++; 171 goto free; 172 } 173 if (x != seq) { 174 p = pk->p_ib[x]; 175 pk->p_ib[x] = pk->p_ib[seq]; 176 pk->p_is[x] = pk->p_is[seq]; 177 pk->p_ib[seq] = p; 178 } 179 pk->p_is[seq] = B_MARK; 180 accept++; 181 cc = 0; 182 if (cntl&B_SHORT) { 183 pk->p_is[seq] = B_MARK+B_SHORT; 184 p = pk->p_ib[seq]; 185 cc = (unsigned)*p++ & 0377; 186 if (cc & 0200) { 187 cc &= 0177; 188 cc |= *p << 7; 189 } 190 } 191 pk->p_isum[seq] = pk->p_rsize - cc; 192 } else { 193 goto dup; 194 } 195 } else { 196 bad++; 197 goto free; 198 } 199 } 200 201 /* 202 * scan window again turning marked buffers into 203 * COPY buffers and looking for missing sequence 204 * numbers. 205 */ 206 accept = 0; 207 t = -1; 208 for(x=next[pk->p_pr]; m & mask[x]; x = next[x]) { 209 if (pk->p_is[x] & B_MARK) 210 pk->p_is[x] |= B_COPY; 211 212 if (pk->p_is[x] & B_COPY) { 213 if (t >= 0) { 214 bp = (char **)pk->p_ib[x]; 215 *bp = (char *)pk->p_ipool; 216 pk->p_ipool = bp; 217 pk->p_is[x] = 0; 218 skip++; 219 } else 220 accept++; 221 } else { 222 if (t<0) 223 t = x; 224 } 225 } 226 227 if (bad) { 228 pk->p_msg |= M_RJ; 229 } 230 231 if (skip) { 232 pk->p_msg |= M_RR; 233 } 234 235 pk->p_rcount = accept; 236 return accept; 237 } 238 239 /*ARGSUSED*/ 240 pkread(pk, ibuf, icount) 241 register struct pack *pk; 242 char *ibuf; 243 int icount; 244 { 245 register x; 246 int is, cc, xfr, count; 247 char *cp, **bp; 248 249 xfr = 0; 250 count = 0; 251 pktimeout = PKRTIME; 252 pktimeskew = PKRSKEW; 253 Ntimeout = 0; 254 while (pkaccept(pk) == 0) 255 ; 256 257 while (icount) { 258 x = next[pk->p_pr]; 259 is = pk->p_is[x]; 260 261 if (is & B_COPY) { 262 cc = MIN(pk->p_isum[x], icount); 263 if (cc==0 && xfr) { 264 break; 265 } 266 if (is & B_RESID) 267 cp = pk->p_rptr; 268 else { 269 cp = pk->p_ib[x]; 270 if (is & B_SHORT) { 271 if (*cp++ & 0200) 272 cp++; 273 } 274 } 275 bcopy(cp, ibuf, cc); 276 ibuf += cc; 277 icount -= cc; 278 count += cc; 279 xfr++; 280 pk->p_isum[x] -= cc; 281 if (pk->p_isum[x] == 0) { 282 pk->p_pr = x; 283 bp = (char **)pk->p_ib[x]; 284 *bp = (char *)pk->p_ipool; 285 pk->p_ipool = bp; 286 pk->p_is[x] = 0; 287 pk->p_rcount--; 288 pk->p_msg |= M_RR; 289 } else { 290 pk->p_rptr = cp+cc; 291 pk->p_is[x] |= B_RESID; 292 } 293 if (cc==0) 294 break; 295 } else 296 break; 297 } 298 pkoutput(pk); 299 return count; 300 } 301 302 /*ARGSUSED*/ 303 pkwrite(pk, ibuf, icount) 304 register struct pack *pk; 305 char *ibuf; 306 int icount; 307 { 308 register x; 309 int partial; 310 caddr_t cp; 311 int cc, fc, count; 312 313 if (pk->p_state&DOWN || !pk->p_state&LIVE) { 314 return -1; 315 } 316 317 pktimeout = PKWTIME; 318 pktimeskew = PKWSKEW; 319 Ntimeout = 0; 320 count = icount; 321 do { 322 while (pk->p_xcount>=pk->p_swindow) { 323 pkoutput(pk); 324 pkgetpack(pk); 325 } 326 x = next[pk->p_pscopy]; 327 while (pk->p_os[x]!=B_NULL) { 328 pkgetpack(pk); 329 } 330 pk->p_os[x] = B_MARK; 331 pk->p_pscopy = x; 332 pk->p_xcount++; 333 334 cp = pk->p_ob[x] = malloc((unsigned)pk->p_xsize); 335 partial = 0; 336 if ((int)icount < pk->p_xsize) { 337 cc = icount; 338 fc = pk->p_xsize - cc; 339 *cp = fc&0177; 340 if (fc > 127) { 341 *cp++ |= 0200; 342 *cp++ = fc>>7; 343 } else 344 cp++; 345 partial = B_SHORT; 346 } else 347 cc = pk->p_xsize; 348 bcopy(ibuf, cp, cc); 349 ibuf += cc; 350 icount -= cc; 351 pk->p_osum[x] = chksum(pk->p_ob[x], pk->p_xsize); 352 pk->p_os[x] = B_READY+partial; 353 pkoutput(pk); 354 } while (icount); 355 356 return count; 357 } 358 359 pksack(pk) 360 register struct pack *pk; 361 { 362 register x, i; 363 364 i = 0; 365 for(x=pk->p_ps; x!=pk->p_rpr; ) { 366 x = next[x]; 367 if (pk->p_os[x]&B_SENT) { 368 i++; 369 pk->p_os[x] = B_NULL; 370 pk->p_state &= ~WAITO; 371 pk->p_xcount--; 372 free((char *)pk->p_ob[x]); 373 pk->p_ps = x; 374 } 375 } 376 return i; 377 } 378 379 pkoutput(pk) 380 register struct pack *pk; 381 { 382 register x; 383 int i; 384 char bstate; 385 386 if (pk->p_obusy++) { 387 pk->p_obusy--; 388 return; 389 } 390 391 /* 392 * find seq number and buffer state 393 * of next output packet 394 */ 395 if (pk->p_state&RXMIT) { 396 pk->p_nxtps = next[pk->p_rpr]; 397 } 398 x = pk->p_nxtps; 399 bstate = pk->p_os[x]; 400 401 /* 402 * Send control packet if indicated 403 */ 404 if (pk->p_msg) { 405 if (pk->p_msg & ~M_RR || !(bstate&B_READY) ) { 406 x = pk->p_msg; 407 for(i=0; i<8; i++) 408 if (x&1) 409 break; 410 else 411 x >>= 1; 412 x = i; 413 x <<= 3; 414 switch(i) { 415 case CLOSE: 416 break; 417 case RJ: 418 case RR: 419 x += pk->p_pr; 420 break; 421 case SRJ: 422 break; 423 case INITB: 424 x += pksize(pk->p_rsize); 425 break; 426 case INITC: 427 x += pk->p_rwindow; 428 break; 429 case INITA: 430 x += pk->p_rwindow; 431 break; 432 } 433 434 pk->p_msg &= ~mask[i]; 435 pkxstart(pk, x, -1); 436 goto out; 437 } 438 } 439 440 441 /* 442 * Don't send data packets if line is marked dead. 443 */ 444 if (pk->p_state&DOWN) { 445 goto out; 446 } 447 /* 448 * Start transmission (or retransmission) of data packets. 449 */ 450 if (bstate & (B_READY|B_SENT)) { 451 char seq; 452 453 bstate |= B_SENT; 454 seq = x; 455 pk->p_nxtps = next[x]; 456 457 x = 0200+pk->p_pr+(seq<<3); 458 if (bstate & B_SHORT) 459 x |= 0100; 460 pkxstart(pk, x, seq); 461 pk->p_os[seq] = bstate; 462 pk->p_state &= ~RXMIT; 463 goto out; 464 } 465 /* 466 * enable timeout if there's nothing to send 467 * and transmission buffers are languishing 468 */ 469 if (pk->p_xcount) { 470 pk->p_state |= WAITO; 471 } else 472 pk->p_state &= ~WAITO; 473 out: 474 pk->p_obusy = 0; 475 } 476 477 /* 478 * shut down line by 479 * ignoring new input 480 * letting output drain 481 * releasing space and turning off line discipline 482 */ 483 /*ARGSUSED*/ 484 pkclose(pk) 485 register struct pack *pk; 486 { 487 register i; 488 char **bp; 489 int rcheck = 0; 490 491 pk->p_state |= DRAINO; 492 493 /* 494 * try to flush output 495 */ 496 i = 0; 497 while (pk->p_xcount && pk->p_state&LIVE) { 498 if (pk->p_state&(RCLOSE+DOWN) || ++i > 2) 499 break; 500 pkoutput(pk); 501 } 502 pk->p_state |= DOWN; 503 504 /* 505 * try to exchange CLOSE messages 506 */ 507 i = 0; 508 while ((pk->p_state&RCLOSE)==0 && i<2) { 509 pk->p_msg = M_CLOSE; 510 pkoutput(pk); 511 i++; 512 } 513 514 for(i=0;i<NPLINES;i++) 515 if (pklines[i]==pk) { 516 pklines[i] = NULL; 517 } 518 519 /* 520 * free space 521 */ 522 rcheck = 0; 523 for (i=0;i<8;i++) { 524 if (pk->p_os[i] != B_NULL) { 525 free((char *)pk->p_ob[i]); 526 pk->p_xcount--; 527 } 528 if (pk->p_is[i] != B_NULL) { 529 free((char *)pk->p_ib[i]); 530 rcheck++; 531 } 532 } 533 while (pk->p_ipool != NULL) { 534 bp = pk->p_ipool; 535 pk->p_ipool = (char **)*bp; 536 rcheck++; 537 free((char *)bp); 538 } 539 if (rcheck != pk->p_rwindow) { 540 syslog(LOG_WARNING, "%s: pk0: rc %d rw %d", Rmtname, rcheck, 541 pk->p_rwindow); 542 } 543 free((char *)pk); 544 } 545 546 pkreset(pk) 547 register struct pack *pk; 548 { 549 550 pk->p_ps = pk->p_pr = pk->p_rpr = 0; 551 pk->p_nxtps = 1; 552 } 553 554 #ifndef BSD4_2 555 bzero(s,n) 556 register char *s; 557 register n; 558 { 559 while (n--) 560 *s++ = 0; 561 } 562 #endif !BSD4_2 563 564 pksize(n) 565 register n; 566 { 567 register k; 568 569 n >>= 5; 570 for(k=0; n >>= 1; k++) 571 ; 572 return k; 573 } 574