Commit b8f04cb5 authored by Jon Grimm's avatar Jon Grimm

[SCTP] Handle requests of 0 streams & missing state cookie.

Cleaning up some RFC 2960 corner cases.  We need to ABORT the case
where peer requests inbound/outbound streams of value 0.   We need
to abort the missing state cookie case. 
parent 5e595b1c
...@@ -116,8 +116,8 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, ...@@ -116,8 +116,8 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
err.cause = cause_code; err.cause = cause_code;
len = sizeof(sctp_errhdr_t) + paylen; len = sizeof(sctp_errhdr_t) + paylen;
padlen = len % 4; padlen = len % 4;
len += padlen;
err.length = htons(len); err.length = htons(len);
len += padlen;
sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);
chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload); chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload);
} }
...@@ -540,7 +540,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, ...@@ -540,7 +540,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
dp.stream = htons(sinfo->sinfo_stream); dp.stream = htons(sinfo->sinfo_stream);
dp.ppid = htonl(sinfo->sinfo_ppid); dp.ppid = htonl(sinfo->sinfo_ppid);
dp.ssn = htons(ssn); dp.ssn = htons(ssn);
/* Set the flags for an unordered send. */ /* Set the flags for an unordered send. */
if (sinfo->sinfo_flags & MSG_UNORDERED) if (sinfo->sinfo_flags & MSG_UNORDERED)
flags |= SCTP_DATA_UNORDERED; flags |= SCTP_DATA_UNORDERED;
...@@ -552,7 +552,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, ...@@ -552,7 +552,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
nodata: nodata:
return retval; return retval;
} }
...@@ -598,23 +598,9 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, ...@@ -598,23 +598,9 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len) int data_len)
{ {
__u16 ssn;
__u8 flags = SCTP_DATA_NOT_FRAG; __u8 flags = SCTP_DATA_NOT_FRAG;
/* Sockets API Extensions for SCTP 5.2.2 return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
* MSG_UNORDERED - This flag requests the un-ordered delivery of the
* message. If this flag is clear, the datagram is considered an
* ordered send and a new ssn is generated. The flags field is set
* in the inner routine - sctp_make_datafrag_empty().
*/
// if (sinfo->sinfo_flags & MSG_UNORDERED) {
ssn = 0;
// } else {
// ssn = __sctp_association_get_next_ssn(asoc,
// sinfo->sinfo_stream);
// }
return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
} }
/* Create a selective ackowledgement (SACK) for the given /* Create a selective ackowledgement (SACK) for the given
...@@ -714,6 +700,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -714,6 +700,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
return retval; return retval;
} }
/* FIXME: Comments. */
sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
{ {
sctp_chunk_t *retval; sctp_chunk_t *retval;
...@@ -1427,6 +1414,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1427,6 +1414,7 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* for init collision case of lost COOKIE ACK. * for init collision case of lost COOKIE ACK.
*/ */
if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) {
__u16 len;
/* /*
* Section 3.3.10.3 Stale Cookie Error (3) * Section 3.3.10.3 Stale Cookie Error (3)
* *
...@@ -1435,8 +1423,8 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1435,8 +1423,8 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* Stale Cookie Error: Indicates the receipt of a valid State * Stale Cookie Error: Indicates the receipt of a valid State
* Cookie that has expired. * Cookie that has expired.
*/ */
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len = ntohs(chunk->chunk_hdr->length);
ntohs(chunk->chunk_hdr->length)); *err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
if (*err_chk_p) { if (*err_chk_p) {
suseconds_t usecs = (chunk->skb->stamp.tv_sec - suseconds_t usecs = (chunk->skb->stamp.tv_sec -
bear_cookie->expiration.tv_sec) * 1000000L + bear_cookie->expiration.tv_sec) * 1000000L +
...@@ -1501,6 +1489,57 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1501,6 +1489,57 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions * 3rd Level Abstractions
********************************************************************/ ********************************************************************/
/*
* Report a missing mandatory parameter.
*/
struct __sctp_missing {
__u32 num_missing;
__u16 type;
} __attribute__((packed));;
static int sctp_process_missing_param(const sctp_association_t *asoc,
sctp_param_t paramtype,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
struct __sctp_missing report;
__u16 len;
len = WORD_ROUND(sizeof(report));
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
*/
if (!*err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
if (*err_chk_p) {
report.num_missing = htonl(1);
report.type = paramtype;
sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM,
&report, sizeof(report));
}
/* Stop processing this chunk. */
return 0;
}
/* Report an Invalid Mandatory Parameter. */
static int sctp_process_inv_mandatory(const sctp_association_t *asoc,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
/* Invalid Mandatory Parameter Error has no payload. */
if (!*err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, 0);
if (*err_chk_p)
sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0);
/* Stop processing this chunk. */
return 0;
}
/* Do not attempt to handle the HOST_NAME parm. However, do /* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer. * send back an indicator to the peer.
*/ */
...@@ -1511,9 +1550,7 @@ static int sctp_process_hn_param(const sctp_association_t *asoc, ...@@ -1511,9 +1550,7 @@ static int sctp_process_hn_param(const sctp_association_t *asoc,
{ {
__u16 len = ntohs(param.p->length); __u16 len = ntohs(param.p->length);
/* Make an ERROR chunk, preparing enough room for /* Make an ERROR chunk. */
* returning multiple unknown parameters.
*/
if (!*err_chk_p) if (!*err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len); *err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
...@@ -1594,7 +1631,8 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1594,7 +1631,8 @@ static int sctp_process_unk_param(const sctp_association_t *asoc,
} else { } else {
/* If there is no memory for generating the ERROR /* If there is no memory for generating the ERROR
* report as specified, an ABORT will be triggered * report as specified, an ABORT will be triggered
* to the peer and the association won't be established. * to the peer and the association won't be
* established.
*/ */
retval = 0; retval = 0;
} }
...@@ -1657,12 +1695,33 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1657,12 +1695,33 @@ int sctp_verify_init(const sctp_association_t *asoc,
sctp_chunk_t **err_chk_p) sctp_chunk_t **err_chk_p)
{ {
union sctp_params param; union sctp_params param;
int has_cookie = 0;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify /* Verify stream values are non-zero. */
* the mandatory parameters somewhere here and generate either the if ((0 == peer_init->init_hdr.num_outbound_streams) ||
* "Missing mandatory parameter" error or the "Invalid mandatory (0 == peer_init->init_hdr.num_inbound_streams)) {
* parameter" error.
sctp_process_inv_mandatory(asoc, chunk, err_chk_p);
return 0;
}
/* Check for missing mandatory parameters. */
sctp_walk_params(param, peer_init, init_hdr.params) {
if (SCTP_PARAM_STATE_COOKIE == param.p->type)
has_cookie = 1;
} /* for (loop through all parameters) */
/* The only missing mandatory param possible today is
* the state cookie for an INIT-ACK chunk.
*/ */
if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) {
sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
chunk, err_chk_p);
return 0;
}
/* Find unrecognized parameters. */ /* Find unrecognized parameters. */
...@@ -1678,7 +1737,7 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1678,7 +1737,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
/* Unpack the parameters in an INIT packet into an association. /* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success. * Returns 0 on failure, else success.
* FIXME: This is an association method. * FIXME: This is an association method.
*/ */
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const union sctp_addr *peer_addr, const union sctp_addr *peer_addr,
......
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