diff options
author | James Chapman <jchapman@katalix.com> | 2012-04-30 01:48:55 +0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-01 17:30:55 +0400 |
commit | 5dac94e109263e75ab7fe4e66ef88e9b49f500bf (patch) | |
tree | d87a313b3078911e612e7b18d99853be282b7700 /net | |
parent | a32e0eec7042b21ccb52896cf715e3e2641fed93 (diff) | |
download | linux-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.c | 72 |
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: |