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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  *
     31  * flow control protocol.
     32  *
     33  * This protocol relies on flow control of the data stream.
     34  * It is meant for working over links that can (almost) be
     35  * guaranteed to be errorfree, specifically X.25/PAD links.
     36  * A sumcheck is carried out over a whole file only. If a
     37  * transport fails the receiver can request retransmission(s).
     38  * This protocol uses a 7-bit datapath only, so it can be
     39  * used on links that are not 8-bit transparent.
     40  *
     41  * When using this protocol with an X.25 PAD:
     42  * Although this protocol uses no control chars except CR,
     43  * control chars NULL and ^P are used before this protocol
     44  * is started; since ^P is the default char for accessing
     45  * PAD X.28 command mode, be sure to disable that access
     46  * (PAD par 1). Also make sure both flow control pars
     47  * (5 and 12) are set. The CR used in this proto is meant
     48  * to trigger packet transmission, hence par 3 should be
     49  * set to 2; a good value for the Idle Timer (par 4) is 10.
     50  * All other pars should be set to 0.
     51  *
     52  * Normally a calling site will take care of setting the
     53  * local PAD pars via an X.28 command and those of the remote
     54  * PAD via an X.29 command, unless the remote site has a
     55  * special channel assigned for this protocol with the proper
     56  * par settings.
     57  *
     58  * Additional comments for hosts with direct X.25 access:
     59  * - the global variable IsTcpIp, when set, excludes the ioctl's,
     60  *   so the same binary can run on X.25 and non-X.25 hosts;
     61  * - reads are done in small chunks, which can be smaller than
     62  *   the packet size; your X.25 driver must support that.
     63  *
     64  *
     65  * Author:
     66  *	Piet Beertema, CWI, Amsterdam, Sep 1984
     67  * Modified for X.25 hosts:
     68  *	Robert Elz, Melbourne Univ, Mar 1985
     69  */
     70 
     71 #include "uucp.h"
     72 #ifdef F_PROTOCOL
     73 
     74 extern unsigned msgtime;
     75 
     76 /* privates */
     77 static int frdblk(), fwrblk();
     78 
     79 #define FIBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size,
     80 				 * but see comment above
     81 				 */
     82 
     83 #define FOBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size;
     84 				 * otherwise make as large as feasible to reduce
     85 				 * number of write system calls
     86 				 */
     87 
     88 #ifndef MAXMSGLEN
     89 #define MAXMSGLEN	BUFSIZ
     90 #endif	/* MAXMSGLEN */
     91 
     92 static int fchksum;
     93 static jmp_buf Ffailbuf;
     94 
     95 /* ARGSUSED */
     96 static void
     97 falarm(sig)
     98 	int sig;
     99 {
    100 	signal(SIGALRM, falarm);
    101 	longjmp(Ffailbuf, 1);
    102 }
    103 
    104 static void (*fsig)();
    105 
    106 static int ioctlok;
    107 #ifdef ATTSVTTY
    108 static struct termio ttbuf;
    109 #else
    110 static struct sgttyb ttbuf;
    111 #endif
    112 
    113 int
    114 fturnon(void)
    115 {
    116 	int ret;
    117 #ifdef ATTSVTTY
    118 	struct termio save_ttbuf;
    119 #else
    120 	struct sgttyb save_ttbuf;
    121 #endif
    122 
    123 #ifdef ATTSVTTY
    124 	if (ioctl(Ifn, TCGETA, &ttbuf) >= 0) {
    125 		ioctlok = 1;
    126 		save_ttbuf = ttbuf;
    127 		ioctl(Ifn, TCGETA, &ttbuf);
    128 		ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
    129 		ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
    130 		ttbuf.c_cc[VTIME] = 5;
    131 		ret = ioctl(Ifn, TCSETA, &ttbuf);
    132 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
    133 		ttbuf = save_ttbuf;
    134 	}
    135 #else /* !ATTSVTTY */
    136 	if (ioctl(Ifn, TIOCGETP, &ttbuf) >= 0) {
    137 		ioctlok = 1;
    138 		save_ttbuf = ttbuf;
    139 		ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
    140 		ret = ioctl(Ifn, TIOCSETP, &ttbuf);
    141 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
    142 		ttbuf = save_ttbuf;
    143 	}
    144 #endif /* ATTSVTTY */
    145 	fsig = signal(SIGALRM, falarm);
    146 	/* give the other side time to perform its ioctl;
    147 	 * otherwise it may flush out the first data this
    148 	 * side is about to send.
    149 	 */
    150 	sleep(2);
    151 	return SUCCESS;
    152 }
    153 
    154 int
    155 fturnoff(void)
    156 {
    157 	if (ioctlok) {
    158 #ifdef ATTSVTTY
    159 		(void) ioctl(Ifn, TCSETA, &ttbuf);
    160 #else
    161 		(void) ioctl(Ifn, TIOCSETP, &ttbuf);
    162 #endif
    163 	}
    164 	(void) signal(SIGALRM, fsig);
    165 	sleep(2);
    166 	return SUCCESS;
    167 }
    168 
    169 int
    170 fwrmsg(type, str, fn)
    171 char *str;
    172 int fn;
    173 char type;
    174 {
    175 	char *s;
    176 	char bufr[MAXMSGLEN];
    177 
    178 	s = bufr;
    179 	*s++ = type;
    180 	while (*str)
    181 		*s++ = *str++;
    182 	if (*(s-1) == '\n')
    183 		s--;
    184 	*s++ = '\r';
    185 	*s = 0;
    186 	(void) write(fn, bufr, s - bufr);
    187 	return SUCCESS;
    188 }
    189 
    190 int
    191 frdmsg(str, fn)
    192 char *str;
    193 int fn;
    194 {
    195 	char *smax;
    196 
    197 	if (setjmp(Ffailbuf))
    198 		return FAIL;
    199 	smax = str + MAXMSGLEN - 1;
    200 	(void) alarm(msgtime);
    201 	for (;;) {
    202 		if (read(fn, str, 1) <= 0)
    203 			goto msgerr;
    204 		*str &= 0177;
    205 		if (*str == '\r')
    206 			break;
    207 		if (*str < ' ') {
    208 			continue;
    209 		}
    210 		if (str++ >= smax)
    211 			goto msgerr;
    212 	}
    213 	*str = '\0';
    214 	(void) alarm(0);
    215 	return SUCCESS;
    216 msgerr:
    217 	(void) alarm(0);
    218 	return FAIL;
    219 }
    220 
    221 int
    222 fwrdata(fp1, fn)
    223 FILE *fp1;
    224 int fn;
    225 {
    226 	int alen, ret;
    227 	char ack, ibuf[MAXMSGLEN];
    228 	int flen, retries = 0;
    229 	long fbytes;
    230 
    231 	ret = FAIL;
    232 retry:
    233 	fchksum = 0xffff;
    234 	fbytes = 0L;
    235 	ack = '\0';
    236 	do {
    237 		alen = fwrblk(fn, fp1, &flen);
    238 		fbytes += flen;
    239 		if (alen <= 0) {
    240 			goto acct;
    241 		}
    242 	} while (!feof(fp1) && !ferror(fp1));
    243 	DEBUG(8, "\nchecksum: %04x\n", fchksum);
    244 	if (frdmsg(ibuf, fn) != FAIL) {
    245 		if ((ack = ibuf[0]) == 'G')
    246 			ret = SUCCESS;
    247 		DEBUG(4, "ack - '%c'\n", ack);
    248 	}
    249 acct:
    250 	DEBUG(7, "%d retries\n", retries);
    251 	if (ack == 'R') {
    252 		DEBUG(4, "RETRY:\n", 0);
    253 		fseek(fp1, 0L, 0);
    254 		retries++;
    255 		goto retry;
    256 	}
    257 	return ret;
    258 }
    259 
    260 /* max. attempts to retransmit a file: */
    261 #define MAXRETRIES	(fbytes < 10000L ? 2 : 1)
    262 
    263 int
    264 frddata(fn, fp2)
    265 int fn;
    266 FILE *fp2;
    267 {
    268 	int flen;
    269 	char eof;
    270 	char ibuf[FIBUFSIZ];
    271 	int ret, retries = 0;
    272 	long alen, fbytes;
    273 
    274 	ret = FAIL;
    275 retry:
    276 	fchksum = 0xffff;
    277 	fbytes = 0L;
    278 	do {
    279 		flen = frdblk(ibuf, fn, &alen);
    280 		if (flen < 0)
    281 			goto acct;
    282 		if (eof = flen > FIBUFSIZ)
    283 			flen -= FIBUFSIZ + 1;
    284 		fbytes += flen;
    285 		if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
    286 			goto acct;
    287 	} while (!eof);
    288 	ret = SUCCESS;
    289 acct:
    290 	DEBUG(7, "%d retries\n", retries);
    291 	if (ret == FAIL) {
    292 		if (retries++ < MAXRETRIES) {
    293 			DEBUG(8, "send ack: 'R'\n", 0);
    294 			fwrmsg('R', "", fn);
    295 			fseek(fp2, 0L, 0);
    296 			DEBUG(4, "RETRY:\n", 0);
    297 			goto retry;
    298 		}
    299 		DEBUG(8, "send ack: 'Q'\n", 0);
    300 		fwrmsg('Q', "", fn);
    301 	}
    302 	else {
    303 		DEBUG(8, "send ack: 'G'\n", 0);
    304 		fwrmsg('G', "", fn);
    305 	}
    306 	return ret;
    307 }
    308 
    309 static int
    310 frdbuf(blk, len, fn)
    311 char *blk;
    312 int len;
    313 int fn;
    314 {
    315 	static int ret = FIBUFSIZ / 2;
    316 
    317 	if (setjmp(Ffailbuf))
    318 		return FAIL;
    319 	(void) alarm(msgtime);
    320 	ret = read(fn, blk, len);
    321 	alarm(0);
    322 	return ret <= 0 ? FAIL : ret;
    323 }
    324 
    325 #if !defined(ATTSVKILL)
    326 /* call ultouch every TC calls to either frdblk or fwrblk  */
    327 #define TC	20
    328 static int tc = TC;
    329 #endif	/* !defined(ATTSVKILL) */
    330 
    331 /* Byte conversion:
    332  *
    333  *   from	 pre	   to
    334  * 000-037	 172	 100-137
    335  * 040-171		 040-171
    336  * 172-177	 173	 072-077
    337  * 200-237	 174	 100-137
    338  * 240-371	 175	 040-171
    339  * 372-377	 176	 072-077
    340  */
    341 
    342 static int
    343 fwrblk(fn, fp, lenp)
    344 int fn;
    345 FILE *fp;
    346 int *lenp;
    347 {
    348 	char *op;
    349 	int c, sum, nl, len;
    350 	char obuf[FOBUFSIZ + 8];
    351 	int ret;
    352 
    353 #if !defined(ATTSVKILL)
    354 	/* call ultouch occasionally */
    355 	if (--tc < 0) {
    356 		tc = TC;
    357 		ultouch();
    358 	}
    359 #endif /*!defined(ATTSVKILL)*/
    360 	op = obuf;
    361 	nl = 0;
    362 	len = 0;
    363 	sum = fchksum;
    364 	while ((c = getc(fp)) != EOF) {
    365 		len++;
    366 		if (sum & 0x8000) {
    367 			sum <<= 1;
    368 			sum++;
    369 		} else
    370 			sum <<= 1;
    371 		sum += c;
    372 		sum &= 0xffff;
    373 		if (c & 0200) {
    374 			c &= 0177;
    375 			if (c < 040) {
    376 				*op++ = '\174';
    377 				*op++ = c + 0100;
    378 			} else
    379 			if (c <= 0171) {
    380 				*op++ = '\175';
    381 				*op++ = c;
    382 			}
    383 			else {
    384 				*op++ = '\176';
    385 				*op++ = c - 0100;
    386 			}
    387 			nl += 2;
    388 		} else {
    389 			if (c < 040) {
    390 				*op++ = '\172';
    391 				*op++ = c + 0100;
    392 				nl += 2;
    393 			} else
    394 			if (c <= 0171) {
    395 				*op++ = c;
    396 				nl++;
    397 			} else {
    398 				*op++ = '\173';
    399 				*op++ = c - 0100;
    400 				nl += 2;
    401 			}
    402 		}
    403 		if (nl >= FOBUFSIZ - 1) {
    404 			/*
    405 			 * peek at next char, see if it will fit
    406 			 */
    407 			c = getc(fp);
    408 			if (c == EOF)
    409 				break;
    410 			(void) ungetc(c, fp);
    411 			if (nl >= FOBUFSIZ || c < 040 || c > 0171)
    412 				goto writeit;
    413 		}
    414 	}
    415 	/*
    416 	 * At EOF - append checksum, there is space for it...
    417 	 */
    418 	sprintf(op, "\176\176%04x\r", sum);
    419 	nl += strlen(op);
    420 writeit:
    421 	*lenp = len;
    422 	fchksum = sum;
    423 	DEBUG(8, "%d/", len);
    424 	DEBUG(8, "%d,", nl);
    425 	ret = write(fn, obuf, nl);
    426 	return ret == nl ? nl : ret < 0 ? 0 : -ret;
    427 }
    428 
    429 static int
    430 frdblk(ip, fn, rlen)
    431 char *ip;
    432 int fn;
    433 long *rlen;
    434 {
    435 	char *op, c;
    436 	int sum, len, nl;
    437 	char buf[5], *erbp = ip;
    438 	int i;
    439 	static char special = 0;
    440 
    441 #if !defined(ATTSVKILL)
    442 	/* call ultouch occasionally */
    443 	if (--tc < 0) {
    444 		tc = TC;
    445 		ultouch();
    446 	}
    447 #endif /*!defined(ATTSVKILL)*/
    448 	if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
    449 		*rlen = 0;
    450 		goto dcorr;
    451 	}
    452 	*rlen = len;
    453 	DEBUG(8, "%d/", len);
    454 	op = ip;
    455 	nl = 0;
    456 	sum = fchksum;
    457 	do {
    458 		if ((*ip &= 0177) >= '\172') {
    459 			if (special) {
    460 				DEBUG(8, "%d", nl);
    461 				special = 0;
    462 				op = buf;
    463 				if (*ip++ != '\176' || (i = --len) > 5)
    464 					goto dcorr;
    465 				while (i--)
    466 					*op++ = *ip++ & 0177;
    467 				while (len < 5) {
    468 					i = frdbuf(&buf[len], 5 - len, fn);
    469 					if (i == FAIL) {
    470 						len = FAIL;
    471 						goto dcorr;
    472 					}
    473 					DEBUG(8, ",%d", i);
    474 					len += i;
    475 					*rlen += i;
    476 					while (i--)
    477 						*op++ &= 0177;
    478 				}
    479 				if (buf[4] != '\r')
    480 					goto dcorr;
    481 				sscanf(buf, "%4x", &fchksum);
    482 				DEBUG(8, "\nchecksum: %04x\n", sum);
    483 				if (fchksum == sum)
    484 					return FIBUFSIZ + 1 + nl;
    485 				else {
    486 					DEBUG(8, "\n", 0);
    487 					DEBUG(4, "Bad checksum\n", 0);
    488 					return FAIL;
    489 				}
    490 			}
    491 			special = *ip++;
    492 		} else {
    493 			if (*ip < '\040') {
    494 				/* error: shouldn't get control chars */
    495 				goto dcorr;
    496 			}
    497 			switch (special) {
    498 			case 0:
    499 				c = *ip++;
    500 				break;
    501 			case '\172':
    502 				c = *ip++ - 0100;
    503 				break;
    504 			case '\173':
    505 				c = *ip++ + 0100;
    506 				break;
    507 			case '\174':
    508 				c = *ip++ + 0100;
    509 				break;
    510 			case '\175':
    511 				c = *ip++ + 0200;
    512 				break;
    513 			case '\176':
    514 				c = *ip++ + 0300;
    515 				break;
    516 			}
    517 			*op++ = c;
    518 			if (sum & 0x8000) {
    519 				sum <<= 1;
    520 				sum++;
    521 			} else
    522 				sum <<= 1;
    523 			sum += c & 0377;
    524 			sum &= 0xffff;
    525 			special = 0;
    526 			nl++;
    527 		}
    528 	} while (--len);
    529 	fchksum = sum;
    530 	DEBUG(8, "%d,", nl);
    531 	return nl;
    532 dcorr:
    533 	DEBUG(8, "\n", 0);
    534 	DEBUG(4, "Data corrupted\n", 0);
    535 	while (len != FAIL) {
    536 		if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
    537 			*rlen += len;
    538 	}
    539 	return FAIL;
    540 }
    541 #endif /* F_PROTOCOL */
    542