* after reaching 4294967295.
         */
        __u32 addip_serial;
+       union sctp_addr *asconf_addr_del_pending;
+       int src_out_of_asoc_ok;
 
        /* SCTP AUTH: list of the endpoint shared keys.  These
         * keys are provided out of band by the user applicaton
 
        asoc->peer.asconf_capable = 0;
        if (sctp_addip_noauth)
                asoc->peer.asconf_capable = 1;
+       asoc->asconf_addr_del_pending = NULL;
+       asoc->src_out_of_asoc_ok = 0;
 
        /* Create an input queue.  */
        sctp_inq_init(&asoc->base.inqueue);
 
        sctp_asconf_queue_teardown(asoc);
 
+       /* Free pending address space being deleted */
+       if (asoc->asconf_addr_del_pending != NULL)
+               kfree(asoc->asconf_addr_del_pending);
+
        /* AUTH - Free the endpoint shared keys */
        sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
 
 
         */
 
        list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+               /* RFC 5061, 5.3
+                * F1) This means that until such time as the ASCONF
+                * containing the add is acknowledged, the sender MUST
+                * NOT use the new IP address as a source for ANY SCTP
+                * packet except on carrying an ASCONF Chunk.
+                */
+               if (asoc->src_out_of_asoc_ok &&
+                   chunk->chunk_hdr->type != SCTP_CID_ASCONF)
+                       continue;
+
                list_del_init(&chunk->list);
 
                /* Pick the right transport to use. */
                }
        }
 
+       if (q->asoc->src_out_of_asoc_ok)
+               goto sctp_flush_out;
+
        /* Is it OK to send data chunks?  */
        switch (asoc->state) {
        case SCTP_STATE_COOKIE_ECHOED:
 
                sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
                rcu_read_lock();
                list_for_each_entry_rcu(laddr, &bp->address_list, list) {
-                       if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+                       if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) ||
+                           (laddr->state != SCTP_ADDR_SRC &&
+                           !asoc->src_out_of_asoc_ok))
                                continue;
                        if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
                                goto out_unlock;
 
        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;
                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. */
 
                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;
 }
 
        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) {
                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);
 
                        goto out;
                }
 
-               retval = sctp_send_asconf(asoc, chunk);
-               if (retval)
-                       goto out;
-
                /* Add the new addresses to the bind address list with
                 * use_as_src set to 0.
                 */
                                                    SCTP_ADDR_NEW, GFP_ATOMIC);
                        addr_buf += af->sockaddr_len;
                }
+               if (asoc->src_out_of_asoc_ok) {
+                       struct sctp_transport *trans;
+
+                       list_for_each_entry(trans,
+                           &asoc->peer.transport_addr_list, transports) {
+                               /* Clear the source and route cache */
+                               dst_release(trans->dst);
+                               trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
+                                   2*asoc->pathmtu, 4380));
+                               trans->ssthresh = asoc->peer.i.a_rwnd;
+                               trans->rto = asoc->rto_initial;
+                               trans->rtt = trans->srtt = trans->rttvar = 0;
+                               sctp_transport_route(trans, NULL,
+                                   sctp_sk(asoc->base.sk));
+                       }
+               }
+               retval = sctp_send_asconf(asoc, chunk);
        }
 
 out:
        struct sctp_sockaddr_entry *saddr;
        int                     i;
        int                     retval = 0;
+       int                     stored = 0;
 
+       chunk = NULL;
        if (!sctp_addip_enable)
                return retval;
 
                bp = &asoc->base.bind_addr;
                laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
                                               addrcnt, sp);
-               if (!laddr)
-                       continue;
+               if ((laddr == NULL) && (addrcnt == 1)) {
+                       if (asoc->asconf_addr_del_pending)
+                               continue;
+                       asoc->asconf_addr_del_pending =
+                           kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
+                       asoc->asconf_addr_del_pending->sa.sa_family =
+                                   addrs->sa_family;
+                       asoc->asconf_addr_del_pending->v4.sin_port =
+                                   htons(bp->port);
+                       if (addrs->sa_family == AF_INET) {
+                               struct sockaddr_in *sin;
+
+                               sin = (struct sockaddr_in *)addrs;
+                               asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
+                       } else if (addrs->sa_family == AF_INET6) {
+                               struct sockaddr_in6 *sin6;
+
+                               sin6 = (struct sockaddr_in6 *)addrs;
+                               ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr);
+                       }
+                       SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
+                           " at %p\n", asoc, asoc->asconf_addr_del_pending,
+                           asoc->asconf_addr_del_pending);
+                       asoc->src_out_of_asoc_ok = 1;
+                       stored = 1;
+                       goto skip_mkasconf;
+               }
 
                /* We do not need RCU protection throughout this loop
                 * because this is done under a socket lock from the
                        goto out;
                }
 
+skip_mkasconf:
                /* Reset use_as_src flag for the addresses in the bind address
                 * list that are to be deleted.
                 */
                                             sctp_sk(asoc->base.sk));
                }
 
+               if (stored)
+                       /* We don't need to transmit ASCONF */
+                       continue;
                retval = sctp_send_asconf(asoc, chunk);
        }
 out: