SCTP_CMD_T1_RETRAN,      /* Mark for retransmission after T1 timeout  */
        SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
        SCTP_CMD_SEND_MSG,       /* Send the whole use message */
-       SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
        SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/
        SCTP_CMD_SET_ASOC,       /* Restore association context */
        SCTP_CMD_LAST
 
 }
 
 
-/* Sent the next ASCONF packet currently stored in the association.
- * This happens after the ASCONF_ACK was succeffully processed.
- */
-static void sctp_cmd_send_asconf(struct sctp_association *asoc)
-{
-       struct net *net = sock_net(asoc->base.sk);
-
-       /* 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;
-               struct sctp_chunk *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(net, asoc, asconf))
-                       sctp_chunk_free(asconf);
-               else
-                       asoc->addip_last_asconf = asconf;
-       }
-}
-
-
 /* These three macros allow us to pull the debugging code out of the
  * main flow of sctp_do_sm() to keep attention focused on the real
  * functionality there.
                        }
                        sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp);
                        break;
-               case SCTP_CMD_SEND_NEXT_ASCONF:
-                       sctp_cmd_send_asconf(asoc);
-                       break;
                case SCTP_CMD_PURGE_ASCONF_QUEUE:
                        sctp_asconf_queue_teardown(asoc);
                        break;
 
        return SCTP_DISPOSITION_CONSUME;
 }
 
+static enum sctp_disposition sctp_send_next_asconf(
+                                       struct net *net,
+                                       const struct sctp_endpoint *ep,
+                                       struct sctp_association *asoc,
+                                       const union sctp_subtype type,
+                                       struct sctp_cmd_seq *commands)
+{
+       struct sctp_chunk *asconf;
+       struct list_head *entry;
+
+       if (list_empty(&asoc->addip_chunk_list))
+               return SCTP_DISPOSITION_CONSUME;
+
+       entry = asoc->addip_chunk_list.next;
+       asconf = list_entry(entry, struct sctp_chunk, list);
+
+       list_del_init(entry);
+       sctp_chunk_hold(asconf);
+       asoc->addip_last_asconf = asconf;
+
+       return sctp_sf_do_prm_asconf(net, ep, asoc, type, asconf, commands);
+}
+
 /*
  * ADDIP Section 4.3 General rules for address manipulation
  * When building TLV parameters for the ASCONF Chunk that will add or
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
 
                if (!sctp_process_asconf_ack((struct sctp_association *)asoc,
-                                            asconf_ack)) {
-                       /* Successfully processed ASCONF_ACK.  We can
-                        * release the next asconf if we have one.
-                        */
-                       sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF,
-                                       SCTP_NULL());
-                       return SCTP_DISPOSITION_CONSUME;
-               }
+                                            asconf_ack))
+                       return sctp_send_next_asconf(net, ep,
+                                       (struct sctp_association *)asoc,
+                                                       type, commands);
 
                abort = sctp_make_abort(asoc, asconf_ack,
                                        sizeof(struct sctp_errhdr));