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