diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2014-04-08 22:53:42 +0200 |
---|---|---|
committer | Dmitry Kozlov <xeb@mail.ru> | 2014-04-11 06:47:26 +0400 |
commit | 250167afcf5918d8bd310cd887a0f554eac9e8b1 (patch) | |
tree | 6e032df9f436537eedf194fc12a84f028455497d /accel-pppd/ctrl | |
parent | 3448534c7fc579793840af199ae97f8184e99aa1 (diff) | |
download | accel-ppp-250167afcf5918d8bd310cd887a0f554eac9e8b1.tar.gz accel-ppp-250167afcf5918d8bd310cd887a0f554eac9e8b1.zip |
l2tp: automatically delete tunnel if disconnection fails
Let l2tp_tunnel_disconnect() delete the tunnel when an error occurs.
Return an int to indicate if conn has been deleted.
Most callers are compatible with this new behaviour, either because
they never use the tunnel after disconnection or because they hold
a reference on the tunnel.
A few callers need to be adapted though:
-l2tp_conn_close() calls l2tp_tunnel_disconnect() to properly inform
the peer of tunnel disconnection. But it also deletes the tunnel
immediately, no matter if StopCCN message was sent or not. Since
l2tp_conn_close() doesn't hold a reference on the tunnel, care must
be taken not to access the tunnel if it was deleted by
l2tp_tunnel_disconnect().
Since immediate deletion isn't required, the l2tp_tunnel_free() call
is simply removed. The normal disconnection process is now followed,
with detection and retransmission of lost messages, acknowledgment
handling, etc.
-situation is similar for l2tp_tunnel_timeout() and handled in the
same way.
This patch also deletes tunnel's sessions, as well as the establishment
and hello timers. These are of no use once the tunnel enters the
disconnection process.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Diffstat (limited to 'accel-pppd/ctrl')
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index e6ec0751..b337e008 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -163,6 +163,8 @@ static int l2tp_tunnel_send(struct l2tp_conn_t *conn, static int l2tp_session_send(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack); static int l2tp_conn_read(struct triton_md_handler_t *); +static void l2tp_session_free(struct l2tp_sess_t *sess); +static void l2tp_tunnel_free(struct l2tp_conn_t *conn); static void apses_stop(void *data); @@ -567,7 +569,19 @@ out_err: return -1; } -static void l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, int res, int err) +static void l2tp_tunnel_free_sessions(struct l2tp_conn_t *conn) +{ + void *sessions = conn->sessions; + + conn->sessions = NULL; + tdestroy(sessions, (__free_fn_t)l2tp_session_free); + /* Let l2tp_session_free() handle the session counter and + * the reference held by the tunnel. + */ +} + +static int l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, + uint16_t res, uint16_t err) { switch (conn->state) { case STATE_INIT: @@ -582,21 +596,38 @@ static void l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, int res, int err) break; case STATE_FIN: case STATE_CLOSE: - return; + return 0; default: log_tunnel(log_error, conn, "impossible to disconnect tunnel:" " invalid state %i\n", conn->state); - return; + return 0; } - if (l2tp_send_StopCCN(conn, res, err) < 0) + if (l2tp_send_StopCCN(conn, res, err) < 0) { log_tunnel(log_error, conn, - "impossible to notify peer of tunnel disconnection," - " disconnecting anyway\n"); + "impossible to notify peer of tunnel disconnection:" + " sending StopCCN failed," + " deleting tunnel anyway\n"); + + conn->state = STATE_FIN; + l2tp_tunnel_free(conn); + + return -1; + } conn->state = STATE_FIN; + + if (conn->timeout_timer.tpd) + triton_timer_del(&conn->timeout_timer); + if (conn->hello_timer.tpd) + triton_timer_del(&conn->hello_timer); + + if (conn->sessions) + l2tp_tunnel_free_sessions(conn); + + return 0; } static void __tunnel_destroy(struct l2tp_conn_t *conn) @@ -812,15 +843,8 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) l2tp_packet_free(pack); } - if (conn->sessions) { - void *sessions = conn->sessions; - - conn->sessions = NULL; - tdestroy(sessions, (__free_fn_t)l2tp_session_free); - /* Let l2tp_session_free() handle the session counter and - * the reference held by the tunnel. - */ - } + if (conn->sessions) + l2tp_tunnel_free_sessions(conn); pthread_mutex_lock(&conn->ctx_lock); if (conn->ctx.tpd) @@ -1144,7 +1168,6 @@ static void l2tp_conn_close(struct triton_context_t *ctx) log_tunnel(log_info1, conn, "context thread is closing," " disconnecting tunnel\n"); l2tp_tunnel_disconnect(conn, 0, 0); - l2tp_tunnel_free(conn); } static int l2tp_tunnel_start(struct l2tp_conn_t *conn, @@ -1702,7 +1725,6 @@ static void l2tp_tunnel_timeout(struct triton_timer_t *t) log_tunnel(log_info1, conn, "tunnel establishment timeout," " disconnecting tunnel\n"); l2tp_tunnel_disconnect(conn, 1, 0); - l2tp_tunnel_free(conn); } static int l2tp_tunnel_send(struct l2tp_conn_t *conn, |