diff options
-rw-r--r-- | src/compat/Kbuild.include | 6 | ||||
-rw-r--r-- | src/compat/checksum/checksum_partial_compat.h | 201 | ||||
-rw-r--r-- | src/compat/compat.h | 24 | ||||
-rw-r--r-- | src/compat/fpu/include/asm/fpu/api.h (renamed from src/compat/i387/include/asm/fpu/api.h) | 0 | ||||
-rw-r--r-- | src/compat/simd/include/asm/simd.h | 1 | ||||
-rw-r--r-- | src/compat/siphash/siphash.c | 10 | ||||
-rw-r--r-- | src/dkms.conf | 4 | ||||
-rw-r--r-- | src/tests/qemu/kernel.config | 1 |
8 files changed, 240 insertions, 7 deletions
diff --git a/src/compat/Kbuild.include b/src/compat/Kbuild.include index ebd5aaf..aaaffcb 100644 --- a/src/compat/Kbuild.include +++ b/src/compat/Kbuild.include @@ -15,7 +15,11 @@ wireguard-y += compat/dst_cache/dst_cache.o endif ifeq ($(wildcard $(srctree)/arch/x86/include/asm/fpu/api.h),) -ccflags-y += -I$(src)/compat/i387/include +ccflags-y += -I$(src)/compat/fpu/include +endif + +ifeq ($(wildcard $(srctree)/arch/x86/include/asm/simd.h),) +ccflags-y += -I$(src)/compat/simd/include endif ifeq ($(wildcard $(srctree)/include/net/udp_tunnel.h),) diff --git a/src/compat/checksum/checksum_partial_compat.h b/src/compat/checksum/checksum_partial_compat.h new file mode 100644 index 0000000..5175d84 --- /dev/null +++ b/src/compat/checksum/checksum_partial_compat.h @@ -0,0 +1,201 @@ +#include <net/route.h> +#include <net/esp.h> +#include <net/ip.h> +#include <net/ipv6.h> +#define IP6_MF 0x0001 +#define IP6_OFFSET 0xFFF8 +static inline int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, unsigned int max) +{ + if (skb_headlen(skb) >= len) + return 0; + if (max > skb->len) + max = skb->len; + if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) + return -ENOMEM; + if (skb_headlen(skb) < len) + return -EPROTO; + return 0; +} +#define MAX_IP_HDR_LEN 128 +static inline int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate) +{ + unsigned int off; + bool fragment; + int err; + fragment = false; + err = skb_maybe_pull_tail(skb, sizeof(struct iphdr), MAX_IP_HDR_LEN); + if (err < 0) + goto out; + if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) + fragment = true; + off = ip_hdrlen(skb); + err = -EPROTO; + if (fragment) + goto out; + switch (ip_hdr(skb)->protocol) { + case IPPROTO_TCP: + err = skb_maybe_pull_tail(skb, + off + sizeof(struct tcphdr), + MAX_IP_HDR_LEN); + if (err < 0) + goto out; + + if (!skb_partial_csum_set(skb, off, + offsetof(struct tcphdr, check))) { + err = -EPROTO; + goto out; + } + + if (recalculate) + tcp_hdr(skb)->check = + ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + skb->len - off, + IPPROTO_TCP, 0); + break; + case IPPROTO_UDP: + err = skb_maybe_pull_tail(skb, + off + sizeof(struct udphdr), + MAX_IP_HDR_LEN); + if (err < 0) + goto out; + + if (!skb_partial_csum_set(skb, off, + offsetof(struct udphdr, check))) { + err = -EPROTO; + goto out; + } + + if (recalculate) + udp_hdr(skb)->check = + ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + skb->len - off, + IPPROTO_UDP, 0); + break; + default: + goto out; + } + err = 0; +out: + return err; +} +#define MAX_IPV6_HDR_LEN 256 +#define OPT_HDR(type, skb, off) \ + (type *)(skb_network_header(skb) + (off)) +static inline int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) +{ + int err; + u8 nexthdr; + unsigned int off; + unsigned int len; + bool fragment; + bool done; + fragment = false; + done = false; + off = sizeof(struct ipv6hdr); + err = skb_maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); + if (err < 0) + goto out; + nexthdr = ipv6_hdr(skb)->nexthdr; + len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); + while (off <= len && !done) { + switch (nexthdr) { + case IPPROTO_DSTOPTS: + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: { + struct ipv6_opt_hdr *hp; + + err = skb_maybe_pull_tail(skb, off + sizeof(struct ipv6_opt_hdr), MAX_IPV6_HDR_LEN); + if (err < 0) + goto out; + hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); + nexthdr = hp->nexthdr; + off += ipv6_optlen(hp); + break; + } + case IPPROTO_FRAGMENT: { + struct frag_hdr *hp; + err = skb_maybe_pull_tail(skb, off + sizeof(struct frag_hdr), MAX_IPV6_HDR_LEN); + if (err < 0) + goto out; + hp = OPT_HDR(struct frag_hdr, skb, off); + if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) + fragment = true; + nexthdr = hp->nexthdr; + off += sizeof(struct frag_hdr); + break; + } + default: + done = true; + break; + } + } + err = -EPROTO; + if (!done || fragment) + goto out; + switch (nexthdr) { + case IPPROTO_TCP: + err = skb_maybe_pull_tail(skb, + off + sizeof(struct tcphdr), + MAX_IPV6_HDR_LEN); + if (err < 0) + goto out; + + if (!skb_partial_csum_set(skb, off, + offsetof(struct tcphdr, check))) { + err = -EPROTO; + goto out; + } + + if (recalculate) + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len - off, + IPPROTO_TCP, 0); + break; + case IPPROTO_UDP: + err = skb_maybe_pull_tail(skb, + off + sizeof(struct udphdr), + MAX_IPV6_HDR_LEN); + if (err < 0) + goto out; + + if (!skb_partial_csum_set(skb, off, + offsetof(struct udphdr, check))) { + err = -EPROTO; + goto out; + } + + if (recalculate) + udp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len - off, + IPPROTO_UDP, 0); + break; + default: + goto out; + } + err = 0; +out: + return err; +} +static inline int skb_checksum_setup(struct sk_buff *skb, bool recalculate) +{ + int err; + switch (skb->protocol) { + case htons(ETH_P_IP): + err = skb_checksum_setup_ip(skb, recalculate); + break; + + case htons(ETH_P_IPV6): + err = skb_checksum_setup_ipv6(skb, recalculate); + break; + default: + err = -EPROTO; + break; + } + return err; +} diff --git a/src/compat/compat.h b/src/compat/compat.h index 4f2acb9..a586b93 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -7,8 +7,8 @@ #include <linux/version.h> #include <linux/types.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) -#error "WireGuard requires Linux >= 3.14" +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) +#error "WireGuard requires Linux >= 3.12" #endif /* These conditionals can't be enforced by an out of tree module very easily, @@ -41,7 +41,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 6)) || \ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 12) && LINUX_VERSION_CODE > KERNEL_VERSION(3, 17, 0)) || \ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 8) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || \ - (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 40) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 40) #define dev_recursion_level() 0 #endif @@ -110,7 +110,10 @@ static inline void netif_keep_dst(struct net_device *dev) } #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) +#define pcpu_sw_netstats pcpu_tstats +#define netdev_alloc_pcpu_stats alloc_percpu +#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) #define netdev_alloc_pcpu_stats(type) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \ @@ -126,6 +129,19 @@ static inline void netif_keep_dst(struct net_device *dev) }) #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) +#include "checksum/checksum_partial_compat.h" +static inline void *our_pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) +{ + if (tail != skb) { + skb->data_len += len; + skb->len += len; + } + return skb_put(tail, len); +} +#define pskb_put our_pskb_put +#endif + /* https://lkml.org/lkml/2015/6/12/415 */ #include <linux/netdevice.h> static inline struct net_device *netdev_pub(void *dev) diff --git a/src/compat/i387/include/asm/fpu/api.h b/src/compat/fpu/include/asm/fpu/api.h index f3f9117..f3f9117 100644 --- a/src/compat/i387/include/asm/fpu/api.h +++ b/src/compat/fpu/include/asm/fpu/api.h diff --git a/src/compat/simd/include/asm/simd.h b/src/compat/simd/include/asm/simd.h new file mode 100644 index 0000000..f3f9117 --- /dev/null +++ b/src/compat/simd/include/asm/simd.h @@ -0,0 +1 @@ +#include <asm/i387.h> diff --git a/src/compat/siphash/siphash.c b/src/compat/siphash/siphash.c index 3ae58b4..1ebfd5e 100644 --- a/src/compat/siphash/siphash.c +++ b/src/compat/siphash/siphash.c @@ -13,6 +13,16 @@ #include <linux/siphash.h> #include <asm/unaligned.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) +#ifdef __LITTLE_ENDIAN + #define HASH_LEN_DECLARE u32 hash; u32 len; + #define bytemask_from_count(cnt) (~(~0ul << (cnt)*8)) +#else + #define HASH_LEN_DECLARE u32 len; u32 hash; + #define bytemask_from_count(cnt) (~(~0ul >> (cnt)*8)) +#endif +#endif + #if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 #include <linux/dcache.h> #include <asm/word-at-a-time.h> diff --git a/src/dkms.conf b/src/dkms.conf index d772902..2e66bc9 100644 --- a/src/dkms.conf +++ b/src/dkms.conf @@ -5,5 +5,5 @@ AUTOINSTALL=yes BUILT_MODULE_NAME="wireguard" DEST_MODULE_LOCATION="/kernel/net" -# requires kernel 3.14 or greater: -BUILD_EXCLUSIVE_KERNEL="^(([^1230]\.)|(3\.1[456789]))" +# requires kernel 3.12 or greater: +BUILD_EXCLUSIVE_KERNEL="^(([^1230]\.)|(3\.1[23456789]))" diff --git a/src/tests/qemu/kernel.config b/src/tests/qemu/kernel.config index 9df706a..c6cc5c9 100644 --- a/src/tests/qemu/kernel.config +++ b/src/tests/qemu/kernel.config @@ -1,6 +1,7 @@ CONFIG_NET=y CONFIG_NETDEVICES=y CONFIG_NET_CORE=y +CONFIG_NET_IPIP=y CONFIG_VETH=y CONFIG_MULTIUSER=y CONFIG_NAMESPACES=y |