Home | History | Annotate | Download | only in bnu
      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