aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_pppol2tp.h28
-rw-r--r--include/linux/if_pppox.h12
-rw-r--r--net/l2tp/l2tp_core.c89
-rw-r--r--net/l2tp/l2tp_ppp.c42
4 files changed, 157 insertions, 14 deletions
diff --git a/include/linux/if_pppol2tp.h b/include/linux/if_pppol2tp.h
index 23cefa1111bf..b4775418d525 100644
--- a/include/linux/if_pppol2tp.h
+++ b/include/linux/if_pppol2tp.h
@@ -19,10 +19,11 @@
19 19
20#ifdef __KERNEL__ 20#ifdef __KERNEL__
21#include <linux/in.h> 21#include <linux/in.h>
22#include <linux/in6.h>
22#endif 23#endif
23 24
24/* Structure used to connect() the socket to a particular tunnel UDP 25/* Structure used to connect() the socket to a particular tunnel UDP
25 * socket. 26 * socket over IPv4.
26 */ 27 */
27struct pppol2tp_addr { 28struct pppol2tp_addr {
28 __kernel_pid_t pid; /* pid that owns the fd. 29 __kernel_pid_t pid; /* pid that owns the fd.
@@ -35,6 +36,20 @@ struct pppol2tp_addr {
35 __u16 d_tunnel, d_session; /* For sending outgoing packets */ 36 __u16 d_tunnel, d_session; /* For sending outgoing packets */
36}; 37};
37 38
39/* Structure used to connect() the socket to a particular tunnel UDP
40 * socket over IPv6.
41 */
42struct pppol2tpin6_addr {
43 __kernel_pid_t pid; /* pid that owns the fd.
44 * 0 => current */
45 int fd; /* FD of UDP socket to use */
46
47 __u16 s_tunnel, s_session; /* For matching incoming packets */
48 __u16 d_tunnel, d_session; /* For sending outgoing packets */
49
50 struct sockaddr_in6 addr; /* IP address and port to send to */
51};
52
38/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 53/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
39 * bits. So we need a different sockaddr structure. 54 * bits. So we need a different sockaddr structure.
40 */ 55 */
@@ -49,6 +64,17 @@ struct pppol2tpv3_addr {
49 __u32 d_tunnel, d_session; /* For sending outgoing packets */ 64 __u32 d_tunnel, d_session; /* For sending outgoing packets */
50}; 65};
51 66
67struct pppol2tpv3in6_addr {
68 __kernel_pid_t pid; /* pid that owns the fd.
69 * 0 => current */
70 int fd; /* FD of UDP or IP socket to use */
71
72 __u32 s_tunnel, s_session; /* For matching incoming packets */
73 __u32 d_tunnel, d_session; /* For sending outgoing packets */
74
75 struct sockaddr_in6 addr; /* IP address and port to send to */
76};
77
52/* Socket options: 78/* Socket options:
53 * DEBUG - bitmask of debug message categories 79 * DEBUG - bitmask of debug message categories
54 * SENDSEQ - 0 => don't send packets with sequence numbers 80 * SENDSEQ - 0 => don't send packets with sequence numbers
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index b5f927f59f26..6720d57cc1ea 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -83,6 +83,12 @@ struct sockaddr_pppol2tp {
83 struct pppol2tp_addr pppol2tp; 83 struct pppol2tp_addr pppol2tp;
84} __attribute__((packed)); 84} __attribute__((packed));
85 85
86struct sockaddr_pppol2tpin6 {
87 __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
88 unsigned int sa_protocol; /* protocol identifier */
89 struct pppol2tpin6_addr pppol2tp;
90} __attribute__((packed));
91
86/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 92/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
87 * bits. So we need a different sockaddr structure. 93 * bits. So we need a different sockaddr structure.
88 */ 94 */
@@ -92,6 +98,12 @@ struct sockaddr_pppol2tpv3 {
92 struct pppol2tpv3_addr pppol2tp; 98 struct pppol2tpv3_addr pppol2tp;
93} __attribute__((packed)); 99} __attribute__((packed));
94 100
101struct sockaddr_pppol2tpv3in6 {
102 __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */
103 unsigned int sa_protocol; /* protocol identifier */
104 struct pppol2tpv3in6_addr pppol2tp;
105} __attribute__((packed));
106
95/********************************************************************* 107/*********************************************************************
96 * 108 *
97 * ioctl interface for defining forwarding of connections 109 * ioctl interface for defining forwarding of connections
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);