diff --git a/include/linux/compiler.h b/include/linux/compiler.h new file mode 100644 index 0000000..923d093 --- /dev/null +++ b/include/linux/compiler.h @@ -0,0 +1,313 @@ +#ifndef __LINUX_COMPILER_H +#define __LINUX_COMPILER_H + +#ifndef __ASSEMBLY__ + +#ifdef __CHECKER__ +# define __user __attribute__((noderef, address_space(1))) +# define __kernel __attribute__((address_space(0))) +# define __safe __attribute__((safe)) +# define __force __attribute__((force)) +# define __nocast __attribute__((nocast)) +# define __iomem __attribute__((noderef, address_space(2))) +# define __acquires(x) __attribute__((context(x,0,1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) +# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) +# define __percpu __attribute__((noderef, address_space(3))) +#ifdef CONFIG_SPARSE_RCU_POINTER +# define __rcu __attribute__((noderef, address_space(4))) +#else +# define __rcu +#endif +extern void __chk_user_ptr(const volatile void __user *); +extern void __chk_io_ptr(const volatile void __iomem *); +#else +# define __user +# define __kernel +# define __safe +# define __force +# define __nocast +# define __iomem +# define __chk_user_ptr(x) (void)0 +# define __chk_io_ptr(x) (void)0 +# define __builtin_warning(x, y...) (1) +# define __acquires(x) +# define __releases(x) +# define __acquire(x) (void)0 +# define __release(x) (void)0 +# define __cond_lock(x,c) (c) +# define __percpu +# define __rcu +#endif + +#ifdef __KERNEL__ + +#ifdef __GNUC__ +#include +#endif + +#define notrace __attribute__((no_instrument_function)) + +/* Intel compiler defines __GNUC__. So we will overwrite implementations + * coming from above header files here + */ +#ifdef __INTEL_COMPILER +# include +#endif + +/* + * Generic compiler-dependent macros required for kernel + * build go below this comment. Actual compiler/compiler version + * specific implementations come from the above header files + */ + +struct ftrace_branch_data { + const char *func; + const char *file; + unsigned line; + union { + struct { + unsigned long correct; + unsigned long incorrect; + }; + struct { + unsigned long miss; + unsigned long hit; + }; + unsigned long miss_hit[2]; + }; +}; + +/* + * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code + * to disable branch tracing on a per file basis. + */ +#if defined(CONFIG_TRACE_BRANCH_PROFILING) \ + && !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__) +void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); + +#define likely_notrace(x) __builtin_expect(!!(x), 1) +#define unlikely_notrace(x) __builtin_expect(!!(x), 0) + +#define __branch_check__(x, expect) ({ \ + int ______r; \ + static struct ftrace_branch_data \ + __attribute__((__aligned__(4))) \ + __attribute__((section("_ftrace_annotated_branch"))) \ + ______f = { \ + .func = __func__, \ + .file = __FILE__, \ + .line = __LINE__, \ + }; \ + ______r = likely_notrace(x); \ + ftrace_likely_update(&______f, ______r, expect); \ + ______r; \ + }) + +/* + * Using __builtin_constant_p(x) to ignore cases where the return + * value is always the same. This idea is taken from a similar patch + * written by Daniel Walker. + */ +# ifndef likely +# define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1)) +# endif +# ifndef unlikely +# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0)) +# endif + +#ifdef CONFIG_PROFILE_ALL_BRANCHES +/* + * "Define 'is'", Bill Clinton + * "Define 'if'", Steven Rostedt + */ +#define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) ) +#define __trace_if(cond) \ + if (__builtin_constant_p((cond)) ? !!(cond) : \ + ({ \ + int ______r; \ + static struct ftrace_branch_data \ + __attribute__((__aligned__(4))) \ + __attribute__((section("_ftrace_branch"))) \ + ______f = { \ + .func = __func__, \ + .file = __FILE__, \ + .line = __LINE__, \ + }; \ + ______r = !!(cond); \ + ______f.miss_hit[______r]++; \ + ______r; \ + })) +#endif /* CONFIG_PROFILE_ALL_BRANCHES */ + +#else +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +/* Optimization barrier */ +#ifndef barrier +# define barrier() __memory_barrier() +#endif + +/* Unreachable code */ +#ifndef unreachable +# define unreachable() do { } while (1) +#endif + +#ifndef RELOC_HIDE +# define RELOC_HIDE(ptr, off) \ + ({ unsigned long __ptr; \ + __ptr = (unsigned long) (ptr); \ + (typeof(ptr)) (__ptr + (off)); }) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#ifdef __KERNEL__ +/* + * Allow us to mark functions as 'deprecated' and have gcc emit a nice + * warning for each use, in hopes of speeding the functions removal. + * Usage is: + * int __deprecated foo(void) + */ +#ifndef __deprecated +# define __deprecated /* unimplemented */ +#endif + +#ifdef MODULE +#define __deprecated_for_modules __deprecated +#else +#define __deprecated_for_modules +#endif + +#ifndef __must_check +#define __must_check +#endif + +#ifndef CONFIG_ENABLE_MUST_CHECK +#undef __must_check +#define __must_check +#endif +#ifndef CONFIG_ENABLE_WARN_DEPRECATED +#undef __deprecated +#undef __deprecated_for_modules +#define __deprecated +#define __deprecated_for_modules +#endif + +/* + * Allow us to avoid 'defined but not used' warnings on functions and data, + * as well as force them to be emitted to the assembly file. + * + * As of gcc 3.4, static functions that are not marked with attribute((used)) + * may be elided from the assembly file. As of gcc 3.4, static data not so + * marked will not be elided, but this may change in a future gcc version. + * + * NOTE: Because distributions shipped with a backported unit-at-a-time + * compiler in gcc 3.3, we must define __used to be __attribute__((used)) + * for gcc >=3.3 instead of 3.4. + * + * In prior versions of gcc, such functions and data would be emitted, but + * would be warned about except with attribute((unused)). + * + * Mark functions that are referenced only in inline assembly as __used so + * the code is emitted even though it appears to be unreferenced. + */ +#ifndef __used +# define __used /* unimplemented */ +#endif + +#ifndef __maybe_unused +# define __maybe_unused /* unimplemented */ +#endif + +#ifndef __always_unused +# define __always_unused /* unimplemented */ +#endif + +#ifndef noinline +#define noinline +#endif + +/* + * Rather then using noinline to prevent stack consumption, use + * noinline_for_stack instead. For documentation reasons. + */ +#define noinline_for_stack noinline + +#ifndef __always_inline +#define __always_inline inline +#endif + +#endif /* __KERNEL__ */ + +/* + * From the GCC manual: + * + * Many functions do not examine any values except their arguments, + * and have no effects except the return value. Basically this is + * just slightly more strict class than the `pure' attribute above, + * since function is not allowed to read global memory. + * + * Note that a function that has pointer arguments and examines the + * data pointed to must _not_ be declared `const'. Likewise, a + * function that calls a non-`const' function usually must not be + * `const'. It does not make sense for a `const' function to return + * `void'. + */ +#ifndef __attribute_const__ +# define __attribute_const__ /* unimplemented */ +#endif + +/* + * Tell gcc if a function is cold. The compiler will assume any path + * directly leading to the call is unlikely. + */ + +#ifndef __cold +#define __cold +#endif + +/* Simple shorthand for a section definition */ +#ifndef __section +# define __section(S) __attribute__ ((__section__(#S))) +#endif + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#ifndef __same_type +# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) +#endif + +/* Compile time object size, -1 for unknown */ +#ifndef __compiletime_object_size +# define __compiletime_object_size(obj) -1 +#endif +#ifndef __compiletime_warning +# define __compiletime_warning(message) +#endif +#ifndef __compiletime_error +# define __compiletime_error(message) +#endif +#ifndef __linktime_error +# define __linktime_error(message) +#endif +/* + * Prevent the compiler from merging or refetching accesses. The compiler + * is also forbidden from reordering successive instances of ACCESS_ONCE(), + * but only when the compiler is aware of some particular ordering. One way + * to make the compiler aware of ordering is to put the two invocations of + * ACCESS_ONCE() in different C statements. + * + * This macro does absolutely -nothing- to prevent the CPU from reordering, + * merging, or refetching absolutely anything at any time. Its main intended + * use is to mediate communication between process-level code and irq/NMI + * handlers, all running on the same CPU. + */ +#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#endif /* __LINUX_COMPILER_H */ diff --git a/include/linux/if.h b/include/linux/if.h index 238cf43..e9391d5 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -19,8 +19,14 @@ #ifndef _LINUX_IF_H #define _LINUX_IF_H +//#include /* for "__kernel_caddr_t" et al */ +//#include /* for "struct sockaddr" et al */ +#include /* for "__user" et al */ + + #define IFNAMSIZ 16 #define IFALIASZ 256 +#include /* Standard interface flags (netdevice->flags). */ #define IFF_UP 0x1 /* interface is up */ @@ -123,6 +129,27 @@ enum { IF_CARRIER_UP }; + + +struct if_settings { + unsigned int type; /* Type of physical device or protocol */ + unsigned int size; /* Size of the data allocated by the caller */ + union { + /* {atm/eth/dsl}_settings anyone ? */ + raw_hdlc_proto __user *raw_hdlc; + cisco_proto __user *cisco; + fr_proto __user *fr; + fr_proto_pvc __user *fr_pvc; + fr_proto_pvc_info __user *fr_pvc_info; + + /* interface settings */ + sync_serial_settings __user *sync; + te1_settings __user *te1; + } ifs_ifsu; +}; + + + /* * Device mapping structure. I'd just gone off and designed a * beautiful scheme using only loadable modules with arguments @@ -143,4 +170,55 @@ struct ifmap { /* 3 bytes spare */ }; + + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ + +struct ifreq { +#define IFHWADDRLEN 6 + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + void __user * ifru_data; + struct if_settings ifru_settings; + } ifr_ifru; +}; +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_ivalue /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_map ifr_ifru.ifru_map /* device map */ +#define ifr_slave ifr_ifru.ifru_slave /* slave device */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ +#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ +#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ +#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */ +#define ifr_newname ifr_ifru.ifru_newname /* New name */ +#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ + + #endif /* _LINUX_IF_H */ diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h new file mode 100644 index 0000000..2835b85 --- /dev/null +++ b/include/linux/if_tun.h @@ -0,0 +1,101 @@ +/* + * Universal TUN/TAP device driver. + * Copyright (C) 1999-2000 Maxim Krasnyansky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UAPI__IF_TUN_H +#define _UAPI__IF_TUN_H + +#include +#include +#include + +/* Read queue size */ +#define TUN_READQ_SIZE 500 + +/* TUN device flags */ +#define TUN_TUN_DEV 0x0001 +#define TUN_TAP_DEV 0x0002 +#define TUN_TYPE_MASK 0x000f + +#define TUN_FASYNC 0x0010 +#define TUN_NOCHECKSUM 0x0020 +#define TUN_NO_PI 0x0040 +/* This flag has no real effect */ +#define TUN_ONE_QUEUE 0x0080 +#define TUN_PERSIST 0x0100 +#define TUN_VNET_HDR 0x0200 +#define TUN_TAP_MQ 0x0400 + +/* Ioctl defines */ +#define TUNSETNOCSUM _IOW('T', 200, int) +#define TUNSETDEBUG _IOW('T', 201, int) +#define TUNSETIFF _IOW('T', 202, int) +#define TUNSETPERSIST _IOW('T', 203, int) +#define TUNSETOWNER _IOW('T', 204, int) +#define TUNSETLINK _IOW('T', 205, int) +#define TUNSETGROUP _IOW('T', 206, int) +#define TUNGETFEATURES _IOR('T', 207, unsigned int) +#define TUNSETOFFLOAD _IOW('T', 208, unsigned int) +#define TUNSETTXFILTER _IOW('T', 209, unsigned int) +#define TUNGETIFF _IOR('T', 210, unsigned int) +#define TUNGETSNDBUF _IOR('T', 211, int) +#define TUNSETSNDBUF _IOW('T', 212, int) +#define TUNATTACHFILTER _IOW('T', 213, struct sock_fprog) +#define TUNDETACHFILTER _IOW('T', 214, struct sock_fprog) +#define TUNGETVNETHDRSZ _IOR('T', 215, int) +#define TUNSETVNETHDRSZ _IOW('T', 216, int) +#define TUNSETQUEUE _IOW('T', 217, int) + +/* TUNSETIFF ifr flags */ +#define IFF_TUN 0x0001 +#define IFF_TAP 0x0002 +#define IFF_NO_PI 0x1000 +/* This flag has no real effect */ +#define IFF_ONE_QUEUE 0x2000 +#define IFF_VNET_HDR 0x4000 +#define IFF_TUN_EXCL 0x8000 +#define IFF_MULTI_QUEUE 0x0100 +#define IFF_ATTACH_QUEUE 0x0200 +#define IFF_DETACH_QUEUE 0x0400 + +/* Features for GSO (TUNSETOFFLOAD). */ +#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ +#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ +#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ +#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ +#define TUN_F_UFO 0x10 /* I can handle UFO packets */ + +/* Protocol info prepended to the packets (when IFF_NO_PI is not set) */ +#define TUN_PKT_STRIP 0x0001 +struct tun_pi { + __u16 flags; + __be16 proto; +}; + +/* + * Filter spec (used for SETXXFILTER ioctls) + * This stuff is applicable only to the TAP (Ethernet) devices. + * If the count is zero the filter is disabled and the driver accepts + * all packets (promisc mode). + * If the filter is enabled in order to accept broadcast packets + * broadcast addr must be explicitly included in the addr list. + */ +#define TUN_FLT_ALLMULTI 0x0001 /* Accept all multicast packets */ +struct tun_filter { + __u16 flags; /* TUN_FLT_ flags see above */ + __u16 count; /* Number of addresses */ + __u8 addr[0][ETH_ALEN]; +}; + +#endif /* _UAPI__IF_TUN_H */ diff --git a/include/netlink-private/route/link/api.h b/include/netlink-private/route/link/api.h index bb98ccc..3f6c62e 100644 --- a/include/netlink-private/route/link/api.h +++ b/include/netlink-private/route/link/api.h @@ -26,7 +26,7 @@ extern "C" { struct rtnl_link_info_ops { /** Name of link info type, must match name on kernel side */ - char * io_name; + const char * io_name; /** Reference count, DO NOT MODIFY */ int io_refcnt; diff --git a/include/netlink/route/link/tuntap.h b/include/netlink/route/link/tuntap.h new file mode 100644 index 0000000..8ecf3ed --- /dev/null +++ b/include/netlink/route/link/tuntap.h @@ -0,0 +1,50 @@ +/* + * netlink/route/link/tuntap.h Tuntap + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2013 Matthieu Coudron + */ + +#ifndef NETLINK_LINK_TUNTAP_H_ +#define NETLINK_LINK_TUNTAP_H_ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Transform into an enum ? +#define TUNTAP_MODE_TUN 1 +#define TUNTAP_MODE_TAP 2 + +//enum rtnl_link_tuntap_flags { +// RTNL_TUNTAP_PERSISTENT = TUNSETPERSIST +// IFF_MULTI_QUEUE +//}; + +extern struct rtnl_link *rtnl_link_tun_alloc(void); +extern struct rtnl_link *rtnl_link_tap_alloc(void); + +// check againt tun/tap or both +int rtnl_link_is_tuntap(struct rtnl_link *link, const short flag); + + +int rtnl_link_tuntap_set_persistent(struct rtnl_link *link); + +int rtnl_link_tuntap_get_flags(struct rtnl_link *link); +int rtnl_link_tuntap_set_flags(struct rtnl_link *link, short flags); + +int rtnl_link_tuntap_set_user(struct rtnl_link *link, const char* user); +int rtnl_link_tuntap_set_group(struct rtnl_link *link, const char* group); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/Makefile.am b/lib/Makefile.am index 697683f..a2d2f43 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -76,7 +76,7 @@ libnl_route_3_la_SOURCES = \ route/link/api.c route/link/vlan.c route/link/dummy.c \ route/link/bridge.c route/link/inet6.c route/link/inet.c \ route/link/bonding.c route/link/can.c route/link/macvlan.c \ - route/link/vxlan.c \ + route/link/vxlan.c route/link/tuntap.c \ \ route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \ route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \ diff --git a/lib/object.c b/lib/object.c index c3751a6..eec26fa 100644 --- a/lib/object.c +++ b/lib/object.c @@ -69,7 +69,7 @@ struct nl_object *nl_object_alloc(struct nl_object_ops *ops) if (ops->oo_constructor) ops->oo_constructor(new); - NL_DBG(4, "Allocated new object %p\n", new); + NL_DBG(4, "Allocated new object %p of type [%s]\n", new, ops->oo_name); return new; } @@ -117,6 +117,8 @@ struct nl_object *nl_object_clone(struct nl_object *obj) if (!obj) return NULL; + NL_DBG(4,"Cloning obj [%p]\n", obj); + new = nl_object_alloc(ops); if (!new) return NULL; @@ -176,7 +178,7 @@ void nl_object_free(struct nl_object *obj) ops = obj_ops(obj); if (obj->ce_refcnt > 0) - NL_DBG(1, "Warning: Freeing object in use...\n"); + NL_DBG(1, "Warning: Freeing object [%p] in use...\n", obj); if (obj->ce_cache) nl_cache_remove(obj); diff --git a/lib/route/link.c b/lib/route/link.c index a016899..6d6b235 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -2171,8 +2171,10 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type) if (link->l_info_ops) release_link_info(link); - if (!type) - return 0; + if (!type){ + NL_DBG(4,"Null string describing the type of link"); + return -NLE_FAILURE; + } kind = strdup(type); if (!kind) @@ -2185,6 +2187,9 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type) link->l_info_ops = io; } + else { + NL_DBG(4,"Warning: no link type [%s] registered", type); + } link->l_info_kind = kind; link->ce_mask |= LINK_ATTR_LINKINFO; diff --git a/lib/route/link/tuntap.c b/lib/route/link/tuntap.c new file mode 100644 index 0000000..195abea --- /dev/null +++ b/lib/route/link/tuntap.c @@ -0,0 +1,363 @@ +/** + * @ingroup link + * @defgroup tuntap Tuntap + * + * @details + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +struct tuntap_info { + struct ifreq tt_ifr; + int tt_fd; +}; + +static const char* LIBNL_TUNTAP_DEVICE="/dev/net/tun"; + +/** @cond SKIP */ +#define IS_TUNTAP_LINK_ASSERT(link) \ + if ( !rtnl_link_is_tuntap(link,0) ) { \ + APPBUG("Link is not a tuntap link. set type to \"tun\" or \"tap\" first."); \ + } +/** @endcond */ + + + + + +static int tuntap_alloc(struct rtnl_link * link, const short flags ) +{ + struct tuntap_info *ti; + char *name; + int err; + + if ((ti = calloc(1, sizeof(*ti))) == NULL) + return -NLE_NOMEM; + + link->l_info = ti; + + + if( ( ti->tt_fd = open(LIBNL_TUNTAP_DEVICE, O_RDWR)) < 0 ) { + + /* TODO choose a good error code NLE_OPNOTSUPP / NLE_NODEV / NLE_PERM ? */ + NL_DBG(2,"could not open [%s] in READ WRITE mode\n",LIBNL_TUNTAP_DEVICE); + return -NLE_NOACCESS ; + } + + memset(&(ti->tt_ifr), 0, sizeof( ti->tt_ifr)); + + ti->tt_ifr.ifr_flags = flags; + + + name = rtnl_link_get_name(link); + if( name ) { + NL_DBG(4,"Name of the tuntap set to [%s]\n", name ); + strncpy( ti->tt_ifr.ifr_name, name, IFNAMSIZ); + } + + + /** 3 conditions are required to use TUNSETIFF on an existing iff + http://backreference.org/2010/03/26/tuntap-interface-tutorial/ + **/ + if( (err = ioctl(ti->tt_fd, TUNSETIFF, (void *) &(ti->tt_ifr) ) ) < 0 ){ + NL_DBG(1,"could not set ioctl TUNSETIFF: error %d [%s]\n",err,strerror(err) ); + return err; + } + + return 0; +} + +/** + * Allocate link object of type TUN (no Ethernet headers) + * @warning You need to setup the TUN name beforehand via rtnl_link_set_name + * + * @return 0 in case of success, the error code otherwise. + */ +static int tun_alloc(struct rtnl_link * link ) +{ + /* IFF_NO_PI - Do not provide packet information */ + return tuntap_alloc(link, IFF_TUN | IFF_NO_PI); +} + +/** + * Allocate link object of type TAP + * @warning You need to setup the TUN name beforehand via rtnl_link_set_name + * + * @return 0 in case of success, the error code otherwise. + */ +static int tap_alloc(struct rtnl_link * link ) +{ + return tuntap_alloc(link, IFF_TAP | IFF_NO_PI); +} + +/** + * Free additionnal information of tuntap links + * + */ +static void tuntap_free(struct rtnl_link *link) +{ + struct tuntap_info *ti = link->l_info; + + IS_TUNTAP_LINK_ASSERT(link); + + if(ti) { + if(ti->tt_fd){ + NL_DBG(4,"Closing fd [%d]", ti->tt_fd); + close(ti->tt_fd); + } + free(ti); + } + + link->l_info = NULL; +} + + + + +/** +TODO: +**/ +static void tuntap_dump_line(struct rtnl_link *link, struct nl_dump_params *p) +{ + struct tuntap_info *ti = link->l_info; + + nl_dump(p, "tuntap name [%s]", ti->tt_ifr.ifr_name); +} + +/** +TODO: +**/ +static void tuntap_dump_details(struct rtnl_link *link, struct nl_dump_params *p) +{ + tuntap_dump_line(link,p); +} + + +/** +TODO: a priori no point in cloning since we needto set link name before allocation +**/ +//static int tuntap_clone(struct rtnl_link *dst, struct rtnl_link *src) +//{ +// struct tuntap_info *tdst, *tsrc = src->l_info; +// int err; +// +//// IS_TUNTAP_LINK_ASSERT(src); +//// +//// dst->l_info = NULL; +//// +//// rtnl_link_set_name( dst, tsrc->tt_ifr.name ); +//// if ((err = rtnl_link_set_type(dst, src->l_info_ops->io_name)) < 0) { +//// NL_DBG(4,"Could not set [%p] to type [%s]\n", dst, src->l_info_ops->io_name); +//// return err; +//// } +//// tdst = dst->l_info; +// +// return 0; +//} + +static struct rtnl_link_info_ops tun_info_ops = { + .io_name = "tun", + .io_alloc = tun_alloc, + .io_dump[NL_DUMP_LINE] = tuntap_dump_line, + .io_dump[NL_DUMP_DETAILS] = tuntap_dump_details, + .io_free = tuntap_free, +// .io_clone = tuntap_clone +}; + +static struct rtnl_link_info_ops tap_info_ops = { + .io_name = "tap", + .io_alloc = tap_alloc, + .io_dump[NL_DUMP_LINE] = tuntap_dump_line, + .io_dump[NL_DUMP_DETAILS] = tuntap_dump_details, + .io_free = tuntap_free, +// .io_clone = tuntap_clone +}; + +static void __init tuntap_init(void) +{ + rtnl_link_register_info(&tap_info_ops); + rtnl_link_register_info(&tun_info_ops); +} + +static void __exit tuntap_exit(void) +{ + rtnl_link_unregister_info(&tap_info_ops); + rtnl_link_unregister_info(&tun_info_ops); +} + + +/** + * Set the tuntap persistent if you want it to survive its application creator + * + * @return 0 in case of success, the error code otherwise. + */ +int rtnl_link_tuntap_set_persistent(struct rtnl_link *link) { + + + struct tuntap_info *ti; + + IS_TUNTAP_LINK_ASSERT(link); + + ti = link->l_info; + + if (ioctl( ti->tt_fd, TUNSETPERSIST, 1) < 0) { + NL_DBG(1,"ioctl(TUNSETPERSIST)"); + return -NLE_FAILURE; + } + + + return 0; +} + + +/** + * Accepts either the usersame (e.g. "root") or an uid (as a string e.g. "0") + * + * @return 0 in case of success, the error code otherwise. + */ +int rtnl_link_tuntap_set_user(struct rtnl_link *link, const char* userId) { + + + uid_t uid; + struct passwd *pw; + struct tuntap_info *ti; + + char* end; + IS_TUNTAP_LINK_ASSERT(link); + + if( userId == NULL) { + NL_DBG(1, "Null user id\n"); + return NLE_INVAL; + } + + /* attempts to convert userId in an integer (base 10) */ + if ( ((uid = strtol( userId, &end, 10)), !*end) ) { + /* Do nothing */ + } + /* in case username is written as a string */ + else { + pw = getpwnam(userId); + if (!pw) { + NL_DBG(1, "invalid user [%s]\n", userId); + return (-NLE_INVAL); + } + + uid = pw->pw_uid; + } + + NL_DBG(1,"Setting tuntap owner to uid [%d]\n",uid); + + ti = link->l_info; + + if (uid != -1 && ioctl( ti->tt_fd, TUNSETOWNER, uid)) { + NL_DBG(1,"ioctl(TUNSETOWNER)\n"); + return -NLE_NOACCESS; + } + + return 0; +} + + +/** + * Accepts either the group name (e.g. "root") or a gid (as a string e.g. "0") + * + * @return 0 in case of success, the error code otherwise. + */ +int rtnl_link_tuntap_set_group(struct rtnl_link *link, const char* groupId) { + + gid_t gid; + unsigned long group; + char* end; + struct tuntap_info *ti; + + + IS_TUNTAP_LINK_ASSERT(link); + + if( groupId == NULL) { + NL_DBG(1, "Null group id.\n"); + return NLE_INVAL; + } + + + if ((group = strtol( groupId, &end, 10)), !*end) { + gid = group; + } + else { + struct group *gr = getgrnam(groupId); + if (!gr) { + NL_DBG(1, "invalid group [%s]\n", groupId); + exit(-1); + } + gid = gr->gr_gid; + } + + + ti = link->l_info; + + if (gid != -1 && ioctl( ti->tt_fd, TUNSETGROUP, gid)) { + NL_DBG(1,"ioctl(TUNSETOWNER)\n"); + return -NLE_NOACCESS; + } + + return 0; +} + + + +//int rtnl_link_tuntap_get_flags(struct rtnl_link *link) { +// +// struct tuntap_info *ti = link->l_info; +// +// IS_TUNTAP_LINK_ASSERT(link); +// +// return ti->tt_ifr.ifr_flags; +//} +// +//int rtnl_link_tuntap_set_flags(struct rtnl_link *link, short flags); + + +/** + * Check if link is a Tuntap link + * @arg link Link object + * @arg flag To check against tun and/or tap (not implemented yet) + * @return True if link is a TunTaplink, otherwise false is returned. + */ +int rtnl_link_is_tuntap(struct rtnl_link *link, const short flag) +{ + + if( link + && (link)->l_info_ops + && ( + (strcmp(link->l_info_ops->io_name, "tun") == 0) || + (strcmp(link->l_info_ops->io_name, "tap") == 0) ) + ) { +// NL_DBG(4,"[%p] is a tuntap\n", link); + return 1; + } +// else { +// NL_DBG(4,"Not a tuntap. Determining why"); +// if ( (link)->l_info_ops ) { +// NL_DBG(4,"This link is a %s",link->l_info_ops->io_name); +// } +// else { +// NL_DBG(4,"This link has no operations registered"); +// } +// return 0; +// } + return 0; +} + +