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>
This commit is contained in:
parent
a32e0eec70
commit
5dac94e109
net/l2tp
|
@ -1368,6 +1368,7 @@ static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2t
|
||||||
struct sockaddr_in udp_addr;
|
struct sockaddr_in udp_addr;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
struct sockaddr_in6 udp6_addr;
|
struct sockaddr_in6 udp6_addr;
|
||||||
|
struct sockaddr_l2tpip6 ip6_addr;
|
||||||
#endif
|
#endif
|
||||||
struct sockaddr_l2tpip ip_addr;
|
struct sockaddr_l2tpip ip_addr;
|
||||||
struct socket *sock = NULL;
|
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:
|
case L2TP_ENCAPTYPE_IP:
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
if (cfg->local_ip6 && cfg->peer_ip6) {
|
if (cfg->local_ip6 && cfg->peer_ip6) {
|
||||||
/* IP encap over IPv6 not yet supported */
|
err = sock_create(AF_INET6, SOCK_DGRAM, IPPROTO_L2TP,
|
||||||
err = -EPROTONOSUPPORT;
|
sockp);
|
||||||
goto out;
|
if (err < 0)
|
||||||
}
|
goto out;
|
||||||
|
|
||||||
|
sock = *sockp;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
|
{
|
||||||
if (err < 0)
|
err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP,
|
||||||
goto out;
|
sockp);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
sock = *sockp;
|
sock = *sockp;
|
||||||
|
|
||||||
memset(&ip_addr, 0, sizeof(ip_addr));
|
memset(&ip_addr, 0, sizeof(ip_addr));
|
||||||
ip_addr.l2tp_family = AF_INET;
|
ip_addr.l2tp_family = AF_INET;
|
||||||
ip_addr.l2tp_addr = cfg->local_ip;
|
ip_addr.l2tp_addr = cfg->local_ip;
|
||||||
ip_addr.l2tp_conn_id = tunnel_id;
|
ip_addr.l2tp_conn_id = tunnel_id;
|
||||||
err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
|
err = kernel_bind(sock, (struct sockaddr *) &ip_addr,
|
||||||
if (err < 0)
|
sizeof(ip_addr));
|
||||||
goto out;
|
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;
|
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue