l2tp: don't use inet_shutdown on ppp session destroy
[pandora-kernel.git] / net / l2tp / l2tp_ppp.c
index 8a90d75..54e249e 100644 (file)
@@ -95,6 +95,7 @@
 #include <net/ip.h>
 #include <net/udp.h>
 #include <net/xfrm.h>
+#include <net/inet_common.h>
 
 #include <asm/byteorder.h>
 #include <linux/atomic.h>
 struct pppol2tp_session {
        int                     owner;          /* pid that opened the socket */
 
-       struct sock             *sock;          /* Pointer to the session
+       struct mutex            sk_lock;        /* Protects .sk */
+       struct sock __rcu       *sk;            /* Pointer to the session
                                                 * PPPoX socket */
+       struct sock             *__sk;          /* Copy of .sk, for cleanup */
+       struct rcu_head         rcu;            /* For asynchronous release */
        struct sock             *tunnel_sock;   /* Pointer to the tunnel UDP
                                                 * socket */
        int                     flags;          /* accessed by PPPIOCGFLAGS.
@@ -141,6 +145,24 @@ static const struct ppp_channel_ops pppol2tp_chan_ops = {
 
 static const struct proto_ops pppol2tp_ops;
 
+/* Retrieves the pppol2tp socket associated to a session.
+ * A reference is held on the returned socket, so this function must be paired
+ * with sock_put().
+ */
+static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk;
+
+       rcu_read_lock();
+       sk = rcu_dereference(ps->sk);
+       if (sk)
+               sock_hold(sk);
+       rcu_read_unlock();
+
+       return sk;
+}
+
 /* Helpers to obtain tunnel/session contexts from sockets.
  */
 static inline struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk)
@@ -200,8 +222,6 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (sk->sk_state & PPPOX_BOUND)
                goto end;
 
-       msg->msg_namelen = 0;
-
        err = 0;
        skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
                                flags & MSG_DONTWAIT, &err);
@@ -230,7 +250,8 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
        /* If the socket is bound, send it in to PPP's input queue. Otherwise
         * queue it on the session socket.
         */
-       sk = ps->sock;
+       rcu_read_lock();
+       sk = rcu_dereference(ps->sk);
        if (sk == NULL)
                goto no_sock;
 
@@ -266,31 +287,17 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                session->stats.rx_errors++;
                kfree_skb(skb);
        }
+       rcu_read_unlock();
 
        return;
 
 no_sock:
+       rcu_read_unlock();
        PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
               "%s: no socket\n", session->name);
        kfree_skb(skb);
 }
 
-static void pppol2tp_session_sock_hold(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock)
-               sock_hold(ps->sock);
-}
-
-static void pppol2tp_session_sock_put(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock)
-               sock_put(ps->sock);
-}
-
 /************************************************************************
  * Transmit handling
  ***********************************************************************/
@@ -350,18 +357,21 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        skb_put(skb, 2);
 
        /* Copy user data into skb */
-       error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
+       error = memcpy_fromiovec(skb_put(skb, total_len), m->msg_iov,
+                                total_len);
        if (error < 0) {
                kfree_skb(skb);
                goto error_put_sess_tun;
        }
-       skb_put(skb, total_len);
 
+       local_bh_disable();
        l2tp_xmit_skb(session, skb, session->hdr_len);
+       local_bh_enable();
 
        sock_put(ps->tunnel_sock);
+       sock_put(sk);
 
-       return error;
+       return total_len;
 
 error_put_sess_tun:
        sock_put(ps->tunnel_sock);
@@ -431,7 +441,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        skb->data[0] = ppph[0];
        skb->data[1] = ppph[1];
 
+       local_bh_disable();
        l2tp_xmit_skb(session, skb, session->hdr_len);
+       local_bh_enable();
 
        sock_put(sk_tun);
        sock_put(sk);
@@ -455,37 +467,6 @@ abort:
  */
 static void pppol2tp_session_close(struct l2tp_session *session)
 {
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-       struct sock *sk = ps->sock;
-       struct sk_buff *skb;
-
-       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-
-       if (session->session_id == 0)
-               goto out;
-
-       if (sk != NULL) {
-               lock_sock(sk);
-
-               if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
-                       pppox_unbind_sock(sk);
-                       sk->sk_state = PPPOX_DEAD;
-                       sk->sk_state_change(sk);
-               }
-
-               /* Purge any queued data */
-               skb_queue_purge(&sk->sk_receive_queue);
-               skb_queue_purge(&sk->sk_write_queue);
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
-
-               release_sock(sk);
-       }
-
-out:
-       return;
 }
 
 /* Really kill the session socket. (Called from sock_put() if
@@ -509,6 +490,14 @@ out:
        return;
 }
 
+static void pppol2tp_put_sk(struct rcu_head *head)
+{
+       struct pppol2tp_session *ps;
+
+       ps = container_of(head, typeof(*ps), rcu);
+       sock_put(ps->__sk);
+}
+
 /* Called when the PPPoX socket (session) is closed.
  */
 static int pppol2tp_release(struct socket *sock)
@@ -534,17 +523,26 @@ static int pppol2tp_release(struct socket *sock)
 
        session = pppol2tp_sock_to_session(sk);
 
-       /* Purge any queued data */
-       skb_queue_purge(&sk->sk_receive_queue);
-       skb_queue_purge(&sk->sk_write_queue);
        if (session != NULL) {
-               struct sk_buff *skb;
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
-               sock_put(sk);
+               struct pppol2tp_session *ps;
+
+               l2tp_session_delete(session);
+
+               ps = l2tp_session_priv(session);
+               mutex_lock(&ps->sk_lock);
+               ps->__sk = rcu_dereference_protected(ps->sk,
+                                                    lockdep_is_held(&ps->sk_lock));
+               RCU_INIT_POINTER(ps->sk, NULL);
+               mutex_unlock(&ps->sk_lock);
+               call_rcu(&ps->rcu, pppol2tp_put_sk);
+
+               /* Rely on the sock_put() call at the end of the function for
+                * dropping the reference held by pppol2tp_sock_to_session().
+                * The last reference will be dropped by pppol2tp_put_sk().
+                */
        }
+       skb_queue_purge(&sk->sk_receive_queue);
+       skb_queue_purge(&sk->sk_write_queue);
 
        release_sock(sk);
 
@@ -611,16 +609,47 @@ out:
 static void pppol2tp_show(struct seq_file *m, void *arg)
 {
        struct l2tp_session *session = arg;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk;
+
+       sk = pppol2tp_session_get_sock(session);
+       if (sk) {
+               struct pppox_sock *po = pppox_sk(sk);
 
-       if (ps) {
-               struct pppox_sock *po = pppox_sk(ps->sock);
-               if (po)
-                       seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               sock_put(sk);
        }
 }
 #endif
 
+static void pppol2tp_session_init(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps;
+       struct dst_entry *dst;
+
+       session->recv_skb = pppol2tp_recv;
+       session->session_close = pppol2tp_session_close;
+#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
+       session->show = pppol2tp_show;
+#endif
+
+       ps = l2tp_session_priv(session);
+       mutex_init(&ps->sk_lock);
+       ps->tunnel_sock = session->tunnel->sock;
+       ps->owner = current->pid;
+
+       /* If PMTU discovery was enabled, use the MTU that was discovered */
+       dst = sk_dst_get(session->tunnel->sock);
+       if (dst) {
+               u32 pmtu = dst_mtu(dst);
+
+               if (pmtu) {
+                       session->mtu = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+                       session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+               }
+               dst_release(dst);
+       }
+}
+
 /* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
  */
 static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
@@ -633,11 +662,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        struct l2tp_session *session = NULL;
        struct l2tp_tunnel *tunnel;
        struct pppol2tp_session *ps;
-       struct dst_entry *dst;
        struct l2tp_session_cfg cfg = { 0, };
        int error = 0;
        u32 tunnel_id, peer_tunnel_id;
        u32 session_id, peer_session_id;
+       bool drop_refcnt = false;
+       bool drop_tunnel = false;
        int ver = 2;
        int fd;
 
@@ -681,7 +711,9 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        if (tunnel_id == 0)
                goto end;
 
-       tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id);
+       tunnel = l2tp_tunnel_get(sock_net(sk), tunnel_id);
+       if (tunnel)
+               drop_tunnel = true;
 
        /* Special case: create tunnel context if session_id and
         * peer_session_id is 0. Otherwise look up tunnel using supplied
@@ -718,64 +750,53 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                        tunnel->peer_tunnel_id = sp3->pppol2tp.d_tunnel;
        }
 
-       /* Create session if it doesn't already exist. We handle the
-        * case where a session was previously created by the netlink
-        * interface by checking that the session doesn't already have
-        * a socket and its tunnel socket are what we expect. If any
-        * of those checks fail, return EEXIST to the caller.
-        */
-       session = l2tp_session_find(sock_net(sk), tunnel, session_id);
-       if (session == NULL) {
-               /* Default MTU must allow space for UDP/L2TP/PPP
-                * headers.
+       session = l2tp_session_get(sock_net(sk), tunnel, session_id, false);
+       if (session) {
+               drop_refcnt = true;
+               ps = l2tp_session_priv(session);
+
+               /* Using a pre-existing session is fine as long as it hasn't
+                * been connected yet.
                 */
-               cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+               mutex_lock(&ps->sk_lock);
+               if (rcu_dereference_protected(ps->sk,
+                                             lockdep_is_held(&ps->sk_lock))) {
+                       mutex_unlock(&ps->sk_lock);
+                       error = -EEXIST;
+                       goto end;
+               }
+
+               /* consistency checks */
+               if (ps->tunnel_sock != tunnel->sock) {
+                       mutex_unlock(&ps->sk_lock);
+                       error = -EEXIST;
+                       goto end;
+               }
+       } else {
+               /* Default MTU must allow space for UDP/L2TP/PPP headers */
+               cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+               cfg.mru = cfg.mtu;
 
-               /* Allocate and initialize a new session context. */
                session = l2tp_session_create(sizeof(struct pppol2tp_session),
                                              tunnel, session_id,
                                              peer_session_id, &cfg);
-               if (session == NULL) {
-                       error = -ENOMEM;
+               if (IS_ERR(session)) {
+                       error = PTR_ERR(session);
                        goto end;
                }
-       } else {
+
+               pppol2tp_session_init(session);
                ps = l2tp_session_priv(session);
-               error = -EEXIST;
-               if (ps->sock != NULL)
-                       goto end;
+               l2tp_session_inc_refcount(session);
 
-               /* consistency checks */
-               if (ps->tunnel_sock != tunnel->sock)
+               mutex_lock(&ps->sk_lock);
+               error = l2tp_session_register(session, tunnel);
+               if (error < 0) {
+                       mutex_unlock(&ps->sk_lock);
+                       kfree(session);
                        goto end;
-       }
-
-       /* Associate session with its PPPoL2TP socket */
-       ps = l2tp_session_priv(session);
-       ps->owner            = current->pid;
-       ps->sock             = sk;
-       ps->tunnel_sock = tunnel->sock;
-
-       session->recv_skb       = pppol2tp_recv;
-       session->session_close  = pppol2tp_session_close;
-#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
-       session->show           = pppol2tp_show;
-#endif
-
-       /* We need to know each time a skb is dropped from the reorder
-        * queue.
-        */
-       session->ref = pppol2tp_session_sock_hold;
-       session->deref = pppol2tp_session_sock_put;
-
-       /* If PMTU discovery was enabled, use the MTU that was discovered */
-       dst = sk_dst_get(sk);
-       if (dst != NULL) {
-               u32 pmtu = dst_mtu(__sk_dst_get(sk));
-               if (pmtu != 0)
-                       session->mtu = session->mru = pmtu -
-                               PPPOL2TP_HEADER_OVERHEAD;
-               dst_release(dst);
+               }
+               drop_refcnt = true;
        }
 
        /* Special case: if source & dest session_id == 0x0000, this
@@ -800,17 +821,32 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        po->chan.mtu     = session->mtu;
 
        error = ppp_register_net_channel(sock_net(sk), &po->chan);
-       if (error)
+       if (error) {
+               mutex_unlock(&ps->sk_lock);
                goto end;
+       }
 
 out_no_ppp:
        /* This is how we get the session context from the socket. */
        sk->sk_user_data = session;
+       rcu_assign_pointer(ps->sk, sk);
+       mutex_unlock(&ps->sk_lock);
+
+       /* Keep the reference we've grabbed on the session: sk doesn't expect
+        * the session to disappear. pppol2tp_session_destruct() is responsible
+        * for dropping it.
+        */
+       drop_refcnt = false;
+
        sk->sk_state = PPPOX_CONNECTED;
        PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
               "%s: created\n", session->name);
 
 end:
+       if (drop_refcnt)
+               l2tp_session_dec_refcount(session);
+       if (drop_tunnel)
+               l2tp_tunnel_dec_refcount(tunnel);
        release_sock(sk);
 
        return error;
@@ -818,31 +854,19 @@ end:
 
 #ifdef CONFIG_L2TP_V3
 
-/* Called when creating sessions via the netlink interface.
- */
-static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+/* Called when creating sessions via the netlink interface. */
+static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
+                                  u32 session_id, u32 peer_session_id,
+                                  struct l2tp_session_cfg *cfg)
 {
        int error;
-       struct l2tp_tunnel *tunnel;
        struct l2tp_session *session;
-       struct pppol2tp_session *ps;
-
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-
-       /* Error if we can't find the tunnel */
-       error = -ENOENT;
-       if (tunnel == NULL)
-               goto out;
 
        /* Error if tunnel socket is not prepped */
-       if (tunnel->sock == NULL)
-               goto out;
-
-       /* Check that this session doesn't already exist */
-       error = -EEXIST;
-       session = l2tp_session_find(net, tunnel, session_id);
-       if (session != NULL)
-               goto out;
+       if (!tunnel->sock) {
+               error = -ENOENT;
+               goto err;
+       }
 
        /* Default MTU values. */
        if (cfg->mtu == 0)
@@ -851,37 +875,28 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
                cfg->mru = cfg->mtu;
 
        /* Allocate and initialize a new session context. */
-       error = -ENOMEM;
        session = l2tp_session_create(sizeof(struct pppol2tp_session),
                                      tunnel, session_id,
                                      peer_session_id, cfg);
-       if (session == NULL)
-               goto out;
+       if (IS_ERR(session)) {
+               error = PTR_ERR(session);
+               goto err;
+       }
 
-       ps = l2tp_session_priv(session);
-       ps->tunnel_sock = tunnel->sock;
+       pppol2tp_session_init(session);
 
-       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-              "%s: created\n", session->name);
+       error = l2tp_session_register(session, tunnel);
+       if (error < 0)
+               goto err_sess;
 
-       error = 0;
+       return 0;
 
-out:
+err_sess:
+       kfree(session);
+err:
        return error;
 }
 
-/* Called when deleting sessions via the netlink interface.
- */
-static int pppol2tp_session_delete(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock == NULL)
-               l2tp_session_dec_refcount(session);
-
-       return 0;
-}
-
 #endif /* CONFIG_L2TP_V3 */
 
 /* getname() support.
@@ -910,12 +925,10 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
 
        pls = l2tp_session_priv(session);
        tunnel = l2tp_sock_to_tunnel(pls->tunnel_sock);
-       if (tunnel == NULL) {
-               error = -EBADF;
+       if (tunnel == NULL)
                goto end_put_sess;
-       }
 
-       inet = inet_sk(sk);
+       inet = inet_sk(tunnel->sock);
        if (tunnel->version == 2) {
                struct sockaddr_pppol2tp sp;
                len = sizeof(sp);
@@ -951,12 +964,11 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
        }
 
        *usockaddr_len = len;
+       error = 0;
 
        sock_put(pls->tunnel_sock);
 end_put_sess:
        sock_put(sk);
-       error = 0;
-
 end:
        return error;
 }
@@ -1002,8 +1014,9 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
               "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
               session->name, cmd, arg);
 
-       sk = ps->sock;
-       sock_hold(sk);
+       sk = pppol2tp_session_get_sock(session);
+       if (!sk)
+               return -EBADR;
 
        switch (cmd) {
        case SIOCGIFMTU:
@@ -1149,11 +1162,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
                if (stats.session_id != 0) {
                        /* resend to session ioctl handler */
                        struct l2tp_session *session =
-                               l2tp_session_find(sock_net(sk), tunnel, stats.session_id);
-                       if (session != NULL)
-                               err = pppol2tp_session_ioctl(session, cmd, arg);
-                       else
+                               l2tp_session_get(sock_net(sk), tunnel,
+                                                stats.session_id, true);
+
+                       if (session) {
+                               err = pppol2tp_session_ioctl(session, cmd,
+                                                            arg);
+                               if (session->deref)
+                                       session->deref(session);
+                               l2tp_session_dec_refcount(session);
+                       } else {
                                err = -EBADR;
+                       }
                        break;
                }
 #ifdef CONFIG_XFRM
@@ -1273,7 +1293,6 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                                       int optname, int val)
 {
        int err = 0;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
 
        switch (optname) {
        case PPPOL2TP_SO_RECVSEQ:
@@ -1293,8 +1312,8 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                }
                session->send_seq = val ? -1 : 0;
                {
-                       struct sock *ssk      = ps->sock;
-                       struct pppox_sock *po = pppox_sk(ssk);
+                       struct pppox_sock *po = pppox_sk(sk);
+
                        po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
                                PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
                }
@@ -1348,7 +1367,7 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
        int err;
 
        if (level != SOL_PPPOL2TP)
-               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+               return -EINVAL;
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -1381,8 +1400,6 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
        } else
                err = pppol2tp_session_setsockopt(sk, session, optname, val);
 
-       err = 0;
-
 end_put_sess:
        sock_put(sk);
 end:
@@ -1474,7 +1491,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
        struct pppol2tp_session *ps;
 
        if (level != SOL_PPPOL2TP)
-               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+               return -EINVAL;
 
        if (get_user(len, (int __user *) optlen))
                return -EFAULT;
@@ -1505,8 +1522,13 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
 
                err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
                sock_put(ps->tunnel_sock);
-       } else
+               if (err)
+                       goto end_put_sess;
+       } else {
                err = pppol2tp_session_getsockopt(sk, session, optname, &val);
+               if (err)
+                       goto end_put_sess;
+       }
 
        err = -EFAULT;
        if (put_user(len, (int __user *) optlen))
@@ -1558,7 +1580,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
 
 static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
 {
-       pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx);
+       pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true);
        pd->session_idx++;
 
        if (pd->session == NULL) {
@@ -1626,8 +1648,9 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
 {
        struct l2tp_session *session = v;
        struct l2tp_tunnel *tunnel = session->tunnel;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-       struct pppox_sock *po = pppox_sk(ps->sock);
+       unsigned char state;
+       char user_data_ok;
+       struct sock *sk;
        u32 ip = 0;
        u16 port = 0;
 
@@ -1637,6 +1660,15 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                port = ntohs(inet->inet_sport);
        }
 
+       sk = pppol2tp_session_get_sock(session);
+       if (sk) {
+               state = sk->sk_state;
+               user_data_ok = (session == sk->sk_user_data) ? 'Y' : 'N';
+       } else {
+               state = 0;
+               user_data_ok = 'N';
+       }
+
        seq_printf(m, "  SESSION '%s' %08X/%d %04X/%04X -> "
                   "%04X/%04X %d %c\n",
                   session->name, ip, port,
@@ -1644,9 +1676,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   session->session_id,
                   tunnel->peer_tunnel_id,
                   session->peer_session_id,
-                  ps->sock->sk_state,
-                  (session == ps->sock->sk_user_data) ?
-                  'Y' : 'N');
+                  state, user_data_ok);
        seq_printf(m, "   %d/%d/%c/%c/%s %08x %u\n",
                   session->mtu, session->mru,
                   session->recv_seq ? 'R' : '-',
@@ -1663,8 +1693,12 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   (unsigned long long)session->stats.rx_bytes,
                   (unsigned long long)session->stats.rx_errors);
 
-       if (po)
+       if (sk) {
+               struct pppox_sock *po = pppox_sk(sk);
+
                seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               sock_put(sk);
+       }
 }
 
 static int pppol2tp_seq_show(struct seq_file *m, void *v)
@@ -1685,10 +1719,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v)
 
        /* Show the tunnel or session context.
         */
-       if (pd->session == NULL)
+       if (!pd->session) {
                pppol2tp_seq_tunnel_show(m, pd->tunnel);
-       else
+       } else {
                pppol2tp_seq_session_show(m, pd->session);
+               if (pd->session->deref)
+                       pd->session->deref(pd->session);
+               l2tp_session_dec_refcount(pd->session);
+       }
 
 out:
        return 0;
@@ -1777,14 +1815,15 @@ static const struct proto_ops pppol2tp_ops = {
 
 static const struct pppox_proto pppol2tp_proto = {
        .create         = pppol2tp_create,
-       .ioctl          = pppol2tp_ioctl
+       .ioctl          = pppol2tp_ioctl,
+       .owner          = THIS_MODULE,
 };
 
 #ifdef CONFIG_L2TP_V3
 
 static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = {
        .session_create = pppol2tp_session_create,
-       .session_delete = pppol2tp_session_delete,
+       .session_delete = l2tp_session_delete,
 };
 
 #endif /* CONFIG_L2TP_V3 */