SUNRPC: don't map EKEYEXPIRED to EACCES in call_refreshresult
[linux-3.10.git] / net / sctp / sm_make_chunk.c
index 58eb27f..cf579e7 100644 (file)
@@ -132,7 +132,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 +198,7 @@ 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);
        sctp_inithdr_t init;
        union sctp_params addrs;
        size_t chunksize;
@@ -237,7 +238,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 +246,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 +258,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 (net->sctp.auth_enable) {
                /* Add random parameter length*/
                chunksize += sizeof(asoc->c.auth_random);
 
@@ -331,7 +332,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 +343,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 (net->sctp.auth_enable) {
                sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
                                 asoc->c.auth_random);
                if (auth_hmacs)
@@ -734,8 +735,10 @@ 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);
@@ -801,10 +804,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;
 }
@@ -1073,6 +1091,25 @@ 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)
@@ -1164,7 +1201,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,
@@ -1552,8 +1589,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.
@@ -1613,12 +1648,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;
        }
@@ -1645,8 +1679,7 @@ 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;
@@ -1681,34 +1714,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:
@@ -1924,7 +1944,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;
@@ -1948,10 +1968,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;
@@ -1960,13 +1980,14 @@ 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 &&
+                           if (net->sctp.prsctp_enable &&
                                !asoc->peer.prsctp_capable)
                                    asoc->peer.prsctp_capable = 1;
                            break;
@@ -1974,12 +1995,12 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
                            /* if the peer reports AUTH, assume that he
                             * supports AUTH.
                             */
-                           if (sctp_auth_enable)
+                           if (net->sctp.auth_enable)
                                    asoc->peer.auth_capable = 1;
                            break;
                    case SCTP_CID_ASCONF:
                    case SCTP_CID_ASCONF_ACK:
-                           if (sctp_addip_enable)
+                           if (net->sctp.addip_enable)
                                    asoc->peer.asconf_capable = 1;
                            break;
                    default:
@@ -2065,7 +2086,8 @@ 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_association *asoc,
                                        union sctp_params param,
                                        sctp_cid_t cid,
                                        struct sctp_chunk *chunk,
@@ -2094,12 +2116,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;
 
@@ -2110,12 +2132,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 (!net->sctp.auth_enable)
                        goto fallthrough;
 
                /* SCTP-AUTH: Secion 6.1
@@ -2132,7 +2154,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_CHUNKS:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fallthrough;
 
                /* SCTP-AUTH: Section 3.2
@@ -2148,7 +2170,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fallthrough;
 
                hmacs = (struct sctp_hmac_algo_param *)param.p;
@@ -2182,7 +2204,7 @@ fallthrough:
 }
 
 /* Verify the INIT packet before we process it.  */
-int sctp_verify_init(const struct sctp_association *asoc,
+int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
                     sctp_cid_t cid,
                     sctp_init_chunk_t *peer_init,
                     struct sctp_chunk *chunk,
@@ -2229,7 +2251,7 @@ 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, asoc, param, cid, chunk, errp);
                switch (result) {
                    case SCTP_IERROR_ABORT:
                    case SCTP_IERROR_NOMEM:
@@ -2254,6 +2276,7 @@ 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;
@@ -2310,7 +2333,7 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
         * 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 |
@@ -2450,6 +2473,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;
@@ -2478,13 +2502,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);
@@ -2564,7 +2588,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);
@@ -2591,7 +2615,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;
                }
@@ -2599,7 +2623,7 @@ do_addr_param:
                goto fall_through;
 
        case SCTP_PARAM_RANDOM:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                /* Save peer's random parameter */
@@ -2612,7 +2636,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                /* Save peer's HMAC list */
@@ -2628,7 +2652,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_CHUNKS:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                asoc->peer.peer_chunks = kmemdup(param.p,
@@ -2768,11 +2792,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 +2805,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 +2822,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 +2834,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 +2982,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 &&
@@ -2997,6 +3039,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
@@ -3014,7 +3057,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 +3168,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 +3209,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 +3239,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 +3265,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 +3324,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 +3337,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 +3369,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 +3420,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);