diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2014-04-08 22:52:59 +0200 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2014-04-11 06:47:26 +0400 |
commit | f2c1387d79966e950c534be9f020ccbbc75f4aa3 (patch) | |
tree | 2070b7852650fdce27bbf6f8b05486b15da50d03 | |
parent | 411c4f943bdfdc8ebb79582d17e93923109c95b0 (diff) | |
download | accel-ppp-f2c1387d79966e950c534be9f020ccbbc75f4aa3.tar.gz accel-ppp-f2c1387d79966e950c534be9f020ccbbc75f4aa3.zip |
l2tp: allow tunnel deletion in main reception loop
Let functions launched by l2tp_conn_read() delete the tunnel. This is
done by taking a reference on conn to ensure it'll remain a valid
tunnel, even after calling l2tp_tunnel_free(conn).
l2tp_conn_read() now detects if conn got deleted, so that we know if
the tunnel still holds a reference to itself. If it doesn't,
tunnel_put() may free the tunnel and thus the triton handler we're
running from. So we have to return -1 in this case.
l2tp_tunnel_free() also needs to be modified: it can't safely close
conn->hnd.fd anymore. Since l2tp_conn_read() relies on conn->hnd.fd
being a valid file descriptor, closing it inside the reception loop
would break this assumption in next iteration.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index 086d2a8..8addf16 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -603,6 +603,8 @@ static void __tunnel_destroy(struct l2tp_conn_t *conn) { pthread_mutex_destroy(&conn->ctx_lock); + if (conn->hnd.fd >= 0) + close(conn->hnd.fd); if (conn->challenge) _free(conn->challenge); if (conn->secret) @@ -797,10 +799,6 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) if (conn->hnd.tpd) triton_md_unregister_handler(&conn->hnd); - if (conn->hnd.fd >= 0) { - close(conn->hnd.fd); - conn->hnd.fd = -1; - } if (conn->timeout_timer.tpd) triton_timer_del(&conn->timeout_timer); if (conn->rtimeout_timer.tpd) @@ -3596,6 +3594,11 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) const struct l2tp_attr_t *msg_type; int res; + /* Hold the tunnel. This allows any function we call to free the + * tunnel while still keeping the tunnel valid until we return. + */ + tunnel_hold(conn); + while (1) { res = l2tp_recv(h->fd, &pack, NULL, conn->secret, conn->secret_len); @@ -3604,11 +3607,10 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) log_tunnel(log_info1, conn, "peer is unreachable," " disconnecting tunnel\n"); - l2tp_tunnel_free(conn); - - return -1; + goto err_tunfree; } - return 0; + + break; } if (!pack) @@ -3779,9 +3781,21 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) l2tp_packet_free(pack); } + /* Use conn->state to detect tunnel deletion */ + if (conn->state == STATE_CLOSE) + goto err; + + tunnel_put(conn); + + return 0; + drop: l2tp_packet_free(pack); +err_tunfree: l2tp_tunnel_free(conn); +err: + tunnel_put(conn); + return -1; } |