Cleanup the handling of error causes for ERROR chunks. This fixes

an inconsistency of the padding handling. The final padding is
now considered to be a chunk padding.

MFC after:	1 week
This commit is contained in:
Michael Tuexen 2015-09-12 17:08:51 +00:00
parent 8fbc5d1840
commit 86eda749af
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=287717
5 changed files with 82 additions and 156 deletions

View File

@ -388,33 +388,32 @@ struct sctp_error_cause {
} SCTP_PACKED;
struct sctp_error_invalid_stream {
struct sctp_error_cause cause; /* code=SCTP_ERROR_INVALID_STREAM */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_INVALID_STREAM */
uint16_t stream_id; /* stream id of the DATA in error */
uint16_t reserved;
} SCTP_PACKED;
struct sctp_error_missing_param {
struct sctp_error_cause cause; /* code=SCTP_ERROR_MISSING_PARAM */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_MISSING_PARAM */
uint32_t num_missing_params; /* number of missing parameters */
/* uint16_t param_type's follow */
uint16_t type[];
} SCTP_PACKED;
struct sctp_error_stale_cookie {
struct sctp_error_cause cause; /* code=SCTP_ERROR_STALE_COOKIE */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_STALE_COOKIE */
uint32_t stale_time; /* time in usec of staleness */
} SCTP_PACKED;
struct sctp_error_out_of_resource {
struct sctp_error_cause cause; /* code=SCTP_ERROR_OUT_OF_RESOURCES */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_OUT_OF_RESOURCES */
} SCTP_PACKED;
struct sctp_error_unresolv_addr {
struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRESOLVABLE_ADDR */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRESOLVABLE_ADDR */
} SCTP_PACKED;
struct sctp_error_unrecognized_chunk {
struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRECOG_CHUNK */
struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRECOG_CHUNK */
struct sctp_chunkhdr ch;/* header from chunk in error */
} SCTP_PACKED;
@ -423,6 +422,11 @@ struct sctp_error_no_user_data {
uint32_t tsn; /* TSN of the empty data chunk */
} SCTP_PACKED;
struct sctp_error_auth_invalid_hmac {
struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNSUPPORTED_HMACID */
uint16_t hmac_id;
} SCTP_PACKED;
/*
* Main SCTP chunk types we place these here so natd and f/w's in user land
* can find them.

View File

@ -1651,8 +1651,8 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
/* is the indicated HMAC supported? */
if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) {
struct mbuf *m_err;
struct sctp_auth_invalid_hmac *err;
struct mbuf *op_err;
struct sctp_error_auth_invalid_hmac *cause;
SCTP_STAT_INCR(sctps_recvivalhmacid);
SCTPDBG(SCTP_DEBUG_AUTH1,
@ -1662,20 +1662,19 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
* report this in an Error Chunk: Unsupported HMAC
* Identifier
*/
m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT,
1, MT_HEADER);
if (m_err != NULL) {
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_auth_invalid_hmac),
0, M_NOWAIT, 1, MT_HEADER);
if (op_err != NULL) {
/* pre-reserve some space */
SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
/* fill in the error */
err = mtod(m_err, struct sctp_auth_invalid_hmac *);
bzero(err, sizeof(*err));
err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
err->ph.param_length = htons(sizeof(*err));
err->hmac_id = ntohs(hmac_id);
SCTP_BUF_LEN(m_err) = sizeof(*err);
cause = mtod(op_err, struct sctp_error_auth_invalid_hmac *);
cause->cause.code = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
cause->cause.length = htons(sizeof(struct sctp_error_auth_invalid_hmac));
cause->hmac_id = ntohs(hmac_id);
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_auth_invalid_hmac);
/* queue it */
sctp_queue_op_err(stcb, m_err);
sctp_queue_op_err(stcb, op_err);
}
return (-1);
}

View File

@ -202,34 +202,6 @@ struct sctp_state_cookie { /* this is our definition... */
*/
} SCTP_PACKED;
/* Used for NAT state error cause */
struct sctp_missing_nat_state {
uint16_t cause;
uint16_t length;
uint8_t data[];
} SCTP_PACKED;
struct sctp_inv_mandatory_param {
uint16_t cause;
uint16_t length;
uint32_t num_param;
uint16_t param;
/*
* We include this to 0 it since only a missing cookie will cause
* this error.
*/
uint16_t resv;
} SCTP_PACKED;
struct sctp_unresolv_addr {
uint16_t cause;
uint16_t length;
uint16_t addr_type;
uint16_t reserved; /* Only one invalid addr type */
} SCTP_PACKED;
/* state cookie parameter */
struct sctp_state_cookie_param {
struct sctp_paramhdr ph;
@ -370,28 +342,11 @@ struct sctp_shutdown_complete_chunk {
struct sctp_chunkhdr ch;
} SCTP_PACKED;
/* Oper error holding a stale cookie */
struct sctp_stale_cookie_msg {
struct sctp_paramhdr ph;/* really an error cause */
uint32_t time_usec;
} SCTP_PACKED;
struct sctp_adaptation_layer_indication {
struct sctp_paramhdr ph;
uint32_t indication;
} SCTP_PACKED;
struct sctp_cookie_while_shutting_down {
struct sctphdr sh;
struct sctp_chunkhdr ch;
struct sctp_paramhdr ph;/* really an error cause */
} SCTP_PACKED;
struct sctp_shutdown_complete_msg {
struct sctphdr sh;
struct sctp_shutdown_complete_chunk shut_cmp;
} SCTP_PACKED;
/*
* draft-ietf-tsvwg-addip-sctp
*/
@ -554,12 +509,6 @@ struct sctp_auth_chunk {
uint8_t hmac[];
} SCTP_PACKED;
struct sctp_auth_invalid_hmac {
struct sctp_paramhdr ph;
uint16_t hmac_id;
uint16_t padding;
} SCTP_PACKED;
/*
* we pre-reserve enough room for a ECNE or CWR AND a SACK with no missing
* pieces. If ENCE is missing we could have a couple of blocks. This way we

View File

@ -1426,30 +1426,25 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
strmno = ntohs(ch->dp.stream_id);
if (strmno >= asoc->streamincnt) {
struct sctp_paramhdr *phdr;
struct mbuf *mb;
struct sctp_error_invalid_stream *cause;
mb = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) * 2),
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
0, M_NOWAIT, 1, MT_DATA);
if (mb != NULL) {
if (op_err != NULL) {
/* add some space up front so prepend will work well */
SCTP_BUF_RESV_UF(mb, sizeof(struct sctp_chunkhdr));
phdr = mtod(mb, struct sctp_paramhdr *);
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
cause = mtod(op_err, struct sctp_error_invalid_stream *);
/*
* Error causes are just param's and this one has
* two back to back phdr, one with the error type
* and size, the other with the streamid and a rsvd
*/
SCTP_BUF_LEN(mb) = (sizeof(struct sctp_paramhdr) * 2);
phdr->param_type = htons(SCTP_CAUSE_INVALID_STREAM);
phdr->param_length =
htons(sizeof(struct sctp_paramhdr) * 2);
phdr++;
/* We insert the stream in the type field */
phdr->param_type = ch->dp.stream_id;
/* And set the length to 0 for the rsvd field */
phdr->param_length = 0;
sctp_queue_op_err(stcb, mb);
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
cause->stream_id = ch->dp.stream_id;
cause->reserved = htons(0);
sctp_queue_op_err(stcb, op_err);
}
SCTP_STAT_INCR(sctps_badsid);
SCTP_TCB_LOCK_ASSERT(stcb);
@ -2492,30 +2487,21 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
/* unknown chunk type, use bit rules */
if (ch->ch.chunk_type & 0x40) {
/* Add a error report to the queue */
struct mbuf *merr;
struct sctp_paramhdr *phd;
struct mbuf *op_err;
struct sctp_gen_error_cause *cause;
merr = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_NOWAIT, 1, MT_DATA);
if (merr) {
phd = mtod(merr, struct sctp_paramhdr *);
/*
* We cheat and use param
* type since we did not
* bother to define a error
* cause struct. They are
* the same basic format
* with different names.
*/
phd->param_type =
htons(SCTP_CAUSE_UNRECOG_CHUNK);
phd->param_length =
htons(chk_length + sizeof(*phd));
SCTP_BUF_LEN(merr) = sizeof(*phd);
SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
if (SCTP_BUF_NEXT(merr)) {
sctp_queue_op_err(stcb, merr);
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
0, M_NOWAIT, 1, MT_DATA);
if (op_err != NULL) {
cause = mtod(op_err, struct sctp_gen_error_cause *);
cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
cause->length = htons(chk_length + sizeof(struct sctp_gen_error_cause));
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
if (SCTP_BUF_NEXT(op_err) != NULL) {
sctp_queue_op_err(stcb, op_err);
} else {
sctp_m_freem(merr);
sctp_m_freem(op_err);
}
}
}

View File

@ -530,25 +530,21 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
* abandon the peer, its broke.
*/
if (retval == -3) {
/* We abort with an error of missing mandatory param */
op_err = sctp_generate_cause(SCTP_CAUSE_MISSING_PARAM, "");
if (op_err) {
/*
* Expand beyond to include the mandatory
* param cookie
*/
struct sctp_inv_mandatory_param *mp;
size_t len;
SCTP_BUF_LEN(op_err) =
sizeof(struct sctp_inv_mandatory_param);
mp = mtod(op_err,
struct sctp_inv_mandatory_param *);
len = sizeof(struct sctp_error_missing_param) + sizeof(uint16_t);
/* We abort with an error of missing mandatory param */
op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
if (op_err != NULL) {
struct sctp_error_missing_param *cause;
SCTP_BUF_LEN(op_err) = len;
cause = mtod(op_err, struct sctp_error_missing_param *);
/* Subtract the reserved param */
mp->length =
htons(sizeof(struct sctp_inv_mandatory_param) - 2);
mp->num_param = htonl(1);
mp->param = htons(SCTP_STATE_COOKIE);
mp->resv = 0;
cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM);
cause->cause.length = htons(len);
cause->num_missing_params = htonl(1);
cause->type[0] = htons(SCTP_STATE_COOKIE);
}
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
@ -781,10 +777,10 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
* Need to check the cause codes for our two magic nat
* aborts which don't kill the assoc necessarily.
*/
struct sctp_missing_nat_state *natc;
struct sctp_gen_error_cause *cause;
natc = (struct sctp_missing_nat_state *)(abort + 1);
error = ntohs(natc->cause);
cause = (struct sctp_gen_error_cause *)(abort + 1);
error = ntohs(cause->code);
if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) {
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
abort->ch.chunk_flags);
@ -2558,27 +2554,27 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (timevalcmp(&now, &time_expires, >)) {
/* cookie is stale! */
struct mbuf *op_err;
struct sctp_stale_cookie_msg *scm;
struct sctp_error_stale_cookie *cause;
uint32_t tim;
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_stale_cookie_msg),
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_stale_cookie),
0, M_NOWAIT, 1, MT_DATA);
if (op_err == NULL) {
/* FOOBAR */
return (NULL);
}
/* Set the len */
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg);
scm = mtod(op_err, struct sctp_stale_cookie_msg *);
scm->ph.param_type = htons(SCTP_CAUSE_STALE_COOKIE);
scm->ph.param_length = htons((sizeof(struct sctp_paramhdr) +
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_stale_cookie);
cause = mtod(op_err, struct sctp_error_stale_cookie *);
cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE);
cause->cause.length = htons((sizeof(struct sctp_paramhdr) +
(sizeof(uint32_t))));
/* seconds to usec */
tim = (now.tv_sec - time_expires.tv_sec) * 1000000;
/* add in usec */
if (tim == 0)
tim = now.tv_usec - cookie->time_entered.tv_usec;
scm->time_usec = htonl(tim);
cause->stale_time = htonl(tim);
sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err,
mflowtype, mflowid, l_inp->fibnum,
vrf_id, port);
@ -5581,35 +5577,27 @@ __attribute__((noinline))
unknown_chunk:
/* it's an unknown chunk! */
if ((ch->chunk_type & 0x40) && (stcb != NULL)) {
struct mbuf *mm;
struct sctp_paramhdr *phd;
struct sctp_gen_error_cause *cause;
int len;
mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
0, M_NOWAIT, 1, MT_DATA);
if (mm) {
if (op_err != NULL) {
len = min(SCTP_SIZE32(chk_length), (uint32_t) (length - *offset));
phd = mtod(mm, struct sctp_paramhdr *);
/*
* We cheat and use param type since
* we did not bother to define a
* error cause struct. They are the
* same basic format with different
* names.
*/
phd->param_type = htons(SCTP_CAUSE_UNRECOG_CHUNK);
phd->param_length = htons(len + sizeof(*phd));
SCTP_BUF_LEN(mm) = sizeof(*phd);
SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
if (SCTP_BUF_NEXT(mm)) {
cause = mtod(op_err, struct sctp_gen_error_cause *);
cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
cause->length = htons(len + sizeof(struct sctp_gen_error_cause));
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
if (SCTP_BUF_NEXT(op_err) != NULL) {
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
sctp_log_mbc(SCTP_BUF_NEXT(mm), SCTP_MBUF_ICOPY);
}
#endif
sctp_queue_op_err(stcb, mm);
sctp_queue_op_err(stcb, op_err);
} else {
sctp_m_freem(mm);
sctp_m_freem(op_err);
}
}
}