[08/16] gtp: add socket destroy handler
diff mbox

Message ID 1447686417-3979-9-git-send-email-aschultz@tpip.net
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Andreas Schultz Nov. 16, 2015, 3:06 p.m. UTC
Add a socket destroy handler and use it to detach and release all
resources from an UDP socket.

Do not longer pin the socket with a reference. This together with
the release handler allows user space to close the socket from
underneath us. The destroy handler will handle the rest.

Signed-off-by: Andreas Schultz <aschultz@tpip.net>
---
 gtp.c | 34 +++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)

Patch
diff mbox

diff --git a/gtp.c b/gtp.c
index 61add82..40a5d1c 100644
--- a/gtp.c
+++ b/gtp.c
@@ -80,6 +80,8 @@  struct gtp_net {
 	struct list_head gtp_instance_list;
 };
 
+static void gtp_encap_disable(struct gtp_instance *gti);
+
 static inline u32 gtp0_hashfn(u64 tid)
 {
 	u32 *tid32 = (u32 *) &tid;
@@ -317,6 +319,16 @@  out_rcu:
 	return ret;
 }
 
+static void gtp_udp_encap_destroy(struct sock *sk)
+{
+	struct gtp_instance *gti = sk_to_gti(sk);
+
+	if (gti) {
+		gtp_encap_disable(gti);
+		sock_put(sk);
+	}
+}
+
 /* UDP encapsulation receive handler. See net/ipv4/udp.c.
  * Return codes: 0: success, <0: error, >0: passed up to userspace UDP.
  */
@@ -401,8 +413,6 @@  static int gtp_dev_init(struct net_device *dev)
 	return 0;
 }
 
-static void gtp_encap_disable(struct gtp_instance *gti);
-
 static void gtp_dev_uninit(struct net_device *dev)
 {
 	struct gtp_instance *gti = netdev_priv(dev);
@@ -958,15 +968,18 @@  static int gtp_encap_enable(struct net_device *dev, struct gtp_instance *gti,
 	sk = gti->sock0->sk;
 	udp_sk(sk)->encap_type = UDP_ENCAP_GTP0;
 	udp_sk(sk)->encap_rcv = gtp_udp_encap_recv;
+	udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy;
 	sk->sk_user_data = gti;
 	udp_encap_enable();
 
 	sk = gti->sock1u->sk;
 	udp_sk(sk)->encap_type = UDP_ENCAP_GTP1U;
 	udp_sk(sk)->encap_rcv = gtp_udp_encap_recv;
+	udp_sk(sk)->encap_destroy = gtp_udp_encap_destroy;
 	sk->sk_user_data = gti;
 
-	return 0;
+	err = 0;
+
 err2:
 	sockfd_put(sock1u);
 err1:
@@ -976,10 +989,17 @@  err1:
 
 static void gtp_encap_disable(struct gtp_instance *gti)
 {
-	if (gti->sock1u)
-		sockfd_put(gti->sock1u);
-	if (gti->sock0)
-		sockfd_put(gti->sock0);
+	if (gti->sock0 && gti->sock0->sk) {
+		udp_sk(gti->sock0->sk)->encap_type = 0;
+		rcu_assign_sk_user_data(gti->sock0->sk, NULL);
+	}
+	if (gti->sock1u && gti->sock1u->sk) {
+		udp_sk(gti->sock1u->sk)->encap_type = 0;
+		rcu_assign_sk_user_data(gti->sock1u->sk, NULL);
+	}
+
+	gti->sock0 = NULL;
+	gti->sock1u = NULL;
 }
 
 static struct net_device *gtp_find_dev(struct net *net, int ifindex)