Removed some warnings.
[contiki-2.x/lpc17xxx.git] / tools / stm32w / tapslip6.c
blob31ac0ecd23b04adb4c14962b5d41576e561021f7
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.1 2010/10/25 10:42:41 salvopitru Exp $
35 /**
36 * \file
37 * A driver for the uip6-bridge customized for STM32W. Thanks to
38 * Adam Dunkels, Joakim Eriksson, Niclas Finne for the original
39 * code.
40 * \author
41 * Salvatore Pitrulli <salvopitru@users.sourceforge.net>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include <time.h>
49 #include <sys/types.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <signal.h>
55 #include <termios.h>
56 #include <sys/ioctl.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
62 #include <err.h>
64 int ssystem(const char *fmt, ...)
65 __attribute__ ((__format__(__printf__, 1, 2)));
66 void write_to_serial(void *inbuf, int len);
68 #define PRINTF(...) if(verbose)printf(__VA_ARGS__)
70 //#define PROGRESS(s) fprintf(stderr, s)
71 #define PROGRESS(s) do { } while (0)
73 #define USAGE_STRING "usage: tapslip6 [-B baudrate] [-s siodev] [-t tundev] [-a ipaddress[/prefixlen]|-p 64bit-prefix[/prefixlen]] [-c channel] [-r] [-v] [-h]"
74 #define HELP_STRING "usage: tapslip6 [-B baudrate] [-s siodev] [-t tundev] [-a ipaddress[/prefixlen]|-p 64bit-prefix[/prefixlen]] [-c channel] [-r] [-v] [-h]\r\n\n\
75 Options:\r\n\
76 -B baudrate\tBaudrate of the serial port (default:115200).\r\n\
77 -s siodev\tDevice that identifies the bridge (default: the first available\r\n\
78 \t\tamong ttyUSB0, cuaU0 and ucom0)\r\n\
79 -t tundev\tThe virtual network interface (default: tap0)\r\n\
80 -c channel\t802.15.4 radio channel.\r\n\
81 -r\t\tSet sniffer mode. \r\n\
82 -a ipaddress/[prefixlen] The address to be assigned to the virtual network\r\n\
83 \t\tadapter.\r\n\
84 -p 64bit-prefix\tAutomatic assignment of the IPv6 address from the specified\r\n\
85 \t\tsubnet prefix. It may be followed by the prefix length\r\n\
86 \t\tfor the on-link determination.\r\n\
87 -v\t\tVerbose. Print more infos.\r\n\
88 -h\t\tShow this help.\r\n"
90 typedef enum {
91 false = 0,
92 true = 1,
93 } bool;
95 char tundev[32] = { "tap0" };
97 const char *ipaddr = NULL;
98 char *ipprefix = NULL;
99 char autoconf_addr[44] = { 0 };
101 bool autoconf = false;
102 bool verbose = false;
104 struct uip_eth_addr {
105 uint8_t addr[6];
107 struct uip_802154_longaddr {
108 uint8_t addr[8];
111 static struct uip_eth_addr eth_addr;
112 const struct uip_eth_addr eth_addr_null = { {0} };
114 static int request_mac = 1;
115 static int send_mac = 1;
116 static int set_sniffer_mode = 1;
117 static int set_channel = 1;
119 static int sniffer_mode = 0;
120 static int channel = 0;
123 int ssystem(const char *fmt, ...)
124 __attribute__ ((__format__(__printf__, 1, 2)));
126 int ssystem(const char *fmt, ...)
128 char cmd[128];
129 va_list ap;
130 va_start(ap, fmt);
131 vsnprintf(cmd, sizeof(cmd), fmt, ap);
132 va_end(ap);
133 printf("%s\n", cmd);
134 fflush(stdout);
135 return system(cmd);
138 #define SLIP_END 0300
139 #define SLIP_ESC 0333
140 #define SLIP_ESC_END 0334
141 #define SLIP_ESC_ESC 0335
143 static void print_packet(u_int8_t * p, int len)
145 int i;
146 for (i = 0; i < len; i++) {
147 printf("%02x", p[i]);
148 if ((i & 3) == 3)
149 printf(" ");
150 if ((i & 15) == 15)
151 printf("\n");
153 printf("\n");
156 int is_sensible_string(const unsigned char *s, int len)
158 int i;
159 for (i = 1; i < len; i++) {
160 if (s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
161 continue;
163 else if (s[i] < ' ' || '~' < s[i]) {
164 return 0;
167 return 1;
173 * Read from serial, when we have a packet write it to tun. No output
174 * buffering, input buffered by stdio.
176 void serial_to_tun(FILE * inslip, int outfd)
178 static union {
179 unsigned char inbuf[2000];
180 } uip;
181 static int inbufptr = 0;
183 int ret;
184 unsigned char c;
186 #ifdef linux
187 ret = fread(&c, 1, 1, inslip);
188 if (ret == -1 || ret == 0)
189 err(1, "serial_to_tun: read");
190 goto after_fread;
191 #endif
193 read_more:
194 if (inbufptr >= sizeof(uip.inbuf)) {
195 inbufptr = 0;
197 ret = fread(&c, 1, 1, inslip);
198 #ifdef linux
199 after_fread:
200 #endif
201 if (ret == -1) {
202 err(1, "serial_to_tun: read");
204 if (ret == 0) {
205 clearerr(inslip);
206 return;
207 fprintf(stderr, "serial_to_tun: EOF\n");
208 exit(1);
210 /* fprintf(stderr, "."); */
211 switch (c) {
212 case SLIP_END:
213 if (inbufptr > 0) {
214 if (uip.inbuf[0] == '!') {
215 if (uip.inbuf[1] == 'M') {
216 /* Read gateway MAC address and autoconfigure tap0 interface */
217 char macs[24];
218 int i, pos;
219 struct uip_802154_longaddr dev_addr = { {0} }; // Bridge EUI-64.
221 for (i = 0, pos = 0; i < 16; i++) {
222 macs[pos++] = uip.inbuf[2 + i];
223 if ((i & 1) == 1 && i < 14) {
224 macs[pos++] = ':';
227 macs[pos] = '\0';
228 printf("*** Gateway's MAC address: %s\n", macs);
232 int addr_bytes[8]; // sscanf requires int instead of 8-bit for hexadecimal variables.
234 sscanf(macs, "%2X:%2X:%2X:%2X:%2X:%2X:%2X:%2X",
235 &addr_bytes[0],
236 &addr_bytes[1],
237 &addr_bytes[2],
238 &addr_bytes[3],
239 &addr_bytes[4],
240 &addr_bytes[5],
241 &addr_bytes[6],
242 &addr_bytes[7]);
244 for(i=0;i<8;i++){
245 dev_addr.addr[i] = addr_bytes[i];
249 ////////////////////////////////////////
250 /*PRINTF("MAC:\n");
251 for (i = 0; i < 8; i++)
252 PRINTF("%02X ", dev_addr.addr[i]);
253 PRINTF("\n"); */
254 ////////////////////////////////////////
256 // Remember what will be our MAC address (two middle bytes will be elided).
257 memcpy(&eth_addr, &dev_addr, 3);
258 memcpy(&eth_addr.addr[3], &dev_addr.addr[5], 3);
260 if (autoconf) {
262 struct in6_addr ipv6addr;
264 dev_addr.addr[0] |= 0x02;
266 strtok(ipprefix, "/");
268 if (inet_pton(AF_INET6, ipprefix, &ipv6addr) != 1) {
269 printf("Invalid IPv6 address.\n");
270 exit(1);
273 // Copy modified EUI-64 to the last 64 bits of IPv6 address.
274 memcpy(&ipv6addr.s6_addr[8], &dev_addr, 8);
276 inet_ntop(AF_INET6, &ipv6addr, autoconf_addr, INET6_ADDRSTRLEN); // To string format.
278 char *substr = strtok(NULL, "/");
279 if (substr != NULL) { // Add the prefix length.
280 strcat(autoconf_addr, "/");
281 strcat(autoconf_addr, substr);
283 ipaddr = autoconf_addr;
286 ssystem("ifconfig %s down", tundev);
289 strcpy(&macs[9], &macs[15]); // Elide two middle bytes.
290 ssystem("ifconfig %s hw ether %s", tundev, macs);
291 ssystem("ifconfig %s inet6 up", tundev);
292 if(ipaddr){
293 ssystem("ifconfig %s inet6 add %s", tundev, ipaddr);
294 ssystem("sysctl -w net.ipv6.conf.all.forwarding=1");
296 ssystem("ifconfig %s\n", tundev);
299 #define DEBUG_LINE_MARKER '\r'
301 else if (uip.inbuf[0] == '?') {
302 if (uip.inbuf[1] == 'M'
303 && memcmp(&eth_addr, &eth_addr_null, 6) != 0) {
304 /* Send our MAC address and other configuration options. */
305 send_mac = 1;
306 set_sniffer_mode = 1;
307 set_channel = 1;
310 else if (uip.inbuf[0] == DEBUG_LINE_MARKER) {
311 fwrite(uip.inbuf + 1, inbufptr - 1, 1, stdout);
313 else if (is_sensible_string(uip.inbuf, inbufptr)) {
314 fwrite(uip.inbuf, inbufptr, 1, stdout);
316 else {
317 PRINTF("Writing to tun len: %d\n", inbufptr);
318 /* print_packet(uip.inbuf, inbufptr); */
319 if (write(outfd, uip.inbuf, inbufptr) != inbufptr) {
320 err(1, "serial_to_tun: write");
323 inbufptr = 0;
325 break;
327 case SLIP_ESC:
328 if (fread(&c, 1, 1, inslip) != 1) {
329 clearerr(inslip);
330 /* Put ESC back and give up! */
331 ungetc(SLIP_ESC, inslip);
332 return;
335 switch (c) {
336 case SLIP_ESC_END:
337 c = SLIP_END;
338 break;
339 case SLIP_ESC_ESC:
340 c = SLIP_ESC;
341 break;
343 /* FALLTHROUGH */
344 default:
345 uip.inbuf[inbufptr++] = c;
346 break;
349 goto read_more;
352 unsigned char slip_buf[2000];
353 int slip_end, slip_begin;
356 void slip_send(unsigned char c)
358 if (slip_end >= sizeof(slip_buf))
359 err(1, "slip_send overflow");
360 slip_buf[slip_end] = c;
361 slip_end++;
364 int slip_empty()
366 return slip_end == 0;
369 void slip_flushbuf(int fd)
371 int n;
373 if (slip_empty())
374 return;
376 n = write(fd, slip_buf + slip_begin, (slip_end - slip_begin));
378 if (n == -1 && errno != EAGAIN) {
379 err(1, "slip_flushbuf write failed");
381 else if (n == -1) {
382 PROGRESS("Q"); /* Outqueueis full! */
384 else {
385 slip_begin += n;
386 if (slip_begin == slip_end) {
387 slip_begin = slip_end = 0;
392 void write_to_serial(void *inbuf, int len)
394 u_int8_t *p = inbuf;
395 int i;
397 /* printf("Got packet of length %d - write SLIP\n", len); */
398 /* print_packet(p, len); */
400 /* It would be ``nice'' to send a SLIP_END here but it's not
401 * really necessary.
403 /* slip_send(outfd, SLIP_END); */
404 PRINTF("Writing to serial len: %d\n", len);
405 for (i = 0; i < len; i++) {
406 switch (p[i]) {
407 case SLIP_END:
408 slip_send(SLIP_ESC);
409 slip_send(SLIP_ESC_END);
410 break;
411 case SLIP_ESC:
412 slip_send(SLIP_ESC);
413 slip_send(SLIP_ESC_ESC);
414 break;
415 default:
416 slip_send(p[i]);
417 break;
421 slip_send(SLIP_END);
422 PROGRESS("t");
427 * Read from tun, write to slip.
429 void tun_to_serial(int infd, int outfd)
431 struct {
432 unsigned char inbuf[2000];
433 } uip;
434 int size;
436 if ((size = read(infd, uip.inbuf, 2000)) == -1)
437 err(1, "tun_to_serial: read");
439 write_to_serial(uip.inbuf, size);
442 #ifndef BAUDRATE
443 #define BAUDRATE B115200
444 #endif
445 speed_t b_rate = BAUDRATE;
447 void stty_telos(int fd)
449 struct termios tty;
450 speed_t speed = b_rate;
451 int i;
453 if (tcflush(fd, TCIOFLUSH) == -1)
454 err(1, "tcflush");
456 if (tcgetattr(fd, &tty) == -1)
457 err(1, "tcgetattr");
459 cfmakeraw(&tty);
461 /* Nonblocking read. */
462 tty.c_cc[VTIME] = 0;
463 tty.c_cc[VMIN] = 0;
464 tty.c_cflag &= ~CRTSCTS;
465 tty.c_cflag &= ~HUPCL;
466 tty.c_cflag &= ~CLOCAL;
468 cfsetispeed(&tty, speed);
469 cfsetospeed(&tty, speed);
471 if (tcsetattr(fd, TCSAFLUSH, &tty) == -1)
472 err(1, "tcsetattr");
474 #if 1
475 /* Nonblocking read and write. */
476 /* if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */
478 tty.c_cflag |= CLOCAL;
479 if (tcsetattr(fd, TCSAFLUSH, &tty) == -1)
480 err(1, "tcsetattr");
482 i = TIOCM_DTR;
483 if (ioctl(fd, TIOCMBIS, &i) == -1)
484 err(1, "ioctl");
485 #endif
487 usleep(10 * 1000); /* Wait for hardware 10ms. */
489 /* Flush input and output buffers. */
490 if (tcflush(fd, TCIOFLUSH) == -1)
491 err(1, "tcflush");
494 int devopen(const char *dev, int flags)
496 char t[32];
497 strcpy(t, "/dev/");
498 strcat(t, dev);
499 return open(t, flags);
502 #ifdef linux
503 #include <linux/if.h>
504 #include <linux/if_tun.h>
506 int tun_alloc(char *dev)
508 struct ifreq ifr;
509 int fd, err;
511 if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
512 return -1;
514 memset(&ifr, 0, sizeof(ifr));
516 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
517 * IFF_TAP - TAP device
519 * IFF_NO_PI - Do not provide packet information
521 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
522 if (*dev != 0)
523 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
525 if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
526 close(fd);
527 return err;
529 strcpy(dev, ifr.ifr_name);
530 return fd;
532 #else
533 int tun_alloc(char *dev)
535 return devopen(dev, O_RDWR);
537 #endif
540 void cleanup(void)
542 ssystem("ifconfig %s down", tundev);
543 if(ipaddr){
544 ssystem("sysctl -w net.ipv6.conf.all.forwarding=0");
548 void sigcleanup(int signo)
550 fprintf(stderr, "signal %d\n", signo);
551 exit(0); /* exit(0) will call cleanup() */
555 static int request_mac;
556 static int send_mac;
558 void send_commands(void)
560 char buf[3];
562 if (request_mac) {
563 slip_send('?');
564 slip_send('M');
565 slip_send(SLIP_END);
567 request_mac = 0;
569 /* Send our mac to the device. If it knows our address, it is not needed to change
570 the MAC address of our local interface (this can be also unsupported, especially under
571 Windows).
573 else if(send_mac && memcmp(&eth_addr, &eth_addr_null, 6) != 0
574 && slip_empty()){
575 short i;
576 PRINTF("Sending our MAC.\n");
578 slip_send('!');
579 slip_send('M');
581 for(i=0; i < 6; i++){
582 sprintf(buf,"%02X",eth_addr.addr[i]);
583 slip_send(buf[0]);
584 slip_send(buf[1]);
586 slip_send(SLIP_END);
588 send_mac = 0;
590 else if(set_sniffer_mode && slip_empty()){
592 PRINTF("Setting sniffer mode to %d.\n", sniffer_mode);
594 slip_send('!');
595 slip_send('O');
596 slip_send('S');
598 if(sniffer_mode){
599 slip_send('1');
601 else {
602 slip_send('0');
604 slip_send(SLIP_END);
606 set_sniffer_mode = 0;
609 else if(set_channel && slip_empty()){
611 if(channel != 0){
612 PRINTF("Setting channel %02d.\n", channel);
614 slip_send('!');
615 slip_send('O');
616 slip_send('C');
618 sprintf(buf,"%02d",channel);
619 slip_send(buf[0]);
620 slip_send(buf[1]);
622 slip_send(SLIP_END);
625 set_channel = 0;
631 int main(int argc, char **argv)
633 int c;
634 int tunfd, slipfd, maxfd;
635 int ret;
636 fd_set rset, wset;
637 FILE *inslip;
638 const char *siodev = NULL;
639 int baudrate = -2;
641 setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */
643 while ((c = getopt(argc, argv, "B:D:hs:c:rt:a:p:v")) != -1) {
644 switch (c) {
645 case 'B':
646 baudrate = atoi(optarg);
647 break;
649 case 's':
650 if (strncmp("/dev/", optarg, 5) == 0) {
651 siodev = optarg + 5;
653 else {
654 siodev = optarg;
656 break;
658 case 't':
659 if (strncmp("/dev/", optarg, 5) == 0) {
660 strcpy(tundev, optarg + 5);
662 else {
663 strcpy(tundev, optarg);
665 break;
667 case 'c':
668 channel = atoi(optarg);
669 set_channel = 1;
670 break;
671 case 'r':
672 sniffer_mode = 1;
673 break;
675 case 'a':
676 if (autoconf == true) {
677 errx(1, USAGE_STRING);
679 ipaddr = optarg;
680 break;
682 case 'p':
683 if (ipaddr != NULL) {
684 errx(1, USAGE_STRING);
686 autoconf = true;
687 ipprefix = optarg;
688 break;
690 case 'v':
691 verbose = true;
692 break;
694 case '?':
695 case 'h':
696 default:
697 errx(1, HELP_STRING);
698 break;
701 #if 0
702 argc -= (optind - 1);
703 argv += (optind - 1);
705 //if(argc != 3 && argc != 4) {
706 //if (autoconf == false && ipaddr == NULL ) {
707 errx(1, USAGE_STRING);
709 #endif
712 switch (baudrate) {
713 case -2:
714 break; /* Use default. */
715 case 9600:
716 b_rate = B9600;
717 break;
718 case 19200:
719 b_rate = B19200;
720 break;
721 case 38400:
722 b_rate = B38400;
723 break;
724 case 57600:
725 b_rate = B57600;
726 break;
727 case 115200:
728 b_rate = B115200;
729 break;
730 default:
731 err(1, "unknown baudrate %d", baudrate);
732 break;
736 if (siodev != NULL) {
737 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
738 if (slipfd == -1) {
739 err(1, "can't open siodev ``/dev/%s''", siodev);
742 else {
743 static const char *siodevs[] = {
744 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
746 int i;
747 for (i = 0; i < 3; i++) {
748 siodev = siodevs[i];
749 slipfd = devopen(siodev, O_RDWR | O_NONBLOCK);
750 if (slipfd != -1)
751 break;
753 if (slipfd == -1) {
754 err(1, "can't open siodev");
757 fprintf(stderr, "slip started on ``/dev/%s''\n", siodev);
758 stty_telos(slipfd);
759 slip_send(SLIP_END);
760 inslip = fdopen(slipfd, "r");
761 if (inslip == NULL)
762 err(1, "main: fdopen");
764 tunfd = tun_alloc(tundev);
765 printf("opening: %s\n", tundev);
766 if (tunfd == -1)
767 err(1, "main: open");
768 fprintf(stderr, "opened device ``/dev/%s''\n", tundev);
770 atexit(cleanup);
771 signal(SIGHUP, sigcleanup);
772 signal(SIGTERM, sigcleanup);
773 signal(SIGINT, sigcleanup);
777 while (1) {
778 maxfd = 0;
779 FD_ZERO(&rset);
780 FD_ZERO(&wset);
782 send_commands();
784 if (!slip_empty()) { /* Anything to flush? */
785 FD_SET(slipfd, &wset);
788 FD_SET(slipfd, &rset); /* Read from slip ASAP! */
789 if (slipfd > maxfd)
790 maxfd = slipfd;
792 /* We only have one packet at a time queued for slip output. */
793 if (slip_empty()) {
794 FD_SET(tunfd, &rset);
795 if (tunfd > maxfd)
796 maxfd = tunfd;
799 ret = select(maxfd + 1, &rset, &wset, NULL, NULL);
800 if (ret == -1 && errno != EINTR) {
801 err(1, "select");
803 else if (ret > 0) {
804 if (FD_ISSET(slipfd, &rset)) {
805 serial_to_tun(inslip, tunfd);
808 if (FD_ISSET(slipfd, &wset)) {
809 slip_flushbuf(slipfd);
812 if (slip_empty() && FD_ISSET(tunfd, &rset)) {
813 tun_to_serial(tunfd, slipfd);
814 slip_flushbuf(slipfd);