aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/l2tp/l2tp_core.c75
-rw-r--r--net/l2tp/l2tp_core.h1
-rw-r--r--net/l2tp/l2tp_ppp.c12
3 files changed, 38 insertions, 50 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 97d30ac67c88..8aecf5df6656 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1316,26 +1316,12 @@ again:
1316 1316
1317 hlist_del_init(&session->hlist); 1317 hlist_del_init(&session->hlist);
1318 1318
1319 /* Since we should hold the sock lock while
1320 * doing any unbinding, we need to release the
1321 * lock we're holding before taking that lock.
1322 * Hold a reference to the sock so it doesn't
1323 * disappear as we're jumping between locks.
1324 */
1325 if (session->ref != NULL) 1319 if (session->ref != NULL)
1326 (*session->ref)(session); 1320 (*session->ref)(session);
1327 1321
1328 write_unlock_bh(&tunnel->hlist_lock); 1322 write_unlock_bh(&tunnel->hlist_lock);
1329 1323
1330 if (tunnel->version != L2TP_HDR_VER_2) { 1324 __l2tp_session_unhash(session);
1331 struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
1332
1333 spin_lock_bh(&pn->l2tp_session_hlist_lock);
1334 hlist_del_init_rcu(&session->global_hlist);
1335 spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1336 synchronize_rcu();
1337 }
1338
1339 l2tp_session_queue_purge(session); 1325 l2tp_session_queue_purge(session);
1340 1326
1341 if (session->session_close != NULL) 1327 if (session->session_close != NULL)
@@ -1732,64 +1718,71 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
1732 */ 1718 */
1733void l2tp_session_free(struct l2tp_session *session) 1719void l2tp_session_free(struct l2tp_session *session)
1734{ 1720{
1735 struct l2tp_tunnel *tunnel; 1721 struct l2tp_tunnel *tunnel = session->tunnel;
1736 1722
1737 BUG_ON(atomic_read(&session->ref_count) != 0); 1723 BUG_ON(atomic_read(&session->ref_count) != 0);
1738 1724
1739 tunnel = session->tunnel; 1725 if (tunnel) {
1740 if (tunnel != NULL) {
1741 BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC); 1726 BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
1727 if (session->session_id != 0)
1728 atomic_dec(&l2tp_session_count);
1729 sock_put(tunnel->sock);
1730 session->tunnel = NULL;
1731 l2tp_tunnel_dec_refcount(tunnel);
1732 }
1733
1734 kfree(session);
1735
1736 return;
1737}
1738EXPORT_SYMBOL_GPL(l2tp_session_free);
1739
1740/* Remove an l2tp session from l2tp_core's hash lists.
1741 * Provides a tidyup interface for pseudowire code which can't just route all
1742 * shutdown via. l2tp_session_delete and a pseudowire-specific session_close
1743 * callback.
1744 */
1745void __l2tp_session_unhash(struct l2tp_session *session)
1746{
1747 struct l2tp_tunnel *tunnel = session->tunnel;
1742 1748
1743 /* Delete the session from the hash */ 1749 /* Remove the session from core hashes */
1750 if (tunnel) {
1751 /* Remove from the per-tunnel hash */
1744 write_lock_bh(&tunnel->hlist_lock); 1752 write_lock_bh(&tunnel->hlist_lock);
1745 hlist_del_init(&session->hlist); 1753 hlist_del_init(&session->hlist);
1746 write_unlock_bh(&tunnel->hlist_lock); 1754 write_unlock_bh(&tunnel->hlist_lock);
1747 1755
1748 /* Unlink from the global hash if not L2TPv2 */ 1756 /* For L2TPv3 we have a per-net hash: remove from there, too */
1749 if (tunnel->version != L2TP_HDR_VER_2) { 1757 if (tunnel->version != L2TP_HDR_VER_2) {
1750 struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); 1758 struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
1751
1752 spin_lock_bh(&pn->l2tp_session_hlist_lock); 1759 spin_lock_bh(&pn->l2tp_session_hlist_lock);
1753 hlist_del_init_rcu(&session->global_hlist); 1760 hlist_del_init_rcu(&session->global_hlist);
1754 spin_unlock_bh(&pn->l2tp_session_hlist_lock); 1761 spin_unlock_bh(&pn->l2tp_session_hlist_lock);
1755 synchronize_rcu(); 1762 synchronize_rcu();
1756 } 1763 }
1757
1758 if (session->session_id != 0)
1759 atomic_dec(&l2tp_session_count);
1760
1761 sock_put(tunnel->sock);
1762
1763 /* This will delete the tunnel context if this
1764 * is the last session on the tunnel.
1765 */
1766 session->tunnel = NULL;
1767 l2tp_tunnel_dec_refcount(tunnel);
1768 } 1764 }
1769
1770 kfree(session);
1771
1772 return;
1773} 1765}
1774EXPORT_SYMBOL_GPL(l2tp_session_free); 1766EXPORT_SYMBOL_GPL(__l2tp_session_unhash);
1775 1767
1776/* This function is used by the netlink SESSION_DELETE command and by 1768/* This function is used by the netlink SESSION_DELETE command and by
1777 pseudowire modules. 1769 pseudowire modules.
1778 */ 1770 */
1779int l2tp_session_delete(struct l2tp_session *session) 1771int l2tp_session_delete(struct l2tp_session *session)
1780{ 1772{
1773 if (session->ref)
1774 (*session->ref)(session);
1775 __l2tp_session_unhash(session);
1781 l2tp_session_queue_purge(session); 1776 l2tp_session_queue_purge(session);
1782
1783 if (session->session_close != NULL) 1777 if (session->session_close != NULL)
1784 (*session->session_close)(session); 1778 (*session->session_close)(session);
1785 1779 if (session->deref)
1780 (*session->ref)(session);
1786 l2tp_session_dec_refcount(session); 1781 l2tp_session_dec_refcount(session);
1787
1788 return 0; 1782 return 0;
1789} 1783}
1790EXPORT_SYMBOL_GPL(l2tp_session_delete); 1784EXPORT_SYMBOL_GPL(l2tp_session_delete);
1791 1785
1792
1793/* We come here whenever a session's send_seq, cookie_len or 1786/* We come here whenever a session's send_seq, cookie_len or
1794 * l2specific_len parameters are set. 1787 * l2specific_len parameters are set.
1795 */ 1788 */
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 519b013f8b31..485a490fd990 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -242,6 +242,7 @@ extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_i
242extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel); 242extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
243extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel); 243extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
244extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg); 244extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
245extern void __l2tp_session_unhash(struct l2tp_session *session);
245extern int l2tp_session_delete(struct l2tp_session *session); 246extern int l2tp_session_delete(struct l2tp_session *session);
246extern void l2tp_session_free(struct l2tp_session *session); 247extern void l2tp_session_free(struct l2tp_session *session);
247extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb)); 248extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 9d0eb8c13530..637a341c1e2d 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -466,19 +466,12 @@ static void pppol2tp_session_close(struct l2tp_session *session)
466 */ 466 */
467static void pppol2tp_session_destruct(struct sock *sk) 467static void pppol2tp_session_destruct(struct sock *sk)
468{ 468{
469 struct l2tp_session *session; 469 struct l2tp_session *session = sk->sk_user_data;
470 470 if (session) {
471 if (sk->sk_user_data != NULL) {
472 session = sk->sk_user_data;
473 if (session == NULL)
474 goto out;
475
476 sk->sk_user_data = NULL; 471 sk->sk_user_data = NULL;
477 BUG_ON(session->magic != L2TP_SESSION_MAGIC); 472 BUG_ON(session->magic != L2TP_SESSION_MAGIC);
478 l2tp_session_dec_refcount(session); 473 l2tp_session_dec_refcount(session);
479 } 474 }
480
481out:
482 return; 475 return;
483} 476}
484 477
@@ -509,6 +502,7 @@ static int pppol2tp_release(struct socket *sock)
509 502
510 /* Purge any queued data */ 503 /* Purge any queued data */
511 if (session != NULL) { 504 if (session != NULL) {
505 __l2tp_session_unhash(session);
512 l2tp_session_queue_purge(session); 506 l2tp_session_queue_purge(session);
513 sock_put(sk); 507 sock_put(sk);
514 } 508 }