diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2004-12-26 22:13:06 -0800 |
---|---|---|
committer | Sridhar Samudrala <sri@us.ibm.com> | 2004-12-26 22:13:06 -0800 |
commit | 5aabd1fe268e850c2e93048a5ccc5eb6970ac49c (patch) | |
tree | ecb5821b020c382727a298fc4c9880f53ac189f2 /net | |
parent | 3da25caccc4e293aada9c1f7130a98be64907c77 (diff) | |
download | history-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.c | 3 | ||||
-rw-r--r-- | net/sctp/input.c | 33 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 6 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 42 | ||||
-rw-r--r-- | net/sctp/sm_statetable.c | 23 |
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 { \ |