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 {
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. */
......
......@@ -173,6 +173,10 @@ void sctp_err_finish(struct sock *, struct sctp_endpoint *,
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
......
......@@ -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_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;
......@@ -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_ssn(struct sctp_chunk *);
void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error);
/* Prototypes for statetable processing. */
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)
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";
}
......
......@@ -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:
......
......@@ -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;
}
......
......@@ -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,
......@@ -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);
}
/*
* 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
*
......
......@@ -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 { \
......
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