summaryrefslogtreecommitdiff
path: root/net/l2tp/l2tp_core.c
diff options
context:
space:
mode:
authorChris Elston <celston@katalix.com>2012-04-29 21:48:52 +0000
committerDavid S. Miller <davem@davemloft.net>2012-05-01 09:30:55 -0400
commitf9bac8df908d7c0a36960265c92f3445623b19d1 (patch)
tree58bc4af4f65eed62a01027d2358b713b1a060e37 /net/l2tp/l2tp_core.c
parent2121c3f571f08bd723f449f2477f1582709f5a2a (diff)
l2tp: netlink api for l2tpv3 ipv6 unmanaged tunnels
This patch adds support for unmanaged L2TPv3 tunnels over IPv6 using the netlink API. We already support unmanaged L2TPv3 tunnels over IPv4. A patch to iproute2 to make use of this feature will be submitted separately. Signed-off-by: Chris Elston <celston@katalix.com> Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_core.c')
-rw-r--r--net/l2tp/l2tp_core.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index f1bfae3e1ba6..55fc569c8170 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1366,31 +1366,68 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t
{
int err = -EINVAL;
struct sockaddr_in udp_addr;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct sockaddr_in6 udp6_addr;
+#endif
struct sockaddr_l2tpip ip_addr;
struct socket *sock = NULL;
switch (cfg->encap) {
case L2TP_ENCAPTYPE_UDP:
- err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
- if (err < 0)
- goto out;
+#if IS_ENABLED(CONFIG_IPV6)
+ if (cfg->local_ip6 && cfg->peer_ip6) {
+ err = sock_create(AF_INET6, SOCK_DGRAM, 0, sockp);
+ if (err < 0)
+ goto out;
- sock = *sockp;
+ sock = *sockp;
- memset(&udp_addr, 0, sizeof(udp_addr));
- udp_addr.sin_family = AF_INET;
- udp_addr.sin_addr = cfg->local_ip;
- udp_addr.sin_port = htons(cfg->local_udp_port);
- err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
- if (err < 0)
- goto out;
+ memset(&udp6_addr, 0, sizeof(udp6_addr));
+ udp6_addr.sin6_family = AF_INET6;
+ memcpy(&udp6_addr.sin6_addr, cfg->local_ip6,
+ sizeof(udp6_addr.sin6_addr));
+ udp6_addr.sin6_port = htons(cfg->local_udp_port);
+ err = kernel_bind(sock, (struct sockaddr *) &udp6_addr,
+ sizeof(udp6_addr));
+ if (err < 0)
+ goto out;
- udp_addr.sin_family = AF_INET;
- udp_addr.sin_addr = cfg->peer_ip;
- udp_addr.sin_port = htons(cfg->peer_udp_port);
- err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
- if (err < 0)
- goto out;
+ udp6_addr.sin6_family = AF_INET6;
+ memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6,
+ sizeof(udp6_addr.sin6_addr));
+ udp6_addr.sin6_port = htons(cfg->peer_udp_port);
+ err = kernel_connect(sock,
+ (struct sockaddr *) &udp6_addr,
+ sizeof(udp6_addr), 0);
+ if (err < 0)
+ goto out;
+ } else
+#endif
+ {
+ err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
+ if (err < 0)
+ goto out;
+
+ sock = *sockp;
+
+ memset(&udp_addr, 0, sizeof(udp_addr));
+ udp_addr.sin_family = AF_INET;
+ udp_addr.sin_addr = cfg->local_ip;
+ udp_addr.sin_port = htons(cfg->local_udp_port);
+ err = kernel_bind(sock, (struct sockaddr *) &udp_addr,
+ sizeof(udp_addr));
+ if (err < 0)
+ goto out;
+
+ udp_addr.sin_family = AF_INET;
+ udp_addr.sin_addr = cfg->peer_ip;
+ udp_addr.sin_port = htons(cfg->peer_udp_port);
+ err = kernel_connect(sock,
+ (struct sockaddr *) &udp_addr,
+ sizeof(udp_addr), 0);
+ if (err < 0)
+ goto out;
+ }
if (!cfg->use_udp_checksums)
sock->sk->sk_no_check = UDP_CSUM_NOXMIT;
@@ -1398,6 +1435,13 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t
break;
case L2TP_ENCAPTYPE_IP:
+#if IS_ENABLED(CONFIG_IPV6)
+ if (cfg->local_ip6 && cfg->peer_ip6) {
+ /* IP encap over IPv6 not yet supported */
+ err = -EPROTONOSUPPORT;
+ goto out;
+ }
+#endif
err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
if (err < 0)
goto out;