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