[SCTP] Treat ICMP protocol unreachable errors from non-SCTP capable hosts as

Linux Kernel Mailing List <[email protected]>
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1530.1.13, 2004/12/27 14:15:44-08:00, [email protected]

	[SCTP] Treat ICMP protocol unreachable errors from non-SCTP capable hosts as
	ABORTs.
	
	Signed-off-by: Jerome Forissier <[email protected]>
	Signed-off-by: Sridhar Samudrala <[email protected]>



 include/net/sctp/constants.h |    3 ++-
 include/net/sctp/sctp.h      |    4 ++++
 include/net/sctp/sm.h        |    3 +++
 net/sctp/debug.c             |    3 ++-
 net/sctp/input.c             |   33 ++++++++++++++++++++++++++++++++-
 net/sctp/ipv6.c              |    6 ++++++
 net/sctp/sm_statefuns.c      |   41 +++++++++++++++++++++++++++++++----------
 net/sctp/sm_statetable.c     |   23 +++++++++++++++++++++++
 8 files changed, 103 insertions(+), 13 deletions(-)


diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h
--- a/include/net/sctp/constants.h	2005-01-15 07:05:16 -08:00
+++ b/include/net/sctp/constants.h	2005-01-15 07:05:16 -08:00
@@ -105,9 +105,10 @@
 
 typedef enum {
 	SCTP_EVENT_NO_PENDING_TSN = 0,
+	SCTP_EVENT_ICMP_PROTO_UNREACH,
 } sctp_event_other_t;
 
-#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_NO_PENDING_TSN
+#define SCTP_EVENT_OTHER_MAX		SCTP_EVENT_ICMP_PROTO_UNREACH
 #define SCTP_NUM_OTHER_TYPES		(SCTP_EVENT_OTHER_MAX + 1)
 
 /* These are primitive requests from the ULP.  */
diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
--- a/include/net/sctp/sctp.h	2005-01-15 07:05:16 -08:00
+++ b/include/net/sctp/sctp.h	2005-01-15 07:05:16 -08:00
@@ -177,6 +177,10 @@
 			    struct sctp_association *);
 void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
 			   struct sctp_transport *t, __u32 pmtu);
+void sctp_icmp_proto_unreachable(struct sock *sk,
+				 struct sctp_endpoint *ep,
+				 struct sctp_association *asoc,
+				 struct sctp_transport *t);
 
 /*
  *  Section:  Macros, externs, and inlines
diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h
--- a/include/net/sctp/sm.h	2005-01-15 07:05:16 -08:00
+++ b/include/net/sctp/sm.h	2005-01-15 07:05:16 -08:00
@@ -165,6 +165,7 @@
 sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
 sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack;
 sctp_state_fn_t sctp_sf_ignore_other;
+sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
 
 /* Prototypes for timeout event state functions.  */
 sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
@@ -251,6 +252,8 @@
 
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
+
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error);
 
 /* Prototypes for statetable processing. */
 
diff -Nru a/net/sctp/debug.c b/net/sctp/debug.c
--- a/net/sctp/debug.c	2005-01-15 07:05:16 -08:00
+++ b/net/sctp/debug.c	2005-01-15 07:05:16 -08:00
@@ -154,6 +154,7 @@
 
 static const char *sctp_other_tbl[] = {
 	"NO_PENDING_TSN",
+        "ICMP_PROTO_UNREACH",
 };
 
 /* Lookup "other" debug name. */
@@ -161,7 +162,7 @@
 {
 	if (id.other < 0)
 		return "illegal 'other' event";
-	if (id.other < SCTP_EVENT_OTHER_MAX)
+	if (id.other <= SCTP_EVENT_OTHER_MAX)
 		return sctp_other_tbl[id.other];
 	return "unknown 'other' event";
 }
diff -Nru a/net/sctp/input.c b/net/sctp/input.c
--- a/net/sctp/input.c	2005-01-15 07:05:16 -08:00
+++ b/net/sctp/input.c	2005-01-15 07:05:16 -08:00
@@ -282,6 +282,31 @@
 	}
 }
 
+/*
+ * SCTP Implementer's Guide, 2.37 ICMP handling procedures
+ *
+ * ICMP8) If the ICMP code is a "Unrecognized next header type encountered"
+ *        or a "Protocol Unreachable" treat this message as an abort
+ *        with the T bit set.
+ *
+ * This function sends an event to the state machine, which will abort the
+ * association.
+ *
+ */
+void sctp_icmp_proto_unreachable(struct sock *sk,
+                           struct sctp_endpoint *ep,
+                           struct sctp_association *asoc,
+                           struct sctp_transport *t)
+{
+	SCTP_DEBUG_PRINTK("%s\n",  __FUNCTION__);
+
+	sctp_do_sm(SCTP_EVENT_T_OTHER,
+		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
+		   asoc->state, asoc->ep, asoc, NULL,
+		   GFP_ATOMIC);
+
+}
+
 /* Common lookup code for icmp/icmpv6 error handler. */
 struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
 			     struct sctphdr *sctphdr,
@@ -431,7 +456,13 @@
 			sctp_icmp_frag_needed(sk, asoc, transport, info);
 			goto out_unlock;
 		}
-
+		else {
+			if (ICMP_PROT_UNREACH == code) {
+				sctp_icmp_proto_unreachable(sk, ep, asoc,
+							    transport);
+				goto out_unlock;
+			}
+		}
 		err = icmp_err_convert[code].errno;
 		break;
 	case ICMP_TIME_EXCEEDED:
diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c
--- a/net/sctp/ipv6.c	2005-01-15 07:05:16 -08:00
+++ b/net/sctp/ipv6.c	2005-01-15 07:05:16 -08:00
@@ -133,6 +133,12 @@
 	case ICMPV6_PKT_TOOBIG:
 		sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
 		goto out_unlock;
+	case ICMPV6_PARAMPROB:
+		if (ICMPV6_UNK_NEXTHDR == code) {
+			sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
+			goto out_unlock;
+		}
+		break;
 	default:
 		break;
 	}
diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
--- a/net/sctp/sm_statefuns.c	2005-01-15 07:05:16 -08:00
+++ b/net/sctp/sm_statefuns.c	2005-01-15 07:05:16 -08:00
@@ -2123,27 +2123,31 @@
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
-	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
-			SCTP_STATE(SCTP_STATE_CLOSED));
-	SCTP_INC_STATS(SctpAborteds);
-	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
-			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
-
 	/* Check that chunk header looks valid.  */
 	len = ntohs(chunk->chunk_hdr->length);
 	if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
 		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-	/* CMD_INIT_FAILED will DELETE_TCB. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
+	sctp_stop_t1_and_abort(commands, error);
 
 	return SCTP_DISPOSITION_ABORT;
 }
 
 /*
+ * Process an incoming ICMP as an ABORT.  (COOKIE-WAIT state)
+ */
+sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
+{
+	sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR);
+	return SCTP_DISPOSITION_ABORT;
+}
+
+/*
  * Process an ABORT.  (COOKIE-ECHOED state)
- *
- * See sctp_sf_do_9_1_abort() above.
  */
 sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
 					       const struct sctp_association *asoc,
@@ -2155,6 +2159,23 @@
 	 * common function with the COOKIE-WAIT state.
 	 */
 	return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
+}
+
+/*
+ * Stop T1 timer and abort association with "INIT failed".
+ *
+ * This is common code called by several sctp_sf_*_abort() functions above.
+ */
+void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error)
+{
+	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+			SCTP_STATE(SCTP_STATE_CLOSED));
+	SCTP_INC_STATS(SctpAborteds);
+	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
+	/* CMD_INIT_FAILED will DELETE_TCB. */
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
+			SCTP_U32(error));
 }
 
 /*
diff -Nru a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
--- a/net/sctp/sm_statetable.c	2005-01-15 07:05:16 -08:00
+++ b/net/sctp/sm_statetable.c	2005-01-15 07:05:16 -08:00
@@ -727,8 +727,31 @@
 	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
 }
 
+#define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH  { \
+	/* SCTP_STATE_EMPTY */ \
+	{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+	/* SCTP_STATE_CLOSED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_COOKIE_WAIT */ \
+	{.fn = sctp_sf_cookie_wait_icmp_abort, \
+	 .name = "sctp_sf_cookie_wait_icmp_abort"}, \
+	/* SCTP_STATE_COOKIE_ECHOED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_ESTABLISHED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_PENDING */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+	/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
+	{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
+}
+
 static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
 	TYPE_SCTP_OTHER_NO_PENDING_TSN,
+	TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH,
 };
 
 #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.