summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2013-03-15 21:47:59 +0100
committerKozlov Dmitry <xeb@mail.ru>2013-03-16 08:34:46 +0400
commitf7d4b0ba1c00c6e56af8e8b3ca64b09fb06f5ba7 (patch)
treee0c753e94e4fe2e22d16ba875f51c2c9a8118656 /accel-pppd
parent47d51c689d2e80f09b0815d0905e15e4d16ae0bb (diff)
downloadaccel-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.c30
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;