l2tp: initialise PPP sessions before registering them
[pandora-kernel.git] / net / l2tp / l2tp_ppp.c
index 37bea01..f25cb19 100644 (file)
@@ -478,9 +478,6 @@ static void pppol2tp_session_close(struct l2tp_session *session)
                        inet_shutdown(sk->sk_socket, SEND_SHUTDOWN);
                sock_put(sk);
        }
-
-       /* Don't let the session go away before our socket does */
-       l2tp_session_inc_refcount(session);
        return;
 }
 
@@ -541,7 +538,7 @@ static int pppol2tp_release(struct socket *sock)
        if (session != NULL) {
                struct pppol2tp_session *ps;
 
-               l2tp_session_queue_purge(session);
+               l2tp_session_delete(session);
 
                ps = l2tp_session_priv(session);
                mutex_lock(&ps->sk_lock);
@@ -636,6 +633,35 @@ static void pppol2tp_show(struct seq_file *m, void *arg)
 }
 #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,
@@ -648,7 +674,6 @@ 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;
@@ -772,8 +797,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                        goto end;
                }
 
+               pppol2tp_session_init(session);
                ps = l2tp_session_priv(session);
-               mutex_init(&ps->sk_lock);
                l2tp_session_inc_refcount(session);
 
                mutex_lock(&ps->sk_lock);
@@ -786,26 +811,6 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                drop_refcnt = true;
        }
 
-       ps->owner            = current->pid;
-       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
-
-       /* If PMTU discovery was enabled, use the MTU that was discovered */
-       dst = sk_dst_get(tunnel->sock);
-       if (dst != NULL) {
-               u32 pmtu = dst_mtu(dst);
-
-               if (pmtu != 0)
-                       session->mtu = session->mru = pmtu -
-                               PPPOL2TP_HEADER_OVERHEAD;
-               dst_release(dst);
-       }
-
        /* Special case: if source & dest session_id == 0x0000, this
         * socket is being created to manage the tunnel. Just set up
         * the internal context for use by ioctl() and sockopt()
@@ -839,6 +844,12 @@ out_no_ppp:
        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);
@@ -862,7 +873,6 @@ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
 {
        int error;
        struct l2tp_session *session;
-       struct pppol2tp_session *ps;
 
        /* Error if tunnel socket is not prepped */
        if (!tunnel->sock) {
@@ -885,9 +895,7 @@ static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
                goto err;
        }
 
-       ps = l2tp_session_priv(session);
-       mutex_init(&ps->sk_lock);
-       ps->tunnel_sock = tunnel->sock;
+       pppol2tp_session_init(session);
 
        error = l2tp_session_register(session, tunnel);
        if (error < 0)