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 pkfail(), pkzero(), pkoutput(), pkreset(), pkcntl(), pkgetpack(); 39 extern int pksack(); 40 static void pkdata(); 41 static int pkcget(); 42 43 /* 44 * Code added to allow translation of states from numbers to 45 * letters, to be done in such a way as to be meaningful to 46 * John Q. Public 47 */ 48 struct { 49 int state; 50 char *msg; 51 } st_trans[] = { 52 DEAD, "Dead!", 53 INITa, "INIT code a", 54 INITb, "INIT code b", 55 LIVE, "O.K.", 56 RXMIT, "Rcv/Xmit", 57 RREJ, "RREJ?", 58 PDEBUG, "PDEBUG?", 59 DRAINO, "Draino...", 60 WAITO, "Waiting", 61 DOWN, "Link down", 62 RCLOSE, "RCLOSE?", 63 BADFRAME, "Bad frame", 64 -1, "End of the line", 65 }; 66 67 extern char _Protocol[]; /* Protocol string with (options) */ 68 69 #define PKMAXSTMSG 40 70 int Connodata = 0; /* Continuous Non Valid Data Count */ 71 int Ntimeout = 0; 72 #define CONNODATA 20 /* Max Continuous Non Valid Data Count */ 73 #define NTIMEOUT 50 /* This is not currently used, but maybe future */ 74 75 extern jmp_buf Getjbuf; 76 77 /* 78 * start initial synchronization. 79 */ 80 struct pack * 81 pkopen(ifn, ofn) 82 int ifn, ofn; 83 { 84 register struct pack *pk; 85 register char **bp; 86 register int i; 87 int windows = WINDOWS; 88 extern int xpacksize, packsize; 89 90 if ((pk = (struct pack *) calloc(1, sizeof (struct pack))) == NULL) 91 return(NULL); 92 pk->p_ifn = ifn; 93 pk->p_ofn = ofn; 94 DEBUG(7, "Setting up protocol parameters '%s'\n", _Protocol); 95 if ( _Protocol[1] == '(' ) { 96 if (sscanf(_Protocol, "%*c(%d,%d)", &windows, &packsize) == 0) 97 sscanf(_Protocol, "%*c(,%d)", &packsize); 98 windows = ( windows < MINWINDOWS ? WINDOWS : 99 ( windows > MAXWINDOWS ? WINDOWS : windows ) ); 100 packsize = ( packsize < MINPACKSIZE ? PACKSIZE : 101 ( packsize > MAXPACKSIZE ? PACKSIZE : packsize ) ); 102 } 103 if ( (_Protocol[0] == 'g') && (packsize > OLDPACKSIZE) ) { 104 /* 105 * We reset to OLDPACKSIZE to maintain compatibility 106 * with old limited implementations. Maybe we should 107 * just warn the administrator and continue? 108 */ 109 packsize = OLDPACKSIZE; 110 } 111 pk->p_xsize = pk->p_rsize = xpacksize = packsize; 112 pk->p_rwindow = pk->p_swindow = windows; 113 114 /* 115 * allocate input window 116 */ 117 for (i = 0; i < pk->p_rwindow; i++) { 118 if ((bp = (char **) malloc((unsigned) pk->p_xsize)) == NULL) 119 break; 120 *bp = (char *) pk->p_ipool; 121 pk->p_ipool = bp; 122 } 123 if (i == 0) 124 return(NULL); 125 pk->p_rwindow = i; 126 127 /* 128 * start synchronization 129 */ 130 pk->p_msg = pk->p_rmsg = M_INITA; 131 pkoutput(pk); 132 133 for (i = 0; i < PKMAXSTMSG; i++) { 134 pkgetpack(pk); 135 if ((pk->p_state & LIVE) != 0) 136 break; 137 } 138 if (i >= PKMAXSTMSG) 139 return(NULL); 140 141 pkreset(pk); 142 return(pk); 143 } 144 145 /* 146 * input framing and block checking. 147 * frame layout for most devices is: 148 * 149 * S|K|X|Y|C|Z| ... data ... | 150 * 151 * where S == initial synch byte 152 * K == encoded frame size (indexes pksizes[]) 153 * X, Y == block check bytes 154 * C == control byte 155 * Z == XOR of header (K^X^Y^C) 156 * data == 0 or more data bytes 157 * 158 */ 159 #define GETRIES 10 160 161 /* 162 * Byte collection. 163 */ 164 void 165 pkgetpack(ipk) 166 register struct pack *ipk; 167 { 168 register char *p; 169 register struct pack *pk; 170 register struct header *h; 171 unsigned short sum; 172 int k, tries, ifn, noise; 173 char **bp, hdchk; 174 175 pk = ipk; 176 /* 177 * If we are known to be DOWN, or if we've received too many garbage 178 * packets or timeouts, give up without a fight. 179 */ 180 if ((pk->p_state & DOWN) || Connodata > CONNODATA || Ntimeout > NTIMEOUT) 181 pkfail(); 182 ifn = pk->p_ifn; 183 h = &pk->p_ihbuf; 184 185 /* 186 * Attempt no more than GETRIES times to read a packet. The only valid 187 * exit from this loop is a return. Break forces a failure. 188 */ 189 for (tries = 0; tries < GETRIES; tries++) { 190 /* 191 * Read header. 192 * First look for SYN. If more than 3 * packetsize characters 193 * go by w/o a SYN, request a retransmit. 194 */ 195 p = (caddr_t) h; 196 noise = 0; 197 for ( ; ; ) { 198 if (pkcget(ifn, p, HDRSIZ) != SUCCESS) { 199 DEBUG(7, 200 "Alarm while looking for SYN -- request RXMIT\n%s", ""); 201 goto retransmit; 202 } 203 if (*p == SYN) 204 break; /* got it */ 205 else { 206 char *pp, *pend; 207 208 DEBUG(7, "first char not SYN (%x)\n", *p&0xff); 209 if ((pp = memchr(p, SYN, HDRSIZ)) != NULL) { 210 pend = p + HDRSIZ; 211 while (pp < pend) 212 *p++ = *pp++; 213 /* Now look for remainder of header */ 214 if (pkcget(ifn, p, pend - p) != 215 SUCCESS) { 216 DEBUG(7, 217 "Alarm while looking for header -- request RXMIT\n%s", ""); 218 goto retransmit; 219 } 220 p = (caddr_t) h; 221 break; /* got entire header */ 222 } 223 } 224 if ((noise += HDRSIZ) > 3 * pk->p_rsize) { 225 DEBUG(7, 226 "No SYN in %d characters -- request RXMIT\n", noise); 227 goto retransmit; 228 } 229 } 230 /* Validate the header */ 231 Connodata++; 232 hdchk = p[1] ^ p[2] ^ p[3] ^ p[4]; 233 sum = ((unsigned) p[2] & 0377) | ((unsigned) p[3] << 8); 234 h->sum = sum; 235 k = h->ksize; 236 if (hdchk != h->ccntl) { 237 /* bad header */ 238 DEBUG(7, "bad header checksum\n%s", ""); 239 return; 240 } 241 242 if (k == 9) { /* control packet */ 243 if (((h->sum + h->cntl) & 0xffff) == CHECK) { 244 pkcntl(h->cntl, pk); 245 xlatestate(pk, 7); 246 } else { 247 /* bad header */ 248 DEBUG(7, "bad header (k == 9) 0%o\n", h->cntl&0xff); 249 pk->p_state |= BADFRAME; 250 } 251 return; 252 } 253 /* data packet */ 254 if (k && pksizes[k] != pk->p_rsize) 255 return; 256 pk->p_rpr = h->cntl & MOD8; 257 pksack(pk); 258 if ((bp = pk->p_ipool) == NULL) { 259 DEBUG(7, "bp NULL\n%s", ""); 260 return; 261 } 262 pk->p_ipool = (char **) *bp; 263 /* Header checks out, go for data */ 264 if (pkcget(pk->p_ifn, (char *) bp, pk->p_rsize) == SUCCESS) { 265 pkdata(h->cntl, h->sum, pk, bp); 266 Ntimeout = 0; 267 return; 268 } 269 DEBUG(7, "Alarm while reading data -- request RXMIT\n%s", ""); 270 retransmit: 271 /* 272 * Transmission error or excessive noise. Send a RXMIT 273 * and try again. 274 */ 275 /* 276 Retries++; 277 */ 278 pk->p_msg |= pk->p_rmsg; 279 if (pk->p_msg == 0) 280 pk->p_msg |= M_RR; 281 if ((pk->p_state & LIVE) == LIVE) 282 pk->p_state |= RXMIT; 283 pkoutput(pk); 284 } 285 DEBUG(7, "pkgetpack failed after %d tries\n", tries); 286 pkfail(); 287 } 288 289 /* 290 * Translate pk->p_state into something printable. 291 */ 292 xlatestate(pk, dbglvl) 293 register struct pack *pk; 294 { 295 register int i; 296 char delimc = ' ', msgline[80], *buf = msgline; 297 298 if (Debug < dbglvl) 299 return; 300 sprintf(buf, "state -"); 301 buf += strlen(buf); 302 for(i = 0; st_trans[i].state != -1; i++) { 303 if (pk->p_state&st_trans[i].state){ 304 sprintf(buf, "%c[%s]", delimc, st_trans[i].msg); 305 buf += strlen(buf); 306 delimc = '&'; 307 } 308 } 309 sprintf(buf, " (0%o)\n", pk->p_state); 310 DEBUG(dbglvl, "%s", msgline); 311 } 312 313 static void 314 pkdata(c, sum, pk, bp) 315 register struct pack *pk; 316 unsigned short sum; 317 char c; 318 char **bp; 319 { 320 register x; 321 int t; 322 char m; 323 324 if (pk->p_state & DRAINO || !(pk->p_state & LIVE)) { 325 pk->p_msg |= pk->p_rmsg; 326 pkoutput(pk); 327 goto drop; 328 } 329 t = next[pk->p_pr]; 330 for(x=pk->p_pr; x!=t; x = (x-1)&7) { 331 if (pk->p_is[x] == 0) 332 goto slot; 333 } 334 drop: 335 *bp = (char *)pk->p_ipool; 336 pk->p_ipool = bp; 337 return; 338 339 slot: 340 m = mask[x]; 341 pk->p_imap |= m; 342 pk->p_is[x] = c; 343 pk->p_isum[x] = sum; 344 pk->p_ib[x] = (char *)bp; 345 } 346 347 /* 348 * Start transmission on output device associated with pk. 349 * For asynch devices (t_line==1) framing is 350 * imposed. For devices with framing and crc 351 * in the driver (t_line==2) the transfer is 352 * passed on to the driver. 353 */ 354 void 355 pkxstart(pk, cntl, x) 356 register struct pack *pk; 357 int x; 358 char cntl; 359 { 360 register char *p; 361 register short checkword; 362 register char hdchk; 363 364 p = (caddr_t) &pk->p_ohbuf; 365 *p++ = SYN; 366 if (x < 0) { 367 *p++ = hdchk = 9; 368 checkword = cntl; 369 } else { 370 *p++ = hdchk = pk->p_lpsize; 371 checkword = pk->p_osum[x] ^ (unsigned)(cntl & 0377); 372 } 373 checkword = CHECK - checkword; 374 *p = checkword; 375 hdchk ^= *p++; 376 *p = checkword>>8; 377 hdchk ^= *p++; 378 *p = cntl; 379 hdchk ^= *p++; 380 *p = hdchk; 381 382 /* 383 * writes 384 */ 385 if (Debug >= 9) 386 xlatecntl(1, cntl); 387 388 p = (caddr_t) & pk->p_ohbuf; 389 if (x < 0) { 390 if ((*Write)(pk->p_ofn, p, HDRSIZ) != HDRSIZ) { 391 DEBUG(4, "pkxstart, write failed, %s\n", 392 strerror(errno)); 393 logent(strerror(errno), "PKXSTART WRITE"); 394 pkfail(); 395 /* NOT REACHED */ 396 } 397 } else { 398 char buf[MAXPACKSIZE + HDRSIZ]; 399 400 memcpy(buf, p, HDRSIZ); 401 memcpy(buf+HDRSIZ, pk->p_ob[x], pk->p_xsize); 402 if ((*Write)(pk->p_ofn, buf, pk->p_xsize + HDRSIZ) != 403 pk->p_xsize + HDRSIZ) { 404 DEBUG(4, "pkxstart, write failed, %s\n", 405 strerror(errno)); 406 logent(strerror(errno), "PKXSTART WRITE"); 407 pkfail(); 408 /* NOT REACHED */ 409 } 410 Connodata = 0; 411 } 412 if (pk->p_msg) 413 pkoutput(pk); 414 } 415 416 /* 417 * get n characters from input 418 * b -> buffer for characters 419 * fn -> file descriptor 420 * n -> requested number of characters 421 * return: 422 * SUCCESS -> n chars successfully read 423 * FAIL -> o.w. 424 */ 425 426 static int 427 pkcget(fn, b, n) 428 register int n; 429 register char *b; 430 register int fn; 431 { 432 register int ret; 433 #ifdef PKSPEEDUP 434 extern int linebaudrate; 435 register int donap = (linebaudrate > 0 && linebaudrate < 4800); 436 #endif /* PKSPEEDUP */ 437 438 if (n == 0) 439 return(SUCCESS); 440 if (setjmp(Getjbuf)) { 441 Ntimeout++; 442 DEBUG(4, "pkcget: alarm %d\n", Ntimeout); 443 return(FAIL); 444 } 445 446 (void) alarm( (unsigned) ( 10 + (n >> 7)) ); 447 448 for (;;) { 449 ret = (*Read)(fn, b, n); 450 (void) alarm(0); 451 if (ret == 0) { 452 DEBUG(4, "pkcget, read failed, EOF\n", 0); 453 /* 454 * Device has decided that the connection has no 455 * more data to send. Any further tries are futile... 456 * (The only other way to get a zero return value 457 * is to read a zero length message from a STREAM. 458 * However, uucp *never* sends zero length messages 459 * over any sort of channel...) 460 */ 461 pkfail(); 462 /* NOT REACHED */ 463 } 464 if (ret < 0) { 465 DEBUG(4, "pkcget, read failed, %s\n", 466 strerror(errno)); 467 logent(strerror(errno), "PKCGET READ"); 468 pkfail(); 469 /* NOT REACHED */ 470 } 471 if ((n -= ret) <= 0) 472 break; 473 #ifdef PKSPEEDUP 474 if (donap) { 475 #if defined(BSD4_2) || defined(ATTSVR4) 476 /* wait for more chars to come in */ 477 nap((n * HZ * 10) / linebaudrate); /* n char times */ 478 #else 479 sleep(1); 480 #endif 481 } 482 #endif /* PKSPEEDUP */ 483 b += ret; 484 (void) alarm( (unsigned) ( 10 + (n >> 7)) ); 485 } 486 (void) alarm(0); 487 return(SUCCESS); 488 } 489 490 /* 491 * role == 0: receive 492 * role == 1: send 493 */ 494 xlatecntl(role, cntl) 495 { 496 static char *cntltype[4] = {"CNTL, ", "ALT, ", "DATA, ", "SHORT, "}; 497 static char *cntlxxx[8] = {"ZERO, ", "CLOSE, ", "RJ, ", "SRJ, ", 498 "RR, ", "INITC, ", "INITB, ", "INITA, "}; 499 char dbgbuf[128]; 500 register char *ptr; 501 502 ptr = dbgbuf; 503 strcpy(ptr, role ? "send " : "recv "); 504 ptr += strlen(ptr); 505 506 strcpy(ptr, cntltype[(cntl&0300)>>6]); 507 ptr += strlen(ptr); 508 509 if (cntl&0300) { 510 /* data packet */ 511 if (role) 512 sprintf(ptr, "loc %o, rem %o\n", (cntl & 070) >> 3, cntl & 7); 513 else 514 sprintf(ptr, "loc %o, rem %o\n", cntl & 7, (cntl & 070) >> 3); 515 } else { 516 /* control packet */ 517 strcpy(ptr, cntlxxx[(cntl&070)>>3]); 518 ptr += strlen(ptr); 519 sprintf(ptr, "val %o\n", cntl & 7); 520 } 521 522 DEBUG(1, dbgbuf, 0); 523 } 524