SCTP: Make sctp_verify_param return multiple indications.

SCTP-AUTH and future ADD-IP updates have a requirement to
do additional verification of parameters and an ability to
ABORT the association if verification fails.  So, introduce
additional return code so that we can clear signal a required
action.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
This commit is contained in:
Vlad Yasevich 2007-11-09 11:43:41 -05:00
parent d970dbf845
commit 7ab9080467
2 changed files with 77 additions and 74 deletions

View File

@ -186,6 +186,8 @@ typedef enum {
SCTP_IERROR_AUTH_BAD_HMAC, SCTP_IERROR_AUTH_BAD_HMAC,
SCTP_IERROR_AUTH_BAD_KEYID, SCTP_IERROR_AUTH_BAD_KEYID,
SCTP_IERROR_PROTO_VIOLATION, SCTP_IERROR_PROTO_VIOLATION,
SCTP_IERROR_ERROR,
SCTP_IERROR_ABORT,
} sctp_ierror_t; } sctp_ierror_t;

View File

@ -1788,9 +1788,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
sizeof(sctp_paramhdr_t); sizeof(sctp_paramhdr_t);
/* This is a fatal error. Any accumulated non-fatal errors are
* not reported.
*/
if (*errp)
sctp_chunk_free(*errp);
/* Create an error chunk and fill it in with our payload. */ /* Create an error chunk and fill it in with our payload. */
if (!*errp) *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
if (*errp) { if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
@ -1813,9 +1818,15 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
{ {
__u16 len = ntohs(param.p->length); __u16 len = ntohs(param.p->length);
/* Make an ERROR chunk. */ /* Processing of the HOST_NAME parameter will generate an
if (!*errp) * ABORT. If we've accumulated any non-fatal errors, they
*errp = sctp_make_op_error_space(asoc, chunk, len); * would be unrecognized parameters and we should not include
* them in the ABORT.
*/
if (*errp)
sctp_chunk_free(*errp);
*errp = sctp_make_op_error_space(asoc, chunk, len);
if (*errp) { if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len);
@ -1862,56 +1873,40 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
* taken if the processing endpoint does not recognize the * taken if the processing endpoint does not recognize the
* Parameter Type. * Parameter Type.
* *
* 00 - Stop processing this SCTP chunk and discard it, * 00 - Stop processing this parameter; do not process any further
* do not process any further chunks within it. * parameters within this chunk
* *
* 01 - Stop processing this SCTP chunk and discard it, * 01 - Stop processing this parameter, do not process any further
* do not process any further chunks within it, and report * parameters within this chunk, and report the unrecognized
* the unrecognized parameter in an 'Unrecognized * parameter in an 'Unrecognized Parameter' ERROR chunk.
* Parameter Type' (in either an ERROR or in the INIT ACK).
* *
* 10 - Skip this parameter and continue processing. * 10 - Skip this parameter and continue processing.
* *
* 11 - Skip this parameter and continue processing but * 11 - Skip this parameter and continue processing but
* report the unrecognized parameter in an * report the unrecognized parameter in an
* 'Unrecognized Parameter Type' (in either an ERROR or in * 'Unrecognized Parameter' ERROR chunk.
* the INIT ACK).
* *
* Return value: * Return value:
* 0 - discard the chunk * SCTP_IERROR_NO_ERROR - continue with the chunk
* 1 - continue with the chunk * SCTP_IERROR_ERROR - stop and report an error.
* SCTP_IERROR_NOMEME - out of memory.
*/ */
static int sctp_process_unk_param(const struct sctp_association *asoc, static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
struct sctp_chunk **errp) struct sctp_chunk **errp)
{ {
int retval = 1; int retval = SCTP_IERROR_NO_ERROR;
switch (param.p->type & SCTP_PARAM_ACTION_MASK) { switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
case SCTP_PARAM_ACTION_DISCARD: case SCTP_PARAM_ACTION_DISCARD:
retval = 0; retval = SCTP_IERROR_ERROR;
break;
case SCTP_PARAM_ACTION_DISCARD_ERR:
retval = 0;
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if (NULL == *errp)
*errp = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length));
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
WORD_ROUND(ntohs(param.p->length)));
sctp_addto_chunk(*errp,
WORD_ROUND(ntohs(param.p->length)),
param.v);
}
break; break;
case SCTP_PARAM_ACTION_SKIP: case SCTP_PARAM_ACTION_SKIP:
break; break;
case SCTP_PARAM_ACTION_DISCARD_ERR:
retval = SCTP_IERROR_ERROR;
/* Fall through */
case SCTP_PARAM_ACTION_SKIP_ERR: case SCTP_PARAM_ACTION_SKIP_ERR:
/* Make an ERROR chunk, preparing enough room for /* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters. * returning multiple unknown parameters.
@ -1932,9 +1927,8 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
* to the peer and the association won't be * to the peer and the association won't be
* established. * established.
*/ */
retval = 0; retval = SCTP_IERROR_NOMEM;
} }
break; break;
default: default:
break; break;
@ -1943,18 +1937,20 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
return retval; return retval;
} }
/* Find unrecognized parameters in the chunk. /* Verify variable length parameters
* Return values: * Return values:
* 0 - discard the chunk * SCTP_IERROR_ABORT - trigger an ABORT
* 1 - continue with the chunk * SCTP_IERROR_NOMEM - out of memory (abort)
* SCTP_IERROR_ERROR - stop processing, trigger an ERROR
* SCTP_IERROR_NO_ERROR - continue with the chunk
*/ */
static int sctp_verify_param(const struct sctp_association *asoc, static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
sctp_cid_t cid, sctp_cid_t cid,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
struct sctp_chunk **err_chunk) struct sctp_chunk **err_chunk)
{ {
int retval = 1; int retval = SCTP_IERROR_NO_ERROR;
/* FIXME - This routine is not looking at each parameter per the /* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further * chunk type, i.e., unrecognized parameters should be further
@ -1976,7 +1972,9 @@ static int sctp_verify_param(const struct sctp_association *asoc,
case SCTP_PARAM_HOST_NAME_ADDRESS: case SCTP_PARAM_HOST_NAME_ADDRESS:
/* Tell the peer, we won't support this param. */ /* Tell the peer, we won't support this param. */
return sctp_process_hn_param(asoc, param, chunk, err_chunk); sctp_process_hn_param(asoc, param, chunk, err_chunk);
retval = SCTP_IERROR_ABORT;
break;
case SCTP_PARAM_FWD_TSN_SUPPORT: case SCTP_PARAM_FWD_TSN_SUPPORT:
if (sctp_prsctp_enable) if (sctp_prsctp_enable)
@ -1993,9 +1991,11 @@ static int sctp_verify_param(const struct sctp_association *asoc,
* cause 'Protocol Violation'. * cause 'Protocol Violation'.
*/ */
if (SCTP_AUTH_RANDOM_LENGTH != if (SCTP_AUTH_RANDOM_LENGTH !=
ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) {
return sctp_process_inv_paramlength(asoc, param.p, sctp_process_inv_paramlength(asoc, param.p,
chunk, err_chunk); chunk, err_chunk);
retval = SCTP_IERROR_ABORT;
}
break; break;
case SCTP_PARAM_CHUNKS: case SCTP_PARAM_CHUNKS:
@ -2007,9 +2007,11 @@ static int sctp_verify_param(const struct sctp_association *asoc,
* INIT-ACK chunk if the sender wants to receive authenticated * INIT-ACK chunk if the sender wants to receive authenticated
* chunks. Its maximum length is 260 bytes. * chunks. Its maximum length is 260 bytes.
*/ */
if (260 < ntohs(param.p->length)) if (260 < ntohs(param.p->length)) {
return sctp_process_inv_paramlength(asoc, param.p, sctp_process_inv_paramlength(asoc, param.p,
chunk, err_chunk); chunk, err_chunk);
retval = SCTP_IERROR_ABORT;
}
break; break;
case SCTP_PARAM_HMAC_ALGO: case SCTP_PARAM_HMAC_ALGO:
@ -2020,8 +2022,7 @@ fallthrough:
default: default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid); ntohs(param.p->type), cid);
return sctp_process_unk_param(asoc, param, chunk, err_chunk); retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
break; break;
} }
return retval; return retval;
@ -2036,6 +2037,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
{ {
union sctp_params param; union sctp_params param;
int has_cookie = 0; int has_cookie = 0;
int result;
/* Verify stream values are non-zero. */ /* Verify stream values are non-zero. */
if ((0 == peer_init->init_hdr.num_outbound_streams) || if ((0 == peer_init->init_hdr.num_outbound_streams) ||
@ -2043,8 +2045,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
(0 == peer_init->init_hdr.init_tag) || (0 == peer_init->init_hdr.init_tag) ||
(SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) { (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) {
sctp_process_inv_mandatory(asoc, chunk, errp); return sctp_process_inv_mandatory(asoc, chunk, errp);
return 0;
} }
/* Check for missing mandatory parameters. */ /* Check for missing mandatory parameters. */
@ -2062,29 +2063,29 @@ int sctp_verify_init(const struct sctp_association *asoc,
* VIOLATION error. We build the ERROR chunk here and let the normal * VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet. * error handling code build and send the packet.
*/ */
if (param.v != (void*)chunk->chunk_end) { if (param.v != (void*)chunk->chunk_end)
sctp_process_inv_paramlength(asoc, param.p, chunk, errp); return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
return 0;
}
/* The only missing mandatory param possible today is /* The only missing mandatory param possible today is
* the state cookie for an INIT-ACK chunk. * the state cookie for an INIT-ACK chunk.
*/ */
if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { if ((SCTP_CID_INIT_ACK == cid) && !has_cookie)
sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
chunk, errp); chunk, errp);
return 0;
}
/* Find unrecognized parameters. */
/* Verify all the variable length parameters */
sctp_walk_params(param, peer_init, init_hdr.params) { sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_verify_param(asoc, param, cid, chunk, errp)) { result = sctp_verify_param(asoc, param, cid, chunk, errp);
if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type) switch (result) {
case SCTP_IERROR_ABORT:
case SCTP_IERROR_NOMEM:
return 0; return 0;
else case SCTP_IERROR_ERROR:
return 1; return 1;
case SCTP_IERROR_NO_ERROR:
default:
break;
} }
} /* for (loop through all parameters) */ } /* for (loop through all parameters) */