sctp: Fix oops when sending queued ASCONF chunks
[safe/jmp/linux-2.6] / net / sctp / sm_make_chunk.c
index e45be4e..0fd5b4c 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/inet.h>
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
+#include <linux/slab.h>
 #include <net/sock.h>
 
 #include <linux/skbuff.h>
@@ -100,11 +101,11 @@ int sctp_chunk_iif(const struct sctp_chunk *chunk)
  */
 static const struct sctp_paramhdr ecap_param = {
        SCTP_PARAM_ECN_CAPABLE,
-       __constant_htons(sizeof(struct sctp_paramhdr)),
+       cpu_to_be16(sizeof(struct sctp_paramhdr)),
 };
 static const struct sctp_paramhdr prsctp_param = {
        SCTP_PARAM_FWD_TSN_SUPPORT,
-       __constant_htons(sizeof(struct sctp_paramhdr)),
+       cpu_to_be16(sizeof(struct sctp_paramhdr)),
 };
 
 /* A helper to initialize to initialize an op error inside a
@@ -207,7 +208,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)
@@ -224,7 +226,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
+
        chunksize += vparam_len;
 
        /* Account for AUTH related parameters */
@@ -235,14 +239,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;
 
@@ -252,7 +256,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)
         *
@@ -304,10 +309,12 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        if (sctp_prsctp_enable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sp->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        /* Add SCTP-AUTH chunks to the parameter list */
        if (sctp_auth_enable) {
@@ -332,6 +339,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        sctp_inithdr_t initack;
        struct sctp_chunk *retval;
        union sctp_params addrs;
+       struct sctp_sock *sp;
        int addrs_len;
        sctp_cookie_param_t *cookie;
        int cookie_len;
@@ -366,22 +374,24 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        /* Calculate the total size of allocation, include the reserved
         * space for reporting unknown parameters if it is specified.
         */
+       sp = sctp_sk(asoc->base.sk);
        chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
 
        /* Tell peer that we'll do ECN only if peer advertised such cap.  */
        if (asoc->peer.ecn_capable)
                chunksize += sizeof(ecap_param);
 
-       if (sctp_prsctp_enable)
+       if (asoc->peer.prsctp_capable)
                chunksize += sizeof(prsctp_param);
 
-       if (sctp_addip_enable) {
+       if (asoc->peer.asconf_capable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
                extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
 
        if (asoc->peer.auth_capable) {
                auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
@@ -389,13 +399,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;
 
@@ -404,7 +414,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);
@@ -432,10 +443,12 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.prsctp_capable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        if (asoc->peer.auth_capable) {
                sctp_addto_chunk(retval, ntohs(auth_random->length),
@@ -702,12 +715,14 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
        __u32 ctsn;
        __u16 num_gabs, num_dup_tsns;
        struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
+       struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
 
+       memset(gabs, 0, sizeof(gabs));
        ctsn = sctp_tsnmap_get_ctsn(map);
        SCTP_DEBUG_PRINTK("sackCTSNAck sent:  0x%x.\n", ctsn);
 
        /* How much room is needed in the chunk? */
-       num_gabs = sctp_tsnmap_num_gabs(map);
+       num_gabs = sctp_tsnmap_num_gabs(map, gabs);
        num_dup_tsns = sctp_tsnmap_num_dups(map);
 
        /* Initialize the SACK header.  */
@@ -763,7 +778,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
        /* Add the gap ack block information.   */
        if (num_gabs)
                sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
-                                sctp_tsnmap_get_gabs(map));
+                                gabs);
 
        /* Add the duplicate TSN information.  */
        if (num_dup_tsns)
@@ -976,7 +991,10 @@ static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
 
        target = skb_put(chunk->skb, len);
 
-       memcpy(target, data, len);
+       if (data)
+               memcpy(target, data, len);
+       else
+               memset(target, 0, len);
 
        /* Adjust the chunk length field.  */
        chunk->chunk_hdr->length = htons(chunklen + len);
@@ -1012,6 +1030,29 @@ end:
        return retval;
 }
 
+struct sctp_chunk *sctp_make_violation_paramlen(
+       const struct sctp_association *asoc,
+       const struct sctp_chunk *chunk,
+       struct sctp_paramhdr *param)
+{
+       struct sctp_chunk *retval;
+       static const char error[] = "The following parameter had invalid length:";
+       size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) +
+                               sizeof(sctp_paramhdr_t);
+
+       retval = sctp_make_abort(asoc, chunk, payload_len);
+       if (!retval)
+               goto nodata;
+
+       sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
+                       sizeof(error) + sizeof(sctp_paramhdr_t));
+       sctp_addto_chunk(retval, sizeof(error), error);
+       sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param);
+
+nodata:
+       return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
                                  const struct sctp_transport *transport,
@@ -1095,16 +1136,18 @@ nodata:
 struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
                                 const struct sctp_chunk *chunk,
                                 __be16 cause_code, const void *payload,
-                                size_t paylen)
+                                size_t paylen, size_t reserve_tail)
 {
        struct sctp_chunk *retval;
 
-       retval = sctp_make_op_error_space(asoc, chunk, paylen);
+       retval = sctp_make_op_error_space(asoc, chunk, paylen + reserve_tail);
        if (!retval)
                goto nodata;
 
-       sctp_init_cause(retval, cause_code, paylen);
+       sctp_init_cause(retval, cause_code, paylen + reserve_tail);
        sctp_addto_chunk(retval, paylen, payload);
+       if (reserve_tail)
+               sctp_addto_param(retval, reserve_tail, NULL);
 
 nodata:
        return retval;
@@ -1188,7 +1231,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
         */
        retval->tsn_missing_report = 0;
        retval->tsn_gap_acked = 0;
-       retval->fast_retransmit = 0;
+       retval->fast_retransmit = SCTP_CAN_FRTX;
 
        /* If this is a fragmented message, track all fragments
         * of the message (for SEND_FAILED).
@@ -1782,11 +1825,6 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
                                        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);
-
-
        /* This is a fatal error.  Any accumulated non-fatal errors are
         * not reported.
         */
@@ -1794,14 +1832,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
                sctp_chunk_free(*errp);
 
        /* Create an error chunk and fill it in with our payload. */
-       *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
-
-       if (*errp) {
-               sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
-                               sizeof(error) + sizeof(sctp_paramhdr_t));
-               sctp_addto_chunk(*errp, sizeof(error), error);
-               sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
-       }
+       *errp = sctp_make_violation_paramlen(asoc, chunk, param);
 
        return 0;
 }
@@ -1886,11 +1917,13 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
                            /* if the peer reports AUTH, assume that he
                             * supports AUTH.
                             */
-                           asoc->peer.auth_capable = 1;
+                           if (sctp_auth_enable)
+                                   asoc->peer.auth_capable = 1;
                            break;
                    case SCTP_CID_ASCONF:
                    case SCTP_CID_ASCONF_ACK:
-                           asoc->peer.asconf_capable = 1;
+                           if (sctp_addip_enable)
+                                   asoc->peer.asconf_capable = 1;
                            break;
                    default:
                            break;
@@ -1982,7 +2015,10 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                                        struct sctp_chunk *chunk,
                                        struct sctp_chunk **err_chunk)
 {
+       struct sctp_hmac_algo_param *hmacs;
        int retval = SCTP_IERROR_NO_ERROR;
+       __u16 n_elt, id = 0;
+       int i;
 
        /* FIXME - This routine is not looking at each parameter per the
         * chunk type, i.e., unrecognized parameters should be further
@@ -2056,9 +2092,29 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (sctp_auth_enable)
-                       break;
-               /* Fall Through */
+               if (!sctp_auth_enable)
+                       goto fallthrough;
+
+               hmacs = (struct sctp_hmac_algo_param *)param.p;
+               n_elt = (ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) >> 1;
+
+               /* SCTP-AUTH: Section 6.1
+                * The HMAC algorithm based on SHA-1 MUST be supported and
+                * included in the HMAC-ALGO parameter.
+                */
+               for (i = 0; i < n_elt; i++) {
+                       id = ntohs(hmacs->hmac_ids[i]);
+
+                       if (id == SCTP_AUTH_HMAC_ID_SHA1)
+                               break;
+               }
+
+               if (id != SCTP_AUTH_HMAC_ID_SHA1) {
+                       sctp_process_inv_paramlength(asoc, param.p, chunk,
+                                                    err_chunk);
+                       retval = SCTP_IERROR_ABORT;
+               }
+               break;
 fallthrough:
        default:
                SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
@@ -2246,14 +2302,15 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
         * high (for example, implementations MAY use the size of the receiver
         * advertised window).
         */
-       list_for_each(pos, &asoc->peer.transport_addr_list) {
-               transport = list_entry(pos, struct sctp_transport, transports);
+       list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+                       transports) {
                transport->ssthresh = asoc->peer.i.a_rwnd;
        }
 
        /* Set up the TSN tracking pieces.  */
-       sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
-                        asoc->peer.i.initial_tsn);
+       if (!sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
+                               asoc->peer.i.initial_tsn, gfp))
+               goto clean_up;
 
        /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
         *
@@ -2296,12 +2353,10 @@ clean_up:
        /* Release the transport structures. */
        list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
                transport = list_entry(pos, struct sctp_transport, transports);
-               list_del_init(pos);
-               sctp_transport_free(transport);
+               if (transport->state != SCTP_ACTIVE)
+                       sctp_assoc_rm_peer(asoc, transport);
        }
 
-       asoc->peer.transport_count = 0;
-
 nomem:
        return 0;
 }
@@ -2341,8 +2396,13 @@ static int sctp_process_param(struct sctp_association *asoc,
        case SCTP_PARAM_IPV6_ADDRESS:
                if (PF_INET6 != asoc->base.sk->sk_family)
                        break;
-               /* Fall through. */
+               goto do_addr_param;
+
        case SCTP_PARAM_IPV4_ADDRESS:
+               /* v4 addresses are not allowed on v6-only socket */
+               if (ipv6_only_sock(asoc->base.sk))
+                       break;
+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);
@@ -2375,6 +2435,14 @@ static int sctp_process_param(struct sctp_association *asoc,
                asoc->peer.ipv4_address = 0;
                asoc->peer.ipv6_address = 0;
 
+               /* Assume that peer supports the address family
+                * by which it sends a packet.
+                */
+               if (peer_addr->sa.sa_family == AF_INET6)
+                       asoc->peer.ipv6_address = 1;
+               else if (peer_addr->sa.sa_family == AF_INET)
+                       asoc->peer.ipv4_address = 1;
+
                /* Cycle through address types; avoid divide by 0. */
                sat = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
                if (sat)
@@ -2387,7 +2455,8 @@ static int sctp_process_param(struct sctp_association *asoc,
                                break;
 
                        case SCTP_PARAM_IPV6_ADDRESS:
-                               asoc->peer.ipv6_address = 1;
+                               if (PF_INET6 == asoc->base.sk->sk_family)
+                                       asoc->peer.ipv6_address = 1;
                                break;
 
                        case SCTP_PARAM_HOST_NAME_ADDRESS:
@@ -2419,10 +2488,13 @@ static int sctp_process_param(struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_ADAPTATION_LAYER_IND:
-               asoc->peer.adaptation_ind = param.aind->adaptation_ind;
+               asoc->peer.adaptation_ind = ntohl(param.aind->adaptation_ind);
                break;
 
        case SCTP_PARAM_SET_PRIMARY:
+               if (!sctp_addip_enable)
+                       goto fall_through;
+
                addr_param = param.v + sizeof(sctp_addip_param_t);
 
                af = sctp_get_af_specific(param_type2af(param.p->type));
@@ -2798,9 +2870,27 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
        addr_param = (union sctp_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) {
+       case SCTP_PARAM_IPV6_ADDRESS:
+               if (!asoc->peer.ipv6_address)
+                       return SCTP_ERROR_DNS_FAILED;
+               break;
+       case SCTP_PARAM_IPV4_ADDRESS:
+               if (!asoc->peer.ipv4_address)
+                       return SCTP_ERROR_DNS_FAILED;
+               break;
+       default:
+               return SCTP_ERROR_DNS_FAILED;
+       }
+
        af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
        if (unlikely(!af))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
 
@@ -2810,7 +2900,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
         *  make sure we check for that)
         */
        if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        switch (asconf_param->param_hdr.type) {
        case SCTP_PARAM_ADD_IP:
@@ -2878,13 +2968,10 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
 
                peer = sctp_assoc_lookup_paddr(asoc, &addr);
                if (!peer)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
 
                sctp_assoc_set_primary(asoc, peer);
                break;
-       default:
-               return SCTP_ERROR_INV_PARAM;
-               break;
        }
 
        return SCTP_ERROR_NO_ERROR;
@@ -3028,17 +3115,15 @@ done:
 }
 
 /* Process a asconf parameter that is successfully acked. */
-static int sctp_asconf_param_success(struct sctp_association *asoc,
+static void sctp_asconf_param_success(struct sctp_association *asoc,
                                     sctp_addip_param_t *asconf_param)
 {
        struct sctp_af *af;
        union sctp_addr addr;
        struct sctp_bind_addr *bp = &asoc->base.bind_addr;
        union sctp_addr_param *addr_param;
-       struct list_head *pos;
        struct sctp_transport *transport;
        struct sctp_sockaddr_entry *saddr;
-       int retval = 0;
 
        addr_param = (union sctp_addr_param *)
                        ((void *)asconf_param + sizeof(sctp_addip_param_t));
@@ -3058,14 +3143,21 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
                                saddr->state = SCTP_ADDR_SRC;
                }
                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));
+               }
                break;
        case SCTP_PARAM_DEL_IP:
                local_bh_disable();
-               retval = sctp_del_bind_addr(bp, &addr);
+               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);
+               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));
@@ -3074,8 +3166,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
        default:
                break;
        }
-
-       return retval;
 }
 
 /* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
@@ -3192,14 +3282,14 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
 
                switch (err_code) {
                case SCTP_ERROR_NO_ERROR:
-                       retval = sctp_asconf_param_success(asoc, asconf_param);
+                       sctp_asconf_param_success(asoc, asconf_param);
                        break;
 
                case SCTP_ERROR_RSRC_LOW:
                        retval = 1;
                        break;
 
-               case SCTP_ERROR_INV_PARAM:
+               case SCTP_ERROR_UNKNOWN_PARAM:
                        /* Disable sending this type of asconf parameter in
                         * future.
                         */
@@ -3228,21 +3318,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;
 }