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