Commit c5fab809 authored by David S. Miller's avatar David S. Miller

Merge branch 'sctp-chunk-fix'

Xin Long says:

====================
sctp: always send a chunk with the asoc that it belongs to

Currently when processing a duplicate COOKIE-ECHO chunk, a new temp
asoc would be created, then it creates the chunks with the new asoc.
However, later on it uses the old asoc to send these chunks, which
has caused quite a few issues.

This patchset is to fix this and make sure that the COOKIE-ACK and
SHUTDOWN chunks are created with the same asoc that will be used to
send them out.

v1->v2:
  - see Patch 3/3.
====================
Acked-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c5197b4e 51eac7f2
...@@ -68,7 +68,6 @@ enum sctp_verb { ...@@ -68,7 +68,6 @@ enum sctp_verb {
SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */
SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */ SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */
SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */
SCTP_CMD_UPDATE_ASSOC, /* Update association information. */
SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */ SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */
......
...@@ -826,28 +826,6 @@ static void sctp_cmd_setup_t2(struct sctp_cmd_seq *cmds, ...@@ -826,28 +826,6 @@ static void sctp_cmd_setup_t2(struct sctp_cmd_seq *cmds,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
} }
static void sctp_cmd_assoc_update(struct sctp_cmd_seq *cmds,
struct sctp_association *asoc,
struct sctp_association *new)
{
struct net *net = asoc->base.net;
struct sctp_chunk *abort;
if (!sctp_assoc_update(asoc, new))
return;
abort = sctp_make_abort(asoc, NULL, sizeof(struct sctp_errhdr));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
sctp_add_cmd_sf(cmds, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
}
sctp_add_cmd_sf(cmds, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNABORTED));
sctp_add_cmd_sf(cmds, SCTP_CMD_ASSOC_FAILED,
SCTP_PERR(SCTP_ERROR_RSRC_LOW));
SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
}
/* Helper function to change the state of an association. */ /* Helper function to change the state of an association. */
static void sctp_cmd_new_state(struct sctp_cmd_seq *cmds, static void sctp_cmd_new_state(struct sctp_cmd_seq *cmds,
struct sctp_association *asoc, struct sctp_association *asoc,
...@@ -1301,10 +1279,6 @@ static int sctp_cmd_interpreter(enum sctp_event_type event_type, ...@@ -1301,10 +1279,6 @@ static int sctp_cmd_interpreter(enum sctp_event_type event_type,
sctp_endpoint_add_asoc(ep, asoc); sctp_endpoint_add_asoc(ep, asoc);
break; break;
case SCTP_CMD_UPDATE_ASSOC:
sctp_cmd_assoc_update(commands, asoc, cmd->obj.asoc);
break;
case SCTP_CMD_PURGE_OUTQUEUE: case SCTP_CMD_PURGE_OUTQUEUE:
sctp_outq_teardown(&asoc->outqueue); sctp_outq_teardown(&asoc->outqueue);
break; break;
......
...@@ -1773,6 +1773,30 @@ enum sctp_disposition sctp_sf_do_5_2_3_initack( ...@@ -1773,6 +1773,30 @@ enum sctp_disposition sctp_sf_do_5_2_3_initack(
return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
} }
static int sctp_sf_do_assoc_update(struct sctp_association *asoc,
struct sctp_association *new,
struct sctp_cmd_seq *cmds)
{
struct net *net = asoc->base.net;
struct sctp_chunk *abort;
if (!sctp_assoc_update(asoc, new))
return 0;
abort = sctp_make_abort(asoc, NULL, sizeof(struct sctp_errhdr));
if (abort) {
sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0);
sctp_add_cmd_sf(cmds, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
}
sctp_add_cmd_sf(cmds, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNABORTED));
sctp_add_cmd_sf(cmds, SCTP_CMD_ASSOC_FAILED,
SCTP_PERR(SCTP_ERROR_RSRC_LOW));
SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
return -ENOMEM;
}
/* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A') /* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
* *
* Section 5.2.4 * Section 5.2.4
...@@ -1852,20 +1876,22 @@ static enum sctp_disposition sctp_sf_do_dupcook_a( ...@@ -1852,20 +1876,22 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_ASCONF_QUEUE, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_ASCONF_QUEUE, SCTP_NULL());
repl = sctp_make_cookie_ack(new_asoc, chunk); /* Update the content of current association. */
if (sctp_sf_do_assoc_update((struct sctp_association *)asoc, new_asoc, commands))
goto nomem;
repl = sctp_make_cookie_ack(asoc, chunk);
if (!repl) if (!repl)
goto nomem; goto nomem;
/* Report association restart to upper layer. */ /* Report association restart to upper layer. */
ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
new_asoc->c.sinit_num_ostreams, asoc->c.sinit_num_ostreams,
new_asoc->c.sinit_max_instreams, asoc->c.sinit_max_instreams,
NULL, GFP_ATOMIC); NULL, GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem_ev; goto nomem_ev;
/* Update the content of current association. */
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
if ((sctp_state(asoc, SHUTDOWN_PENDING) || if ((sctp_state(asoc, SHUTDOWN_PENDING) ||
sctp_state(asoc, SHUTDOWN_SENT)) && sctp_state(asoc, SHUTDOWN_SENT)) &&
...@@ -1877,7 +1903,7 @@ static enum sctp_disposition sctp_sf_do_dupcook_a( ...@@ -1877,7 +1903,7 @@ static enum sctp_disposition sctp_sf_do_dupcook_a(
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
return sctp_sf_do_9_2_start_shutdown(net, ep, asoc, return sctp_sf_do_9_2_start_shutdown(net, ep, asoc,
SCTP_ST_CHUNK(0), repl, SCTP_ST_CHUNK(0), NULL,
commands); commands);
} else { } else {
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
...@@ -1925,14 +1951,16 @@ static enum sctp_disposition sctp_sf_do_dupcook_b( ...@@ -1925,14 +1951,16 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
/* Update the content of current association. */
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_ESTABLISHED)); SCTP_STATE(SCTP_STATE_ESTABLISHED));
SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB); SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
repl = sctp_make_cookie_ack(new_asoc, chunk); /* Update the content of current association. */
if (sctp_sf_do_assoc_update((struct sctp_association *)asoc, new_asoc, commands))
goto nomem;
repl = sctp_make_cookie_ack(asoc, chunk);
if (!repl) if (!repl)
goto nomem; goto nomem;
...@@ -5521,7 +5549,7 @@ enum sctp_disposition sctp_sf_do_9_2_start_shutdown( ...@@ -5521,7 +5549,7 @@ enum sctp_disposition sctp_sf_do_9_2_start_shutdown(
* in the Cumulative TSN Ack field the last sequential TSN it * in the Cumulative TSN Ack field the last sequential TSN it
* has received from the peer. * has received from the peer.
*/ */
reply = sctp_make_shutdown(asoc, arg); reply = sctp_make_shutdown(asoc, NULL);
if (!reply) if (!reply)
goto nomem; goto nomem;
...@@ -6119,7 +6147,7 @@ enum sctp_disposition sctp_sf_autoclose_timer_expire( ...@@ -6119,7 +6147,7 @@ enum sctp_disposition sctp_sf_autoclose_timer_expire(
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outq_is_empty(&asoc->outqueue)) { if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_start_shutdown(net, ep, asoc, type, disposition = sctp_sf_do_9_2_start_shutdown(net, ep, asoc, type,
NULL, commands); arg, commands);
} }
return disposition; return disposition;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment