diff options
author | Xin Long <lucien.xin@gmail.com> | 2017-02-17 12:45:41 +0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-02-19 18:17:59 -0500 |
commit | ea62504373fa9ff3ced27e07e1eac041888ecc46 (patch) | |
tree | ac30c689bd6d88b6356b7f39787fc55623e9cdd0 | |
parent | 16e1a91965b02fe24d24e8b8d7b2245d29ed6a70 (diff) | |
download | op-kernel-dev-ea62504373fa9ff3ced27e07e1eac041888ecc46.zip op-kernel-dev-ea62504373fa9ff3ced27e07e1eac041888ecc46.tar.gz |
sctp: add a function to verify the sctp reconf chunk
This patch is to add a function sctp_verify_reconf to do some length
check and multi-params check for sctp stream reconf according to rfc6525
section 3.1.
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/sctp/sm.h | 3 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 59 |
2 files changed, 62 insertions, 0 deletions
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index f6a828d..ca9fbfb 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -277,6 +277,9 @@ struct sctp_chunk *sctp_make_strreset_tsnresp( struct sctp_association *asoc, __u32 result, __u32 sn, __u32 sender_tsn, __u32 receiver_tsn); +bool sctp_verify_reconf(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + struct sctp_paramhdr **errp); void sctp_chunk_assign_tsn(struct sctp_chunk *); void sctp_chunk_assign_ssn(struct sctp_chunk *); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 60d9fdc..969a30c 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3801,3 +3801,62 @@ struct sctp_chunk *sctp_make_strreset_tsnresp( return retval; } + +bool sctp_verify_reconf(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + struct sctp_paramhdr **errp) +{ + struct sctp_reconf_chunk *hdr; + union sctp_params param; + __u16 last = 0, cnt = 0; + + hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr; + sctp_walk_params(param, hdr, params) { + __u16 length = ntohs(param.p->length); + + *errp = param.p; + if (cnt++ > 2) + return false; + switch (param.p->type) { + case SCTP_PARAM_RESET_OUT_REQUEST: + if (length < sizeof(struct sctp_strreset_outreq) || + (last && last != SCTP_PARAM_RESET_RESPONSE && + last != SCTP_PARAM_RESET_IN_REQUEST)) + return false; + break; + case SCTP_PARAM_RESET_IN_REQUEST: + if (length < sizeof(struct sctp_strreset_inreq) || + (last && last != SCTP_PARAM_RESET_OUT_REQUEST)) + return false; + break; + case SCTP_PARAM_RESET_RESPONSE: + if ((length != sizeof(struct sctp_strreset_resp) && + length != sizeof(struct sctp_strreset_resptsn)) || + (last && last != SCTP_PARAM_RESET_RESPONSE && + last != SCTP_PARAM_RESET_OUT_REQUEST)) + return false; + break; + case SCTP_PARAM_RESET_TSN_REQUEST: + if (length != + sizeof(struct sctp_strreset_tsnreq) || last) + return false; + break; + case SCTP_PARAM_RESET_ADD_IN_STREAMS: + if (length != sizeof(struct sctp_strreset_addstrm) || + (last && last != SCTP_PARAM_RESET_ADD_OUT_STREAMS)) + return false; + break; + case SCTP_PARAM_RESET_ADD_OUT_STREAMS: + if (length != sizeof(struct sctp_strreset_addstrm) || + (last && last != SCTP_PARAM_RESET_ADD_IN_STREAMS)) + return false; + break; + default: + return false; + } + + last = param.p->type; + } + + return true; +} |