/* * Copyright (c) 2011, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * \author * Niclas Finne * Joakim Eriksson */ #include "net/ipv6/uip.h" #include "net/ipv6/uip-ds6.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------*/ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "BR" #define LOG_LEVEL LOG_LEVEL_NONE #ifdef linux #include #include #endif #include #include "net/netstack.h" #include "net/packetbuf.h" #include "cmd.h" #include "border-router.h" extern const char *slip_config_ipaddr; extern char slip_config_tundev[32]; extern uint16_t slip_config_basedelay; #ifndef __CYGWIN__ static int tunfd; static int set_fd(fd_set *rset, fd_set *wset); static void handle_fd(fd_set *rset, fd_set *wset); static const struct select_callback tun_select_callback = { set_fd, handle_fd }; #endif /* __CYGWIN__ */ int ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); int ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); int ssystem(const char *fmt, ...) { char cmd[128]; va_list ap; va_start(ap, fmt); vsnprintf(cmd, sizeof(cmd), fmt, ap); va_end(ap); printf("%s\n", cmd); fflush(stdout); return system(cmd); } /*---------------------------------------------------------------------------*/ void cleanup(void) { ssystem("ifconfig %s down", slip_config_tundev); #ifndef linux ssystem("sysctl -w net.ipv6.conf.all.forwarding=1"); #endif ssystem("netstat -nr" " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'" " | sh", slip_config_tundev); } /*---------------------------------------------------------------------------*/ void sigcleanup(int signo) { fprintf(stderr, "signal %d\n", signo); exit(0); /* exit(0) will call cleanup() */ } /*---------------------------------------------------------------------------*/ void ifconf(const char *tundev, const char *ipaddr) { #ifdef linux ssystem("ifconfig %s inet `hostname` up", tundev); ssystem("ifconfig %s add %s", tundev, ipaddr); #elif defined(__APPLE__) ssystem("ifconfig %s inet6 %s up", tundev, ipaddr); ssystem("sysctl -w net.inet.ip.forwarding=1"); #else ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr); ssystem("sysctl -w net.inet.ip.forwarding=1"); #endif /* !linux */ /* Print the configuration to the console. */ ssystem("ifconfig %s\n", tundev); } /*---------------------------------------------------------------------------*/ int devopen(const char *dev, int flags) { char t[32]; strcpy(t, "/dev/"); strncat(t, dev, sizeof(t) - 5); return open(t, flags); } /*---------------------------------------------------------------------------*/ #ifdef linux int tun_alloc(char *dev) { struct ifreq ifr; int fd, err; if((fd = open("/dev/net/tun", O_RDWR)) < 0) { return -1; } memset(&ifr, 0, sizeof(ifr)); /* Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_NO_PI - Do not provide packet information */ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; if(*dev != 0) { strncpy(ifr.ifr_name, dev, IFNAMSIZ); } if((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { close(fd); return err; } strcpy(dev, ifr.ifr_name); return fd; } #else int tun_alloc(char *dev) { return devopen(dev, O_RDWR); } #endif #ifdef __CYGWIN__ /*wpcap process is used to connect to host interface */ void tun_init() { setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ slip_init(); } #else static uint16_t delaymsec = 0; static uint32_t delaystartsec, delaystartmsec; /*---------------------------------------------------------------------------*/ void tun_init() { setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ slip_init(); LOG_INFO("Opening tun interface:%s\n", slip_config_tundev); tunfd = tun_alloc(slip_config_tundev); if(tunfd == -1) { err(1, "tun_init: open"); } select_set_callback(tunfd, &tun_select_callback); fprintf(stderr, "opened %s device ``/dev/%s''\n", "tun", slip_config_tundev); atexit(cleanup); signal(SIGHUP, sigcleanup); signal(SIGTERM, sigcleanup); signal(SIGINT, sigcleanup); ifconf(slip_config_tundev, slip_config_ipaddr); } /*---------------------------------------------------------------------------*/ static int tun_output(uint8_t *data, int len) { /* fprintf(stderr, "*** Writing to tun...%d\n", len); */ if(write(tunfd, data, len) != len) { err(1, "serial_to_tun: write"); return -1; } return 0; } /*---------------------------------------------------------------------------*/ int tun_input(unsigned char *data, int maxlen) { int size; if((size = read(tunfd, data, maxlen)) == -1) { err(1, "tun_input: read"); } return size; } /*---------------------------------------------------------------------------*/ static void init(void) { } /*---------------------------------------------------------------------------*/ static int output(void) { LOG_DBG("SUT: %u\n", uip_len); if(uip_len > 0) { return tun_output(uip_buf, uip_len); } return 0; } const struct uip_fallback_interface rpl_interface = { init, output }; /*---------------------------------------------------------------------------*/ /* tun and slip select callback */ /*---------------------------------------------------------------------------*/ static int set_fd(fd_set *rset, fd_set *wset) { FD_SET(tunfd, rset); return 1; } /*---------------------------------------------------------------------------*/ static void handle_fd(fd_set *rset, fd_set *wset) { /* Optional delay between outgoing packets */ /* Base delay times number of 6lowpan fragments to be sent */ /* delaymsec = 10; */ if(delaymsec) { struct timeval tv; int dmsec; gettimeofday(&tv, NULL); dmsec = (tv.tv_sec - delaystartsec) * 1000 + tv.tv_usec / 1000 - delaystartmsec; if(dmsec < 0) { delaymsec = 0; } if(dmsec > delaymsec) { delaymsec = 0; } } if(delaymsec == 0) { int size; if(FD_ISSET(tunfd, rset)) { size = tun_input(uip_buf, sizeof(uip_buf)); /* printf("TUN data incoming read:%d\n", size); */ uip_len = size; tcpip_input(); if(slip_config_basedelay) { struct timeval tv; gettimeofday(&tv, NULL); delaymsec = slip_config_basedelay; delaystartsec = tv.tv_sec; delaystartmsec = tv.tv_usec / 1000; } } } } #endif /* __CYGWIN_ */ /*---------------------------------------------------------------------------*/