Don't requeue IKEv1 init tasks if they already exist in a second keyingtry
[strongswan.git] / src / libcharon / sa / ikev1 / task_manager_v1.c
index e8399e4..f31f497 100644 (file)
@@ -21,6 +21,7 @@
 #include <daemon.h>
 #include <sa/ikev1/tasks/main_mode.h>
 #include <sa/ikev1/tasks/quick_mode.h>
+#include <sa/ikev1/tasks/quick_delete.h>
 #include <sa/ikev1/tasks/xauth.h>
 #include <sa/ikev1/tasks/mode_config.h>
 #include <sa/ikev1/tasks/informational.h>
@@ -28,6 +29,7 @@
 #include <sa/ikev1/tasks/isakmp_vendor.h>
 #include <sa/ikev1/tasks/isakmp_cert_pre.h>
 #include <sa/ikev1/tasks/isakmp_cert_post.h>
+#include <sa/ikev1/tasks/isakmp_delete.h>
 #include <processing/jobs/retransmit_job.h>
 #include <processing/jobs/delete_ike_sa_job.h>
 
@@ -1011,14 +1013,95 @@ METHOD(task_manager_t, queue_task, void,
        this->queued_tasks->insert_last(this->queued_tasks, task);
 }
 
+/**
+ * Check if a given task has been queued already
+ */
+static bool has_queued(private_task_manager_t *this, task_type_t type)
+{
+       enumerator_t *enumerator;
+       bool found = FALSE;
+       task_t *task;
+
+       enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+       while (enumerator->enumerate(enumerator, &task))
+       {
+               if (task->get_type(task) == type)
+               {
+                       found = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
 METHOD(task_manager_t, queue_ike, void,
        private_task_manager_t *this)
 {
-       queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE));
-       queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE));
-       queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE));
-       queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE));
-       queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE));
+       if (!has_queued(this, TASK_ISAKMP_VENDOR))
+       {
+               queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE));
+       }
+       if (!has_queued(this, TASK_ISAKMP_CERT_PRE))
+       {
+               queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE));
+       }
+       if (!has_queued(this, TASK_MAIN_MODE))
+       {
+               queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE));
+       }
+       if (!has_queued(this, TASK_ISAKMP_CERT_POST))
+       {
+               queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE));
+       }
+       if (!has_queued(this, TASK_ISAKMP_NATD))
+       {
+               queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE));
+       }
+}
+
+METHOD(task_manager_t, queue_ike_rekey, void,
+       private_task_manager_t *this)
+{
+       /* TODO-IKEv1: IKE_SA rekeying */
+}
+
+METHOD(task_manager_t, queue_ike_reauth, void,
+       private_task_manager_t *this)
+{
+       /* TODO-IKEv1: IKE_SA reauth */
+}
+
+METHOD(task_manager_t, queue_ike_delete, void,
+       private_task_manager_t *this)
+{
+       queue_task(this, (task_t*)isakmp_delete_create(this->ike_sa, TRUE));
+}
+
+METHOD(task_manager_t, queue_mobike, void,
+       private_task_manager_t *this, bool roam, bool address)
+{
+       /* Not supported in IKEv1 */
+}
+
+METHOD(task_manager_t, queue_child, void,
+       private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid,
+       traffic_selector_t *tsi, traffic_selector_t *tsr)
+{
+       queue_task(this, (task_t*)quick_mode_create(this->ike_sa, cfg, tsi, tsr));
+}
+
+METHOD(task_manager_t, queue_child_rekey, void,
+       private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi)
+{
+       /* TODO-IKEv1: CHILD rekeying */
+}
+
+METHOD(task_manager_t, queue_child_delete, void,
+       private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi)
+{
+       queue_task(this, (task_t*)quick_delete_create(this->ike_sa, protocol,
+                                                                                                 spi, FALSE));
 }
 
 METHOD(task_manager_t, queue_dpd, void,
@@ -1057,6 +1140,34 @@ METHOD(task_manager_t, incr_mid, void,
 METHOD(task_manager_t, reset, void,
        private_task_manager_t *this, u_int32_t initiate, u_int32_t respond)
 {
+       enumerator_t *enumerator;
+       task_t *task;
+
+       /* reset message counters and retransmit packets */
+       DESTROY_IF(this->responding.packet);
+       DESTROY_IF(this->initiating.packet);
+       this->responding.packet = NULL;
+       this->initiating.packet = NULL;
+       this->initiating.mid = 0;
+       this->initiating.seqnr = 0;
+       this->initiating.retransmitted = 0;
+       this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
+
+       /* reset queued tasks */
+       enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+       while (enumerator->enumerate(enumerator, &task))
+       {
+               task->migrate(task, this->ike_sa);
+       }
+       enumerator->destroy(enumerator);
+
+       /* reset active tasks */
+       while (this->active_tasks->remove_last(this->active_tasks,
+                                                                                  (void**)&task) == SUCCESS)
+       {
+               task->migrate(task, this->ike_sa);
+               this->queued_tasks->insert_first(this->queued_tasks, task);
+       }
 }
 
 METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
@@ -1104,6 +1215,13 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
                                .process_message = _process_message,
                                .queue_task = _queue_task,
                                .queue_ike = _queue_ike,
+                               .queue_ike_rekey = _queue_ike_rekey,
+                               .queue_ike_reauth = _queue_ike_reauth,
+                               .queue_ike_delete = _queue_ike_delete,
+                               .queue_mobike = _queue_mobike,
+                               .queue_child = _queue_child,
+                               .queue_child_rekey = _queue_child_rekey,
+                               .queue_child_delete = _queue_child_delete,
                                .queue_dpd = _queue_dpd,
                                .initiate = _initiate,
                                .retransmit = _retransmit,