1 /* slip 1.1 - Serial line IP Author: Kees J. Bot 2 * 19 Jul 1997 3 */ 4 #define nil 0 5 #include <sys/types.h> 6 #include <stdarg.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <fcntl.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <sys/asynchio.h> 13 14 #if __minix && !__minix_vmd 15 #define HAS_ASYN 0 /* Standard Minix doesn't have async I/O. */ 16 #else 17 #define HAS_ASYN 1 /* Everyone else does in some way. */ 18 #endif 19 20 #if !HAS_ASYN 21 #include <signal.h> 22 #endif 23 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. */ 28 29 #define PACKLEN 2048 /* Max datagram size. */ 30 #define SLIPLEN (1 + 2*PACKLEN + 1) /* Max serial size when all escaped. */ 31 32 /* Pathetic fprintf() clone to avoid dragging in the stdio library. */ 33 static int fprintf(int fd, const char *format, ...); 34 #define stderr 2 35 36 int main(int argc, char **argv) 37 { 38 char *ps_device; 39 int ps_fd; 40 int doing[2], discard; 41 ssize_t r; 42 #if !HAS_ASYN 43 pid_t other_pid; 44 #endif 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]; 49 asynchio_t asyn; 50 51 if (argc != 2) { 52 fprintf(stderr, "Usage: slip psip-device\n"); 53 exit(1); 54 } 55 ps_device= argv[1]; 56 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)); 60 exit(1); 61 } 62 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. */ 68 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. */ 72 73 #if !HAS_ASYN 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.) 79 */ 80 switch ((other_pid= fork())) { 81 case -1: 82 fprintf(stderr, "slip: can't fork: %s\n", strerror(errno)); 83 exit(1); 84 case 0: 85 /* Child. */ 86 doing[0]= 0; /* *Not* doing serial -> psip. */ 87 other_pid= getppid(); 88 break; 89 default: 90 /* Parent. */ 91 doing[1]= 0; /* *Not* doing psip -> serial. */ 92 } 93 #endif 94 95 asyn_init(&asyn); 96 97 for (;;) { 98 if (doing[0]) { 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. 101 */ 102 while (sl_end != nil && ps_len[0] == 0) { 103 unsigned char *sp= sl_buf[0]; 104 unsigned char *pp= ps_buf[0]; 105 106 while (sp < sl_end) { 107 int c= *sp++; 108 109 if (c == ESC) { 110 switch (*sp++) { 111 case ESC_ESC: /* ESC ESC_ESC -> ESC. */ 112 c= ESC; 113 break; 114 case ESC_END: /* ESC ESC_END -> END. */ 115 c= END; 116 break; 117 default: 118 /* Protocol error. */ 119 discard= 1; 120 } 121 } 122 if (pp < ps_buf[0] + PACKLEN) { 123 *pp++ = c; 124 } else { 125 /* Packet too big, discard. */ 126 discard= 1; 127 } 128 } 129 if (discard) { 130 discard= 0; 131 } else { 132 /* A new packet can be send to the TCP/IP server. */ 133 ps_len[0]= (pp - ps_buf[0]); 134 } 135 /* Move what's beyond END to the front. */ 136 sl_end++; 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]); 140 } 141 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]); 146 if (r > 0) { 147 sl_end= memchr(sl_buf[0] + sl_len[0], END, r); 148 sl_len[0]+= r; 149 if (sl_end == nil && sl_len[0] == SLIPLEN) { 150 /* Packet is idiotically big and no END in sight. */ 151 sl_len[0]= 0; 152 discard= 1; 153 } 154 } else 155 if (r == 0) { 156 fprintf(stderr, "slip: EOF on serial input\n"); 157 break; 158 } else 159 if (errno != ASYN_INPROGRESS) { 160 fprintf(stderr, "slip: serial input error: %s\n", 161 strerror(errno)); 162 break; 163 } 164 } 165 166 /* Writing to the psip device. */ 167 if (ps_len[0] > 0) { 168 r= asyn_write(&asyn, ps_fd, ps_buf[0], ps_len[0]); 169 if (r == ps_len[0]) { 170 /* Packet written. */ 171 ps_len[0]= 0; 172 } else 173 if (r >= 0) { 174 fprintf(stderr, 175 "slip: odd write to %s, tried %u, wrote %d\n", 176 ps_device, (unsigned) ps_len[0], (int) r); 177 break; 178 } else 179 if (errno != ASYN_INPROGRESS) { 180 fprintf(stderr, "slip: error writing %s: %s\n", 181 ps_device, strerror(errno)); 182 break; 183 } 184 } 185 } 186 187 if (doing[1]) { 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]; 192 193 *sp++ = END; 194 while (ps_len[1] > 0) { 195 int c= *pp++; 196 ps_len[1]--; 197 switch (c) { 198 case ESC: /* ESC -> ESC ESC_ESC. */ 199 *sp++ = ESC; 200 c= ESC_ESC; 201 break; 202 case END: /* END -> ESC ESC_END. */ 203 *sp++ = ESC; 204 c= ESC_END; 205 break; 206 } 207 *sp++ = c; 208 } 209 *sp++ = END; 210 sl_len[1]= (sp - sl_buf[1]); 211 } 212 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); 216 if (r > 0) { 217 /* One packet read. */ 218 ps_len[1]= r; 219 } else 220 if (r == 0) { 221 fprintf(stderr, "slip: EOF on %s\n", ps_device); 222 break; 223 } else 224 if (errno != ASYN_INPROGRESS) { 225 fprintf(stderr, "slip: error reading %s: %s\n", 226 ps_device, strerror(errno)); 227 break; 228 } 229 } 230 231 /* Writing to serial output. */ 232 if (sl_len[1] > 0) { 233 r= asyn_write(&asyn, 1, sl_buf[1], sl_len[1]); 234 if (r > 0) { 235 if ((sl_len[1]-= r) > 0) { 236 memmove(sl_buf[1], sl_buf[1] + r, sl_len[1]); 237 } 238 } else 239 if (r == 0) { 240 fprintf(stderr, "slip: EOF on serial output\n"); 241 break; 242 } else 243 if (errno != ASYN_INPROGRESS) { 244 fprintf(stderr, "slip: serial output error: %s\n", 245 strerror(errno)); 246 break; 247 } 248 } 249 } 250 251 /* Wait for something to happen. */ 252 if (asyn_wait(&asyn, 0, nil) < 0) { 253 fprintf(stderr, 254 "slip: error while waiting for I/O to happen: %s\n", 255 strerror(errno)); 256 break; 257 } 258 } 259 #if !HAS_ASYN 260 /* Tell my alter ego that the game is over. */ 261 kill(other_pid, SIGKILL); 262 #endif 263 return 1; 264 } 265 266 static int fprintf(int fd, const char *format, ...) 267 /* Simple fprintf() to save a few bytes by not using the stdio library. */ 268 { 269 int len; 270 ssize_t r; 271 const char *fp0, *fp; 272 va_list ap; 273 274 len= 0; 275 fp= fp0= format; 276 va_start(ap, format); 277 278 while (*fp != 0) { 279 if (*fp == '%' && memchr("sdu", fp[1], 3) != nil) { 280 if (fp > fp0) { 281 if ((r= write(fd, fp0, (fp - fp0))) < 0) goto error; 282 len+= r; 283 } 284 fp++; 285 fp0= fp+1; 286 287 if (*fp == 's') { 288 char *s= va_arg(ap, char *); 289 290 if ((r= write(fd, s, strlen(s))) < 0) goto error; 291 len+= r; 292 } else { 293 int d; 294 unsigned u; 295 char a[3 * sizeof(u) + 2]; 296 char *p; 297 298 if (*fp == 'd') { 299 u= d= va_arg(ap, int); 300 if (d < 0) u= -u; 301 } else { 302 u= va_arg(ap, unsigned); 303 d= 0; 304 } 305 306 p= a + sizeof(a); 307 *--p= 0; 308 do *--p= '0' + (u % 10); while ((u /= 10) > 0); 309 310 if (d < 0) *--p= '-'; 311 if ((r= write(fd, p, (a + sizeof(a)) - p)) < 0) goto error; 312 len+= r; 313 } 314 } 315 fp++; 316 } 317 if (fp > fp0) { 318 if ((r= write(fd, fp0, (fp - fp0))) < 0) goto error; 319 len+= r; 320 } 321 va_end(ap); 322 return len; 323 error: 324 va_end(ap); 325 return -1; 326 } 327