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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 * flow control protocol.
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.
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.
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
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.
66 * Piet Beertema, CWI, Amsterdam, Sep 1984
67 * Modified for X.25 hosts:
68 * Robert Elz, Melbourne Univ, Mar 1985
74 extern unsigned msgtime
;
77 static int frdblk(), fwrblk();
79 #define FIBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size,
80 * but see comment above
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
89 #define MAXMSGLEN BUFSIZ
90 #endif /* MAXMSGLEN */
93 static jmp_buf Ffailbuf
;
100 signal(SIGALRM
, falarm
);
101 longjmp(Ffailbuf
, 1);
104 static void (*fsig
)();
108 static struct termio ttbuf
;
110 static struct sgttyb ttbuf
;
118 struct termio save_ttbuf
;
120 struct sgttyb save_ttbuf
;
124 if (ioctl(Ifn
, TCGETA
, &ttbuf
) >= 0) {
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
);
135 #else /* !ATTSVTTY */
136 if (ioctl(Ifn
, TIOCGETP
, &ttbuf
) >= 0) {
139 ttbuf
.sg_flags
= ANYP
|CBREAK
|TANDEM
;
140 ret
= ioctl(Ifn
, TIOCSETP
, &ttbuf
);
141 ASSERT(ret
>= 0, "STTY FAILED", "", ret
);
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.
159 (void) ioctl(Ifn
, TCSETA
, &ttbuf
);
161 (void) ioctl(Ifn
, TIOCSETP
, &ttbuf
);
164 (void) signal(SIGALRM
, fsig
);
170 fwrmsg(type
, str
, fn
)
176 char bufr
[MAXMSGLEN
];
186 (void) write(fn
, bufr
, s
- bufr
);
197 if (setjmp(Ffailbuf
))
199 smax
= str
+ MAXMSGLEN
- 1;
200 (void) alarm(msgtime
);
202 if (read(fn
, str
, 1) <= 0)
227 char ack
, ibuf
[MAXMSGLEN
];
228 int flen
, retries
= 0;
237 alen
= fwrblk(fn
, fp1
, &flen
);
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')
247 DEBUG(4, "ack - '%c'\n", ack
);
250 DEBUG(7, "%d retries\n", retries
);
252 DEBUG(4, "RETRY:\n", 0);
260 /* max. attempts to retransmit a file: */
261 #define MAXRETRIES (fbytes < 10000L ? 2 : 1)
271 int ret
, retries
= 0;
279 flen
= frdblk(ibuf
, fn
, &alen
);
282 if (eof
= flen
> FIBUFSIZ
)
283 flen
-= FIBUFSIZ
+ 1;
285 if (fwrite(ibuf
, sizeof (char), flen
, fp2
) != flen
)
290 DEBUG(7, "%d retries\n", retries
);
292 if (retries
++ < MAXRETRIES
) {
293 DEBUG(8, "send ack: 'R'\n", 0);
296 DEBUG(4, "RETRY:\n", 0);
299 DEBUG(8, "send ack: 'Q'\n", 0);
303 DEBUG(8, "send ack: 'G'\n", 0);
315 static int ret
= FIBUFSIZ
/ 2;
317 if (setjmp(Ffailbuf
))
319 (void) alarm(msgtime
);
320 ret
= read(fn
, blk
, len
);
322 return ret
<= 0 ? FAIL
: ret
;
325 #if !defined(ATTSVKILL)
326 /* call ultouch every TC calls to either frdblk or fwrblk */
329 #endif /* !defined(ATTSVKILL) */
334 * 000-037 172 100-137
336 * 172-177 173 072-077
337 * 200-237 174 100-137
338 * 240-371 175 040-171
339 * 372-377 176 072-077
350 char obuf
[FOBUFSIZ
+ 8];
353 #if !defined(ATTSVKILL)
354 /* call ultouch occasionally */
359 #endif /*!defined(ATTSVKILL)*/
364 while ((c
= getc(fp
)) != EOF
) {
403 if (nl
>= FOBUFSIZ
- 1) {
405 * peek at next char, see if it will fit
410 (void) ungetc(c
, fp
);
411 if (nl
>= FOBUFSIZ
|| c
< 040 || c
> 0171)
416 * At EOF - append checksum, there is space for it...
418 sprintf(op
, "\176\176%04x\r", sum
);
423 DEBUG(8, "%d/", len
);
425 ret
= write(fn
, obuf
, nl
);
426 return ret
== nl
? nl
: ret
< 0 ? 0 : -ret
;
437 char buf
[5], *erbp
= ip
;
439 static char special
= 0;
441 #if !defined(ATTSVKILL)
442 /* call ultouch occasionally */
447 #endif /*!defined(ATTSVKILL)*/
448 if ((len
= frdbuf(ip
, FIBUFSIZ
, fn
)) == FAIL
) {
453 DEBUG(8, "%d/", len
);
458 if ((*ip
&= 0177) >= '\172') {
463 if (*ip
++ != '\176' || (i
= --len
) > 5)
466 *op
++ = *ip
++ & 0177;
468 i
= frdbuf(&buf
[len
], 5 - len
, fn
);
481 sscanf(buf
, "%4x", &fchksum
);
482 DEBUG(8, "\nchecksum: %04x\n", sum
);
484 return FIBUFSIZ
+ 1 + nl
;
487 DEBUG(4, "Bad checksum\n", 0);
494 /* error: shouldn't get control chars */
534 DEBUG(4, "Data corrupted\n", 0);
535 while (len
!= FAIL
) {
536 if ((len
= frdbuf(erbp
, FIBUFSIZ
, fn
)) != FAIL
)
541 #endif /* F_PROTOCOL */