diff options
-rw-r--r-- | include/linux/if_pppol2tp.h | 28 | ||||
-rw-r--r-- | include/linux/if_pppox.h | 12 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.c | 89 | ||||
-rw-r--r-- | net/l2tp/l2tp_ppp.c | 42 |
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 | */ |
27 | struct pppol2tp_addr { | 28 | struct 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 | */ | ||
42 | struct 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 | ||
67 | struct 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 | ||
86 | struct 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 | ||
101 | struct 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) | ||
1055 | static 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); |