diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 159 |
1 files changed, 104 insertions, 55 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 1f0676d1ffbc..7a0c6fa4c33c 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -67,6 +67,19 @@ extern kmem_cache_t *sctp_chunk_cachep; +SCTP_STATIC +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, + __u8 type, __u8 flags, int paylen); +static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *init_chunk, + int *cookie_len, + const __u8 *raw_addrs, int addrs_len); +static int sctp_process_param(struct sctp_association *asoc, + union sctp_params param, + const union sctp_addr *peer_addr, + int gfp); + /* What was the inbound interface for this chunk? */ int sctp_chunk_iif(const struct sctp_chunk *chunk) { @@ -559,52 +572,6 @@ nodata: return retval; } -/* Make a DATA chunk for the given association. Populate the data - * payload. - */ -struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len, const __u8 *data, - __u8 flags, __u16 ssn) -{ - struct sctp_chunk *retval; - - retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); - if (retval) - sctp_addto_chunk(retval, data_len, data); - - return retval; -} - -/* Make a DATA chunk for the given association to ride on stream id - * 'stream', with a payload id of 'payload', and a body of 'data'. - */ -struct sctp_chunk *sctp_make_data(struct sctp_association *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len, const __u8 *data) -{ - struct sctp_chunk *retval = NULL; - - retval = sctp_make_data_empty(asoc, sinfo, data_len); - if (retval) - sctp_addto_chunk(retval, data_len, data); - return retval; -} - -/* Make a DATA chunk for the given association to ride on stream id - * 'stream', with a payload id of 'payload', and a body big enough to - * hold 'data_len' octets of data. We use this version when we need - * to build the message AFTER allocating memory. - */ -struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len) -{ - __u8 flags = SCTP_DATA_NOT_FRAG; - - return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0); -} - /* Create a selective ackowledgement (SACK) for the given * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. @@ -881,6 +848,31 @@ err_chunk: return retval; } +/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */ +struct sctp_chunk *sctp_make_abort_violation( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, + const __u8 *payload, + const size_t paylen) +{ + struct sctp_chunk *retval; + struct sctp_paramhdr phdr; + + retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen + + sizeof(sctp_chunkhdr_t)); + if (!retval) + goto end; + + sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen); + + phdr.type = htons(chunk->chunk_hdr->type); + phdr.length = chunk->chunk_hdr->length; + sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr); + +end: + return retval; +} + /* Make a HEARTBEAT chunk. */ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, @@ -933,7 +925,7 @@ nodata: /* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ -struct sctp_chunk *sctp_make_op_error_space( +static struct sctp_chunk *sctp_make_op_error_space( const struct sctp_association *asoc, const struct sctp_chunk *chunk, size_t size) @@ -1034,7 +1026,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, SCTP_DBG_OBJCNT_INC(chunk); atomic_set(&retval->refcnt, 1); - nodata: return retval; } @@ -1062,6 +1053,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ +SCTP_STATIC struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen) { @@ -1261,7 +1253,7 @@ fail: /* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */ -sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, +static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, const struct sctp_association *asoc, const struct sctp_chunk *init_chunk, int *cookie_len, @@ -1409,6 +1401,24 @@ struct sctp_association *sctp_unpack_cookie( } no_hmac: + /* IG Section 2.35.2: + * 3) Compare the port numbers and the verification tag contained + * within the COOKIE ECHO chunk to the actual port numbers and the + * verification tag within the SCTP common header of the received + * packet. If these values do not match the packet MUST be silently + * discarded, + */ + if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) { + *error = -SCTP_IERROR_BAD_TAG; + goto fail; + } + + if (ntohs(chunk->sctp_hdr->source) != bear_cookie->peer_addr.v4.sin_port || + ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) { + *error = -SCTP_IERROR_BAD_PORTS; + goto fail; + } + /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. @@ -1547,6 +1557,30 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc, return 0; } +static int sctp_process_inv_paramlength(const struct sctp_association *asoc, + struct sctp_paramhdr *param, + const struct sctp_chunk *chunk, + struct sctp_chunk **errp) +{ + char error[] = "The following parameter had invalid length:"; + size_t payload_len = WORD_ROUND(sizeof(error)) + + sizeof(sctp_paramhdr_t); + + + /* Create an error chunk and fill it in with our payload. */ + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, payload_len); + + if (*errp) { + sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error, + sizeof(error)); + sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param); + } + + return 0; +} + + /* Do not attempt to handle the HOST_NAME parm. However, do * send back an indicator to the peer. */ @@ -1725,6 +1759,18 @@ int sctp_verify_init(const struct sctp_association *asoc, } /* for (loop through all parameters) */ + /* There is a possibility that a parameter length was bad and + * in that case we would have stoped walking the parameters. + * The current param.p would point at the bad one. + * Current consensus on the mailing list is to generate a PROTOCOL + * VIOLATION error. We build the ERROR chunk here and let the normal + * error handling code build and send the packet. + */ + if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) { + sctp_process_inv_paramlength(asoc, param.p, chunk, errp); + return 0; + } + /* The only missing mandatory param possible today is * the state cookie for an INIT-ACK chunk. */ @@ -1912,8 +1958,10 @@ nomem: * work we do. In particular, we should not build transport * structures for the addresses. */ -int sctp_process_param(struct sctp_association *asoc, union sctp_params param, - const union sctp_addr *peer_addr, int gfp) +static int sctp_process_param(struct sctp_association *asoc, + union sctp_params param, + const union sctp_addr *peer_addr, + int gfp) { union sctp_addr addr; int i; @@ -2078,8 +2126,9 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep) * * Address Parameter and other parameter will not be wrapped in this function */ -struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, - union sctp_addr *addr, int vparam_len) +static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, + union sctp_addr *addr, + int vparam_len) { sctp_addiphdr_t asconf; struct sctp_chunk *retval; @@ -2248,8 +2297,8 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, * * Create an ASCONF_ACK chunk with enough space for the parameter responses. */ -struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc, - __u32 serial, int vparam_len) +static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc, + __u32 serial, int vparam_len) { sctp_addiphdr_t asconf; struct sctp_chunk *retval; |
