| From foo@baz Sun Oct 12 17:18:11 CEST 2014 |
| From: Vlad Yasevich <vyasevich@gmail.com> |
| Date: Fri, 3 Oct 2014 18:16:20 -0400 |
| Subject: sctp: handle association restarts when the socket is closed. |
| |
| From: Vlad Yasevich <vyasevich@gmail.com> |
| |
| [ Upstream commit bdf6fa52f01b941d4a80372d56de465bdbbd1d23 ] |
| |
| Currently association restarts do not take into consideration the |
| state of the socket. When a restart happens, the current assocation |
| simply transitions into established state. This creates a condition |
| where a remote system, through a the restart procedure, may create a |
| local association that is no way reachable by user. The conditions |
| to trigger this are as follows: |
| 1) Remote does not acknoledge some data causing data to remain |
| outstanding. |
| 2) Local application calls close() on the socket. Since data |
| is still outstanding, the association is placed in SHUTDOWN_PENDING |
| state. However, the socket is closed. |
| 3) The remote tries to create a new association, triggering a restart |
| on the local system. The association moves from SHUTDOWN_PENDING |
| to ESTABLISHED. At this point, it is no longer reachable by |
| any socket on the local system. |
| |
| This patch addresses the above situation by moving the newly ESTABLISHED |
| association into SHUTDOWN-SENT state and bundling a SHUTDOWN after |
| the COOKIE-ACK chunk. This way, the restarted associate immidiately |
| enters the shutdown procedure and forces the termination of the |
| unreachable association. |
| |
| Reported-by: David Laight <David.Laight@aculab.com> |
| Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/net/sctp/command.h | 2 +- |
| net/sctp/sm_statefuns.c | 19 ++++++++++++++++--- |
| 2 files changed, 17 insertions(+), 4 deletions(-) |
| |
| --- a/include/net/sctp/command.h |
| +++ b/include/net/sctp/command.h |
| @@ -115,7 +115,7 @@ typedef enum { |
| * analysis of the state functions, but in reality just taken from |
| * thin air in the hopes othat we don't trigger a kernel panic. |
| */ |
| -#define SCTP_MAX_NUM_COMMANDS 14 |
| +#define SCTP_MAX_NUM_COMMANDS 20 |
| |
| typedef union { |
| void *zero_all; /* Set to NULL to clear the entire union */ |
| --- a/net/sctp/sm_statefuns.c |
| +++ b/net/sctp/sm_statefuns.c |
| @@ -1775,9 +1775,22 @@ static sctp_disposition_t sctp_sf_do_dup |
| /* 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_NEW_STATE, |
| - SCTP_STATE(SCTP_STATE_ESTABLISHED)); |
| - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
| + if (sctp_state(asoc, SHUTDOWN_PENDING) && |
| + (sctp_sstate(asoc->base.sk, CLOSING) || |
| + sock_flag(asoc->base.sk, SOCK_DEAD))) { |
| + /* if were currently in SHUTDOWN_PENDING, but the socket |
| + * has been closed by user, don't transition to ESTABLISHED. |
| + * Instead trigger SHUTDOWN bundled with COOKIE_ACK. |
| + */ |
| + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
| + return sctp_sf_do_9_2_start_shutdown(net, ep, asoc, |
| + SCTP_ST_CHUNK(0), NULL, |
| + commands); |
| + } else { |
| + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
| + SCTP_STATE(SCTP_STATE_ESTABLISHED)); |
| + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
| + } |
| return SCTP_DISPOSITION_CONSUME; |
| |
| nomem_ev: |