aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
authorBenjamin LaHaise <bcrl@kvack.org>2012-04-27 04:24:18 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-28 22:21:51 -0400
commitd2cf3361677e5bb5d01d45052212b7050a9aa8c4 (patch)
treea0239e574876ca385c8578c7cbffb783bf951e51 /net/l2tp
parentd7f3f62167bc2299d9669888b493b6e6ba561c35 (diff)
net/l2tp: add support for L2TP over IPv6 UDP
Now that encap_rcv() works on IPv6 UDP sockets, wire L2TP up to IPv6. Support has been tested with and without hardware offloading. This version fixes the L2TP over localhost issue with incorrect checksums being reported. Signed-off-by: Benjamin LaHaise <bcrl@kvack.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c89
-rw-r--r--net/l2tp/l2tp_ppp.c42
2 files changed, 118 insertions, 13 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index f6732b6c758b..e91d55924d94 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -53,6 +53,9 @@
53#include <net/inet_common.h> 53#include <net/inet_common.h>
54#include <net/xfrm.h> 54#include <net/xfrm.h>
55#include <net/protocol.h> 55#include <net/protocol.h>
56#include <net/inet6_connection_sock.h>
57#include <net/inet_ecn.h>
58#include <net/ip6_route.h>
56 59
57#include <asm/byteorder.h> 60#include <asm/byteorder.h>
58#include <linux/atomic.h> 61#include <linux/atomic.h>
@@ -446,21 +449,43 @@ static inline int l2tp_verify_udp_checksum(struct sock *sk,
446{ 449{
447 struct udphdr *uh = udp_hdr(skb); 450 struct udphdr *uh = udp_hdr(skb);
448 u16 ulen = ntohs(uh->len); 451 u16 ulen = ntohs(uh->len);
449 struct inet_sock *inet;
450 __wsum psum; 452 __wsum psum;
451 453
452 if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check) 454 if (sk->sk_no_check || skb_csum_unnecessary(skb))
453 return 0;
454
455 inet = inet_sk(sk);
456 psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
457 IPPROTO_UDP, 0);
458
459 if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
460 !csum_fold(csum_add(psum, skb->csum)))
461 return 0; 455 return 0;
462 456
463 skb->csum = psum; 457#if IS_ENABLED(CONFIG_IPV6)
458 if (sk->sk_family == PF_INET6) {
459 if (!uh->check) {
460 LIMIT_NETDEBUG(KERN_INFO "L2TP: IPv6: checksum is 0\n");
461 return 1;
462 }
463 if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
464 !csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
465 &ipv6_hdr(skb)->daddr, ulen,
466 IPPROTO_UDP, skb->csum)) {
467 skb->ip_summed = CHECKSUM_UNNECESSARY;
468 return 0;
469 }
470 skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
471 &ipv6_hdr(skb)->daddr,
472 skb->len, IPPROTO_UDP,
473 0));
474 } else
475#endif
476 {
477 struct inet_sock *inet;
478 if (!uh->check)
479 return 0;
480 inet = inet_sk(sk);
481 psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr,
482 ulen, IPPROTO_UDP, 0);
483
484 if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
485 !csum_fold(csum_add(psum, skb->csum)))
486 return 0;
487 skb->csum = psum;
488 }
464 489
465 return __skb_checksum_complete(skb); 490 return __skb_checksum_complete(skb);
466} 491}
@@ -988,7 +1013,12 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
988 1013
989 /* Queue the packet to IP for output */ 1014 /* Queue the packet to IP for output */
990 skb->local_df = 1; 1015 skb->local_df = 1;
991 error = ip_queue_xmit(skb, fl); 1016#if IS_ENABLED(CONFIG_IPV6)
1017 if (skb->sk->sk_family == PF_INET6)
1018 error = inet6_csk_xmit(skb, NULL);
1019 else
1020#endif
1021 error = ip_queue_xmit(skb, fl);
992 1022
993 /* Update stats */ 1023 /* Update stats */
994 if (error >= 0) { 1024 if (error >= 0) {
@@ -1021,6 +1051,31 @@ static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
1021 skb->destructor = l2tp_sock_wfree; 1051 skb->destructor = l2tp_sock_wfree;
1022} 1052}
1023 1053
1054#if IS_ENABLED(CONFIG_IPV6)
1055static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb,
1056 int udp_len)
1057{
1058 struct ipv6_pinfo *np = inet6_sk(sk);
1059 struct udphdr *uh = udp_hdr(skb);
1060
1061 if (!skb_dst(skb) || !skb_dst(skb)->dev ||
1062 !(skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) {
1063 __wsum csum = skb_checksum(skb, 0, udp_len, 0);
1064 skb->ip_summed = CHECKSUM_UNNECESSARY;
1065 uh->check = csum_ipv6_magic(&np->saddr, &np->daddr, udp_len,
1066 IPPROTO_UDP, csum);
1067 if (uh->check == 0)
1068 uh->check = CSUM_MANGLED_0;
1069 } else {
1070 skb->ip_summed = CHECKSUM_PARTIAL;
1071 skb->csum_start = skb_transport_header(skb) - skb->head;
1072 skb->csum_offset = offsetof(struct udphdr, check);
1073 uh->check = ~csum_ipv6_magic(&np->saddr, &np->daddr,
1074 udp_len, IPPROTO_UDP, 0);
1075 }
1076}
1077#endif
1078
1024/* If caller requires the skb to have a ppp header, the header must be 1079/* If caller requires the skb to have a ppp header, the header must be
1025 * inserted in the skb data before calling this function. 1080 * inserted in the skb data before calling this function.
1026 */ 1081 */
@@ -1089,6 +1144,11 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
1089 uh->check = 0; 1144 uh->check = 0;
1090 1145
1091 /* Calculate UDP checksum if configured to do so */ 1146 /* Calculate UDP checksum if configured to do so */
1147#if IS_ENABLED(CONFIG_IPV6)
1148 if (sk->sk_family == PF_INET6)
1149 l2tp_xmit_ipv6_csum(sk, skb, udp_len);
1150 else
1151#endif
1092 if (sk->sk_no_check == UDP_CSUM_NOXMIT) 1152 if (sk->sk_no_check == UDP_CSUM_NOXMIT)
1093 skb->ip_summed = CHECKSUM_NONE; 1153 skb->ip_summed = CHECKSUM_NONE;
1094 else if ((skb_dst(skb) && skb_dst(skb)->dev) && 1154 else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
@@ -1424,6 +1484,11 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
1424 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ 1484 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
1425 udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; 1485 udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
1426 udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; 1486 udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
1487#if IS_ENABLED(CONFIG_IPV6)
1488 if (sk->sk_family == PF_INET6)
1489 udpv6_encap_enable();
1490 else
1491#endif
1427 udp_encap_enable(); 1492 udp_encap_enable();
1428 } 1493 }
1429 1494
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 1addd9f3f40a..27b9dec9d254 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -916,7 +916,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
916 } 916 }
917 917
918 inet = inet_sk(tunnel->sock); 918 inet = inet_sk(tunnel->sock);
919 if (tunnel->version == 2) { 919 if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) {
920 struct sockaddr_pppol2tp sp; 920 struct sockaddr_pppol2tp sp;
921 len = sizeof(sp); 921 len = sizeof(sp);
922 memset(&sp, 0, len); 922 memset(&sp, 0, len);
@@ -932,6 +932,46 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
932 sp.pppol2tp.addr.sin_port = inet->inet_dport; 932 sp.pppol2tp.addr.sin_port = inet->inet_dport;
933 sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr; 933 sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
934 memcpy(uaddr, &sp, len); 934 memcpy(uaddr, &sp, len);
935#if IS_ENABLED(CONFIG_IPV6)
936 } else if ((tunnel->version == 2) &&
937 (tunnel->sock->sk_family == AF_INET6)) {
938 struct ipv6_pinfo *np = inet6_sk(tunnel->sock);
939 struct sockaddr_pppol2tpin6 sp;
940 len = sizeof(sp);
941 memset(&sp, 0, len);
942 sp.sa_family = AF_PPPOX;
943 sp.sa_protocol = PX_PROTO_OL2TP;
944 sp.pppol2tp.fd = tunnel->fd;
945 sp.pppol2tp.pid = pls->owner;
946 sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
947 sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
948 sp.pppol2tp.s_session = session->session_id;
949 sp.pppol2tp.d_session = session->peer_session_id;
950 sp.pppol2tp.addr.sin6_family = AF_INET6;
951 sp.pppol2tp.addr.sin6_port = inet->inet_dport;
952 memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr,
953 sizeof(np->daddr));
954 memcpy(uaddr, &sp, len);
955 } else if ((tunnel->version == 3) &&
956 (tunnel->sock->sk_family == AF_INET6)) {
957 struct ipv6_pinfo *np = inet6_sk(tunnel->sock);
958 struct sockaddr_pppol2tpv3in6 sp;
959 len = sizeof(sp);
960 memset(&sp, 0, len);
961 sp.sa_family = AF_PPPOX;
962 sp.sa_protocol = PX_PROTO_OL2TP;
963 sp.pppol2tp.fd = tunnel->fd;
964 sp.pppol2tp.pid = pls->owner;
965 sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
966 sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
967 sp.pppol2tp.s_session = session->session_id;
968 sp.pppol2tp.d_session = session->peer_session_id;
969 sp.pppol2tp.addr.sin6_family = AF_INET6;
970 sp.pppol2tp.addr.sin6_port = inet->inet_dport;
971 memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr,
972 sizeof(np->daddr));
973 memcpy(uaddr, &sp, len);
974#endif
935 } else if (tunnel->version == 3) { 975 } else if (tunnel->version == 3) {
936 struct sockaddr_pppol2tpv3 sp; 976 struct sockaddr_pppol2tpv3 sp;
937 len = sizeof(sp); 977 len = sizeof(sp);