From 64d3b900de895f2fb38886613ac1710301c2a375 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 7 Sep 2012 12:36:54 +0200 Subject: [PATCH] L2TP: Re-enable per session logs Use a triton context per session so that log_ppp_*() functions can prepend log messages with PPP session information. Since functions must now be called within the right context, allocating and freeing sessions is done in the following manner: * Tunnels allocate new sessions within their own context and activate the new session's context just before answering the ICRQ. * Freeing sessions is slightly more complex. The session is first removed from its tunnel session list (done within the tunnel context), then the session itself if disconnected and freed (done within the session context). The l2tp_tunnel_*() and the l2tp_session_*() functions must now be used within tunnel and session contexts respectively. Signed-off-by: Guillaume Nault --- accel-pppd/ctrl/l2tp/l2tp.c | 214 ++++++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 68 deletions(-) diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index edbdb98..39d7481 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -77,6 +77,7 @@ struct l2tp_sess_t int state1; int state2; + struct triton_context_t sctx; struct triton_timer_t timeout_timer; struct ap_ctrl ctrl; struct ppp_t ppp; @@ -191,6 +192,18 @@ out_err: return -1; } +static int l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, int res, int err) +{ + log_ppp_debug("l2tp: terminate (%i, %i)\n", res, err); + + if (l2tp_send_StopCCN(conn, res, err) < 0) + return -1; + + conn->state = STATE_FIN; + + return 0; +} + static void __l2tp_session_free(void *data) { struct l2tp_sess_t *sess = data; @@ -220,6 +233,8 @@ static void __l2tp_session_free(void *data) log_ppp_info1("disconnected\n"); + triton_context_unregister(&sess->sctx); + if (sess->timeout_timer.tpd) triton_timer_del(&sess->timeout_timer); if (sess->ppp.fd != -1) @@ -234,12 +249,29 @@ static void __l2tp_session_free(void *data) mempool_free(sess); } -static void l2tp_session_free(struct l2tp_sess_t *sess) +static void __l2tp_tunnel_free_session(void *data) { - if (tdelete(sess, &sess->paren_conn->sessions, sess_cmp) == NULL) { - log_warn("ERROR: impossible to delete unexisting session %hu\n", sess->sid); + struct l2tp_sess_t *sess = data; + + triton_context_call(&sess->sctx, __l2tp_session_free, sess); +} + +static void l2tp_tunnel_free_session(void *sess) +{ + struct triton_context_t *ctx = triton_context_self(); + struct l2tp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); + + tdelete(sess, &conn->sessions, sess_cmp); + __l2tp_tunnel_free_session(sess); + if (conn->sessions == NULL) { + l2tp_tunnel_disconnect(conn, 1, 0); } - __l2tp_session_free(sess); +} + +static void l2tp_session_free(struct l2tp_sess_t *sess) +{ + triton_context_call(&sess->paren_conn->ctx, l2tp_tunnel_free_session, + sess); } static void l2tp_tunnel_free(struct l2tp_conn_t *conn) @@ -249,7 +281,7 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) if (conn->state == STATE_CLOSE) return; - tdestroy(conn->sessions, __l2tp_session_free); + tdestroy(conn->sessions, __l2tp_tunnel_free_session); triton_md_unregister_handler(&conn->hnd); close(conn->hnd.fd); @@ -286,18 +318,6 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) mempool_free(conn); } -static int l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, int res, int err) -{ - log_ppp_debug("l2tp: terminate (%i, %i)\n", res, err); - - if (l2tp_send_StopCCN(conn, res, err) < 0) - return -1; - - conn->state = STATE_FIN; - - return 0; -} - static int l2tp_session_disconnect(struct l2tp_sess_t *sess, uint16_t res, uint16_t err) { @@ -305,11 +325,7 @@ static int l2tp_session_disconnect(struct l2tp_sess_t *sess, return -1; l2tp_session_free(sess); - /* Free the tunnel when all sessions have been closed */ - if (sess->paren_conn->sessions == NULL) - return l2tp_tunnel_disconnect(sess->paren_conn, 1, 0); - else - return 0; + return 0; } static void l2tp_ppp_session_disconnect(void *param) @@ -324,12 +340,6 @@ static void l2tp_ppp_session_disconnect(void *param) Now, call __l2tp_session_free() again to finish cleanup. */ __l2tp_session_free(sess); } - - /* Disconnect the tunnel when all sessions have been closed */ - if (sess->paren_conn->sessions == NULL) { - l2tp_tunnel_disconnect(sess->paren_conn, 1, 0); - sess->paren_conn->state = STATE_FIN; - } } static void l2tp_ppp_started(struct ap_session *ses) @@ -343,22 +353,16 @@ static void l2tp_ppp_finished(struct ap_session *ses) struct l2tp_sess_t *sess = container_of(ppp, typeof(*sess), ppp); log_ppp_debug("l2tp: ppp finished\n"); - triton_context_call(&sess->paren_conn->ctx, - l2tp_ppp_session_disconnect, sess); + triton_context_call(&sess->sctx, l2tp_ppp_session_disconnect, sess); } static void l2tp_session_timeout(struct triton_timer_t *t) { struct l2tp_sess_t *sess = container_of(t, typeof(*sess), timeout_timer); + log_ppp_debug("l2tp: session timeout\n"); l2tp_session_free(sess); - - /* Disconnect the tunnel when all sessions have been closed */ - if (sess->paren_conn->sessions == NULL) { - l2tp_tunnel_disconnect(sess->paren_conn, 1, 0); - sess->paren_conn->state = STATE_FIN; - } } static struct l2tp_sess_t *l2tp_tunnel_new_session(struct l2tp_conn_t *conn) @@ -406,7 +410,14 @@ out_err: return NULL; } -static struct l2tp_sess_t *l2tp_session_alloc(struct l2tp_conn_t *conn) +static void l2tp_sess_close(struct triton_context_t *ctx) +{ + struct l2tp_sess_t *sess = container_of(ctx, typeof(*sess), sctx); + + l2tp_session_disconnect(sess, 3, 0); +} + +static struct l2tp_sess_t *l2tp_tunnel_alloc_session(struct l2tp_conn_t *conn) { struct l2tp_sess_t *sess = NULL; @@ -419,7 +430,10 @@ static struct l2tp_sess_t *l2tp_session_alloc(struct l2tp_conn_t *conn) sess->state1 = STATE_CLOSE; sess->state2 = STATE_CLOSE; - sess->ctrl.ctx = &conn->ctx; + sess->sctx.before_switch = log_switch; + sess->sctx.close = l2tp_sess_close; + + sess->ctrl.ctx = &sess->sctx; sess->ctrl.type = CTRL_TYPE_L2TP; sess->ctrl.ppp = 1; sess->ctrl.name = "l2tp"; @@ -441,9 +455,31 @@ static struct l2tp_sess_t *l2tp_session_alloc(struct l2tp_conn_t *conn) sess->ppp.ses.ctrl = &sess->ctrl; sess->ppp.fd = -1; + return sess; +} + +static int l2tp_tunnel_confirm_session(struct l2tp_sess_t *sess) +{ + if (triton_context_register(&sess->sctx, &sess->ppp.ses) < 0) + return -1; + triton_context_wakeup(&sess->sctx); __sync_add_and_fetch(&stat_starting, 1); - return sess; + return 0; +} + +static int l2tp_tunnel_cancel_session(struct l2tp_sess_t *sess, + uint16_t res, uint16_t err) +{ + l2tp_send_CDN(sess, res, err); + tdelete(sess, &sess->paren_conn->sessions, sess_cmp); + if (sess->ctrl.calling_station_id) + _free(sess->ctrl.calling_station_id); + if (sess->ctrl.called_station_id) + _free(sess->ctrl.called_station_id); + mempool_free(sess); + + return 0; } static void l2tp_conn_close(struct triton_context_t *ctx) @@ -1019,13 +1055,15 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) struct l2tp_attr_t *attr; struct l2tp_attr_t *assigned_sid = NULL; struct l2tp_sess_t *sess = NULL; + uint16_t res = 0; + uint16_t err = 0; if (conn->state != STATE_ESTB) { log_ppp_warn("l2tp: unexpected ICRQ\n"); return 0; } - sess = l2tp_session_alloc(conn); + sess = l2tp_tunnel_alloc_session(conn); if (sess == NULL) { log_ppp_warn("l2tp: no more session available\n"); return 0; @@ -1048,30 +1086,40 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) if (attr->M) { if (conf_verbose) { log_ppp_warn("l2tp: ICRQ: unknown attribute %i\n", attr->attr->id); - if (l2tp_session_disconnect(sess, 2, 8) < 0) - return -1; - return 0; } + res = 2; + err = 8; } + break; } } if (!assigned_sid) { if (conf_verbose) log_ppp_warn("l2tp: ICRQ: no Assigned-Session-ID attribute present in message\n"); - if (l2tp_session_disconnect(sess, 0, 0) < 0) - return -1; + res = 0; + err = 0; + goto out_reject; } sess->peer_sid = assigned_sid->val.uint16; + if (err) + goto out_reject; + + if (l2tp_tunnel_confirm_session(sess) < 0) { + res = 2; + err = 4; + goto out_reject; + } if (l2tp_send_ICRP(sess)) return -1; - - /*if (l2tp_send_OCRQ(conn)) - return -1;*/ - + return 0; + +out_reject: + l2tp_tunnel_cancel_session(sess, res, err); + return -1; } static int l2tp_recv_ICCN(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack) @@ -1131,11 +1179,7 @@ static int l2tp_recv_CDN(struct l2tp_sess_t *sess, struct l2tp_packet_t *pack) l2tp_session_free(sess); - /* Free the tunnel when all sessions have been closed */ - if (sess->paren_conn->sessions == NULL) - return l2tp_tunnel_disconnect(sess->paren_conn, 1, 0); - else - return 0; + return 0; } static int l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) @@ -1143,6 +1187,51 @@ static int l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) return 0; } +static void l2tp_session_recv(void *data) +{ + struct triton_context_t *ctx = triton_context_self(); + struct l2tp_sess_t *sess = container_of(ctx, typeof(*sess), sctx); + struct l2tp_packet_t *pack = data; + struct l2tp_attr_t *msg_type = NULL; + + msg_type = list_entry(pack->attrs.next, typeof(*msg_type), entry); + if (msg_type->attr->id != Message_Type) { + if (conf_verbose) + log_ppp_error("l2tp: first attribute is not" + " Message-Type, dropping session...\n"); + l2tp_session_disconnect(sess, 2, 3); + goto out; + } + + switch (msg_type->val.uint16) { + case Message_Type_Incoming_Call_Connected: + l2tp_recv_ICCN(sess, pack); + break; + case Message_Type_Outgoing_Call_Reply: + l2tp_recv_OCRP(sess, pack); + break; + case Message_Type_Outgoing_Call_Connected: + l2tp_recv_OCCN(sess, pack); + break; + case Message_Type_Call_Disconnect_Notify: + l2tp_recv_CDN(sess, pack); + break; + default: + if (conf_verbose) { + log_warn("l2tp: unexpected Message-Type %hu\n", + msg_type->val.uint16); + } + if (msg_type->M) { + l2tp_session_disconnect(sess, 2, 8); + } + break; + } + +out: + l2tp_packet_free(pack); + return; +} + static int l2tp_conn_read(struct triton_md_handler_t *h) { struct l2tp_conn_t *conn = container_of(h, typeof(*conn), hnd); @@ -1239,25 +1328,14 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) goto drop; break; case Message_Type_Incoming_Call_Connected: - sess = l2tp_tunnel_get_session(conn, ntohs(pack->hdr.sid)); - if (sess == NULL || l2tp_recv_ICCN(sess, pack) < 0) - goto drop; - break; case Message_Type_Outgoing_Call_Reply: - sess = l2tp_tunnel_get_session(conn, ntohs(pack->hdr.sid)); - if (sess == NULL || l2tp_recv_OCRP(sess, pack) < 0) - goto drop; - break; case Message_Type_Outgoing_Call_Connected: - sess = l2tp_tunnel_get_session(conn, ntohs(pack->hdr.sid)); - if (sess == NULL || l2tp_recv_OCCN(sess, pack) < 0) - goto drop; - break; case Message_Type_Call_Disconnect_Notify: sess = l2tp_tunnel_get_session(conn, ntohs(pack->hdr.sid)); - if (sess == NULL || l2tp_recv_CDN(sess, pack) < 0) + if (sess == NULL) goto drop; - break; + triton_context_call(&sess->sctx, l2tp_session_recv, pack); + continue; case Message_Type_Set_Link_Info: if (l2tp_recv_SLI(conn, pack)) goto drop; -- GitLab