diff options
author | Chris Elston <celston@katalix.com> | 2012-04-29 17:48:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-01 09:30:55 -0400 |
commit | f9bac8df908d7c0a36960265c92f3445623b19d1 (patch) | |
tree | 58bc4af4f65eed62a01027d2358b713b1a060e37 /net/l2tp/l2tp_core.c | |
parent | 2121c3f571f08bd723f449f2477f1582709f5a2a (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.c | 78 |
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 | |||
1366 | { | 1366 | { |
1367 | int err = -EINVAL; | 1367 | int err = -EINVAL; |
1368 | struct sockaddr_in udp_addr; | 1368 | struct sockaddr_in udp_addr; |
1369 | #if IS_ENABLED(CONFIG_IPV6) | ||
1370 | struct sockaddr_in6 udp6_addr; | ||
1371 | #endif | ||
1369 | struct sockaddr_l2tpip ip_addr; | 1372 | struct sockaddr_l2tpip ip_addr; |
1370 | struct socket *sock = NULL; | 1373 | struct socket *sock = NULL; |
1371 | 1374 | ||
1372 | switch (cfg->encap) { | 1375 | switch (cfg->encap) { |
1373 | case L2TP_ENCAPTYPE_UDP: | 1376 | case L2TP_ENCAPTYPE_UDP: |
1374 | err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp); | 1377 | #if IS_ENABLED(CONFIG_IPV6) |
1375 | if (err < 0) | 1378 | if (cfg->local_ip6 && cfg->peer_ip6) { |
1376 | goto out; | 1379 | err = sock_create(AF_INET6, SOCK_DGRAM, 0, sockp); |
1380 | if (err < 0) | ||
1381 | goto out; | ||
1377 | 1382 | ||
1378 | sock = *sockp; | 1383 | sock = *sockp; |
1379 | 1384 | ||
1380 | memset(&udp_addr, 0, sizeof(udp_addr)); | 1385 | memset(&udp6_addr, 0, sizeof(udp6_addr)); |
1381 | udp_addr.sin_family = AF_INET; | 1386 | udp6_addr.sin6_family = AF_INET6; |
1382 | udp_addr.sin_addr = cfg->local_ip; | 1387 | memcpy(&udp6_addr.sin6_addr, cfg->local_ip6, |
1383 | udp_addr.sin_port = htons(cfg->local_udp_port); | 1388 | sizeof(udp6_addr.sin6_addr)); |
1384 | err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr)); | 1389 | udp6_addr.sin6_port = htons(cfg->local_udp_port); |
1385 | if (err < 0) | 1390 | err = kernel_bind(sock, (struct sockaddr *) &udp6_addr, |
1386 | goto out; | 1391 | sizeof(udp6_addr)); |
1392 | if (err < 0) | ||
1393 | goto out; | ||
1387 | 1394 | ||
1388 | udp_addr.sin_family = AF_INET; | 1395 | udp6_addr.sin6_family = AF_INET6; |
1389 | udp_addr.sin_addr = cfg->peer_ip; | 1396 | memcpy(&udp6_addr.sin6_addr, cfg->peer_ip6, |
1390 | udp_addr.sin_port = htons(cfg->peer_udp_port); | 1397 | sizeof(udp6_addr.sin6_addr)); |
1391 | err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0); | 1398 | udp6_addr.sin6_port = htons(cfg->peer_udp_port); |
1392 | if (err < 0) | 1399 | err = kernel_connect(sock, |
1393 | goto out; | 1400 | (struct sockaddr *) &udp6_addr, |
1401 | sizeof(udp6_addr), 0); | ||
1402 | if (err < 0) | ||
1403 | goto out; | ||
1404 | } else | ||
1405 | #endif | ||
1406 | { | ||
1407 | err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp); | ||
1408 | if (err < 0) | ||
1409 | goto out; | ||
1410 | |||
1411 | sock = *sockp; | ||
1412 | |||
1413 | memset(&udp_addr, 0, sizeof(udp_addr)); | ||
1414 | udp_addr.sin_family = AF_INET; | ||
1415 | udp_addr.sin_addr = cfg->local_ip; | ||
1416 | udp_addr.sin_port = htons(cfg->local_udp_port); | ||
1417 | err = kernel_bind(sock, (struct sockaddr *) &udp_addr, | ||
1418 | sizeof(udp_addr)); | ||
1419 | if (err < 0) | ||
1420 | goto out; | ||
1421 | |||
1422 | udp_addr.sin_family = AF_INET; | ||
1423 | udp_addr.sin_addr = cfg->peer_ip; | ||
1424 | udp_addr.sin_port = htons(cfg->peer_udp_port); | ||
1425 | err = kernel_connect(sock, | ||
1426 | (struct sockaddr *) &udp_addr, | ||
1427 | sizeof(udp_addr), 0); | ||
1428 | if (err < 0) | ||
1429 | goto out; | ||
1430 | } | ||
1394 | 1431 | ||
1395 | if (!cfg->use_udp_checksums) | 1432 | if (!cfg->use_udp_checksums) |
1396 | sock->sk->sk_no_check = UDP_CSUM_NOXMIT; | 1433 | 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 | |||
1398 | break; | 1435 | break; |
1399 | 1436 | ||
1400 | case L2TP_ENCAPTYPE_IP: | 1437 | case L2TP_ENCAPTYPE_IP: |
1438 | #if IS_ENABLED(CONFIG_IPV6) | ||
1439 | if (cfg->local_ip6 && cfg->peer_ip6) { | ||
1440 | /* IP encap over IPv6 not yet supported */ | ||
1441 | err = -EPROTONOSUPPORT; | ||
1442 | goto out; | ||
1443 | } | ||
1444 | #endif | ||
1401 | err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp); | 1445 | err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp); |
1402 | if (err < 0) | 1446 | if (err < 0) |
1403 | goto out; | 1447 | goto out; |