l2tp: Add support for zero IPv6 checksums
authorTom Herbert <therbert@google.com>
Fri, 23 May 2014 15:47:40 +0000 (08:47 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 23 May 2014 20:28:53 +0000 (16:28 -0400)
Added new L2TP configuration options to allow TX and RX of
zero checksums in IPv6. Default is not to use them.

Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/l2tp.h
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_netlink.c

index 8adb681603273c287f25be055c0258c8a2a73c65..21caa2631c209fdc0f0c7e21591e0507fc3e0b9a 100644 (file)
@@ -124,6 +124,8 @@ enum {
        L2TP_ATTR_STATS,                /* nested */
        L2TP_ATTR_IP6_SADDR,            /* struct in6_addr */
        L2TP_ATTR_IP6_DADDR,            /* struct in6_addr */
+       L2TP_ATTR_UDP_ZERO_CSUM6_TX,    /* u8 */
+       L2TP_ATTR_UDP_ZERO_CSUM6_RX,    /* u8 */
        __L2TP_ATTR_MAX,
 };
 
index a1186105f53739401c437dee964e965779419204..379558014b60f40a19964fdbe6c0f8ea9fd3c03e 100644 (file)
@@ -1102,7 +1102,9 @@ static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct udphdr *uh = udp_hdr(skb);
 
-       if (!skb_dst(skb) || !skb_dst(skb)->dev ||
+       if (udp_get_no_check6_tx(sk))
+               skb->ip_summed = CHECKSUM_NONE;
+       else if (!skb_dst(skb) || !skb_dst(skb)->dev ||
            !(skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) {
                __wsum csum = skb_checksum(skb, 0, udp_len, 0);
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1435,6 +1437,11 @@ static int l2tp_tunnel_sock_create(struct net *net,
                                             sizeof(udp6_addr), 0);
                        if (err < 0)
                                goto out;
+
+                       if (cfg->udp6_zero_tx_checksums)
+                               udp_set_no_check6_tx(sock->sk, true);
+                       if (cfg->udp6_zero_rx_checksums)
+                               udp_set_no_check6_rx(sock->sk, true);
                } else
 #endif
                {
index 3f93ccd6ba9768fe171f4e35e79d613226c1dbc7..68aa9ffd4ae4d972cdd57ea742ddf3b78ba497d6 100644 (file)
@@ -162,7 +162,9 @@ struct l2tp_tunnel_cfg {
 #endif
        u16                     local_udp_port;
        u16                     peer_udp_port;
-       unsigned int            use_udp_checksums:1;
+       unsigned int            use_udp_checksums:1,
+                               udp6_zero_tx_checksums:1,
+                               udp6_zero_rx_checksums:1;
 };
 
 struct l2tp_tunnel {
index f3d331bdd7062b27312e827a31db816f701b5f7d..0ac907adb2f472c0d49508ca6843363db27129b1 100644 (file)
@@ -161,6 +161,13 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
                        cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
                if (info->attrs[L2TP_ATTR_UDP_CSUM])
                        cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
+
+#if IS_ENABLED(CONFIG_IPV6)
+               if (info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX])
+                       cfg.udp6_zero_tx_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]);
+               if (info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX])
+                       cfg.udp6_zero_rx_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]);
+#endif
        }
 
        if (info->attrs[L2TP_ATTR_DEBUG])