10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*728Sceastha * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * flow control protocol.
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * This protocol relies on flow control of the data stream.
340Sstevel@tonic-gate * It is meant for working over links that can (almost) be
350Sstevel@tonic-gate * guaranteed to be errorfree, specifically X.25/PAD links.
360Sstevel@tonic-gate * A sumcheck is carried out over a whole file only. If a
370Sstevel@tonic-gate * transport fails the receiver can request retransmission(s).
380Sstevel@tonic-gate * This protocol uses a 7-bit datapath only, so it can be
390Sstevel@tonic-gate * used on links that are not 8-bit transparent.
400Sstevel@tonic-gate *
410Sstevel@tonic-gate * When using this protocol with an X.25 PAD:
420Sstevel@tonic-gate * Although this protocol uses no control chars except CR,
430Sstevel@tonic-gate * control chars NULL and ^P are used before this protocol
440Sstevel@tonic-gate * is started; since ^P is the default char for accessing
450Sstevel@tonic-gate * PAD X.28 command mode, be sure to disable that access
460Sstevel@tonic-gate * (PAD par 1). Also make sure both flow control pars
470Sstevel@tonic-gate * (5 and 12) are set. The CR used in this proto is meant
480Sstevel@tonic-gate * to trigger packet transmission, hence par 3 should be
490Sstevel@tonic-gate * set to 2; a good value for the Idle Timer (par 4) is 10.
500Sstevel@tonic-gate * All other pars should be set to 0.
510Sstevel@tonic-gate *
520Sstevel@tonic-gate * Normally a calling site will take care of setting the
530Sstevel@tonic-gate * local PAD pars via an X.28 command and those of the remote
540Sstevel@tonic-gate * PAD via an X.29 command, unless the remote site has a
550Sstevel@tonic-gate * special channel assigned for this protocol with the proper
560Sstevel@tonic-gate * par settings.
570Sstevel@tonic-gate *
580Sstevel@tonic-gate * Additional comments for hosts with direct X.25 access:
590Sstevel@tonic-gate * - the global variable IsTcpIp, when set, excludes the ioctl's,
600Sstevel@tonic-gate * so the same binary can run on X.25 and non-X.25 hosts;
610Sstevel@tonic-gate * - reads are done in small chunks, which can be smaller than
620Sstevel@tonic-gate * the packet size; your X.25 driver must support that.
630Sstevel@tonic-gate *
640Sstevel@tonic-gate *
650Sstevel@tonic-gate * Author:
660Sstevel@tonic-gate * Piet Beertema, CWI, Amsterdam, Sep 1984
670Sstevel@tonic-gate * Modified for X.25 hosts:
680Sstevel@tonic-gate * Robert Elz, Melbourne Univ, Mar 1985
690Sstevel@tonic-gate */
700Sstevel@tonic-gate
710Sstevel@tonic-gate #include "uucp.h"
720Sstevel@tonic-gate #ifdef F_PROTOCOL
730Sstevel@tonic-gate
740Sstevel@tonic-gate extern unsigned msgtime;
750Sstevel@tonic-gate
760Sstevel@tonic-gate /* privates */
770Sstevel@tonic-gate static int frdblk(), fwrblk();
780Sstevel@tonic-gate
790Sstevel@tonic-gate #define FIBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size,
800Sstevel@tonic-gate * but see comment above
810Sstevel@tonic-gate */
820Sstevel@tonic-gate
830Sstevel@tonic-gate #define FOBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size;
840Sstevel@tonic-gate * otherwise make as large as feasible to reduce
850Sstevel@tonic-gate * number of write system calls
860Sstevel@tonic-gate */
870Sstevel@tonic-gate
880Sstevel@tonic-gate #ifndef MAXMSGLEN
890Sstevel@tonic-gate #define MAXMSGLEN BUFSIZ
90*728Sceastha #endif /* MAXMSGLEN */
910Sstevel@tonic-gate
920Sstevel@tonic-gate static int fchksum;
930Sstevel@tonic-gate static jmp_buf Ffailbuf;
940Sstevel@tonic-gate
950Sstevel@tonic-gate /* ARGSUSED */
960Sstevel@tonic-gate static void
falarm(sig)970Sstevel@tonic-gate falarm(sig)
980Sstevel@tonic-gate int sig;
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate signal(SIGALRM, falarm);
1010Sstevel@tonic-gate longjmp(Ffailbuf, 1);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate static void (*fsig)();
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate static int ioctlok;
1070Sstevel@tonic-gate #ifdef ATTSVTTY
1080Sstevel@tonic-gate static struct termio ttbuf;
1090Sstevel@tonic-gate #else
1100Sstevel@tonic-gate static struct sgttyb ttbuf;
1110Sstevel@tonic-gate #endif
1120Sstevel@tonic-gate
113*728Sceastha int
fturnon(void)114*728Sceastha fturnon(void)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate int ret;
1170Sstevel@tonic-gate #ifdef ATTSVTTY
1180Sstevel@tonic-gate struct termio save_ttbuf;
1190Sstevel@tonic-gate #else
1200Sstevel@tonic-gate struct sgttyb save_ttbuf;
1210Sstevel@tonic-gate #endif
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate #ifdef ATTSVTTY
1240Sstevel@tonic-gate if (ioctl(Ifn, TCGETA, &ttbuf) >= 0) {
1250Sstevel@tonic-gate ioctlok = 1;
1260Sstevel@tonic-gate save_ttbuf = ttbuf;
1270Sstevel@tonic-gate ioctl(Ifn, TCGETA, &ttbuf);
1280Sstevel@tonic-gate ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
1290Sstevel@tonic-gate ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
1300Sstevel@tonic-gate ttbuf.c_cc[VTIME] = 5;
1310Sstevel@tonic-gate ret = ioctl(Ifn, TCSETA, &ttbuf);
1320Sstevel@tonic-gate ASSERT(ret >= 0, "STTY FAILED", "", ret);
1330Sstevel@tonic-gate ttbuf = save_ttbuf;
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate #else /* !ATTSVTTY */
1360Sstevel@tonic-gate if (ioctl(Ifn, TIOCGETP, &ttbuf) >= 0) {
1370Sstevel@tonic-gate ioctlok = 1;
1380Sstevel@tonic-gate save_ttbuf = ttbuf;
1390Sstevel@tonic-gate ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
1400Sstevel@tonic-gate ret = ioctl(Ifn, TIOCSETP, &ttbuf);
1410Sstevel@tonic-gate ASSERT(ret >= 0, "STTY FAILED", "", ret);
1420Sstevel@tonic-gate ttbuf = save_ttbuf;
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate #endif /* ATTSVTTY */
1450Sstevel@tonic-gate fsig = signal(SIGALRM, falarm);
1460Sstevel@tonic-gate /* give the other side time to perform its ioctl;
1470Sstevel@tonic-gate * otherwise it may flush out the first data this
1480Sstevel@tonic-gate * side is about to send.
1490Sstevel@tonic-gate */
1500Sstevel@tonic-gate sleep(2);
1510Sstevel@tonic-gate return SUCCESS;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
154*728Sceastha int
fturnoff(void)155*728Sceastha fturnoff(void)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate if (ioctlok) {
1580Sstevel@tonic-gate #ifdef ATTSVTTY
1590Sstevel@tonic-gate (void) ioctl(Ifn, TCSETA, &ttbuf);
1600Sstevel@tonic-gate #else
1610Sstevel@tonic-gate (void) ioctl(Ifn, TIOCSETP, &ttbuf);
1620Sstevel@tonic-gate #endif
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate (void) signal(SIGALRM, fsig);
1650Sstevel@tonic-gate sleep(2);
1660Sstevel@tonic-gate return SUCCESS;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
169*728Sceastha int
fwrmsg(type,str,fn)1700Sstevel@tonic-gate fwrmsg(type, str, fn)
171*728Sceastha char *str;
1720Sstevel@tonic-gate int fn;
1730Sstevel@tonic-gate char type;
1740Sstevel@tonic-gate {
175*728Sceastha char *s;
1760Sstevel@tonic-gate char bufr[MAXMSGLEN];
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate s = bufr;
1790Sstevel@tonic-gate *s++ = type;
1800Sstevel@tonic-gate while (*str)
1810Sstevel@tonic-gate *s++ = *str++;
1820Sstevel@tonic-gate if (*(s-1) == '\n')
1830Sstevel@tonic-gate s--;
1840Sstevel@tonic-gate *s++ = '\r';
1850Sstevel@tonic-gate *s = 0;
1860Sstevel@tonic-gate (void) write(fn, bufr, s - bufr);
1870Sstevel@tonic-gate return SUCCESS;
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
190*728Sceastha int
frdmsg(str,fn)1910Sstevel@tonic-gate frdmsg(str, fn)
192*728Sceastha char *str;
193*728Sceastha int fn;
1940Sstevel@tonic-gate {
195*728Sceastha char *smax;
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate if (setjmp(Ffailbuf))
1980Sstevel@tonic-gate return FAIL;
1990Sstevel@tonic-gate smax = str + MAXMSGLEN - 1;
2000Sstevel@tonic-gate (void) alarm(msgtime);
2010Sstevel@tonic-gate for (;;) {
2020Sstevel@tonic-gate if (read(fn, str, 1) <= 0)
2030Sstevel@tonic-gate goto msgerr;
2040Sstevel@tonic-gate *str &= 0177;
2050Sstevel@tonic-gate if (*str == '\r')
2060Sstevel@tonic-gate break;
2070Sstevel@tonic-gate if (*str < ' ') {
2080Sstevel@tonic-gate continue;
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate if (str++ >= smax)
2110Sstevel@tonic-gate goto msgerr;
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate *str = '\0';
2140Sstevel@tonic-gate (void) alarm(0);
2150Sstevel@tonic-gate return SUCCESS;
2160Sstevel@tonic-gate msgerr:
2170Sstevel@tonic-gate (void) alarm(0);
2180Sstevel@tonic-gate return FAIL;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
221*728Sceastha int
fwrdata(fp1,fn)2220Sstevel@tonic-gate fwrdata(fp1, fn)
2230Sstevel@tonic-gate FILE *fp1;
2240Sstevel@tonic-gate int fn;
2250Sstevel@tonic-gate {
226*728Sceastha int alen, ret;
2270Sstevel@tonic-gate char ack, ibuf[MAXMSGLEN];
2280Sstevel@tonic-gate int flen, retries = 0;
2290Sstevel@tonic-gate long fbytes;
2300Sstevel@tonic-gate
2310Sstevel@tonic-gate ret = FAIL;
2320Sstevel@tonic-gate retry:
2330Sstevel@tonic-gate fchksum = 0xffff;
2340Sstevel@tonic-gate fbytes = 0L;
2350Sstevel@tonic-gate ack = '\0';
2360Sstevel@tonic-gate do {
2370Sstevel@tonic-gate alen = fwrblk(fn, fp1, &flen);
2380Sstevel@tonic-gate fbytes += flen;
2390Sstevel@tonic-gate if (alen <= 0) {
2400Sstevel@tonic-gate goto acct;
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate } while (!feof(fp1) && !ferror(fp1));
2430Sstevel@tonic-gate DEBUG(8, "\nchecksum: %04x\n", fchksum);
2440Sstevel@tonic-gate if (frdmsg(ibuf, fn) != FAIL) {
2450Sstevel@tonic-gate if ((ack = ibuf[0]) == 'G')
2460Sstevel@tonic-gate ret = SUCCESS;
2470Sstevel@tonic-gate DEBUG(4, "ack - '%c'\n", ack);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate acct:
2500Sstevel@tonic-gate DEBUG(7, "%d retries\n", retries);
2510Sstevel@tonic-gate if (ack == 'R') {
2520Sstevel@tonic-gate DEBUG(4, "RETRY:\n", 0);
2530Sstevel@tonic-gate fseek(fp1, 0L, 0);
2540Sstevel@tonic-gate retries++;
2550Sstevel@tonic-gate goto retry;
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate return ret;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate /* max. attempts to retransmit a file: */
2610Sstevel@tonic-gate #define MAXRETRIES (fbytes < 10000L ? 2 : 1)
2620Sstevel@tonic-gate
263*728Sceastha int
frddata(fn,fp2)2640Sstevel@tonic-gate frddata(fn, fp2)
265*728Sceastha int fn;
266*728Sceastha FILE *fp2;
2670Sstevel@tonic-gate {
268*728Sceastha int flen;
269*728Sceastha char eof;
2700Sstevel@tonic-gate char ibuf[FIBUFSIZ];
2710Sstevel@tonic-gate int ret, retries = 0;
2720Sstevel@tonic-gate long alen, fbytes;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate ret = FAIL;
2750Sstevel@tonic-gate retry:
2760Sstevel@tonic-gate fchksum = 0xffff;
2770Sstevel@tonic-gate fbytes = 0L;
2780Sstevel@tonic-gate do {
2790Sstevel@tonic-gate flen = frdblk(ibuf, fn, &alen);
2800Sstevel@tonic-gate if (flen < 0)
2810Sstevel@tonic-gate goto acct;
2820Sstevel@tonic-gate if (eof = flen > FIBUFSIZ)
2830Sstevel@tonic-gate flen -= FIBUFSIZ + 1;
2840Sstevel@tonic-gate fbytes += flen;
2850Sstevel@tonic-gate if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
2860Sstevel@tonic-gate goto acct;
2870Sstevel@tonic-gate } while (!eof);
2880Sstevel@tonic-gate ret = SUCCESS;
2890Sstevel@tonic-gate acct:
2900Sstevel@tonic-gate DEBUG(7, "%d retries\n", retries);
2910Sstevel@tonic-gate if (ret == FAIL) {
2920Sstevel@tonic-gate if (retries++ < MAXRETRIES) {
2930Sstevel@tonic-gate DEBUG(8, "send ack: 'R'\n", 0);
2940Sstevel@tonic-gate fwrmsg('R', "", fn);
2950Sstevel@tonic-gate fseek(fp2, 0L, 0);
2960Sstevel@tonic-gate DEBUG(4, "RETRY:\n", 0);
2970Sstevel@tonic-gate goto retry;
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate DEBUG(8, "send ack: 'Q'\n", 0);
3000Sstevel@tonic-gate fwrmsg('Q', "", fn);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate else {
3030Sstevel@tonic-gate DEBUG(8, "send ack: 'G'\n", 0);
3040Sstevel@tonic-gate fwrmsg('G', "", fn);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate return ret;
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
309*728Sceastha static int
frdbuf(blk,len,fn)3100Sstevel@tonic-gate frdbuf(blk, len, fn)
311*728Sceastha char *blk;
312*728Sceastha int len;
313*728Sceastha int fn;
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate static int ret = FIBUFSIZ / 2;
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate if (setjmp(Ffailbuf))
3180Sstevel@tonic-gate return FAIL;
3190Sstevel@tonic-gate (void) alarm(msgtime);
3200Sstevel@tonic-gate ret = read(fn, blk, len);
3210Sstevel@tonic-gate alarm(0);
3220Sstevel@tonic-gate return ret <= 0 ? FAIL : ret;
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate #if !defined(ATTSVKILL)
3260Sstevel@tonic-gate /* call ultouch every TC calls to either frdblk or fwrblk */
3270Sstevel@tonic-gate #define TC 20
3280Sstevel@tonic-gate static int tc = TC;
329*728Sceastha #endif /* !defined(ATTSVKILL) */
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate /* Byte conversion:
3320Sstevel@tonic-gate *
3330Sstevel@tonic-gate * from pre to
3340Sstevel@tonic-gate * 000-037 172 100-137
3350Sstevel@tonic-gate * 040-171 040-171
3360Sstevel@tonic-gate * 172-177 173 072-077
3370Sstevel@tonic-gate * 200-237 174 100-137
3380Sstevel@tonic-gate * 240-371 175 040-171
3390Sstevel@tonic-gate * 372-377 176 072-077
3400Sstevel@tonic-gate */
3410Sstevel@tonic-gate
342*728Sceastha static int
fwrblk(fn,fp,lenp)3430Sstevel@tonic-gate fwrblk(fn, fp, lenp)
3440Sstevel@tonic-gate int fn;
345*728Sceastha FILE *fp;
3460Sstevel@tonic-gate int *lenp;
3470Sstevel@tonic-gate {
348*728Sceastha char *op;
349*728Sceastha int c, sum, nl, len;
3500Sstevel@tonic-gate char obuf[FOBUFSIZ + 8];
3510Sstevel@tonic-gate int ret;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate #if !defined(ATTSVKILL)
3540Sstevel@tonic-gate /* call ultouch occasionally */
3550Sstevel@tonic-gate if (--tc < 0) {
3560Sstevel@tonic-gate tc = TC;
3570Sstevel@tonic-gate ultouch();
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate #endif /*!defined(ATTSVKILL)*/
3600Sstevel@tonic-gate op = obuf;
3610Sstevel@tonic-gate nl = 0;
3620Sstevel@tonic-gate len = 0;
3630Sstevel@tonic-gate sum = fchksum;
3640Sstevel@tonic-gate while ((c = getc(fp)) != EOF) {
3650Sstevel@tonic-gate len++;
3660Sstevel@tonic-gate if (sum & 0x8000) {
3670Sstevel@tonic-gate sum <<= 1;
3680Sstevel@tonic-gate sum++;
3690Sstevel@tonic-gate } else
3700Sstevel@tonic-gate sum <<= 1;
3710Sstevel@tonic-gate sum += c;
3720Sstevel@tonic-gate sum &= 0xffff;
3730Sstevel@tonic-gate if (c & 0200) {
3740Sstevel@tonic-gate c &= 0177;
3750Sstevel@tonic-gate if (c < 040) {
3760Sstevel@tonic-gate *op++ = '\174';
3770Sstevel@tonic-gate *op++ = c + 0100;
3780Sstevel@tonic-gate } else
3790Sstevel@tonic-gate if (c <= 0171) {
3800Sstevel@tonic-gate *op++ = '\175';
3810Sstevel@tonic-gate *op++ = c;
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate else {
3840Sstevel@tonic-gate *op++ = '\176';
3850Sstevel@tonic-gate *op++ = c - 0100;
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate nl += 2;
3880Sstevel@tonic-gate } else {
3890Sstevel@tonic-gate if (c < 040) {
3900Sstevel@tonic-gate *op++ = '\172';
3910Sstevel@tonic-gate *op++ = c + 0100;
3920Sstevel@tonic-gate nl += 2;
3930Sstevel@tonic-gate } else
3940Sstevel@tonic-gate if (c <= 0171) {
3950Sstevel@tonic-gate *op++ = c;
3960Sstevel@tonic-gate nl++;
3970Sstevel@tonic-gate } else {
3980Sstevel@tonic-gate *op++ = '\173';
3990Sstevel@tonic-gate *op++ = c - 0100;
4000Sstevel@tonic-gate nl += 2;
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate if (nl >= FOBUFSIZ - 1) {
4040Sstevel@tonic-gate /*
4050Sstevel@tonic-gate * peek at next char, see if it will fit
4060Sstevel@tonic-gate */
4070Sstevel@tonic-gate c = getc(fp);
4080Sstevel@tonic-gate if (c == EOF)
4090Sstevel@tonic-gate break;
4100Sstevel@tonic-gate (void) ungetc(c, fp);
4110Sstevel@tonic-gate if (nl >= FOBUFSIZ || c < 040 || c > 0171)
4120Sstevel@tonic-gate goto writeit;
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate /*
4160Sstevel@tonic-gate * At EOF - append checksum, there is space for it...
4170Sstevel@tonic-gate */
4180Sstevel@tonic-gate sprintf(op, "\176\176%04x\r", sum);
4190Sstevel@tonic-gate nl += strlen(op);
4200Sstevel@tonic-gate writeit:
4210Sstevel@tonic-gate *lenp = len;
4220Sstevel@tonic-gate fchksum = sum;
4230Sstevel@tonic-gate DEBUG(8, "%d/", len);
4240Sstevel@tonic-gate DEBUG(8, "%d,", nl);
4250Sstevel@tonic-gate ret = write(fn, obuf, nl);
4260Sstevel@tonic-gate return ret == nl ? nl : ret < 0 ? 0 : -ret;
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
429*728Sceastha static int
frdblk(ip,fn,rlen)4300Sstevel@tonic-gate frdblk(ip, fn, rlen)
431*728Sceastha char *ip;
4320Sstevel@tonic-gate int fn;
4330Sstevel@tonic-gate long *rlen;
4340Sstevel@tonic-gate {
435*728Sceastha char *op, c;
436*728Sceastha int sum, len, nl;
4370Sstevel@tonic-gate char buf[5], *erbp = ip;
4380Sstevel@tonic-gate int i;
4390Sstevel@tonic-gate static char special = 0;
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate #if !defined(ATTSVKILL)
4420Sstevel@tonic-gate /* call ultouch occasionally */
4430Sstevel@tonic-gate if (--tc < 0) {
4440Sstevel@tonic-gate tc = TC;
4450Sstevel@tonic-gate ultouch();
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate #endif /*!defined(ATTSVKILL)*/
4480Sstevel@tonic-gate if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
4490Sstevel@tonic-gate *rlen = 0;
4500Sstevel@tonic-gate goto dcorr;
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate *rlen = len;
4530Sstevel@tonic-gate DEBUG(8, "%d/", len);
4540Sstevel@tonic-gate op = ip;
4550Sstevel@tonic-gate nl = 0;
4560Sstevel@tonic-gate sum = fchksum;
4570Sstevel@tonic-gate do {
4580Sstevel@tonic-gate if ((*ip &= 0177) >= '\172') {
4590Sstevel@tonic-gate if (special) {
4600Sstevel@tonic-gate DEBUG(8, "%d", nl);
4610Sstevel@tonic-gate special = 0;
4620Sstevel@tonic-gate op = buf;
4630Sstevel@tonic-gate if (*ip++ != '\176' || (i = --len) > 5)
4640Sstevel@tonic-gate goto dcorr;
4650Sstevel@tonic-gate while (i--)
4660Sstevel@tonic-gate *op++ = *ip++ & 0177;
4670Sstevel@tonic-gate while (len < 5) {
4680Sstevel@tonic-gate i = frdbuf(&buf[len], 5 - len, fn);
4690Sstevel@tonic-gate if (i == FAIL) {
4700Sstevel@tonic-gate len = FAIL;
4710Sstevel@tonic-gate goto dcorr;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate DEBUG(8, ",%d", i);
4740Sstevel@tonic-gate len += i;
4750Sstevel@tonic-gate *rlen += i;
4760Sstevel@tonic-gate while (i--)
4770Sstevel@tonic-gate *op++ &= 0177;
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate if (buf[4] != '\r')
4800Sstevel@tonic-gate goto dcorr;
4810Sstevel@tonic-gate sscanf(buf, "%4x", &fchksum);
4820Sstevel@tonic-gate DEBUG(8, "\nchecksum: %04x\n", sum);
4830Sstevel@tonic-gate if (fchksum == sum)
4840Sstevel@tonic-gate return FIBUFSIZ + 1 + nl;
4850Sstevel@tonic-gate else {
4860Sstevel@tonic-gate DEBUG(8, "\n", 0);
4870Sstevel@tonic-gate DEBUG(4, "Bad checksum\n", 0);
4880Sstevel@tonic-gate return FAIL;
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate special = *ip++;
4920Sstevel@tonic-gate } else {
4930Sstevel@tonic-gate if (*ip < '\040') {
4940Sstevel@tonic-gate /* error: shouldn't get control chars */
4950Sstevel@tonic-gate goto dcorr;
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate switch (special) {
4980Sstevel@tonic-gate case 0:
4990Sstevel@tonic-gate c = *ip++;
5000Sstevel@tonic-gate break;
5010Sstevel@tonic-gate case '\172':
5020Sstevel@tonic-gate c = *ip++ - 0100;
5030Sstevel@tonic-gate break;
5040Sstevel@tonic-gate case '\173':
5050Sstevel@tonic-gate c = *ip++ + 0100;
5060Sstevel@tonic-gate break;
5070Sstevel@tonic-gate case '\174':
5080Sstevel@tonic-gate c = *ip++ + 0100;
5090Sstevel@tonic-gate break;
5100Sstevel@tonic-gate case '\175':
5110Sstevel@tonic-gate c = *ip++ + 0200;
5120Sstevel@tonic-gate break;
5130Sstevel@tonic-gate case '\176':
5140Sstevel@tonic-gate c = *ip++ + 0300;
5150Sstevel@tonic-gate break;
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate *op++ = c;
5180Sstevel@tonic-gate if (sum & 0x8000) {
5190Sstevel@tonic-gate sum <<= 1;
5200Sstevel@tonic-gate sum++;
5210Sstevel@tonic-gate } else
5220Sstevel@tonic-gate sum <<= 1;
5230Sstevel@tonic-gate sum += c & 0377;
5240Sstevel@tonic-gate sum &= 0xffff;
5250Sstevel@tonic-gate special = 0;
5260Sstevel@tonic-gate nl++;
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate } while (--len);
5290Sstevel@tonic-gate fchksum = sum;
5300Sstevel@tonic-gate DEBUG(8, "%d,", nl);
5310Sstevel@tonic-gate return nl;
5320Sstevel@tonic-gate dcorr:
5330Sstevel@tonic-gate DEBUG(8, "\n", 0);
5340Sstevel@tonic-gate DEBUG(4, "Data corrupted\n", 0);
5350Sstevel@tonic-gate while (len != FAIL) {
5360Sstevel@tonic-gate if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
5370Sstevel@tonic-gate *rlen += len;
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate return FAIL;
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate #endif /* F_PROTOCOL */
542