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 | |
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')
-rw-r--r-- | net/l2tp/l2tp_core.c | 78 | ||||
-rw-r--r-- | net/l2tp/l2tp_core.h | 4 | ||||
-rw-r--r-- | net/l2tp/l2tp_netlink.c | 48 |
3 files changed, 109 insertions, 21 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; |
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a8c943bf4140..0bf60fc88bb7 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -151,6 +151,10 @@ struct l2tp_tunnel_cfg { | |||
151 | /* Used only for kernel-created sockets */ | 151 | /* Used only for kernel-created sockets */ |
152 | struct in_addr local_ip; | 152 | struct in_addr local_ip; |
153 | struct in_addr peer_ip; | 153 | struct in_addr peer_ip; |
154 | #if IS_ENABLED(CONFIG_IPV6) | ||
155 | struct in6_addr *local_ip6; | ||
156 | struct in6_addr *peer_ip6; | ||
157 | #endif | ||
154 | u16 local_udp_port; | 158 | u16 local_udp_port; |
155 | u16 peer_udp_port; | 159 | u16 peer_udp_port; |
156 | unsigned int use_udp_checksums:1; | 160 | unsigned int use_udp_checksums:1; |
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 1dbb9772fc45..24edad0fd9ba 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -133,10 +133,25 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info | |||
133 | if (info->attrs[L2TP_ATTR_FD]) { | 133 | if (info->attrs[L2TP_ATTR_FD]) { |
134 | fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]); | 134 | fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]); |
135 | } else { | 135 | } else { |
136 | if (info->attrs[L2TP_ATTR_IP_SADDR]) | 136 | #if IS_ENABLED(CONFIG_IPV6) |
137 | cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]); | 137 | if (info->attrs[L2TP_ATTR_IP6_SADDR] && |
138 | if (info->attrs[L2TP_ATTR_IP_DADDR]) | 138 | info->attrs[L2TP_ATTR_IP6_DADDR]) { |
139 | cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]); | 139 | cfg.local_ip6 = nla_data( |
140 | info->attrs[L2TP_ATTR_IP6_SADDR]); | ||
141 | cfg.peer_ip6 = nla_data( | ||
142 | info->attrs[L2TP_ATTR_IP6_DADDR]); | ||
143 | } else | ||
144 | #endif | ||
145 | if (info->attrs[L2TP_ATTR_IP_SADDR] && | ||
146 | info->attrs[L2TP_ATTR_IP_DADDR]) { | ||
147 | cfg.local_ip.s_addr = nla_get_be32( | ||
148 | info->attrs[L2TP_ATTR_IP_SADDR]); | ||
149 | cfg.peer_ip.s_addr = nla_get_be32( | ||
150 | info->attrs[L2TP_ATTR_IP_DADDR]); | ||
151 | } else { | ||
152 | ret = -EINVAL; | ||
153 | goto out; | ||
154 | } | ||
140 | if (info->attrs[L2TP_ATTR_UDP_SPORT]) | 155 | if (info->attrs[L2TP_ATTR_UDP_SPORT]) |
141 | cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]); | 156 | cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]); |
142 | if (info->attrs[L2TP_ATTR_UDP_DPORT]) | 157 | if (info->attrs[L2TP_ATTR_UDP_DPORT]) |
@@ -225,6 +240,9 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, | |||
225 | struct nlattr *nest; | 240 | struct nlattr *nest; |
226 | struct sock *sk = NULL; | 241 | struct sock *sk = NULL; |
227 | struct inet_sock *inet; | 242 | struct inet_sock *inet; |
243 | #if IS_ENABLED(CONFIG_IPV6) | ||
244 | struct ipv6_pinfo *np = NULL; | ||
245 | #endif | ||
228 | struct l2tp_stats stats; | 246 | struct l2tp_stats stats; |
229 | unsigned int start; | 247 | unsigned int start; |
230 | 248 | ||
@@ -273,6 +291,11 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, | |||
273 | if (!sk) | 291 | if (!sk) |
274 | goto out; | 292 | goto out; |
275 | 293 | ||
294 | #if IS_ENABLED(CONFIG_IPV6) | ||
295 | if (sk->sk_family == AF_INET6) | ||
296 | np = inet6_sk(sk); | ||
297 | #endif | ||
298 | |||
276 | inet = inet_sk(sk); | 299 | inet = inet_sk(sk); |
277 | 300 | ||
278 | switch (tunnel->encap) { | 301 | switch (tunnel->encap) { |
@@ -284,6 +307,15 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags, | |||
284 | goto nla_put_failure; | 307 | goto nla_put_failure; |
285 | /* NOBREAK */ | 308 | /* NOBREAK */ |
286 | case L2TP_ENCAPTYPE_IP: | 309 | case L2TP_ENCAPTYPE_IP: |
310 | #if IS_ENABLED(CONFIG_IPV6) | ||
311 | if (np) { | ||
312 | if (nla_put(skb, L2TP_ATTR_IP6_SADDR, sizeof(np->saddr), | ||
313 | &np->saddr) || | ||
314 | nla_put(skb, L2TP_ATTR_IP6_DADDR, sizeof(np->daddr), | ||
315 | &np->daddr)) | ||
316 | goto nla_put_failure; | ||
317 | } else | ||
318 | #endif | ||
287 | if (nla_put_be32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr) || | 319 | if (nla_put_be32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr) || |
288 | nla_put_be32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr)) | 320 | nla_put_be32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr)) |
289 | goto nla_put_failure; | 321 | goto nla_put_failure; |
@@ -752,6 +784,14 @@ static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = { | |||
752 | [L2TP_ATTR_MTU] = { .type = NLA_U16, }, | 784 | [L2TP_ATTR_MTU] = { .type = NLA_U16, }, |
753 | [L2TP_ATTR_MRU] = { .type = NLA_U16, }, | 785 | [L2TP_ATTR_MRU] = { .type = NLA_U16, }, |
754 | [L2TP_ATTR_STATS] = { .type = NLA_NESTED, }, | 786 | [L2TP_ATTR_STATS] = { .type = NLA_NESTED, }, |
787 | [L2TP_ATTR_IP6_SADDR] = { | ||
788 | .type = NLA_BINARY, | ||
789 | .len = sizeof(struct in6_addr), | ||
790 | }, | ||
791 | [L2TP_ATTR_IP6_DADDR] = { | ||
792 | .type = NLA_BINARY, | ||
793 | .len = sizeof(struct in6_addr), | ||
794 | }, | ||
755 | [L2TP_ATTR_IFNAME] = { | 795 | [L2TP_ATTR_IFNAME] = { |
756 | .type = NLA_NUL_STRING, | 796 | .type = NLA_NUL_STRING, |
757 | .len = IFNAMSIZ - 1, | 797 | .len = IFNAMSIZ - 1, |