summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 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;
}