summaryrefslogtreecommitdiffstats
path: root/net/sctp/sm_make_chunk.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r--net/sctp/sm_make_chunk.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 58eb27fed4b..81db4e38535 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2768,11 +2768,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);
@@ -2780,6 +2781,13 @@ 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;
+ SCTP_DEBUG_PRINTK("mkasconf_update_ip: picked same-scope del_pending addr, totallen for all addresses is %d\n", totallen);
+ }
}
/* Create an asconf chunk with the required length. */
@@ -2790,7 +2798,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;
@@ -2802,6 +2810,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, &param);
+ sctp_addto_chunk(retval, addr_param_len, &addr_param);
+ }
return retval;
}
@@ -2939,8 +2958,7 @@ 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 &&
@@ -3014,7 +3032,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
@@ -3125,7 +3143,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
* asconf parameter.
*/
length = ntohs(addr_param->p.length);
- asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
+ asconf_param = (void *)addr_param + length;
chunk_len -= length;
/* create an ASCONF_ACK chunk.
@@ -3166,8 +3184,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;
}
@@ -3197,8 +3214,7 @@ 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->p.type));
@@ -3224,6 +3240,11 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
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) {
@@ -3278,8 +3299,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
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;
@@ -3292,8 +3312,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;
}
@@ -3325,7 +3344,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
* pointer to the first asconf parameter.
*/
length = ntohs(addr_param->p.length);
- asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
+ asconf_param = (void *)addr_param + length;
asconf_len -= length;
/* ADDIP 4.1
@@ -3376,11 +3395,13 @@ 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;
+
/* Free the cached last sent asconf chunk. */
list_del_init(&asconf->transmitted_list);
sctp_chunk_free(asconf);