1 /* slip 1.1 - Serial line IP Author: Kees J. Bot
12 #include <sys/asynchio.h>
14 #if __minix && !__minix_vmd
15 #define HAS_ASYN 0 /* Standard Minix doesn't have async I/O. */
17 #define HAS_ASYN 1 /* Everyone else does in some way. */
24 #define END 0300 /* End of packet. */
25 #define ESC 0333 /* Byte stuffing escape. */
26 #define ESC_END 0334 /* END -> ESC ESC_END -> END. */
27 #define ESC_ESC 0335 /* ESC -> ESC ESC_ESC -> ESC. */
29 #define PACKLEN 2048 /* Max datagram size. */
30 #define SLIPLEN (1 + 2*PACKLEN + 1) /* Max serial size when all escaped. */
32 /* Pathetic fprintf() clone to avoid dragging in the stdio library. */
33 static int fprintf(int fd
, const char *format
, ...);
36 int main(int argc
, char **argv
)
40 int doing
[2], discard
;
45 size_t ps_len
[2], sl_len
[2];
46 unsigned char *sl_end
;
47 unsigned char ps_buf
[2][PACKLEN
];
48 unsigned char sl_buf
[2][SLIPLEN
];
52 fprintf(stderr
, "Usage: slip psip-device\n");
57 if ((ps_fd
= open(ps_device
, O_RDWR
)) < 0) {
58 fprintf(stderr
, "slip: can't open %s: %s\n",
59 ps_device
, strerror(errno
));
63 doing
[0]= 1; /* We're doing serial -> psip. */
64 discard
= 0; /* No input error. */
65 sl_len
[0]= 0; /* Nothing read from serial line yet. */
66 sl_end
= nil
; /* No END marker seen. */
67 ps_len
[0]= 0; /* Nothing to write to pseudo IP device. */
69 doing
[1]= 1; /* We're doing psip -> serial. */
70 sl_len
[1]= 0; /* Nothing read from pseudo IP device yet. */
71 ps_len
[1]= 0; /* Nothing to write to serial line. */
74 /* Oops, standard Minix can't do asynchronous I/O. Fork and let the parent
75 * do serial -> psip, and the child do psip -> serial. (Note that we have
76 * to make sure that we're not reading and writing at the same time even
77 * for standard Minix. For Minix-vmd we do fill an input buffer while an
78 * output buffer is waiting to be drained to improve performance a bit.)
80 switch ((other_pid
= fork())) {
82 fprintf(stderr
, "slip: can't fork: %s\n", strerror(errno
));
86 doing
[0]= 0; /* *Not* doing serial -> psip. */
91 doing
[1]= 0; /* *Not* doing psip -> serial. */
99 /* If there is an END marker in the serial input then create
100 * an IP packet to be send to the TCP/IP task.
102 while (sl_end
!= nil
&& ps_len
[0] == 0) {
103 unsigned char *sp
= sl_buf
[0];
104 unsigned char *pp
= ps_buf
[0];
106 while (sp
< sl_end
) {
111 case ESC_ESC
: /* ESC ESC_ESC -> ESC. */
114 case ESC_END
: /* ESC ESC_END -> END. */
118 /* Protocol error. */
122 if (pp
< ps_buf
[0] + PACKLEN
) {
125 /* Packet too big, discard. */
132 /* A new packet can be send to the TCP/IP server. */
133 ps_len
[0]= (pp
- ps_buf
[0]);
135 /* Move what's beyond END to the front. */
137 sl_len
[0] -= (sl_end
- sl_buf
[0]);
138 memmove(sl_buf
[0], sl_end
, sl_len
[0]);
139 sl_end
= memchr(sl_buf
[0], END
, sl_len
[0]);
142 /* Reading from serial input. */
143 if (sl_end
== nil
&& (HAS_ASYN
|| ps_len
[0] == 0)) {
144 r
= asyn_read(&asyn
, 0, sl_buf
[0] + sl_len
[0],
145 SLIPLEN
- sl_len
[0]);
147 sl_end
= memchr(sl_buf
[0] + sl_len
[0], END
, r
);
149 if (sl_end
== nil
&& sl_len
[0] == SLIPLEN
) {
150 /* Packet is idiotically big and no END in sight. */
156 fprintf(stderr
, "slip: EOF on serial input\n");
159 if (errno
!= ASYN_INPROGRESS
) {
160 fprintf(stderr
, "slip: serial input error: %s\n",
166 /* Writing to the psip device. */
168 r
= asyn_write(&asyn
, ps_fd
, ps_buf
[0], ps_len
[0]);
169 if (r
== ps_len
[0]) {
170 /* Packet written. */
175 "slip: odd write to %s, tried %u, wrote %d\n",
176 ps_device
, (unsigned) ps_len
[0], (int) r
);
179 if (errno
!= ASYN_INPROGRESS
) {
180 fprintf(stderr
, "slip: error writing %s: %s\n",
181 ps_device
, strerror(errno
));
188 /* Transform an IP packet to a "byte stuffed" serial packet. */
189 if (ps_len
[1] > 0 && sl_len
[1] == 0) {
190 unsigned char *pp
= ps_buf
[1];
191 unsigned char *sp
= sl_buf
[1];
194 while (ps_len
[1] > 0) {
198 case ESC
: /* ESC -> ESC ESC_ESC. */
202 case END
: /* END -> ESC ESC_END. */
210 sl_len
[1]= (sp
- sl_buf
[1]);
213 /* Reading from the psip device. */
214 if (ps_len
[1] == 0 && (HAS_ASYN
|| sl_len
[1] == 0)) {
215 r
= asyn_read(&asyn
, ps_fd
, ps_buf
[1], PACKLEN
);
217 /* One packet read. */
221 fprintf(stderr
, "slip: EOF on %s\n", ps_device
);
224 if (errno
!= ASYN_INPROGRESS
) {
225 fprintf(stderr
, "slip: error reading %s: %s\n",
226 ps_device
, strerror(errno
));
231 /* Writing to serial output. */
233 r
= asyn_write(&asyn
, 1, sl_buf
[1], sl_len
[1]);
235 if ((sl_len
[1]-= r
) > 0) {
236 memmove(sl_buf
[1], sl_buf
[1] + r
, sl_len
[1]);
240 fprintf(stderr
, "slip: EOF on serial output\n");
243 if (errno
!= ASYN_INPROGRESS
) {
244 fprintf(stderr
, "slip: serial output error: %s\n",
251 /* Wait for something to happen. */
252 if (asyn_wait(&asyn
, 0, nil
) < 0) {
254 "slip: error while waiting for I/O to happen: %s\n",
260 /* Tell my alter ego that the game is over. */
261 kill(other_pid
, SIGKILL
);
266 static int fprintf(int fd
, const char *format
, ...)
267 /* Simple fprintf() to save a few bytes by not using the stdio library. */
271 const char *fp0
, *fp
;
276 va_start(ap
, format
);
279 if (*fp
== '%' && memchr("sdu", fp
[1], 3) != nil
) {
281 if ((r
= write(fd
, fp0
, (fp
- fp0
))) < 0) return -1;
288 char *s
= va_arg(ap
, char *);
290 if ((r
= write(fd
, s
, strlen(s
))) < 0) return -1;
295 char a
[3 * sizeof(u
) + 2];
299 u
= d
= va_arg(ap
, int);
302 u
= va_arg(ap
, unsigned);
308 do *--p
= '0' + (u
% 10); while ((u
/= 10) > 0);
310 if (d
< 0) *--p
= '-';
311 if ((r
= write(fd
, p
, (a
+ sizeof(a
)) - p
)) < 0) return -1;
318 if ((r
= write(fd
, fp0
, (fp
- fp0
))) < 0) return -1;