summaryrefslogtreecommitdiff
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.c335
1 files changed, 221 insertions, 114 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index c377e4e8f653..77383e9b3988 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -77,6 +77,8 @@ static int sctp_process_param(struct sctp_association *asoc,
union sctp_params param,
const union sctp_addr *peer_addr,
gfp_t gfp);
+static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
+ const void *data);
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
@@ -207,11 +209,10 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
chunksize += sizeof(ecap_param);
- if (sctp_prsctp_enable) {
+
+ if (sctp_prsctp_enable)
chunksize += sizeof(prsctp_param);
- extensions[num_ext] = SCTP_CID_FWD_TSN;
- num_ext += 1;
- }
+
/* ADDIP: Section 4.2.7:
* An implementation supporting this extension [ADDIP] MUST list
* the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and
@@ -243,7 +244,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
if (auth_chunks->length)
chunksize += ntohs(auth_chunks->length);
else
- auth_hmacs = NULL;
+ auth_chunks = NULL;
extensions[num_ext] = SCTP_CID_AUTH;
num_ext += 1;
@@ -288,7 +289,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
- /* Add the supported extensions paramter. Be nice and add this
+ /* Add the supported extensions parameter. Be nice and add this
* fist before addiding the parameters for the extensions themselves
*/
if (num_ext) {
@@ -297,7 +298,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
htons(sizeof(sctp_supported_ext_param_t) + num_ext);
sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t),
&ext_param);
- sctp_addto_chunk(retval, num_ext, extensions);
+ sctp_addto_param(retval, num_ext, extensions);
}
if (sctp_prsctp_enable)
@@ -371,12 +372,8 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
if (asoc->peer.ecn_capable)
chunksize += sizeof(ecap_param);
- /* Tell peer that we'll do PR-SCTP only if peer advertised. */
- if (asoc->peer.prsctp_capable) {
+ if (sctp_prsctp_enable)
chunksize += sizeof(prsctp_param);
- extensions[num_ext] = SCTP_CID_FWD_TSN;
- num_ext += 1;
- }
if (sctp_addip_enable) {
extensions[num_ext] = SCTP_CID_ASCONF;
@@ -384,7 +381,6 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
num_ext += 2;
}
- chunksize += sizeof(ext_param) + num_ext;
chunksize += sizeof(aiparam);
if (asoc->peer.auth_capable) {
@@ -407,6 +403,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
num_ext += 1;
}
+ if (num_ext)
+ chunksize += 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);
if (!retval)
@@ -428,7 +427,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
htons(sizeof(sctp_supported_ext_param_t) + num_ext);
sctp_addto_chunk(retval, sizeof(sctp_supported_ext_param_t),
&ext_param);
- sctp_addto_chunk(retval, num_ext, extensions);
+ sctp_addto_param(retval, num_ext, extensions);
}
if (asoc->peer.prsctp_capable)
sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
@@ -1276,6 +1275,9 @@ nodata:
/* Release the memory occupied by a chunk. */
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);
@@ -1286,9 +1288,6 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
/* Possibly, free the chunk. */
void sctp_chunk_free(struct sctp_chunk *chunk)
{
- BUG_ON(!list_empty(&chunk->list));
- list_del_init(&chunk->transmitted_list);
-
/* Release our reference on the message tracker. */
if (chunk->msg)
sctp_datamsg_put(chunk->msg);
@@ -1693,8 +1692,8 @@ no_hmac:
/* Also, add the destination address. */
if (list_empty(&retval->base.bind_addr.address_list)) {
- sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1,
- GFP_ATOMIC);
+ sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
+ SCTP_ADDR_SRC, GFP_ATOMIC);
}
retval->next_tsn = retval->c.initial_tsn;
@@ -1788,9 +1787,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
sizeof(sctp_paramhdr_t);
+ /* This is a fatal error. Any accumulated non-fatal errors are
+ * not reported.
+ */
+ if (*errp)
+ sctp_chunk_free(*errp);
+
/* Create an error chunk and fill it in with our payload. */
- if (!*errp)
- *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+ *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
@@ -1813,9 +1817,15 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
{
__u16 len = ntohs(param.p->length);
- /* Make an ERROR chunk. */
- if (!*errp)
- *errp = sctp_make_op_error_space(asoc, chunk, len);
+ /* Processing of the HOST_NAME parameter will generate an
+ * ABORT. If we've accumulated any non-fatal errors, they
+ * would be unrecognized parameters and we should not include
+ * them in the ABORT.
+ */
+ if (*errp)
+ sctp_chunk_free(*errp);
+
+ *errp = sctp_make_op_error_space(asoc, chunk, len);
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len);
@@ -1826,6 +1836,39 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
return 0;
}
+static int sctp_verify_ext_param(union sctp_params param)
+{
+ __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
+ int have_auth = 0;
+ int have_asconf = 0;
+ int i;
+
+ 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;
+ }
+ }
+
+ /* ADD-IP Security: The draft requires us to ABORT or ignore the
+ * INIT/INIT-ACK if ADD-IP is listed, but AUTH is not. Do this
+ * only if ADD-IP is turned on and we are not backward-compatible
+ * mode.
+ */
+ if (sctp_addip_noauth)
+ return 1;
+
+ if (sctp_addip_enable && !have_auth && have_asconf)
+ return 0;
+
+ return 1;
+}
+
static void sctp_process_ext_param(struct sctp_association *asoc,
union sctp_params param)
{
@@ -1847,7 +1890,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
break;
case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK:
- asoc->peer.addip_capable = 1;
+ asoc->peer.asconf_capable = 1;
break;
default:
break;
@@ -1862,56 +1905,40 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
* taken if the processing endpoint does not recognize the
* Parameter Type.
*
- * 00 - Stop processing this SCTP chunk and discard it,
- * do not process any further chunks within it.
+ * 00 - Stop processing this parameter; do not process any further
+ * parameters within this chunk
*
- * 01 - Stop processing this SCTP chunk and discard it,
- * do not process any further chunks within it, and report
- * the unrecognized parameter in an 'Unrecognized
- * Parameter Type' (in either an ERROR or in the INIT ACK).
+ * 01 - Stop processing this parameter, do not process any further
+ * parameters within this chunk, and report the unrecognized
+ * parameter in an 'Unrecognized Parameter' ERROR chunk.
*
* 10 - Skip this parameter and continue processing.
*
* 11 - Skip this parameter and continue processing but
* report the unrecognized parameter in an
- * 'Unrecognized Parameter Type' (in either an ERROR or in
- * the INIT ACK).
+ * 'Unrecognized Parameter' ERROR chunk.
*
* Return value:
- * 0 - discard the chunk
- * 1 - continue with the chunk
+ * SCTP_IERROR_NO_ERROR - continue with the chunk
+ * SCTP_IERROR_ERROR - stop and report an error.
+ * SCTP_IERROR_NOMEME - out of memory.
*/
-static int sctp_process_unk_param(const struct sctp_association *asoc,
- union sctp_params param,
- struct sctp_chunk *chunk,
- struct sctp_chunk **errp)
+static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
+ union sctp_params param,
+ struct sctp_chunk *chunk,
+ struct sctp_chunk **errp)
{
- int retval = 1;
+ int retval = SCTP_IERROR_NO_ERROR;
switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
case SCTP_PARAM_ACTION_DISCARD:
- retval = 0;
- break;
- case SCTP_PARAM_ACTION_DISCARD_ERR:
- retval = 0;
- /* Make an ERROR chunk, preparing enough room for
- * returning multiple unknown parameters.
- */
- if (NULL == *errp)
- *errp = sctp_make_op_error_space(asoc, chunk,
- ntohs(chunk->chunk_hdr->length));
-
- if (*errp) {
- sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
- WORD_ROUND(ntohs(param.p->length)));
- sctp_addto_chunk(*errp,
- WORD_ROUND(ntohs(param.p->length)),
- param.v);
- }
-
+ retval = SCTP_IERROR_ERROR;
break;
case SCTP_PARAM_ACTION_SKIP:
break;
+ case SCTP_PARAM_ACTION_DISCARD_ERR:
+ retval = SCTP_IERROR_ERROR;
+ /* Fall through */
case SCTP_PARAM_ACTION_SKIP_ERR:
/* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters.
@@ -1932,9 +1959,8 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
* to the peer and the association won't be
* established.
*/
- retval = 0;
+ retval = SCTP_IERROR_NOMEM;
}
-
break;
default:
break;
@@ -1943,18 +1969,20 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
return retval;
}
-/* Find unrecognized parameters in the chunk.
+/* Verify variable length parameters
* Return values:
- * 0 - discard the chunk
- * 1 - continue with the chunk
+ * SCTP_IERROR_ABORT - trigger an ABORT
+ * SCTP_IERROR_NOMEM - out of memory (abort)
+ * SCTP_IERROR_ERROR - stop processing, trigger an ERROR
+ * SCTP_IERROR_NO_ERROR - continue with the chunk
*/
-static int sctp_verify_param(const struct sctp_association *asoc,
- union sctp_params param,
- sctp_cid_t cid,
- struct sctp_chunk *chunk,
- struct sctp_chunk **err_chunk)
+static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
+ union sctp_params param,
+ sctp_cid_t cid,
+ struct sctp_chunk *chunk,
+ struct sctp_chunk **err_chunk)
{
- int retval = 1;
+ int retval = SCTP_IERROR_NO_ERROR;
/* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further
@@ -1971,12 +1999,23 @@ static int sctp_verify_param(const struct sctp_association *asoc,
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
case SCTP_PARAM_ADAPTATION_LAYER_IND:
+ break;
+
case SCTP_PARAM_SUPPORTED_EXT:
+ if (!sctp_verify_ext_param(param))
+ return SCTP_IERROR_ABORT;
break;
+ case SCTP_PARAM_SET_PRIMARY:
+ if (sctp_addip_enable)
+ break;
+ goto fallthrough;
+
case SCTP_PARAM_HOST_NAME_ADDRESS:
/* Tell the peer, we won't support this param. */
- return sctp_process_hn_param(asoc, param, chunk, err_chunk);
+ sctp_process_hn_param(asoc, param, chunk, err_chunk);
+ retval = SCTP_IERROR_ABORT;
+ break;
case SCTP_PARAM_FWD_TSN_SUPPORT:
if (sctp_prsctp_enable)
@@ -1993,9 +2032,11 @@ static int sctp_verify_param(const struct sctp_association *asoc,
* cause 'Protocol Violation'.
*/
if (SCTP_AUTH_RANDOM_LENGTH !=
- ntohs(param.p->length) - sizeof(sctp_paramhdr_t))
- return sctp_process_inv_paramlength(asoc, param.p,
+ ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) {
+ sctp_process_inv_paramlength(asoc, param.p,
chunk, err_chunk);
+ retval = SCTP_IERROR_ABORT;
+ }
break;
case SCTP_PARAM_CHUNKS:
@@ -2007,21 +2048,22 @@ static int sctp_verify_param(const struct sctp_association *asoc,
* INIT-ACK chunk if the sender wants to receive authenticated
* chunks. Its maximum length is 260 bytes.
*/
- if (260 < ntohs(param.p->length))
- return sctp_process_inv_paramlength(asoc, param.p,
- chunk, err_chunk);
+ if (260 < ntohs(param.p->length)) {
+ sctp_process_inv_paramlength(asoc, param.p,
+ chunk, err_chunk);
+ retval = SCTP_IERROR_ABORT;
+ }
break;
case SCTP_PARAM_HMAC_ALGO:
- if (!sctp_auth_enable)
+ if (sctp_auth_enable)
break;
/* Fall Through */
fallthrough:
default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid);
- return sctp_process_unk_param(asoc, param, chunk, err_chunk);
-
+ retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
break;
}
return retval;
@@ -2036,6 +2078,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
{
union sctp_params param;
int has_cookie = 0;
+ int result;
/* Verify stream values are non-zero. */
if ((0 == peer_init->init_hdr.num_outbound_streams) ||
@@ -2043,8 +2086,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
(0 == peer_init->init_hdr.init_tag) ||
(SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) {
- sctp_process_inv_mandatory(asoc, chunk, errp);
- return 0;
+ return sctp_process_inv_mandatory(asoc, chunk, errp);
}
/* Check for missing mandatory parameters. */
@@ -2062,29 +2104,29 @@ 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) {
- sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
- return 0;
- }
+ 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
* the state cookie for an INIT-ACK chunk.
*/
- if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) {
- sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
- chunk, errp);
- return 0;
- }
-
- /* Find unrecognized parameters. */
+ if ((SCTP_CID_INIT_ACK == cid) && !has_cookie)
+ return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
+ chunk, errp);
+ /* Verify all the variable length parameters */
sctp_walk_params(param, peer_init, init_hdr.params) {
- if (!sctp_verify_param(asoc, param, cid, chunk, errp)) {
- if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type)
+ result = sctp_verify_param(asoc, param, cid, chunk, errp);
+ switch (result) {
+ case SCTP_IERROR_ABORT:
+ case SCTP_IERROR_NOMEM:
return 0;
- else
+ case SCTP_IERROR_ERROR:
return 1;
+ case SCTP_IERROR_NO_ERROR:
+ default:
+ break;
}
} /* for (loop through all parameters) */
@@ -2134,14 +2176,19 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
!asoc->peer.peer_hmacs))
asoc->peer.auth_capable = 0;
-
- /* If the peer claims support for ADD-IP without support
- * for AUTH, disable support for ADD-IP.
+ /* In a non-backward compatible mode, if the peer claims
+ * support for ADD-IP but not AUTH, the ADD-IP spec states
+ * that we MUST ABORT the association. Section 6. The section
+ * also give us an option to silently ignore the packet, which
+ * is what we'll do here.
*/
- if (asoc->peer.addip_capable && !asoc->peer.auth_capable) {
+ if (!sctp_addip_noauth &&
+ (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
SCTP_PARAM_DEL_IP |
SCTP_PARAM_SET_PRIMARY);
+ asoc->peer.asconf_capable = 0;
+ goto clean_up;
}
/* Walk list of transports, removing transports in the UNKNOWN state. */
@@ -2283,6 +2330,8 @@ static int sctp_process_param(struct sctp_association *asoc,
sctp_scope_t scope;
time_t stale;
struct sctp_af *af;
+ union sctp_addr_param *addr_param;
+ struct sctp_transport *t;
/* We maintain all INIT parameters in network byte order all the
* time. This allows us to not worry about whether the parameters
@@ -2373,6 +2422,26 @@ static int sctp_process_param(struct sctp_association *asoc,
asoc->peer.adaptation_ind = param.aind->adaptation_ind;
break;
+ case SCTP_PARAM_SET_PRIMARY:
+ addr_param = param.v + sizeof(sctp_addip_param_t);
+
+ af = sctp_get_af_specific(param_type2af(param.p->type));
+ af->from_addr_param(&addr, addr_param,
+ htons(asoc->peer.port), 0);
+
+ /* if the address is invalid, we can't process it.
+ * XXX: see spec for what to do.
+ */
+ if (!af->addr_valid(&addr, NULL, NULL))
+ break;
+
+ t = sctp_assoc_lookup_paddr(asoc, &addr);
+ if (!t)
+ break;
+
+ sctp_assoc_set_primary(asoc, t);
+ break;
+
case SCTP_PARAM_SUPPORTED_EXT:
sctp_process_ext_param(asoc, param);
break;
@@ -2724,7 +2793,6 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
struct sctp_transport *peer;
struct sctp_af *af;
union sctp_addr addr;
- struct list_head *pos;
union sctp_addr_param *addr_param;
addr_param = (union sctp_addr_param *)
@@ -2735,8 +2803,24 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
return SCTP_ERROR_INV_PARAM;
af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
+
+ /* ADDIP 4.2.1 This parameter MUST NOT contain a broadcast
+ * or multicast address.
+ * (note: wildcard is permitted and requires special handling so
+ * make sure we check for that)
+ */
+ if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
+ return SCTP_ERROR_INV_PARAM;
+
switch (asconf_param->param_hdr.type) {
case SCTP_PARAM_ADD_IP:
+ /* Section 4.2.1:
+ * If the address 0.0.0.0 or ::0 is provided, the source
+ * address of the packet MUST be added.
+ */
+ if (af->is_any(&addr))
+ memcpy(&addr, &asconf->source, sizeof(addr));
+
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this
* new address to the association, it MUST return an Error
@@ -2758,8 +2842,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
* MUST send an Error Cause TLV with the error cause set to the
* new error code 'Request to Delete Last Remaining IP Address'.
*/
- pos = asoc->peer.transport_addr_list.next;
- if (pos->next == &asoc->peer.transport_addr_list)
+ if (asoc->peer.transport_count == 1)
return SCTP_ERROR_DEL_LAST_IP;
/* ADDIP 4.3 D8) If a request is received to delete an IP
@@ -2772,9 +2855,27 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
if (sctp_cmp_addr_exact(sctp_source(asconf), &addr))
return SCTP_ERROR_DEL_SRC_IP;
- sctp_assoc_del_peer(asoc, &addr);
+ /* Section 4.2.2
+ * If the address 0.0.0.0 or ::0 is provided, all
+ * addresses of the peer except the source address of the
+ * packet MUST be deleted.
+ */
+ if (af->is_any(&addr)) {
+ sctp_assoc_set_primary(asoc, asconf->transport);
+ sctp_assoc_del_nonprimary_peers(asoc,
+ asconf->transport);
+ } else
+ sctp_assoc_del_peer(asoc, &addr);
break;
case SCTP_PARAM_SET_PRIMARY:
+ /* ADDIP Section 4.2.4
+ * If the address 0.0.0.0 or ::0 is provided, the receiver
+ * MAY mark the source address of the packet as its
+ * primary.
+ */
+ if (af->is_any(&addr))
+ memcpy(&addr.v4, sctp_source(asconf), sizeof(addr));
+
peer = sctp_assoc_lookup_paddr(asoc, &addr);
if (!peer)
return SCTP_ERROR_INV_PARAM;
@@ -2848,10 +2949,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
__be16 err_code;
int length = 0;
- int chunk_len = asconf->skb->len;
+ int chunk_len;
__u32 serial;
int all_param_pass = 1;
+ chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
hdr = (sctp_addiphdr_t *)asconf->skb->data;
serial = ntohl(hdr->serial);
@@ -2861,7 +2963,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
chunk_len -= length;
/* Skip the address parameter and store a pointer to the first
- * asconf paramter.
+ * asconf parameter.
*/
length = ntohs(addr_param->v4.param_hdr.length);
asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
@@ -2870,7 +2972,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
/* 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
- * paramters.
+ * parameters.
*/
asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 2);
if (!asconf_ack)
@@ -2917,11 +3019,9 @@ done:
* after freeing the reference to old asconf ack if any.
*/
if (asconf_ack) {
- if (asoc->addip_last_asconf_ack)
- sctp_chunk_free(asoc->addip_last_asconf_ack);
-
sctp_chunk_hold(asconf_ack);
- asoc->addip_last_asconf_ack = asconf_ack;
+ list_add_tail(&asconf_ack->transmitted_list,
+ &asoc->asconf_ack_list);
}
return asconf_ack;
@@ -2952,13 +3052,17 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
/* This is always done in BH context with a socket lock
* held, so the list can not change.
*/
+ local_bh_disable();
list_for_each_entry(saddr, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&saddr->a, &addr))
- saddr->use_as_src = 1;
+ saddr->state = SCTP_ADDR_SRC;
}
+ local_bh_enable();
break;
case SCTP_PARAM_DEL_IP:
- retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh);
+ local_bh_disable();
+ retval = sctp_del_bind_addr(bp, &addr);
+ local_bh_enable();
list_for_each(pos, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
@@ -2990,7 +3094,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
sctp_addip_param_t *asconf_ack_param;
sctp_errhdr_t *err_param;
int length;
- int asconf_ack_len = asconf_ack->skb->len;
+ int asconf_ack_len;
__be16 err_code;
if (no_err)
@@ -2998,6 +3102,9 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
else
err_code = SCTP_ERROR_REQ_REFUSED;
+ asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) -
+ sizeof(sctp_chunkhdr_t);
+
/* Skip the addiphdr from the asconf_ack chunk and store a pointer to
* the first asconf_ack parameter.
*/
@@ -3057,7 +3164,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
asconf_len -= length;
/* Skip the address parameter in the last asconf sent and store a
- * pointer to the first asconf paramter.
+ * pointer to the first asconf parameter.
*/
length = ntohs(addr_param->v4.param_hdr.length);
asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);