summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2008-09-18 16:28:27 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-08 20:23:09 -0700
commitce8fd8b97b424c7abb5123640e05bd0f3d292131 (patch)
treed66d7196c139540831d790dcee20bc53d19836de
parent43562861a5c17416151964c9a6c09a38fdda00a7 (diff)
sctp: Fix oops when INIT-ACK indicates that peer doesn't support AUTH
[ Upstream commit add52379dde2e5300e2d574b172e62c6cf43b3d3 ] If INIT-ACK is received with SupportedExtensions parameter which indicates that the peer does not support AUTH, the packet will be silently ignore, and sctp_process_init() do cleanup all of the transports in the association. When T1-Init timer is expires, OOPS happen while we try to choose a different init transport. The solution is to only clean up the non-active transports, i.e the ones that the peer added. However, that introduces a problem with sctp_connectx(), because we don't mark the proper state for the transports provided by the user. So, we'll simply mark user-provided transports as ACTIVE. That will allow INIT retransmissions to work properly in the sctp_connectx() context and prevent the crash. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--net/sctp/associola.c9
-rw-r--r--net/sctp/sm_make_chunk.c6
2 files changed, 7 insertions, 8 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 024c3ebd9661..31ca4f4007bb 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -597,11 +597,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr);
if (peer) {
+ /* An UNKNOWN state is only set on transports added by
+ * user in sctp_connectx() call. Such transports should be
+ * considered CONFIRMED per RFC 4960, Section 5.4.
+ */
if (peer->state == SCTP_UNKNOWN) {
- if (peer_state == SCTP_ACTIVE)
- peer->state = SCTP_ACTIVE;
- if (peer_state == SCTP_UNCONFIRMED)
- peer->state = SCTP_UNCONFIRMED;
+ peer->state = SCTP_ACTIVE;
}
return peer;
}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index cb590d1b774c..650f75926ca3 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2321,12 +2321,10 @@ clean_up:
/* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports);
- list_del_init(pos);
- sctp_transport_free(transport);
+ if (transport->state != SCTP_ACTIVE)
+ sctp_assoc_rm_peer(asoc, transport);
}
- asoc->peer.transport_count = 0;
-
nomem:
return 0;
}