|
@@ -113,7 +113,6 @@ struct l2tp_net {
|
|
|
spinlock_t l2tp_session_hlist_lock;
|
|
|
};
|
|
|
|
|
|
-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
|
|
|
|
|
|
static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
|
|
|
{
|
|
@@ -127,39 +126,6 @@ static inline struct l2tp_net *l2tp_pernet(const struct net *net)
|
|
|
return net_generic(net, l2tp_net_id);
|
|
|
}
|
|
|
|
|
|
-/* Tunnel reference counts. Incremented per session that is added to
|
|
|
- * the tunnel.
|
|
|
- */
|
|
|
-static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
|
|
|
-{
|
|
|
- refcount_inc(&tunnel->ref_count);
|
|
|
-}
|
|
|
-
|
|
|
-static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
|
|
|
-{
|
|
|
- if (refcount_dec_and_test(&tunnel->ref_count))
|
|
|
- l2tp_tunnel_free(tunnel);
|
|
|
-}
|
|
|
-#ifdef L2TP_REFCNT_DEBUG
|
|
|
-#define l2tp_tunnel_inc_refcount(_t) \
|
|
|
-do { \
|
|
|
- pr_debug("l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", \
|
|
|
- __func__, __LINE__, (_t)->name, \
|
|
|
- refcount_read(&_t->ref_count)); \
|
|
|
- l2tp_tunnel_inc_refcount_1(_t); \
|
|
|
-} while (0)
|
|
|
-#define l2tp_tunnel_dec_refcount(_t) \
|
|
|
-do { \
|
|
|
- pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", \
|
|
|
- __func__, __LINE__, (_t)->name, \
|
|
|
- refcount_read(&_t->ref_count)); \
|
|
|
- l2tp_tunnel_dec_refcount_1(_t); \
|
|
|
-} while (0)
|
|
|
-#else
|
|
|
-#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
|
|
|
-#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
|
|
|
-#endif
|
|
|
-
|
|
|
/* Session hash global list for L2TPv3.
|
|
|
* The session_id SHOULD be random according to RFC3931, but several
|
|
|
* L2TP implementations use incrementing session_ids. So we do a real
|
|
@@ -229,6 +195,27 @@ l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
|
|
|
return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
|
|
|
}
|
|
|
|
|
|
+/* Lookup a tunnel. A new reference is held on the returned tunnel. */
|
|
|
+struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
|
|
|
+{
|
|
|
+ const struct l2tp_net *pn = l2tp_pernet(net);
|
|
|
+ struct l2tp_tunnel *tunnel;
|
|
|
+
|
|
|
+ rcu_read_lock_bh();
|
|
|
+ list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
|
|
|
+ if (tunnel->tunnel_id == tunnel_id) {
|
|
|
+ l2tp_tunnel_inc_refcount(tunnel);
|
|
|
+ rcu_read_unlock_bh();
|
|
|
+
|
|
|
+ return tunnel;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rcu_read_unlock_bh();
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
|
|
|
+
|
|
|
/* Lookup a session. A new reference is held on the returned session.
|
|
|
* Optionally calls session->ref() too if do_ref is true.
|
|
|
*/
|
|
@@ -1348,17 +1335,6 @@ static void l2tp_udp_encap_destroy(struct sock *sk)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Really kill the tunnel.
|
|
|
- * Come here only when all sessions have been cleared from the tunnel.
|
|
|
- */
|
|
|
-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
|
|
-{
|
|
|
- BUG_ON(refcount_read(&tunnel->ref_count) != 0);
|
|
|
- BUG_ON(tunnel->sock != NULL);
|
|
|
- l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: free...\n", tunnel->name);
|
|
|
- kfree_rcu(tunnel, rcu);
|
|
|
-}
|
|
|
-
|
|
|
/* Workqueue tunnel deletion function */
|
|
|
static void l2tp_tunnel_del_work(struct work_struct *work)
|
|
|
{
|