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