From fad9ed431b545a8b314e952f50e7fefc49477553 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 1 Dec 2017 15:29:30 +0100 Subject: Split implementation of tun_setaddr6 into a separate module Some systems containing specific versions of libc and linux kernel can produce compilation errors due to conflicting definition of structures in different include files. This can be the case when including and . See for more information: https://sourceware.org/glibc/wiki/Synchronizing_Headers I hit this compilation error on the system I'm compiling osmo-ggsn with: arm-poky-linux-gnueabi-gcc ... -c in46_addr.c In file included from /usr/include/linux/ipv6.h:5:0, from tun.c:75: /usr/include/linux/in6.h:30:8: error: redefinition of 'struct in6_addr' struct in6_addr { ^ In file included from tun.c:24:0: /usr/include/netinet/in.h:196:8: note: originally defined here struct in6_addr ^ To fix the issue, this patch moves tun_setaddr6 to its own file which then includes (which in turn includes in6.h). Change-Id: Ie161f376edda605e5cd87176169553176235fafd --- lib/Makefile.am | 2 +- lib/tun.c | 91 +++--------------------------------------------------- lib/tun6.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 88 deletions(-) create mode 100644 lib/tun6.c diff --git a/lib/Makefile.am b/lib/Makefile.am index 632990c..6eb2a0f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,4 +4,4 @@ noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) -libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c +libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c tun6.c debug.c in46_addr.c diff --git a/lib/tun.c b/lib/tun.c index d8e4b62..4052672 100644 --- a/lib/tun.c +++ b/lib/tun.c @@ -61,9 +61,6 @@ #include "syserr.h" #if defined(__linux__) - -#include - static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen) { int len = RTA_LENGTH(dlen); @@ -79,7 +76,7 @@ static int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, int dlen } #endif -static int tun_sifflags(struct tun_t *this, int flags) +int tun_sifflags(struct tun_t *this, int flags) { struct ifreq ifr; int fd; @@ -197,89 +194,9 @@ static int tun_setaddr4(struct tun_t *this, struct in_addr *addr, return 0; } -static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr, - size_t prefixlen) -{ - struct in6_ifreq ifr; - int fd; - - memset(&ifr, 0, sizeof(ifr)); - -#if defined(__linux__) - ifr.ifr6_prefixlen = prefixlen; - ifr.ifr6_ifindex = if_nametoindex(this->devname); - if (ifr.ifr6_ifindex == 0) { - SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", this->devname); - return -1; - } -#elif defined(__FreeBSD__) || defined (__APPLE__) - strncpy(ifr.ifr_name, this->devname, IFNAMSIZ); -#endif - - /* Create a channel to the NET kernel */ - if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed"); - return -1; - } - -#if defined(__linux__) - if (addr) { - memcpy(&ifr.ifr6_addr, addr, sizeof(*addr)); - if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) { - if (errno != EEXIST) { - SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed"); - } else { - SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists"); - } - close(fd); - return -1; - } - } - -#if 0 - /* FIXME: looks like this is not possible/necessary for IPv6? */ - if (dstaddr) { - memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr)); - memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr)); - if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) { - SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed"); - close(fd); - return -1; - } - } -#endif - -#elif defined(__FreeBSD__) || defined (__APPLE__) - if (addr) - memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr)); - if (dstaddr) - memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr)); - - if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) { - SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed"); - close(fd); - return -1; - } -#endif - - close(fd); - this->addrs++; - - /* On linux the route to the interface is set automatically - on FreeBSD we have to do this manually */ - - /* TODO: How does it work on Solaris? */ - - tun_sifflags(this, IFF_UP | IFF_RUNNING); - -#if 0 /* FIXME */ -//#if defined(__FreeBSD__) || defined (__APPLE__) - tun_addroute6(this, dstaddr, addr, prefixlen); - this->routes = 1; -#endif - - return 0; -} +/* Implemented in tun6.c due to include issues between ip6.h/in6.h and in.h in some systems */ +int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr, + size_t prefixlen); int tun_setaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *dstaddr, size_t prefixlen) { diff --git a/lib/tun6.c b/lib/tun6.c new file mode 100644 index 0000000..85139e5 --- /dev/null +++ b/lib/tun6.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include + +#include "tun.h" +#include "syserr.h" + +/* Defined in tun.c */ +int tun_sifflags(struct tun_t *this, int flags); + +int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr, + size_t prefixlen) +{ + struct in6_ifreq ifr; + int fd; + + memset(&ifr, 0, sizeof(ifr)); + +#if defined(__linux__) + ifr.ifr6_prefixlen = prefixlen; + ifr.ifr6_ifindex = if_nametoindex(this->devname); + if (ifr.ifr6_ifindex == 0) { + SYS_ERR(DTUN, LOGL_ERROR, 0, "Error getting ifindex for %s\n", this->devname); + return -1; + } +#elif defined(__FreeBSD__) || defined (__APPLE__) + strncpy(ifr.ifr_name, this->devname, IFNAMSIZ); +#endif + + /* Create a channel to the NET kernel */ + if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + SYS_ERR(DTUN, LOGL_ERROR, 0, "socket() failed"); + return -1; + } + +#if defined(__linux__) + if (addr) { + memcpy(&ifr.ifr6_addr, addr, sizeof(*addr)); + if (ioctl(fd, SIOCSIFADDR, (void *) &ifr) < 0) { + if (errno != EEXIST) { + SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR) failed"); + } else { + SYS_ERR(DTUN, LOGL_NOTICE, 0, "ioctl(SIOCSIFADDR): Address already exists"); + } + close(fd); + return -1; + } + } + +#if 0 + /* FIXME: looks like this is not possible/necessary for IPv6? */ + if (dstaddr) { + memcpy(&this->dstaddr, dstaddr, sizeof(*dstaddr)); + memcpy(&ifr.ifr6_addr, dstaddr, sizeof(*dstaddr)); + if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t *) &ifr) < 0) { + SYS_ERR(DTUN, LOGL_ERROR, "ioctl(SIOCSIFDSTADDR) failed"); + close(fd); + return -1; + } + } +#endif + +#elif defined(__FreeBSD__) || defined (__APPLE__) + if (addr) + memcpy(&ifr.ifr_ifru.ifru_addr, addr, sizeof(ifr.ifr_ifru.ifru_addr)); + if (dstaddr) + memcpy(&ifr.ifr_ifru.ifru_dstaddr, dstaddr, sizeof(ifr.ifr_ifru.ifru_dstaddr)); + + if (ioctl(fd, SIOCSIFADDR_IN6, (struct ifreq *)&ifr) < 0) { + SYS_ERR(DTUN, LOGL_ERROR, 0, "ioctl(SIOCSIFADDR_IN6) failed"); + close(fd); + return -1; + } +#endif + + close(fd); + this->addrs++; + + /* On linux the route to the interface is set automatically + on FreeBSD we have to do this manually */ + + /* TODO: How does it work on Solaris? */ + + tun_sifflags(this, IFF_UP | IFF_RUNNING); + +#if 0 /* FIXME */ +//#if defined(__FreeBSD__) || defined (__APPLE__) + tun_addroute6(this, dstaddr, addr, prefixlen); + this->routes = 1; +#endif + + return 0; +} -- cgit v1.2.3