aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2004-12-26 22:13:06 -0800
committerSridhar Samudrala <sri@us.ibm.com>2004-12-26 22:13:06 -0800
commit5aabd1fe268e850c2e93048a5ccc5eb6970ac49c (patch)
treeecb5821b020c382727a298fc4c9880f53ac189f2 /net
parent3da25caccc4e293aada9c1f7130a98be64907c77 (diff)
downloadhistory-5aabd1fe268e850c2e93048a5ccc5eb6970ac49c.tar.gz
[SCTP] Treat ICMP protocol unreachable errors from non-SCTP capable hosts as
ABORTs. Signed-off-by: Jerome Forissier <jerome.forissier@hp.com> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/debug.c3
-rw-r--r--net/sctp/input.c33
-rw-r--r--net/sctp/ipv6.c6
-rw-r--r--net/sctp/sm_statefuns.c42
-rw-r--r--net/sctp/sm_statetable.c23
5 files changed, 94 insertions, 13 deletions
diff --git a/net/sctp/debug.c b/net/sctp/debug.c
index 449c424eff3a47..aa8340373af7f1 100644
--- a/net/sctp/debug.c
+++ b/net/sctp/debug.c
@@ -154,6 +154,7 @@ const char *sctp_pname(const sctp_subtype_t id)
static const char *sctp_other_tbl[] = {
"NO_PENDING_TSN",
+ "ICMP_PROTO_UNREACH",
};
/* Lookup "other" debug name. */
@@ -161,7 +162,7 @@ const char *sctp_oname(const sctp_subtype_t id)
{
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 --git a/net/sctp/input.c b/net/sctp/input.c
index 72a17b9c703122..79addb5c82bbdb 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -288,6 +288,31 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
}
}
+/*
+ * 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,
@@ -437,7 +462,13 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
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 --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e8864256aa9f21..e1ee4ff71cb13e 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -122,6 +122,12 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
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 --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 9b72a0676af467..348eeeecf72e9e 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -2123,27 +2123,30 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
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(SCTP_MIB_ABORTEDS);
- 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,
@@ -2158,6 +2161,23 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
}
/*
+ * 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(SCTP_MIB_ABORTEDS);
+ 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));
+}
+
+/*
* sctp_sf_do_9_2_shut
*
* Section: 9.2
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index c66dbf5984897d..8967846f69e888 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -727,8 +727,31 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE
{.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 { \