aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2010-04-28 04:47:22 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-28 15:16:34 -0400
commitc0786693404cffd80ca3cb6e75ee7b35186b2825 (patch)
tree92a9026abbe71399c95330656af0f8c9d9c0019c
parenta8170c35e738d62e9919ce5b109cf4ed66e95bde (diff)
sctp: Fix oops when sending queued ASCONF chunks
When we finish processing ASCONF_ACK chunk, we try to send the next queued ASCONF. This action runs the sctp state machine recursively and it's not prepared to do so. kernel BUG at kernel/timer.c:790! invalid opcode: 0000 [#1] SMP last sysfs file: /sys/module/ipv6/initstate Modules linked in: sha256_generic sctp libcrc32c ipv6 dm_multipath uinput 8139too i2c_piix4 8139cp mii i2c_core pcspkr virtio_net joydev floppy virtio_blk virtio_pci [last unloaded: scsi_wait_scan] Pid: 0, comm: swapper Not tainted 2.6.34-rc4 #15 /Bochs EIP: 0060:[<c044a2ef>] EFLAGS: 00010286 CPU: 0 EIP is at add_timer+0xd/0x1b EAX: cecbab14 EBX: 000000f0 ECX: c0957b1c EDX: 03595cf4 ESI: cecba800 EDI: cf276f00 EBP: c0957aa0 ESP: c0957aa0 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process swapper (pid: 0, ti=c0956000 task=c0988ba0 task.ti=c0956000) Stack: c0957ae0 d1851214 c0ab62e4 c0ab5f26 0500ffff 00000004 00000005 00000004 <0> 00000000 d18694fd 00000004 1666b892 cecba800 cecba800 c0957b14 00000004 <0> c0957b94 d1851b11 ceda8b00 cecba800 cf276f00 00000001 c0957b14 000000d0 Call Trace: [<d1851214>] ? sctp_side_effects+0x607/0xdfc [sctp] [<d1851b11>] ? sctp_do_sm+0x108/0x159 [sctp] [<d1863386>] ? sctp_pname+0x0/0x1d [sctp] [<d1861a56>] ? sctp_primitive_ASCONF+0x36/0x3b [sctp] [<d185657c>] ? sctp_process_asconf_ack+0x2a4/0x2d3 [sctp] [<d184e35c>] ? sctp_sf_do_asconf_ack+0x1dd/0x2b4 [sctp] [<d1851ac1>] ? sctp_do_sm+0xb8/0x159 [sctp] [<d1863334>] ? sctp_cname+0x0/0x52 [sctp] [<d1854377>] ? sctp_assoc_bh_rcv+0xac/0xe1 [sctp] [<d1858f0f>] ? sctp_inq_push+0x2d/0x30 [sctp] [<d186329d>] ? sctp_rcv+0x797/0x82e [sctp] Tested-by: Wei Yongjun <yjwei@cn.fujitsu.com> Signed-off-by: Yuansong Qiao <ysqiao@research.ait.ie> Signed-off-by: Shuaijun Zhang <szhang@research.ait.ie> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sctp/command.h1
-rw-r--r--net/sctp/sm_make_chunk.c15
-rw-r--r--net/sctp/sm_sideeffect.c26
-rw-r--r--net/sctp/sm_statefuns.c8
4 files changed, 34 insertions, 16 deletions
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 8be5135ff7aa..2c55a7ea20af 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -107,6 +107,7 @@ typedef enum {
107 SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */ 107 SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
108 SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */ 108 SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
109 SCTP_CMD_SEND_MSG, /* Send the whole use message */ 109 SCTP_CMD_SEND_MSG, /* Send the whole use message */
110 SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
110 SCTP_CMD_LAST 111 SCTP_CMD_LAST
111} sctp_verb_t; 112} sctp_verb_t;
112 113
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index f6fc5c1a4078..0fd5b4c88358 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -3318,21 +3318,6 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
3318 sctp_chunk_free(asconf); 3318 sctp_chunk_free(asconf);
3319 asoc->addip_last_asconf = NULL; 3319 asoc->addip_last_asconf = NULL;
3320 3320
3321 /* Send the next asconf chunk from the addip chunk queue. */
3322 if (!list_empty(&asoc->addip_chunk_list)) {
3323 struct list_head *entry = asoc->addip_chunk_list.next;
3324 asconf = list_entry(entry, struct sctp_chunk, list);
3325
3326 list_del_init(entry);
3327
3328 /* Hold the chunk until an ASCONF_ACK is received. */
3329 sctp_chunk_hold(asconf);
3330 if (sctp_primitive_ASCONF(asoc, asconf))
3331 sctp_chunk_free(asconf);
3332 else
3333 asoc->addip_last_asconf = asconf;
3334 }
3335
3336 return retval; 3321 return retval;
3337} 3322}
3338 3323
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 4c5bed9af4e3..d5ae450b6f02 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -962,6 +962,29 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc,
962} 962}
963 963
964 964
965/* Sent the next ASCONF packet currently stored in the association.
966 * This happens after the ASCONF_ACK was succeffully processed.
967 */
968static void sctp_cmd_send_asconf(struct sctp_association *asoc)
969{
970 /* Send the next asconf chunk from the addip chunk
971 * queue.
972 */
973 if (!list_empty(&asoc->addip_chunk_list)) {
974 struct list_head *entry = asoc->addip_chunk_list.next;
975 struct sctp_chunk *asconf = list_entry(entry,
976 struct sctp_chunk, list);
977 list_del_init(entry);
978
979 /* Hold the chunk until an ASCONF_ACK is received. */
980 sctp_chunk_hold(asconf);
981 if (sctp_primitive_ASCONF(asoc, asconf))
982 sctp_chunk_free(asconf);
983 else
984 asoc->addip_last_asconf = asconf;
985 }
986}
987
965 988
966/* These three macros allow us to pull the debugging code out of the 989/* These three macros allow us to pull the debugging code out of the
967 * main flow of sctp_do_sm() to keep attention focused on the real 990 * main flow of sctp_do_sm() to keep attention focused on the real
@@ -1617,6 +1640,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
1617 } 1640 }
1618 error = sctp_cmd_send_msg(asoc, cmd->obj.msg); 1641 error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
1619 break; 1642 break;
1643 case SCTP_CMD_SEND_NEXT_ASCONF:
1644 sctp_cmd_send_asconf(asoc);
1645 break;
1620 default: 1646 default:
1621 printk(KERN_WARNING "Impossible command: %u, %p\n", 1647 printk(KERN_WARNING "Impossible command: %u, %p\n",
1622 cmd->verb, cmd->obj.ptr); 1648 cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index abf601a1b847..24b2cd555637 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3676,8 +3676,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
3676 SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); 3676 SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
3677 3677
3678 if (!sctp_process_asconf_ack((struct sctp_association *)asoc, 3678 if (!sctp_process_asconf_ack((struct sctp_association *)asoc,
3679 asconf_ack)) 3679 asconf_ack)) {
3680 /* Successfully processed ASCONF_ACK. We can
3681 * release the next asconf if we have one.
3682 */
3683 sctp_add_cmd_sf(commands, SCTP_CMD_SEND_NEXT_ASCONF,
3684 SCTP_NULL());
3680 return SCTP_DISPOSITION_CONSUME; 3685 return SCTP_DISPOSITION_CONSUME;
3686 }
3681 3687
3682 abort = sctp_make_abort(asoc, asconf_ack, 3688 abort = sctp_make_abort(asoc, asconf_ack,
3683 sizeof(sctp_errhdr_t)); 3689 sizeof(sctp_errhdr_t));