The linux kernel will die if an application send SET_PRIMARY ASCONF immediately after ADDIP ASCONF. The reason is that SCTP finishes processing ASCONF_ACK, it sends the next pending ASCONF. Therefore the state machine function sctp_do_sm() run recursively. The commands for ASCONF are executed before the commands for ASCONF_ACK. The command sequences are running in reversed order. Therefore, the T4 timer for the new ASCONF starts before the old T4 timer stops. However, SCTP uses only one timer for all ASCONF chunks. This fixes the problem if deleting the statements for sending the next ASCONF during processing ASCONF_ACK, and instead, use a new command "SCTP_CMD_SEND_NEXT_ASCONF" for sending the next ASCONF chunk in the sideeffect function of ASCONF_ACK. Kernel version: 2.6.27.28 diff -uprN a/include/net/sctp/command.h b/include/net/sctp/command.h --- a/include/net/sctp/command.h 2010-04-20 17:24:18.000000000 +0100 +++ b/include/net/sctp/command.h 2010-04-21 09:55:37.000000000 +0100 @@ -105,6 +105,7 @@ typedef enum { SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */ SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ + SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after processing ASCONF_ACK */ SCTP_CMD_LAST } sctp_verb_t; diff -uprN a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c --- a/net/sctp/sm_make_chunk.c 2010-04-20 17:15:01.000000000 +0100 +++ b/net/sctp/sm_make_chunk.c 2010-04-21 09:39:17.000000000 +0100 @@ -3290,21 +3290,6 @@ int sctp_process_asconf_ack(struct sctp_ 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; } diff -uprN a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- a/net/sctp/sm_sideeffect.c 2010-04-20 17:15:01.000000000 +0100 +++ b/net/sctp/sm_sideeffect.c 2010-04-21 09:33:43.000000000 +0100 @@ -1082,6 +1082,25 @@ static int sctp_cmd_interpreter(sctp_eve */ while (NULL != (cmd = sctp_next_cmd(commands))) { switch (cmd->verb) { + + case SCTP_CMD_SEND_NEXT_ASCONF: + asoc = cmd->obj.ptr; + /* 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(asoc, asconf)) + sctp_chunk_free(asconf); + else + asoc->addip_last_asconf = asconf; + } + break; + case SCTP_CMD_NOP: /* Do nothing. */ break; diff -uprN a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- a/net/sctp/sm_statefuns.c 2010-04-20 17:15:01.000000000 +0100 +++ b/net/sctp/sm_statefuns.c 2010-04-21 09:54:15.000000000 +0100 @@ -3585,6 +3585,9 @@ sctp_disposition_t sctp_sf_do_asconf_ack if ((rcvd_serial == sent_serial) && asoc->addip_last_asconf) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF, + SCTP_ASOC(asoc)); if (!sctp_process_asconf_ack((struct sctp_association *)asoc, asconf_ack)) Signed-off-by: Yuansong Qiao <ysqiao@xxxxxxxxxxxxxxx> Shuaijun Zhang <szhang@xxxxxxxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html