diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 565 | 
1 files changed, 324 insertions, 241 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 2cc46f0962c..ae0e616a7ca 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -23,16 +23,12 @@   * See the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING.  If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING.  If not, see + * <http://www.gnu.org/licenses/>.   *   * Please send any bug reports or fixes you make to the   * email address(es): - *    lksctp developers <lksctp-developers@lists.sourceforge.net> - * - * Or submit a bug report through the following website: - *    http://www.sf.net/projects/lksctp + *    lksctp developers <linux-sctp@vger.kernel.org>   *   * Written or modified by:   *    La Monte H.P. Yarroll <piggy@acm.org> @@ -45,9 +41,6 @@   *    Daisy Chang	    <daisyc@us.ibm.com>   *    Ardelle Fan	    <ardelle.fan@intel.com>   *    Kevin Gao             <kevin.gao@intel.com> - * - * Any bugs reported given to us we will try to fix... any fixes shared will - * be incorporated into the next SCTP release.   */  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -68,9 +61,12 @@  #include <net/sctp/sctp.h>  #include <net/sctp/sm.h> -SCTP_STATIC -struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, -				   __u8 type, __u8 flags, int paylen); +static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, +					    __u8 type, __u8 flags, int paylen); +static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, +					 __u8 flags, int paylen); +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, @@ -82,6 +78,30 @@ static int sctp_process_param(struct sctp_association *asoc,  			      gfp_t gfp);  static void *sctp_addto_param(struct sctp_chunk *chunk, int len,  			      const void *data); +static void  *sctp_addto_chunk_fixed(struct sctp_chunk *, int len, +				     const void *data); + +/* Control chunk destructor */ +static void sctp_control_release_owner(struct sk_buff *skb) +{ +	/*TODO: do memory release */ +} + +static void sctp_control_set_owner_w(struct sctp_chunk *chunk) +{ +	struct sctp_association *asoc = chunk->asoc; +	struct sk_buff *skb = chunk->skb; + +	/* TODO: properly account for control chunks. +	 * To do it right we'll need: +	 *  1) endpoint if association isn't known. +	 *  2) proper memory accounting. +	 * +	 *  For now don't do anything for now. +	 */ +	skb->sk = asoc ? asoc->base.sk : NULL; +	skb->destructor = sctp_control_release_owner; +}  /* What was the inbound interface for this chunk? */  int sctp_chunk_iif(const struct sctp_chunk *chunk) @@ -132,7 +152,7 @@ void  sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code,   * 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, +static int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code,  		      size_t paylen)  {  	sctp_errhdr_t err; @@ -198,6 +218,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  			     const struct sctp_bind_addr *bp,  			     gfp_t gfp, int vparam_len)  { +	struct net *net = sock_net(asoc->base.sk); +	struct sctp_endpoint *ep = asoc->ep;  	sctp_inithdr_t init;  	union sctp_params addrs;  	size_t chunksize; @@ -237,7 +259,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types));  	chunksize += sizeof(ecap_param); -	if (sctp_prsctp_enable) +	if (net->sctp.prsctp_enable)  		chunksize += sizeof(prsctp_param);  	/* ADDIP: Section 4.2.7: @@ -245,7 +267,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	 *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and  	 *  INIT-ACK parameters.  	 */ -	if (sctp_addip_enable) { +	if (net->sctp.addip_enable) {  		extensions[num_ext] = SCTP_CID_ASCONF;  		extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;  		num_ext += 2; @@ -257,7 +279,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	chunksize += vparam_len;  	/* Account for AUTH related parameters */ -	if (sctp_auth_enable) { +	if (ep->auth_enable) {  		/* Add random parameter length*/  		chunksize += sizeof(asoc->c.auth_random); @@ -296,7 +318,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	 * PLEASE DO NOT FIXME [This version does not support Host Name.]  	 */ -	retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); +	retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize);  	if (!retval)  		goto nodata; @@ -331,7 +353,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  		sctp_addto_param(retval, num_ext, extensions);  	} -	if (sctp_prsctp_enable) +	if (net->sctp.prsctp_enable)  		sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);  	if (sp->adaptation_ind) { @@ -342,7 +364,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,  	}  	/* Add SCTP-AUTH chunks to the parameter list */ -	if (sctp_auth_enable) { +	if (ep->auth_enable) {  		sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),  				 asoc->c.auth_random);  		if (auth_hmacs) @@ -443,7 +465,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,  					num_ext);  	/* Now allocate and fill out the chunk.  */ -	retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); +	retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize);  	if (!retval)  		goto nomem_chunk; @@ -548,7 +570,7 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,  	cookie_len = asoc->peer.cookie_len;  	/* Build a cookie echo chunk.  */ -	retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); +	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len);  	if (!retval)  		goto nodata;  	retval->subh.cookie_hdr = @@ -593,7 +615,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,  {  	struct sctp_chunk *retval; -	retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); +	retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0);  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints  	 * @@ -641,8 +663,8 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,  	sctp_cwrhdr_t cwr;  	cwr.lowest_tsn = htonl(lowest_tsn); -	retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, -				 sizeof(sctp_cwrhdr_t)); +	retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0, +				   sizeof(sctp_cwrhdr_t));  	if (!retval)  		goto nodata; @@ -675,8 +697,8 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,  	sctp_ecnehdr_t ecne;  	ecne.lowest_tsn = htonl(lowest_tsn); -	retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, -				 sizeof(sctp_ecnehdr_t)); +	retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0, +				   sizeof(sctp_ecnehdr_t));  	if (!retval)  		goto nodata;  	retval->subh.ecne_hdr = @@ -712,7 +734,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,  		dp.ssn = htons(ssn);  	chunk_len = sizeof(dp) + data_len; -	retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); +	retval = sctp_make_data(asoc, flags, chunk_len);  	if (!retval)  		goto nodata; @@ -734,12 +756,15 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)  	int len;  	__u32 ctsn;  	__u16 num_gabs, num_dup_tsns; +	struct sctp_association *aptr = (struct sctp_association *)asoc;  	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;  	struct sctp_gap_ack_block gabs[SCTP_MAX_GABS]; +	struct sctp_transport *trans;  	memset(gabs, 0, sizeof(gabs));  	ctsn = sctp_tsnmap_get_ctsn(map); -	SCTP_DEBUG_PRINTK("sackCTSNAck sent:  0x%x.\n", ctsn); + +	pr_debug("%s: sackCTSNAck sent:0x%x\n", __func__, ctsn);  	/* How much room is needed in the chunk? */  	num_gabs = sctp_tsnmap_num_gabs(map, gabs); @@ -756,7 +781,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)  		+ sizeof(__u32) * num_dup_tsns;  	/* Create the chunk.  */ -	retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len); +	retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len);  	if (!retval)  		goto nodata; @@ -801,10 +826,25 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)  				 gabs);  	/* Add the duplicate TSN information.  */ -	if (num_dup_tsns) +	if (num_dup_tsns) { +		aptr->stats.idupchunks += num_dup_tsns;  		sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,  				 sctp_tsnmap_get_dups(map)); - +	} +	/* Once we have a sack generated, check to see what our sack +	 * generation is, if its 0, reset the transports to 0, and reset +	 * the association generation to 1 +	 * +	 * The idea is that zero is never used as a valid generation for the +	 * association so no transport will match after a wrap event like this, +	 * Until the next sack +	 */ +	if (++aptr->peer.sack_generation == 0) { +		list_for_each_entry(trans, &asoc->peer.transport_addr_list, +				    transports) +			trans->sack_generation = 0; +		aptr->peer.sack_generation = 1; +	}  nodata:  	return retval;  } @@ -820,8 +860,8 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,  	ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);  	shut.cum_tsn_ack = htonl(ctsn); -	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, -				 sizeof(sctp_shutdownhdr_t)); +	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, +				   sizeof(sctp_shutdownhdr_t));  	if (!retval)  		goto nodata; @@ -839,7 +879,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,  {  	struct sctp_chunk *retval; -	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); +	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints  	 * @@ -868,7 +908,7 @@ struct sctp_chunk *sctp_make_shutdown_complete(  	 */  	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; -	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); +	retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints  	 * @@ -907,7 +947,7 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,  			flags = SCTP_CHUNK_FLAG_T;  	} -	retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); +	retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint);  	/* RFC 2960 6.4 Multi-homed SCTP Endpoints  	 * @@ -1073,22 +1113,49 @@ nodata:  	return retval;  } +struct sctp_chunk *sctp_make_violation_max_retrans( +	const struct sctp_association *asoc, +	const struct sctp_chunk *chunk) +{ +	struct sctp_chunk *retval; +	static const char error[] = "Association exceeded its max_retans count"; +	size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t); + +	retval = sctp_make_abort(asoc, chunk, payload_len); +	if (!retval) +		goto nodata; + +	sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, sizeof(error)); +	sctp_addto_chunk(retval, sizeof(error), error); + +nodata: +	return retval; +} +  /* Make a HEARTBEAT chunk.  */  struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, -				  const struct sctp_transport *transport, -				  const void *payload, const size_t paylen) +				  const struct sctp_transport *transport)  { -	struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, -						    0, paylen); +	struct sctp_chunk *retval; +	sctp_sender_hb_info_t hbinfo; + +	retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));  	if (!retval)  		goto nodata; +	hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; +	hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); +	hbinfo.daddr = transport->ipaddr; +	hbinfo.sent_at = jiffies; +	hbinfo.hb_nonce = transport->hb_nonce; +  	/* Cast away the 'const', as this is just telling the chunk  	 * what transport it belongs to.  	 */  	retval->transport = (struct sctp_transport *) transport; -	retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); +	retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo), +						&hbinfo);  nodata:  	return retval; @@ -1100,7 +1167,7 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,  {  	struct sctp_chunk *retval; -	retval  = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); +	retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);  	if (!retval)  		goto nodata; @@ -1132,8 +1199,8 @@ static struct sctp_chunk *sctp_make_op_error_space(  {  	struct sctp_chunk *retval; -	retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, -				 sizeof(sctp_errhdr_t) + size); +	retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0, +				   sizeof(sctp_errhdr_t) + size);  	if (!retval)  		goto nodata; @@ -1156,7 +1223,7 @@ nodata:   * 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 + * to report all the errors, if the incoming chunk is large   */  static inline struct sctp_chunk *sctp_make_op_error_fixed(  	const struct sctp_association *asoc, @@ -1203,7 +1270,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)  	if (unlikely(!hmac_desc))  		return NULL; -	retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0, +	retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,  			hmac_desc->hmac_len + sizeof(sctp_authhdr_t));  	if (!retval)  		return NULL; @@ -1232,6 +1299,13 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)  /* Turn an skb into a chunk.   * FIXME: Eventually move the structure directly inside the skb->cb[]. + * + * sctpimpguide-05.txt Section 2.8.2 + * M1) Each time a new DATA chunk is transmitted + * set the 'TSN.Missing.Report' count for that TSN to 0. The + * 'TSN.Missing.Report' count will be used to determine missing chunks + * and when to fast retransmit. + *   */  struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,  			    const struct sctp_association *asoc, @@ -1243,37 +1317,15 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,  	if (!retval)  		goto nodata; - -	if (!sk) { -		SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); -	} +	if (!sk) +		pr_debug("%s: chunkifying skb:%p w/o an sk\n", __func__, skb);  	INIT_LIST_HEAD(&retval->list);  	retval->skb		= skb;  	retval->asoc		= (struct sctp_association *)asoc; -	retval->has_tsn		= 0; -	retval->has_ssn         = 0; -	retval->rtt_in_progress	= 0; -	retval->sent_at		= 0;  	retval->singleton	= 1; -	retval->end_of_packet	= 0; -	retval->ecn_ce_done	= 0; -	retval->pdiscard	= 0; - -	/* sctpimpguide-05.txt Section 2.8.2 -	 * M1) Each time a new DATA chunk is transmitted -	 * set the 'TSN.Missing.Report' count for that TSN to 0. The -	 * 'TSN.Missing.Report' count will be used to determine missing chunks -	 * and when to fast retransmit. -	 */ -	retval->tsn_missing_report = 0; -	retval->tsn_gap_acked = 0; -	retval->fast_retransmit = SCTP_CAN_FRTX; -	/* If this is a fragmented message, track all fragments -	 * of the message (for SEND_FAILED). -	 */ -	retval->msg = NULL; +	retval->fast_retransmit = SCTP_CAN_FRTX;  	/* Polish the bead hole.  */  	INIT_LIST_HEAD(&retval->transmitted_list); @@ -1308,9 +1360,8 @@ 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) +static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, +					    __u8 type, __u8 flags, int paylen)  {  	struct sctp_chunk *retval;  	sctp_chunkhdr_t *chunk_hdr; @@ -1343,14 +1394,27 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,  	if (sctp_auth_send_cid(type, asoc))  		retval->auth = 1; -	/* Set the skb to the belonging sock for accounting.  */ -	skb->sk = sk; -  	return retval;  nodata:  	return NULL;  } +static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, +					 __u8 flags, int paylen) +{ +	return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen); +} + +static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, +					    __u8 type, __u8 flags, int paylen) +{ +	struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen); + +	if (chunk) +		sctp_control_set_owner_w(chunk); + +	return chunk; +}  /* Release the memory occupied by a chunk.  */  static void sctp_chunk_destroy(struct sctp_chunk *chunk) @@ -1358,8 +1422,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)  	BUG_ON(!list_empty(&chunk->list));  	list_del_init(&chunk->transmitted_list); -	/* Free the chunk skb data and the SCTP_chunk stub itself. */ -	dev_kfree_skb(chunk->skb); +	consume_skb(chunk->skb); +	consume_skb(chunk->auth_chunk);  	SCTP_DBG_OBJCNT_DEC(chunk);  	kmem_cache_free(sctp_chunk_cachep, chunk); @@ -1414,8 +1478,8 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)  /* 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) +static 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); @@ -1544,8 +1608,6 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,  	struct sctp_signed_cookie *cookie;  	struct scatterlist sg;  	int headersize, bodysize; -	unsigned int keylen; -	char *key;  	/* Header size is static data prior to the actual cookie, including  	 * any padding. @@ -1589,8 +1651,8 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,  	cookie->c.adaptation_ind = asoc->peer.adaptation_ind;  	/* Set an expiration time for the cookie.  */ -	do_gettimeofday(&cookie->c.expiration); -	TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); +	cookie->c.expiration = ktime_add(asoc->cookie_life, +					 ktime_get());  	/* Copy the peer's init packet.  */  	memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, @@ -1605,12 +1667,11 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,  		/* Sign the message.  */  		sg_init_one(&sg, &cookie->c, bodysize); -		keylen = SCTP_SECRET_SIZE; -		key = (char *)ep->secret_key[ep->current_key];  		desc.tfm = sctp_sk(ep->base.sk)->hmac;  		desc.flags = 0; -		if (crypto_hash_setkey(desc.tfm, key, keylen) || +		if (crypto_hash_setkey(desc.tfm, ep->secret_key, +				       sizeof(ep->secret_key)) ||  		    crypto_hash_digest(&desc, &sg, bodysize, cookie->signature))  			goto free_cookie;  	} @@ -1637,11 +1698,10 @@ struct sctp_association *sctp_unpack_cookie(  	int headersize, bodysize, fixed_size;  	__u8 *digest = ep->digest;  	struct scatterlist sg; -	unsigned int keylen, len; -	char *key; +	unsigned int len;  	sctp_scope_t scope;  	struct sk_buff *skb = chunk->skb; -	struct timeval tv; +	ktime_t kt;  	struct hash_desc desc;  	/* Header size is static data prior to the actual cookie, including @@ -1673,34 +1733,21 @@ struct sctp_association *sctp_unpack_cookie(  		goto no_hmac;  	/* Check the signature.  */ -	keylen = SCTP_SECRET_SIZE;  	sg_init_one(&sg, bear_cookie, bodysize); -	key = (char *)ep->secret_key[ep->current_key];  	desc.tfm = sctp_sk(ep->base.sk)->hmac;  	desc.flags = 0;  	memset(digest, 0x00, SCTP_SIGNATURE_SIZE); -	if (crypto_hash_setkey(desc.tfm, key, keylen) || +	if (crypto_hash_setkey(desc.tfm, ep->secret_key, +			       sizeof(ep->secret_key)) ||  	    crypto_hash_digest(&desc, &sg, bodysize, digest)) {  		*error = -SCTP_IERROR_NOMEM;  		goto fail;  	}  	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { -		/* Try the previous key. */ -		key = (char *)ep->secret_key[ep->last_key]; -		memset(digest, 0x00, SCTP_SIGNATURE_SIZE); -		if (crypto_hash_setkey(desc.tfm, key, keylen) || -		    crypto_hash_digest(&desc, &sg, bodysize, digest)) { -			*error = -SCTP_IERROR_NOMEM; -			goto fail; -		} - -		if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { -			/* Yikes!  Still bad signature! */ -			*error = -SCTP_IERROR_BAD_SIG; -			goto fail; -		} +		*error = -SCTP_IERROR_BAD_SIG; +		goto fail;  	}  no_hmac: @@ -1731,11 +1778,11 @@ no_hmac:  	 * down the new association establishment instead of every packet.  	 */  	if (sock_flag(ep->base.sk, SOCK_TIMESTAMP)) -		skb_get_timestamp(skb, &tv); +		kt = skb_get_ktime(skb);  	else -		do_gettimeofday(&tv); +		kt = ktime_get(); -	if (!asoc && tv_lt(bear_cookie->expiration, tv)) { +	if (!asoc && ktime_before(bear_cookie->expiration, kt)) {  		/*  		 * Section 3.3.10.3 Stale Cookie Error (3)  		 * @@ -1747,9 +1794,7 @@ no_hmac:  		len = ntohs(chunk->chunk_hdr->length);  		*errp = sctp_make_op_error_space(asoc, chunk, len);  		if (*errp) { -			suseconds_t usecs = (tv.tv_sec - -				bear_cookie->expiration.tv_sec) * 1000000L + -				tv.tv_usec - bear_cookie->expiration.tv_usec; +			suseconds_t usecs = ktime_to_us(ktime_sub(kt, bear_cookie->expiration));  			__be32 n = htonl(usecs);  			sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, @@ -1916,7 +1961,7 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,  	return 0;  } -static int sctp_verify_ext_param(union sctp_params param) +static int sctp_verify_ext_param(struct net *net, union sctp_params param)  {  	__u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);  	int have_auth = 0; @@ -1925,13 +1970,13 @@ static int sctp_verify_ext_param(union sctp_params param)  	for (i = 0; i < num_ext; i++) {  		switch (param.ext->chunks[i]) { -		    case SCTP_CID_AUTH: -			    have_auth = 1; -			    break; -		    case SCTP_CID_ASCONF: -		    case SCTP_CID_ASCONF_ACK: -			    have_asconf = 1; -			    break; +		case SCTP_CID_AUTH: +			have_auth = 1; +			break; +		case SCTP_CID_ASCONF: +		case SCTP_CID_ASCONF_ACK: +			have_asconf = 1; +			break;  		}  	} @@ -1940,10 +1985,10 @@ static int sctp_verify_ext_param(union sctp_params param)  	 * only if ADD-IP is turned on and we are not backward-compatible  	 * mode.  	 */ -	if (sctp_addip_noauth) +	if (net->sctp.addip_noauth)  		return 1; -	if (sctp_addip_enable && !have_auth && have_asconf) +	if (net->sctp.addip_enable && !have_auth && have_asconf)  		return 0;  	return 1; @@ -1952,30 +1997,30 @@ static int sctp_verify_ext_param(union sctp_params param)  static void sctp_process_ext_param(struct sctp_association *asoc,  				    union sctp_params param)  { +	struct net *net = sock_net(asoc->base.sk);  	__u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);  	int i;  	for (i = 0; i < num_ext; i++) {  		switch (param.ext->chunks[i]) { -		    case SCTP_CID_FWD_TSN: -			    if (sctp_prsctp_enable && -				!asoc->peer.prsctp_capable) +		case SCTP_CID_FWD_TSN: +			if (net->sctp.prsctp_enable && !asoc->peer.prsctp_capable)  				    asoc->peer.prsctp_capable = 1; -			    break; -		    case SCTP_CID_AUTH: -			    /* if the peer reports AUTH, assume that he -			     * supports AUTH. -			     */ -			    if (sctp_auth_enable) -				    asoc->peer.auth_capable = 1; -			    break; -		    case SCTP_CID_ASCONF: -		    case SCTP_CID_ASCONF_ACK: -			    if (sctp_addip_enable) -				    asoc->peer.asconf_capable = 1; -			    break; -		    default: -			    break; +			break; +		case SCTP_CID_AUTH: +			/* if the peer reports AUTH, assume that he +			 * supports AUTH. +			 */ +			if (asoc->ep->auth_enable) +				asoc->peer.auth_capable = 1; +			break; +		case SCTP_CID_ASCONF: +		case SCTP_CID_ASCONF_ACK: +			if (net->sctp.addip_enable) +				asoc->peer.asconf_capable = 1; +			break; +		default: +			break;  		}  	}  } @@ -2029,11 +2074,11 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,  			*errp = sctp_make_op_error_fixed(asoc, chunk);  		if (*errp) { -			sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, -					WORD_ROUND(ntohs(param.p->length))); -			sctp_addto_chunk_fixed(*errp, -					WORD_ROUND(ntohs(param.p->length)), -					param.v); +			if (!sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM, +					WORD_ROUND(ntohs(param.p->length)))) +				sctp_addto_chunk_fixed(*errp, +						WORD_ROUND(ntohs(param.p->length)), +						param.v);  		} else {  			/* If there is no memory for generating the ERROR  			 * report as specified, an ABORT will be triggered @@ -2057,7 +2102,9 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,   *	SCTP_IERROR_ERROR - stop processing, trigger an ERROR   * 	SCTP_IERROR_NO_ERROR - continue with the chunk   */ -static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc, +static sctp_ierror_t sctp_verify_param(struct net *net, +					const struct sctp_endpoint *ep, +					const struct sctp_association *asoc,  					union sctp_params param,  					sctp_cid_t cid,  					struct sctp_chunk *chunk, @@ -2086,12 +2133,12 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,  		break;  	case SCTP_PARAM_SUPPORTED_EXT: -		if (!sctp_verify_ext_param(param)) +		if (!sctp_verify_ext_param(net, param))  			return SCTP_IERROR_ABORT;  		break;  	case SCTP_PARAM_SET_PRIMARY: -		if (sctp_addip_enable) +		if (net->sctp.addip_enable)  			break;  		goto fallthrough; @@ -2102,12 +2149,12 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,  		break;  	case SCTP_PARAM_FWD_TSN_SUPPORT: -		if (sctp_prsctp_enable) +		if (net->sctp.prsctp_enable)  			break;  		goto fallthrough;  	case SCTP_PARAM_RANDOM: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fallthrough;  		/* SCTP-AUTH: Secion 6.1 @@ -2124,7 +2171,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,  		break;  	case SCTP_PARAM_CHUNKS: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fallthrough;  		/* SCTP-AUTH: Section 3.2 @@ -2140,7 +2187,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,  		break;  	case SCTP_PARAM_HMAC_ALGO: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fallthrough;  		hmacs = (struct sctp_hmac_algo_param *)param.p; @@ -2165,8 +2212,9 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,  		break;  fallthrough:  	default: -		SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", -				ntohs(param.p->type), cid); +		pr_debug("%s: unrecognized param:%d for chunk:%d\n", +			 __func__, ntohs(param.p->type), cid); +  		retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);  		break;  	} @@ -2174,32 +2222,29 @@ fallthrough:  }  /* Verify the INIT packet before we process it.  */ -int sctp_verify_init(const struct sctp_association *asoc, -		     sctp_cid_t cid, -		     sctp_init_chunk_t *peer_init, -		     struct sctp_chunk *chunk, +int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep, +		     const struct sctp_association *asoc, sctp_cid_t cid, +		     sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk,  		     struct sctp_chunk **errp)  {  	union sctp_params param; -	int has_cookie = 0; +	bool has_cookie = false;  	int result; -	/* Verify stream values are non-zero. */ -	if ((0 == peer_init->init_hdr.num_outbound_streams) || -	    (0 == peer_init->init_hdr.num_inbound_streams) || -	    (0 == peer_init->init_hdr.init_tag) || -	    (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) { - +	/* Check for missing mandatory parameters. Note: Initial TSN is +	 * also mandatory, but is not checked here since the valid range +	 * is 0..2**32-1. RFC4960, section 3.3.3. +	 */ +	if (peer_init->init_hdr.num_outbound_streams == 0 || +	    peer_init->init_hdr.num_inbound_streams == 0 || +	    peer_init->init_hdr.init_tag == 0 || +	    ntohl(peer_init->init_hdr.a_rwnd) < SCTP_DEFAULT_MINWINDOW)  		return sctp_process_inv_mandatory(asoc, chunk, errp); -	} -	/* 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) */ +		if (param.p->type == SCTP_PARAM_STATE_COOKIE) +			has_cookie = true; +	}  	/* There is a possibility that a parameter length was bad and  	 * in that case we would have stoped walking the parameters. @@ -2208,7 +2253,7 @@ int sctp_verify_init(const struct sctp_association *asoc,  	 * 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) +	if (param.v != (void *)chunk->chunk_end)  		return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);  	/* The only missing mandatory param possible today is @@ -2220,17 +2265,17 @@ int sctp_verify_init(const struct sctp_association *asoc,  	/* Verify all the variable length parameters */  	sctp_walk_params(param, peer_init, init_hdr.params) { - -		result = sctp_verify_param(asoc, param, cid, chunk, errp); +		result = sctp_verify_param(net, ep, asoc, param, cid, +					   chunk, errp);  		switch (result) { -		    case SCTP_IERROR_ABORT: -		    case SCTP_IERROR_NOMEM: -				return 0; -		    case SCTP_IERROR_ERROR: -				return 1; -		    case SCTP_IERROR_NO_ERROR: -		    default: -				break; +		case SCTP_IERROR_ABORT: +		case SCTP_IERROR_NOMEM: +			return 0; +		case SCTP_IERROR_ERROR: +			return 1; +		case SCTP_IERROR_NO_ERROR: +		default: +			break;  		}  	} /* for (loop through all parameters) */ @@ -2242,14 +2287,18 @@ int sctp_verify_init(const struct sctp_association *asoc,   * Returns 0 on failure, else success.   * FIXME:  This is an association method.   */ -int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,  		      const union sctp_addr *peer_addr,  		      sctp_init_chunk_t *peer_init, gfp_t gfp)  { +	struct net *net = sock_net(asoc->base.sk);  	union sctp_params param;  	struct sctp_transport *transport;  	struct list_head *pos, *temp; +	struct sctp_af *af; +	union sctp_addr addr;  	char *cookie; +	int src_match = 0;  	/* We must include the address that the INIT packet came from.  	 * This is the only address that matters for an INIT packet. @@ -2261,18 +2310,31 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,  	 * added as the primary transport.  The source address seems to  	 * be a a better choice than any of the embedded addresses.  	 */ -	if (peer_addr) { -		if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) -			goto nomem; -	} +	if (!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE)) +		goto nomem; + +	if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr)) +		src_match = 1;  	/* Process the initialization parameters.  */  	sctp_walk_params(param, peer_init, init_hdr.params) { +		if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS || +		    param.p->type == SCTP_PARAM_IPV6_ADDRESS)) { +			af = sctp_get_af_specific(param_type2af(param.p->type)); +			af->from_addr_param(&addr, param.addr, +					    chunk->sctp_hdr->source, 0); +			if (sctp_cmp_addr_exact(sctp_source(chunk), &addr)) +				src_match = 1; +		}  		if (!sctp_process_param(asoc, param, peer_addr, gfp))  			goto clean_up;  	} +	/* source address of chunk may not match any valid address */ +	if (!src_match) +		goto clean_up; +  	/* AUTH: After processing the parameters, make sure that we  	 * have all the required info to potentially do authentications.  	 */ @@ -2286,7 +2348,7 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,  	 * also give us an option to silently ignore the packet, which  	 * is what we'll do here.  	 */ -	if (!sctp_addip_noauth && +	if (!net->sctp.addip_noauth &&  	     (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {  		asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |  						  SCTP_PARAM_DEL_IP | @@ -2426,6 +2488,7 @@ static int sctp_process_param(struct sctp_association *asoc,  			      const union sctp_addr *peer_addr,  			      gfp_t gfp)  { +	struct net *net = sock_net(asoc->base.sk);  	union sctp_addr addr;  	int i;  	__u16 sat; @@ -2435,6 +2498,7 @@ static int sctp_process_param(struct sctp_association *asoc,  	struct sctp_af *af;  	union sctp_addr_param *addr_param;  	struct sctp_transport *t; +	struct sctp_endpoint *ep = asoc->ep;  	/* We maintain all INIT parameters in network byte order all the  	 * time.  This allows us to not worry about whether the parameters @@ -2454,13 +2518,13 @@ do_addr_param:  		af = sctp_get_af_specific(param_type2af(param.p->type));  		af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);  		scope = sctp_scope(peer_addr); -		if (sctp_in_scope(&addr, scope)) +		if (sctp_in_scope(net, &addr, scope))  			if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))  				return 0;  		break;  	case SCTP_PARAM_COOKIE_PRESERVATIVE: -		if (!sctp_cookie_preserve_enable) +		if (!net->sctp.cookie_preserve_enable)  			break;  		stale = ntohl(param.life->lifespan_increment); @@ -2468,12 +2532,11 @@ do_addr_param:  		/* Suggested Cookie Life span increment's unit is msec,  		 * (1/1000sec).  		 */ -		asoc->cookie_life.tv_sec += stale / 1000; -		asoc->cookie_life.tv_usec += (stale % 1000) * 1000; +		asoc->cookie_life = ktime_add_ms(asoc->cookie_life, stale);  		break;  	case SCTP_PARAM_HOST_NAME_ADDRESS: -		SCTP_DEBUG_PRINTK("unimplemented SCTP_HOST_NAME_ADDRESS\n"); +		pr_debug("%s: unimplemented SCTP_HOST_NAME_ADDRESS\n", __func__);  		break;  	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: @@ -2540,7 +2603,7 @@ do_addr_param:  		break;  	case SCTP_PARAM_SET_PRIMARY: -		if (!sctp_addip_enable) +		if (!net->sctp.addip_enable)  			goto fall_through;  		addr_param = param.v + sizeof(sctp_addip_param_t); @@ -2567,7 +2630,7 @@ do_addr_param:  		break;  	case SCTP_PARAM_FWD_TSN_SUPPORT: -		if (sctp_prsctp_enable) { +		if (net->sctp.prsctp_enable) {  			asoc->peer.prsctp_capable = 1;  			break;  		} @@ -2575,7 +2638,7 @@ do_addr_param:  		goto fall_through;  	case SCTP_PARAM_RANDOM: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fall_through;  		/* Save peer's random parameter */ @@ -2588,7 +2651,7 @@ do_addr_param:  		break;  	case SCTP_PARAM_HMAC_ALGO: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fall_through;  		/* Save peer's HMAC list */ @@ -2604,7 +2667,7 @@ do_addr_param:  		break;  	case SCTP_PARAM_CHUNKS: -		if (!sctp_auth_enable) +		if (!ep->auth_enable)  			goto fall_through;  		asoc->peer.peer_chunks = kmemdup(param.p, @@ -2619,8 +2682,8 @@ fall_through:  		 * called prior to this routine.  Simply log the error  		 * here.  		 */ -		SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", -				  ntohs(param.p->type), asoc); +		pr_debug("%s: ignoring param:%d for association:%p.\n", +			 __func__, ntohs(param.p->type), asoc);  		break;  	} @@ -2690,7 +2753,7 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,  	length += addrlen;  	/* Create the chunk.  */ -	retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length); +	retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length);  	if (!retval)  		return NULL; @@ -2744,11 +2807,12 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,  	int			addr_param_len = 0;  	int 			totallen = 0;  	int 			i; +	int			del_pickup = 0;  	/* Get total length of all the address parameters. */  	addr_buf = addrs;  	for (i = 0; i < addrcnt; i++) { -		addr = (union sctp_addr *)addr_buf; +		addr = addr_buf;  		af = sctp_get_af_specific(addr->v4.sin_family);  		addr_param_len = af->to_addr_param(addr, &addr_param); @@ -2756,6 +2820,16 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,  		totallen += addr_param_len;  		addr_buf += af->sockaddr_len; +		if (asoc->asconf_addr_del_pending && !del_pickup) { +			/* reuse the parameter length from the same scope one */ +			totallen += paramlen; +			totallen += addr_param_len; +			del_pickup = 1; + +			pr_debug("%s: picked same-scope del_pending addr, " +				 "totallen for all addresses is %d\n", +				 __func__, totallen); +		}  	}  	/* Create an asconf chunk with the required length. */ @@ -2766,7 +2840,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,  	/* Add the address parameters to the asconf chunk. */  	addr_buf = addrs;  	for (i = 0; i < addrcnt; i++) { -		addr = (union sctp_addr *)addr_buf; +		addr = addr_buf;  		af = sctp_get_af_specific(addr->v4.sin_family);  		addr_param_len = af->to_addr_param(addr, &addr_param);  		param.param_hdr.type = flags; @@ -2778,6 +2852,17 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,  		addr_buf += af->sockaddr_len;  	} +	if (flags == SCTP_PARAM_ADD_IP && del_pickup) { +		addr = asoc->asconf_addr_del_pending; +		af = sctp_get_af_specific(addr->v4.sin_family); +		addr_param_len = af->to_addr_param(addr, &addr_param); +		param.param_hdr.type = SCTP_PARAM_DEL_IP; +		param.param_hdr.length = htons(paramlen + addr_param_len); +		param.crr_id = i; + +		sctp_addto_chunk(retval, paramlen, ¶m); +		sctp_addto_chunk(retval, addr_param_len, &addr_param); +	}  	return retval;  } @@ -2852,7 +2937,7 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as  	int			length = sizeof(asconf) + vparam_len;  	/* Create the chunk.  */ -	retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length); +	retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length);  	if (!retval)  		return NULL; @@ -2915,15 +3000,14 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,  	union sctp_addr	addr;  	union sctp_addr_param *addr_param; -	addr_param = (union sctp_addr_param *) -			((void *)asconf_param + sizeof(sctp_addip_param_t)); +	addr_param = (void *)asconf_param + sizeof(sctp_addip_param_t);  	if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&  	    asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&  	    asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)  		return SCTP_ERROR_UNKNOWN_PARAM; -	switch (addr_param->v4.param_hdr.type) { +	switch (addr_param->p.type) {  	case SCTP_PARAM_IPV6_ADDRESS:  		if (!asoc->peer.ipv6_address)  			return SCTP_ERROR_DNS_FAILED; @@ -2936,7 +3020,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,  		return SCTP_ERROR_DNS_FAILED;  	} -	af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); +	af = sctp_get_af_specific(param_type2af(addr_param->p.type));  	if (unlikely(!af))  		return SCTP_ERROR_DNS_FAILED; @@ -2973,6 +3057,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,  		/* Start the heartbeat timer. */  		if (!mod_timer(&peer->hb_timer, sctp_transport_timeout(peer)))  			sctp_transport_hold(peer); +		asoc->new_transport = peer;  		break;  	case SCTP_PARAM_DEL_IP:  		/* ADDIP 4.3 D7) If a request is received to delete the @@ -2990,7 +3075,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,  		 * an Error Cause TLV set to the new error code 'Request to  		 * Delete Source IP Address'  		 */ -		if (sctp_cmp_addr_exact(sctp_source(asconf), &addr)) +		if (sctp_cmp_addr_exact(&asconf->source, &addr))  			return SCTP_ERROR_DEL_SRC_IP;  		/* Section 4.2.2 @@ -3100,16 +3185,16 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,  	/* Skip the address parameter and store a pointer to the first  	 * asconf parameter.  	 */ -	length = ntohs(addr_param->v4.param_hdr.length); -	asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); +	length = ntohs(addr_param->p.length); +	asconf_param = (void *)addr_param + length;  	chunk_len -= length;  	/* create an ASCONF_ACK chunk.  	 * Based on the definitions of parameters, we know that the size of -	 * ASCONF_ACK parameters are less than or equal to the twice of ASCONF +	 * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF  	 * parameters.  	 */ -	asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 2); +	asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);  	if (!asconf_ack)  		goto done; @@ -3142,8 +3227,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,  		/* Move to the next ASCONF param. */  		length = ntohs(asconf_param->param_hdr.length); -		asconf_param = (sctp_addip_param_t *)((void *)asconf_param + -						      length); +		asconf_param = (void *)asconf_param + length;  		chunk_len -= length;  	} @@ -3173,11 +3257,10 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,  	struct sctp_transport *transport;  	struct sctp_sockaddr_entry *saddr; -	addr_param = (union sctp_addr_param *) -			((void *)asconf_param + sizeof(sctp_addip_param_t)); +	addr_param = (void *)asconf_param + sizeof(sctp_addip_param_t);  	/* We have checked the packet before, so we do not check again.	*/ -	af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); +	af = sctp_get_af_specific(param_type2af(addr_param->p.type));  	af->from_addr_param(&addr, addr_param, htons(bp->port), 0);  	switch (asconf_param->param_hdr.type) { @@ -3193,22 +3276,23 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,  		local_bh_enable();  		list_for_each_entry(transport, &asoc->peer.transport_addr_list,  				transports) { -			if (transport->state == SCTP_ACTIVE) -				continue;  			dst_release(transport->dst); -			sctp_transport_route(transport, NULL, -					     sctp_sk(asoc->base.sk)); +			transport->dst = NULL;  		}  		break;  	case SCTP_PARAM_DEL_IP:  		local_bh_disable();  		sctp_del_bind_addr(bp, &addr); +		if (asoc->asconf_addr_del_pending != NULL && +		    sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) { +			kfree(asoc->asconf_addr_del_pending); +			asoc->asconf_addr_del_pending = NULL; +		}  		local_bh_enable();  		list_for_each_entry(transport, &asoc->peer.transport_addr_list,  				transports) {  			dst_release(transport->dst); -			sctp_transport_route(transport, NULL, -					     sctp_sk(asoc->base.sk)); +			transport->dst = NULL;  		}  		break;  	default: @@ -3253,13 +3337,12 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,  	while (asconf_ack_len > 0) {  		if (asconf_ack_param->crr_id == asconf_param->crr_id) { -			switch(asconf_ack_param->param_hdr.type) { +			switch (asconf_ack_param->param_hdr.type) {  			case SCTP_PARAM_SUCCESS_REPORT:  				return SCTP_ERROR_NO_ERROR;  			case SCTP_PARAM_ERR_CAUSE:  				length = sizeof(sctp_addip_param_t); -				err_param = (sctp_errhdr_t *) -					   ((void *)asconf_ack_param + length); +				err_param = (void *)asconf_ack_param + length;  				asconf_ack_len -= length;  				if (asconf_ack_len > 0)  					return err_param->cause; @@ -3272,8 +3355,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,  		}  		length = ntohs(asconf_ack_param->param_hdr.length); -		asconf_ack_param = (sctp_addip_param_t *) -					((void *)asconf_ack_param + length); +		asconf_ack_param = (void *)asconf_ack_param + length;  		asconf_ack_len -= length;  	} @@ -3304,8 +3386,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,  	/* Skip the address parameter in the last asconf sent and store a  	 * pointer to the first asconf parameter.  	 */ -	length = ntohs(addr_param->v4.param_hdr.length); -	asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); +	length = ntohs(addr_param->p.length); +	asconf_param = (void *)addr_param + length;  	asconf_len -= length;  	/* ADDIP 4.1 @@ -3356,11 +3438,15 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,  		 * one.  		 */  		length = ntohs(asconf_param->param_hdr.length); -		asconf_param = (sctp_addip_param_t *)((void *)asconf_param + -						      length); +		asconf_param = (void *)asconf_param + length;  		asconf_len -= length;  	} +	if (no_err && asoc->src_out_of_asoc_ok) { +		asoc->src_out_of_asoc_ok = 0; +		sctp_transport_immediate_rtx(asoc->peer.primary_path); +	} +  	/* Free the cached last sent asconf chunk. */  	list_del_init(&asconf->transmitted_list);  	sctp_chunk_free(asconf); @@ -3375,7 +3461,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,  				    struct sctp_fwdtsn_skip *skiplist)  {  	struct sctp_chunk *retval = NULL; -	struct sctp_fwdtsn_chunk *ftsn_chunk;  	struct sctp_fwdtsn_hdr ftsn_hdr;  	struct sctp_fwdtsn_skip skip;  	size_t hint; @@ -3383,13 +3468,11 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,  	hint = (nstreams + 1) * sizeof(__u32); -	retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint); +	retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint);  	if (!retval)  		return NULL; -	ftsn_chunk = (struct sctp_fwdtsn_chunk *)retval->subh.fwdtsn_hdr; -  	ftsn_hdr.new_cum_tsn = htonl(new_cum_tsn);  	retval->subh.fwdtsn_hdr =  		sctp_addto_chunk(retval, sizeof(ftsn_hdr), &ftsn_hdr);  | 
