diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2013-03-15 21:47:59 +0100 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2013-03-16 08:34:46 +0400 |
commit | f7d4b0ba1c00c6e56af8e8b3ca64b09fb06f5ba7 (patch) | |
tree | e0c753e94e4fe2e22d16ba875f51c2c9a8118656 /accel-pppd | |
parent | 47d51c689d2e80f09b0815d0905e15e4d16ae0bb (diff) | |
download | accel-ppp-f7d4b0ba1c00c6e56af8e8b3ca64b09fb06f5ba7.tar.gz accel-ppp-f7d4b0ba1c00c6e56af8e8b3ca64b09fb06f5ba7.zip |
l2tp: Fix early message sending during tunnel establishment
A side effect of setting peer port to zero when sending SCCRQ messages
is that the tunnel can't send any new message before receiving first
peer's answer (this doesn't apply to retransmissions as peer port is
set in the original packet). It is then impossible to send StopCCN
messages within this time frame.
This patch fixes this issue using a new tunnel flag which indicates if
tunnel's peer port has a default value or if it has been set after
reception of peer's first message.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index 00b2f0f1..d1b0831c 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -100,6 +100,7 @@ struct l2tp_conn_t uint16_t peer_tid; uint32_t framing_cap; uint16_t lns_mode:1; + uint16_t port_set:1; uint16_t challenge_len; uint8_t *challenge; @@ -991,7 +992,7 @@ err: static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, const struct sockaddr_in *host, uint32_t framing_cap, - int lns_mode) + int lns_mode, int port_set) { struct l2tp_conn_t *conn; socklen_t hostaddrlen = sizeof(conn->host_addr); @@ -1044,11 +1045,19 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, goto out_err; } - if (connect(conn->hnd.fd, (struct sockaddr *)peer, sizeof(*peer))) { + memcpy(&conn->peer_addr, peer, sizeof(*peer)); + if (!port_set) + /* 'peer.sin_port' is set to a default destination port but the + source port that will be used by the peer isn't known yet */ + conn->peer_addr.sin_port = 0; + if (connect(conn->hnd.fd, (struct sockaddr *)&conn->peer_addr, + sizeof(conn->peer_addr))) { log_error("l2tp: impossible to allocate new tunnel:" " connect() failed: %s\n", strerror(errno)); goto out_err; } + if (!port_set) + conn->peer_addr.sin_port = peer->sin_port; flag = fcntl(conn->hnd.fd, F_GETFL); if (flag < 0) { @@ -1094,7 +1103,6 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, goto out_err; } - memcpy(&conn->peer_addr, peer, sizeof(*peer)); conn->framing_cap = framing_cap; conn->ctx.before_switch = log_switch; @@ -1112,6 +1120,7 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, conn->sessions = NULL; conn->sess_count = 0; conn->lns_mode = lns_mode; + conn->port_set = port_set; return conn; @@ -1494,13 +1503,6 @@ static void l2tp_send_SCCRQ(void *peer_addr) goto pack_err; } - /* Peer may reply with arbitrary source port */ - if (l2tp_tunnel_update_peerport(conn, 0) < 0) { - log_tunnel(log_error, conn, "impossible to send SCCRQ:" - " resetting peer port failed\n"); - goto err; - } - if (l2tp_tunnel_send(conn, pack) < 0) { log_tunnel(log_error, conn, "impossible to send SCCRQ:" " sending packet failed\n"); @@ -1937,7 +1939,7 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv, host_addr.sin_port = 0; conn = l2tp_tunnel_alloc(&pack->addr, &host_addr, - framing_cap->val.uint32, 1); + framing_cap->val.uint32, 1, 1); if (conn == NULL) { log_error("l2tp: impossible to handle SCCRQ from %s:" " tunnel allocation failed\n", src_addr); @@ -1958,6 +1960,7 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv, } conn->peer_tid = assigned_tid->val.uint16; + conn->port_set = 1; conn->Nr = 1; if (l2tp_tunnel_start(conn, (triton_event_func)l2tp_send_SCCRP, conn) < 0) { @@ -2919,7 +2922,7 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) if (!pack) continue; - if (conn->peer_addr.sin_port == 0) { + if (conn->port_set == 0) { /* Get peer's first reply source port and use it as destination port for further outgoing messages */ res = l2tp_tunnel_update_peerport(conn, @@ -2930,6 +2933,7 @@ static int l2tp_conn_read(struct triton_md_handler_t *h) " closing tunnel\n"); goto drop; } + conn->port_set = 1; } if (ntohs(pack->hdr.tid) != conn->tid && (pack->hdr.tid || !conf_dir300_quirk)) { @@ -3362,7 +3366,7 @@ static int l2tp_create_tunnel_exec(const char *cmd, char * const *fields, return CLI_CMD_INVAL; } - conn = l2tp_tunnel_alloc(&peer, &host, 3, lns_mode); + conn = l2tp_tunnel_alloc(&peer, &host, 3, lns_mode, 0); if (conn == NULL) { cli_send(client, "tunnel allocation failed\r\n"); return CLI_CMD_FAILED; |