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: tunslip6.c,v 1.1 2010/04/02 18:17:20 joxe 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 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" };
68 ssystem(const char *fmt
, ...) __attribute__((__format__ (__printf__
, 1, 2)));
71 ssystem(const char *fmt
, ...)
76 vsnprintf(cmd
, sizeof(cmd
), fmt
, ap
);
85 #define SLIP_ESC_END 0334
86 #define SLIP_ESC_ESC 0335
90 is_sensible_string(const unsigned char *s
, int len
)
93 for(i
= 1; i
< len
; i
++) {
94 if(s
[i
] == 0 || s
[i
] == '\r' || s
[i
] == '\n' || s
[i
] == '\t') {
96 } else if(s
[i
] < ' ' || '~' < s
[i
]) {
104 * Read from serial, when we have a packet write it to tun. No output
105 * buffering, input buffered by stdio.
108 serial_to_tun(FILE *inslip
, int outfd
)
111 unsigned char inbuf
[2000];
113 static int inbufptr
= 0;
119 ret
= fread(&c
, 1, 1, inslip
);
120 if(ret
== -1 || ret
== 0) err(1, "serial_to_tun: read");
125 if(inbufptr
>= sizeof(uip
.inbuf
)) {
128 ret
= fread(&c
, 1, 1, inslip
);
133 err(1, "serial_to_tun: read");
138 fprintf(stderr
, "serial_to_tun: EOF\n");
141 /* fprintf(stderr, ".");*/
145 if(uip
.inbuf
[0] == '!') {
146 if (uip
.inbuf
[1] == 'M') {
147 /* Read gateway MAC address and autoconfigure tap0 interface */
150 for(i
= 0, pos
= 0; i
< 16; i
++) {
151 macs
[pos
++] = uip
.inbuf
[2 + i
];
152 if ((i
& 1) == 1 && i
< 14) {
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
);
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");
179 if(fread(&c
, 1, 1, inslip
) != 1) {
181 /* Put ESC back and give up! */
182 ungetc(SLIP_ESC
, inslip
);
196 uip
.inbuf
[inbufptr
++] = c
;
203 unsigned char slip_buf
[2000];
204 int slip_end
, slip_begin
;
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
;
218 return slip_end
== 0;
222 slip_flushbuf(int fd
)
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");
234 PROGRESS("Q"); /* Outqueueis full! */
237 if(slip_begin
== slip_end
) {
238 slip_begin
= slip_end
= 0;
244 write_to_serial(int outfd
, void *inbuf
, int len
)
250 printf("Got packet of length %d - write SLIP\n", len
);
251 for(i
= 0; i
< len
; i
++) {
252 printf("%02x", p
[i
]);
261 /* It would be ``nice'' to send a SLIP_END here but it's not
264 /* slip_send(outfd, SLIP_END); */
266 printf("writing packet to serial!!! %d\n", len
);
268 for(i
= 0; i
< len
; i
++) {
271 slip_send(outfd
, SLIP_ESC
);
272 slip_send(outfd
, SLIP_ESC_END
);
275 slip_send(outfd
, SLIP_ESC
);
276 slip_send(outfd
, SLIP_ESC_ESC
);
279 slip_send(outfd
, p
[i
]);
284 slip_send(outfd
, SLIP_END
);
290 * Read from tun, write to slip.
293 tun_to_serial(int infd
, int outfd
)
296 unsigned char inbuf
[2000];
300 if((size
= read(infd
, uip
.inbuf
, 2000)) == -1) err(1, "tun_to_serial: read");
302 write_to_serial(outfd
, uip
.inbuf
, size
);
306 #define BAUDRATE B115200
308 speed_t b_rate
= BAUDRATE
;
314 speed_t speed
= b_rate
;
317 if(tcflush(fd
, TCIOFLUSH
) == -1) err(1, "tcflush");
319 if(tcgetattr(fd
, &tty
) == -1) err(1, "tcgetattr");
323 /* Nonblocking read. */
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");
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");
343 if(ioctl(fd
, TIOCMBIS
, &i
) == -1) err(1, "ioctl");
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
)
358 return open(t
, flags
);
362 #include <linux/if.h>
363 #include <linux/if_tun.h>
371 if( (fd
= open("/dev/net/tun", O_RDWR
)) < 0 )
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
;
383 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
385 if((err
= ioctl(fd
, TUNSETIFF
, (void *) &ifr
)) < 0 ){
389 strcpy(dev
, ifr
.ifr_name
);
396 return devopen(dev
, O_RDWR
);
406 ssystem("ifconfig %s down", tundev
);
408 ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
411 /* ssystem("arp -d %s", ipaddr); */
412 ssystem("netstat -nr"
413 " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
419 sigcleanup(int signo
)
421 fprintf(stderr
, "signal %d\n", signo
);
422 exit(0); /* exit(0) will call cleanup() */
425 static int got_sigalarm
;
438 #define TIMEOUT (997*1000)
440 #define TIMEOUT (2451*1000)
442 ualarm(TIMEOUT
, TIMEOUT
);
447 ifconf(const char *tundev
, const char *ipaddr
)
450 ssystem("ifconfig %s inet `hostname` up", tundev
);
451 ssystem("ifconfig %s add %s", tundev
, ipaddr
);
453 ssystem("ifconfig %s inet `hostname` %s up", tundev
, ipaddr
);
454 ssystem("sysctl -w net.inet.ip.forwarding=1");
457 ssystem("ifconfig %s\n", tundev
);
461 main(int argc
, char **argv
)
464 int tunfd
, slipfd
, maxfd
;
468 const char *siodev
= NULL
;
471 setvbuf(stdout
, NULL
, _IOLBF
, 0); /* Line buffered output. */
473 while((c
= getopt(argc
, argv
, "B:D:hs:t:v:")) != -1) {
476 baudrate
= atoi(optarg
);
480 if(strncmp("/dev/", optarg
, 5) == 0) {
488 if(strncmp("/dev/", optarg
, 5) == 0) {
489 strcpy(tundev
, optarg
+ 5);
491 strcpy(tundev
, optarg
);
500 err(1, "usage: tunslip6 [-B baudrate] [-s siodev] [-t tundev] ipaddress");
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 ");
514 break; /* Use default. */
531 err(1, "unknown baudrate %d", baudrate
);
537 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
539 err(1, "can't open siodev ``/dev/%s''", siodev
);
542 static const char *siodevs
[] = {
543 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
546 for(i
= 0; i
< 3; i
++) {
548 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
553 err(1, "can't open siodev");
556 fprintf(stderr
, "slip started on ``/dev/%s''\n", siodev
);
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
);
567 signal(SIGHUP
, sigcleanup
);
568 signal(SIGTERM
, sigcleanup
);
569 signal(SIGINT
, sigcleanup
);
570 signal(SIGALRM
, sigalarm
);
571 ifconf(tundev
, ipaddr
);
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; */
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. */
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
) {
606 if(FD_ISSET(slipfd
, &rset
)) {
607 serial_to_tun(inslip
, tunfd
);
610 if(FD_ISSET(slipfd
, &wset
)) {
611 slip_flushbuf(slipfd
);
615 if(slip_empty() && FD_ISSET(tunfd
, &rset
)) {
616 tun_to_serial(tunfd
, slipfd
);
617 slip_flushbuf(slipfd
);