[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 { \