|
@@ -3110,50 +3110,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
|
|
|
return SCTP_ERROR_NO_ERROR;
|
|
|
}
|
|
|
|
|
|
-/* Verify the ASCONF packet before we process it. */
|
|
|
-int sctp_verify_asconf(const struct sctp_association *asoc,
|
|
|
- struct sctp_paramhdr *param_hdr, void *chunk_end,
|
|
|
- struct sctp_paramhdr **errp) {
|
|
|
- sctp_addip_param_t *asconf_param;
|
|
|
+/* Verify the ASCONF packet before we process it. */
|
|
|
+bool sctp_verify_asconf(const struct sctp_association *asoc,
|
|
|
+ struct sctp_chunk *chunk, bool addr_param_needed,
|
|
|
+ struct sctp_paramhdr **errp)
|
|
|
+{
|
|
|
+ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr;
|
|
|
union sctp_params param;
|
|
|
- int length, plen;
|
|
|
-
|
|
|
- param.v = (sctp_paramhdr_t *) param_hdr;
|
|
|
- while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) {
|
|
|
- length = ntohs(param.p->length);
|
|
|
- *errp = param.p;
|
|
|
+ bool addr_param_seen = false;
|
|
|
|
|
|
- if (param.v > chunk_end - length ||
|
|
|
- length < sizeof(sctp_paramhdr_t))
|
|
|
- return 0;
|
|
|
+ sctp_walk_params(param, addip, addip_hdr.params) {
|
|
|
+ size_t length = ntohs(param.p->length);
|
|
|
|
|
|
+ *errp = param.p;
|
|
|
switch (param.p->type) {
|
|
|
+ case SCTP_PARAM_ERR_CAUSE:
|
|
|
+ break;
|
|
|
+ case SCTP_PARAM_IPV4_ADDRESS:
|
|
|
+ if (length != sizeof(sctp_ipv4addr_param_t))
|
|
|
+ return false;
|
|
|
+ addr_param_seen = true;
|
|
|
+ break;
|
|
|
+ case SCTP_PARAM_IPV6_ADDRESS:
|
|
|
+ if (length != sizeof(sctp_ipv6addr_param_t))
|
|
|
+ return false;
|
|
|
+ addr_param_seen = true;
|
|
|
+ break;
|
|
|
case SCTP_PARAM_ADD_IP:
|
|
|
case SCTP_PARAM_DEL_IP:
|
|
|
case SCTP_PARAM_SET_PRIMARY:
|
|
|
- asconf_param = (sctp_addip_param_t *)param.v;
|
|
|
- plen = ntohs(asconf_param->param_hdr.length);
|
|
|
- if (plen < sizeof(sctp_addip_param_t) +
|
|
|
- sizeof(sctp_paramhdr_t))
|
|
|
- return 0;
|
|
|
+ /* In ASCONF chunks, these need to be first. */
|
|
|
+ if (addr_param_needed && !addr_param_seen)
|
|
|
+ return false;
|
|
|
+ length = ntohs(param.addip->param_hdr.length);
|
|
|
+ if (length < sizeof(sctp_addip_param_t) +
|
|
|
+ sizeof(sctp_paramhdr_t))
|
|
|
+ return false;
|
|
|
break;
|
|
|
case SCTP_PARAM_SUCCESS_REPORT:
|
|
|
case SCTP_PARAM_ADAPTATION_LAYER_IND:
|
|
|
if (length != sizeof(sctp_addip_param_t))
|
|
|
- return 0;
|
|
|
-
|
|
|
+ return false;
|
|
|
break;
|
|
|
default:
|
|
|
- break;
|
|
|
+ /* This is unkown to us, reject! */
|
|
|
+ return false;
|
|
|
}
|
|
|
-
|
|
|
- param.v += WORD_ROUND(length);
|
|
|
}
|
|
|
|
|
|
- if (param.v != chunk_end)
|
|
|
- return 0;
|
|
|
+ /* Remaining sanity checks. */
|
|
|
+ if (addr_param_needed && !addr_param_seen)
|
|
|
+ return false;
|
|
|
+ if (!addr_param_needed && addr_param_seen)
|
|
|
+ return false;
|
|
|
+ if (param.v != chunk->chunk_end)
|
|
|
+ return false;
|
|
|
|
|
|
- return 1;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
/* Process an incoming ASCONF chunk with the next expected serial no. and
|
|
@@ -3162,16 +3175,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc,
|
|
|
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
|
|
|
struct sctp_chunk *asconf)
|
|
|
{
|
|
|
+ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr;
|
|
|
+ bool all_param_pass = true;
|
|
|
+ union sctp_params param;
|
|
|
sctp_addiphdr_t *hdr;
|
|
|
union sctp_addr_param *addr_param;
|
|
|
sctp_addip_param_t *asconf_param;
|
|
|
struct sctp_chunk *asconf_ack;
|
|
|
-
|
|
|
__be16 err_code;
|
|
|
int length = 0;
|
|
|
int chunk_len;
|
|
|
__u32 serial;
|
|
|
- int all_param_pass = 1;
|
|
|
|
|
|
chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
|
|
|
hdr = (sctp_addiphdr_t *)asconf->skb->data;
|
|
@@ -3199,9 +3213,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
|
|
|
goto done;
|
|
|
|
|
|
/* Process the TLVs contained within the ASCONF chunk. */
|
|
|
- while (chunk_len > 0) {
|
|
|
+ sctp_walk_params(param, addip, addip_hdr.params) {
|
|
|
+ /* Skip preceeding address parameters. */
|
|
|
+ if (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
|
|
|
+ param.p->type == SCTP_PARAM_IPV6_ADDRESS)
|
|
|
+ continue;
|
|
|
+
|
|
|
err_code = sctp_process_asconf_param(asoc, asconf,
|
|
|
- asconf_param);
|
|
|
+ param.addip);
|
|
|
/* ADDIP 4.1 A7)
|
|
|
* If an error response is received for a TLV parameter,
|
|
|
* all TLVs with no response before the failed TLV are
|
|
@@ -3209,28 +3228,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
|
|
|
* the failed response are considered unsuccessful unless
|
|
|
* a specific success indication is present for the parameter.
|
|
|
*/
|
|
|
- if (SCTP_ERROR_NO_ERROR != err_code)
|
|
|
- all_param_pass = 0;
|
|
|
-
|
|
|
+ if (err_code != SCTP_ERROR_NO_ERROR)
|
|
|
+ all_param_pass = false;
|
|
|
if (!all_param_pass)
|
|
|
- sctp_add_asconf_response(asconf_ack,
|
|
|
- asconf_param->crr_id, err_code,
|
|
|
- asconf_param);
|
|
|
+ sctp_add_asconf_response(asconf_ack, param.addip->crr_id,
|
|
|
+ err_code, param.addip);
|
|
|
|
|
|
/* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
|
|
|
* an IP address sends an 'Out of Resource' in its response, it
|
|
|
* MUST also fail any subsequent add or delete requests bundled
|
|
|
* in the ASCONF.
|
|
|
*/
|
|
|
- if (SCTP_ERROR_RSRC_LOW == err_code)
|
|
|
+ if (err_code == SCTP_ERROR_RSRC_LOW)
|
|
|
goto done;
|
|
|
-
|
|
|
- /* Move to the next ASCONF param. */
|
|
|
- length = ntohs(asconf_param->param_hdr.length);
|
|
|
- asconf_param = (void *)asconf_param + length;
|
|
|
- chunk_len -= length;
|
|
|
}
|
|
|
-
|
|
|
done:
|
|
|
asoc->peer.addip_serial++;
|
|
|
|