diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2012-09-07 12:34:38 +0200 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-09-07 14:49:18 +0400 |
commit | a7d5a6af9d089165b74435527b99fc01947c3827 (patch) | |
tree | fca5951af567030b1e385fbf682e74cf71078e8a /accel-pppd/ctrl/l2tp/l2tp.c | |
parent | eff719a6d3fd9005a7ee551a0ae53cfa69644de4 (diff) | |
download | accel-ppp-a7d5a6af9d089165b74435527b99fc01947c3827.tar.gz accel-ppp-a7d5a6af9d089165b74435527b99fc01947c3827.zip |
L2TP: Terminate sessions without closing tunnel
Implement CDN message sending in order to give the possibility
to close a session without closing the underlying tunnel (close
a tunnel only when closing its last session, which is always the
case as long as session-multiplexing is not implemented).
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Diffstat (limited to 'accel-pppd/ctrl/l2tp/l2tp.c')
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index c4ff01be..8ebed1d0 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -119,6 +119,32 @@ static void l2tp_send_SCCRP(struct l2tp_conn_t *conn); static int l2tp_send(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack, int log_debug); static int l2tp_conn_read(struct triton_md_handler_t *); +static int l2tp_send_CDN(struct l2tp_conn_t *conn, uint16_t res, uint16_t err) +{ + struct l2tp_packet_t *pack = NULL; + struct l2tp_avp_result_code rc = {res, err}; + + pack = l2tp_packet_alloc(2, Message_Type_Call_Disconnect_Notify, + &conn->lac_addr); + if (pack == NULL) + goto out_err; + if (l2tp_packet_add_int16(pack, Assigned_Session_ID, + conn->sess.sid, 1) < 0) + goto out_err; + if (l2tp_packet_add_octets(pack, Result_Code, (uint8_t *)&rc, + sizeof(rc), 1) < 0) + goto out_err; + + pack->hdr.sid = htons(conn->sess.peer_sid); + + return l2tp_send(conn, pack, 0); + +out_err: + if (pack) + l2tp_packet_free(pack); + return -1; +} + static void l2tp_session_free(struct l2tp_conn_t *conn) { switch (conn->sess.state1) { @@ -222,6 +248,17 @@ out_err: return -1; } +static int l2tp_session_disconnect(struct l2tp_conn_t *conn, + uint16_t res, uint16_t err) +{ + if (l2tp_send_CDN(conn, res, err) < 0) + return -1; + l2tp_session_free(conn); + + /* Free the tunnel when all sessions have been closed */ + return l2tp_terminate(conn, 1, 0); +} + static void l2tp_ppp_started(struct ap_session *ses) { struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); @@ -881,7 +918,7 @@ 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_terminate(conn, 2, 8)) + if (l2tp_session_disconnect(conn, 2, 8) < 0) return -1; return 0; } @@ -892,7 +929,7 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) if (!assigned_sid) { if (conf_verbose) log_ppp_warn("l2tp: ICRQ: no Assigned-Session-ID attribute present in message\n"); - if (l2tp_terminate(conn, 2, 0)) + if (l2tp_session_disconnect(conn, 0, 0) < 0) return -1; } @@ -917,7 +954,7 @@ static int l2tp_recv_ICCN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) conn->sess.state1 = STATE_ESTB; if (l2tp_session_connect(conn)) { - if (l2tp_terminate(conn, 2, 0)) + if (l2tp_session_disconnect(conn, 2, 4) < 0) return -1; return 0; } @@ -963,10 +1000,9 @@ static int l2tp_recv_CDN(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) } l2tp_session_free(conn); - if (l2tp_terminate(conn, 0, 0)) - return -1; - - return 0; + + /* Free the tunnel when all sessions have been closed */ + return l2tp_terminate(conn, 1, 0); } static int l2tp_recv_SLI(struct l2tp_conn_t *conn, struct l2tp_packet_t *pack) |