diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 94 | 
1 files changed, 67 insertions, 27 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 17cb400ecd6..30c1767186b 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -108,7 +108,7 @@ static const struct sctp_paramhdr prsctp_param = {  	cpu_to_be16(sizeof(struct sctp_paramhdr)),  }; -/* A helper to initialize to initialize an op error inside a +/* A helper to initialize an op error inside a   * provided chunk, as most cause codes will be embedded inside an   * abort chunk.   */ @@ -125,6 +125,29 @@ void  sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,  	chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err);  } +/* A helper to initialize an op error inside a + * provided chunk, as most cause codes will be embedded inside an + * abort chunk.  Differs from sctp_init_cause in that it won't oops + * if there isn't enough space in the op error chunk + */ +int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code, +		      size_t paylen) +{ +	sctp_errhdr_t err; +	__u16 len; + +	/* Cause code constants are now defined in network order.  */ +	err.cause = cause_code; +	len = sizeof(sctp_errhdr_t) + paylen; +	err.length  = htons(len); + +	if (skb_tailroom(chunk->skb) >  len) +		return -ENOSPC; +	chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk, +						     sizeof(sctp_errhdr_t), +						     &err); +	return 0; +}  /* 3.3.2 Initiation (INIT) (1)   *   * This chunk is used to initiate a SCTP association between two @@ -208,7 +231,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	sp = sctp_sk(asoc->base.sk);  	num_types = sp->pf->supported_addrs(sp, types); -	chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); +	chunksize = sizeof(init) + addrs_len; +	chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types));  	chunksize += sizeof(ecap_param);  	if (sctp_prsctp_enable) @@ -238,14 +262,14 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  		/* Add HMACS parameter length if any were defined */  		auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;  		if (auth_hmacs->length) -			chunksize += ntohs(auth_hmacs->length); +			chunksize += WORD_ROUND(ntohs(auth_hmacs->length));  		else  			auth_hmacs = NULL;  		/* Add CHUNKS parameter length */  		auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;  		if (auth_chunks->length) -			chunksize += ntohs(auth_chunks->length); +			chunksize += WORD_ROUND(ntohs(auth_chunks->length));  		else  			auth_chunks = NULL; @@ -255,7 +279,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	/* If we have any extensions to report, account for that */  	if (num_ext) -		chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; +		chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + +					num_ext);  	/* RFC 2960 3.3.2 Initiation (INIT) (1)  	 * @@ -397,13 +422,13 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,  		auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;  		if (auth_hmacs->length) -			chunksize += ntohs(auth_hmacs->length); +			chunksize += WORD_ROUND(ntohs(auth_hmacs->length));  		else  			auth_hmacs = NULL;  		auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;  		if (auth_chunks->length) -			chunksize += ntohs(auth_chunks->length); +			chunksize += WORD_ROUND(ntohs(auth_chunks->length));  		else  			auth_chunks = NULL; @@ -412,7 +437,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,  	}  	if (num_ext) -		chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; +		chunksize += WORD_ROUND(sizeof(sctp_supported_ext_param_t) + +					num_ext);  	/* Now allocate and fill out the chunk.  */  	retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); @@ -1129,6 +1155,24 @@ nodata:  	return retval;  } +/* Create an Operation Error chunk of a fixed size, + * specifically, max(asoc->pathmtu, SCTP_DEFAULT_MAXSEGMENT) + * This is a helper function to allocate an error chunk for + * for those invalid parameter codes in which we may not want + * to report all the errors, if the incomming chunk is large + */ +static inline struct sctp_chunk *sctp_make_op_error_fixed( +	const struct sctp_association *asoc, +	const struct sctp_chunk *chunk) +{ +	size_t size = asoc ? asoc->pathmtu : 0; + +	if (!size) +		size = SCTP_DEFAULT_MAXSEGMENT; + +	return sctp_make_op_error_space(asoc, chunk, size); +} +  /* Create an Operation Error chunk.  */  struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,  				 const struct sctp_chunk *chunk, @@ -1371,6 +1415,18 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)  	return target;  } +/* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient + * space in the chunk + */ +void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk, +			     int len, const void *data) +{ +	if (skb_tailroom(chunk->skb) > len) +		return sctp_addto_chunk(chunk, len, data); +	else +		return NULL; +} +  /* Append bytes from user space to the end of a chunk.  Will panic if   * chunk is not big enough.   * Returns a kernel err value. @@ -1974,13 +2030,12 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,  		 * returning multiple unknown parameters.  		 */  		if (NULL == *errp) -			*errp = sctp_make_op_error_space(asoc, chunk, -					ntohs(chunk->chunk_hdr->length)); +			*errp = sctp_make_op_error_fixed(asoc, chunk);  		if (*errp) { -			sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, +			sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,  					WORD_ROUND(ntohs(param.p->length))); -			sctp_addto_chunk(*errp, +			sctp_addto_chunk_fixed(*errp,  					WORD_ROUND(ntohs(param.p->length)),  					param.v);  		} else { @@ -3315,21 +3370,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,  	sctp_chunk_free(asconf);  	asoc->addip_last_asconf = NULL; -	/* Send the next asconf chunk from the addip chunk queue. */ -	if (!list_empty(&asoc->addip_chunk_list)) { -		struct list_head *entry = asoc->addip_chunk_list.next; -		asconf = list_entry(entry, struct sctp_chunk, list); - -		list_del_init(entry); - -		/* Hold the chunk until an ASCONF_ACK is received. */ -		sctp_chunk_hold(asconf); -		if (sctp_primitive_ASCONF(asoc, asconf)) -			sctp_chunk_free(asconf); -		else -			asoc->addip_last_asconf = asconf; -	} -  	return retval;  }  |