summaryrefslogtreecommitdiffhomepage
path: root/src/compat/udp_tunnel
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-04-09 05:39:28 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-04-09 05:39:28 +0200
commit7a1eab5cb8879818b9dc4a5305d5be5e2d0bd7f6 (patch)
tree37009ed6fbfc2b43b876675c81fa0732c1c5795f /src/compat/udp_tunnel
parent390f012f41d60215a4eed92a8d19ce7efd3707ff (diff)
compat: support 3.14
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/compat/udp_tunnel')
-rw-r--r--src/compat/udp_tunnel/udp_tunnel.c105
1 files changed, 103 insertions, 2 deletions
diff --git a/src/compat/udp_tunnel/udp_tunnel.c b/src/compat/udp_tunnel/udp_tunnel.c
index 35e54e0..58ac61c 100644
--- a/src/compat/udp_tunnel/udp_tunnel.c
+++ b/src/compat/udp_tunnel/udp_tunnel.c
@@ -11,7 +11,11 @@
/* This is global so, uh, only one real call site... This is the kind of horrific hack you'd expect to see in compat code. */
static udp_tunnel_encap_rcv_t encap_rcv = NULL;
-static void our_sk_data_ready(struct sock *sk)
+static void our_sk_data_ready(struct sock *sk
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
+ ,int unused_vulnerable_length_param
+#endif
+ )
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
@@ -50,7 +54,11 @@ int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
goto error;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
+ sock->sk->sk_no_check = !cfg->use_udp_checksums;
+#else
sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
+#endif
*sockp = sock;
return 0;
@@ -75,6 +83,48 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
}
EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
+static inline __sum16 udp_v4_check(int len, __be32 saddr,
+ __be32 daddr, __wsum base)
+{
+ return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
+}
+
+static void udp_set_csum(bool nocheck, struct sk_buff *skb,
+ __be32 saddr, __be32 daddr, int len)
+{
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (nocheck)
+ uh->check = 0;
+ else if (skb_is_gso(skb))
+ uh->check = ~udp_v4_check(len, saddr, daddr, 0);
+ else if (skb_dst(skb) && skb_dst(skb)->dev &&
+ (skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
+
+ BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
+
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ uh->check = ~udp_v4_check(len, saddr, daddr, 0);
+ } else {
+ __wsum csum;
+
+ BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
+
+ uh->check = 0;
+ csum = skb_checksum(skb, 0, len, 0);
+ uh->check = udp_v4_check(len, saddr, daddr, csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+}
+
+#endif
+
static void fake_destructor(struct sk_buff *skb)
{
}
@@ -103,7 +153,11 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
skb->destructor = fake_destructor;
}
- iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
+ iptunnel_xmit(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ sk,
+#endif
+ rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
}
EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb);
@@ -171,8 +225,12 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
if (err < 0)
goto error;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
+ sock->sk->sk_no_check = !cfg->use_udp_checksums;
+#else
udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums);
udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums);
+#endif
*sockp = sock;
return 0;
@@ -187,6 +245,49 @@ error:
}
EXPORT_SYMBOL_GPL(udp_sock_create6);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
+static inline __sum16 udp_v6_check(int len,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ __wsum base)
+{
+ return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base);
+}
+static void udp6_set_csum(bool nocheck, struct sk_buff *skb,
+ const struct in6_addr *saddr,
+ const struct in6_addr *daddr, int len)
+{
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (nocheck)
+ uh->check = 0;
+ else if (skb_is_gso(skb))
+ uh->check = ~udp_v6_check(len, saddr, daddr, 0);
+ else if (skb_dst(skb) && skb_dst(skb)->dev &&
+ (skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) {
+
+ BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
+
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ uh->check = ~udp_v6_check(len, saddr, daddr, 0);
+ } else {
+ __wsum csum;
+
+ BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
+
+ uh->check = 0;
+ csum = skb_checksum(skb, 0, len, 0);
+ uh->check = udp_v6_check(len, saddr, daddr, csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+}
+#endif
+
int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb,
struct net_device *dev, struct in6_addr *saddr,