2 * Copyright (c) 2001, Adam Dunkels.
3 * Copyright (c) 2009, Joakim Eriksson, Niclas Finne.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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 $
41 #include <sys/types.h>
48 #include <sys/ioctl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
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" };
72 ssystem(const char *fmt
, ...) __attribute__((__format__ (__printf__
, 1, 2)));
75 ssystem(const char *fmt
, ...)
80 vsnprintf(cmd
, sizeof(cmd
), fmt
, ap
);
89 #define SLIP_ESC_END 0334
90 #define SLIP_ESC_ESC 0335
93 print_packet(u_int8_t
*p
, int len
) {
95 for(i
= 0; i
< len
; i
++) {
106 is_sensible_string(const unsigned char *s
, int len
)
109 for(i
= 1; i
< len
; i
++) {
110 if(s
[i
] == 0 || s
[i
] == '\r' || s
[i
] == '\n' || s
[i
] == '\t') {
112 } else if(s
[i
] < ' ' || '~' < s
[i
]) {
122 * Read from serial, when we have a packet write it to tun. No output
123 * buffering, input buffered by stdio.
126 serial_to_tun(FILE *inslip
, int outfd
)
129 unsigned char inbuf
[2000];
131 static int inbufptr
= 0;
137 ret
= fread(&c
, 1, 1, inslip
);
138 if(ret
== -1 || ret
== 0) err(1, "serial_to_tun: read");
143 if(inbufptr
>= sizeof(uip
.inbuf
)) {
146 ret
= fread(&c
, 1, 1, inslip
);
151 err(1, "serial_to_tun: read");
156 fprintf(stderr
, "serial_to_tun: EOF\n");
159 /* fprintf(stderr, ".");*/
163 if(uip
.inbuf
[0] == '!') {
164 if (uip
.inbuf
[1] == 'M') {
165 /* Read gateway MAC address and autoconfigure tap0 interface */
168 for(i
= 0, pos
= 0; i
< 16; i
++) {
169 macs
[pos
++] = uip
.inbuf
[2 + i
];
170 if ((i
& 1) == 1 && i
< 14) {
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
);
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");
198 if(fread(&c
, 1, 1, inslip
) != 1) {
200 /* Put ESC back and give up! */
201 ungetc(SLIP_ESC
, inslip
);
215 uip
.inbuf
[inbufptr
++] = c
;
222 unsigned char slip_buf
[2000];
223 int slip_end
, slip_begin
;
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
;
238 return slip_end
== 0;
242 slip_flushbuf(int fd
)
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");
254 PROGRESS("Q"); /* Outqueueis full! */
257 if(slip_begin
== slip_end
) {
258 slip_begin
= slip_end
= 0;
264 write_to_serial(int outfd
, void *inbuf
, int len
)
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
275 /* slip_send(outfd, SLIP_END); */
276 /* printf("writing packet to serial!!! %d\n", len);*/
277 for(i
= 0; i
< len
; i
++) {
280 slip_send(outfd
, SLIP_ESC
);
281 slip_send(outfd
, SLIP_ESC_END
);
284 slip_send(outfd
, SLIP_ESC
);
285 slip_send(outfd
, SLIP_ESC_ESC
);
288 slip_send(outfd
, p
[i
]);
293 slip_send(outfd
, SLIP_END
);
299 * Read from tun, write to slip.
302 tun_to_serial(int infd
, int outfd
)
305 unsigned char inbuf
[2000];
309 if((size
= read(infd
, uip
.inbuf
, 2000)) == -1) err(1, "tun_to_serial: read");
311 write_to_serial(outfd
, uip
.inbuf
, size
);
315 #define BAUDRATE B115200
317 speed_t b_rate
= BAUDRATE
;
323 speed_t speed
= b_rate
;
326 if(tcflush(fd
, TCIOFLUSH
) == -1) err(1, "tcflush");
328 if(tcgetattr(fd
, &tty
) == -1) err(1, "tcgetattr");
332 /* Nonblocking read. */
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");
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");
352 if(ioctl(fd
, TIOCMBIS
, &i
) == -1) err(1, "ioctl");
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
)
367 return open(t
, flags
);
371 #include <linux/if.h>
372 #include <linux/if_tun.h>
380 if( (fd
= open("/dev/net/tun", O_RDWR
)) < 0 )
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
;
392 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
394 if((err
= ioctl(fd
, TUNSETIFF
, (void *) &ifr
)) < 0 ){
398 strcpy(dev
, ifr
.ifr_name
);
405 return devopen(dev
, O_RDWR
);
415 ssystem("ifconfig %s down", tundev
);
417 ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
419 /* ssystem("arp -d %s", ipaddr); */
420 ssystem("netstat -nr"
421 " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
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
;
447 #define TIMEOUT (997*1000)
449 #define TIMEOUT (2451*1000)
451 ualarm(TIMEOUT
, TIMEOUT
);
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
);
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
);
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");
476 ssystem("ifconfig %s\n", tundev
);
480 main(int argc
, char **argv
)
483 int tunfd
, slipfd
, maxfd
;
487 const char *siodev
= NULL
;
490 setvbuf(stdout
, NULL
, _IOLBF
, 0); /* Line buffered output. */
492 while((c
= getopt(argc
, argv
, "B:D:hs:t:")) != -1) {
495 baudrate
= atoi(optarg
);
499 if(strncmp("/dev/", optarg
, 5) == 0) {
507 if(strncmp("/dev/", optarg
, 5) == 0) {
508 strcpy(tundev
, optarg
+ 5);
510 strcpy(tundev
, optarg
);
517 errx(1, USAGE_STRING
);
521 argc
-= (optind
- 1);
522 argv
+= (optind
- 1);
524 if(argc
!= 3 && argc
!= 4) {
525 errx(1, USAGE_STRING
);
529 circuit_addr
= inet_addr(ipaddr
);
530 netaddr
= inet_addr(ipaddr
) & inet_addr(netmask
);
534 break; /* Use default. */
551 err(1, "unknown baudrate %d", baudrate
);
557 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
559 err(1, "can't open siodev ``/dev/%s''", siodev
);
562 static const char *siodevs
[] = {
563 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
566 for(i
= 0; i
< 3; i
++) {
568 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
573 err(1, "can't open siodev");
576 fprintf(stderr
, "slip started on ``/dev/%s''\n", siodev
);
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
);
588 signal(SIGHUP
, sigcleanup
);
589 signal(SIGTERM
, sigcleanup
);
590 signal(SIGINT
, sigcleanup
);
591 signal(SIGALRM
, sigalarm
);
592 ifconf(tundev
, ipaddr
, netmask
);
599 /* request mac address from gateway node for autoconfiguration of
600 ethernet interface tap0 */
602 slip_send(slipfd
, '?');
603 slip_send(slipfd
, 'M');
604 slip_send(slipfd
, SLIP_END
);
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
);
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. */
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
) {
635 if(FD_ISSET(slipfd
, &rset
)) {
636 serial_to_tun(inslip
, tunfd
);
639 if(FD_ISSET(slipfd
, &wset
)) {
640 slip_flushbuf(slipfd
);
644 if(slip_empty() && FD_ISSET(tunfd
, &rset
)) {
645 tun_to_serial(tunfd
, slipfd
);
646 slip_flushbuf(slipfd
);