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