Added hint on recently added example.
[contiki-2.x.git] / tools / tapslip6.c
blob8fc0f58894a601da152ed5c72eb1351cadff7a8c
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: tapslip6.c,v 1.3 2009/11/03 14:00:28 nvt-se 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 in_addr_t giaddr;
57 in_addr_t netaddr;
58 in_addr_t circuit_addr;
60 int ssystem(const char *fmt, ...)
61 __attribute__((__format__ (__printf__, 1, 2)));
62 void write_to_serial(int outfd, void *inbuf, int len);
64 //#define PROGRESS(s) fprintf(stderr, s)
65 #define PROGRESS(s) do { } while (0)
67 #define USAGE_STRING "usage: tapslip6 [-B baudrate] [-s siodev] [-t tundev] ipaddress netmask"
69 char tundev[32] = { "tap0" };
71 int
72 ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
74 int
75 ssystem(const char *fmt, ...)
77 char cmd[128];
78 va_list ap;
79 va_start(ap, fmt);
80 vsnprintf(cmd, sizeof(cmd), fmt, ap);
81 va_end(ap);
82 printf("%s\n", cmd);
83 fflush(stdout);
84 return system(cmd);
87 #define SLIP_END 0300
88 #define SLIP_ESC 0333
89 #define SLIP_ESC_END 0334
90 #define SLIP_ESC_ESC 0335
92 static void
93 print_packet(u_int8_t *p, int len) {
94 int i;
95 for(i = 0; i < len; i++) {
96 printf("%02x", p[i]);
97 if ((i & 3) == 3)
98 printf(" ");
99 if ((i & 15) == 15)
100 printf("\n");
102 printf("\n");
106 is_sensible_string(const unsigned char *s, int len)
108 int i;
109 for(i = 1; i < len; i++) {
110 if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
111 continue;
112 } else if(s[i] < ' ' || '~' < s[i]) {
113 return 0;
116 return 1;
122 * Read from serial, when we have a packet write it to tun. No output
123 * buffering, input buffered by stdio.
125 void
126 serial_to_tun(FILE *inslip, int outfd)
128 static union {
129 unsigned char inbuf[2000];
130 } uip;
131 static int inbufptr = 0;
133 int ret;
134 unsigned char c;
136 #ifdef linux
137 ret = fread(&c, 1, 1, inslip);
138 if(ret == -1 || ret == 0) err(1, "serial_to_tun: read");
139 goto after_fread;
140 #endif
142 read_more:
143 if(inbufptr >= sizeof(uip.inbuf)) {
144 inbufptr = 0;
146 ret = fread(&c, 1, 1, inslip);
147 #ifdef linux
148 after_fread:
149 #endif
150 if(ret == -1) {
151 err(1, "serial_to_tun: read");
153 if(ret == 0) {
154 clearerr(inslip);
155 return;
156 fprintf(stderr, "serial_to_tun: EOF\n");
157 exit(1);
159 /* fprintf(stderr, ".");*/
160 switch(c) {
161 case SLIP_END:
162 if(inbufptr > 0) {
163 if(uip.inbuf[0] == '!') {
164 if (uip.inbuf[1] == 'M') {
165 /* Read gateway MAC address and autoconfigure tap0 interface */
166 char macs[24];
167 int i, pos;
168 for(i = 0, pos = 0; i < 16; i++) {
169 macs[pos++] = uip.inbuf[2 + i];
170 if ((i & 1) == 1 && i < 14) {
171 macs[pos++] = ':';
174 macs[pos] = '\0';
175 printf("*** Gateway's MAC address: %s\n", macs);
177 ssystem("ifconfig %s down", tundev);
178 ssystem("ifconfig %s hw ether %s", tundev, &macs[6]);
179 ssystem("ifconfig %s up", tundev);
181 #define DEBUG_LINE_MARKER '\r'
182 } else if(uip.inbuf[0] == DEBUG_LINE_MARKER) {
183 fwrite(uip.inbuf + 1, inbufptr - 1, 1, stdout);
184 } else if(is_sensible_string(uip.inbuf, inbufptr)) {
185 fwrite(uip.inbuf, inbufptr, 1, stdout);
186 } else {
187 printf("Writing to tun len: %d\n", inbufptr);
188 /* print_packet(uip.inbuf, inbufptr);*/
189 if(write(outfd, uip.inbuf, inbufptr) != inbufptr) {
190 err(1, "serial_to_tun: write");
193 inbufptr = 0;
195 break;
197 case SLIP_ESC:
198 if(fread(&c, 1, 1, inslip) != 1) {
199 clearerr(inslip);
200 /* Put ESC back and give up! */
201 ungetc(SLIP_ESC, inslip);
202 return;
205 switch(c) {
206 case SLIP_ESC_END:
207 c = SLIP_END;
208 break;
209 case SLIP_ESC_ESC:
210 c = SLIP_ESC;
211 break;
213 /* FALLTHROUGH */
214 default:
215 uip.inbuf[inbufptr++] = c;
216 break;
219 goto read_more;
222 unsigned char slip_buf[2000];
223 int slip_end, slip_begin;
226 void
227 slip_send(int fd, unsigned char c)
229 if (slip_end >= sizeof(slip_buf))
230 err(1, "slip_send overflow");
231 slip_buf[slip_end] = c;
232 slip_end++;
236 slip_empty()
238 return slip_end == 0;
241 void
242 slip_flushbuf(int fd)
244 int n;
246 if (slip_empty())
247 return;
249 n = write(fd, slip_buf + slip_begin, (slip_end - slip_begin));
251 if(n == -1 && errno != EAGAIN) {
252 err(1, "slip_flushbuf write failed");
253 } else if(n == -1) {
254 PROGRESS("Q"); /* Outqueueis full! */
255 } else {
256 slip_begin += n;
257 if(slip_begin == slip_end) {
258 slip_begin = slip_end = 0;
263 void
264 write_to_serial(int outfd, void *inbuf, int len)
266 u_int8_t *p = inbuf;
267 int i, ecode;
269 /* printf("Got packet of length %d - write SLIP\n", len);*/
270 /* print_packet(p, len);*/
272 /* It would be ``nice'' to send a SLIP_END here but it's not
273 * really necessary.
275 /* slip_send(outfd, SLIP_END); */
276 /* printf("writing packet to serial!!! %d\n", len);*/
277 for(i = 0; i < len; i++) {
278 switch(p[i]) {
279 case SLIP_END:
280 slip_send(outfd, SLIP_ESC);
281 slip_send(outfd, SLIP_ESC_END);
282 break;
283 case SLIP_ESC:
284 slip_send(outfd, SLIP_ESC);
285 slip_send(outfd, SLIP_ESC_ESC);
286 break;
287 default:
288 slip_send(outfd, p[i]);
289 break;
293 slip_send(outfd, SLIP_END);
294 PROGRESS("t");
299 * Read from tun, write to slip.
301 void
302 tun_to_serial(int infd, int outfd)
304 struct {
305 unsigned char inbuf[2000];
306 } uip;
307 int size;
309 if((size = read(infd, uip.inbuf, 2000)) == -1) err(1, "tun_to_serial: read");
311 write_to_serial(outfd, uip.inbuf, size);
314 #ifndef BAUDRATE
315 #define BAUDRATE B115200
316 #endif
317 speed_t b_rate = BAUDRATE;
319 void
320 stty_telos(int fd)
322 struct termios tty;
323 speed_t speed = b_rate;
324 int i;
326 if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush");
328 if(tcgetattr(fd, &tty) == -1) err(1, "tcgetattr");
330 cfmakeraw(&tty);
332 /* Nonblocking read. */
333 tty.c_cc[VTIME] = 0;
334 tty.c_cc[VMIN] = 0;
335 tty.c_cflag &= ~CRTSCTS;
336 tty.c_cflag &= ~HUPCL;
337 tty.c_cflag &= ~CLOCAL;
339 cfsetispeed(&tty, speed);
340 cfsetospeed(&tty, speed);
342 if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr");
344 #if 1
345 /* Nonblocking read and write. */
346 /* if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */
348 tty.c_cflag |= CLOCAL;
349 if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr");
351 i = TIOCM_DTR;
352 if(ioctl(fd, TIOCMBIS, &i) == -1) err(1, "ioctl");
353 #endif
355 usleep(10*1000); /* Wait for hardware 10ms. */
357 /* Flush input and output buffers. */
358 if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush");
362 devopen(const char *dev, int flags)
364 char t[32];
365 strcpy(t, "/dev/");
366 strcat(t, dev);
367 return open(t, flags);
370 #ifdef linux
371 #include <linux/if.h>
372 #include <linux/if_tun.h>
375 tun_alloc(char *dev)
377 struct ifreq ifr;
378 int fd, err;
380 if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
381 return -1;
383 memset(&ifr, 0, sizeof(ifr));
385 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
386 * IFF_TAP - TAP device
388 * IFF_NO_PI - Do not provide packet information
390 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
391 if(*dev != 0)
392 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
394 if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
395 close(fd);
396 return err;
398 strcpy(dev, ifr.ifr_name);
399 return fd;
401 #else
403 tun_alloc(char *dev)
405 return devopen(dev, O_RDWR);
407 #endif
409 const char *ipaddr;
410 const char *netmask;
412 void
413 cleanup(void)
415 ssystem("ifconfig %s down", tundev);
416 #ifndef linux
417 ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
418 #endif
419 /* ssystem("arp -d %s", ipaddr); */
420 ssystem("netstat -nr"
421 " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
422 " | sh",
423 tundev);
426 void
427 sigcleanup(int signo)
429 fprintf(stderr, "signal %d\n", signo);
430 exit(0); /* exit(0) will call cleanup() */
433 static int got_sigalarm;
434 static int request_mac;
436 void
437 sigalarm(int signo)
439 got_sigalarm = 1;
440 return;
443 void
444 sigalarm_reset()
446 #ifdef linux
447 #define TIMEOUT (997*1000)
448 #else
449 #define TIMEOUT (2451*1000)
450 #endif
451 ualarm(TIMEOUT, TIMEOUT);
452 got_sigalarm = 0;
455 void
456 ifconf(const char *tundev, const char *ipaddr, const char *netmask)
458 struct in_addr netname;
459 netname.s_addr = inet_addr(ipaddr) & inet_addr(netmask);
461 #ifdef linux
462 ssystem("ifconfig %s inet `hostname` up", tundev);
463 if(strcmp(ipaddr, "0.0.0.0") != 0) {
464 ssystem("route add -net %s netmask %s dev %s",
465 inet_ntoa(netname), netmask, tundev);
467 #else
468 ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr);
469 if(strcmp(ipaddr, "0.0.0.0") != 0) {
470 ssystem("route add -net %s -netmask %s -interface %s",
471 inet_ntoa(netname), netmask, tundev);
473 ssystem("sysctl -w net.inet.ip.forwarding=1");
474 #endif /* !linux */
476 ssystem("ifconfig %s\n", tundev);
480 main(int argc, char **argv)
482 int c;
483 int tunfd, slipfd, maxfd;
484 int ret;
485 fd_set rset, wset;
486 FILE *inslip;
487 const char *siodev = NULL;
488 int baudrate = -2;
489 request_mac = 1;
490 setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */
492 while((c = getopt(argc, argv, "B:D:hs:t:")) != -1) {
493 switch (c) {
494 case 'B':
495 baudrate = atoi(optarg);
496 break;
498 case 's':
499 if(strncmp("/dev/", optarg, 5) == 0) {
500 siodev = optarg + 5;
501 } else {
502 siodev = optarg;
504 break;
506 case 't':
507 if(strncmp("/dev/", optarg, 5) == 0) {
508 strcpy(tundev, optarg + 5);
509 } else {
510 strcpy(tundev, optarg);
512 break;
514 case '?':
515 case 'h':
516 default:
517 errx(1, USAGE_STRING);
518 break;
521 argc -= (optind - 1);
522 argv += (optind - 1);
524 if(argc != 3 && argc != 4) {
525 errx(1, USAGE_STRING);
527 ipaddr = argv[1];
528 netmask = argv[2];
529 circuit_addr = inet_addr(ipaddr);
530 netaddr = inet_addr(ipaddr) & inet_addr(netmask);
532 switch(baudrate) {
533 case -2:
534 break; /* Use default. */
535 case 9600:
536 b_rate = B9600;
537 break;
538 case 19200:
539 b_rate = B19200;
540 break;
541 case 38400:
542 b_rate = B38400;
543 break;
544 case 57600:
545 b_rate = B57600;
546 break;
547 case 115200:
548 b_rate = B115200;
549 break;
550 default:
551 err(1, "unknown baudrate %d", baudrate);
552 break;
556 if(siodev != NULL) {
557 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
558 if(slipfd == -1) {
559 err(1, "can't open siodev ``/dev/%s''", siodev);
561 } else {
562 static const char *siodevs[] = {
563 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
565 int i;
566 for(i = 0; i < 3; i++) {
567 siodev = siodevs[i];
568 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
569 if (slipfd != -1)
570 break;
572 if(slipfd == -1) {
573 err(1, "can't open siodev");
576 fprintf(stderr, "slip started on ``/dev/%s''\n", siodev);
577 stty_telos(slipfd);
578 slip_send(slipfd, SLIP_END);
579 inslip = fdopen(slipfd, "r");
580 if(inslip == NULL) err(1, "main: fdopen");
582 tunfd = tun_alloc(tundev);
583 printf("opening: %s", tundev);
584 if(tunfd == -1) err(1, "main: open");
585 fprintf(stderr, "opened device ``/dev/%s''\n", tundev);
587 atexit(cleanup);
588 signal(SIGHUP, sigcleanup);
589 signal(SIGTERM, sigcleanup);
590 signal(SIGINT, sigcleanup);
591 signal(SIGALRM, sigalarm);
592 ifconf(tundev, ipaddr, netmask);
594 while(1) {
595 maxfd = 0;
596 FD_ZERO(&rset);
597 FD_ZERO(&wset);
599 /* request mac address from gateway node for autoconfiguration of
600 ethernet interface tap0 */
601 if (request_mac) {
602 slip_send(slipfd, '?');
603 slip_send(slipfd, 'M');
604 slip_send(slipfd, SLIP_END);
605 request_mac = 0;
608 if(got_sigalarm) {
609 /* Send "?IPA". */
610 slip_send(slipfd, '?');
611 slip_send(slipfd, 'I');
612 slip_send(slipfd, 'P');
613 slip_send(slipfd, 'A');
614 slip_send(slipfd, SLIP_END);
615 got_sigalarm = 0;
618 if(!slip_empty()) { /* Anything to flush? */
619 FD_SET(slipfd, &wset);
622 FD_SET(slipfd, &rset); /* Read from slip ASAP! */
623 if(slipfd > maxfd) maxfd = slipfd;
625 /* We only have one packet at a time queued for slip output. */
626 if(slip_empty()) {
627 FD_SET(tunfd, &rset);
628 if(tunfd > maxfd) maxfd = tunfd;
631 ret = select(maxfd + 1, &rset, &wset, NULL, NULL);
632 if(ret == -1 && errno != EINTR) {
633 err(1, "select");
634 } else if(ret > 0) {
635 if(FD_ISSET(slipfd, &rset)) {
636 serial_to_tun(inslip, tunfd);
639 if(FD_ISSET(slipfd, &wset)) {
640 slip_flushbuf(slipfd);
641 sigalarm_reset();
644 if(slip_empty() && FD_ISSET(tunfd, &rset)) {
645 tun_to_serial(tunfd, slipfd);
646 slip_flushbuf(slipfd);
647 sigalarm_reset();