Commit 5aabd1fe authored by Sridhar Samudrala's avatar Sridhar Samudrala

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

ABORTs.
Signed-off-by: default avatarJerome Forissier <jerome.forissier@hp.com>
Signed-off-by: default avatarSridhar Samudrala <sri@us.ibm.com>
parent 3da25cac
...@@ -105,9 +105,10 @@ typedef enum { ...@@ -105,9 +105,10 @@ typedef enum {
typedef enum { typedef enum {
SCTP_EVENT_NO_PENDING_TSN = 0, SCTP_EVENT_NO_PENDING_TSN = 0,
SCTP_EVENT_ICMP_PROTO_UNREACH,
} sctp_event_other_t; } 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) #define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1)
/* These are primitive requests from the ULP. */ /* These are primitive requests from the ULP. */
......
...@@ -173,6 +173,10 @@ void sctp_err_finish(struct sock *, struct sctp_endpoint *, ...@@ -173,6 +173,10 @@ void sctp_err_finish(struct sock *, struct sctp_endpoint *,
struct sctp_association *); struct sctp_association *);
void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
struct sctp_transport *t, __u32 pmtu); 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 * Section: Macros, externs, and inlines
......
...@@ -165,6 +165,7 @@ sctp_state_fn_t sctp_sf_do_prm_asconf; ...@@ -165,6 +165,7 @@ sctp_state_fn_t sctp_sf_do_prm_asconf;
sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; 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_do_9_2_shutdown_ack;
sctp_state_fn_t sctp_sf_ignore_other; sctp_state_fn_t sctp_sf_ignore_other;
sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
/* Prototypes for timeout event state functions. */ /* Prototypes for timeout event state functions. */
sctp_state_fn_t sctp_sf_do_6_3_3_rtx; sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
...@@ -252,6 +253,8 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, ...@@ -252,6 +253,8 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(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. */ /* Prototypes for statetable processing. */
int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
......
...@@ -154,6 +154,7 @@ const char *sctp_pname(const sctp_subtype_t id) ...@@ -154,6 +154,7 @@ const char *sctp_pname(const sctp_subtype_t id)
static const char *sctp_other_tbl[] = { static const char *sctp_other_tbl[] = {
"NO_PENDING_TSN", "NO_PENDING_TSN",
"ICMP_PROTO_UNREACH",
}; };
/* Lookup "other" debug name. */ /* Lookup "other" debug name. */
...@@ -161,7 +162,7 @@ const char *sctp_oname(const sctp_subtype_t id) ...@@ -161,7 +162,7 @@ const char *sctp_oname(const sctp_subtype_t id)
{ {
if (id.other < 0) if (id.other < 0)
return "illegal 'other' event"; 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 sctp_other_tbl[id.other];
return "unknown 'other' event"; return "unknown 'other' event";
} }
......
...@@ -288,6 +288,31 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, ...@@ -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. */ /* Common lookup code for icmp/icmpv6 error handler. */
struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
struct sctphdr *sctphdr, struct sctphdr *sctphdr,
...@@ -437,7 +462,13 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -437,7 +462,13 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
sctp_icmp_frag_needed(sk, asoc, transport, info); sctp_icmp_frag_needed(sk, asoc, transport, info);
goto out_unlock; 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; err = icmp_err_convert[code].errno;
break; break;
case ICMP_TIME_EXCEEDED: case ICMP_TIME_EXCEEDED:
......
...@@ -122,6 +122,12 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -122,6 +122,12 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
case ICMPV6_PKT_TOOBIG: case ICMPV6_PKT_TOOBIG:
sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info)); sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
goto out_unlock; goto out_unlock;
case ICMPV6_PARAMPROB:
if (ICMPV6_UNK_NEXTHDR == code) {
sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
goto out_unlock;
}
break;
default: default:
break; break;
} }
......
...@@ -2123,27 +2123,30 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, ...@@ -2123,27 +2123,30 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify_either(chunk, asoc)) if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); 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. */ /* Check that chunk header looks valid. */
len = ntohs(chunk->chunk_hdr->length); len = ntohs(chunk->chunk_hdr->length);
if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause; error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
/* CMD_INIT_FAILED will DELETE_TCB. */ sctp_stop_t1_and_abort(commands, error);
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
return SCTP_DISPOSITION_ABORT; 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) * 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, sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
...@@ -2157,6 +2160,23 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep, ...@@ -2157,6 +2160,23 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands); 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(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 * sctp_sf_do_9_2_shut
* *
......
...@@ -727,8 +727,31 @@ static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPE ...@@ -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"}, \ {.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] = { 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_NO_PENDING_TSN,
TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH,
}; };
#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment