summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2012-04-30 01:48:55 +0400
committerDavid S. Miller <davem@davemloft.net>2012-05-01 17:30:55 +0400
commit5dac94e109263e75ab7fe4e66ef88e9b49f500bf (patch)
treed87a313b3078911e612e7b18d99853be282b7700 /net
parenta32e0eec7042b21ccb52896cf715e3e2641fed93 (diff)
downloadlinux-5dac94e109263e75ab7fe4e66ef88e9b49f500bf.tar.xz
l2tp: let iproute2 create L2TPv3 IP tunnels using IPv6
The netlink API lets users create unmanaged L2TPv3 tunnels using iproute2. Until now, a request to create an unmanaged L2TPv3 IP encapsulation tunnel over IPv6 would be rejected with EPROTONOSUPPORT. Now that l2tp_ip6 implements sockets for L2TP IP encapsulation over IPv6, we can add support for that tunnel type. Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/l2tp/l2tp_core.c72
1 files changed, 50 insertions, 22 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 55fc569c8170..456b52d8f6d8 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1368,6 +1368,7 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t
struct sockaddr_in udp_addr;
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 udp6_addr;
+ struct sockaddr_l2tpip6 ip6_addr;
#endif
struct sockaddr_l2tpip ip_addr;
struct socket *sock = NULL;
@@ -1437,32 +1438,59 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t
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;
+ err = sock_create(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP,
+ sockp);
+ if (err < 0)
+ goto out;
- sock = *sockp;
+ sock = *sockp;
- memset(&ip_addr, 0, sizeof(ip_addr));
- ip_addr.l2tp_family = AF_INET;
- ip_addr.l2tp_addr = cfg->local_ip;
- ip_addr.l2tp_conn_id = tunnel_id;
- err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
- if (err < 0)
- goto out;
+ memset(&ip6_addr, 0, sizeof(ip6_addr));
+ ip6_addr.l2tp_family = AF_INET6;
+ memcpy(&ip6_addr.l2tp_addr, cfg->local_ip6,
+ sizeof(ip6_addr.l2tp_addr));
+ ip6_addr.l2tp_conn_id = tunnel_id;
+ err = kernel_bind(sock, (struct sockaddr *) &ip6_addr,
+ sizeof(ip6_addr));
+ if (err < 0)
+ goto out;
- ip_addr.l2tp_family = AF_INET;
- ip_addr.l2tp_addr = cfg->peer_ip;
- ip_addr.l2tp_conn_id = peer_tunnel_id;
- err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
- if (err < 0)
- goto out;
+ ip6_addr.l2tp_family = AF_INET6;
+ memcpy(&ip6_addr.l2tp_addr, cfg->peer_ip6,
+ sizeof(ip6_addr.l2tp_addr));
+ ip6_addr.l2tp_conn_id = peer_tunnel_id;
+ err = kernel_connect(sock,
+ (struct sockaddr *) &ip6_addr,
+ sizeof(ip6_addr), 0);
+ if (err < 0)
+ goto out;
+ } else
+#endif
+ {
+ err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP,
+ sockp);
+ if (err < 0)
+ goto out;
+ sock = *sockp;
+
+ memset(&ip_addr, 0, sizeof(ip_addr));
+ ip_addr.l2tp_family = AF_INET;
+ ip_addr.l2tp_addr = cfg->local_ip;
+ ip_addr.l2tp_conn_id = tunnel_id;
+ err = kernel_bind(sock, (struct sockaddr *) &ip_addr,
+ sizeof(ip_addr));
+ if (err < 0)
+ goto out;
+
+ ip_addr.l2tp_family = AF_INET;
+ ip_addr.l2tp_addr = cfg->peer_ip;
+ ip_addr.l2tp_conn_id = peer_tunnel_id;
+ err = kernel_connect(sock, (struct sockaddr *) &ip_addr,
+ sizeof(ip_addr), 0);
+ if (err < 0)
+ goto out;
+ }
break;
default: