summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2014-04-08 22:53:42 +0200
committerDmitry Kozlov <xeb@mail.ru>2014-04-11 06:47:26 +0400
commit250167afcf5918d8bd310cd887a0f554eac9e8b1 (patch)
tree6e032df9f436537eedf194fc12a84f028455497d
parent3448534c7fc579793840af199ae97f8184e99aa1 (diff)
downloadaccel-ppp-xebd-250167afcf5918d8bd310cd887a0f554eac9e8b1.tar.gz
accel-ppp-xebd-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>
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c56
1 files changed, 39 insertions, 17 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index e6ec075..b337e00 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,