summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2014-04-08 22:52:59 +0200
committerDmitry Kozlov <xeb@mail.ru>2014-04-11 06:47:26 +0400
commitf2c1387d79966e950c534be9f020ccbbc75f4aa3 (patch)
tree2070b7852650fdce27bbf6f8b05486b15da50d03 /accel-pppd
parent411c4f943bdfdc8ebb79582d17e93923109c95b0 (diff)
downloadaccel-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>
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 086d2a83..8addf167 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;
}