Programs using CFS should #include "cfs.h" ;-)
[contiki-2.x.git] / tools / tunslip6.c
blobcfb6aaf61797c3201dff689f2dccd957628e5092
1 /*
2 * Copyright (c) 2001, Adam Dunkels.
3 * Copyright (c) 2009, Joakim Eriksson, Niclas Finne.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior
16 * written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * This file is part of the uIP TCP/IP stack.
32 * $Id: tunslip6.c,v 1.1 2010/04/02 18:17:20 joxe Exp $
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <time.h>
41 #include <sys/types.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <signal.h>
47 #include <termios.h>
48 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
54 #include <err.h>
56 int verbose = 0;
58 int ssystem(const char *fmt, ...)
59 __attribute__((__format__ (__printf__, 1, 2)));
60 void write_to_serial(int outfd, void *inbuf, int len);
62 //#define PROGRESS(s) fprintf(stderr, s)
63 #define PROGRESS(s) do { } while (0)
65 char tundev[32] = { "tun0" };
67 int
68 ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
70 int
71 ssystem(const char *fmt, ...)
73 char cmd[128];
74 va_list ap;
75 va_start(ap, fmt);
76 vsnprintf(cmd, sizeof(cmd), fmt, ap);
77 va_end(ap);
78 printf("%s\n", cmd);
79 fflush(stdout);
80 return system(cmd);
83 #define SLIP_END 0300
84 #define SLIP_ESC 0333
85 #define SLIP_ESC_END 0334
86 #define SLIP_ESC_ESC 0335
89 int
90 is_sensible_string(const unsigned char *s, int len)
92 int i;
93 for(i = 1; i < len; i++) {
94 if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
95 continue;
96 } else if(s[i] < ' ' || '~' < s[i]) {
97 return 0;
100 return 1;
104 * Read from serial, when we have a packet write it to tun. No output
105 * buffering, input buffered by stdio.
107 void
108 serial_to_tun(FILE *inslip, int outfd)
110 static union {
111 unsigned char inbuf[2000];
112 } uip;
113 static int inbufptr = 0;
115 int ret;
116 unsigned char c;
118 #ifdef linux
119 ret = fread(&c, 1, 1, inslip);
120 if(ret == -1 || ret == 0) err(1, "serial_to_tun: read");
121 goto after_fread;
122 #endif
124 read_more:
125 if(inbufptr >= sizeof(uip.inbuf)) {
126 inbufptr = 0;
128 ret = fread(&c, 1, 1, inslip);
129 #ifdef linux
130 after_fread:
131 #endif
132 if(ret == -1) {
133 err(1, "serial_to_tun: read");
135 if(ret == 0) {
136 clearerr(inslip);
137 return;
138 fprintf(stderr, "serial_to_tun: EOF\n");
139 exit(1);
141 /* fprintf(stderr, ".");*/
142 switch(c) {
143 case SLIP_END:
144 if(inbufptr > 0) {
145 if(uip.inbuf[0] == '!') {
146 if (uip.inbuf[1] == 'M') {
147 /* Read gateway MAC address and autoconfigure tap0 interface */
148 char macs[24];
149 int i, pos;
150 for(i = 0, pos = 0; i < 16; i++) {
151 macs[pos++] = uip.inbuf[2 + i];
152 if ((i & 1) == 1 && i < 14) {
153 macs[pos++] = ':';
156 macs[pos] = '\0';
157 printf("*** Gateway's MAC address: %s\n", macs);
159 ssystem("ifconfig %s down", tundev);
160 ssystem("ifconfig %s hw ether %s", tundev, &macs[6]);
161 ssystem("ifconfig %s up", tundev);
163 #define DEBUG_LINE_MARKER '\r'
164 } else if(uip.inbuf[0] == DEBUG_LINE_MARKER) {
165 fwrite(uip.inbuf + 1, inbufptr - 1, 1, stdout);
166 } else if(is_sensible_string(uip.inbuf, inbufptr)) {
167 fwrite(uip.inbuf, inbufptr, 1, stdout);
168 } else {
169 if (verbose) printf("Writing to tun len: %d\n", inbufptr);
170 if(write(outfd, uip.inbuf, inbufptr) != inbufptr) {
171 err(1, "serial_to_tun: write");
174 inbufptr = 0;
176 break;
178 case SLIP_ESC:
179 if(fread(&c, 1, 1, inslip) != 1) {
180 clearerr(inslip);
181 /* Put ESC back and give up! */
182 ungetc(SLIP_ESC, inslip);
183 return;
186 switch(c) {
187 case SLIP_ESC_END:
188 c = SLIP_END;
189 break;
190 case SLIP_ESC_ESC:
191 c = SLIP_ESC;
192 break;
194 /* FALLTHROUGH */
195 default:
196 uip.inbuf[inbufptr++] = c;
197 break;
200 goto read_more;
203 unsigned char slip_buf[2000];
204 int slip_end, slip_begin;
206 void
207 slip_send(int fd, unsigned char c)
209 if (slip_end >= sizeof(slip_buf))
210 err(1, "slip_send overflow");
211 slip_buf[slip_end] = c;
212 slip_end++;
216 slip_empty()
218 return slip_end == 0;
221 void
222 slip_flushbuf(int fd)
224 int n;
226 if (slip_empty())
227 return;
229 n = write(fd, slip_buf + slip_begin, (slip_end - slip_begin));
231 if(n == -1 && errno != EAGAIN) {
232 err(1, "slip_flushbuf write failed");
233 } else if(n == -1) {
234 PROGRESS("Q"); /* Outqueueis full! */
235 } else {
236 slip_begin += n;
237 if(slip_begin == slip_end) {
238 slip_begin = slip_end = 0;
243 void
244 write_to_serial(int outfd, void *inbuf, int len)
246 u_int8_t *p = inbuf;
247 int i, ecode;
249 if (verbose) {
250 printf("Got packet of length %d - write SLIP\n", len);
251 for(i = 0; i < len; i++) {
252 printf("%02x", p[i]);
253 if((i & 3) == 3)
254 printf(" ");
255 if((i & 15) == 15)
256 printf("\n");
258 printf("\n");
261 /* It would be ``nice'' to send a SLIP_END here but it's not
262 * really necessary.
264 /* slip_send(outfd, SLIP_END); */
265 if(verbose) {
266 printf("writing packet to serial!!! %d\n", len);
268 for(i = 0; i < len; i++) {
269 switch(p[i]) {
270 case SLIP_END:
271 slip_send(outfd, SLIP_ESC);
272 slip_send(outfd, SLIP_ESC_END);
273 break;
274 case SLIP_ESC:
275 slip_send(outfd, SLIP_ESC);
276 slip_send(outfd, SLIP_ESC_ESC);
277 break;
278 default:
279 slip_send(outfd, p[i]);
280 break;
284 slip_send(outfd, SLIP_END);
285 PROGRESS("t");
290 * Read from tun, write to slip.
292 void
293 tun_to_serial(int infd, int outfd)
295 struct {
296 unsigned char inbuf[2000];
297 } uip;
298 int size;
300 if((size = read(infd, uip.inbuf, 2000)) == -1) err(1, "tun_to_serial: read");
302 write_to_serial(outfd, uip.inbuf, size);
305 #ifndef BAUDRATE
306 #define BAUDRATE B115200
307 #endif
308 speed_t b_rate = BAUDRATE;
310 void
311 stty_telos(int fd)
313 struct termios tty;
314 speed_t speed = b_rate;
315 int i;
317 if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush");
319 if(tcgetattr(fd, &tty) == -1) err(1, "tcgetattr");
321 cfmakeraw(&tty);
323 /* Nonblocking read. */
324 tty.c_cc[VTIME] = 0;
325 tty.c_cc[VMIN] = 0;
326 tty.c_cflag &= ~CRTSCTS;
327 tty.c_cflag &= ~HUPCL;
328 tty.c_cflag &= ~CLOCAL;
330 cfsetispeed(&tty, speed);
331 cfsetospeed(&tty, speed);
333 if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr");
335 #if 1
336 /* Nonblocking read and write. */
337 /* if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */
339 tty.c_cflag |= CLOCAL;
340 if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr");
342 i = TIOCM_DTR;
343 if(ioctl(fd, TIOCMBIS, &i) == -1) err(1, "ioctl");
344 #endif
346 usleep(10*1000); /* Wait for hardware 10ms. */
348 /* Flush input and output buffers. */
349 if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush");
353 devopen(const char *dev, int flags)
355 char t[32];
356 strcpy(t, "/dev/");
357 strcat(t, dev);
358 return open(t, flags);
361 #ifdef linux
362 #include <linux/if.h>
363 #include <linux/if_tun.h>
366 tun_alloc(char *dev)
368 struct ifreq ifr;
369 int fd, err;
371 if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
372 return -1;
374 memset(&ifr, 0, sizeof(ifr));
376 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
377 * IFF_TAP - TAP device
379 * IFF_NO_PI - Do not provide packet information
381 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
382 if(*dev != 0)
383 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
385 if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
386 close(fd);
387 return err;
389 strcpy(dev, ifr.ifr_name);
390 return fd;
392 #else
394 tun_alloc(char *dev)
396 return devopen(dev, O_RDWR);
398 #endif
400 const char *ipaddr;
401 const char *netmask;
403 void
404 cleanup(void)
406 ssystem("ifconfig %s down", tundev);
407 #ifndef linux
408 ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
409 Adam Dunkels.
410 #endif
411 /* ssystem("arp -d %s", ipaddr); */
412 ssystem("netstat -nr"
413 " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
414 " | sh",
415 tundev);
418 void
419 sigcleanup(int signo)
421 fprintf(stderr, "signal %d\n", signo);
422 exit(0); /* exit(0) will call cleanup() */
425 static int got_sigalarm;
427 void
428 sigalarm(int signo)
430 got_sigalarm = 1;
431 return;
434 void
435 sigalarm_reset()
437 #ifdef linux
438 #define TIMEOUT (997*1000)
439 #else
440 #define TIMEOUT (2451*1000)
441 #endif
442 ualarm(TIMEOUT, TIMEOUT);
443 got_sigalarm = 0;
446 void
447 ifconf(const char *tundev, const char *ipaddr)
449 #ifdef linux
450 ssystem("ifconfig %s inet `hostname` up", tundev);
451 ssystem("ifconfig %s add %s", tundev, ipaddr);
452 #else
453 ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr);
454 ssystem("sysctl -w net.inet.ip.forwarding=1");
455 #endif /* !linux */
457 ssystem("ifconfig %s\n", tundev);
461 main(int argc, char **argv)
463 int c;
464 int tunfd, slipfd, maxfd;
465 int ret;
466 fd_set rset, wset;
467 FILE *inslip;
468 const char *siodev = NULL;
469 int baudrate = -2;
471 setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */
473 while((c = getopt(argc, argv, "B:D:hs:t:v:")) != -1) {
474 switch (c) {
475 case 'B':
476 baudrate = atoi(optarg);
477 break;
479 case 's':
480 if(strncmp("/dev/", optarg, 5) == 0) {
481 siodev = optarg + 5;
482 } else {
483 siodev = optarg;
485 break;
487 case 't':
488 if(strncmp("/dev/", optarg, 5) == 0) {
489 strcpy(tundev, optarg + 5);
490 } else {
491 strcpy(tundev, optarg);
493 break;
494 case 'v':
495 verbose = 1;
496 break;
497 case '?':
498 case 'h':
499 default:
500 err(1, "usage: tunslip6 [-B baudrate] [-s siodev] [-t tundev] ipaddress");
501 break;
504 argc -= (optind - 1);
505 argv += (optind - 1);
507 if(argc != 2 && argc != 3) {
508 err(1, "usage: tunslip6 [-B baudrate] [-s siodev] [-t tundev] ipaddress ");
510 ipaddr = argv[1];
512 switch(baudrate) {
513 case -2:
514 break; /* Use default. */
515 case 9600:
516 b_rate = B9600;
517 break;
518 case 19200:
519 b_rate = B19200;
520 break;
521 case 38400:
522 b_rate = B38400;
523 break;
524 case 57600:
525 b_rate = B57600;
526 break;
527 case 115200:
528 b_rate = B115200;
529 break;
530 default:
531 err(1, "unknown baudrate %d", baudrate);
532 break;
536 if(siodev != NULL) {
537 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
538 if(slipfd == -1) {
539 err(1, "can't open siodev ``/dev/%s''", siodev);
541 } else {
542 static const char *siodevs[] = {
543 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
545 int i;
546 for(i = 0; i < 3; i++) {
547 siodev = siodevs[i];
548 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
549 if (slipfd != -1)
550 break;
552 if(slipfd == -1) {
553 err(1, "can't open siodev");
556 fprintf(stderr, "slip started on ``/dev/%s''\n", siodev);
557 stty_telos(slipfd);
558 slip_send(slipfd, SLIP_END);
559 inslip = fdopen(slipfd, "r");
560 if(inslip == NULL) err(1, "main: fdopen");
562 tunfd = tun_alloc(tundev);
563 if(tunfd == -1) err(1, "main: open");
564 fprintf(stderr, "opened device ``/dev/%s''\n", tundev);
566 atexit(cleanup);
567 signal(SIGHUP, sigcleanup);
568 signal(SIGTERM, sigcleanup);
569 signal(SIGINT, sigcleanup);
570 signal(SIGALRM, sigalarm);
571 ifconf(tundev, ipaddr);
573 while(1) {
574 maxfd = 0;
575 FD_ZERO(&rset);
576 FD_ZERO(&wset);
578 /* do not send IPA all the time... - add get MAC later... */
579 /* if(got_sigalarm) { */
580 /* /\* Send "?IPA". *\/ */
581 /* slip_send(slipfd, '?'); */
582 /* slip_send(slipfd, 'I'); */
583 /* slip_send(slipfd, 'P'); */
584 /* slip_send(slipfd, 'A'); */
585 /* slip_send(slipfd, SLIP_END); */
586 /* got_sigalarm = 0; */
587 /* } */
589 if(!slip_empty()) { /* Anything to flush? */
590 FD_SET(slipfd, &wset);
593 FD_SET(slipfd, &rset); /* Read from slip ASAP! */
594 if(slipfd > maxfd) maxfd = slipfd;
596 /* We only have one packet at a time queued for slip output. */
597 if(slip_empty()) {
598 FD_SET(tunfd, &rset);
599 if(tunfd > maxfd) maxfd = tunfd;
602 ret = select(maxfd + 1, &rset, &wset, NULL, NULL);
603 if(ret == -1 && errno != EINTR) {
604 err(1, "select");
605 } else if(ret > 0) {
606 if(FD_ISSET(slipfd, &rset)) {
607 serial_to_tun(inslip, tunfd);
610 if(FD_ISSET(slipfd, &wset)) {
611 slip_flushbuf(slipfd);
612 sigalarm_reset();
615 if(slip_empty() && FD_ISSET(tunfd, &rset)) {
616 tun_to_serial(tunfd, slipfd);
617 slip_flushbuf(slipfd);
618 sigalarm_reset();