aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp/l2tp_core.c
diff options
context:
space:
mode:
authorTom Parkin <tparkin@katalix.com>2013-03-19 02:11:13 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-20 12:10:38 -0400
commit9980d001cec86c3c75f3a6008ddb73c397ea3b3e (patch)
tree85c5d87a35ad66c01cc37d6c7ac2b9d29f477daf /net/l2tp/l2tp_core.c
parent44046a593eb770dbecdabf1c82bcd252f2a8337b (diff)
l2tp: add udp encap socket destroy handler
L2TP sessions hold a reference to the tunnel socket to prevent it going away while sessions are still active. However, since tunnel destruction is handled by the sock sk_destruct callback there is a catch-22: a tunnel with sessions cannot be deleted since each session holds a reference to the tunnel socket. If userspace closes a managed tunnel socket, or dies, the tunnel will persist and it will be neccessary to individually delete the sessions using netlink commands. This is ugly. To prevent this occuring, this patch leverages the udp encapsulation socket destroy callback to gain early notification when the tunnel socket is closed. This allows us to safely close the sessions running in the tunnel, dropping the tunnel socket references in the process. The tunnel socket is then destroyed as normal, and the tunnel resources deallocated in sk_destruct. While we're at it, ensure that l2tp_tunnel_closeall correctly drops session references to allow the sessions to be deleted rather than leaking. Signed-off-by: Tom Parkin <tparkin@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.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index d36875f3427e..ee726a752292 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1282,6 +1282,7 @@ static void l2tp_tunnel_destruct(struct sock *sk)
1282 /* No longer an encapsulation socket. See net/ipv4/udp.c */ 1282 /* No longer an encapsulation socket. See net/ipv4/udp.c */
1283 (udp_sk(sk))->encap_type = 0; 1283 (udp_sk(sk))->encap_type = 0;
1284 (udp_sk(sk))->encap_rcv = NULL; 1284 (udp_sk(sk))->encap_rcv = NULL;
1285 (udp_sk(sk))->encap_destroy = NULL;
1285 break; 1286 break;
1286 case L2TP_ENCAPTYPE_IP: 1287 case L2TP_ENCAPTYPE_IP:
1287 break; 1288 break;
@@ -1360,6 +1361,8 @@ again:
1360 if (session->deref != NULL) 1361 if (session->deref != NULL)
1361 (*session->deref)(session); 1362 (*session->deref)(session);
1362 1363
1364 l2tp_session_dec_refcount(session);
1365
1363 write_lock_bh(&tunnel->hlist_lock); 1366 write_lock_bh(&tunnel->hlist_lock);
1364 1367
1365 /* Now restart from the beginning of this hash 1368 /* Now restart from the beginning of this hash
@@ -1373,6 +1376,16 @@ again:
1373 write_unlock_bh(&tunnel->hlist_lock); 1376 write_unlock_bh(&tunnel->hlist_lock);
1374} 1377}
1375 1378
1379/* Tunnel socket destroy hook for UDP encapsulation */
1380static void l2tp_udp_encap_destroy(struct sock *sk)
1381{
1382 struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
1383 if (tunnel) {
1384 l2tp_tunnel_closeall(tunnel);
1385 sock_put(sk);
1386 }
1387}
1388
1376/* Really kill the tunnel. 1389/* Really kill the tunnel.
1377 * Come here only when all sessions have been cleared from the tunnel. 1390 * Come here only when all sessions have been cleared from the tunnel.
1378 */ 1391 */
@@ -1668,6 +1681,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
1668 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ 1681 /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
1669 udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; 1682 udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
1670 udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; 1683 udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
1684 udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy;
1671#if IS_ENABLED(CONFIG_IPV6) 1685#if IS_ENABLED(CONFIG_IPV6)
1672 if (sk->sk_family == PF_INET6) 1686 if (sk->sk_family == PF_INET6)
1673 udpv6_encap_enable(); 1687 udpv6_encap_enable();